From ad410fd1938eb99175e71940823e8a668dc70f5b Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Tue, 25 Nov 2025 09:25:11 +0100 Subject: [PATCH 001/179] Initial commit --- .editorconfig | 20 + .gitignore | 6 + Assembly-CSharp-Editor.csproj | 1293 +++++++++++++++++ Assembly-CSharp.csproj | 1240 ++++++++++++++++ Assets/InputSystem_Actions.inputactions | 1057 ++++++++++++++ Assets/InputSystem_Actions.inputactions.meta | 14 + Assets/NanoBrain.meta | 8 + Assets/NanoBrain/Editor.meta | 8 + Assets/NanoBrain/Editor/GraphEditorWindow.cs | 204 +++ .../Editor/GraphEditorWindow.cs.meta | 2 + Assets/NanoBrain/Neuroid.cs | 109 ++ Assets/NanoBrain/Neuroid.cs.meta | 2 + Assets/NanoBrain/NeuroidBehaviour.cs | 14 + Assets/NanoBrain/NeuroidBehaviour.cs.meta | 2 + Assets/Scenes.meta | 8 + Assets/Scenes/Ants.meta | 8 + Assets/Scenes/Boids.meta | 8 + Assets/Scenes/Boids/Boid Graph.asset | 17 + Assets/Scenes/Boids/Boid Graph.asset.meta | 8 + Assets/Scenes/Boids/Boids.unity | 416 ++++++ Assets/Scenes/Boids/Boids.unity.meta | 7 + Assets/Scenes/Boids/Materials.meta | 8 + Assets/Scenes/Boids/Materials/White.mat | 137 ++ Assets/Scenes/Boids/Materials/White.mat.meta | 8 + Assets/Scenes/Boids/Prefabs.meta | 8 + Assets/Scenes/Boids/Prefabs/Boid.prefab | 172 +++ Assets/Scenes/Boids/Prefabs/Boid.prefab.meta | 7 + Assets/Scenes/Boids/Scripts.meta | 8 + Assets/Scenes/Boids/Scripts/Boid.cs | 94 ++ Assets/Scenes/Boids/Scripts/Boid.cs.meta | 2 + Assets/Scenes/Boids/Scripts/SwarmControl.cs | 14 + .../Scenes/Boids/Scripts/SwarmControl.cs.meta | 2 + Assets/Scenes/Boids/Scripts/SwarmSpawner.cs | 32 + .../Scenes/Boids/Scripts/SwarmSpawner.cs.meta | 2 + Assets/Scenes/Gaze.meta | 8 + Assets/Scenes/SampleScene.unity | 432 ++++++ Assets/Scenes/SampleScene.unity.meta | 7 + Assets/Settings.meta | 8 + Assets/_Recovery.meta | 8 + Assets/_Recovery/0.unity | 474 ++++++ Assets/_Recovery/0.unity.meta | 7 + NanoBrain.sln | 26 + Packages/manifest.json | 46 + Packages/packages-lock.json | 455 ++++++ ProjectSettings/AudioManager.asset | 19 + ProjectSettings/ClusterInputManager.asset | 6 + ProjectSettings/DynamicsManager.asset | 36 + ProjectSettings/EditorBuildSettings.asset | 13 + ProjectSettings/EditorSettings.asset | 50 + ProjectSettings/GraphicsSettings.asset | 70 + ProjectSettings/InputManager.asset | 487 +++++++ ProjectSettings/MemorySettings.asset | 35 + ProjectSettings/MultiplayerManager.asset | 7 + ProjectSettings/NavMeshAreas.asset | 91 ++ ProjectSettings/PackageManagerSettings.asset | 43 + ProjectSettings/Physics2DSettings.asset | 56 + ProjectSettings/PresetManager.asset | 7 + ProjectSettings/ProjectSettings.asset | 938 ++++++++++++ ProjectSettings/ProjectVersion.txt | 2 + ProjectSettings/QualitySettings.asset | 134 ++ ProjectSettings/SceneTemplateSettings.json | 121 ++ ProjectSettings/ShaderGraphSettings.asset | 19 + ProjectSettings/TagManager.asset | 76 + ProjectSettings/TimeManager.asset | 9 + ProjectSettings/URPProjectSettings.asset | 15 + ProjectSettings/UnityConnectSettings.asset | 40 + ProjectSettings/VFXManager.asset | 12 + ProjectSettings/VersionControlSettings.asset | 8 + ProjectSettings/VisualScriptingSettings.asset | 21 + ProjectSettings/XRSettings.asset | 10 + 70 files changed, 8741 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitignore create mode 100644 Assembly-CSharp-Editor.csproj create mode 100644 Assembly-CSharp.csproj create mode 100644 Assets/InputSystem_Actions.inputactions create mode 100644 Assets/InputSystem_Actions.inputactions.meta create mode 100644 Assets/NanoBrain.meta create mode 100644 Assets/NanoBrain/Editor.meta create mode 100644 Assets/NanoBrain/Editor/GraphEditorWindow.cs create mode 100644 Assets/NanoBrain/Editor/GraphEditorWindow.cs.meta create mode 100644 Assets/NanoBrain/Neuroid.cs create mode 100644 Assets/NanoBrain/Neuroid.cs.meta create mode 100644 Assets/NanoBrain/NeuroidBehaviour.cs create mode 100644 Assets/NanoBrain/NeuroidBehaviour.cs.meta create mode 100644 Assets/Scenes.meta create mode 100644 Assets/Scenes/Ants.meta create mode 100644 Assets/Scenes/Boids.meta create mode 100644 Assets/Scenes/Boids/Boid Graph.asset create mode 100644 Assets/Scenes/Boids/Boid Graph.asset.meta create mode 100644 Assets/Scenes/Boids/Boids.unity create mode 100644 Assets/Scenes/Boids/Boids.unity.meta create mode 100644 Assets/Scenes/Boids/Materials.meta create mode 100644 Assets/Scenes/Boids/Materials/White.mat create mode 100644 Assets/Scenes/Boids/Materials/White.mat.meta create mode 100644 Assets/Scenes/Boids/Prefabs.meta create mode 100644 Assets/Scenes/Boids/Prefabs/Boid.prefab create mode 100644 Assets/Scenes/Boids/Prefabs/Boid.prefab.meta create mode 100644 Assets/Scenes/Boids/Scripts.meta create mode 100644 Assets/Scenes/Boids/Scripts/Boid.cs create mode 100644 Assets/Scenes/Boids/Scripts/Boid.cs.meta create mode 100644 Assets/Scenes/Boids/Scripts/SwarmControl.cs create mode 100644 Assets/Scenes/Boids/Scripts/SwarmControl.cs.meta create mode 100644 Assets/Scenes/Boids/Scripts/SwarmSpawner.cs create mode 100644 Assets/Scenes/Boids/Scripts/SwarmSpawner.cs.meta create mode 100644 Assets/Scenes/Gaze.meta create mode 100644 Assets/Scenes/SampleScene.unity create mode 100644 Assets/Scenes/SampleScene.unity.meta create mode 100644 Assets/Settings.meta create mode 100644 Assets/_Recovery.meta create mode 100644 Assets/_Recovery/0.unity create mode 100644 Assets/_Recovery/0.unity.meta create mode 100644 NanoBrain.sln create mode 100644 Packages/manifest.json create mode 100644 Packages/packages-lock.json create mode 100644 ProjectSettings/AudioManager.asset create mode 100644 ProjectSettings/ClusterInputManager.asset create mode 100644 ProjectSettings/DynamicsManager.asset create mode 100644 ProjectSettings/EditorBuildSettings.asset create mode 100644 ProjectSettings/EditorSettings.asset create mode 100644 ProjectSettings/GraphicsSettings.asset create mode 100644 ProjectSettings/InputManager.asset create mode 100644 ProjectSettings/MemorySettings.asset create mode 100644 ProjectSettings/MultiplayerManager.asset create mode 100644 ProjectSettings/NavMeshAreas.asset create mode 100644 ProjectSettings/PackageManagerSettings.asset create mode 100644 ProjectSettings/Physics2DSettings.asset create mode 100644 ProjectSettings/PresetManager.asset create mode 100644 ProjectSettings/ProjectSettings.asset create mode 100644 ProjectSettings/ProjectVersion.txt create mode 100644 ProjectSettings/QualitySettings.asset create mode 100644 ProjectSettings/SceneTemplateSettings.json create mode 100644 ProjectSettings/ShaderGraphSettings.asset create mode 100644 ProjectSettings/TagManager.asset create mode 100644 ProjectSettings/TimeManager.asset create mode 100644 ProjectSettings/URPProjectSettings.asset create mode 100644 ProjectSettings/UnityConnectSettings.asset create mode 100644 ProjectSettings/VFXManager.asset create mode 100644 ProjectSettings/VersionControlSettings.asset create mode 100644 ProjectSettings/VisualScriptingSettings.asset create mode 100644 ProjectSettings/XRSettings.asset diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..def86c3 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,20 @@ +root = true + +[*.cs] +# Use tabs for indentation +indent_style = space # To use spaces, you could set this to 'space' +indent_size = 2 # Standard C# indent size + +# Alignment and Style Rules +csharp_indent_case_contents = true +csharp_new_line_after_open_brace = all +csharp_new_line_before_open_brace = none +csharp_new_line_before_else = true +csharp_new_line_before_catch = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_between_query_expression_clauses = true + +# Limit the number of characters in a line +max_line_length = 100 # This setting does not enforce it; it's a guideline. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8bd4dbe --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +.vscode +Library +Assets/Settings +Logs +Temp +UserSettings \ No newline at end of file diff --git a/Assembly-CSharp-Editor.csproj b/Assembly-CSharp-Editor.csproj new file mode 100644 index 0000000..740c939 --- /dev/null +++ b/Assembly-CSharp-Editor.csproj @@ -0,0 +1,1293 @@ + + + + Temp\obj\$(MSBuildProjectName) + $(BaseIntermediateOutputPath) + false + true + Temp\bin\Debug\ + + + + + + + false + false + 9.0 + + Library + Assembly-CSharp-Editor + netstandard2.1 + . + + + 0169;USG0001 + UNITY_6000_2_7;UNITY_6000_2;UNITY_6000;UNITY_5_3_OR_NEWER;UNITY_5_4_OR_NEWER;UNITY_5_5_OR_NEWER;UNITY_5_6_OR_NEWER;UNITY_2017_1_OR_NEWER;UNITY_2017_2_OR_NEWER;UNITY_2017_3_OR_NEWER;UNITY_2017_4_OR_NEWER;UNITY_2018_1_OR_NEWER;UNITY_2018_2_OR_NEWER;UNITY_2018_3_OR_NEWER;UNITY_2018_4_OR_NEWER;UNITY_2019_1_OR_NEWER;UNITY_2019_2_OR_NEWER;UNITY_2019_3_OR_NEWER;UNITY_2019_4_OR_NEWER;UNITY_2020_1_OR_NEWER;UNITY_2020_2_OR_NEWER;UNITY_2020_3_OR_NEWER;UNITY_2021_1_OR_NEWER;UNITY_2021_2_OR_NEWER;UNITY_2021_3_OR_NEWER;UNITY_2022_1_OR_NEWER;UNITY_2022_2_OR_NEWER;UNITY_2022_3_OR_NEWER;UNITY_2023_1_OR_NEWER;UNITY_2023_2_OR_NEWER;UNITY_2023_3_OR_NEWER;UNITY_6000_0_OR_NEWER;UNITY_6000_1_OR_NEWER;UNITY_6000_2_OR_NEWER;PLATFORM_ARCH_64;UNITY_64;UNITY_INCLUDE_TESTS;ENABLE_AR;ENABLE_AUDIO;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_EVENT_QUEUE;ENABLE_MICROPHONE;ENABLE_MULTIPLE_DISPLAYS;ENABLE_PHYSICS;ENABLE_TEXTURE_STREAMING;ENABLE_VIRTUALTEXTURING;ENABLE_LZMA;ENABLE_UNITYEVENTS;ENABLE_VR;ENABLE_WEBCAM;ENABLE_UNITYWEBREQUEST;ENABLE_WWW;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_SERVICES_USE_WEBREQUEST;ENABLE_UNITY_CONSENT;ENABLE_UNITY_CLOUD_IDENTIFIERS;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_NATIVE_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_EDITOR_GAME_SERVICES;ENABLE_UNITY_GAME_SERVICES_ANALYTICS_SUPPORT;ENABLE_CLOUD_LICENSE;ENABLE_EDITOR_HUB_LICENSE;ENABLE_WEBSOCKET_CLIENT;ENABLE_GENERATE_NATIVE_PLUGINS_FOR_ASSEMBLIES_API;ENABLE_DIRECTOR_AUDIO;ENABLE_DIRECTOR_TEXTURE;ENABLE_MANAGED_JOBS;ENABLE_MANAGED_TRANSFORM_JOBS;ENABLE_MANAGED_ANIMATION_JOBS;ENABLE_MANAGED_AUDIO_JOBS;ENABLE_MANAGED_UNITYTLS;INCLUDE_DYNAMIC_GI;ENABLE_SCRIPTING_GC_WBARRIERS;PLATFORM_SUPPORTS_MONO;RENDER_SOFTWARE_CURSOR;ENABLE_MARSHALLING_TESTS;ENABLE_VIDEO;ENABLE_NAVIGATION_OFFMESHLINK_TO_NAVMESHLINK;ENABLE_ACCELERATOR_CLIENT_DEBUGGING;TEXTCORE_1_0_OR_NEWER;EDITOR_ONLY_NAVMESH_BUILDER_DEPRECATED;PLATFORM_STANDALONE_WIN;PLATFORM_STANDALONE;UNITY_STANDALONE_WIN;UNITY_STANDALONE;ENABLE_RUNTIME_GI;ENABLE_MOVIES;ENABLE_NETWORK;ENABLE_NVIDIA;ENABLE_AMD;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_CLOUD_SERVICES_ENGINE_DIAGNOSTICS;ENABLE_OUT_OF_PROCESS_CRASH_HANDLER;ENABLE_CLUSTER_SYNC;ENABLE_CLUSTERINPUT;PLATFORM_UPDATES_TIME_OUTSIDE_OF_PLAYER_LOOP;GFXDEVICE_WAITFOREVENT_MESSAGEPUMP;PLATFORM_USES_EXPLICIT_MEMORY_MANAGER_INITIALIZER;PLATFORM_SUPPORTS_WAIT_FOR_PRESENTATION;PLATFORM_SUPPORTS_SPLIT_GRAPHICS_JOBS;ENABLE_MONO;NET_4_6;NET_UNITY_4_8;ENABLE_PROFILER;DEBUG;TRACE;UNITY_ASSERTIONS;UNITY_EDITOR;UNITY_EDITOR_64;UNITY_EDITOR_WIN;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_BURST_AOT;UNITY_TEAM_LICENSE;ENABLE_CUSTOM_RENDER_TEXTURE;ENABLE_DIRECTOR;ENABLE_LOCALIZATION;ENABLE_SPRITES;ENABLE_TERRAIN;ENABLE_TILEMAP;ENABLE_TIMELINE;ENABLE_INPUT_SYSTEM;TEXTCORE_FONT_ENGINE_1_5_OR_NEWER;TEXTCORE_TEXT_ENGINE_1_5_OR_NEWER;CSHARP_7_OR_LATER;CSHARP_7_3_OR_NEWER;UNITY_EDITOR_ONLY_COMPILATION + False + + + true + true + true + true + MSB3277 + + + Package + 2.0.23 + SDK + Editor:5 + StandaloneWindows64:19 + 6000.2.7f2 + + + + + + + + + + + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.AIModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.AMDModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.ARModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.AccessibilityModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.AndroidJNIModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.AnimationModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.AssetBundleModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.AudioModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.ClothModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.ClusterInputModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.ClusterRendererModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.ContentLoadModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.CrashReportingModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.DSPGraphModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.DirectorModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.GIModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.GameCenterModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.GraphicsStateCollectionSerializerModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.GridModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.HierarchyCoreModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.HotReloadModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.IMGUIModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.IdentifiersModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.ImageConversionModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.InputModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.InputForUIModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.InputLegacyModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.InsightsModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.JSONSerializeModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.LocalizationModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.MarshallingModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.MultiplayerModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.NVIDIAModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.ParticleSystemModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.PerformanceReportingModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.PhysicsModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.Physics2DModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.PropertiesModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.RuntimeInitializeOnLoadManagerInitializerModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.ScreenCaptureModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.ShaderVariantAnalyticsModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.SharedInternalsModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.SpriteMaskModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.SpriteShapeModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.StreamingModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.SubstanceModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.SubsystemsModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.TLSModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.TerrainModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.TerrainPhysicsModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.TextCoreFontEngineModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.TextCoreTextEngineModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.TextRenderingModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.TilemapModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UIModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UIElementsModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UmbraModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityAnalyticsModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityAnalyticsCommonModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityConnectModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityConsentModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityCurlModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityTestProtocolModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestAssetBundleModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestAudioModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestTextureModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestWWWModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.VFXModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.VRModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.VehiclesModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.VideoModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.VirtualTexturingModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.WindModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.XRModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.AccessibilityModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.AdaptivePerformanceModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.BuildProfileModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.ClothModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.CoreBusinessMetricsModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.CoreModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.DeviceSimulatorModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.DiagnosticsModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.EditorToolbarModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.EmbreeModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.GIModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.GraphViewModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.GraphicsStateCollectionSerializerModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.GridAndSnapModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.GridModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.InAppPurchasingModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.LevelPlayModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.MultiplayerModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.Physics2DModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.PhysicsModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.PresetsUIModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.PropertiesModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.QuickSearchModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.SafeModeModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.SceneTemplateModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.SceneViewModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.ShaderFoundryModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.SketchUpModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.SpriteMaskModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.SpriteShapeModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.SubstanceModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.TerrainModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.TextCoreFontEngineModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.TextCoreTextEngineModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.TextRenderingModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.TilemapModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.TreeModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.UIAutomationModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.UIBuilderModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.UIElementsModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.UIElementsSamplesModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.UmbraModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.UnityConnectModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.VFXModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.VideoModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.XRModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEditor.Graphs.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\PlaybackEngines\WindowsStandaloneSupport\UnityEditor.WindowsStandalone.Extensions.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\PlaybackEngines\AndroidPlayer\UnityEditor.Android.Extensions.dll + False + + + Library\PackageCache\com.unity.collections@d49facba0036\Unity.Collections.LowLevel.ILSupport\Unity.Collections.LowLevel.ILSupport.dll + False + + + Library\PackageCache\com.unity.ext.nunit@031a54704bff\net40\unity-custom\nunit.framework.dll + False + + + Library\PackageCache\com.unity.collab-proxy@3351acaba9c9\Lib\Editor\Unity.Plastic.Antlr3.Runtime.dll + False + + + Library\PackageCache\com.unity.collab-proxy@3351acaba9c9\Lib\Editor\Unity.Plastic.Newtonsoft.Json.dll + False + + + Library\PackageCache\com.unity.collab-proxy@3351acaba9c9\Lib\Editor\log4netPlastic.dll + False + + + Library\PackageCache\com.unity.collab-proxy@3351acaba9c9\Lib\Editor\unityplastic.dll + False + + + Library\PackageCache\com.unity.collections@d49facba0036\Unity.Collections.Tests\System.IO.Hashing\System.IO.Hashing.dll + False + + + Library\PackageCache\com.unity.nuget.mono-cecil@d78732e851eb\Mono.Cecil.dll + False + + + Library\PackageCache\com.unity.collections@d49facba0036\Unity.Collections.Tests\System.Runtime.CompilerServices.Unsafe\System.Runtime.CompilerServices.Unsafe.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\PlaybackEngines\AndroidPlayer\Unity.Android.Types.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\PlaybackEngines\AndroidPlayer\Unity.Android.Gradle.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\mscorlib.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Core.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Runtime.Serialization.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Xml.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Xml.Linq.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Numerics.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Numerics.Vectors.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Net.Http.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.IO.Compression.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Microsoft.CSharp.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Data.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Data.DataSetExtensions.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Drawing.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.IO.Compression.FileSystem.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.ComponentModel.Composition.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Transactions.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\Microsoft.Win32.Primitives.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\netstandard.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.AppContext.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Buffers.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Collections.Concurrent.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Collections.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Collections.NonGeneric.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Collections.Specialized.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ComponentModel.Annotations.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ComponentModel.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ComponentModel.EventBasedAsync.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ComponentModel.Primitives.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ComponentModel.TypeConverter.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Console.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Data.Common.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.Contracts.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.Debug.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.FileVersionInfo.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.Process.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.StackTrace.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.TextWriterTraceListener.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.Tools.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.TraceSource.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Drawing.Primitives.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Dynamic.Runtime.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Globalization.Calendars.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Globalization.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Globalization.Extensions.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.Compression.ZipFile.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.FileSystem.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.FileSystem.DriveInfo.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.FileSystem.Primitives.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.FileSystem.Watcher.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.IsolatedStorage.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.MemoryMappedFiles.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.Pipes.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.UnmanagedMemoryStream.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Linq.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Linq.Expressions.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Linq.Parallel.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Linq.Queryable.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Memory.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.Http.Rtc.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.NameResolution.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.NetworkInformation.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.Ping.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.Primitives.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.Requests.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.Security.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.Sockets.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.WebHeaderCollection.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.WebSockets.Client.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.WebSockets.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ObjectModel.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.DispatchProxy.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.Emit.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.Emit.ILGeneration.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.Emit.Lightweight.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.Extensions.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.Primitives.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Resources.Reader.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Resources.ResourceManager.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Resources.Writer.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.CompilerServices.VisualC.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Extensions.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Handles.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.InteropServices.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.InteropServices.RuntimeInformation.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.InteropServices.WindowsRuntime.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Numerics.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Serialization.Formatters.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Serialization.Json.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Serialization.Primitives.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Serialization.Xml.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Claims.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Cryptography.Algorithms.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Cryptography.Csp.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Cryptography.Encoding.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Cryptography.Primitives.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Cryptography.X509Certificates.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Principal.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.SecureString.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ServiceModel.Duplex.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ServiceModel.Http.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ServiceModel.NetTcp.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ServiceModel.Primitives.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ServiceModel.Security.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Text.Encoding.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Text.Encoding.Extensions.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Text.RegularExpressions.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.Overlapped.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.Tasks.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.Tasks.Extensions.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.Tasks.Parallel.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.Thread.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.ThreadPool.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.Timer.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ValueTuple.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Xml.ReaderWriter.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Xml.XDocument.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Xml.XmlDocument.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Xml.XmlSerializer.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Xml.XPath.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Xml.XPath.XDocument.dll + False + + + Library\ScriptAssemblies\UnityEditor.TestRunner.dll + False + + + Library\ScriptAssemblies\UnityEngine.TestRunner.dll + False + + + Library\ScriptAssemblies\Unity.RenderPipelines.Core.Runtime.dll + False + + + Library\ScriptAssemblies\Unity.RenderPipelines.Core.Editor.dll + False + + + Library\ScriptAssemblies\Unity.TextMeshPro.Editor.dll + False + + + Library\ScriptAssemblies\Unity.TextMeshPro.dll + False + + + Library\ScriptAssemblies\Unity.VisualStudio.Editor.dll + False + + + Library\ScriptAssemblies\Unity.AI.Navigation.dll + False + + + Library\ScriptAssemblies\Unity.RenderPipelines.Core.ShaderLibrary.dll + False + + + Library\ScriptAssemblies\Unity.Collections.dll + False + + + Library\ScriptAssemblies\Unity.InputSystem.ForUI.dll + False + + + Library\ScriptAssemblies\Unity.RenderPipelines.GPUDriven.Runtime.dll + False + + + Library\ScriptAssemblies\Unity.Timeline.Editor.dll + False + + + Library\ScriptAssemblies\Unity.Mathematics.dll + False + + + Library\ScriptAssemblies\Unity.RenderPipelines.Universal.Shaders.dll + False + + + Library\ScriptAssemblies\UnityEngine.UI.dll + False + + + Library\ScriptAssemblies\Unity.Multiplayer.Center.Common.dll + False + + + Library\ScriptAssemblies\Unity.RenderPipelines.Universal.Editor.dll + False + + + Library\ScriptAssemblies\Unity.Burst.dll + False + + + Library\ScriptAssemblies\Unity.Timeline.dll + False + + + Library\ScriptAssemblies\Unity.AI.Navigation.Updater.dll + False + + + Library\ScriptAssemblies\Unity.AI.Navigation.Editor.dll + False + + + Library\ScriptAssemblies\PPv2URPConverters.dll + False + + + Library\ScriptAssemblies\Unity.RenderPipelines.Core.Runtime.Shared.dll + False + + + Library\ScriptAssemblies\Unity.Multiplayer.Center.Editor.dll + False + + + Library\ScriptAssemblies\Unity.RenderPipelines.Universal.2D.Runtime.dll + False + + + Library\ScriptAssemblies\Unity.Searcher.Editor.dll + False + + + Library\ScriptAssemblies\Unity.PlasticSCM.Editor.dll + False + + + Library\ScriptAssemblies\Unity.RenderPipelines.Universal.Runtime.dll + False + + + Library\ScriptAssemblies\Unity.Burst.Editor.dll + False + + + Library\ScriptAssemblies\Unity.Rendering.LightTransport.Runtime.dll + False + + + Library\ScriptAssemblies\Unity.Mathematics.Editor.dll + False + + + Library\ScriptAssemblies\Unity.RenderPipelines.Universal.Config.Runtime.dll + False + + + Library\ScriptAssemblies\Unity.RenderPipeline.Universal.ShaderLibrary.dll + False + + + Library\ScriptAssemblies\Unity.Collections.Editor.dll + False + + + Library\ScriptAssemblies\Unity.ShaderGraph.Editor.dll + False + + + Library\ScriptAssemblies\Unity.Rendering.LightTransport.Editor.dll + False + + + Library\ScriptAssemblies\Unity.RenderPipelines.Core.Editor.Shared.dll + False + + + Library\ScriptAssemblies\Unity.InputSystem.dll + False + + + Library\ScriptAssemblies\Unity.Rider.Editor.dll + False + + + Library\ScriptAssemblies\Unity.AI.Navigation.Editor.ConversionSystem.dll + False + + + Library\ScriptAssemblies\UnityEditor.UI.dll + False + + + Library\ScriptAssemblies\Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary.dll + False + + + + + + + + + + + + + + + + + diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj new file mode 100644 index 0000000..828c178 --- /dev/null +++ b/Assembly-CSharp.csproj @@ -0,0 +1,1240 @@ + + + + Temp\obj\$(MSBuildProjectName) + $(BaseIntermediateOutputPath) + false + true + Temp\bin\Debug\ + + + + + + + false + false + 9.0 + + Library + Assembly-CSharp + netstandard2.1 + . + + + 0169;USG0001 + UNITY_6000_2_7;UNITY_6000_2;UNITY_6000;UNITY_5_3_OR_NEWER;UNITY_5_4_OR_NEWER;UNITY_5_5_OR_NEWER;UNITY_5_6_OR_NEWER;UNITY_2017_1_OR_NEWER;UNITY_2017_2_OR_NEWER;UNITY_2017_3_OR_NEWER;UNITY_2017_4_OR_NEWER;UNITY_2018_1_OR_NEWER;UNITY_2018_2_OR_NEWER;UNITY_2018_3_OR_NEWER;UNITY_2018_4_OR_NEWER;UNITY_2019_1_OR_NEWER;UNITY_2019_2_OR_NEWER;UNITY_2019_3_OR_NEWER;UNITY_2019_4_OR_NEWER;UNITY_2020_1_OR_NEWER;UNITY_2020_2_OR_NEWER;UNITY_2020_3_OR_NEWER;UNITY_2021_1_OR_NEWER;UNITY_2021_2_OR_NEWER;UNITY_2021_3_OR_NEWER;UNITY_2022_1_OR_NEWER;UNITY_2022_2_OR_NEWER;UNITY_2022_3_OR_NEWER;UNITY_2023_1_OR_NEWER;UNITY_2023_2_OR_NEWER;UNITY_2023_3_OR_NEWER;UNITY_6000_0_OR_NEWER;UNITY_6000_1_OR_NEWER;UNITY_6000_2_OR_NEWER;PLATFORM_ARCH_64;UNITY_64;UNITY_INCLUDE_TESTS;ENABLE_AR;ENABLE_AUDIO;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_EVENT_QUEUE;ENABLE_MICROPHONE;ENABLE_MULTIPLE_DISPLAYS;ENABLE_PHYSICS;ENABLE_TEXTURE_STREAMING;ENABLE_VIRTUALTEXTURING;ENABLE_LZMA;ENABLE_UNITYEVENTS;ENABLE_VR;ENABLE_WEBCAM;ENABLE_UNITYWEBREQUEST;ENABLE_WWW;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_SERVICES_USE_WEBREQUEST;ENABLE_UNITY_CONSENT;ENABLE_UNITY_CLOUD_IDENTIFIERS;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_NATIVE_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_EDITOR_GAME_SERVICES;ENABLE_UNITY_GAME_SERVICES_ANALYTICS_SUPPORT;ENABLE_CLOUD_LICENSE;ENABLE_EDITOR_HUB_LICENSE;ENABLE_WEBSOCKET_CLIENT;ENABLE_GENERATE_NATIVE_PLUGINS_FOR_ASSEMBLIES_API;ENABLE_DIRECTOR_AUDIO;ENABLE_DIRECTOR_TEXTURE;ENABLE_MANAGED_JOBS;ENABLE_MANAGED_TRANSFORM_JOBS;ENABLE_MANAGED_ANIMATION_JOBS;ENABLE_MANAGED_AUDIO_JOBS;ENABLE_MANAGED_UNITYTLS;INCLUDE_DYNAMIC_GI;ENABLE_SCRIPTING_GC_WBARRIERS;PLATFORM_SUPPORTS_MONO;RENDER_SOFTWARE_CURSOR;ENABLE_MARSHALLING_TESTS;ENABLE_VIDEO;ENABLE_NAVIGATION_OFFMESHLINK_TO_NAVMESHLINK;ENABLE_ACCELERATOR_CLIENT_DEBUGGING;TEXTCORE_1_0_OR_NEWER;EDITOR_ONLY_NAVMESH_BUILDER_DEPRECATED;PLATFORM_STANDALONE_WIN;PLATFORM_STANDALONE;UNITY_STANDALONE_WIN;UNITY_STANDALONE;ENABLE_RUNTIME_GI;ENABLE_MOVIES;ENABLE_NETWORK;ENABLE_NVIDIA;ENABLE_AMD;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_CLOUD_SERVICES_ENGINE_DIAGNOSTICS;ENABLE_OUT_OF_PROCESS_CRASH_HANDLER;ENABLE_CLUSTER_SYNC;ENABLE_CLUSTERINPUT;PLATFORM_UPDATES_TIME_OUTSIDE_OF_PLAYER_LOOP;GFXDEVICE_WAITFOREVENT_MESSAGEPUMP;PLATFORM_USES_EXPLICIT_MEMORY_MANAGER_INITIALIZER;PLATFORM_SUPPORTS_WAIT_FOR_PRESENTATION;PLATFORM_SUPPORTS_SPLIT_GRAPHICS_JOBS;ENABLE_MONO;NET_STANDARD_2_0;NET_STANDARD;NET_STANDARD_2_1;NETSTANDARD;NETSTANDARD2_1;ENABLE_PROFILER;DEBUG;TRACE;UNITY_ASSERTIONS;UNITY_EDITOR;UNITY_EDITOR_64;UNITY_EDITOR_WIN;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_BURST_AOT;UNITY_TEAM_LICENSE;ENABLE_CUSTOM_RENDER_TEXTURE;ENABLE_DIRECTOR;ENABLE_LOCALIZATION;ENABLE_SPRITES;ENABLE_TERRAIN;ENABLE_TILEMAP;ENABLE_TIMELINE;ENABLE_INPUT_SYSTEM;TEXTCORE_FONT_ENGINE_1_5_OR_NEWER;TEXTCORE_TEXT_ENGINE_1_5_OR_NEWER;CSHARP_7_OR_LATER;CSHARP_7_3_OR_NEWER + False + + + true + true + true + true + MSB3277 + + + Package + 2.0.23 + SDK + Game:1 + StandaloneWindows64:19 + 6000.2.7f2 + + + + + + + + + + + + + + + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.AIModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.ARModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.AccessibilityModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.AndroidJNIModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.AnimationModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.AssetBundleModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.AudioModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.ClothModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.ClusterInputModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.ClusterRendererModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.ContentLoadModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.CrashReportingModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.DSPGraphModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.DirectorModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.GIModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.GameCenterModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.GraphicsStateCollectionSerializerModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.GridModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.HierarchyCoreModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.HotReloadModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.IMGUIModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.IdentifiersModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.ImageConversionModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.InputModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.InputForUIModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.InputLegacyModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.InsightsModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.JSONSerializeModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.LocalizationModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.MarshallingModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.MultiplayerModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.ParticleSystemModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.PerformanceReportingModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.PhysicsModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.Physics2DModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.PropertiesModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.RuntimeInitializeOnLoadManagerInitializerModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.ScreenCaptureModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.ShaderVariantAnalyticsModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.SharedInternalsModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.SpriteMaskModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.SpriteShapeModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.StreamingModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.SubstanceModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.SubsystemsModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.TLSModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.TerrainModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.TerrainPhysicsModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.TextCoreFontEngineModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.TextCoreTextEngineModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.TextRenderingModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.TilemapModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UIModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UIElementsModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UmbraModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityAnalyticsModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityAnalyticsCommonModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityConnectModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityConsentModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityCurlModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityTestProtocolModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestAssetBundleModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestAudioModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestTextureModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestWWWModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.VFXModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.VRModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.VehiclesModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.VideoModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.VirtualTexturingModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.WindModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.XRModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.AccessibilityModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.AdaptivePerformanceModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.BuildProfileModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.ClothModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.CoreBusinessMetricsModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.CoreModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.DeviceSimulatorModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.DiagnosticsModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.EditorToolbarModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.EmbreeModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.GIModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.GraphViewModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.GraphicsStateCollectionSerializerModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.GridAndSnapModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.GridModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.InAppPurchasingModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.LevelPlayModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.MultiplayerModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.Physics2DModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.PhysicsModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.PresetsUIModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.PropertiesModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.QuickSearchModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.SafeModeModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.SceneTemplateModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.SceneViewModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.ShaderFoundryModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.SketchUpModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.SpriteMaskModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.SpriteShapeModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.SubstanceModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.TerrainModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.TextCoreFontEngineModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.TextCoreTextEngineModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.TextRenderingModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.TilemapModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.TreeModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.UIAutomationModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.UIBuilderModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.UIElementsModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.UIElementsSamplesModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.UmbraModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.UnityConnectModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.VFXModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.VideoModule.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.XRModule.dll + False + + + Library\PackageCache\com.unity.collections@d49facba0036\Unity.Collections.LowLevel.ILSupport\Unity.Collections.LowLevel.ILSupport.dll + False + + + Library\PackageCache\com.unity.ext.nunit@031a54704bff\net40\unity-custom\nunit.framework.dll + False + + + Library\PackageCache\com.unity.collections@d49facba0036\Unity.Collections.Tests\System.IO.Hashing\System.IO.Hashing.dll + False + + + Library\PackageCache\com.unity.nuget.mono-cecil@d78732e851eb\Mono.Cecil.dll + False + + + Library\PackageCache\com.unity.collections@d49facba0036\Unity.Collections.Tests\System.Runtime.CompilerServices.Unsafe\System.Runtime.CompilerServices.Unsafe.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\PlaybackEngines\AndroidPlayer\Unity.Android.Types.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\PlaybackEngines\AndroidPlayer\Unity.Android.Gradle.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\ref\2.1.0\netstandard.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\Microsoft.Win32.Primitives.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.AppContext.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Buffers.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Collections.Concurrent.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Collections.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Collections.NonGeneric.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Collections.Specialized.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.ComponentModel.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.ComponentModel.EventBasedAsync.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.ComponentModel.Primitives.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.ComponentModel.TypeConverter.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Console.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Data.Common.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Diagnostics.Contracts.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Diagnostics.Debug.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Diagnostics.FileVersionInfo.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Diagnostics.Process.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Diagnostics.StackTrace.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Diagnostics.TextWriterTraceListener.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Diagnostics.Tools.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Diagnostics.TraceSource.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Diagnostics.Tracing.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Drawing.Primitives.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Dynamic.Runtime.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Globalization.Calendars.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Globalization.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Globalization.Extensions.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.IO.Compression.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.IO.Compression.ZipFile.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.IO.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.IO.FileSystem.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.IO.FileSystem.DriveInfo.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.IO.FileSystem.Primitives.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.IO.FileSystem.Watcher.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.IO.IsolatedStorage.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.IO.MemoryMappedFiles.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.IO.Pipes.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.IO.UnmanagedMemoryStream.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Linq.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Linq.Expressions.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Linq.Parallel.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Linq.Queryable.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Memory.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Net.Http.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Net.NameResolution.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Net.NetworkInformation.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Net.Ping.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Net.Primitives.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Net.Requests.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Net.Security.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Net.Sockets.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Net.WebHeaderCollection.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Net.WebSockets.Client.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Net.WebSockets.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Numerics.Vectors.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.ObjectModel.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Reflection.DispatchProxy.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Reflection.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Reflection.Emit.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Reflection.Emit.ILGeneration.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Reflection.Emit.Lightweight.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Reflection.Extensions.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Reflection.Primitives.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Resources.Reader.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Resources.ResourceManager.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Resources.Writer.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Runtime.CompilerServices.VisualC.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Runtime.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Runtime.Extensions.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Runtime.Handles.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Runtime.InteropServices.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Runtime.InteropServices.RuntimeInformation.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Runtime.Numerics.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Runtime.Serialization.Formatters.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Runtime.Serialization.Json.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Runtime.Serialization.Primitives.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Runtime.Serialization.Xml.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Security.Claims.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Security.Cryptography.Algorithms.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Security.Cryptography.Csp.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Security.Cryptography.Encoding.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Security.Cryptography.Primitives.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Security.Cryptography.X509Certificates.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Security.Principal.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Security.SecureString.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Text.Encoding.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Text.Encoding.Extensions.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Text.RegularExpressions.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Threading.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Threading.Overlapped.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Threading.Tasks.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Threading.Tasks.Extensions.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Threading.Tasks.Parallel.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Threading.Thread.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Threading.ThreadPool.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Threading.Timer.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.ValueTuple.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Xml.ReaderWriter.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Xml.XDocument.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Xml.XmlDocument.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Xml.XmlSerializer.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Xml.XPath.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Xml.XPath.XDocument.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\Extensions\2.0.0\System.Runtime.InteropServices.WindowsRuntime.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\mscorlib.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.ComponentModel.Composition.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.Core.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.Data.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.Drawing.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.IO.Compression.FileSystem.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.Net.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.Numerics.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.Runtime.Serialization.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.ServiceModel.Web.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.Transactions.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.Web.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.Windows.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.Xml.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.Xml.Linq.dll + False + + + X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.Xml.Serialization.dll + False + + + Library\ScriptAssemblies\Unity.RenderPipelines.Core.Runtime.dll + False + + + Library\ScriptAssemblies\Unity.RenderPipelines.Core.Editor.dll + False + + + Library\ScriptAssemblies\Unity.TextMeshPro.Editor.dll + False + + + Library\ScriptAssemblies\Unity.TextMeshPro.dll + False + + + Library\ScriptAssemblies\Unity.VisualStudio.Editor.dll + False + + + Library\ScriptAssemblies\Unity.AI.Navigation.dll + False + + + Library\ScriptAssemblies\Unity.RenderPipelines.Core.ShaderLibrary.dll + False + + + Library\ScriptAssemblies\Unity.Collections.dll + False + + + Library\ScriptAssemblies\Unity.InputSystem.ForUI.dll + False + + + Library\ScriptAssemblies\Unity.RenderPipelines.GPUDriven.Runtime.dll + False + + + Library\ScriptAssemblies\Unity.Timeline.Editor.dll + False + + + Library\ScriptAssemblies\Unity.Mathematics.dll + False + + + Library\ScriptAssemblies\Unity.RenderPipelines.Universal.Shaders.dll + False + + + Library\ScriptAssemblies\UnityEngine.UI.dll + False + + + Library\ScriptAssemblies\Unity.Multiplayer.Center.Common.dll + False + + + Library\ScriptAssemblies\Unity.RenderPipelines.Universal.Editor.dll + False + + + Library\ScriptAssemblies\Unity.Burst.dll + False + + + Library\ScriptAssemblies\Unity.Timeline.dll + False + + + Library\ScriptAssemblies\Unity.AI.Navigation.Updater.dll + False + + + Library\ScriptAssemblies\Unity.AI.Navigation.Editor.dll + False + + + Library\ScriptAssemblies\PPv2URPConverters.dll + False + + + Library\ScriptAssemblies\Unity.RenderPipelines.Core.Runtime.Shared.dll + False + + + Library\ScriptAssemblies\Unity.Multiplayer.Center.Editor.dll + False + + + Library\ScriptAssemblies\Unity.RenderPipelines.Universal.2D.Runtime.dll + False + + + Library\ScriptAssemblies\Unity.Searcher.Editor.dll + False + + + Library\ScriptAssemblies\Unity.PlasticSCM.Editor.dll + False + + + Library\ScriptAssemblies\Unity.RenderPipelines.Universal.Runtime.dll + False + + + Library\ScriptAssemblies\Unity.Burst.Editor.dll + False + + + Library\ScriptAssemblies\Unity.Rendering.LightTransport.Runtime.dll + False + + + Library\ScriptAssemblies\Unity.Mathematics.Editor.dll + False + + + Library\ScriptAssemblies\Unity.RenderPipelines.Universal.Config.Runtime.dll + False + + + Library\ScriptAssemblies\Unity.RenderPipeline.Universal.ShaderLibrary.dll + False + + + Library\ScriptAssemblies\Unity.Collections.Editor.dll + False + + + Library\ScriptAssemblies\Unity.ShaderGraph.Editor.dll + False + + + Library\ScriptAssemblies\Unity.Rendering.LightTransport.Editor.dll + False + + + Library\ScriptAssemblies\Unity.RenderPipelines.Core.Editor.Shared.dll + False + + + Library\ScriptAssemblies\Unity.InputSystem.dll + False + + + Library\ScriptAssemblies\Unity.Rider.Editor.dll + False + + + Library\ScriptAssemblies\Unity.AI.Navigation.Editor.ConversionSystem.dll + False + + + Library\ScriptAssemblies\UnityEditor.UI.dll + False + + + Library\ScriptAssemblies\Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary.dll + False + + + + + + + + + + + + + + + + diff --git a/Assets/InputSystem_Actions.inputactions b/Assets/InputSystem_Actions.inputactions new file mode 100644 index 0000000..1a12cb9 --- /dev/null +++ b/Assets/InputSystem_Actions.inputactions @@ -0,0 +1,1057 @@ +{ + "name": "InputSystem_Actions", + "maps": [ + { + "name": "Player", + "id": "df70fa95-8a34-4494-b137-73ab6b9c7d37", + "actions": [ + { + "name": "Move", + "type": "Value", + "id": "351f2ccd-1f9f-44bf-9bec-d62ac5c5f408", + "expectedControlType": "Vector2", + "processors": "", + "interactions": "", + "initialStateCheck": true + }, + { + "name": "Look", + "type": "Value", + "id": "6b444451-8a00-4d00-a97e-f47457f736a8", + "expectedControlType": "Vector2", + "processors": "", + "interactions": "", + "initialStateCheck": true + }, + { + "name": "Attack", + "type": "Button", + "id": "6c2ab1b8-8984-453a-af3d-a3c78ae1679a", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Interact", + "type": "Button", + "id": "852140f2-7766-474d-8707-702459ba45f3", + "expectedControlType": "Button", + "processors": "", + "interactions": "Hold", + "initialStateCheck": false + }, + { + "name": "Crouch", + "type": "Button", + "id": "27c5f898-bc57-4ee1-8800-db469aca5fe3", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Jump", + "type": "Button", + "id": "f1ba0d36-48eb-4cd5-b651-1c94a6531f70", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Previous", + "type": "Button", + "id": "2776c80d-3c14-4091-8c56-d04ced07a2b0", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Next", + "type": "Button", + "id": "b7230bb6-fc9b-4f52-8b25-f5e19cb2c2ba", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Sprint", + "type": "Button", + "id": "641cd816-40e6-41b4-8c3d-04687c349290", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + } + ], + "bindings": [ + { + "name": "", + "id": "978bfe49-cc26-4a3d-ab7b-7d7a29327403", + "path": "/leftStick", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Move", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "WASD", + "id": "00ca640b-d935-4593-8157-c05846ea39b3", + "path": "Dpad", + "interactions": "", + "processors": "", + "groups": "", + "action": "Move", + "isComposite": true, + "isPartOfComposite": false + }, + { + "name": "up", + "id": "e2062cb9-1b15-46a2-838c-2f8d72a0bdd9", + "path": "/w", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Move", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "up", + "id": "8180e8bd-4097-4f4e-ab88-4523101a6ce9", + "path": "/upArrow", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Move", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "down", + "id": "320bffee-a40b-4347-ac70-c210eb8bc73a", + "path": "/s", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Move", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "down", + "id": "1c5327b5-f71c-4f60-99c7-4e737386f1d1", + "path": "/downArrow", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Move", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "left", + "id": "d2581a9b-1d11-4566-b27d-b92aff5fabbc", + "path": "/a", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Move", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "left", + "id": "2e46982e-44cc-431b-9f0b-c11910bf467a", + "path": "/leftArrow", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Move", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "right", + "id": "fcfe95b8-67b9-4526-84b5-5d0bc98d6400", + "path": "/d", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Move", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "right", + "id": "77bff152-3580-4b21-b6de-dcd0c7e41164", + "path": "/rightArrow", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Move", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "", + "id": "1635d3fe-58b6-4ba9-a4e2-f4b964f6b5c8", + "path": "/{Primary2DAxis}", + "interactions": "", + "processors": "", + "groups": "XR", + "action": "Move", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "3ea4d645-4504-4529-b061-ab81934c3752", + "path": "/stick", + "interactions": "", + "processors": "", + "groups": "Joystick", + "action": "Move", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "c1f7a91b-d0fd-4a62-997e-7fb9b69bf235", + "path": "/rightStick", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Look", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "8c8e490b-c610-4785-884f-f04217b23ca4", + "path": "/delta", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse;Touch", + "action": "Look", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "3e5f5442-8668-4b27-a940-df99bad7e831", + "path": "/{Hatswitch}", + "interactions": "", + "processors": "", + "groups": "Joystick", + "action": "Look", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "143bb1cd-cc10-4eca-a2f0-a3664166fe91", + "path": "/buttonWest", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Attack", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "05f6913d-c316-48b2-a6bb-e225f14c7960", + "path": "/leftButton", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Attack", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "886e731e-7071-4ae4-95c0-e61739dad6fd", + "path": "/primaryTouch/tap", + "interactions": "", + "processors": "", + "groups": ";Touch", + "action": "Attack", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "ee3d0cd2-254e-47a7-a8cb-bc94d9658c54", + "path": "/trigger", + "interactions": "", + "processors": "", + "groups": "Joystick", + "action": "Attack", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "8255d333-5683-4943-a58a-ccb207ff1dce", + "path": "/{PrimaryAction}", + "interactions": "", + "processors": "", + "groups": "XR", + "action": "Attack", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "b3c1c7f0-bd20-4ee7-a0f1-899b24bca6d7", + "path": "/enter", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Attack", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "cbac6039-9c09-46a1-b5f2-4e5124ccb5ed", + "path": "/2", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Next", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "e15ca19d-e649-4852-97d5-7fe8ccc44e94", + "path": "/dpad/right", + "interactions": "", + "processors": "", + "groups": "Gamepad", + "action": "Next", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "f2e9ba44-c423-42a7-ad56-f20975884794", + "path": "/leftShift", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Sprint", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "8cbb2f4b-a784-49cc-8d5e-c010b8c7f4e6", + "path": "/leftStickPress", + "interactions": "", + "processors": "", + "groups": "Gamepad", + "action": "Sprint", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "d8bf24bf-3f2f-4160-a97c-38ec1eb520ba", + "path": "/trigger", + "interactions": "", + "processors": "", + "groups": "XR", + "action": "Sprint", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "eb40bb66-4559-4dfa-9a2f-820438abb426", + "path": "/space", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Jump", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "daba33a1-ad0c-4742-a909-43ad1cdfbeb6", + "path": "/buttonSouth", + "interactions": "", + "processors": "", + "groups": "Gamepad", + "action": "Jump", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "603f3daf-40bd-4854-8724-93e8017f59e3", + "path": "/secondaryButton", + "interactions": "", + "processors": "", + "groups": "XR", + "action": "Jump", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "1534dc16-a6aa-499d-9c3a-22b47347b52a", + "path": "/1", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Previous", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "25060bbd-a3a6-476e-8fba-45ae484aad05", + "path": "/dpad/left", + "interactions": "", + "processors": "", + "groups": "Gamepad", + "action": "Previous", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "1c04ea5f-b012-41d1-a6f7-02e963b52893", + "path": "/e", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Interact", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "b3f66d0b-7751-423f-908b-a11c5bd95930", + "path": "/buttonNorth", + "interactions": "", + "processors": "", + "groups": "Gamepad", + "action": "Interact", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "4f4649ac-64a8-4a73-af11-b3faef356a4d", + "path": "/buttonEast", + "interactions": "", + "processors": "", + "groups": "Gamepad", + "action": "Crouch", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "36e52cba-0905-478e-a818-f4bfcb9f3b9a", + "path": "/c", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Crouch", + "isComposite": false, + "isPartOfComposite": false + } + ] + }, + { + "name": "UI", + "id": "272f6d14-89ba-496f-b7ff-215263d3219f", + "actions": [ + { + "name": "Navigate", + "type": "PassThrough", + "id": "c95b2375-e6d9-4b88-9c4c-c5e76515df4b", + "expectedControlType": "Vector2", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Submit", + "type": "Button", + "id": "7607c7b6-cd76-4816-beef-bd0341cfe950", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Cancel", + "type": "Button", + "id": "15cef263-9014-4fd5-94d9-4e4a6234a6ef", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Point", + "type": "PassThrough", + "id": "32b35790-4ed0-4e9a-aa41-69ac6d629449", + "expectedControlType": "Vector2", + "processors": "", + "interactions": "", + "initialStateCheck": true + }, + { + "name": "Click", + "type": "PassThrough", + "id": "3c7022bf-7922-4f7c-a998-c437916075ad", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": true + }, + { + "name": "RightClick", + "type": "PassThrough", + "id": "44b200b1-1557-4083-816c-b22cbdf77ddf", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "MiddleClick", + "type": "PassThrough", + "id": "dad70c86-b58c-4b17-88ad-f5e53adf419e", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "ScrollWheel", + "type": "PassThrough", + "id": "0489e84a-4833-4c40-bfae-cea84b696689", + "expectedControlType": "Vector2", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "TrackedDevicePosition", + "type": "PassThrough", + "id": "24908448-c609-4bc3-a128-ea258674378a", + "expectedControlType": "Vector3", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "TrackedDeviceOrientation", + "type": "PassThrough", + "id": "9caa3d8a-6b2f-4e8e-8bad-6ede561bd9be", + "expectedControlType": "Quaternion", + "processors": "", + "interactions": "", + "initialStateCheck": false + } + ], + "bindings": [ + { + "name": "Gamepad", + "id": "809f371f-c5e2-4e7a-83a1-d867598f40dd", + "path": "2DVector", + "interactions": "", + "processors": "", + "groups": "", + "action": "Navigate", + "isComposite": true, + "isPartOfComposite": false + }, + { + "name": "up", + "id": "14a5d6e8-4aaf-4119-a9ef-34b8c2c548bf", + "path": "/leftStick/up", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "up", + "id": "9144cbe6-05e1-4687-a6d7-24f99d23dd81", + "path": "/rightStick/up", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "down", + "id": "2db08d65-c5fb-421b-983f-c71163608d67", + "path": "/leftStick/down", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "down", + "id": "58748904-2ea9-4a80-8579-b500e6a76df8", + "path": "/rightStick/down", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "left", + "id": "8ba04515-75aa-45de-966d-393d9bbd1c14", + "path": "/leftStick/left", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "left", + "id": "712e721c-bdfb-4b23-a86c-a0d9fcfea921", + "path": "/rightStick/left", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "right", + "id": "fcd248ae-a788-4676-a12e-f4d81205600b", + "path": "/leftStick/right", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "right", + "id": "1f04d9bc-c50b-41a1-bfcc-afb75475ec20", + "path": "/rightStick/right", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "", + "id": "fb8277d4-c5cd-4663-9dc7-ee3f0b506d90", + "path": "/dpad", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "Joystick", + "id": "e25d9774-381c-4a61-b47c-7b6b299ad9f9", + "path": "2DVector", + "interactions": "", + "processors": "", + "groups": "", + "action": "Navigate", + "isComposite": true, + "isPartOfComposite": false + }, + { + "name": "up", + "id": "3db53b26-6601-41be-9887-63ac74e79d19", + "path": "/stick/up", + "interactions": "", + "processors": "", + "groups": "Joystick", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "down", + "id": "0cb3e13e-3d90-4178-8ae6-d9c5501d653f", + "path": "/stick/down", + "interactions": "", + "processors": "", + "groups": "Joystick", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "left", + "id": "0392d399-f6dd-4c82-8062-c1e9c0d34835", + "path": "/stick/left", + "interactions": "", + "processors": "", + "groups": "Joystick", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "right", + "id": "942a66d9-d42f-43d6-8d70-ecb4ba5363bc", + "path": "/stick/right", + "interactions": "", + "processors": "", + "groups": "Joystick", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "Keyboard", + "id": "ff527021-f211-4c02-933e-5976594c46ed", + "path": "2DVector", + "interactions": "", + "processors": "", + "groups": "", + "action": "Navigate", + "isComposite": true, + "isPartOfComposite": false + }, + { + "name": "up", + "id": "563fbfdd-0f09-408d-aa75-8642c4f08ef0", + "path": "/w", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "up", + "id": "eb480147-c587-4a33-85ed-eb0ab9942c43", + "path": "/upArrow", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "down", + "id": "2bf42165-60bc-42ca-8072-8c13ab40239b", + "path": "/s", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "down", + "id": "85d264ad-e0a0-4565-b7ff-1a37edde51ac", + "path": "/downArrow", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "left", + "id": "74214943-c580-44e4-98eb-ad7eebe17902", + "path": "/a", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "left", + "id": "cea9b045-a000-445b-95b8-0c171af70a3b", + "path": "/leftArrow", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "right", + "id": "8607c725-d935-4808-84b1-8354e29bab63", + "path": "/d", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "right", + "id": "4cda81dc-9edd-4e03-9d7c-a71a14345d0b", + "path": "/rightArrow", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "", + "id": "9e92bb26-7e3b-4ec4-b06b-3c8f8e498ddc", + "path": "*/{Submit}", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse;Gamepad;Touch;Joystick;XR", + "action": "Submit", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "82627dcc-3b13-4ba9-841d-e4b746d6553e", + "path": "*/{Cancel}", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse;Gamepad;Touch;Joystick;XR", + "action": "Cancel", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "c52c8e0b-8179-41d3-b8a1-d149033bbe86", + "path": "/position", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Point", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "e1394cbc-336e-44ce-9ea8-6007ed6193f7", + "path": "/position", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Point", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "5693e57a-238a-46ed-b5ae-e64e6e574302", + "path": "/touch*/position", + "interactions": "", + "processors": "", + "groups": "Touch", + "action": "Point", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "4faf7dc9-b979-4210-aa8c-e808e1ef89f5", + "path": "/leftButton", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Click", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "8d66d5ba-88d7-48e6-b1cd-198bbfef7ace", + "path": "/tip", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Click", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "47c2a644-3ebc-4dae-a106-589b7ca75b59", + "path": "/touch*/press", + "interactions": "", + "processors": "", + "groups": "Touch", + "action": "Click", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "bb9e6b34-44bf-4381-ac63-5aa15d19f677", + "path": "/trigger", + "interactions": "", + "processors": "", + "groups": "XR", + "action": "Click", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "38c99815-14ea-4617-8627-164d27641299", + "path": "/scroll", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "ScrollWheel", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "4c191405-5738-4d4b-a523-c6a301dbf754", + "path": "/rightButton", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "RightClick", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "24066f69-da47-44f3-a07e-0015fb02eb2e", + "path": "/middleButton", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "MiddleClick", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "7236c0d9-6ca3-47cf-a6ee-a97f5b59ea77", + "path": "/devicePosition", + "interactions": "", + "processors": "", + "groups": "XR", + "action": "TrackedDevicePosition", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "23e01e3a-f935-4948-8d8b-9bcac77714fb", + "path": "/deviceRotation", + "interactions": "", + "processors": "", + "groups": "XR", + "action": "TrackedDeviceOrientation", + "isComposite": false, + "isPartOfComposite": false + } + ] + } + ], + "controlSchemes": [ + { + "name": "Keyboard&Mouse", + "bindingGroup": "Keyboard&Mouse", + "devices": [ + { + "devicePath": "", + "isOptional": false, + "isOR": false + }, + { + "devicePath": "", + "isOptional": false, + "isOR": false + } + ] + }, + { + "name": "Gamepad", + "bindingGroup": "Gamepad", + "devices": [ + { + "devicePath": "", + "isOptional": false, + "isOR": false + } + ] + }, + { + "name": "Touch", + "bindingGroup": "Touch", + "devices": [ + { + "devicePath": "", + "isOptional": false, + "isOR": false + } + ] + }, + { + "name": "Joystick", + "bindingGroup": "Joystick", + "devices": [ + { + "devicePath": "", + "isOptional": false, + "isOR": false + } + ] + }, + { + "name": "XR", + "bindingGroup": "XR", + "devices": [ + { + "devicePath": "", + "isOptional": false, + "isOR": false + } + ] + } + ] +} \ No newline at end of file diff --git a/Assets/InputSystem_Actions.inputactions.meta b/Assets/InputSystem_Actions.inputactions.meta new file mode 100644 index 0000000..6b38b04 --- /dev/null +++ b/Assets/InputSystem_Actions.inputactions.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 052faaac586de48259a63d0c4782560b +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 8404be70184654265930450def6a9037, type: 3} + generateWrapperCode: 0 + wrapperCodePath: + wrapperClassName: + wrapperCodeNamespace: diff --git a/Assets/NanoBrain.meta b/Assets/NanoBrain.meta new file mode 100644 index 0000000..f63dc81 --- /dev/null +++ b/Assets/NanoBrain.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 235b4d678b27ec7458f2b47a618b5355 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/NanoBrain/Editor.meta b/Assets/NanoBrain/Editor.meta new file mode 100644 index 0000000..090b3ac --- /dev/null +++ b/Assets/NanoBrain/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3aedf57a50b6dfa46a59457c87b8ef9d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/NanoBrain/Editor/GraphEditorWindow.cs b/Assets/NanoBrain/Editor/GraphEditorWindow.cs new file mode 100644 index 0000000..e66eddb --- /dev/null +++ b/Assets/NanoBrain/Editor/GraphEditorWindow.cs @@ -0,0 +1,204 @@ +using UnityEditor; +using UnityEngine; +using System.Linq; +using System.Collections.Generic; + +public class Layer { + public int ix = 0; + public List neuroids = new(); +} + +public class GraphEditorWindow : EditorWindow { + private Neuroid currentNeuroid; + private List allNeuroids; + private Dictionary neuroidPositions = new(); + + private List layers = new(); + + private void OnEnable() { + EditorApplication.update += EditorUpdate; + Selection.selectionChanged += OnSelectionChange; + SelectNeuron(); + } + + private void BuildLayers(List neuroids) { + if (neuroids == null) + return; + + // A temporary list to track what's been added to layers + this.layers = new(); + HashSet neuronVisited = new(); + int layerIx = 0; + + // While there are unvisited neuroid + while (neuroids.Any(neuroid => !neuronVisited.Contains(neuroid))) { + // Create the next layer + Layer currentLayer = new() { ix = layerIx }; + int neuroidIx = 0; + + foreach (Neuroid neuroid in neuroids) { + // If this neuroid is not visited while its output neuroid is visited + if (!neuronVisited.Contains(neuroid) && (neuronVisited.Contains(neuroid.outputNeuroid) || neuroid.outputNeuroid == null)) { + // Add it to the next layer + currentLayer.neuroids.Add(neuroid); + // Register it as visited + neuronVisited.Add(neuroid); + // Store its position + Vector2Int neuroidPosition = new(layerIx, neuroidIx); + neuroidPositions[neuroid] = neuroidPosition; + neuroidIx++; + } + } + + if (currentLayer.neuroids.Count > 0) { + this.layers.Add(currentLayer); + layerIx++; + } + } + } + + private void OnDisable() { + EditorApplication.update -= EditorUpdate; + Selection.selectionChanged -= OnSelectionChange; + } + + private void OnSelectionChange() { + SelectNeuron(); + Repaint(); + } + + private void EditorUpdate() { + if (EditorApplication.isPlaying) + Repaint(); + } + + private void OnGUI() { + GUILayout.Label("Graph Visualizer", EditorStyles.boldLabel); + + DrawGraph(); + } + + private void DrawGraph() { + if (currentNeuroid == null) + return; + + foreach (Layer layer in layers) + DrawLayer(layer); + // int column = 100; + // int row = 200; + // Vector3 parentPos = new(column, row, 0.1f); + // Handles.DrawSolidDisc(parentPos, Vector3.forward, 15); + + // DrawLayer(2, parentPos); + } + + // private void DrawLayer(int layerIx, Vector3 parentPos) { + // int column = layerIx * 100; + // int nodeCount = currentNeuroid.synapses.Count; + // float maxValue = 0; + // foreach (Synapse synapse in currentNeuroid.synapses.Values) { + // float value = synapse.value.magnitude; + // if (value > maxValue) + // maxValue = value; + // } + + // float spacing = 200f / nodeCount; // Calculate spacing + // float margin = 100 + spacing / 3; + // int i = 0; + // foreach (Synapse synapse in currentNeuroid.synapses.Values) { + // Vector3 pos = new(column, margin + i * spacing); + + // float brightness = synapse.weight / 10.0f; + // Handles.color = new Color(brightness, brightness, brightness); + // Handles.DrawLine(parentPos - Vector3.forward, pos); + + // float size = synapse.value.magnitude / maxValue * 20; + // Handles.color = Color.white; + // Handles.DrawSolidDisc(pos, Vector3.forward, size); + // i++; + // } + // } + + private void DrawLayer(Layer layer) { + int column = layer.ix * 100; + int nodeCount = layer.neuroids.Count; + float maxValue = 0; + foreach (Neuroid neuroid in layer.neuroids) { + float value = neuroid.outputValue.magnitude; + if (value > maxValue) + maxValue = value; + } + float spacing = 200f / nodeCount; + float margin = 100 + spacing / 2; + foreach (Neuroid layerNeuroid in layer.neuroids) { + Vector2Int layerNeuroidPos = this.neuroidPositions[layerNeuroid]; + Vector3 parentPos = new(100 + layerNeuroidPos.x * 100, margin + layerNeuroidPos.y * spacing, 0.1f); + + int i = 0; + float inputSpacing = 200f / layerNeuroid.synapses.Count; + float inputMargin = 100 + inputSpacing / 2; + foreach (Synapse synapse in layerNeuroid.synapses.Values) { + if (synapse.neuroid != null) { + Vector2Int inputNeuroidPos = this.neuroidPositions[synapse.neuroid]; + Vector3 pos = new(100 + inputNeuroidPos.x * 100, inputMargin + inputNeuroidPos.y * inputSpacing, 0.0f); + + float brightness = synapse.weight / 10.0f; + Handles.color = new Color(brightness, brightness, brightness); + Handles.DrawLine(parentPos, pos); + } + } + + float size = layerNeuroid.outputValue.magnitude / maxValue * 20; + Handles.color = Color.white; + Handles.DrawSolidDisc(parentPos, Vector3.forward, size); + Rect neuronRect = new(parentPos.x-size, parentPos.y-size, size*2, size*2); + if (neuronRect.Contains(Event.current.mousePosition)) + HandleMouseHover(layerNeuroid, neuronRect); + i++; + + } + } + + private void HandleMouseHover(Neuroid neuroid, Rect rect) { + // Draw the tooltip + GUIContent tooltip = new($"{neuroid.name}\n Value: {neuroid.outputValue}"); + Vector2 mousePosition = Event.current.mousePosition; + + // Display tooltip with some offset + Vector2 tooltipSize = GUI.skin.box.CalcSize(tooltip); + Rect tooltipRect = new Rect(mousePosition.x + 10, mousePosition.y + 10, tooltipSize.x, tooltipSize.y); + + GUI.Box(tooltipRect, tooltip); + } + + + // Update node colors based on selected GameObjects + private void SelectNeuron() { + GameObject[] selectedObjects = Selection.gameObjects; + if (selectedObjects.Length == 0) + return; + + GameObject selectedObject = selectedObjects[0]; + Boid boid = selectedObject.GetComponent(); + if (boid == null) + return; + + Neuroid neuroid = boid.totalForce; + this.currentNeuroid = neuroid; + if (neuroid == null) + this.allNeuroids = new(); + else + this.allNeuroids = neuroid.net.neuroids; + + + //Debug.Log($"Neuroncount = {this.allNeuroids.Count}"); + BuildLayers(this.allNeuroids); + Debug.Log($"Layercount = {this.layers.Count}"); + + } + + [MenuItem("Window/Graph Visualizer")] + public static void ShowWindow() { + GetWindow("Graph Visualizer"); + } +} diff --git a/Assets/NanoBrain/Editor/GraphEditorWindow.cs.meta b/Assets/NanoBrain/Editor/GraphEditorWindow.cs.meta new file mode 100644 index 0000000..a8a1aa1 --- /dev/null +++ b/Assets/NanoBrain/Editor/GraphEditorWindow.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 26e68838038ea5243ae57bc81f4db8a8 \ No newline at end of file diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs new file mode 100644 index 0000000..5a40f88 --- /dev/null +++ b/Assets/NanoBrain/Neuroid.cs @@ -0,0 +1,109 @@ +using System.Collections.Generic; +using UnityEngine; +using System.Linq; + +public class Synapse { + public Synapse(Neuroid neuroid, Vector3 value, float weight) { + this.neuroid = neuroid; + this.value = value; + this.weight = weight; + } + public Neuroid neuroid; + public Vector3 value; + public float weight; +} + +public class NeuroidNetwork { + public List neuroids = new(); + + public Neuroid AddNeuron() { + Neuroid neuroid = new(this); + return neuroid; + } +} + +public class Neuroid { + public int id; + public string name; + + public readonly Dictionary synapses = new(); + + public Vector3 outputValue; + public Neuroid outputNeuroid; + public int outputNeurix; + + public enum Mode { + Sum, + Average, + } + public Mode mode = Mode.Sum; + + + public NeuroidNetwork net; + + public Neuroid(NeuroidNetwork net) { + this.net = net; + this.net.neuroids.Add(this); + } + + public void SetOutputTo(Neuroid neuroid) { + this.outputNeuroid = neuroid; + // neuroid.inputNeuroids.Add(this); + this.outputNeurix = this.id; + } + + public void ResetWeights() { + foreach (Synapse synapse in synapses.Values) + synapse.weight = 1.0f; + } + + public void SetWeight(Neuroid input, float weight) { + if (synapses.ContainsKey(input.id)) + synapses[input.id] = new(input, synapses[input.id].value, weight); + else + synapses[input.id] = new(input, Vector3.zero, weight); + } + + public void GetInputFrom(Neuroid input, float weight = 1.0f) { + input.id = this.synapses.Count; + input.SetOutputTo(this); + synapses[input.id] = new(input, Vector3.zero, weight); + } + + public void SetInput(int inputId, Vector3 value) { + if (synapses.ContainsKey(inputId)) + synapses[inputId].value = value; + else + synapses[inputId] = new(null, value, 1.0f); + UpdateState(); + } + public void SetInput(int inputIx, Vector3 value, float weight) { + if (synapses.ContainsKey(inputIx)) { + Synapse synapse = synapses[inputIx]; + synapse.value = value; + synapse.weight = weight; + } + else + synapses[inputIx] = new(null, value, weight); + UpdateState(); + } + + void UpdateState() { + Vector3 sum = Vector3.zero; + foreach (Synapse synapse in synapses.Values) + sum += synapse.value * synapse.weight; + + this.outputValue = Activation(sum); + this.outputNeuroid?.SetInput(this.outputNeurix, this.outputValue); + } + + Vector3 Activation(Vector3 sum) { + return mode switch { + Mode.Sum => sum, + Mode.Average => sum / synapses.Count, + _ => sum, + }; + //return sum; //(sum.magnitude > 0.5f) ? sum : Vector3.zero; + } +} + diff --git a/Assets/NanoBrain/Neuroid.cs.meta b/Assets/NanoBrain/Neuroid.cs.meta new file mode 100644 index 0000000..1c633f0 --- /dev/null +++ b/Assets/NanoBrain/Neuroid.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 771f64aec709af240a39b1d918bbc829 \ No newline at end of file diff --git a/Assets/NanoBrain/NeuroidBehaviour.cs b/Assets/NanoBrain/NeuroidBehaviour.cs new file mode 100644 index 0000000..411f2a8 --- /dev/null +++ b/Assets/NanoBrain/NeuroidBehaviour.cs @@ -0,0 +1,14 @@ +using UnityEngine; + +public class NeuroidBehaviour : MonoBehaviour +{ + public Neuroid neuroid; + public GameObject thing; + + public void Start() { + Debug.Log("Neuroid start"); + } + public void Update() { + Debug.Log("Neuroid update"); + } +} diff --git a/Assets/NanoBrain/NeuroidBehaviour.cs.meta b/Assets/NanoBrain/NeuroidBehaviour.cs.meta new file mode 100644 index 0000000..a6a62af --- /dev/null +++ b/Assets/NanoBrain/NeuroidBehaviour.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: dded3a10fb4fd894383b44483dd47382 \ No newline at end of file diff --git a/Assets/Scenes.meta b/Assets/Scenes.meta new file mode 100644 index 0000000..e59fb45 --- /dev/null +++ b/Assets/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9c53962885c2c4f449125a979d6ad240 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/Ants.meta b/Assets/Scenes/Ants.meta new file mode 100644 index 0000000..0aa7aee --- /dev/null +++ b/Assets/Scenes/Ants.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 246e42bf1c25a1e4cbfdbc5e96380e9e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/Boids.meta b/Assets/Scenes/Boids.meta new file mode 100644 index 0000000..a2fc235 --- /dev/null +++ b/Assets/Scenes/Boids.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a1c9265a3bf408f418dddc32d192849b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/Boids/Boid Graph.asset b/Assets/Scenes/Boids/Boid Graph.asset new file mode 100644 index 0000000..bd6ef42 --- /dev/null +++ b/Assets/Scenes/Boids/Boid Graph.asset @@ -0,0 +1,17 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 95e66c6366d904e98bc83428217d4fd7, type: 3} + m_Name: Boid Graph + m_EditorClassIdentifier: Unity.VisualScripting.Flow::Unity.VisualScripting.ScriptGraphAsset + _data: + _json: '{"graph":{"variables":{"Kind":"Flow","collection":{"$content":[],"$version":"A"},"$version":"A"},"controlInputDefinitions":[],"controlOutputDefinitions":[],"valueInputDefinitions":[],"valueOutputDefinitions":[],"title":null,"summary":null,"pan":{"x":0.0,"y":0.0},"zoom":1.0,"elements":[],"$version":"A"}}' + _objectReferences: [] diff --git a/Assets/Scenes/Boids/Boid Graph.asset.meta b/Assets/Scenes/Boids/Boid Graph.asset.meta new file mode 100644 index 0000000..3cefbaf --- /dev/null +++ b/Assets/Scenes/Boids/Boid Graph.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1a94b234cb4edce40bbe7e748f0508b3 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/Boids/Boids.unity b/Assets/Scenes/Boids/Boids.unity new file mode 100644 index 0000000..eec3e44 --- /dev/null +++ b/Assets/Scenes/Boids/Boids.unity @@ -0,0 +1,416 @@ +%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: 10 + 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: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 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_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 13 + m_BakeOnSceneLoad: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + 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_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: 1 + m_PVRFilteringGaussRadiusAO: 1 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 20201, guid: 0000000000000000f000000000000000, type: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 3 + 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 + buildHeightMesh: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &301943977 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 301943980} + - component: {fileID: 301943979} + - component: {fileID: 301943978} + m_Layer: 0 + m_Name: Swarm + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &301943978 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 301943977} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0464906885ae3494f8fd0314719fb2db, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::SwarmControl + speed: 0.5 + inertia: 0.1 + alignmentForce: 0 + cohesionForce: 10 + separationForce: 5 + separationDistance: 0.5 + bodyForce: 20 +--- !u!114 &301943979 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 301943977} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ec888ca5333d45a438f9f417fa5ce135, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::SwarmSpawn + count: 100 + boidPrefab: {fileID: 8702527964058765413, guid: f9c706268554ce449a8773675b2864b8, type: 3} + spawnAreaSize: {x: 0.5, y: 0.5, z: 0.5} + minDelay: 0.1 + maxDelay: 1 +--- !u!4 &301943980 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 301943977} + serializedVersion: 2 + 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_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &837238090 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 837238092} + - component: {fileID: 837238091} + - component: {fileID: 837238093} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &837238091 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 837238090} + m_Enabled: 1 + serializedVersion: 11 + m_Type: 1 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ForceVisible: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 + m_LightUnit: 1 + m_LuxAtDistance: 1 + m_EnableSpotReflector: 1 +--- !u!4 &837238092 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 837238090} + serializedVersion: 2 + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!114 &837238093 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 837238090} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 474bcb49853aa07438625e644c072ee6, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.UniversalAdditionalLightData + m_UsePipelineSettings: 1 + m_AdditionalLightsShadowResolutionTier: 2 + m_CustomShadowLayers: 0 + m_LightCookieSize: {x: 1, y: 1} + m_LightCookieOffset: {x: 0, y: 0} + m_SoftShadowQuality: 0 + m_RenderingLayersMask: + serializedVersion: 0 + m_Bits: 1 + m_ShadowRenderingLayersMask: + serializedVersion: 0 + m_Bits: 1 + m_Version: 4 + m_LightLayerMask: 1 + m_ShadowLayerMask: 1 + m_RenderingLayers: 1 + m_ShadowRenderingLayers: 1 +--- !u!1 &1633626499 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1633626502} + - component: {fileID: 1633626501} + - component: {fileID: 1633626500} + 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 &1633626500 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1633626499} + m_Enabled: 1 +--- !u!20 &1633626501 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1633626499} + 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_Iso: 200 + m_ShutterSpeed: 0.005 + m_Aperture: 16 + m_FocusDistance: 10 + m_FocalLength: 50 + m_BladeCount: 5 + m_Curvature: {x: 2, y: 11} + m_BarrelClipping: 0.25 + m_Anamorphism: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + 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: 0 + 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 &1633626502 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1633626499} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1660057539 &9223372036854775807 +SceneRoots: + m_ObjectHideFlags: 0 + m_Roots: + - {fileID: 1633626502} + - {fileID: 837238092} + - {fileID: 301943980} diff --git a/Assets/Scenes/Boids/Boids.unity.meta b/Assets/Scenes/Boids/Boids.unity.meta new file mode 100644 index 0000000..a257712 --- /dev/null +++ b/Assets/Scenes/Boids/Boids.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e8c08a710b183a848a4da458a0f6be88 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/Boids/Materials.meta b/Assets/Scenes/Boids/Materials.meta new file mode 100644 index 0000000..91a2ccd --- /dev/null +++ b/Assets/Scenes/Boids/Materials.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 09641e25b1492174996b16f4e42a9db0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/Boids/Materials/White.mat b/Assets/Scenes/Boids/Materials/White.mat new file mode 100644 index 0000000..2259a75 --- /dev/null +++ b/Assets/Scenes/Boids/Materials/White.mat @@ -0,0 +1,137 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-4785697467283256856 +MonoBehaviour: + m_ObjectHideFlags: 11 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Editor::UnityEditor.Rendering.Universal.AssetVersion + version: 10 +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: White + m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: + RenderType: Opaque + disabledShaderPasses: + - MOTIONVECTORS + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BaseMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _SpecGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_Lightmaps: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_LightmapsInd: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_ShadowMasks: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _AddPrecomputedVelocity: 0 + - _AlphaClip: 0 + - _AlphaToMask: 0 + - _Blend: 0 + - _BlendModePreserveSpecular: 1 + - _BumpScale: 1 + - _ClearCoatMask: 0 + - _ClearCoatSmoothness: 0 + - _Cull: 2 + - _Cutoff: 0.5 + - _DetailAlbedoMapScale: 1 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _DstBlendAlpha: 0 + - _EnvironmentReflections: 1 + - _GlossMapScale: 0 + - _Glossiness: 0 + - _GlossyReflections: 0 + - _Metallic: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.005 + - _QueueOffset: 0 + - _ReceiveShadows: 1 + - _Smoothness: 0.5 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _SrcBlendAlpha: 1 + - _Surface: 0 + - _WorkflowMode: 1 + - _XRMotionVectorsPass: 1 + - _ZWrite: 1 + m_Colors: + - _BaseColor: {r: 1, g: 1, b: 1, a: 1} + - _Color: {r: 1, g: 1, b: 1, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} + m_BuildTextureStacks: [] + m_AllowLocking: 1 diff --git a/Assets/Scenes/Boids/Materials/White.mat.meta b/Assets/Scenes/Boids/Materials/White.mat.meta new file mode 100644 index 0000000..3bcc57f --- /dev/null +++ b/Assets/Scenes/Boids/Materials/White.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a79ccc131cb43254cb8575d1cedb537e +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/Boids/Prefabs.meta b/Assets/Scenes/Boids/Prefabs.meta new file mode 100644 index 0000000..40e3458 --- /dev/null +++ b/Assets/Scenes/Boids/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7045991fd12f8ed4eaecee534a30ca5f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/Boids/Prefabs/Boid.prefab b/Assets/Scenes/Boids/Prefabs/Boid.prefab new file mode 100644 index 0000000..7f21df2 --- /dev/null +++ b/Assets/Scenes/Boids/Prefabs/Boid.prefab @@ -0,0 +1,172 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &8702527963799169112 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8702527963799169119} + - component: {fileID: 8702527963799169116} + - component: {fileID: 8702527963799169117} + - component: {fileID: 8702527963799169118} + m_Layer: 0 + m_Name: Capsule + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &8702527963799169119 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8702527963799169112} + serializedVersion: 2 + m_LocalRotation: {x: 0.7071068, y: 0, z: 0, w: 0.7071068} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.1, y: 0.1, z: 0.1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 8702527964058765412} + m_LocalEulerAnglesHint: {x: 90, y: 0, z: 0} +--- !u!33 &8702527963799169116 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8702527963799169112} + m_Mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &8702527963799169117 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8702527963799169112} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RayTracingAccelStructBuildFlagsOverride: 0 + m_RayTracingAccelStructBuildFlags: 1 + m_SmallMeshCulling: 1 + m_ForceMeshLod: -1 + m_MeshLodSelectionBias: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: a79ccc131cb43254cb8575d1cedb537e, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_GlobalIlluminationMeshLod: 0 + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!136 &8702527963799169118 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8702527963799169112} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Radius: 0.5 + m_Height: 2 + m_Direction: 1 + m_Center: {x: 0, y: 0, z: 0} +--- !u!1 &8702527964058765413 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8702527964058765412} + - component: {fileID: 9169912378811971808} + m_Layer: 0 + m_Name: Boid + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &8702527964058765412 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8702527964058765413} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 10, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 8702527963799169119} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &9169912378811971808 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8702527964058765413} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe92e8a3728a1e444a25b79acf6b1d00, type: 3} + m_Name: + m_EditorClassIdentifier: + speed: 0.2 + neighbourCount: 0 + inertia: 0.2 + alignmentForce: 1 + cohesionForce: 1 + separationForce: 1 + separationDistance: 0.5 + bodyForce: 1 + sc: {fileID: 0} + velocity: {x: 0, y: 0, z: 0} + acceleration: {x: 0, y: 0, z: 0} + id: 0 diff --git a/Assets/Scenes/Boids/Prefabs/Boid.prefab.meta b/Assets/Scenes/Boids/Prefabs/Boid.prefab.meta new file mode 100644 index 0000000..6e5bf94 --- /dev/null +++ b/Assets/Scenes/Boids/Prefabs/Boid.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f9c706268554ce449a8773675b2864b8 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/Boids/Scripts.meta b/Assets/Scenes/Boids/Scripts.meta new file mode 100644 index 0000000..da4e069 --- /dev/null +++ b/Assets/Scenes/Boids/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 097bca7cdd87e7e4b955ee8624c82da0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/Boids/Scripts/Boid.cs b/Assets/Scenes/Boids/Scripts/Boid.cs new file mode 100644 index 0000000..38941d6 --- /dev/null +++ b/Assets/Scenes/Boids/Scripts/Boid.cs @@ -0,0 +1,94 @@ +using UnityEngine; + + +public class Boid : MonoBehaviour { + public float speed = 0.2f; + public int neighbourCount = 0; + public float inertia = 0.2f; + public float alignmentForce = 1.0f; + public float cohesionForce = 1.0f; + public float separationForce = 1.0f; + public float separationDistance = 0.5f; + public float bodyForce = 1; + + public SwarmControl sc; + public Vector3 velocity = Vector3.zero; + public Vector3 acceleration = Vector3.zero; + + readonly Collider[] results = new Collider[10]; + + public NeuroidNetwork neuroidNet = new(); + public Neuroid bodyVector; + public Neuroid cohesion; + public Neuroid alignment; + public Neuroid separation; + public Neuroid target; + + public Neuroid totalForce; + + public int id; + + void Awake() { + this.id = this.GetInstanceID(); + + sc = FindFirstObjectByType(); + + cohesion = new(neuroidNet) { name = "Cohesion", mode = Neuroid.Mode.Sum }; + alignment = new(neuroidNet) { name = "Alignment", mode = Neuroid.Mode.Average }; + separation = new(neuroidNet) { name = "Separation", mode = Neuroid.Mode.Sum }; + target = new(neuroidNet) { name = "Target", mode = Neuroid.Mode.Sum }; + + + totalForce = new(neuroidNet) { name = "Total force", mode = Neuroid.Mode.Sum }; + totalForce.GetInputFrom(alignment, sc.alignmentForce); + totalForce.GetInputFrom(cohesion, sc.cohesionForce); + totalForce.GetInputFrom(separation, sc.separationForce); + totalForce.GetInputFrom(target, sc.bodyForce); + } + + void Update() { + Physics.OverlapSphereNonAlloc(this.transform.position, 10, results); + neighbourCount = 0; + + cohesion.ResetWeights(); + alignment.ResetWeights(); + separation.ResetWeights(); + + foreach (Collider c in results) { + if (c == null || c as CapsuleCollider == null) + continue; + + Boid neighbour = c.GetComponentInParent(); + if (neighbour == null || neighbour == this) + continue; + + Vector3 localPosition = neighbour.transform.position - this.transform.position; + Vector3 relativeVelocity = neighbour.velocity - this.velocity; + + int id = neighbour.GetInstanceID(); + + Vector3 separationForce = -localPosition / localPosition.sqrMagnitude; + // which is equivalent to -(localPosition.normalized / localPosition.magnitude) + + separation.SetInput(id, separationForce, sc.separationDistance); + cohesion.SetInput(id, localPosition); + alignment.SetInput(id, relativeVelocity); + + neighbourCount++; + } + + Vector3 totalForceVector = totalForce.outputValue; + //Debug.DrawRay(this.transform.position, totalForceVector, Color.magenta); + + this.velocity = (1 - sc.inertia) * (totalForceVector * Time.deltaTime) + sc.inertia * velocity + (sc.speed * transform.forward); + //this.velocity = Vector3.ClampMagnitude(this.velocity, sc.speed); + + this.transform.position += this.velocity * Time.deltaTime; + + if (this.velocity != Vector3.zero) { + Quaternion targetRotation = Quaternion.LookRotation(this.velocity); + transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 2f); // Adjust the speed of rotation + } + } + +} diff --git a/Assets/Scenes/Boids/Scripts/Boid.cs.meta b/Assets/Scenes/Boids/Scripts/Boid.cs.meta new file mode 100644 index 0000000..f22fae8 --- /dev/null +++ b/Assets/Scenes/Boids/Scripts/Boid.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: fe92e8a3728a1e444a25b79acf6b1d00 \ No newline at end of file diff --git a/Assets/Scenes/Boids/Scripts/SwarmControl.cs b/Assets/Scenes/Boids/Scripts/SwarmControl.cs new file mode 100644 index 0000000..b328e9d --- /dev/null +++ b/Assets/Scenes/Boids/Scripts/SwarmControl.cs @@ -0,0 +1,14 @@ +using UnityEngine; + +public class SwarmControl : MonoBehaviour +{ + + public float speed = 0.5f; + //public int neighbourCount = 0; + public float inertia = 0.1f; + public float alignmentForce = 0.0f; + public float cohesionForce = 10.0f; + public float separationForce = 5.0f; + public float separationDistance = 0.5f; + public float bodyForce = 20; +} diff --git a/Assets/Scenes/Boids/Scripts/SwarmControl.cs.meta b/Assets/Scenes/Boids/Scripts/SwarmControl.cs.meta new file mode 100644 index 0000000..a1c47bc --- /dev/null +++ b/Assets/Scenes/Boids/Scripts/SwarmControl.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 0464906885ae3494f8fd0314719fb2db \ No newline at end of file diff --git a/Assets/Scenes/Boids/Scripts/SwarmSpawner.cs b/Assets/Scenes/Boids/Scripts/SwarmSpawner.cs new file mode 100644 index 0000000..241969a --- /dev/null +++ b/Assets/Scenes/Boids/Scripts/SwarmSpawner.cs @@ -0,0 +1,32 @@ +using System.Collections; +using UnityEngine; + +public class SwarmSpawn : MonoBehaviour { + public int count = 1; + public GameObject boidPrefab; + + public Vector3 spawnAreaSize = new(0.5f, 0.5f, 0.5f); // Size of the area to spawn the prefab + public float minDelay = 1f; // Minimum delay between spawns + public float maxDelay = 5f; // Maximum delay between spawns + + void Start() { + StartCoroutine(SpawnPrefab()); + } + + IEnumerator SpawnPrefab() { + for (int i = 0; i < count; i++) { + float delay = Random.Range(minDelay, maxDelay); + yield return new WaitForSeconds(delay); + + // Generate a random local position within the specified area + Vector3 randomPosition = new Vector3( + Random.Range(-spawnAreaSize.x / 2, spawnAreaSize.x / 2), + Random.Range(-spawnAreaSize.y / 2, spawnAreaSize.y / 2), + Random.Range(-spawnAreaSize.z / 2, spawnAreaSize.z / 2) + ); + + // Instantiate the prefab at the random position relative to the spawner + Instantiate(boidPrefab, transform.position + randomPosition, Random.rotation); + } + } +} diff --git a/Assets/Scenes/Boids/Scripts/SwarmSpawner.cs.meta b/Assets/Scenes/Boids/Scripts/SwarmSpawner.cs.meta new file mode 100644 index 0000000..1217a84 --- /dev/null +++ b/Assets/Scenes/Boids/Scripts/SwarmSpawner.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ec888ca5333d45a438f9f417fa5ce135 \ No newline at end of file diff --git a/Assets/Scenes/Gaze.meta b/Assets/Scenes/Gaze.meta new file mode 100644 index 0000000..a5d9020 --- /dev/null +++ b/Assets/Scenes/Gaze.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a0b8e46f4a21ce343b2509b34c712dab +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/SampleScene.unity b/Assets/Scenes/SampleScene.unity new file mode 100644 index 0000000..1c63aa8 --- /dev/null +++ b/Assets/Scenes/SampleScene.unity @@ -0,0 +1,432 @@ +%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: 10 + 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: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 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.18028378, g: 0.22571412, b: 0.30692285, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 12 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + 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_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_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 20201, guid: 0000000000000000f000000000000000, type: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 3 + 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 + buildHeightMesh: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &330585543 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 330585546} + - component: {fileID: 330585545} + - component: {fileID: 330585544} + - component: {fileID: 330585547} + 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 &330585544 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 330585543} + m_Enabled: 1 +--- !u!20 &330585545 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 330585543} + 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_Iso: 200 + m_ShutterSpeed: 0.005 + m_Aperture: 16 + m_FocusDistance: 10 + m_FocalLength: 50 + m_BladeCount: 5 + m_Curvature: {x: 2, y: 11} + m_BarrelClipping: 0.25 + m_Anamorphism: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + 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: 0 + 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 &330585546 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 330585543} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &330585547 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 330585543} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a79441f348de89743a2939f4d699eac1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_RenderShadows: 1 + m_RequiresDepthTextureOption: 2 + m_RequiresOpaqueTextureOption: 2 + m_CameraType: 0 + m_Cameras: [] + m_RendererIndex: -1 + m_VolumeLayerMask: + serializedVersion: 2 + m_Bits: 1 + m_VolumeTrigger: {fileID: 0} + m_VolumeFrameworkUpdateModeOption: 2 + m_RenderPostProcessing: 1 + m_Antialiasing: 0 + m_AntialiasingQuality: 2 + m_StopNaN: 0 + m_Dithering: 0 + m_ClearDepth: 1 + m_AllowXRRendering: 1 + m_AllowHDROutput: 1 + m_UseScreenCoordOverride: 0 + m_ScreenSizeOverride: {x: 0, y: 0, z: 0, w: 0} + m_ScreenCoordScaleBias: {x: 0, y: 0, z: 0, w: 0} + m_RequiresDepthTexture: 0 + m_RequiresColorTexture: 0 + m_Version: 2 + m_TaaSettings: + quality: 3 + frameInfluence: 0.1 + jitterScale: 1 + mipBias: 0 + varianceClampScale: 0.9 + contrastAdaptiveSharpening: 0 +--- !u!1 &410087039 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 410087041} + - component: {fileID: 410087040} + - component: {fileID: 410087042} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &410087040 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 410087039} + m_Enabled: 1 + serializedVersion: 11 + m_Type: 1 + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_Intensity: 2 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 5000 + m_UseColorTemperature: 1 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ForceVisible: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &410087041 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 410087039} + serializedVersion: 2 + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!114 &410087042 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 410087039} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 474bcb49853aa07438625e644c072ee6, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Version: 3 + m_UsePipelineSettings: 1 + m_AdditionalLightsShadowResolutionTier: 2 + m_LightLayerMask: 1 + m_RenderingLayers: 1 + m_CustomShadowLayers: 0 + m_ShadowLayerMask: 1 + m_ShadowRenderingLayers: 1 + m_LightCookieSize: {x: 1, y: 1} + m_LightCookieOffset: {x: 0, y: 0} + m_SoftShadowQuality: 1 +--- !u!1 &832575517 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 832575519} + - component: {fileID: 832575518} + m_Layer: 0 + m_Name: Global Volume + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &832575518 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 832575517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 172515602e62fb746b5d573b38a5fe58, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IsGlobal: 1 + priority: 0 + blendDistance: 0 + weight: 1 + sharedProfile: {fileID: 11400000, guid: 10fc4df2da32a41aaa32d77bc913491c, type: 2} +--- !u!4 &832575519 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 832575517} + serializedVersion: 2 + 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_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1660057539 &9223372036854775807 +SceneRoots: + m_ObjectHideFlags: 0 + m_Roots: + - {fileID: 330585546} + - {fileID: 410087041} + - {fileID: 832575519} diff --git a/Assets/Scenes/SampleScene.unity.meta b/Assets/Scenes/SampleScene.unity.meta new file mode 100644 index 0000000..9531828 --- /dev/null +++ b/Assets/Scenes/SampleScene.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 99c9720ab356a0642a771bea13969a05 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Settings.meta b/Assets/Settings.meta new file mode 100644 index 0000000..39b94dd --- /dev/null +++ b/Assets/Settings.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 709f11a7f3c4041caa4ef136ea32d874 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Recovery.meta b/Assets/_Recovery.meta new file mode 100644 index 0000000..2ca7812 --- /dev/null +++ b/Assets/_Recovery.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7c53f9058d007df4aa1324e04abe30f0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Recovery/0.unity b/Assets/_Recovery/0.unity new file mode 100644 index 0000000..e5fcae4 --- /dev/null +++ b/Assets/_Recovery/0.unity @@ -0,0 +1,474 @@ +%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: 10 + 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: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 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_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 13 + m_BakeOnSceneLoad: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + 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_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: 1 + m_PVRFilteringGaussRadiusAO: 1 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 20201, guid: 0000000000000000f000000000000000, type: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 3 + 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 + buildHeightMesh: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &301943977 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 301943980} + - component: {fileID: 301943979} + - component: {fileID: 301943978} + m_Layer: 0 + m_Name: Swarm + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &301943978 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 301943977} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0464906885ae3494f8fd0314719fb2db, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::SwarmControl + speed: 0.5 + inertia: 0.1 + alignmentForce: 0 + cohesionForce: 10 + separationForce: 5 + separationDistance: 0.5 + bodyForce: 20 +--- !u!114 &301943979 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 301943977} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ec888ca5333d45a438f9f417fa5ce135, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::SwarmSpawn + count: 100 + boidPrefab: {fileID: 8702527964058765413, guid: f9c706268554ce449a8773675b2864b8, type: 3} + spawnAreaSize: {x: 0.5, y: 0.5, z: 0.5} + minDelay: 0.1 + maxDelay: 1 +--- !u!4 &301943980 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 301943977} + serializedVersion: 2 + 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_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1001 &703951470 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 8702527964058765412, guid: f9c706268554ce449a8773675b2864b8, type: 3} + propertyPath: m_LocalPosition.x + value: 2.97655 + objectReference: {fileID: 0} + - target: {fileID: 8702527964058765412, guid: f9c706268554ce449a8773675b2864b8, type: 3} + propertyPath: m_LocalPosition.y + value: -0.73524 + objectReference: {fileID: 0} + - target: {fileID: 8702527964058765412, guid: f9c706268554ce449a8773675b2864b8, type: 3} + propertyPath: m_LocalPosition.z + value: -0.8316 + objectReference: {fileID: 0} + - target: {fileID: 8702527964058765412, guid: f9c706268554ce449a8773675b2864b8, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 8702527964058765412, guid: f9c706268554ce449a8773675b2864b8, type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8702527964058765412, guid: f9c706268554ce449a8773675b2864b8, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8702527964058765412, guid: f9c706268554ce449a8773675b2864b8, type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8702527964058765412, guid: f9c706268554ce449a8773675b2864b8, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8702527964058765412, guid: f9c706268554ce449a8773675b2864b8, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8702527964058765412, guid: f9c706268554ce449a8773675b2864b8, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8702527964058765413, guid: f9c706268554ce449a8773675b2864b8, type: 3} + propertyPath: m_Name + value: Boid + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: f9c706268554ce449a8773675b2864b8, type: 3} +--- !u!1 &837238090 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 837238092} + - component: {fileID: 837238091} + - component: {fileID: 837238093} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &837238091 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 837238090} + m_Enabled: 1 + serializedVersion: 11 + m_Type: 1 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ForceVisible: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 + m_LightUnit: 1 + m_LuxAtDistance: 1 + m_EnableSpotReflector: 1 +--- !u!4 &837238092 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 837238090} + serializedVersion: 2 + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!114 &837238093 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 837238090} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 474bcb49853aa07438625e644c072ee6, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.UniversalAdditionalLightData + m_UsePipelineSettings: 1 + m_AdditionalLightsShadowResolutionTier: 2 + m_CustomShadowLayers: 0 + m_LightCookieSize: {x: 1, y: 1} + m_LightCookieOffset: {x: 0, y: 0} + m_SoftShadowQuality: 0 + m_RenderingLayersMask: + serializedVersion: 0 + m_Bits: 1 + m_ShadowRenderingLayersMask: + serializedVersion: 0 + m_Bits: 1 + m_Version: 4 + m_LightLayerMask: 1 + m_ShadowLayerMask: 1 + m_RenderingLayers: 1 + m_ShadowRenderingLayers: 1 +--- !u!1 &1633626499 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1633626502} + - component: {fileID: 1633626501} + - component: {fileID: 1633626500} + 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 &1633626500 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1633626499} + m_Enabled: 1 +--- !u!20 &1633626501 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1633626499} + 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_Iso: 200 + m_ShutterSpeed: 0.005 + m_Aperture: 16 + m_FocusDistance: 10 + m_FocalLength: 50 + m_BladeCount: 5 + m_Curvature: {x: 2, y: 11} + m_BarrelClipping: 0.25 + m_Anamorphism: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + 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: 0 + 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 &1633626502 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1633626499} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1660057539 &9223372036854775807 +SceneRoots: + m_ObjectHideFlags: 0 + m_Roots: + - {fileID: 1633626502} + - {fileID: 837238092} + - {fileID: 301943980} + - {fileID: 703951470} diff --git a/Assets/_Recovery/0.unity.meta b/Assets/_Recovery/0.unity.meta new file mode 100644 index 0000000..84dc77f --- /dev/null +++ b/Assets/_Recovery/0.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: eeeb110648a395642a15f721ad61e252 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/NanoBrain.sln b/NanoBrain.sln new file mode 100644 index 0000000..d6992f7 --- /dev/null +++ b/NanoBrain.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Assembly-CSharp", "Assembly-CSharp.csproj", "{421F1D6D-0E9B-E088-7112-FB87A00D7B68}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Assembly-CSharp-Editor", "Assembly-CSharp-Editor.csproj", "{4FC2AA99-AF4E-7981-91DB-25688AE496F4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {421F1D6D-0E9B-E088-7112-FB87A00D7B68}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {421F1D6D-0E9B-E088-7112-FB87A00D7B68}.Debug|Any CPU.Build.0 = Debug|Any CPU + {421F1D6D-0E9B-E088-7112-FB87A00D7B68}.Release|Any CPU.ActiveCfg = Release|Any CPU + {421F1D6D-0E9B-E088-7112-FB87A00D7B68}.Release|Any CPU.Build.0 = Release|Any CPU + {4FC2AA99-AF4E-7981-91DB-25688AE496F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4FC2AA99-AF4E-7981-91DB-25688AE496F4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4FC2AA99-AF4E-7981-91DB-25688AE496F4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4FC2AA99-AF4E-7981-91DB-25688AE496F4}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Packages/manifest.json b/Packages/manifest.json new file mode 100644 index 0000000..4e5acb3 --- /dev/null +++ b/Packages/manifest.json @@ -0,0 +1,46 @@ +{ + "dependencies": { + "com.unity.ai.navigation": "2.0.9", + "com.unity.collab-proxy": "2.10.2", + "com.unity.ide.rider": "3.0.38", + "com.unity.ide.visualstudio": "2.0.23", + "com.unity.inputsystem": "1.14.2", + "com.unity.multiplayer.center": "1.0.0", + "com.unity.render-pipelines.universal": "17.2.0", + "com.unity.test-framework": "1.6.0", + "com.unity.timeline": "1.8.9", + "com.unity.ugui": "2.0.0", + "com.unity.modules.accessibility": "1.0.0", + "com.unity.modules.ai": "1.0.0", + "com.unity.modules.androidjni": "1.0.0", + "com.unity.modules.animation": "1.0.0", + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.cloth": "1.0.0", + "com.unity.modules.director": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.particlesystem": "1.0.0", + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.physics2d": "1.0.0", + "com.unity.modules.screencapture": "1.0.0", + "com.unity.modules.terrain": "1.0.0", + "com.unity.modules.terrainphysics": "1.0.0", + "com.unity.modules.tilemap": "1.0.0", + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.uielements": "1.0.0", + "com.unity.modules.umbra": "1.0.0", + "com.unity.modules.unityanalytics": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.unitywebrequestassetbundle": "1.0.0", + "com.unity.modules.unitywebrequestaudio": "1.0.0", + "com.unity.modules.unitywebrequesttexture": "1.0.0", + "com.unity.modules.unitywebrequestwww": "1.0.0", + "com.unity.modules.vehicles": "1.0.0", + "com.unity.modules.video": "1.0.0", + "com.unity.modules.vr": "1.0.0", + "com.unity.modules.wind": "1.0.0", + "com.unity.modules.xr": "1.0.0" + } +} diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json new file mode 100644 index 0000000..46f0878 --- /dev/null +++ b/Packages/packages-lock.json @@ -0,0 +1,455 @@ +{ + "dependencies": { + "com.unity.ai.navigation": { + "version": "2.0.9", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.modules.ai": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.burst": { + "version": "1.8.25", + "depth": 2, + "source": "registry", + "dependencies": { + "com.unity.mathematics": "1.2.1", + "com.unity.modules.jsonserialize": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.collab-proxy": { + "version": "2.10.2", + "depth": 0, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.collections": { + "version": "2.5.7", + "depth": 2, + "source": "registry", + "dependencies": { + "com.unity.burst": "1.8.19", + "com.unity.mathematics": "1.3.2", + "com.unity.test-framework": "1.4.6", + "com.unity.nuget.mono-cecil": "1.11.5", + "com.unity.test-framework.performance": "3.0.3" + }, + "url": "https://packages.unity.com" + }, + "com.unity.ext.nunit": { + "version": "2.0.5", + "depth": 1, + "source": "builtin", + "dependencies": {} + }, + "com.unity.ide.rider": { + "version": "3.0.38", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.ext.nunit": "1.0.6" + }, + "url": "https://packages.unity.com" + }, + "com.unity.ide.visualstudio": { + "version": "2.0.23", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.test-framework": "1.1.9" + }, + "url": "https://packages.unity.com" + }, + "com.unity.inputsystem": { + "version": "1.14.2", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.modules.uielements": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.mathematics": { + "version": "1.3.2", + "depth": 2, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.multiplayer.center": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.uielements": "1.0.0" + } + }, + "com.unity.nuget.mono-cecil": { + "version": "1.11.5", + "depth": 3, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.render-pipelines.core": { + "version": "17.2.0", + "depth": 1, + "source": "builtin", + "dependencies": { + "com.unity.burst": "1.8.14", + "com.unity.mathematics": "1.3.2", + "com.unity.ugui": "2.0.0", + "com.unity.collections": "2.4.3", + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.terrain": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.rendering.light-transport": "1.0.1" + } + }, + "com.unity.render-pipelines.universal": { + "version": "17.2.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.render-pipelines.core": "17.2.0", + "com.unity.shadergraph": "17.2.0", + "com.unity.render-pipelines.universal-config": "17.0.3" + } + }, + "com.unity.render-pipelines.universal-config": { + "version": "17.0.3", + "depth": 1, + "source": "builtin", + "dependencies": { + "com.unity.render-pipelines.core": "17.0.3" + } + }, + "com.unity.rendering.light-transport": { + "version": "1.0.1", + "depth": 2, + "source": "builtin", + "dependencies": { + "com.unity.collections": "2.2.0", + "com.unity.mathematics": "1.2.4", + "com.unity.modules.terrain": "1.0.0" + } + }, + "com.unity.searcher": { + "version": "4.9.3", + "depth": 2, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.shadergraph": { + "version": "17.2.0", + "depth": 1, + "source": "builtin", + "dependencies": { + "com.unity.render-pipelines.core": "17.2.0", + "com.unity.searcher": "4.9.3" + } + }, + "com.unity.test-framework": { + "version": "1.6.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.ext.nunit": "2.0.3", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0" + } + }, + "com.unity.test-framework.performance": { + "version": "3.2.0", + "depth": 3, + "source": "registry", + "dependencies": { + "com.unity.test-framework": "1.1.33", + "com.unity.modules.jsonserialize": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.timeline": { + "version": "1.8.9", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.director": "1.0.0", + "com.unity.modules.animation": "1.0.0", + "com.unity.modules.particlesystem": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.ugui": { + "version": "2.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.imgui": "1.0.0" + } + }, + "com.unity.modules.accessibility": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.ai": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.androidjni": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.animation": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.assetbundle": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.audio": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.cloth": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0" + } + }, + "com.unity.modules.director": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.animation": "1.0.0" + } + }, + "com.unity.modules.hierarchycore": { + "version": "1.0.0", + "depth": 1, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.imageconversion": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.imgui": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.jsonserialize": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.particlesystem": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.physics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.physics2d": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.screencapture": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.imageconversion": "1.0.0" + } + }, + "com.unity.modules.subsystems": { + "version": "1.0.0", + "depth": 1, + "source": "builtin", + "dependencies": { + "com.unity.modules.jsonserialize": "1.0.0" + } + }, + "com.unity.modules.terrain": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.terrainphysics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.terrain": "1.0.0" + } + }, + "com.unity.modules.tilemap": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics2d": "1.0.0" + } + }, + "com.unity.modules.ui": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.uielements": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.hierarchycore": "1.0.0", + "com.unity.modules.physics": "1.0.0" + } + }, + "com.unity.modules.umbra": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.unityanalytics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0" + } + }, + "com.unity.modules.unitywebrequest": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.unitywebrequestassetbundle": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0" + } + }, + "com.unity.modules.unitywebrequestaudio": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.audio": "1.0.0" + } + }, + "com.unity.modules.unitywebrequesttexture": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0" + } + }, + "com.unity.modules.unitywebrequestwww": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.unitywebrequestassetbundle": "1.0.0", + "com.unity.modules.unitywebrequestaudio": "1.0.0", + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0" + } + }, + "com.unity.modules.vehicles": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0" + } + }, + "com.unity.modules.video": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0" + } + }, + "com.unity.modules.vr": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.xr": "1.0.0" + } + }, + "com.unity.modules.wind": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.xr": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.subsystems": "1.0.0" + } + } + } +} diff --git a/ProjectSettings/AudioManager.asset b/ProjectSettings/AudioManager.asset new file mode 100644 index 0000000..27287fe --- /dev/null +++ b/ProjectSettings/AudioManager.asset @@ -0,0 +1,19 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!11 &1 +AudioManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Volume: 1 + Rolloff Scale: 1 + Doppler Factor: 1 + Default Speaker Mode: 2 + m_SampleRate: 0 + m_DSPBufferSize: 1024 + m_VirtualVoiceCount: 512 + m_RealVoiceCount: 32 + m_SpatializerPlugin: + m_AmbisonicDecoderPlugin: + m_DisableAudio: 0 + m_VirtualizeEffects: 1 + m_RequestedDSPBufferSize: 0 diff --git a/ProjectSettings/ClusterInputManager.asset b/ProjectSettings/ClusterInputManager.asset new file mode 100644 index 0000000..e7886b2 --- /dev/null +++ b/ProjectSettings/ClusterInputManager.asset @@ -0,0 +1,6 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!236 &1 +ClusterInputManager: + m_ObjectHideFlags: 0 + m_Inputs: [] diff --git a/ProjectSettings/DynamicsManager.asset b/ProjectSettings/DynamicsManager.asset new file mode 100644 index 0000000..fc90ab9 --- /dev/null +++ b/ProjectSettings/DynamicsManager.asset @@ -0,0 +1,36 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!55 &1 +PhysicsManager: + m_ObjectHideFlags: 0 + serializedVersion: 13 + m_Gravity: {x: 0, y: -9.81, z: 0} + m_DefaultMaterial: {fileID: 0} + m_BounceThreshold: 2 + m_SleepThreshold: 0.005 + m_DefaultContactOffset: 0.01 + m_DefaultSolverIterations: 6 + m_DefaultSolverVelocityIterations: 1 + m_QueriesHitBackfaces: 0 + m_QueriesHitTriggers: 1 + m_EnableAdaptiveForce: 0 + m_ClothInterCollisionDistance: 0.1 + m_ClothInterCollisionStiffness: 0.2 + m_ContactsGeneration: 1 + m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + m_AutoSimulation: 1 + m_AutoSyncTransforms: 0 + m_ReuseCollisionCallbacks: 1 + m_ClothInterCollisionSettingsToggle: 0 + m_ClothGravity: {x: 0, y: -9.81, z: 0} + m_ContactPairsMode: 0 + m_BroadphaseType: 0 + m_WorldBounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 250, y: 250, z: 250} + m_WorldSubdivisions: 8 + m_FrictionType: 0 + m_EnableEnhancedDeterminism: 0 + m_EnableUnifiedHeightmaps: 1 + m_SolverType: 0 + m_DefaultMaxAngularSpeed: 50 diff --git a/ProjectSettings/EditorBuildSettings.asset b/ProjectSettings/EditorBuildSettings.asset new file mode 100644 index 0000000..d057ba3 --- /dev/null +++ b/ProjectSettings/EditorBuildSettings.asset @@ -0,0 +1,13 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1045 &1 +EditorBuildSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Scenes: + - enabled: 1 + path: Assets/Scenes/SampleScene.unity + guid: 99c9720ab356a0642a771bea13969a05 + m_configObjects: + com.unity.input.settings.actions: {fileID: -944628639613478452, guid: 052faaac586de48259a63d0c4782560b, type: 3} + m_UseUCBPForAssetBundles: 0 diff --git a/ProjectSettings/EditorSettings.asset b/ProjectSettings/EditorSettings.asset new file mode 100644 index 0000000..878c4cb --- /dev/null +++ b/ProjectSettings/EditorSettings.asset @@ -0,0 +1,50 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!159 &1 +EditorSettings: + m_ObjectHideFlags: 0 + serializedVersion: 15 + m_SerializationMode: 2 + m_LineEndingsForNewScripts: 0 + m_DefaultBehaviorMode: 0 + m_PrefabRegularEnvironment: {fileID: 0} + m_PrefabUIEnvironment: {fileID: 0} + m_SpritePackerMode: 0 + m_SpritePackerCacheSize: 10 + m_SpritePackerPaddingPower: 1 + m_Bc7TextureCompressor: 0 + m_EtcTextureCompressorBehavior: 1 + m_EtcTextureFastCompressor: 1 + m_EtcTextureNormalCompressor: 2 + m_EtcTextureBestCompressor: 4 + m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd;asmdef;rsp;asmref + m_ProjectGenerationRootNamespace: + m_EnableTextureStreamingInEditMode: 1 + m_EnableTextureStreamingInPlayMode: 1 + m_EnableEditorAsyncCPUTextureLoading: 0 + m_AsyncShaderCompilation: 1 + m_PrefabModeAllowAutoSave: 1 + m_EnterPlayModeOptionsEnabled: 1 + m_EnterPlayModeOptions: 0 + m_GameObjectNamingDigits: 1 + m_GameObjectNamingScheme: 0 + m_AssetNamingUsesSpace: 1 + m_InspectorUseIMGUIDefaultInspector: 0 + m_UseLegacyProbeSampleCount: 0 + m_SerializeInlineMappingsOnOneLine: 1 + m_DisableCookiesInLightmapper: 0 + m_ShadowmaskStitching: 0 + m_AssetPipelineMode: 1 + m_RefreshImportMode: 0 + m_CacheServerMode: 0 + m_CacheServerEndpoint: + m_CacheServerNamespacePrefix: default + m_CacheServerEnableDownload: 1 + m_CacheServerEnableUpload: 1 + m_CacheServerEnableAuth: 0 + m_CacheServerEnableTls: 0 + m_CacheServerValidationMode: 2 + m_CacheServerDownloadBatchSize: 128 + m_EnableEnlightenBakedGI: 0 + m_ReferencedClipsExactNaming: 1 + m_ForceAssetUnloadAndGCOnSceneLoad: 1 diff --git a/ProjectSettings/GraphicsSettings.asset b/ProjectSettings/GraphicsSettings.asset new file mode 100644 index 0000000..aa5a1c3 --- /dev/null +++ b/ProjectSettings/GraphicsSettings.asset @@ -0,0 +1,70 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!30 &1 +GraphicsSettings: + m_ObjectHideFlags: 0 + serializedVersion: 16 + m_Deferred: + m_Mode: 1 + m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0} + m_DeferredReflections: + m_Mode: 1 + m_Shader: {fileID: 74, guid: 0000000000000000f000000000000000, type: 0} + m_ScreenSpaceShadows: + m_Mode: 1 + m_Shader: {fileID: 64, guid: 0000000000000000f000000000000000, type: 0} + m_DepthNormals: + m_Mode: 1 + m_Shader: {fileID: 62, guid: 0000000000000000f000000000000000, type: 0} + m_MotionVectors: + m_Mode: 1 + m_Shader: {fileID: 75, guid: 0000000000000000f000000000000000, type: 0} + m_LightHalo: + m_Mode: 1 + m_Shader: {fileID: 105, guid: 0000000000000000f000000000000000, type: 0} + m_LensFlare: + m_Mode: 1 + m_Shader: {fileID: 102, guid: 0000000000000000f000000000000000, type: 0} + m_VideoShadersIncludeMode: 2 + m_AlwaysIncludedShaders: + - {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15105, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10783, guid: 0000000000000000f000000000000000, type: 0} + m_PreloadedShaders: [] + m_PreloadShadersBatchTimeLimit: -1 + m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, + type: 0} + m_CustomRenderPipeline: {fileID: 11400000, guid: 4b83569d67af61e458304325a23e5dfd, + type: 2} + m_TransparencySortMode: 0 + m_TransparencySortAxis: {x: 0, y: 0, z: 1} + m_DefaultRenderingPath: 1 + m_DefaultMobileRenderingPath: 1 + m_TierSettings: [] + m_LightmapStripping: 0 + m_FogStripping: 0 + m_InstancingStripping: 0 + m_BrgStripping: 0 + m_LightmapKeepPlain: 1 + m_LightmapKeepDirCombined: 1 + m_LightmapKeepDynamicPlain: 1 + m_LightmapKeepDynamicDirCombined: 1 + m_LightmapKeepShadowMask: 1 + m_LightmapKeepSubtractive: 1 + m_FogKeepLinear: 1 + m_FogKeepExp: 1 + m_FogKeepExp2: 1 + m_AlbedoSwatchInfos: [] + m_RenderPipelineGlobalSettingsMap: + UnityEngine.Rendering.Universal.UniversalRenderPipeline: {fileID: 11400000, guid: 18dc0cd2c080841dea60987a38ce93fa, + type: 2} + m_LightsUseLinearIntensity: 1 + m_LightsUseColorTemperature: 1 + m_LogWhenShaderIsCompiled: 0 + m_LightProbeOutsideHullStrategy: 0 + m_CameraRelativeLightCulling: 0 + m_CameraRelativeShadowCulling: 0 diff --git a/ProjectSettings/InputManager.asset b/ProjectSettings/InputManager.asset new file mode 100644 index 0000000..b16147e --- /dev/null +++ b/ProjectSettings/InputManager.asset @@ -0,0 +1,487 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!13 &1 +InputManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Axes: + - serializedVersion: 3 + m_Name: Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: left + positiveButton: right + altNegativeButton: a + altPositiveButton: d + gravity: 3 + dead: 0.001 + sensitivity: 3 + snap: 1 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: down + positiveButton: up + altNegativeButton: s + altPositiveButton: w + gravity: 3 + dead: 0.001 + sensitivity: 3 + snap: 1 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire1 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left ctrl + altNegativeButton: + altPositiveButton: mouse 0 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire2 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left alt + altNegativeButton: + altPositiveButton: mouse 1 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire3 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left shift + altNegativeButton: + altPositiveButton: mouse 2 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Jump + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: space + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse X + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse Y + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 1 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse ScrollWheel + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 2 + joyNum: 0 + - serializedVersion: 3 + m_Name: Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 1 + type: 2 + axis: 1 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire1 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 0 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire2 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 1 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire3 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 2 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Jump + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 3 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Submit + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: return + altNegativeButton: + altPositiveButton: joystick button 0 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Submit + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: enter + altNegativeButton: + altPositiveButton: space + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Cancel + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: escape + altNegativeButton: + altPositiveButton: joystick button 1 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Enable Debug Button 1 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left ctrl + altNegativeButton: + altPositiveButton: joystick button 8 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Enable Debug Button 2 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: backspace + altNegativeButton: + altPositiveButton: joystick button 9 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Reset + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left alt + altNegativeButton: + altPositiveButton: joystick button 1 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Next + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: page down + altNegativeButton: + altPositiveButton: joystick button 5 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Previous + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: page up + altNegativeButton: + altPositiveButton: joystick button 4 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Validate + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: return + altNegativeButton: + altPositiveButton: joystick button 0 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Persistent + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: right shift + altNegativeButton: + altPositiveButton: joystick button 2 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Multiplier + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left shift + altNegativeButton: + altPositiveButton: joystick button 3 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: left + positiveButton: right + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: down + positiveButton: up + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: down + positiveButton: up + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 2 + axis: 6 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: left + positiveButton: right + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 2 + axis: 5 + joyNum: 0 diff --git a/ProjectSettings/MemorySettings.asset b/ProjectSettings/MemorySettings.asset new file mode 100644 index 0000000..5b5face --- /dev/null +++ b/ProjectSettings/MemorySettings.asset @@ -0,0 +1,35 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!387306366 &1 +MemorySettings: + m_ObjectHideFlags: 0 + m_EditorMemorySettings: + m_MainAllocatorBlockSize: -1 + m_ThreadAllocatorBlockSize: -1 + m_MainGfxBlockSize: -1 + m_ThreadGfxBlockSize: -1 + m_CacheBlockSize: -1 + m_TypetreeBlockSize: -1 + m_ProfilerBlockSize: -1 + m_ProfilerEditorBlockSize: -1 + m_BucketAllocatorGranularity: -1 + m_BucketAllocatorBucketsCount: -1 + m_BucketAllocatorBlockSize: -1 + m_BucketAllocatorBlockCount: -1 + m_ProfilerBucketAllocatorGranularity: -1 + m_ProfilerBucketAllocatorBucketsCount: -1 + m_ProfilerBucketAllocatorBlockSize: -1 + m_ProfilerBucketAllocatorBlockCount: -1 + m_TempAllocatorSizeMain: -1 + m_JobTempAllocatorBlockSize: -1 + m_BackgroundJobTempAllocatorBlockSize: -1 + m_JobTempAllocatorReducedBlockSize: -1 + m_TempAllocatorSizeGIBakingWorker: -1 + m_TempAllocatorSizeNavMeshWorker: -1 + m_TempAllocatorSizeAudioWorker: -1 + m_TempAllocatorSizeCloudWorker: -1 + m_TempAllocatorSizeGfx: -1 + m_TempAllocatorSizeJobWorker: -1 + m_TempAllocatorSizeBackgroundWorker: -1 + m_TempAllocatorSizePreloadManager: -1 + m_PlatformMemorySettings: {} diff --git a/ProjectSettings/MultiplayerManager.asset b/ProjectSettings/MultiplayerManager.asset new file mode 100644 index 0000000..2a93664 --- /dev/null +++ b/ProjectSettings/MultiplayerManager.asset @@ -0,0 +1,7 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!655991488 &1 +MultiplayerManager: + m_ObjectHideFlags: 0 + m_EnableMultiplayerRoles: 0 + m_StrippingTypes: {} diff --git a/ProjectSettings/NavMeshAreas.asset b/ProjectSettings/NavMeshAreas.asset new file mode 100644 index 0000000..3b0b7c3 --- /dev/null +++ b/ProjectSettings/NavMeshAreas.asset @@ -0,0 +1,91 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!126 &1 +NavMeshProjectSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + areas: + - name: Walkable + cost: 1 + - name: Not Walkable + cost: 1 + - name: Jump + cost: 2 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + m_LastAgentTypeID: -887442657 + m_Settings: + - serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.75 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_SettingNames: + - Humanoid diff --git a/ProjectSettings/PackageManagerSettings.asset b/ProjectSettings/PackageManagerSettings.asset new file mode 100644 index 0000000..be4a797 --- /dev/null +++ b/ProjectSettings/PackageManagerSettings.asset @@ -0,0 +1,43 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &1 +MonoBehaviour: + m_ObjectHideFlags: 61 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 13964, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_EnablePreviewPackages: 0 + m_EnablePackageDependencies: 0 + m_AdvancedSettingsExpanded: 1 + m_ScopedRegistriesSettingsExpanded: 1 + oneTimeWarningShown: 0 + m_Registries: + - m_Id: main + m_Name: + m_Url: https://packages.unity.com + m_Scopes: [] + m_IsDefault: 1 + m_Capabilities: 7 + m_UserSelectedRegistryName: + m_UserAddingNewScopedRegistry: 0 + m_RegistryInfoDraft: + m_ErrorMessage: + m_Original: + m_Id: + m_Name: + m_Url: + m_Scopes: [] + m_IsDefault: 0 + m_Capabilities: 0 + m_Modified: 0 + m_Name: + m_Url: + m_Scopes: + - + m_SelectedScopeIndex: 0 diff --git a/ProjectSettings/Physics2DSettings.asset b/ProjectSettings/Physics2DSettings.asset new file mode 100644 index 0000000..6c5cf8a --- /dev/null +++ b/ProjectSettings/Physics2DSettings.asset @@ -0,0 +1,56 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!19 &1 +Physics2DSettings: + m_ObjectHideFlags: 0 + serializedVersion: 4 + m_Gravity: {x: 0, y: -9.81} + m_DefaultMaterial: {fileID: 0} + m_VelocityIterations: 8 + m_PositionIterations: 3 + m_VelocityThreshold: 1 + m_MaxLinearCorrection: 0.2 + m_MaxAngularCorrection: 8 + m_MaxTranslationSpeed: 100 + m_MaxRotationSpeed: 360 + m_BaumgarteScale: 0.2 + m_BaumgarteTimeOfImpactScale: 0.75 + m_TimeToSleep: 0.5 + m_LinearSleepTolerance: 0.01 + m_AngularSleepTolerance: 2 + m_DefaultContactOffset: 0.01 + m_JobOptions: + serializedVersion: 2 + useMultithreading: 0 + useConsistencySorting: 0 + m_InterpolationPosesPerJob: 100 + m_NewContactsPerJob: 30 + m_CollideContactsPerJob: 100 + m_ClearFlagsPerJob: 200 + m_ClearBodyForcesPerJob: 200 + m_SyncDiscreteFixturesPerJob: 50 + m_SyncContinuousFixturesPerJob: 50 + m_FindNearestContactsPerJob: 100 + m_UpdateTriggerContactsPerJob: 100 + m_IslandSolverCostThreshold: 100 + m_IslandSolverBodyCostScale: 1 + m_IslandSolverContactCostScale: 10 + m_IslandSolverJointCostScale: 10 + m_IslandSolverBodiesPerJob: 50 + m_IslandSolverContactsPerJob: 50 + m_AutoSimulation: 1 + m_QueriesHitTriggers: 1 + m_QueriesStartInColliders: 1 + m_CallbacksOnDisable: 1 + m_ReuseCollisionCallbacks: 0 + m_AutoSyncTransforms: 0 + m_AlwaysShowColliders: 0 + m_ShowColliderSleep: 1 + m_ShowColliderContacts: 0 + m_ShowColliderAABB: 0 + m_ContactArrowScale: 0.2 + m_ColliderAwakeColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.7529412} + m_ColliderAsleepColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.36078432} + m_ColliderContactColor: {r: 1, g: 0, b: 1, a: 0.6862745} + m_ColliderAABBColor: {r: 1, g: 1, b: 0, a: 0.2509804} + m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff diff --git a/ProjectSettings/PresetManager.asset b/ProjectSettings/PresetManager.asset new file mode 100644 index 0000000..67a94da --- /dev/null +++ b/ProjectSettings/PresetManager.asset @@ -0,0 +1,7 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1386491679 &1 +PresetManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_DefaultPresets: {} diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset new file mode 100644 index 0000000..5c83bc5 --- /dev/null +++ b/ProjectSettings/ProjectSettings.asset @@ -0,0 +1,938 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!129 &1 +PlayerSettings: + m_ObjectHideFlags: 0 + serializedVersion: 28 + productGUID: ae734b3b09caebd4aa3fc5596884a057 + AndroidProfiler: 0 + AndroidFilterTouchesWhenObscured: 0 + AndroidEnableSustainedPerformanceMode: 0 + defaultScreenOrientation: 4 + targetDevice: 2 + useOnDemandResources: 0 + accelerometerFrequency: 60 + companyName: DefaultCompany + productName: NanoBrain + defaultCursor: {fileID: 0} + cursorHotspot: {x: 0, y: 0} + m_SplashScreenBackgroundColor: {r: 0.13725491, g: 0.12156863, b: 0.1254902, a: 1} + m_ShowUnitySplashScreen: 1 + m_ShowUnitySplashLogo: 1 + m_SplashScreenOverlayOpacity: 1 + m_SplashScreenAnimation: 1 + m_SplashScreenLogoStyle: 1 + m_SplashScreenDrawMode: 0 + m_SplashScreenBackgroundAnimationZoom: 1 + m_SplashScreenLogoAnimationZoom: 1 + m_SplashScreenBackgroundLandscapeAspect: 1 + m_SplashScreenBackgroundPortraitAspect: 1 + m_SplashScreenBackgroundLandscapeUvs: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + m_SplashScreenBackgroundPortraitUvs: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + m_SplashScreenLogos: [] + m_VirtualRealitySplashScreen: {fileID: 0} + m_HolographicTrackingLossScreen: {fileID: 0} + defaultScreenWidth: 1024 + defaultScreenHeight: 768 + defaultScreenWidthWeb: 960 + defaultScreenHeightWeb: 600 + m_StereoRenderingPath: 0 + m_ActiveColorSpace: 1 + unsupportedMSAAFallback: 0 + m_SpriteBatchMaxVertexCount: 65535 + m_SpriteBatchVertexThreshold: 300 + m_MTRendering: 1 + mipStripping: 0 + numberOfMipsStripped: 0 + numberOfMipsStrippedPerMipmapLimitGroup: {} + m_StackTraceTypes: 010000000100000001000000010000000100000001000000 + iosShowActivityIndicatorOnLoading: -1 + androidShowActivityIndicatorOnLoading: -1 + iosUseCustomAppBackgroundBehavior: 0 + allowedAutorotateToPortrait: 1 + allowedAutorotateToPortraitUpsideDown: 1 + allowedAutorotateToLandscapeRight: 1 + allowedAutorotateToLandscapeLeft: 1 + useOSAutorotation: 1 + use32BitDisplayBuffer: 1 + preserveFramebufferAlpha: 0 + disableDepthAndStencilBuffers: 0 + androidStartInFullscreen: 1 + androidRenderOutsideSafeArea: 1 + androidUseSwappy: 0 + androidBlitType: 0 + androidResizeableActivity: 1 + androidDefaultWindowWidth: 1920 + androidDefaultWindowHeight: 1080 + androidMinimumWindowWidth: 400 + androidMinimumWindowHeight: 300 + androidFullscreenMode: 1 + androidAutoRotationBehavior: 1 + androidPredictiveBackSupport: 1 + androidApplicationEntry: 2 + defaultIsNativeResolution: 1 + macRetinaSupport: 1 + runInBackground: 0 + muteOtherAudioSources: 0 + Prepare IOS For Recording: 0 + Force IOS Speakers When Recording: 0 + audioSpatialExperience: 0 + deferSystemGesturesMode: 0 + hideHomeButton: 0 + submitAnalytics: 1 + usePlayerLog: 1 + dedicatedServerOptimizations: 1 + bakeCollisionMeshes: 0 + forceSingleInstance: 0 + useFlipModelSwapchain: 1 + resizableWindow: 0 + useMacAppStoreValidation: 0 + macAppStoreCategory: public.app-category.games + gpuSkinning: 1 + meshDeformation: 2 + xboxPIXTextureCapture: 0 + xboxEnableAvatar: 0 + xboxEnableKinect: 0 + xboxEnableKinectAutoTracking: 0 + xboxEnableFitness: 0 + visibleInBackground: 1 + allowFullscreenSwitch: 1 + fullscreenMode: 1 + xboxSpeechDB: 0 + xboxEnableHeadOrientation: 0 + xboxEnableGuest: 0 + xboxEnablePIXSampling: 0 + metalFramebufferOnly: 0 + xboxOneResolution: 0 + xboxOneSResolution: 0 + xboxOneXResolution: 3 + xboxOneMonoLoggingLevel: 0 + xboxOneLoggingLevel: 1 + xboxOneDisableEsram: 0 + xboxOneEnableTypeOptimization: 0 + xboxOnePresentImmediateThreshold: 0 + switchQueueCommandMemory: 1048576 + switchQueueControlMemory: 16384 + switchQueueComputeMemory: 262144 + switchNVNShaderPoolsGranularity: 33554432 + switchNVNDefaultPoolsGranularity: 16777216 + switchNVNOtherPoolsGranularity: 16777216 + switchGpuScratchPoolGranularity: 2097152 + switchAllowGpuScratchShrinking: 0 + switchNVNMaxPublicTextureIDCount: 0 + switchNVNMaxPublicSamplerIDCount: 0 + switchMaxWorkerMultiple: 8 + switchNVNGraphicsFirmwareMemory: 32 + switchGraphicsJobsSyncAfterKick: 1 + vulkanNumSwapchainBuffers: 3 + vulkanEnableSetSRGBWrite: 0 + vulkanEnablePreTransform: 1 + vulkanEnableLateAcquireNextImage: 0 + vulkanEnableCommandBufferRecycling: 1 + loadStoreDebugModeEnabled: 0 + visionOSBundleVersion: 1.0 + tvOSBundleVersion: 1.0 + bundleVersion: 0.1.0 + preloadedAssets: [] + metroInputSource: 0 + wsaTransparentSwapchain: 0 + m_HolographicPauseOnTrackingLoss: 1 + xboxOneDisableKinectGpuReservation: 1 + xboxOneEnable7thCore: 1 + vrSettings: + enable360StereoCapture: 0 + isWsaHolographicRemotingEnabled: 0 + enableFrameTimingStats: 0 + enableOpenGLProfilerGPURecorders: 1 + allowHDRDisplaySupport: 0 + useHDRDisplay: 0 + hdrBitDepth: 0 + m_ColorGamuts: 00000000 + targetPixelDensity: 30 + resolutionScalingMode: 0 + resetResolutionOnWindowResize: 0 + androidSupportedAspectRatio: 1 + androidMaxAspectRatio: 2.4 + androidMinAspectRatio: 1 + applicationIdentifier: + Android: com.UnityTechnologies.com.unity.template.urpblank + Standalone: com.Unity-Technologies.com.unity.template.urp-blank + iPhone: com.Unity-Technologies.com.unity.template.urp-blank + buildNumber: + Standalone: 0 + VisionOS: 0 + iPhone: 0 + tvOS: 0 + overrideDefaultApplicationIdentifier: 1 + AndroidBundleVersionCode: 1 + AndroidMinSdkVersion: 23 + AndroidTargetSdkVersion: 0 + AndroidPreferredInstallLocation: 1 + aotOptions: + stripEngineCode: 1 + iPhoneStrippingLevel: 0 + iPhoneScriptCallOptimization: 0 + ForceInternetPermission: 0 + ForceSDCardPermission: 0 + CreateWallpaper: 0 + androidSplitApplicationBinary: 0 + keepLoadedShadersAlive: 0 + StripUnusedMeshComponents: 0 + strictShaderVariantMatching: 0 + VertexChannelCompressionMask: 4054 + iPhoneSdkVersion: 988 + iOSSimulatorArchitecture: 0 + iOSTargetOSVersionString: 13.0 + tvOSSdkVersion: 0 + tvOSSimulatorArchitecture: 0 + tvOSRequireExtendedGameController: 0 + tvOSTargetOSVersionString: 13.0 + VisionOSSdkVersion: 0 + VisionOSTargetOSVersionString: 1.0 + uIPrerenderedIcon: 0 + uIRequiresPersistentWiFi: 0 + uIRequiresFullScreen: 1 + uIStatusBarHidden: 1 + uIExitOnSuspend: 0 + uIStatusBarStyle: 0 + appleTVSplashScreen: {fileID: 0} + appleTVSplashScreen2x: {fileID: 0} + tvOSSmallIconLayers: [] + tvOSSmallIconLayers2x: [] + tvOSLargeIconLayers: [] + tvOSLargeIconLayers2x: [] + tvOSTopShelfImageLayers: [] + tvOSTopShelfImageLayers2x: [] + tvOSTopShelfImageWideLayers: [] + tvOSTopShelfImageWideLayers2x: [] + iOSLaunchScreenType: 0 + iOSLaunchScreenPortrait: {fileID: 0} + iOSLaunchScreenLandscape: {fileID: 0} + iOSLaunchScreenBackgroundColor: + serializedVersion: 2 + rgba: 0 + iOSLaunchScreenFillPct: 100 + iOSLaunchScreenSize: 100 + iOSLaunchScreeniPadType: 0 + iOSLaunchScreeniPadImage: {fileID: 0} + iOSLaunchScreeniPadBackgroundColor: + serializedVersion: 2 + rgba: 0 + iOSLaunchScreeniPadFillPct: 100 + iOSLaunchScreeniPadSize: 100 + iOSLaunchScreenCustomStoryboardPath: + iOSLaunchScreeniPadCustomStoryboardPath: + iOSDeviceRequirements: [] + iOSURLSchemes: [] + macOSURLSchemes: [] + iOSBackgroundModes: 0 + iOSMetalForceHardShadows: 0 + metalEditorSupport: 1 + metalAPIValidation: 1 + metalCompileShaderBinary: 0 + iOSRenderExtraFrameOnPause: 0 + iosCopyPluginsCodeInsteadOfSymlink: 0 + appleDeveloperTeamID: + iOSManualSigningProvisioningProfileID: + tvOSManualSigningProvisioningProfileID: + VisionOSManualSigningProvisioningProfileID: + iOSManualSigningProvisioningProfileType: 0 + tvOSManualSigningProvisioningProfileType: 0 + VisionOSManualSigningProvisioningProfileType: 0 + appleEnableAutomaticSigning: 0 + iOSRequireARKit: 0 + iOSAutomaticallyDetectAndAddCapabilities: 1 + appleEnableProMotion: 0 + shaderPrecisionModel: 0 + clonedFromGUID: 3c72c65a16f0acb438eed22b8b16c24a + templatePackageId: com.unity.template.urp-blank@17.0.14 + templateDefaultScene: Assets/Scenes/SampleScene.unity + useCustomMainManifest: 0 + useCustomLauncherManifest: 0 + useCustomMainGradleTemplate: 0 + useCustomLauncherGradleManifest: 0 + useCustomBaseGradleTemplate: 0 + useCustomGradlePropertiesTemplate: 0 + useCustomGradleSettingsTemplate: 0 + useCustomProguardFile: 0 + AndroidTargetArchitectures: 2 + AndroidSplashScreenScale: 0 + androidSplashScreen: {fileID: 0} + AndroidKeystoreName: + AndroidKeyaliasName: + AndroidEnableArmv9SecurityFeatures: 0 + AndroidEnableArm64MTE: 0 + AndroidBuildApkPerCpuArchitecture: 0 + AndroidTVCompatibility: 0 + AndroidIsGame: 1 + androidAppCategory: 3 + useAndroidAppCategory: 1 + androidAppCategoryOther: + AndroidEnableTango: 0 + androidEnableBanner: 1 + androidUseLowAccuracyLocation: 0 + androidUseCustomKeystore: 0 + m_AndroidBanners: + - width: 320 + height: 180 + banner: {fileID: 0} + androidGamepadSupportLevel: 0 + AndroidMinifyRelease: 0 + AndroidMinifyDebug: 0 + AndroidValidateAppBundleSize: 1 + AndroidAppBundleSizeToValidate: 150 + AndroidReportGooglePlayAppDependencies: 1 + androidSymbolsSizeThreshold: 800 + m_BuildTargetIcons: [] + m_BuildTargetPlatformIcons: + - m_BuildTarget: iPhone + m_Icons: + - m_Textures: [] + m_Width: 180 + m_Height: 180 + m_Kind: 0 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 120 + m_Height: 120 + m_Kind: 0 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 167 + m_Height: 167 + m_Kind: 0 + m_SubKind: iPad + - m_Textures: [] + m_Width: 152 + m_Height: 152 + m_Kind: 0 + m_SubKind: iPad + - m_Textures: [] + m_Width: 76 + m_Height: 76 + m_Kind: 0 + m_SubKind: iPad + - m_Textures: [] + m_Width: 120 + m_Height: 120 + m_Kind: 3 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 80 + m_Height: 80 + m_Kind: 3 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 80 + m_Height: 80 + m_Kind: 3 + m_SubKind: iPad + - m_Textures: [] + m_Width: 40 + m_Height: 40 + m_Kind: 3 + m_SubKind: iPad + - m_Textures: [] + m_Width: 87 + m_Height: 87 + m_Kind: 1 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 58 + m_Height: 58 + m_Kind: 1 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 29 + m_Height: 29 + m_Kind: 1 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 58 + m_Height: 58 + m_Kind: 1 + m_SubKind: iPad + - m_Textures: [] + m_Width: 29 + m_Height: 29 + m_Kind: 1 + m_SubKind: iPad + - m_Textures: [] + m_Width: 60 + m_Height: 60 + m_Kind: 2 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 40 + m_Height: 40 + m_Kind: 2 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 40 + m_Height: 40 + m_Kind: 2 + m_SubKind: iPad + - m_Textures: [] + m_Width: 20 + m_Height: 20 + m_Kind: 2 + m_SubKind: iPad + - m_Textures: [] + m_Width: 1024 + m_Height: 1024 + m_Kind: 4 + m_SubKind: App Store + - m_BuildTarget: Android + m_Icons: + - m_Textures: [] + m_Width: 432 + m_Height: 432 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 324 + m_Height: 324 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 216 + m_Height: 216 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 162 + m_Height: 162 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 108 + m_Height: 108 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 81 + m_Height: 81 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 192 + m_Height: 192 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 144 + m_Height: 144 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 96 + m_Height: 96 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 72 + m_Height: 72 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 48 + m_Height: 48 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 36 + m_Height: 36 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 192 + m_Height: 192 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 144 + m_Height: 144 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 96 + m_Height: 96 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 72 + m_Height: 72 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 48 + m_Height: 48 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 36 + m_Height: 36 + m_Kind: 0 + m_SubKind: + - m_BuildTarget: tvOS + m_Icons: + - m_Textures: [] + m_Width: 1280 + m_Height: 768 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 800 + m_Height: 480 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 400 + m_Height: 240 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 4640 + m_Height: 1440 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 2320 + m_Height: 720 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 3840 + m_Height: 1440 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 1920 + m_Height: 720 + m_Kind: 1 + m_SubKind: + m_BuildTargetBatching: [] + m_BuildTargetShaderSettings: [] + m_BuildTargetGraphicsJobs: [] + m_BuildTargetGraphicsJobMode: [] + m_BuildTargetGraphicsAPIs: + - m_BuildTarget: iOSSupport + m_APIs: 10000000 + m_Automatic: 1 + - m_BuildTarget: AndroidPlayer + m_APIs: 150000000b000000 + m_Automatic: 0 + m_BuildTargetVRSettings: [] + m_DefaultShaderChunkSizeInMB: 16 + m_DefaultShaderChunkCount: 0 + openGLRequireES31: 0 + openGLRequireES31AEP: 0 + openGLRequireES32: 0 + m_TemplateCustomTags: {} + mobileMTRendering: + Android: 1 + iPhone: 1 + tvOS: 1 + m_BuildTargetGroupLightmapEncodingQuality: + - serializedVersion: 2 + m_BuildTarget: Android + m_EncodingQuality: 1 + m_BuildTargetGroupHDRCubemapEncodingQuality: [] + m_BuildTargetGroupLightmapSettings: [] + m_BuildTargetGroupLoadStoreDebugModeSettings: [] + m_BuildTargetNormalMapEncoding: + - m_BuildTarget: Android + m_Encoding: 1 + m_BuildTargetDefaultTextureCompressionFormat: + - serializedVersion: 3 + m_BuildTarget: Android + m_Formats: 03000000 + playModeTestRunnerEnabled: 0 + runPlayModeTestAsEditModeTest: 0 + actionOnDotNetUnhandledException: 1 + editorGfxJobOverride: 1 + enableInternalProfiler: 0 + logObjCUncaughtExceptions: 1 + enableCrashReportAPI: 0 + cameraUsageDescription: + locationUsageDescription: + microphoneUsageDescription: + bluetoothUsageDescription: + macOSTargetOSVersion: 11.0 + switchNMETAOverride: + switchNetLibKey: + switchSocketMemoryPoolSize: 6144 + switchSocketAllocatorPoolSize: 128 + switchSocketConcurrencyLimit: 14 + switchScreenResolutionBehavior: 2 + switchUseCPUProfiler: 0 + switchEnableFileSystemTrace: 0 + switchLTOSetting: 0 + switchApplicationID: 0x01004b9000490000 + switchNSODependencies: + switchCompilerFlags: + switchTitleNames_0: + switchTitleNames_1: + switchTitleNames_2: + switchTitleNames_3: + switchTitleNames_4: + switchTitleNames_5: + switchTitleNames_6: + switchTitleNames_7: + switchTitleNames_8: + switchTitleNames_9: + switchTitleNames_10: + switchTitleNames_11: + switchTitleNames_12: + switchTitleNames_13: + switchTitleNames_14: + switchTitleNames_15: + switchPublisherNames_0: + switchPublisherNames_1: + switchPublisherNames_2: + switchPublisherNames_3: + switchPublisherNames_4: + switchPublisherNames_5: + switchPublisherNames_6: + switchPublisherNames_7: + switchPublisherNames_8: + switchPublisherNames_9: + switchPublisherNames_10: + switchPublisherNames_11: + switchPublisherNames_12: + switchPublisherNames_13: + switchPublisherNames_14: + switchPublisherNames_15: + switchIcons_0: {fileID: 0} + switchIcons_1: {fileID: 0} + switchIcons_2: {fileID: 0} + switchIcons_3: {fileID: 0} + switchIcons_4: {fileID: 0} + switchIcons_5: {fileID: 0} + switchIcons_6: {fileID: 0} + switchIcons_7: {fileID: 0} + switchIcons_8: {fileID: 0} + switchIcons_9: {fileID: 0} + switchIcons_10: {fileID: 0} + switchIcons_11: {fileID: 0} + switchIcons_12: {fileID: 0} + switchIcons_13: {fileID: 0} + switchIcons_14: {fileID: 0} + switchIcons_15: {fileID: 0} + switchSmallIcons_0: {fileID: 0} + switchSmallIcons_1: {fileID: 0} + switchSmallIcons_2: {fileID: 0} + switchSmallIcons_3: {fileID: 0} + switchSmallIcons_4: {fileID: 0} + switchSmallIcons_5: {fileID: 0} + switchSmallIcons_6: {fileID: 0} + switchSmallIcons_7: {fileID: 0} + switchSmallIcons_8: {fileID: 0} + switchSmallIcons_9: {fileID: 0} + switchSmallIcons_10: {fileID: 0} + switchSmallIcons_11: {fileID: 0} + switchSmallIcons_12: {fileID: 0} + switchSmallIcons_13: {fileID: 0} + switchSmallIcons_14: {fileID: 0} + switchSmallIcons_15: {fileID: 0} + switchManualHTML: + switchAccessibleURLs: + switchLegalInformation: + switchMainThreadStackSize: 1048576 + switchPresenceGroupId: + switchLogoHandling: 0 + switchReleaseVersion: 0 + switchDisplayVersion: 1.0.0 + switchStartupUserAccount: 0 + switchSupportedLanguagesMask: 0 + switchLogoType: 0 + switchApplicationErrorCodeCategory: + switchUserAccountSaveDataSize: 0 + switchUserAccountSaveDataJournalSize: 0 + switchApplicationAttribute: 0 + switchCardSpecSize: -1 + switchCardSpecClock: -1 + switchRatingsMask: 0 + switchRatingsInt_0: 0 + switchRatingsInt_1: 0 + switchRatingsInt_2: 0 + switchRatingsInt_3: 0 + switchRatingsInt_4: 0 + switchRatingsInt_5: 0 + switchRatingsInt_6: 0 + switchRatingsInt_7: 0 + switchRatingsInt_8: 0 + switchRatingsInt_9: 0 + switchRatingsInt_10: 0 + switchRatingsInt_11: 0 + switchRatingsInt_12: 0 + switchLocalCommunicationIds_0: + switchLocalCommunicationIds_1: + switchLocalCommunicationIds_2: + switchLocalCommunicationIds_3: + switchLocalCommunicationIds_4: + switchLocalCommunicationIds_5: + switchLocalCommunicationIds_6: + switchLocalCommunicationIds_7: + switchParentalControl: 0 + switchAllowsScreenshot: 1 + switchAllowsVideoCapturing: 1 + switchAllowsRuntimeAddOnContentInstall: 0 + switchDataLossConfirmation: 0 + switchUserAccountLockEnabled: 0 + switchSystemResourceMemory: 16777216 + switchSupportedNpadStyles: 22 + switchNativeFsCacheSize: 32 + switchIsHoldTypeHorizontal: 0 + switchSupportedNpadCount: 8 + switchEnableTouchScreen: 1 + switchSocketConfigEnabled: 0 + switchTcpInitialSendBufferSize: 32 + switchTcpInitialReceiveBufferSize: 64 + switchTcpAutoSendBufferSizeMax: 256 + switchTcpAutoReceiveBufferSizeMax: 256 + switchUdpSendBufferSize: 9 + switchUdpReceiveBufferSize: 42 + switchSocketBufferEfficiency: 4 + switchSocketInitializeEnabled: 1 + switchNetworkInterfaceManagerInitializeEnabled: 1 + switchDisableHTCSPlayerConnection: 0 + switchUseNewStyleFilepaths: 0 + switchUseLegacyFmodPriorities: 0 + switchUseMicroSleepForYield: 1 + switchEnableRamDiskSupport: 0 + switchMicroSleepForYieldTime: 25 + switchRamDiskSpaceSize: 12 + switchUpgradedPlayerSettingsToNMETA: 0 + ps4NPAgeRating: 12 + ps4NPTitleSecret: + ps4NPTrophyPackPath: + ps4ParentalLevel: 11 + ps4ContentID: ED1633-NPXX51362_00-0000000000000000 + ps4Category: 0 + ps4MasterVersion: 01.00 + ps4AppVersion: 01.00 + ps4AppType: 0 + ps4ParamSfxPath: + ps4VideoOutPixelFormat: 0 + ps4VideoOutInitialWidth: 1920 + ps4VideoOutBaseModeInitialWidth: 1920 + ps4VideoOutReprojectionRate: 60 + ps4PronunciationXMLPath: + ps4PronunciationSIGPath: + ps4BackgroundImagePath: + ps4StartupImagePath: + ps4StartupImagesFolder: + ps4IconImagesFolder: + ps4SaveDataImagePath: + ps4SdkOverride: + ps4BGMPath: + ps4ShareFilePath: + ps4ShareOverlayImagePath: + ps4PrivacyGuardImagePath: + ps4ExtraSceSysFile: + ps4NPtitleDatPath: + ps4RemotePlayKeyAssignment: -1 + ps4RemotePlayKeyMappingDir: + ps4PlayTogetherPlayerCount: 0 + ps4EnterButtonAssignment: 2 + ps4ApplicationParam1: 0 + ps4ApplicationParam2: 0 + ps4ApplicationParam3: 0 + ps4ApplicationParam4: 0 + ps4DownloadDataSize: 0 + ps4GarlicHeapSize: 2048 + ps4ProGarlicHeapSize: 2560 + playerPrefsMaxSize: 32768 + ps4Passcode: frAQBc8Wsa1xVPfvJcrgRYwTiizs2trQ + ps4pnSessions: 1 + ps4pnPresence: 1 + ps4pnFriends: 1 + ps4pnGameCustomData: 1 + playerPrefsSupport: 0 + enableApplicationExit: 0 + resetTempFolder: 1 + restrictedAudioUsageRights: 0 + ps4UseResolutionFallback: 0 + ps4ReprojectionSupport: 0 + ps4UseAudio3dBackend: 0 + ps4UseLowGarlicFragmentationMode: 1 + ps4SocialScreenEnabled: 0 + ps4ScriptOptimizationLevel: 2 + ps4Audio3dVirtualSpeakerCount: 14 + ps4attribCpuUsage: 0 + ps4PatchPkgPath: + ps4PatchLatestPkgPath: + ps4PatchChangeinfoPath: + ps4PatchDayOne: 0 + ps4attribUserManagement: 0 + ps4attribMoveSupport: 0 + ps4attrib3DSupport: 0 + ps4attribShareSupport: 0 + ps4attribExclusiveVR: 0 + ps4disableAutoHideSplash: 0 + ps4videoRecordingFeaturesUsed: 0 + ps4contentSearchFeaturesUsed: 0 + ps4CompatibilityPS5: 0 + ps4AllowPS5Detection: 0 + ps4GPU800MHz: 1 + ps4attribEyeToEyeDistanceSettingVR: 0 + ps4IncludedModules: [] + ps4attribVROutputEnabled: 0 + monoEnv: + splashScreenBackgroundSourceLandscape: {fileID: 0} + splashScreenBackgroundSourcePortrait: {fileID: 0} + blurSplashScreenBackground: 1 + spritePackerPolicy: + webGLMemorySize: 32 + webGLExceptionSupport: 1 + webGLNameFilesAsHashes: 0 + webGLShowDiagnostics: 0 + webGLDataCaching: 1 + webGLDebugSymbols: 0 + webGLEmscriptenArgs: + webGLModulesDirectory: + webGLTemplate: APPLICATION:Default + webGLAnalyzeBuildSize: 0 + webGLUseEmbeddedResources: 0 + webGLCompressionFormat: 0 + webGLWasmArithmeticExceptions: 0 + webGLLinkerTarget: 1 + webGLThreadsSupport: 0 + webGLDecompressionFallback: 0 + webGLInitialMemorySize: 32 + webGLMaximumMemorySize: 2048 + webGLMemoryGrowthMode: 2 + webGLMemoryLinearGrowthStep: 16 + webGLMemoryGeometricGrowthStep: 0.2 + webGLMemoryGeometricGrowthCap: 96 + webGLPowerPreference: 2 + webGLWebAssemblyTable: 0 + webGLWebAssemblyBigInt: 0 + webGLCloseOnQuit: 0 + webWasm2023: 0 + webEnableSubmoduleStrippingCompatibility: 0 + scriptingDefineSymbols: {} + additionalCompilerArguments: {} + platformArchitecture: {} + scriptingBackend: + Android: 1 + il2cppCompilerConfiguration: {} + il2cppCodeGeneration: {} + il2cppStacktraceInformation: {} + managedStrippingLevel: {} + incrementalIl2cppBuild: {} + suppressCommonWarnings: 1 + allowUnsafeCode: 0 + useDeterministicCompilation: 1 + additionalIl2CppArgs: + scriptingRuntimeVersion: 1 + gcIncremental: 1 + gcWBarrierValidation: 0 + apiCompatibilityLevelPerPlatform: {} + editorAssembliesCompatibilityLevel: 1 + m_RenderingPath: 1 + m_MobileRenderingPath: 1 + metroPackageName: NanoBrain + metroPackageVersion: + metroCertificatePath: + metroCertificatePassword: + metroCertificateSubject: + metroCertificateIssuer: + metroCertificateNotAfter: 0000000000000000 + metroApplicationDescription: NanoBrain + wsaImages: {} + metroTileShortName: + metroTileShowName: 0 + metroMediumTileShowName: 0 + metroLargeTileShowName: 0 + metroWideTileShowName: 0 + metroSupportStreamingInstall: 0 + metroLastRequiredScene: 0 + metroDefaultTileSize: 1 + metroTileForegroundText: 2 + metroTileBackgroundColor: {r: 0.13333334, g: 0.17254902, b: 0.21568628, a: 0} + metroSplashScreenBackgroundColor: {r: 0.12941177, g: 0.17254902, b: 0.21568628, a: 1} + metroSplashScreenUseBackgroundColor: 0 + syncCapabilities: 0 + platformCapabilities: {} + metroTargetDeviceFamilies: {} + metroFTAName: + metroFTAFileTypes: [] + metroProtocolName: + vcxProjDefaultLanguage: + XboxOneProductId: + XboxOneUpdateKey: + XboxOneSandboxId: + XboxOneContentId: + XboxOneTitleId: + XboxOneSCId: + XboxOneGameOsOverridePath: + XboxOnePackagingOverridePath: + XboxOneAppManifestOverridePath: + XboxOneVersion: 1.0.0.0 + XboxOnePackageEncryption: 0 + XboxOnePackageUpdateGranularity: 2 + XboxOneDescription: + XboxOneLanguage: + - enus + XboxOneCapability: [] + XboxOneGameRating: {} + XboxOneIsContentPackage: 0 + XboxOneEnhancedXboxCompatibilityMode: 0 + XboxOneEnableGPUVariability: 1 + XboxOneSockets: {} + XboxOneSplashScreen: {fileID: 0} + XboxOneAllowedProductIds: [] + XboxOnePersistentLocalStorageSize: 0 + XboxOneXTitleMemory: 8 + XboxOneOverrideIdentityName: + XboxOneOverrideIdentityPublisher: + vrEditorSettings: {} + cloudServicesEnabled: {} + luminIcon: + m_Name: + m_ModelFolderPath: + m_PortalFolderPath: + luminCert: + m_CertPath: + m_SignPackage: 1 + luminIsChannelApp: 0 + luminVersion: + m_VersionCode: 1 + m_VersionName: + hmiPlayerDataPath: + hmiForceSRGBBlit: 1 + embeddedLinuxEnableGamepadInput: 0 + hmiCpuConfiguration: + hmiLogStartupTiming: 0 + qnxGraphicConfPath: + apiCompatibilityLevel: 6 + captureStartupLogs: {} + activeInputHandler: 1 + windowsGamepadBackendHint: 0 + cloudProjectId: + framebufferDepthMemorylessMode: 0 + qualitySettingsNames: [] + projectName: + organizationId: + cloudEnabled: 0 + legacyClampBlendShapeWeights: 0 + hmiLoadingImage: {fileID: 0} + platformRequiresReadableAssets: 0 + virtualTexturingSupportEnabled: 0 + insecureHttpOption: 0 + androidVulkanDenyFilterList: [] + androidVulkanAllowFilterList: [] + androidVulkanDeviceFilterListAsset: {fileID: 0} + d3d12DeviceFilterListAsset: {fileID: 0} diff --git a/ProjectSettings/ProjectVersion.txt b/ProjectSettings/ProjectVersion.txt new file mode 100644 index 0000000..b3ee2d4 --- /dev/null +++ b/ProjectSettings/ProjectVersion.txt @@ -0,0 +1,2 @@ +m_EditorVersion: 6000.2.7f2 +m_EditorVersionWithRevision: 6000.2.7f2 (2b518236b676) diff --git a/ProjectSettings/QualitySettings.asset b/ProjectSettings/QualitySettings.asset new file mode 100644 index 0000000..f55198a --- /dev/null +++ b/ProjectSettings/QualitySettings.asset @@ -0,0 +1,134 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!47 &1 +QualitySettings: + m_ObjectHideFlags: 0 + serializedVersion: 5 + m_CurrentQuality: 1 + m_QualitySettings: + - serializedVersion: 4 + name: Mobile + pixelLightCount: 2 + shadows: 2 + shadowResolution: 1 + shadowProjection: 1 + shadowCascades: 2 + shadowDistance: 40 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 0 + skinWeights: 2 + globalTextureMipmapLimit: 0 + textureMipmapLimitSettings: [] + anisotropicTextures: 1 + antiAliasing: 0 + softParticles: 0 + softVegetation: 1 + realtimeReflectionProbes: 0 + billboardsFaceCameraPosition: 1 + useLegacyDetailDistribution: 1 + adaptiveVsync: 0 + vSyncCount: 0 + realtimeGICPUUsage: 100 + adaptiveVsyncExtraA: 0 + adaptiveVsyncExtraB: 0 + lodBias: 1 + maximumLODLevel: 0 + enableLODCrossFade: 1 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 256 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 11400000, guid: 5e6cbd92db86f4b18aec3ed561671858, + type: 2} + terrainQualityOverrides: 0 + terrainPixelError: 1 + terrainDetailDensityScale: 1 + terrainBasemapDistance: 1000 + terrainDetailDistance: 80 + terrainTreeDistance: 5000 + terrainBillboardStart: 50 + terrainFadeLength: 5 + terrainMaxTrees: 50 + excludedTargetPlatforms: + - Standalone + - serializedVersion: 4 + name: PC + pixelLightCount: 2 + shadows: 2 + shadowResolution: 1 + shadowProjection: 1 + shadowCascades: 2 + shadowDistance: 40 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 1 + skinWeights: 4 + globalTextureMipmapLimit: 0 + textureMipmapLimitSettings: [] + anisotropicTextures: 2 + antiAliasing: 0 + softParticles: 0 + softVegetation: 1 + realtimeReflectionProbes: 0 + billboardsFaceCameraPosition: 1 + useLegacyDetailDistribution: 1 + adaptiveVsync: 0 + vSyncCount: 0 + realtimeGICPUUsage: 100 + adaptiveVsyncExtraA: 0 + adaptiveVsyncExtraB: 0 + lodBias: 2 + maximumLODLevel: 0 + enableLODCrossFade: 1 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 256 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 11400000, guid: 4b83569d67af61e458304325a23e5dfd, + type: 2} + terrainQualityOverrides: 0 + terrainPixelError: 1 + terrainDetailDensityScale: 1 + terrainBasemapDistance: 1000 + terrainDetailDistance: 80 + terrainTreeDistance: 5000 + terrainBillboardStart: 50 + terrainFadeLength: 5 + terrainMaxTrees: 50 + excludedTargetPlatforms: + - Android + - iPhone + m_TextureMipmapLimitGroupNames: [] + m_PerPlatformDefaultQuality: + Android: 0 + GameCoreScarlett: 1 + GameCoreXboxOne: 1 + Lumin: 0 + Nintendo Switch: 1 + PS4: 1 + PS5: 1 + Server: 0 + Stadia: 0 + Standalone: 1 + WebGL: 0 + Windows Store Apps: 0 + XboxOne: 0 + iPhone: 0 + tvOS: 0 diff --git a/ProjectSettings/SceneTemplateSettings.json b/ProjectSettings/SceneTemplateSettings.json new file mode 100644 index 0000000..ede5887 --- /dev/null +++ b/ProjectSettings/SceneTemplateSettings.json @@ -0,0 +1,121 @@ +{ + "templatePinStates": [], + "dependencyTypeInfos": [ + { + "userAdded": false, + "type": "UnityEngine.AnimationClip", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.Animations.AnimatorController", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.AnimatorOverrideController", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.Audio.AudioMixerController", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.ComputeShader", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.Cubemap", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.GameObject", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.LightingDataAsset", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.LightingSettings", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Material", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.MonoScript", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.PhysicsMaterial", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.PhysicsMaterial2D", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.PostProcessing.PostProcessProfile", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.PostProcessing.PostProcessResources", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.VolumeProfile", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.SceneAsset", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.Shader", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.ShaderVariantCollection", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.Texture", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Texture2D", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Timeline.TimelineAsset", + "defaultInstantiationMode": 0 + } + ], + "defaultDependencyTypeInfo": { + "userAdded": false, + "type": "", + "defaultInstantiationMode": 1 + }, + "newSceneOverride": 0 +} \ No newline at end of file diff --git a/ProjectSettings/ShaderGraphSettings.asset b/ProjectSettings/ShaderGraphSettings.asset new file mode 100644 index 0000000..ce8c243 --- /dev/null +++ b/ProjectSettings/ShaderGraphSettings.asset @@ -0,0 +1,19 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &1 +MonoBehaviour: + m_ObjectHideFlags: 61 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: de02f9e1d18f588468e474319d09a723, type: 3} + m_Name: + m_EditorClassIdentifier: + shaderVariantLimit: 128 + overrideShaderVariantLimit: 0 + customInterpolatorErrorThreshold: 32 + customInterpolatorWarningThreshold: 16 + customHeatmapValues: {fileID: 0} diff --git a/ProjectSettings/TagManager.asset b/ProjectSettings/TagManager.asset new file mode 100644 index 0000000..6413d11 --- /dev/null +++ b/ProjectSettings/TagManager.asset @@ -0,0 +1,76 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!78 &1 +TagManager: + serializedVersion: 2 + tags: [] + layers: + - Default + - TransparentFX + - Ignore Raycast + - + - Water + - UI + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + m_SortingLayers: + - name: Default + uniqueID: 0 + locked: 0 + m_RenderingLayers: + - Default + - Light Layer 1 + - Light Layer 2 + - Light Layer 3 + - Light Layer 4 + - Light Layer 5 + - Light Layer 6 + - Light Layer 7 + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - diff --git a/ProjectSettings/TimeManager.asset b/ProjectSettings/TimeManager.asset new file mode 100644 index 0000000..558a017 --- /dev/null +++ b/ProjectSettings/TimeManager.asset @@ -0,0 +1,9 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!5 &1 +TimeManager: + m_ObjectHideFlags: 0 + Fixed Timestep: 0.02 + Maximum Allowed Timestep: 0.33333334 + m_TimeScale: 1 + Maximum Particle Timestep: 0.03 diff --git a/ProjectSettings/URPProjectSettings.asset b/ProjectSettings/URPProjectSettings.asset new file mode 100644 index 0000000..64a8674 --- /dev/null +++ b/ProjectSettings/URPProjectSettings.asset @@ -0,0 +1,15 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &1 +MonoBehaviour: + m_ObjectHideFlags: 61 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 247994e1f5a72c2419c26a37e9334c01, type: 3} + m_Name: + m_EditorClassIdentifier: + m_LastMaterialVersion: 10 diff --git a/ProjectSettings/UnityConnectSettings.asset b/ProjectSettings/UnityConnectSettings.asset new file mode 100644 index 0000000..029ad8b --- /dev/null +++ b/ProjectSettings/UnityConnectSettings.asset @@ -0,0 +1,40 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!310 &1 +UnityConnectSettings: + m_ObjectHideFlags: 0 + serializedVersion: 1 + m_Enabled: 0 + m_TestMode: 0 + 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_DashboardUrl: https://dashboard.unity3d.com + m_TestInitMode: 0 + InsightsSettings: + m_EngineDiagnosticsEnabled: 1 + m_Enabled: 0 + CrashReportingSettings: + serializedVersion: 2 + m_EventUrl: https://perf-events.cloud.unity3d.com + m_EnableCloudDiagnosticsReporting: 0 + m_LogBufferSize: 10 + m_CaptureEditorExceptions: 1 + UnityPurchasingSettings: + m_Enabled: 0 + m_TestMode: 0 + UnityAnalyticsSettings: + m_Enabled: 0 + m_TestMode: 0 + m_InitializeOnStartup: 1 + m_PackageRequiringCoreStatsPresent: 0 + UnityAdsSettings: + m_Enabled: 0 + m_InitializeOnStartup: 1 + m_TestMode: 0 + m_IosGameId: + m_AndroidGameId: + m_GameIds: {} + m_GameId: + PerformanceReportingSettings: + m_Enabled: 0 diff --git a/ProjectSettings/VFXManager.asset b/ProjectSettings/VFXManager.asset new file mode 100644 index 0000000..3a95c98 --- /dev/null +++ b/ProjectSettings/VFXManager.asset @@ -0,0 +1,12 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!937362698 &1 +VFXManager: + m_ObjectHideFlags: 0 + m_IndirectShader: {fileID: 0} + m_CopyBufferShader: {fileID: 0} + m_SortShader: {fileID: 0} + m_StripUpdateShader: {fileID: 0} + m_RenderPipeSettingsPath: + m_FixedTimeStep: 0.016666668 + m_MaxDeltaTime: 0.05 diff --git a/ProjectSettings/VersionControlSettings.asset b/ProjectSettings/VersionControlSettings.asset new file mode 100644 index 0000000..dca2881 --- /dev/null +++ b/ProjectSettings/VersionControlSettings.asset @@ -0,0 +1,8 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!890905787 &1 +VersionControlSettings: + m_ObjectHideFlags: 0 + m_Mode: Visible Meta Files + m_CollabEditorSettings: + inProgressEnabled: 1 diff --git a/ProjectSettings/VisualScriptingSettings.asset b/ProjectSettings/VisualScriptingSettings.asset new file mode 100644 index 0000000..bea7f0c --- /dev/null +++ b/ProjectSettings/VisualScriptingSettings.asset @@ -0,0 +1,21 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &1 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 65bae8b9f1bd244b3a27e92af4b23b2a, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.VisualScripting.Core::Unity.VisualScripting.DictionaryAsset + _data: + _json: '{"dictionary":{"aotSafeMode":{"$content":true,"$type":"System.Boolean"},"favoriteMembers":{"$content":[],"$type":"System.Collections.Generic.HashSet`1[[Unity.VisualScripting.Member, + Unity.VisualScripting.Core, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]]"},"LinkerPropertyProviderSettings":{"$content":[true,true,true],"$type":"System.Collections.Generic.List`1[[System.Boolean, + mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"},"assemblyOptions":{"$content":["mscorlib","Assembly-CSharp-firstpass","Assembly-CSharp","UnityEngine","UnityEngine.CoreModule","UnityEngine.InputModule","UnityEngine.ClusterInputModule","UnityEngine.InputLegacyModule","UnityEngine.PhysicsModule","UnityEngine.Physics2DModule","UnityEngine.TerrainPhysicsModule","UnityEngine.VehiclesModule","UnityEngine.AudioModule","UnityEngine.AnimationModule","UnityEngine.VideoModule","UnityEngine.DirectorModule","UnityEngine.Timeline","UnityEngine.ParticleSystemModule","UnityEngine.ParticlesLegacyModule","UnityEngine.WindModule","UnityEngine.ClothModule","UnityEngine.TilemapModule","UnityEngine.SpriteMaskModule","UnityEngine.TerrainModule","UnityEngine.ImageConversionModule","UnityEngine.TextRenderingModule","UnityEngine.ClusterRendererModule","UnityEngine.ScreenCaptureModule","UnityEngine.AIModule","UnityEngine.UI","UnityEngine.UIModule","UnityEngine.IMGUIModule","UnityEngine.UIElementsModule","UnityEngine.StyleSheetsModule","UnityEngine.VR","UnityEngine.VRModule","UnityEngine.ARModule","UnityEngine.HoloLens","UnityEngine.SpatialTracking","UnityEngine.GoogleAudioSpatializer","UnityEngine.Networking","UnityEngine.Analytics","UnityEngine.Advertisements","UnityEngine.Purchasing","UnityEngine.UnityConnectModule","UnityEngine.UnityAnalyticsModule","UnityEngine.GameCenterModule","UnityEngine.AccessibilityModule","UnityEngine.AndroidJNIModule","UnityEngine.AssetBundleModule","UnityEngine.FileSystemHttpModule","UnityEngine.JSONSerializeModule","UnityEngine.UmbraModule","Unity.Timeline","Unity.Timeline.Editor","Cinemachine","com.unity.cinemachine.editor","Unity.InputSystem","Unity.TextMeshPro","Unity.VisualScripting.Core","Unity.VisualScripting.Flow","Unity.VisualScripting.State"],"$type":"System.Collections.Generic.List`1[[Unity.VisualScripting.LooseAssemblyName, + Unity.VisualScripting.Core, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]]"},"typeOptions":{"$content":["System.Object","System.Boolean","System.Int32","System.Single","System.String","UnityEngine.Vector2","UnityEngine.Vector3","UnityEngine.Vector4","UnityEngine.Quaternion","UnityEngine.Matrix4x4","UnityEngine.Rect","UnityEngine.Bounds","UnityEngine.Color","UnityEngine.AnimationCurve","UnityEngine.LayerMask","UnityEngine.Ray","UnityEngine.Ray2D","UnityEngine.RaycastHit","UnityEngine.RaycastHit2D","UnityEngine.ContactPoint","UnityEngine.ContactPoint2D","UnityEngine.ParticleCollisionEvent","UnityEngine.SceneManagement.Scene","UnityEngine.Application","UnityEngine.Resources","UnityEngine.Mathf","UnityEngine.Debug","UnityEngine.Input","UnityEngine.Touch","UnityEngine.Screen","UnityEngine.Cursor","UnityEngine.Time","UnityEngine.Random","UnityEngine.Physics","UnityEngine.Physics2D","UnityEngine.SceneManagement.SceneManager","UnityEngine.GUI","UnityEngine.GUILayout","UnityEngine.GUIUtility","UnityEngine.Audio.AudioMixerGroup","UnityEngine.AI.NavMesh","UnityEngine.Gizmos","UnityEngine.AnimatorStateInfo","UnityEngine.EventSystems.BaseEventData","UnityEngine.EventSystems.PointerEventData","UnityEngine.EventSystems.AxisEventData","System.Collections.IList","System.Collections.IDictionary","Unity.VisualScripting.AotList","Unity.VisualScripting.AotDictionary","System.Exception"],"$type":"System.Collections.Generic.List`1[[System.Type, + mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"},"projectSetupCompleted":{"$content":false,"$type":"System.Boolean"},"savedVersion":{"major":1,"minor":9,"patch":9,"label":null,"increment":0,"$type":"Unity.VisualScripting.SemanticVersion"}}}' + _objectReferences: [] diff --git a/ProjectSettings/XRSettings.asset b/ProjectSettings/XRSettings.asset new file mode 100644 index 0000000..482590c --- /dev/null +++ b/ProjectSettings/XRSettings.asset @@ -0,0 +1,10 @@ +{ + "m_SettingKeys": [ + "VR Device Disabled", + "VR Device User Alert" + ], + "m_SettingValues": [ + "False", + "False" + ] +} \ No newline at end of file From 6ded599bb825ef8c4788b24cec174ca2ec5d2bb2 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Tue, 25 Nov 2025 14:28:08 +0100 Subject: [PATCH 002/179] WIP: Added boundary --- .gitignore | 7 +- Assembly-CSharp-Editor.csproj | 2578 +++++++++---------- Assembly-CSharp.csproj | 2464 +++++++++--------- Assets/Scenes/Boids/Boids.unity | 707 +++++ Assets/Scenes/Boids/Scripts/Boid.cs | 75 +- Assets/Scenes/Boids/Scripts/SwarmControl.cs | 4 + Assets/_Recovery.meta | 8 - Assets/_Recovery/0.unity | 474 ---- Assets/_Recovery/0.unity.meta | 7 - Packages/manifest.json | 2 +- Packages/packages-lock.json | 12 +- ProjectSettings/GraphicsSettings.asset | 9 +- ProjectSettings/ProjectVersion.txt | 4 +- 13 files changed, 3295 insertions(+), 3056 deletions(-) delete mode 100644 Assets/_Recovery.meta delete mode 100644 Assets/_Recovery/0.unity delete mode 100644 Assets/_Recovery/0.unity.meta diff --git a/.gitignore b/.gitignore index 8bd4dbe..3f5d4d8 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,9 @@ Library Assets/Settings Logs Temp -UserSettings \ No newline at end of file +UserSettings +Assets/DefaultVolumeProfile.asset +Assets/DefaultVolumeProfile.asset.meta +Assets/UniversalRenderPipelineGlobalSettings.asset +Assets/UniversalRenderPipelineGlobalSettings.asset.meta +NanoBrain-Unity.slnx diff --git a/Assembly-CSharp-Editor.csproj b/Assembly-CSharp-Editor.csproj index 740c939..0750862 100644 --- a/Assembly-CSharp-Editor.csproj +++ b/Assembly-CSharp-Editor.csproj @@ -1,1293 +1,1285 @@ - - - - Temp\obj\$(MSBuildProjectName) - $(BaseIntermediateOutputPath) - false - true - Temp\bin\Debug\ - - - - - - - false - false - 9.0 - - Library - Assembly-CSharp-Editor - netstandard2.1 - . - - - 0169;USG0001 - UNITY_6000_2_7;UNITY_6000_2;UNITY_6000;UNITY_5_3_OR_NEWER;UNITY_5_4_OR_NEWER;UNITY_5_5_OR_NEWER;UNITY_5_6_OR_NEWER;UNITY_2017_1_OR_NEWER;UNITY_2017_2_OR_NEWER;UNITY_2017_3_OR_NEWER;UNITY_2017_4_OR_NEWER;UNITY_2018_1_OR_NEWER;UNITY_2018_2_OR_NEWER;UNITY_2018_3_OR_NEWER;UNITY_2018_4_OR_NEWER;UNITY_2019_1_OR_NEWER;UNITY_2019_2_OR_NEWER;UNITY_2019_3_OR_NEWER;UNITY_2019_4_OR_NEWER;UNITY_2020_1_OR_NEWER;UNITY_2020_2_OR_NEWER;UNITY_2020_3_OR_NEWER;UNITY_2021_1_OR_NEWER;UNITY_2021_2_OR_NEWER;UNITY_2021_3_OR_NEWER;UNITY_2022_1_OR_NEWER;UNITY_2022_2_OR_NEWER;UNITY_2022_3_OR_NEWER;UNITY_2023_1_OR_NEWER;UNITY_2023_2_OR_NEWER;UNITY_2023_3_OR_NEWER;UNITY_6000_0_OR_NEWER;UNITY_6000_1_OR_NEWER;UNITY_6000_2_OR_NEWER;PLATFORM_ARCH_64;UNITY_64;UNITY_INCLUDE_TESTS;ENABLE_AR;ENABLE_AUDIO;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_EVENT_QUEUE;ENABLE_MICROPHONE;ENABLE_MULTIPLE_DISPLAYS;ENABLE_PHYSICS;ENABLE_TEXTURE_STREAMING;ENABLE_VIRTUALTEXTURING;ENABLE_LZMA;ENABLE_UNITYEVENTS;ENABLE_VR;ENABLE_WEBCAM;ENABLE_UNITYWEBREQUEST;ENABLE_WWW;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_SERVICES_USE_WEBREQUEST;ENABLE_UNITY_CONSENT;ENABLE_UNITY_CLOUD_IDENTIFIERS;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_NATIVE_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_EDITOR_GAME_SERVICES;ENABLE_UNITY_GAME_SERVICES_ANALYTICS_SUPPORT;ENABLE_CLOUD_LICENSE;ENABLE_EDITOR_HUB_LICENSE;ENABLE_WEBSOCKET_CLIENT;ENABLE_GENERATE_NATIVE_PLUGINS_FOR_ASSEMBLIES_API;ENABLE_DIRECTOR_AUDIO;ENABLE_DIRECTOR_TEXTURE;ENABLE_MANAGED_JOBS;ENABLE_MANAGED_TRANSFORM_JOBS;ENABLE_MANAGED_ANIMATION_JOBS;ENABLE_MANAGED_AUDIO_JOBS;ENABLE_MANAGED_UNITYTLS;INCLUDE_DYNAMIC_GI;ENABLE_SCRIPTING_GC_WBARRIERS;PLATFORM_SUPPORTS_MONO;RENDER_SOFTWARE_CURSOR;ENABLE_MARSHALLING_TESTS;ENABLE_VIDEO;ENABLE_NAVIGATION_OFFMESHLINK_TO_NAVMESHLINK;ENABLE_ACCELERATOR_CLIENT_DEBUGGING;TEXTCORE_1_0_OR_NEWER;EDITOR_ONLY_NAVMESH_BUILDER_DEPRECATED;PLATFORM_STANDALONE_WIN;PLATFORM_STANDALONE;UNITY_STANDALONE_WIN;UNITY_STANDALONE;ENABLE_RUNTIME_GI;ENABLE_MOVIES;ENABLE_NETWORK;ENABLE_NVIDIA;ENABLE_AMD;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_CLOUD_SERVICES_ENGINE_DIAGNOSTICS;ENABLE_OUT_OF_PROCESS_CRASH_HANDLER;ENABLE_CLUSTER_SYNC;ENABLE_CLUSTERINPUT;PLATFORM_UPDATES_TIME_OUTSIDE_OF_PLAYER_LOOP;GFXDEVICE_WAITFOREVENT_MESSAGEPUMP;PLATFORM_USES_EXPLICIT_MEMORY_MANAGER_INITIALIZER;PLATFORM_SUPPORTS_WAIT_FOR_PRESENTATION;PLATFORM_SUPPORTS_SPLIT_GRAPHICS_JOBS;ENABLE_MONO;NET_4_6;NET_UNITY_4_8;ENABLE_PROFILER;DEBUG;TRACE;UNITY_ASSERTIONS;UNITY_EDITOR;UNITY_EDITOR_64;UNITY_EDITOR_WIN;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_BURST_AOT;UNITY_TEAM_LICENSE;ENABLE_CUSTOM_RENDER_TEXTURE;ENABLE_DIRECTOR;ENABLE_LOCALIZATION;ENABLE_SPRITES;ENABLE_TERRAIN;ENABLE_TILEMAP;ENABLE_TIMELINE;ENABLE_INPUT_SYSTEM;TEXTCORE_FONT_ENGINE_1_5_OR_NEWER;TEXTCORE_TEXT_ENGINE_1_5_OR_NEWER;CSHARP_7_OR_LATER;CSHARP_7_3_OR_NEWER;UNITY_EDITOR_ONLY_COMPILATION - False - - - true - true - true - true - MSB3277 - - - Package - 2.0.23 - SDK - Editor:5 - StandaloneWindows64:19 - 6000.2.7f2 - - - - - - - - - - - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.AIModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.AMDModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.ARModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.AccessibilityModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.AndroidJNIModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.AnimationModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.AssetBundleModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.AudioModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.ClothModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.ClusterInputModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.ClusterRendererModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.ContentLoadModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.CrashReportingModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.DSPGraphModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.DirectorModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.GIModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.GameCenterModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.GraphicsStateCollectionSerializerModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.GridModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.HierarchyCoreModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.HotReloadModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.IMGUIModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.IdentifiersModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.ImageConversionModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.InputModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.InputForUIModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.InputLegacyModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.InsightsModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.JSONSerializeModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.LocalizationModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.MarshallingModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.MultiplayerModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.NVIDIAModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.ParticleSystemModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.PerformanceReportingModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.PhysicsModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.Physics2DModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.PropertiesModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.RuntimeInitializeOnLoadManagerInitializerModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.ScreenCaptureModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.ShaderVariantAnalyticsModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.SharedInternalsModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.SpriteMaskModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.SpriteShapeModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.StreamingModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.SubstanceModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.SubsystemsModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.TLSModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.TerrainModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.TerrainPhysicsModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.TextCoreFontEngineModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.TextCoreTextEngineModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.TextRenderingModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.TilemapModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UIModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UIElementsModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UmbraModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityAnalyticsModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityAnalyticsCommonModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityConnectModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityConsentModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityCurlModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityTestProtocolModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestAssetBundleModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestAudioModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestTextureModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestWWWModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.VFXModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.VRModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.VehiclesModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.VideoModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.VirtualTexturingModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.WindModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.XRModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.AccessibilityModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.AdaptivePerformanceModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.BuildProfileModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.ClothModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.CoreBusinessMetricsModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.CoreModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.DeviceSimulatorModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.DiagnosticsModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.EditorToolbarModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.EmbreeModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.GIModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.GraphViewModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.GraphicsStateCollectionSerializerModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.GridAndSnapModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.GridModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.InAppPurchasingModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.LevelPlayModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.MultiplayerModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.Physics2DModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.PhysicsModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.PresetsUIModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.PropertiesModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.QuickSearchModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.SafeModeModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.SceneTemplateModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.SceneViewModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.ShaderFoundryModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.SketchUpModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.SpriteMaskModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.SpriteShapeModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.SubstanceModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.TerrainModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.TextCoreFontEngineModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.TextCoreTextEngineModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.TextRenderingModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.TilemapModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.TreeModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.UIAutomationModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.UIBuilderModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.UIElementsModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.UIElementsSamplesModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.UmbraModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.UnityConnectModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.VFXModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.VideoModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.XRModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEditor.Graphs.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\PlaybackEngines\WindowsStandaloneSupport\UnityEditor.WindowsStandalone.Extensions.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\PlaybackEngines\AndroidPlayer\UnityEditor.Android.Extensions.dll - False - - - Library\PackageCache\com.unity.collections@d49facba0036\Unity.Collections.LowLevel.ILSupport\Unity.Collections.LowLevel.ILSupport.dll - False - - - Library\PackageCache\com.unity.ext.nunit@031a54704bff\net40\unity-custom\nunit.framework.dll - False - - - Library\PackageCache\com.unity.collab-proxy@3351acaba9c9\Lib\Editor\Unity.Plastic.Antlr3.Runtime.dll - False - - - Library\PackageCache\com.unity.collab-proxy@3351acaba9c9\Lib\Editor\Unity.Plastic.Newtonsoft.Json.dll - False - - - Library\PackageCache\com.unity.collab-proxy@3351acaba9c9\Lib\Editor\log4netPlastic.dll - False - - - Library\PackageCache\com.unity.collab-proxy@3351acaba9c9\Lib\Editor\unityplastic.dll - False - - - Library\PackageCache\com.unity.collections@d49facba0036\Unity.Collections.Tests\System.IO.Hashing\System.IO.Hashing.dll - False - - - Library\PackageCache\com.unity.nuget.mono-cecil@d78732e851eb\Mono.Cecil.dll - False - - - Library\PackageCache\com.unity.collections@d49facba0036\Unity.Collections.Tests\System.Runtime.CompilerServices.Unsafe\System.Runtime.CompilerServices.Unsafe.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\PlaybackEngines\AndroidPlayer\Unity.Android.Types.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\PlaybackEngines\AndroidPlayer\Unity.Android.Gradle.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\mscorlib.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Core.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Runtime.Serialization.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Xml.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Xml.Linq.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Numerics.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Numerics.Vectors.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Net.Http.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.IO.Compression.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Microsoft.CSharp.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Data.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Data.DataSetExtensions.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Drawing.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.IO.Compression.FileSystem.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.ComponentModel.Composition.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Transactions.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\Microsoft.Win32.Primitives.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\netstandard.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.AppContext.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Buffers.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Collections.Concurrent.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Collections.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Collections.NonGeneric.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Collections.Specialized.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ComponentModel.Annotations.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ComponentModel.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ComponentModel.EventBasedAsync.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ComponentModel.Primitives.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ComponentModel.TypeConverter.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Console.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Data.Common.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.Contracts.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.Debug.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.FileVersionInfo.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.Process.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.StackTrace.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.TextWriterTraceListener.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.Tools.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.TraceSource.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Drawing.Primitives.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Dynamic.Runtime.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Globalization.Calendars.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Globalization.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Globalization.Extensions.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.Compression.ZipFile.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.FileSystem.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.FileSystem.DriveInfo.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.FileSystem.Primitives.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.FileSystem.Watcher.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.IsolatedStorage.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.MemoryMappedFiles.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.Pipes.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.UnmanagedMemoryStream.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Linq.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Linq.Expressions.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Linq.Parallel.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Linq.Queryable.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Memory.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.Http.Rtc.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.NameResolution.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.NetworkInformation.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.Ping.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.Primitives.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.Requests.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.Security.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.Sockets.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.WebHeaderCollection.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.WebSockets.Client.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.WebSockets.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ObjectModel.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.DispatchProxy.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.Emit.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.Emit.ILGeneration.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.Emit.Lightweight.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.Extensions.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.Primitives.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Resources.Reader.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Resources.ResourceManager.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Resources.Writer.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.CompilerServices.VisualC.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Extensions.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Handles.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.InteropServices.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.InteropServices.RuntimeInformation.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.InteropServices.WindowsRuntime.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Numerics.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Serialization.Formatters.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Serialization.Json.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Serialization.Primitives.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Serialization.Xml.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Claims.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Cryptography.Algorithms.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Cryptography.Csp.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Cryptography.Encoding.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Cryptography.Primitives.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Cryptography.X509Certificates.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Principal.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.SecureString.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ServiceModel.Duplex.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ServiceModel.Http.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ServiceModel.NetTcp.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ServiceModel.Primitives.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ServiceModel.Security.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Text.Encoding.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Text.Encoding.Extensions.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Text.RegularExpressions.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.Overlapped.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.Tasks.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.Tasks.Extensions.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.Tasks.Parallel.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.Thread.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.ThreadPool.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.Timer.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ValueTuple.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Xml.ReaderWriter.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Xml.XDocument.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Xml.XmlDocument.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Xml.XmlSerializer.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Xml.XPath.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Xml.XPath.XDocument.dll - False - - - Library\ScriptAssemblies\UnityEditor.TestRunner.dll - False - - - Library\ScriptAssemblies\UnityEngine.TestRunner.dll - False - - - Library\ScriptAssemblies\Unity.RenderPipelines.Core.Runtime.dll - False - - - Library\ScriptAssemblies\Unity.RenderPipelines.Core.Editor.dll - False - - - Library\ScriptAssemblies\Unity.TextMeshPro.Editor.dll - False - - - Library\ScriptAssemblies\Unity.TextMeshPro.dll - False - - - Library\ScriptAssemblies\Unity.VisualStudio.Editor.dll - False - - - Library\ScriptAssemblies\Unity.AI.Navigation.dll - False - - - Library\ScriptAssemblies\Unity.RenderPipelines.Core.ShaderLibrary.dll - False - - - Library\ScriptAssemblies\Unity.Collections.dll - False - - - Library\ScriptAssemblies\Unity.InputSystem.ForUI.dll - False - - - Library\ScriptAssemblies\Unity.RenderPipelines.GPUDriven.Runtime.dll - False - - - Library\ScriptAssemblies\Unity.Timeline.Editor.dll - False - - - Library\ScriptAssemblies\Unity.Mathematics.dll - False - - - Library\ScriptAssemblies\Unity.RenderPipelines.Universal.Shaders.dll - False - - - Library\ScriptAssemblies\UnityEngine.UI.dll - False - - - Library\ScriptAssemblies\Unity.Multiplayer.Center.Common.dll - False - - - Library\ScriptAssemblies\Unity.RenderPipelines.Universal.Editor.dll - False - - - Library\ScriptAssemblies\Unity.Burst.dll - False - - - Library\ScriptAssemblies\Unity.Timeline.dll - False - - - Library\ScriptAssemblies\Unity.AI.Navigation.Updater.dll - False - - - Library\ScriptAssemblies\Unity.AI.Navigation.Editor.dll - False - - - Library\ScriptAssemblies\PPv2URPConverters.dll - False - - - Library\ScriptAssemblies\Unity.RenderPipelines.Core.Runtime.Shared.dll - False - - - Library\ScriptAssemblies\Unity.Multiplayer.Center.Editor.dll - False - - - Library\ScriptAssemblies\Unity.RenderPipelines.Universal.2D.Runtime.dll - False - - - Library\ScriptAssemblies\Unity.Searcher.Editor.dll - False - - - Library\ScriptAssemblies\Unity.PlasticSCM.Editor.dll - False - - - Library\ScriptAssemblies\Unity.RenderPipelines.Universal.Runtime.dll - False - - - Library\ScriptAssemblies\Unity.Burst.Editor.dll - False - - - Library\ScriptAssemblies\Unity.Rendering.LightTransport.Runtime.dll - False - - - Library\ScriptAssemblies\Unity.Mathematics.Editor.dll - False - - - Library\ScriptAssemblies\Unity.RenderPipelines.Universal.Config.Runtime.dll - False - - - Library\ScriptAssemblies\Unity.RenderPipeline.Universal.ShaderLibrary.dll - False - - - Library\ScriptAssemblies\Unity.Collections.Editor.dll - False - - - Library\ScriptAssemblies\Unity.ShaderGraph.Editor.dll - False - - - Library\ScriptAssemblies\Unity.Rendering.LightTransport.Editor.dll - False - - - Library\ScriptAssemblies\Unity.RenderPipelines.Core.Editor.Shared.dll - False - - - Library\ScriptAssemblies\Unity.InputSystem.dll - False - - - Library\ScriptAssemblies\Unity.Rider.Editor.dll - False - - - Library\ScriptAssemblies\Unity.AI.Navigation.Editor.ConversionSystem.dll - False - - - Library\ScriptAssemblies\UnityEditor.UI.dll - False - - - Library\ScriptAssemblies\Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary.dll - False - - - - - - - - - - - - - - - - - + + + + Temp/obj/$(MSBuildProjectName) + $(BaseIntermediateOutputPath) + false + true + Temp/bin/Debug/ + + + + + + + false + false + 9.0 + + Library + Assembly-CSharp-Editor + netstandard2.1 + . + + + 0169;USG0001 + UNITY_6000_2_13;UNITY_6000_2;UNITY_6000;UNITY_5_3_OR_NEWER;UNITY_5_4_OR_NEWER;UNITY_5_5_OR_NEWER;UNITY_5_6_OR_NEWER;UNITY_2017_1_OR_NEWER;UNITY_2017_2_OR_NEWER;UNITY_2017_3_OR_NEWER;UNITY_2017_4_OR_NEWER;UNITY_2018_1_OR_NEWER;UNITY_2018_2_OR_NEWER;UNITY_2018_3_OR_NEWER;UNITY_2018_4_OR_NEWER;UNITY_2019_1_OR_NEWER;UNITY_2019_2_OR_NEWER;UNITY_2019_3_OR_NEWER;UNITY_2019_4_OR_NEWER;UNITY_2020_1_OR_NEWER;UNITY_2020_2_OR_NEWER;UNITY_2020_3_OR_NEWER;UNITY_2021_1_OR_NEWER;UNITY_2021_2_OR_NEWER;UNITY_2021_3_OR_NEWER;UNITY_2022_1_OR_NEWER;UNITY_2022_2_OR_NEWER;UNITY_2022_3_OR_NEWER;UNITY_2023_1_OR_NEWER;UNITY_2023_2_OR_NEWER;UNITY_2023_3_OR_NEWER;UNITY_6000_0_OR_NEWER;UNITY_6000_1_OR_NEWER;UNITY_6000_2_OR_NEWER;PLATFORM_ARCH_64;UNITY_64;UNITY_INCLUDE_TESTS;ENABLE_AUDIO;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_MICROPHONE;ENABLE_MULTIPLE_DISPLAYS;ENABLE_PHYSICS;ENABLE_TEXTURE_STREAMING;ENABLE_VIRTUALTEXTURING;ENABLE_LZMA;ENABLE_UNITYEVENTS;ENABLE_VR;ENABLE_WEBCAM;ENABLE_UNITYWEBREQUEST;ENABLE_WWW;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_SERVICES_USE_WEBREQUEST;ENABLE_UNITY_CONSENT;ENABLE_UNITY_CLOUD_IDENTIFIERS;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_EDITOR_GAME_SERVICES;ENABLE_UNITY_GAME_SERVICES_ANALYTICS_SUPPORT;ENABLE_CLOUD_LICENSE;ENABLE_EDITOR_HUB_LICENSE;ENABLE_WEBSOCKET_CLIENT;ENABLE_GENERATE_NATIVE_PLUGINS_FOR_ASSEMBLIES_API;ENABLE_DIRECTOR_AUDIO;ENABLE_DIRECTOR_TEXTURE;ENABLE_MANAGED_JOBS;ENABLE_MANAGED_TRANSFORM_JOBS;ENABLE_MANAGED_ANIMATION_JOBS;ENABLE_MANAGED_AUDIO_JOBS;ENABLE_MANAGED_UNITYTLS;INCLUDE_DYNAMIC_GI;ENABLE_SCRIPTING_GC_WBARRIERS;PLATFORM_SUPPORTS_MONO;RENDER_SOFTWARE_CURSOR;ENABLE_MARSHALLING_TESTS;ENABLE_VIDEO;ENABLE_NAVIGATION_OFFMESHLINK_TO_NAVMESHLINK;ENABLE_ACCELERATOR_CLIENT_DEBUGGING;TEXTCORE_1_0_OR_NEWER;EDITOR_ONLY_NAVMESH_BUILDER_DEPRECATED;PLATFORM_STANDALONE_LINUX;PLATFORM_STANDALONE;UNITY_STANDALONE_LINUX;UNITY_STANDALONE;UNITY_STANDALONE_LINUX_API;ENABLE_RUNTIME_GI;ENABLE_MOVIES;ENABLE_NETWORK;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_CLUSTER_SYNC;ENABLE_CLUSTERINPUT;ENABLE_SPATIALTRACKING;ENABLE_MODULAR_UNITYENGINE_ASSEMBLIES;PLATFORM_SUPPORTS_SPLIT_GRAPHICS_JOBS;PLATFORM_USES_EXPLICIT_MEMORY_MANAGER_INITIALIZER;ENABLE_MONO;NET_4_6;NET_UNITY_4_8;ENABLE_PROFILER;DEBUG;TRACE;UNITY_ASSERTIONS;UNITY_EDITOR;UNITY_EDITOR_64;UNITY_EDITOR_LINUX;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_BURST_AOT;UNITY_TEAM_LICENSE;ENABLE_CUSTOM_RENDER_TEXTURE;ENABLE_DIRECTOR;ENABLE_LOCALIZATION;ENABLE_SPRITES;ENABLE_TERRAIN;ENABLE_TILEMAP;ENABLE_TIMELINE;ENABLE_INPUT_SYSTEM;TEXTCORE_FONT_ENGINE_1_5_OR_NEWER;TEXTCORE_TEXT_ENGINE_1_5_OR_NEWER;CSHARP_7_OR_LATER;CSHARP_7_3_OR_NEWER;UNITY_EDITOR_ONLY_COMPILATION + False + + + true + true + true + true + MSB3277 + + + Package + 2.0.25 + SDK + Editor:5 + StandaloneLinux64:24 + 6000.2.13f1 + + + + + + + + + + + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.AIModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.AMDModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.ARModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.AccessibilityModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.AndroidJNIModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.AnimationModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.AssetBundleModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.AudioModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.ClothModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.ClusterInputModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.ClusterRendererModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.ContentLoadModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.CoreModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.CrashReportingModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.DSPGraphModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.DirectorModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.GIModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.GameCenterModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.GraphicsStateCollectionSerializerModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.GridModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.HierarchyCoreModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.HotReloadModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.IMGUIModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.IdentifiersModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.ImageConversionModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.InputModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.InputForUIModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.InputLegacyModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.InsightsModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.JSONSerializeModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.LocalizationModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.MarshallingModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.MultiplayerModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.NVIDIAModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.ParticleSystemModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.PerformanceReportingModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.PhysicsModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.Physics2DModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.PropertiesModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.RuntimeInitializeOnLoadManagerInitializerModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.ScreenCaptureModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.ShaderVariantAnalyticsModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.SharedInternalsModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.SpriteMaskModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.SpriteShapeModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.StreamingModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.SubstanceModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.SubsystemsModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.TLSModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.TerrainModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.TerrainPhysicsModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.TextCoreFontEngineModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.TextCoreTextEngineModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.TextRenderingModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.TilemapModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UIModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UIElementsModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UmbraModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityAnalyticsModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityAnalyticsCommonModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityConnectModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityConsentModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityCurlModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityTestProtocolModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityWebRequestModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityWebRequestAssetBundleModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityWebRequestAudioModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityWebRequestTextureModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityWebRequestWWWModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.VFXModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.VRModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.VehiclesModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.VideoModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.VirtualTexturingModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.WindModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.XRModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.AccessibilityModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.AdaptivePerformanceModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.BuildProfileModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.ClothModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.CoreBusinessMetricsModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.CoreModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.DeviceSimulatorModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.DiagnosticsModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.EditorToolbarModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.EmbreeModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.GIModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.GraphViewModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.GraphicsStateCollectionSerializerModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.GridAndSnapModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.GridModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.InAppPurchasingModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.LevelPlayModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.MultiplayerModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.Physics2DModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.PhysicsModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.PresetsUIModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.PropertiesModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.QuickSearchModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.SafeModeModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.SceneTemplateModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.SceneViewModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.ShaderFoundryModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.SketchUpModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.SpriteMaskModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.SpriteShapeModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.SubstanceModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.TerrainModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.TextCoreFontEngineModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.TextCoreTextEngineModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.TextRenderingModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.TilemapModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.TreeModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.UIAutomationModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.UIBuilderModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.UIElementsModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.UIElementsSamplesModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.UmbraModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.UnityConnectModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.VFXModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.VideoModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.XRModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEditor.Graphs.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/PlaybackEngines/WebGLSupport/UnityEditor.WebGL.Extensions.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/PlaybackEngines/LinuxStandaloneSupport/UnityEditor.LinuxStandalone.Extensions.dll + False + + + Library/PackageCache/com.unity.collections@aea9d3bd5e19/Unity.Collections.LowLevel.ILSupport/Unity.Collections.LowLevel.ILSupport.dll + False + + + Library/PackageCache/com.unity.ext.nunit@b16e6d09cd93/net40/unity-custom/nunit.framework.dll + False + + + Library/PackageCache/com.unity.collab-proxy@3351acaba9c9/Lib/Editor/Unity.Plastic.Antlr3.Runtime.dll + False + + + Library/PackageCache/com.unity.collab-proxy@3351acaba9c9/Lib/Editor/Unity.Plastic.Newtonsoft.Json.dll + False + + + Library/PackageCache/com.unity.collab-proxy@3351acaba9c9/Lib/Editor/log4netPlastic.dll + False + + + Library/PackageCache/com.unity.collab-proxy@3351acaba9c9/Lib/Editor/unityplastic.dll + False + + + Library/PackageCache/com.unity.collections@aea9d3bd5e19/Unity.Collections.Tests/System.IO.Hashing/System.IO.Hashing.dll + False + + + Library/PackageCache/com.unity.nuget.mono-cecil@d78732e851eb/Mono.Cecil.dll + False + + + Library/PackageCache/com.unity.collections@aea9d3bd5e19/Unity.Collections.Tests/System.Runtime.CompilerServices.Unsafe/System.Runtime.CompilerServices.Unsafe.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/mscorlib.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Core.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Runtime.Serialization.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Xml.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Xml.Linq.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Numerics.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Numerics.Vectors.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Net.Http.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.IO.Compression.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Microsoft.CSharp.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Data.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Data.DataSetExtensions.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Drawing.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.IO.Compression.FileSystem.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.ComponentModel.Composition.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Transactions.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/Microsoft.Win32.Primitives.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.AppContext.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Buffers.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.Concurrent.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.NonGeneric.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.Specialized.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.Annotations.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.EventBasedAsync.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.Primitives.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.TypeConverter.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Console.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Data.Common.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Contracts.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Debug.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.FileVersionInfo.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Process.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.StackTrace.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.TextWriterTraceListener.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Tools.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.TraceSource.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Drawing.Primitives.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Dynamic.Runtime.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Globalization.Calendars.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Globalization.Extensions.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Globalization.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.Compression.ZipFile.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.DriveInfo.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.Primitives.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.Watcher.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.IsolatedStorage.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.MemoryMappedFiles.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.Pipes.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.UnmanagedMemoryStream.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.Expressions.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.Parallel.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.Queryable.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Memory.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Http.Rtc.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.NameResolution.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.NetworkInformation.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Ping.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Primitives.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Requests.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Security.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Sockets.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.WebHeaderCollection.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.WebSockets.Client.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.WebSockets.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ObjectModel.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.DispatchProxy.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Emit.ILGeneration.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Emit.Lightweight.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Emit.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Extensions.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Primitives.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Resources.Reader.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Resources.ResourceManager.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Resources.Writer.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.CompilerServices.VisualC.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Extensions.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Handles.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.InteropServices.RuntimeInformation.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.InteropServices.WindowsRuntime.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.InteropServices.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Numerics.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Formatters.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Json.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Primitives.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Xml.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Claims.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Algorithms.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Csp.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Encoding.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Primitives.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.X509Certificates.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Principal.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.SecureString.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Duplex.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Http.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.NetTcp.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Primitives.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Security.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Text.Encoding.Extensions.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Text.Encoding.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Text.RegularExpressions.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Overlapped.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Tasks.Extensions.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Tasks.Parallel.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Tasks.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Thread.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.ThreadPool.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Timer.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ValueTuple.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.ReaderWriter.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XDocument.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XPath.XDocument.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XPath.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XmlDocument.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XmlSerializer.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/netstandard.dll + False + + + Library/ScriptAssemblies/UnityEditor.TestRunner.dll + False + + + Library/ScriptAssemblies/UnityEngine.TestRunner.dll + False + + + Library/ScriptAssemblies/Unity.RenderPipelines.Core.Runtime.dll + False + + + Library/ScriptAssemblies/Unity.RenderPipelines.Core.Editor.dll + False + + + Library/ScriptAssemblies/Unity.TextMeshPro.Editor.dll + False + + + Library/ScriptAssemblies/Unity.TextMeshPro.dll + False + + + Library/ScriptAssemblies/Unity.VisualStudio.Editor.dll + False + + + Library/ScriptAssemblies/Unity.AI.Navigation.dll + False + + + Library/ScriptAssemblies/Unity.RenderPipelines.Core.ShaderLibrary.dll + False + + + Library/ScriptAssemblies/Unity.Collections.dll + False + + + Library/ScriptAssemblies/Unity.InputSystem.ForUI.dll + False + + + Library/ScriptAssemblies/Unity.RenderPipelines.GPUDriven.Runtime.dll + False + + + Library/ScriptAssemblies/Unity.Timeline.Editor.dll + False + + + Library/ScriptAssemblies/Unity.Mathematics.dll + False + + + Library/ScriptAssemblies/Unity.RenderPipelines.Universal.Shaders.dll + False + + + Library/ScriptAssemblies/UnityEngine.UI.dll + False + + + Library/ScriptAssemblies/Unity.Multiplayer.Center.Common.dll + False + + + Library/ScriptAssemblies/Unity.RenderPipelines.Universal.Editor.dll + False + + + Library/ScriptAssemblies/Unity.Burst.dll + False + + + Library/ScriptAssemblies/Unity.Timeline.dll + False + + + Library/ScriptAssemblies/Unity.AI.Navigation.Updater.dll + False + + + Library/ScriptAssemblies/Unity.AI.Navigation.Editor.dll + False + + + Library/ScriptAssemblies/PPv2URPConverters.dll + False + + + Library/ScriptAssemblies/Unity.RenderPipelines.Core.Runtime.Shared.dll + False + + + Library/ScriptAssemblies/Unity.Multiplayer.Center.Editor.dll + False + + + Library/ScriptAssemblies/Unity.RenderPipelines.Universal.2D.Runtime.dll + False + + + Library/ScriptAssemblies/Unity.Searcher.Editor.dll + False + + + Library/ScriptAssemblies/Unity.PlasticSCM.Editor.dll + False + + + Library/ScriptAssemblies/Unity.RenderPipelines.Universal.Runtime.dll + False + + + Library/ScriptAssemblies/Unity.Burst.Editor.dll + False + + + Library/ScriptAssemblies/Unity.Rendering.LightTransport.Runtime.dll + False + + + Library/ScriptAssemblies/Unity.Mathematics.Editor.dll + False + + + Library/ScriptAssemblies/Unity.RenderPipelines.Universal.Config.Runtime.dll + False + + + Library/ScriptAssemblies/Unity.RenderPipeline.Universal.ShaderLibrary.dll + False + + + Library/ScriptAssemblies/Unity.Collections.Editor.dll + False + + + Library/ScriptAssemblies/Unity.ShaderGraph.Editor.dll + False + + + Library/ScriptAssemblies/Unity.Rendering.LightTransport.Editor.dll + False + + + Library/ScriptAssemblies/Unity.RenderPipelines.Core.Editor.Shared.dll + False + + + Library/ScriptAssemblies/Unity.InputSystem.dll + False + + + Library/ScriptAssemblies/Unity.Rider.Editor.dll + False + + + Library/ScriptAssemblies/Unity.AI.Navigation.Editor.ConversionSystem.dll + False + + + Library/ScriptAssemblies/UnityEditor.UI.dll + False + + + Library/ScriptAssemblies/Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary.dll + False + + + + + + + + + + + + + + + + + diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index 828c178..140f0c3 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -1,1240 +1,1224 @@ - - - - Temp\obj\$(MSBuildProjectName) - $(BaseIntermediateOutputPath) - false - true - Temp\bin\Debug\ - - - - - - - false - false - 9.0 - - Library - Assembly-CSharp - netstandard2.1 - . - - - 0169;USG0001 - UNITY_6000_2_7;UNITY_6000_2;UNITY_6000;UNITY_5_3_OR_NEWER;UNITY_5_4_OR_NEWER;UNITY_5_5_OR_NEWER;UNITY_5_6_OR_NEWER;UNITY_2017_1_OR_NEWER;UNITY_2017_2_OR_NEWER;UNITY_2017_3_OR_NEWER;UNITY_2017_4_OR_NEWER;UNITY_2018_1_OR_NEWER;UNITY_2018_2_OR_NEWER;UNITY_2018_3_OR_NEWER;UNITY_2018_4_OR_NEWER;UNITY_2019_1_OR_NEWER;UNITY_2019_2_OR_NEWER;UNITY_2019_3_OR_NEWER;UNITY_2019_4_OR_NEWER;UNITY_2020_1_OR_NEWER;UNITY_2020_2_OR_NEWER;UNITY_2020_3_OR_NEWER;UNITY_2021_1_OR_NEWER;UNITY_2021_2_OR_NEWER;UNITY_2021_3_OR_NEWER;UNITY_2022_1_OR_NEWER;UNITY_2022_2_OR_NEWER;UNITY_2022_3_OR_NEWER;UNITY_2023_1_OR_NEWER;UNITY_2023_2_OR_NEWER;UNITY_2023_3_OR_NEWER;UNITY_6000_0_OR_NEWER;UNITY_6000_1_OR_NEWER;UNITY_6000_2_OR_NEWER;PLATFORM_ARCH_64;UNITY_64;UNITY_INCLUDE_TESTS;ENABLE_AR;ENABLE_AUDIO;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_EVENT_QUEUE;ENABLE_MICROPHONE;ENABLE_MULTIPLE_DISPLAYS;ENABLE_PHYSICS;ENABLE_TEXTURE_STREAMING;ENABLE_VIRTUALTEXTURING;ENABLE_LZMA;ENABLE_UNITYEVENTS;ENABLE_VR;ENABLE_WEBCAM;ENABLE_UNITYWEBREQUEST;ENABLE_WWW;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_SERVICES_USE_WEBREQUEST;ENABLE_UNITY_CONSENT;ENABLE_UNITY_CLOUD_IDENTIFIERS;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_NATIVE_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_EDITOR_GAME_SERVICES;ENABLE_UNITY_GAME_SERVICES_ANALYTICS_SUPPORT;ENABLE_CLOUD_LICENSE;ENABLE_EDITOR_HUB_LICENSE;ENABLE_WEBSOCKET_CLIENT;ENABLE_GENERATE_NATIVE_PLUGINS_FOR_ASSEMBLIES_API;ENABLE_DIRECTOR_AUDIO;ENABLE_DIRECTOR_TEXTURE;ENABLE_MANAGED_JOBS;ENABLE_MANAGED_TRANSFORM_JOBS;ENABLE_MANAGED_ANIMATION_JOBS;ENABLE_MANAGED_AUDIO_JOBS;ENABLE_MANAGED_UNITYTLS;INCLUDE_DYNAMIC_GI;ENABLE_SCRIPTING_GC_WBARRIERS;PLATFORM_SUPPORTS_MONO;RENDER_SOFTWARE_CURSOR;ENABLE_MARSHALLING_TESTS;ENABLE_VIDEO;ENABLE_NAVIGATION_OFFMESHLINK_TO_NAVMESHLINK;ENABLE_ACCELERATOR_CLIENT_DEBUGGING;TEXTCORE_1_0_OR_NEWER;EDITOR_ONLY_NAVMESH_BUILDER_DEPRECATED;PLATFORM_STANDALONE_WIN;PLATFORM_STANDALONE;UNITY_STANDALONE_WIN;UNITY_STANDALONE;ENABLE_RUNTIME_GI;ENABLE_MOVIES;ENABLE_NETWORK;ENABLE_NVIDIA;ENABLE_AMD;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_CLOUD_SERVICES_ENGINE_DIAGNOSTICS;ENABLE_OUT_OF_PROCESS_CRASH_HANDLER;ENABLE_CLUSTER_SYNC;ENABLE_CLUSTERINPUT;PLATFORM_UPDATES_TIME_OUTSIDE_OF_PLAYER_LOOP;GFXDEVICE_WAITFOREVENT_MESSAGEPUMP;PLATFORM_USES_EXPLICIT_MEMORY_MANAGER_INITIALIZER;PLATFORM_SUPPORTS_WAIT_FOR_PRESENTATION;PLATFORM_SUPPORTS_SPLIT_GRAPHICS_JOBS;ENABLE_MONO;NET_STANDARD_2_0;NET_STANDARD;NET_STANDARD_2_1;NETSTANDARD;NETSTANDARD2_1;ENABLE_PROFILER;DEBUG;TRACE;UNITY_ASSERTIONS;UNITY_EDITOR;UNITY_EDITOR_64;UNITY_EDITOR_WIN;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_BURST_AOT;UNITY_TEAM_LICENSE;ENABLE_CUSTOM_RENDER_TEXTURE;ENABLE_DIRECTOR;ENABLE_LOCALIZATION;ENABLE_SPRITES;ENABLE_TERRAIN;ENABLE_TILEMAP;ENABLE_TIMELINE;ENABLE_INPUT_SYSTEM;TEXTCORE_FONT_ENGINE_1_5_OR_NEWER;TEXTCORE_TEXT_ENGINE_1_5_OR_NEWER;CSHARP_7_OR_LATER;CSHARP_7_3_OR_NEWER - False - - - true - true - true - true - MSB3277 - - - Package - 2.0.23 - SDK - Game:1 - StandaloneWindows64:19 - 6000.2.7f2 - - - - - - - - - - - - - - - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.AIModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.ARModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.AccessibilityModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.AndroidJNIModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.AnimationModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.AssetBundleModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.AudioModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.ClothModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.ClusterInputModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.ClusterRendererModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.ContentLoadModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.CrashReportingModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.DSPGraphModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.DirectorModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.GIModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.GameCenterModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.GraphicsStateCollectionSerializerModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.GridModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.HierarchyCoreModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.HotReloadModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.IMGUIModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.IdentifiersModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.ImageConversionModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.InputModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.InputForUIModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.InputLegacyModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.InsightsModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.JSONSerializeModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.LocalizationModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.MarshallingModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.MultiplayerModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.ParticleSystemModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.PerformanceReportingModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.PhysicsModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.Physics2DModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.PropertiesModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.RuntimeInitializeOnLoadManagerInitializerModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.ScreenCaptureModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.ShaderVariantAnalyticsModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.SharedInternalsModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.SpriteMaskModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.SpriteShapeModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.StreamingModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.SubstanceModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.SubsystemsModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.TLSModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.TerrainModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.TerrainPhysicsModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.TextCoreFontEngineModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.TextCoreTextEngineModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.TextRenderingModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.TilemapModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UIModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UIElementsModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UmbraModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityAnalyticsModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityAnalyticsCommonModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityConnectModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityConsentModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityCurlModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityTestProtocolModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestAssetBundleModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestAudioModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestTextureModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestWWWModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.VFXModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.VRModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.VehiclesModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.VideoModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.VirtualTexturingModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.WindModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEngine.XRModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.AccessibilityModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.AdaptivePerformanceModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.BuildProfileModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.ClothModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.CoreBusinessMetricsModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.CoreModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.DeviceSimulatorModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.DiagnosticsModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.EditorToolbarModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.EmbreeModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.GIModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.GraphViewModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.GraphicsStateCollectionSerializerModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.GridAndSnapModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.GridModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.InAppPurchasingModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.LevelPlayModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.MultiplayerModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.Physics2DModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.PhysicsModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.PresetsUIModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.PropertiesModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.QuickSearchModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.SafeModeModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.SceneTemplateModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.SceneViewModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.ShaderFoundryModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.SketchUpModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.SpriteMaskModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.SpriteShapeModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.SubstanceModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.TerrainModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.TextCoreFontEngineModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.TextCoreTextEngineModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.TextRenderingModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.TilemapModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.TreeModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.UIAutomationModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.UIBuilderModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.UIElementsModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.UIElementsSamplesModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.UmbraModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.UnityConnectModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.VFXModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.VideoModule.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\Managed\UnityEngine\UnityEditor.XRModule.dll - False - - - Library\PackageCache\com.unity.collections@d49facba0036\Unity.Collections.LowLevel.ILSupport\Unity.Collections.LowLevel.ILSupport.dll - False - - - Library\PackageCache\com.unity.ext.nunit@031a54704bff\net40\unity-custom\nunit.framework.dll - False - - - Library\PackageCache\com.unity.collections@d49facba0036\Unity.Collections.Tests\System.IO.Hashing\System.IO.Hashing.dll - False - - - Library\PackageCache\com.unity.nuget.mono-cecil@d78732e851eb\Mono.Cecil.dll - False - - - Library\PackageCache\com.unity.collections@d49facba0036\Unity.Collections.Tests\System.Runtime.CompilerServices.Unsafe\System.Runtime.CompilerServices.Unsafe.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\PlaybackEngines\AndroidPlayer\Unity.Android.Types.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\PlaybackEngines\AndroidPlayer\Unity.Android.Gradle.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\ref\2.1.0\netstandard.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\Microsoft.Win32.Primitives.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.AppContext.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Buffers.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Collections.Concurrent.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Collections.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Collections.NonGeneric.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Collections.Specialized.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.ComponentModel.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.ComponentModel.EventBasedAsync.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.ComponentModel.Primitives.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.ComponentModel.TypeConverter.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Console.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Data.Common.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Diagnostics.Contracts.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Diagnostics.Debug.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Diagnostics.FileVersionInfo.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Diagnostics.Process.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Diagnostics.StackTrace.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Diagnostics.TextWriterTraceListener.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Diagnostics.Tools.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Diagnostics.TraceSource.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Diagnostics.Tracing.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Drawing.Primitives.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Dynamic.Runtime.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Globalization.Calendars.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Globalization.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Globalization.Extensions.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.IO.Compression.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.IO.Compression.ZipFile.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.IO.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.IO.FileSystem.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.IO.FileSystem.DriveInfo.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.IO.FileSystem.Primitives.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.IO.FileSystem.Watcher.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.IO.IsolatedStorage.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.IO.MemoryMappedFiles.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.IO.Pipes.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.IO.UnmanagedMemoryStream.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Linq.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Linq.Expressions.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Linq.Parallel.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Linq.Queryable.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Memory.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Net.Http.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Net.NameResolution.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Net.NetworkInformation.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Net.Ping.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Net.Primitives.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Net.Requests.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Net.Security.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Net.Sockets.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Net.WebHeaderCollection.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Net.WebSockets.Client.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Net.WebSockets.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Numerics.Vectors.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.ObjectModel.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Reflection.DispatchProxy.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Reflection.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Reflection.Emit.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Reflection.Emit.ILGeneration.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Reflection.Emit.Lightweight.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Reflection.Extensions.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Reflection.Primitives.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Resources.Reader.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Resources.ResourceManager.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Resources.Writer.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Runtime.CompilerServices.VisualC.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Runtime.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Runtime.Extensions.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Runtime.Handles.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Runtime.InteropServices.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Runtime.InteropServices.RuntimeInformation.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Runtime.Numerics.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Runtime.Serialization.Formatters.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Runtime.Serialization.Json.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Runtime.Serialization.Primitives.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Runtime.Serialization.Xml.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Security.Claims.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Security.Cryptography.Algorithms.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Security.Cryptography.Csp.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Security.Cryptography.Encoding.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Security.Cryptography.Primitives.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Security.Cryptography.X509Certificates.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Security.Principal.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Security.SecureString.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Text.Encoding.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Text.Encoding.Extensions.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Text.RegularExpressions.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Threading.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Threading.Overlapped.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Threading.Tasks.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Threading.Tasks.Extensions.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Threading.Tasks.Parallel.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Threading.Thread.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Threading.ThreadPool.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Threading.Timer.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.ValueTuple.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Xml.ReaderWriter.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Xml.XDocument.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Xml.XmlDocument.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Xml.XmlSerializer.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Xml.XPath.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Xml.XPath.XDocument.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\Extensions\2.0.0\System.Runtime.InteropServices.WindowsRuntime.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\mscorlib.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.ComponentModel.Composition.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.Core.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.Data.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.Drawing.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.IO.Compression.FileSystem.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.Net.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.Numerics.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.Runtime.Serialization.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.ServiceModel.Web.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.Transactions.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.Web.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.Windows.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.Xml.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.Xml.Linq.dll - False - - - X:\Program Files\Unity\Hub\Editor\6000.2.7f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.Xml.Serialization.dll - False - - - Library\ScriptAssemblies\Unity.RenderPipelines.Core.Runtime.dll - False - - - Library\ScriptAssemblies\Unity.RenderPipelines.Core.Editor.dll - False - - - Library\ScriptAssemblies\Unity.TextMeshPro.Editor.dll - False - - - Library\ScriptAssemblies\Unity.TextMeshPro.dll - False - - - Library\ScriptAssemblies\Unity.VisualStudio.Editor.dll - False - - - Library\ScriptAssemblies\Unity.AI.Navigation.dll - False - - - Library\ScriptAssemblies\Unity.RenderPipelines.Core.ShaderLibrary.dll - False - - - Library\ScriptAssemblies\Unity.Collections.dll - False - - - Library\ScriptAssemblies\Unity.InputSystem.ForUI.dll - False - - - Library\ScriptAssemblies\Unity.RenderPipelines.GPUDriven.Runtime.dll - False - - - Library\ScriptAssemblies\Unity.Timeline.Editor.dll - False - - - Library\ScriptAssemblies\Unity.Mathematics.dll - False - - - Library\ScriptAssemblies\Unity.RenderPipelines.Universal.Shaders.dll - False - - - Library\ScriptAssemblies\UnityEngine.UI.dll - False - - - Library\ScriptAssemblies\Unity.Multiplayer.Center.Common.dll - False - - - Library\ScriptAssemblies\Unity.RenderPipelines.Universal.Editor.dll - False - - - Library\ScriptAssemblies\Unity.Burst.dll - False - - - Library\ScriptAssemblies\Unity.Timeline.dll - False - - - Library\ScriptAssemblies\Unity.AI.Navigation.Updater.dll - False - - - Library\ScriptAssemblies\Unity.AI.Navigation.Editor.dll - False - - - Library\ScriptAssemblies\PPv2URPConverters.dll - False - - - Library\ScriptAssemblies\Unity.RenderPipelines.Core.Runtime.Shared.dll - False - - - Library\ScriptAssemblies\Unity.Multiplayer.Center.Editor.dll - False - - - Library\ScriptAssemblies\Unity.RenderPipelines.Universal.2D.Runtime.dll - False - - - Library\ScriptAssemblies\Unity.Searcher.Editor.dll - False - - - Library\ScriptAssemblies\Unity.PlasticSCM.Editor.dll - False - - - Library\ScriptAssemblies\Unity.RenderPipelines.Universal.Runtime.dll - False - - - Library\ScriptAssemblies\Unity.Burst.Editor.dll - False - - - Library\ScriptAssemblies\Unity.Rendering.LightTransport.Runtime.dll - False - - - Library\ScriptAssemblies\Unity.Mathematics.Editor.dll - False - - - Library\ScriptAssemblies\Unity.RenderPipelines.Universal.Config.Runtime.dll - False - - - Library\ScriptAssemblies\Unity.RenderPipeline.Universal.ShaderLibrary.dll - False - - - Library\ScriptAssemblies\Unity.Collections.Editor.dll - False - - - Library\ScriptAssemblies\Unity.ShaderGraph.Editor.dll - False - - - Library\ScriptAssemblies\Unity.Rendering.LightTransport.Editor.dll - False - - - Library\ScriptAssemblies\Unity.RenderPipelines.Core.Editor.Shared.dll - False - - - Library\ScriptAssemblies\Unity.InputSystem.dll - False - - - Library\ScriptAssemblies\Unity.Rider.Editor.dll - False - - - Library\ScriptAssemblies\Unity.AI.Navigation.Editor.ConversionSystem.dll - False - - - Library\ScriptAssemblies\UnityEditor.UI.dll - False - - - Library\ScriptAssemblies\Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary.dll - False - - - - - - - - - - - - - - - - + + + + Temp/obj/$(MSBuildProjectName) + $(BaseIntermediateOutputPath) + false + true + Temp/bin/Debug/ + + + + + + + false + false + 9.0 + + Library + Assembly-CSharp + netstandard2.1 + . + + + 0169;USG0001 + UNITY_6000_2_13;UNITY_6000_2;UNITY_6000;UNITY_5_3_OR_NEWER;UNITY_5_4_OR_NEWER;UNITY_5_5_OR_NEWER;UNITY_5_6_OR_NEWER;UNITY_2017_1_OR_NEWER;UNITY_2017_2_OR_NEWER;UNITY_2017_3_OR_NEWER;UNITY_2017_4_OR_NEWER;UNITY_2018_1_OR_NEWER;UNITY_2018_2_OR_NEWER;UNITY_2018_3_OR_NEWER;UNITY_2018_4_OR_NEWER;UNITY_2019_1_OR_NEWER;UNITY_2019_2_OR_NEWER;UNITY_2019_3_OR_NEWER;UNITY_2019_4_OR_NEWER;UNITY_2020_1_OR_NEWER;UNITY_2020_2_OR_NEWER;UNITY_2020_3_OR_NEWER;UNITY_2021_1_OR_NEWER;UNITY_2021_2_OR_NEWER;UNITY_2021_3_OR_NEWER;UNITY_2022_1_OR_NEWER;UNITY_2022_2_OR_NEWER;UNITY_2022_3_OR_NEWER;UNITY_2023_1_OR_NEWER;UNITY_2023_2_OR_NEWER;UNITY_2023_3_OR_NEWER;UNITY_6000_0_OR_NEWER;UNITY_6000_1_OR_NEWER;UNITY_6000_2_OR_NEWER;PLATFORM_ARCH_64;UNITY_64;UNITY_INCLUDE_TESTS;ENABLE_AUDIO;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_MICROPHONE;ENABLE_MULTIPLE_DISPLAYS;ENABLE_PHYSICS;ENABLE_TEXTURE_STREAMING;ENABLE_VIRTUALTEXTURING;ENABLE_LZMA;ENABLE_UNITYEVENTS;ENABLE_VR;ENABLE_WEBCAM;ENABLE_UNITYWEBREQUEST;ENABLE_WWW;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_SERVICES_USE_WEBREQUEST;ENABLE_UNITY_CONSENT;ENABLE_UNITY_CLOUD_IDENTIFIERS;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_EDITOR_GAME_SERVICES;ENABLE_UNITY_GAME_SERVICES_ANALYTICS_SUPPORT;ENABLE_CLOUD_LICENSE;ENABLE_EDITOR_HUB_LICENSE;ENABLE_WEBSOCKET_CLIENT;ENABLE_GENERATE_NATIVE_PLUGINS_FOR_ASSEMBLIES_API;ENABLE_DIRECTOR_AUDIO;ENABLE_DIRECTOR_TEXTURE;ENABLE_MANAGED_JOBS;ENABLE_MANAGED_TRANSFORM_JOBS;ENABLE_MANAGED_ANIMATION_JOBS;ENABLE_MANAGED_AUDIO_JOBS;ENABLE_MANAGED_UNITYTLS;INCLUDE_DYNAMIC_GI;ENABLE_SCRIPTING_GC_WBARRIERS;PLATFORM_SUPPORTS_MONO;RENDER_SOFTWARE_CURSOR;ENABLE_MARSHALLING_TESTS;ENABLE_VIDEO;ENABLE_NAVIGATION_OFFMESHLINK_TO_NAVMESHLINK;ENABLE_ACCELERATOR_CLIENT_DEBUGGING;TEXTCORE_1_0_OR_NEWER;EDITOR_ONLY_NAVMESH_BUILDER_DEPRECATED;PLATFORM_STANDALONE_LINUX;PLATFORM_STANDALONE;UNITY_STANDALONE_LINUX;UNITY_STANDALONE;UNITY_STANDALONE_LINUX_API;ENABLE_RUNTIME_GI;ENABLE_MOVIES;ENABLE_NETWORK;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_CLUSTER_SYNC;ENABLE_CLUSTERINPUT;ENABLE_SPATIALTRACKING;ENABLE_MODULAR_UNITYENGINE_ASSEMBLIES;PLATFORM_SUPPORTS_SPLIT_GRAPHICS_JOBS;PLATFORM_USES_EXPLICIT_MEMORY_MANAGER_INITIALIZER;ENABLE_MONO;NET_STANDARD_2_0;NET_STANDARD;NET_STANDARD_2_1;NETSTANDARD;NETSTANDARD2_1;ENABLE_PROFILER;DEBUG;TRACE;UNITY_ASSERTIONS;UNITY_EDITOR;UNITY_EDITOR_64;UNITY_EDITOR_LINUX;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_BURST_AOT;UNITY_TEAM_LICENSE;ENABLE_CUSTOM_RENDER_TEXTURE;ENABLE_DIRECTOR;ENABLE_LOCALIZATION;ENABLE_SPRITES;ENABLE_TERRAIN;ENABLE_TILEMAP;ENABLE_TIMELINE;ENABLE_INPUT_SYSTEM;TEXTCORE_FONT_ENGINE_1_5_OR_NEWER;TEXTCORE_TEXT_ENGINE_1_5_OR_NEWER;CSHARP_7_OR_LATER;CSHARP_7_3_OR_NEWER + False + + + true + true + true + true + MSB3277 + + + Package + 2.0.25 + SDK + Game:1 + StandaloneLinux64:24 + 6000.2.13f1 + + + + + + + + + + + + + + + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.AIModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.AccessibilityModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.AndroidJNIModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.AnimationModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.AssetBundleModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.AudioModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.ClothModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.ClusterInputModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.ClusterRendererModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.ContentLoadModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.CoreModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.CrashReportingModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.DSPGraphModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.DirectorModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.GIModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.GameCenterModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.GraphicsStateCollectionSerializerModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.GridModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.HierarchyCoreModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.HotReloadModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.IMGUIModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.IdentifiersModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.ImageConversionModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.InputModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.InputForUIModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.InputLegacyModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.JSONSerializeModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.LocalizationModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.MarshallingModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.MultiplayerModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.ParticleSystemModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.PerformanceReportingModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.PhysicsModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.Physics2DModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.PropertiesModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.RuntimeInitializeOnLoadManagerInitializerModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.ScreenCaptureModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.ShaderVariantAnalyticsModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.SharedInternalsModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.SpriteMaskModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.SpriteShapeModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.StreamingModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.SubstanceModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.SubsystemsModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.TLSModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.TerrainModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.TerrainPhysicsModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.TextCoreFontEngineModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.TextCoreTextEngineModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.TextRenderingModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.TilemapModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UIModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UIElementsModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UmbraModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityAnalyticsModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityAnalyticsCommonModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityConnectModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityConsentModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityCurlModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityTestProtocolModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityWebRequestModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityWebRequestAssetBundleModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityWebRequestAudioModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityWebRequestTextureModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityWebRequestWWWModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.VFXModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.VRModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.VehiclesModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.VideoModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.VirtualTexturingModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.WindModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.XRModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.AccessibilityModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.AdaptivePerformanceModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.BuildProfileModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.ClothModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.CoreBusinessMetricsModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.CoreModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.DeviceSimulatorModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.DiagnosticsModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.EditorToolbarModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.EmbreeModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.GIModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.GraphViewModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.GraphicsStateCollectionSerializerModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.GridAndSnapModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.GridModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.InAppPurchasingModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.LevelPlayModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.MultiplayerModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.Physics2DModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.PhysicsModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.PresetsUIModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.PropertiesModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.QuickSearchModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.SafeModeModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.SceneTemplateModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.SceneViewModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.ShaderFoundryModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.SketchUpModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.SpriteMaskModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.SpriteShapeModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.SubstanceModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.TerrainModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.TextCoreFontEngineModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.TextCoreTextEngineModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.TextRenderingModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.TilemapModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.TreeModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.UIAutomationModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.UIBuilderModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.UIElementsModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.UIElementsSamplesModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.UmbraModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.UnityConnectModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.VFXModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.VideoModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.XRModule.dll + False + + + Library/PackageCache/com.unity.collections@aea9d3bd5e19/Unity.Collections.LowLevel.ILSupport/Unity.Collections.LowLevel.ILSupport.dll + False + + + Library/PackageCache/com.unity.ext.nunit@b16e6d09cd93/net40/unity-custom/nunit.framework.dll + False + + + Library/PackageCache/com.unity.collections@aea9d3bd5e19/Unity.Collections.Tests/System.IO.Hashing/System.IO.Hashing.dll + False + + + Library/PackageCache/com.unity.nuget.mono-cecil@d78732e851eb/Mono.Cecil.dll + False + + + Library/PackageCache/com.unity.collections@aea9d3bd5e19/Unity.Collections.Tests/System.Runtime.CompilerServices.Unsafe/System.Runtime.CompilerServices.Unsafe.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/ref/2.1.0/netstandard.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/Microsoft.Win32.Primitives.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.AppContext.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Buffers.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Collections.Concurrent.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Collections.NonGeneric.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Collections.Specialized.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Collections.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.ComponentModel.EventBasedAsync.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.ComponentModel.Primitives.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.ComponentModel.TypeConverter.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.ComponentModel.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Console.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Data.Common.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.Contracts.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.Debug.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.FileVersionInfo.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.Process.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.StackTrace.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.TextWriterTraceListener.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.Tools.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.TraceSource.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.Tracing.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Drawing.Primitives.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Dynamic.Runtime.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Globalization.Calendars.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Globalization.Extensions.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Globalization.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.IO.Compression.ZipFile.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.IO.Compression.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.IO.FileSystem.DriveInfo.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.IO.FileSystem.Primitives.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.IO.FileSystem.Watcher.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.IO.FileSystem.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.IO.IsolatedStorage.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.IO.MemoryMappedFiles.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.IO.Pipes.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.IO.UnmanagedMemoryStream.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.IO.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Linq.Expressions.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Linq.Parallel.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Linq.Queryable.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Linq.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Memory.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Net.Http.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Net.NameResolution.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Net.NetworkInformation.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Net.Ping.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Net.Primitives.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Net.Requests.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Net.Security.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Net.Sockets.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Net.WebHeaderCollection.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Net.WebSockets.Client.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Net.WebSockets.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Numerics.Vectors.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.ObjectModel.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.DispatchProxy.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.Emit.ILGeneration.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.Emit.Lightweight.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.Emit.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.Extensions.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.Primitives.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Resources.Reader.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Resources.ResourceManager.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Resources.Writer.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.CompilerServices.VisualC.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Extensions.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Handles.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.InteropServices.RuntimeInformation.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.InteropServices.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Numerics.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Serialization.Formatters.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Serialization.Json.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Serialization.Primitives.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Serialization.Xml.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Claims.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Cryptography.Algorithms.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Cryptography.Csp.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Cryptography.Encoding.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Cryptography.Primitives.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Cryptography.X509Certificates.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Principal.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Security.SecureString.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Text.Encoding.Extensions.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Text.Encoding.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Text.RegularExpressions.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.Overlapped.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.Tasks.Extensions.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.Tasks.Parallel.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.Tasks.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.Thread.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.ThreadPool.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.Timer.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.ValueTuple.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Xml.ReaderWriter.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Xml.XDocument.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Xml.XPath.XDocument.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Xml.XPath.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Xml.XmlDocument.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Xml.XmlSerializer.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/Extensions/2.0.0/System.Runtime.InteropServices.WindowsRuntime.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netfx/System.ComponentModel.Composition.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netfx/System.Core.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netfx/System.Data.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netfx/System.Drawing.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netfx/System.IO.Compression.FileSystem.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netfx/System.Net.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netfx/System.Numerics.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netfx/System.Runtime.Serialization.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netfx/System.ServiceModel.Web.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netfx/System.Transactions.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netfx/System.Web.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netfx/System.Windows.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netfx/System.Xml.Linq.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netfx/System.Xml.Serialization.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netfx/System.Xml.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netfx/System.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netfx/mscorlib.dll + False + + + Library/ScriptAssemblies/Unity.RenderPipelines.Core.Runtime.dll + False + + + Library/ScriptAssemblies/Unity.RenderPipelines.Core.Editor.dll + False + + + Library/ScriptAssemblies/Unity.TextMeshPro.Editor.dll + False + + + Library/ScriptAssemblies/Unity.TextMeshPro.dll + False + + + Library/ScriptAssemblies/Unity.VisualStudio.Editor.dll + False + + + Library/ScriptAssemblies/Unity.AI.Navigation.dll + False + + + Library/ScriptAssemblies/Unity.RenderPipelines.Core.ShaderLibrary.dll + False + + + Library/ScriptAssemblies/Unity.Collections.dll + False + + + Library/ScriptAssemblies/Unity.InputSystem.ForUI.dll + False + + + Library/ScriptAssemblies/Unity.RenderPipelines.GPUDriven.Runtime.dll + False + + + Library/ScriptAssemblies/Unity.Timeline.Editor.dll + False + + + Library/ScriptAssemblies/Unity.Mathematics.dll + False + + + Library/ScriptAssemblies/Unity.RenderPipelines.Universal.Shaders.dll + False + + + Library/ScriptAssemblies/UnityEngine.UI.dll + False + + + Library/ScriptAssemblies/Unity.Multiplayer.Center.Common.dll + False + + + Library/ScriptAssemblies/Unity.RenderPipelines.Universal.Editor.dll + False + + + Library/ScriptAssemblies/Unity.Burst.dll + False + + + Library/ScriptAssemblies/Unity.Timeline.dll + False + + + Library/ScriptAssemblies/Unity.AI.Navigation.Updater.dll + False + + + Library/ScriptAssemblies/Unity.AI.Navigation.Editor.dll + False + + + Library/ScriptAssemblies/PPv2URPConverters.dll + False + + + Library/ScriptAssemblies/Unity.RenderPipelines.Core.Runtime.Shared.dll + False + + + Library/ScriptAssemblies/Unity.Multiplayer.Center.Editor.dll + False + + + Library/ScriptAssemblies/Unity.RenderPipelines.Universal.2D.Runtime.dll + False + + + Library/ScriptAssemblies/Unity.Searcher.Editor.dll + False + + + Library/ScriptAssemblies/Unity.PlasticSCM.Editor.dll + False + + + Library/ScriptAssemblies/Unity.RenderPipelines.Universal.Runtime.dll + False + + + Library/ScriptAssemblies/Unity.Burst.Editor.dll + False + + + Library/ScriptAssemblies/Unity.Rendering.LightTransport.Runtime.dll + False + + + Library/ScriptAssemblies/Unity.Mathematics.Editor.dll + False + + + Library/ScriptAssemblies/Unity.RenderPipelines.Universal.Config.Runtime.dll + False + + + Library/ScriptAssemblies/Unity.RenderPipeline.Universal.ShaderLibrary.dll + False + + + Library/ScriptAssemblies/Unity.Collections.Editor.dll + False + + + Library/ScriptAssemblies/Unity.ShaderGraph.Editor.dll + False + + + Library/ScriptAssemblies/Unity.Rendering.LightTransport.Editor.dll + False + + + Library/ScriptAssemblies/Unity.RenderPipelines.Core.Editor.Shared.dll + False + + + Library/ScriptAssemblies/Unity.InputSystem.dll + False + + + Library/ScriptAssemblies/Unity.Rider.Editor.dll + False + + + Library/ScriptAssemblies/Unity.AI.Navigation.Editor.ConversionSystem.dll + False + + + Library/ScriptAssemblies/UnityEditor.UI.dll + False + + + Library/ScriptAssemblies/Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary.dll + False + + + + + + + + + + + + + + + + diff --git a/Assets/Scenes/Boids/Boids.unity b/Assets/Scenes/Boids/Boids.unity index eec3e44..e9b5a3b 100644 --- a/Assets/Scenes/Boids/Boids.unity +++ b/Assets/Scenes/Boids/Boids.unity @@ -119,6 +119,228 @@ NavMeshSettings: debug: m_Flags: 0 m_NavMeshData: {fileID: 0} +--- !u!1 &231291185 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 231291186} + - component: {fileID: 231291189} + - component: {fileID: 231291188} + - component: {fileID: 231291187} + m_Layer: 0 + m_Name: Wall (1) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &231291186 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 231291185} + serializedVersion: 2 + m_LocalRotation: {x: 0.5, y: 0.5, z: -0.5, w: 0.5} + m_LocalPosition: {x: -5, y: 5, z: 0} + m_LocalScale: {x: 10, y: 1, z: 10} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1826482027} + m_LocalEulerAnglesHint: {x: 90, y: 90, z: 0} +--- !u!65 &231291187 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 231291185} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &231291188 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 231291185} + m_Enabled: 0 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RayTracingAccelStructBuildFlagsOverride: 0 + m_RayTracingAccelStructBuildFlags: 1 + m_SmallMeshCulling: 1 + m_ForceMeshLod: -1 + m_MeshLodSelectionBias: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_GlobalIlluminationMeshLod: 0 + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &231291189 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 231291185} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &246180153 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 246180154} + - component: {fileID: 246180157} + - component: {fileID: 246180156} + - component: {fileID: 246180155} + m_Layer: 0 + m_Name: Wall (2) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &246180154 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 246180153} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0.7071068, z: -0.7071068, w: 0} + m_LocalPosition: {x: 0, y: 5, z: 5} + m_LocalScale: {x: 10, y: 1, z: 10} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1826482027} + m_LocalEulerAnglesHint: {x: 90, y: 180, z: 0} +--- !u!65 &246180155 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 246180153} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &246180156 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 246180153} + m_Enabled: 0 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RayTracingAccelStructBuildFlagsOverride: 0 + m_RayTracingAccelStructBuildFlags: 1 + m_SmallMeshCulling: 1 + m_ForceMeshLod: -1 + m_MeshLodSelectionBias: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_GlobalIlluminationMeshLod: 0 + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &246180157 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 246180153} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} --- !u!1 &301943977 GameObject: m_ObjectHideFlags: 0 @@ -156,6 +378,9 @@ MonoBehaviour: separationForce: 5 separationDistance: 0.5 bodyForce: 20 + boundaryForce: 5 + spaceSize: {x: 10, y: 10, z: 10} + boundaryWidth: {x: 1, y: 1, z: 1} --- !u!114 &301943979 MonoBehaviour: m_ObjectHideFlags: 0 @@ -188,6 +413,117 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &704151342 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 704151343} + - component: {fileID: 704151346} + - component: {fileID: 704151345} + - component: {fileID: 704151344} + m_Layer: 0 + m_Name: Ceiling + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &704151343 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 704151342} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 10, z: 0} + m_LocalScale: {x: 10, y: 1, z: 10} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1826482027} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!65 &704151344 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 704151342} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &704151345 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 704151342} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RayTracingAccelStructBuildFlagsOverride: 0 + m_RayTracingAccelStructBuildFlags: 1 + m_SmallMeshCulling: 1 + m_ForceMeshLod: -1 + m_MeshLodSelectionBias: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_GlobalIlluminationMeshLod: 0 + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &704151346 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 704151342} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} --- !u!1 &837238090 GameObject: m_ObjectHideFlags: 0 @@ -407,6 +743,376 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1690670936 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1690670937} + - component: {fileID: 1690670940} + - component: {fileID: 1690670939} + - component: {fileID: 1690670938} + m_Layer: 0 + m_Name: Floor + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1690670937 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1690670936} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 10, y: 1, z: 10} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1826482027} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!65 &1690670938 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1690670936} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &1690670939 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1690670936} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RayTracingAccelStructBuildFlagsOverride: 0 + m_RayTracingAccelStructBuildFlags: 1 + m_SmallMeshCulling: 1 + m_ForceMeshLod: -1 + m_MeshLodSelectionBias: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_GlobalIlluminationMeshLod: 0 + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &1690670940 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1690670936} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1738679977 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1738679978} + - component: {fileID: 1738679981} + - component: {fileID: 1738679980} + - component: {fileID: 1738679979} + m_Layer: 0 + m_Name: Wall + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1738679978 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1738679977} + serializedVersion: 2 + m_LocalRotation: {x: 0.7071068, y: 0, z: 0, w: 0.7071068} + m_LocalPosition: {x: 0, y: 5, z: -5} + m_LocalScale: {x: 10, y: 1, z: 10} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1826482027} + m_LocalEulerAnglesHint: {x: 90, y: 0, z: 0} +--- !u!65 &1738679979 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1738679977} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &1738679980 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1738679977} + m_Enabled: 0 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RayTracingAccelStructBuildFlagsOverride: 0 + m_RayTracingAccelStructBuildFlags: 1 + m_SmallMeshCulling: 1 + m_ForceMeshLod: -1 + m_MeshLodSelectionBias: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_GlobalIlluminationMeshLod: 0 + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &1738679981 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1738679977} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1826482026 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1826482027} + m_Layer: 0 + m_Name: Boundary + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1826482027 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1826482026} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -0, y: -5, z: -0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1690670937} + - {fileID: 1738679978} + - {fileID: 231291186} + - {fileID: 246180154} + - {fileID: 1924016461} + - {fileID: 704151343} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1924016460 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1924016461} + - component: {fileID: 1924016464} + - component: {fileID: 1924016463} + - component: {fileID: 1924016462} + m_Layer: 0 + m_Name: Wall (3) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1924016461 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1924016460} + serializedVersion: 2 + m_LocalRotation: {x: -0.5, y: 0.5, z: -0.5, w: -0.5} + m_LocalPosition: {x: 5, y: 5, z: 0} + m_LocalScale: {x: 10, y: 1, z: 10} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1826482027} + m_LocalEulerAnglesHint: {x: 90, y: 270, z: 0} +--- !u!65 &1924016462 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1924016460} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &1924016463 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1924016460} + m_Enabled: 0 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RayTracingAccelStructBuildFlagsOverride: 0 + m_RayTracingAccelStructBuildFlags: 1 + m_SmallMeshCulling: 1 + m_ForceMeshLod: -1 + m_MeshLodSelectionBias: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_GlobalIlluminationMeshLod: 0 + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &1924016464 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1924016460} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} --- !u!1660057539 &9223372036854775807 SceneRoots: m_ObjectHideFlags: 0 @@ -414,3 +1120,4 @@ SceneRoots: - {fileID: 1633626502} - {fileID: 837238092} - {fileID: 301943980} + - {fileID: 1826482027} diff --git a/Assets/Scenes/Boids/Scripts/Boid.cs b/Assets/Scenes/Boids/Scripts/Boid.cs index 38941d6..a6d660c 100644 --- a/Assets/Scenes/Boids/Scripts/Boid.cs +++ b/Assets/Scenes/Boids/Scripts/Boid.cs @@ -1,7 +1,8 @@ using UnityEngine; -public class Boid : MonoBehaviour { +public class Boid : MonoBehaviour +{ public float speed = 0.2f; public int neighbourCount = 0; public float inertia = 0.2f; @@ -15,6 +16,8 @@ public class Boid : MonoBehaviour { public Vector3 velocity = Vector3.zero; public Vector3 acceleration = Vector3.zero; + private Bounds bounds; + readonly Collider[] results = new Collider[10]; public NeuroidNetwork neuroidNet = new(); @@ -23,20 +26,25 @@ public class Boid : MonoBehaviour { public Neuroid alignment; public Neuroid separation; public Neuroid target; + public Neuroid boundary; public Neuroid totalForce; public int id; - void Awake() { + void Awake() + { this.id = this.GetInstanceID(); sc = FindFirstObjectByType(); + bounds = new(sc.transform.position, sc.spaceSize - 2 * sc.boundaryWidth); + cohesion = new(neuroidNet) { name = "Cohesion", mode = Neuroid.Mode.Sum }; alignment = new(neuroidNet) { name = "Alignment", mode = Neuroid.Mode.Average }; separation = new(neuroidNet) { name = "Separation", mode = Neuroid.Mode.Sum }; target = new(neuroidNet) { name = "Target", mode = Neuroid.Mode.Sum }; + boundary = new(neuroidNet) { name = "Boundary", mode = Neuroid.Mode.Sum }; totalForce = new(neuroidNet) { name = "Total force", mode = Neuroid.Mode.Sum }; @@ -44,9 +52,11 @@ public class Boid : MonoBehaviour { totalForce.GetInputFrom(cohesion, sc.cohesionForce); totalForce.GetInputFrom(separation, sc.separationForce); totalForce.GetInputFrom(target, sc.bodyForce); + totalForce.GetInputFrom(boundary, sc.boundaryForce); } - void Update() { + void Update() + { Physics.OverlapSphereNonAlloc(this.transform.position, 10, results); neighbourCount = 0; @@ -54,27 +64,55 @@ public class Boid : MonoBehaviour { alignment.ResetWeights(); separation.ResetWeights(); - foreach (Collider c in results) { - if (c == null || c as CapsuleCollider == null) + foreach (Collider c in results) + { + if (c == null) continue; - Boid neighbour = c.GetComponentInParent(); - if (neighbour == null || neighbour == this) - continue; + if (c as CapsuleCollider != null) + { + Boid neighbour = c.GetComponentInParent(); + if (neighbour == null || neighbour == this) + continue; - Vector3 localPosition = neighbour.transform.position - this.transform.position; - Vector3 relativeVelocity = neighbour.velocity - this.velocity; + Vector3 localPosition = neighbour.transform.position - this.transform.position; + Vector3 relativeVelocity = neighbour.velocity - this.velocity; - int id = neighbour.GetInstanceID(); + int id = neighbour.GetInstanceID(); - Vector3 separationForce = -localPosition / localPosition.sqrMagnitude; - // which is equivalent to -(localPosition.normalized / localPosition.magnitude) + Vector3 separationForce = -localPosition / localPosition.sqrMagnitude; + // which is equivalent to -(localPosition.normalized / localPosition.magnitude) - separation.SetInput(id, separationForce, sc.separationDistance); - cohesion.SetInput(id, localPosition); - alignment.SetInput(id, relativeVelocity); + separation.SetInput(id, separationForce, sc.separationDistance); + cohesion.SetInput(id, localPosition, sc.cohesionForce); + alignment.SetInput(id, relativeVelocity, sc.alignmentForce); - neighbourCount++; + neighbourCount++; + } + } + + //Vector3 spaceLocalPosition = sc.transform.InverseTransformPoint(this.transform.position); + if (!bounds.Contains(this.transform.position)) + { + Vector3 point = this.transform.position; + // Vector3 distanceOutside = Vector3.Max(bounds.min - this.transform.position, this.transform.position - bounds.max); + // // Ensure value is > 0 (but isn't this already) + // Vector3 outside = distanceOutside; // Vector3.Max(Vector3.zero, distanceOutside); + + Vector3 below = bounds.min - point; // positive where point < min + Vector3 above = point - bounds.max; // positive where point > max + + // outside distances per axis (0 if inside on that axis) + Vector3 outside = Vector3.Max(Vector3.zero, Vector3.Max(below, above)); + Vector3 dir = Vector3.zero; + dir.x = (below.x > 0f) ? 1f : ((above.x > 0f) ? -1f : 0f); + dir.y = (below.y > 0f) ? 1f : ((above.y > 0f) ? -1f : 0f); + dir.z = (below.z > 0f) ? 1f : ((above.z > 0f) ? -1f : 0f); + + outside = Vector3.Scale(outside, dir); + + boundary.SetInput(id, outside, sc.boundaryForce); + Debug.Log($"boundary {this.transform.position} {outside} force = {outside * sc.boundaryForce}"); } Vector3 totalForceVector = totalForce.outputValue; @@ -85,7 +123,8 @@ public class Boid : MonoBehaviour { this.transform.position += this.velocity * Time.deltaTime; - if (this.velocity != Vector3.zero) { + if (this.velocity != Vector3.zero) + { Quaternion targetRotation = Quaternion.LookRotation(this.velocity); transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 2f); // Adjust the speed of rotation } diff --git a/Assets/Scenes/Boids/Scripts/SwarmControl.cs b/Assets/Scenes/Boids/Scripts/SwarmControl.cs index b328e9d..b662606 100644 --- a/Assets/Scenes/Boids/Scripts/SwarmControl.cs +++ b/Assets/Scenes/Boids/Scripts/SwarmControl.cs @@ -11,4 +11,8 @@ public class SwarmControl : MonoBehaviour public float separationForce = 5.0f; public float separationDistance = 0.5f; public float bodyForce = 20; + + public float boundaryForce = 2.0f; + public Vector3 spaceSize = new (10, 10, 10); + public Vector3 boundaryWidth = Vector3.one * 1.0f; } diff --git a/Assets/_Recovery.meta b/Assets/_Recovery.meta deleted file mode 100644 index 2ca7812..0000000 --- a/Assets/_Recovery.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 7c53f9058d007df4aa1324e04abe30f0 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_Recovery/0.unity b/Assets/_Recovery/0.unity deleted file mode 100644 index e5fcae4..0000000 --- a/Assets/_Recovery/0.unity +++ /dev/null @@ -1,474 +0,0 @@ -%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: 10 - 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: 0 - m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} - m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 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_UseRadianceAmbientProbe: 0 ---- !u!157 &3 -LightmapSettings: - m_ObjectHideFlags: 0 - serializedVersion: 13 - m_BakeOnSceneLoad: 0 - m_GISettings: - serializedVersion: 2 - m_BounceScale: 1 - m_IndirectOutputScale: 1 - m_AlbedoBoost: 1 - m_EnvironmentLightingMode: 0 - m_EnableBakedLightmaps: 1 - 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_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: 1 - m_PVRFilteringGaussRadiusAO: 1 - m_PVRFilteringAtrousPositionSigmaDirect: 0.5 - m_PVRFilteringAtrousPositionSigmaIndirect: 2 - m_PVRFilteringAtrousPositionSigmaAO: 1 - m_ExportTrainingData: 0 - m_TrainingDataDestination: TrainingData - m_LightProbeSampleCountMultiplier: 4 - m_LightingDataAsset: {fileID: 20201, guid: 0000000000000000f000000000000000, type: 0} - m_LightingSettings: {fileID: 0} ---- !u!196 &4 -NavMeshSettings: - serializedVersion: 2 - m_ObjectHideFlags: 0 - m_BuildSettings: - serializedVersion: 3 - 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 - buildHeightMesh: 0 - maxJobWorkers: 0 - preserveTilesOutsideBounds: 0 - debug: - m_Flags: 0 - m_NavMeshData: {fileID: 0} ---- !u!1 &301943977 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 301943980} - - component: {fileID: 301943979} - - component: {fileID: 301943978} - m_Layer: 0 - m_Name: Swarm - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &301943978 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 301943977} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 0464906885ae3494f8fd0314719fb2db, type: 3} - m_Name: - m_EditorClassIdentifier: Assembly-CSharp::SwarmControl - speed: 0.5 - inertia: 0.1 - alignmentForce: 0 - cohesionForce: 10 - separationForce: 5 - separationDistance: 0.5 - bodyForce: 20 ---- !u!114 &301943979 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 301943977} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: ec888ca5333d45a438f9f417fa5ce135, type: 3} - m_Name: - m_EditorClassIdentifier: Assembly-CSharp::SwarmSpawn - count: 100 - boidPrefab: {fileID: 8702527964058765413, guid: f9c706268554ce449a8773675b2864b8, type: 3} - spawnAreaSize: {x: 0.5, y: 0.5, z: 0.5} - minDelay: 0.1 - maxDelay: 1 ---- !u!4 &301943980 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 301943977} - serializedVersion: 2 - 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_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1001 &703951470 -PrefabInstance: - m_ObjectHideFlags: 0 - serializedVersion: 2 - m_Modification: - serializedVersion: 3 - m_TransformParent: {fileID: 0} - m_Modifications: - - target: {fileID: 8702527964058765412, guid: f9c706268554ce449a8773675b2864b8, type: 3} - propertyPath: m_LocalPosition.x - value: 2.97655 - objectReference: {fileID: 0} - - target: {fileID: 8702527964058765412, guid: f9c706268554ce449a8773675b2864b8, type: 3} - propertyPath: m_LocalPosition.y - value: -0.73524 - objectReference: {fileID: 0} - - target: {fileID: 8702527964058765412, guid: f9c706268554ce449a8773675b2864b8, type: 3} - propertyPath: m_LocalPosition.z - value: -0.8316 - objectReference: {fileID: 0} - - target: {fileID: 8702527964058765412, guid: f9c706268554ce449a8773675b2864b8, type: 3} - propertyPath: m_LocalRotation.w - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 8702527964058765412, guid: f9c706268554ce449a8773675b2864b8, type: 3} - propertyPath: m_LocalRotation.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 8702527964058765412, guid: f9c706268554ce449a8773675b2864b8, type: 3} - propertyPath: m_LocalRotation.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 8702527964058765412, guid: f9c706268554ce449a8773675b2864b8, type: 3} - propertyPath: m_LocalRotation.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 8702527964058765412, guid: f9c706268554ce449a8773675b2864b8, type: 3} - propertyPath: m_LocalEulerAnglesHint.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 8702527964058765412, guid: f9c706268554ce449a8773675b2864b8, type: 3} - propertyPath: m_LocalEulerAnglesHint.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 8702527964058765412, guid: f9c706268554ce449a8773675b2864b8, type: 3} - propertyPath: m_LocalEulerAnglesHint.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 8702527964058765413, guid: f9c706268554ce449a8773675b2864b8, type: 3} - propertyPath: m_Name - value: Boid - objectReference: {fileID: 0} - m_RemovedComponents: [] - m_RemovedGameObjects: [] - m_AddedGameObjects: [] - m_AddedComponents: [] - m_SourcePrefab: {fileID: 100100000, guid: f9c706268554ce449a8773675b2864b8, type: 3} ---- !u!1 &837238090 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 837238092} - - component: {fileID: 837238091} - - component: {fileID: 837238093} - m_Layer: 0 - m_Name: Directional Light - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!108 &837238091 -Light: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 837238090} - m_Enabled: 1 - serializedVersion: 11 - m_Type: 1 - m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} - m_Intensity: 1 - m_Range: 10 - m_SpotAngle: 30 - m_InnerSpotAngle: 21.80208 - m_CookieSize: 10 - m_Shadows: - m_Type: 2 - m_Resolution: -1 - m_CustomResolution: -1 - m_Strength: 1 - m_Bias: 0.05 - m_NormalBias: 0.4 - m_NearPlane: 0.2 - m_CullingMatrixOverride: - e00: 1 - e01: 0 - e02: 0 - e03: 0 - e10: 0 - e11: 1 - e12: 0 - e13: 0 - e20: 0 - e21: 0 - e22: 1 - e23: 0 - e30: 0 - e31: 0 - e32: 0 - e33: 1 - m_UseCullingMatrixOverride: 0 - m_Cookie: {fileID: 0} - m_DrawHalo: 0 - m_Flare: {fileID: 0} - m_RenderMode: 0 - m_CullingMask: - serializedVersion: 2 - m_Bits: 4294967295 - m_RenderingLayerMask: 1 - m_Lightmapping: 4 - m_LightShadowCasterMode: 0 - m_AreaSize: {x: 1, y: 1} - m_BounceIntensity: 1 - m_ColorTemperature: 6570 - m_UseColorTemperature: 0 - m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} - m_UseBoundingSphereOverride: 0 - m_UseViewFrustumForShadowCasterCull: 1 - m_ForceVisible: 0 - m_ShadowRadius: 0 - m_ShadowAngle: 0 - m_LightUnit: 1 - m_LuxAtDistance: 1 - m_EnableSpotReflector: 1 ---- !u!4 &837238092 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 837238090} - serializedVersion: 2 - m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} - m_LocalPosition: {x: 0, y: 3, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} ---- !u!114 &837238093 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 837238090} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 474bcb49853aa07438625e644c072ee6, type: 3} - m_Name: - m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.UniversalAdditionalLightData - m_UsePipelineSettings: 1 - m_AdditionalLightsShadowResolutionTier: 2 - m_CustomShadowLayers: 0 - m_LightCookieSize: {x: 1, y: 1} - m_LightCookieOffset: {x: 0, y: 0} - m_SoftShadowQuality: 0 - m_RenderingLayersMask: - serializedVersion: 0 - m_Bits: 1 - m_ShadowRenderingLayersMask: - serializedVersion: 0 - m_Bits: 1 - m_Version: 4 - m_LightLayerMask: 1 - m_ShadowLayerMask: 1 - m_RenderingLayers: 1 - m_ShadowRenderingLayers: 1 ---- !u!1 &1633626499 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1633626502} - - component: {fileID: 1633626501} - - component: {fileID: 1633626500} - 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 &1633626500 -AudioListener: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1633626499} - m_Enabled: 1 ---- !u!20 &1633626501 -Camera: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1633626499} - 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_Iso: 200 - m_ShutterSpeed: 0.005 - m_Aperture: 16 - m_FocusDistance: 10 - m_FocalLength: 50 - m_BladeCount: 5 - m_Curvature: {x: 2, y: 11} - m_BarrelClipping: 0.25 - m_Anamorphism: 0 - m_SensorSize: {x: 36, y: 24} - m_LensShift: {x: 0, y: 0} - 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: 0 - 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 &1633626502 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1633626499} - serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 1, z: -10} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1660057539 &9223372036854775807 -SceneRoots: - m_ObjectHideFlags: 0 - m_Roots: - - {fileID: 1633626502} - - {fileID: 837238092} - - {fileID: 301943980} - - {fileID: 703951470} diff --git a/Assets/_Recovery/0.unity.meta b/Assets/_Recovery/0.unity.meta deleted file mode 100644 index 84dc77f..0000000 --- a/Assets/_Recovery/0.unity.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: eeeb110648a395642a15f721ad61e252 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/manifest.json b/Packages/manifest.json index 4e5acb3..4e3816e 100644 --- a/Packages/manifest.json +++ b/Packages/manifest.json @@ -3,7 +3,7 @@ "com.unity.ai.navigation": "2.0.9", "com.unity.collab-proxy": "2.10.2", "com.unity.ide.rider": "3.0.38", - "com.unity.ide.visualstudio": "2.0.23", + "com.unity.ide.visualstudio": "2.0.25", "com.unity.inputsystem": "1.14.2", "com.unity.multiplayer.center": "1.0.0", "com.unity.render-pipelines.universal": "17.2.0", diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json index 46f0878..a197b82 100644 --- a/Packages/packages-lock.json +++ b/Packages/packages-lock.json @@ -27,14 +27,14 @@ "url": "https://packages.unity.com" }, "com.unity.collections": { - "version": "2.5.7", + "version": "2.6.2", "depth": 2, "source": "registry", "dependencies": { - "com.unity.burst": "1.8.19", + "com.unity.burst": "1.8.23", "com.unity.mathematics": "1.3.2", - "com.unity.test-framework": "1.4.6", "com.unity.nuget.mono-cecil": "1.11.5", + "com.unity.test-framework": "1.4.6", "com.unity.test-framework.performance": "3.0.3" }, "url": "https://packages.unity.com" @@ -55,11 +55,11 @@ "url": "https://packages.unity.com" }, "com.unity.ide.visualstudio": { - "version": "2.0.23", + "version": "2.0.25", "depth": 0, "source": "registry", "dependencies": { - "com.unity.test-framework": "1.1.9" + "com.unity.test-framework": "1.1.31" }, "url": "https://packages.unity.com" }, @@ -178,9 +178,9 @@ "depth": 0, "source": "registry", "dependencies": { - "com.unity.modules.audio": "1.0.0", "com.unity.modules.director": "1.0.0", "com.unity.modules.animation": "1.0.0", + "com.unity.modules.audio": "1.0.0", "com.unity.modules.particlesystem": "1.0.0" }, "url": "https://packages.unity.com" diff --git a/ProjectSettings/GraphicsSettings.asset b/ProjectSettings/GraphicsSettings.asset index aa5a1c3..6ac71e3 100644 --- a/ProjectSettings/GraphicsSettings.asset +++ b/ProjectSettings/GraphicsSettings.asset @@ -36,10 +36,8 @@ GraphicsSettings: - {fileID: 10783, guid: 0000000000000000f000000000000000, type: 0} m_PreloadedShaders: [] m_PreloadShadersBatchTimeLimit: -1 - m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, - type: 0} - m_CustomRenderPipeline: {fileID: 11400000, guid: 4b83569d67af61e458304325a23e5dfd, - type: 2} + m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, type: 0} + m_CustomRenderPipeline: {fileID: 11400000, guid: 4b83569d67af61e458304325a23e5dfd, type: 2} m_TransparencySortMode: 0 m_TransparencySortAxis: {x: 0, y: 0, z: 1} m_DefaultRenderingPath: 1 @@ -60,8 +58,7 @@ GraphicsSettings: m_FogKeepExp2: 1 m_AlbedoSwatchInfos: [] m_RenderPipelineGlobalSettingsMap: - UnityEngine.Rendering.Universal.UniversalRenderPipeline: {fileID: 11400000, guid: 18dc0cd2c080841dea60987a38ce93fa, - type: 2} + UnityEngine.Rendering.Universal.UniversalRenderPipeline: {fileID: 11400000, guid: 3064fa2f5c54792e9ad65c7efc82c18d, type: 2} m_LightsUseLinearIntensity: 1 m_LightsUseColorTemperature: 1 m_LogWhenShaderIsCompiled: 0 diff --git a/ProjectSettings/ProjectVersion.txt b/ProjectSettings/ProjectVersion.txt index b3ee2d4..48c0834 100644 --- a/ProjectSettings/ProjectVersion.txt +++ b/ProjectSettings/ProjectVersion.txt @@ -1,2 +1,2 @@ -m_EditorVersion: 6000.2.7f2 -m_EditorVersionWithRevision: 6000.2.7f2 (2b518236b676) +m_EditorVersion: 6000.2.13f1 +m_EditorVersionWithRevision: 6000.2.13f1 (abdb44fca7f7) From d91057cf973910d84d86103c69e50c6743d7524f Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Tue, 25 Nov 2025 16:19:26 +0100 Subject: [PATCH 003/179] WIP: NaN error because zero distance --- Assembly-CSharp-Editor.csproj | 2 +- .../{GraphEditorWindow.cs => NeuroidWindow.cs} | 16 ++++++++-------- ...ditorWindow.cs.meta => NeuroidWindow.cs.meta} | 0 Assets/NanoBrain/Neuroid.cs | 4 ++++ Assets/Scenes/Boids/Boids.unity | 4 ++-- Assets/Scenes/Boids/Scripts/Boid.cs | 9 +++------ 6 files changed, 18 insertions(+), 17 deletions(-) rename Assets/NanoBrain/Editor/{GraphEditorWindow.cs => NeuroidWindow.cs} (93%) rename Assets/NanoBrain/Editor/{GraphEditorWindow.cs.meta => NeuroidWindow.cs.meta} (100%) diff --git a/Assembly-CSharp-Editor.csproj b/Assembly-CSharp-Editor.csproj index 0750862..584a691 100644 --- a/Assembly-CSharp-Editor.csproj +++ b/Assembly-CSharp-Editor.csproj @@ -48,7 +48,7 @@ - + diff --git a/Assets/NanoBrain/Editor/GraphEditorWindow.cs b/Assets/NanoBrain/Editor/NeuroidWindow.cs similarity index 93% rename from Assets/NanoBrain/Editor/GraphEditorWindow.cs rename to Assets/NanoBrain/Editor/NeuroidWindow.cs index e66eddb..afef229 100644 --- a/Assets/NanoBrain/Editor/GraphEditorWindow.cs +++ b/Assets/NanoBrain/Editor/NeuroidWindow.cs @@ -3,7 +3,7 @@ using UnityEngine; using System.Linq; using System.Collections.Generic; -public class Layer { +public class NeuroidLayer { public int ix = 0; public List neuroids = new(); } @@ -13,7 +13,7 @@ public class GraphEditorWindow : EditorWindow { private List allNeuroids; private Dictionary neuroidPositions = new(); - private List layers = new(); + private List layers = new(); private void OnEnable() { EditorApplication.update += EditorUpdate; @@ -33,7 +33,7 @@ public class GraphEditorWindow : EditorWindow { // While there are unvisited neuroid while (neuroids.Any(neuroid => !neuronVisited.Contains(neuroid))) { // Create the next layer - Layer currentLayer = new() { ix = layerIx }; + NeuroidLayer currentLayer = new() { ix = layerIx }; int neuroidIx = 0; foreach (Neuroid neuroid in neuroids) { @@ -82,7 +82,7 @@ public class GraphEditorWindow : EditorWindow { if (currentNeuroid == null) return; - foreach (Layer layer in layers) + foreach (NeuroidLayer layer in layers) DrawLayer(layer); // int column = 100; // int row = 200; @@ -119,7 +119,7 @@ public class GraphEditorWindow : EditorWindow { // } // } - private void DrawLayer(Layer layer) { + private void DrawLayer(NeuroidLayer layer) { int column = layer.ix * 100; int nodeCount = layer.neuroids.Count; float maxValue = 0; @@ -161,7 +161,7 @@ public class GraphEditorWindow : EditorWindow { private void HandleMouseHover(Neuroid neuroid, Rect rect) { // Draw the tooltip - GUIContent tooltip = new($"{neuroid.name}\n Value: {neuroid.outputValue}"); + GUIContent tooltip = new($"{neuroid.name}\n synapse count {neuroid.synapses.Count} \n Value: {neuroid.outputValue}"); Vector2 mousePosition = Event.current.mousePosition; // Display tooltip with some offset @@ -197,8 +197,8 @@ public class GraphEditorWindow : EditorWindow { } - [MenuItem("Window/Graph Visualizer")] + [MenuItem("Window/Neuroid Visualizer")] public static void ShowWindow() { - GetWindow("Graph Visualizer"); + GetWindow("Neuroid Visualizer"); } } diff --git a/Assets/NanoBrain/Editor/GraphEditorWindow.cs.meta b/Assets/NanoBrain/Editor/NeuroidWindow.cs.meta similarity index 100% rename from Assets/NanoBrain/Editor/GraphEditorWindow.cs.meta rename to Assets/NanoBrain/Editor/NeuroidWindow.cs.meta diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index 5a40f88..1650c1c 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -98,6 +98,10 @@ public class Neuroid { } Vector3 Activation(Vector3 sum) { + if (synapses.Count == 0 && mode == Mode.Average) + Debug.LogWarning($"{this.id} {this.name} has zero synapses for average"); + if (float.IsNaN(sum.magnitude)) + Debug.LogWarning($"{this.id} {this.name} sum is nan"); return mode switch { Mode.Sum => sum, Mode.Average => sum / synapses.Count, diff --git a/Assets/Scenes/Boids/Boids.unity b/Assets/Scenes/Boids/Boids.unity index e9b5a3b..85e18e2 100644 --- a/Assets/Scenes/Boids/Boids.unity +++ b/Assets/Scenes/Boids/Boids.unity @@ -373,12 +373,12 @@ MonoBehaviour: m_EditorClassIdentifier: Assembly-CSharp::SwarmControl speed: 0.5 inertia: 0.1 - alignmentForce: 0 + alignmentForce: 1 cohesionForce: 10 separationForce: 5 separationDistance: 0.5 bodyForce: 20 - boundaryForce: 5 + boundaryForce: 2 spaceSize: {x: 10, y: 10, z: 10} boundaryWidth: {x: 1, y: 1, z: 1} --- !u!114 &301943979 diff --git a/Assets/Scenes/Boids/Scripts/Boid.cs b/Assets/Scenes/Boids/Scripts/Boid.cs index a6d660c..1f1c5d6 100644 --- a/Assets/Scenes/Boids/Scripts/Boid.cs +++ b/Assets/Scenes/Boids/Scripts/Boid.cs @@ -104,12 +104,9 @@ public class Boid : MonoBehaviour // outside distances per axis (0 if inside on that axis) Vector3 outside = Vector3.Max(Vector3.zero, Vector3.Max(below, above)); - Vector3 dir = Vector3.zero; - dir.x = (below.x > 0f) ? 1f : ((above.x > 0f) ? -1f : 0f); - dir.y = (below.y > 0f) ? 1f : ((above.y > 0f) ? -1f : 0f); - dir.z = (below.z > 0f) ? 1f : ((above.z > 0f) ? -1f : 0f); - - outside = Vector3.Scale(outside, dir); + float magnitude = outside.magnitude; + Vector3 direction = (sc.transform.position - this.transform.position).normalized; + outside = direction * magnitude; boundary.SetInput(id, outside, sc.boundaryForce); Debug.Log($"boundary {this.transform.position} {outside} force = {outside * sc.boundaryForce}"); From cb04a7645b41f4b9b0a431216597c376187f3398 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 26 Nov 2025 15:48:00 +0100 Subject: [PATCH 004/179] Assed SensoryNeuroid --- .gitignore | 1 - Assembly-CSharp.csproj | 977 ++++++++++++------------ Assets/NanoBrain/SensoryNeuroid.cs | 19 + Assets/NanoBrain/SensoryNeuroid.cs.meta | 2 + ProjectSettings/GraphicsSettings.asset | 2 +- ProjectSettings/ProjectSettings.asset | 5 +- 6 files changed, 520 insertions(+), 486 deletions(-) create mode 100644 Assets/NanoBrain/SensoryNeuroid.cs create mode 100644 Assets/NanoBrain/SensoryNeuroid.cs.meta diff --git a/.gitignore b/.gitignore index 3f5d4d8..6df0e32 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,3 @@ Assets/DefaultVolumeProfile.asset Assets/DefaultVolumeProfile.asset.meta Assets/UniversalRenderPipelineGlobalSettings.asset Assets/UniversalRenderPipelineGlobalSettings.asset.meta -NanoBrain-Unity.slnx diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index 140f0c3..a3f3720 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -23,7 +23,7 @@ 0169;USG0001 - UNITY_6000_2_13;UNITY_6000_2;UNITY_6000;UNITY_5_3_OR_NEWER;UNITY_5_4_OR_NEWER;UNITY_5_5_OR_NEWER;UNITY_5_6_OR_NEWER;UNITY_2017_1_OR_NEWER;UNITY_2017_2_OR_NEWER;UNITY_2017_3_OR_NEWER;UNITY_2017_4_OR_NEWER;UNITY_2018_1_OR_NEWER;UNITY_2018_2_OR_NEWER;UNITY_2018_3_OR_NEWER;UNITY_2018_4_OR_NEWER;UNITY_2019_1_OR_NEWER;UNITY_2019_2_OR_NEWER;UNITY_2019_3_OR_NEWER;UNITY_2019_4_OR_NEWER;UNITY_2020_1_OR_NEWER;UNITY_2020_2_OR_NEWER;UNITY_2020_3_OR_NEWER;UNITY_2021_1_OR_NEWER;UNITY_2021_2_OR_NEWER;UNITY_2021_3_OR_NEWER;UNITY_2022_1_OR_NEWER;UNITY_2022_2_OR_NEWER;UNITY_2022_3_OR_NEWER;UNITY_2023_1_OR_NEWER;UNITY_2023_2_OR_NEWER;UNITY_2023_3_OR_NEWER;UNITY_6000_0_OR_NEWER;UNITY_6000_1_OR_NEWER;UNITY_6000_2_OR_NEWER;PLATFORM_ARCH_64;UNITY_64;UNITY_INCLUDE_TESTS;ENABLE_AUDIO;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_MICROPHONE;ENABLE_MULTIPLE_DISPLAYS;ENABLE_PHYSICS;ENABLE_TEXTURE_STREAMING;ENABLE_VIRTUALTEXTURING;ENABLE_LZMA;ENABLE_UNITYEVENTS;ENABLE_VR;ENABLE_WEBCAM;ENABLE_UNITYWEBREQUEST;ENABLE_WWW;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_SERVICES_USE_WEBREQUEST;ENABLE_UNITY_CONSENT;ENABLE_UNITY_CLOUD_IDENTIFIERS;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_EDITOR_GAME_SERVICES;ENABLE_UNITY_GAME_SERVICES_ANALYTICS_SUPPORT;ENABLE_CLOUD_LICENSE;ENABLE_EDITOR_HUB_LICENSE;ENABLE_WEBSOCKET_CLIENT;ENABLE_GENERATE_NATIVE_PLUGINS_FOR_ASSEMBLIES_API;ENABLE_DIRECTOR_AUDIO;ENABLE_DIRECTOR_TEXTURE;ENABLE_MANAGED_JOBS;ENABLE_MANAGED_TRANSFORM_JOBS;ENABLE_MANAGED_ANIMATION_JOBS;ENABLE_MANAGED_AUDIO_JOBS;ENABLE_MANAGED_UNITYTLS;INCLUDE_DYNAMIC_GI;ENABLE_SCRIPTING_GC_WBARRIERS;PLATFORM_SUPPORTS_MONO;RENDER_SOFTWARE_CURSOR;ENABLE_MARSHALLING_TESTS;ENABLE_VIDEO;ENABLE_NAVIGATION_OFFMESHLINK_TO_NAVMESHLINK;ENABLE_ACCELERATOR_CLIENT_DEBUGGING;TEXTCORE_1_0_OR_NEWER;EDITOR_ONLY_NAVMESH_BUILDER_DEPRECATED;PLATFORM_STANDALONE_LINUX;PLATFORM_STANDALONE;UNITY_STANDALONE_LINUX;UNITY_STANDALONE;UNITY_STANDALONE_LINUX_API;ENABLE_RUNTIME_GI;ENABLE_MOVIES;ENABLE_NETWORK;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_CLUSTER_SYNC;ENABLE_CLUSTERINPUT;ENABLE_SPATIALTRACKING;ENABLE_MODULAR_UNITYENGINE_ASSEMBLIES;PLATFORM_SUPPORTS_SPLIT_GRAPHICS_JOBS;PLATFORM_USES_EXPLICIT_MEMORY_MANAGER_INITIALIZER;ENABLE_MONO;NET_STANDARD_2_0;NET_STANDARD;NET_STANDARD_2_1;NETSTANDARD;NETSTANDARD2_1;ENABLE_PROFILER;DEBUG;TRACE;UNITY_ASSERTIONS;UNITY_EDITOR;UNITY_EDITOR_64;UNITY_EDITOR_LINUX;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_BURST_AOT;UNITY_TEAM_LICENSE;ENABLE_CUSTOM_RENDER_TEXTURE;ENABLE_DIRECTOR;ENABLE_LOCALIZATION;ENABLE_SPRITES;ENABLE_TERRAIN;ENABLE_TILEMAP;ENABLE_TIMELINE;ENABLE_INPUT_SYSTEM;TEXTCORE_FONT_ENGINE_1_5_OR_NEWER;TEXTCORE_TEXT_ENGINE_1_5_OR_NEWER;CSHARP_7_OR_LATER;CSHARP_7_3_OR_NEWER + UNITY_6000_2_13;UNITY_6000_2;UNITY_6000;UNITY_5_3_OR_NEWER;UNITY_5_4_OR_NEWER;UNITY_5_5_OR_NEWER;UNITY_5_6_OR_NEWER;UNITY_2017_1_OR_NEWER;UNITY_2017_2_OR_NEWER;UNITY_2017_3_OR_NEWER;UNITY_2017_4_OR_NEWER;UNITY_2018_1_OR_NEWER;UNITY_2018_2_OR_NEWER;UNITY_2018_3_OR_NEWER;UNITY_2018_4_OR_NEWER;UNITY_2019_1_OR_NEWER;UNITY_2019_2_OR_NEWER;UNITY_2019_3_OR_NEWER;UNITY_2019_4_OR_NEWER;UNITY_2020_1_OR_NEWER;UNITY_2020_2_OR_NEWER;UNITY_2020_3_OR_NEWER;UNITY_2021_1_OR_NEWER;UNITY_2021_2_OR_NEWER;UNITY_2021_3_OR_NEWER;UNITY_2022_1_OR_NEWER;UNITY_2022_2_OR_NEWER;UNITY_2022_3_OR_NEWER;UNITY_2023_1_OR_NEWER;UNITY_2023_2_OR_NEWER;UNITY_2023_3_OR_NEWER;UNITY_6000_0_OR_NEWER;UNITY_6000_1_OR_NEWER;UNITY_6000_2_OR_NEWER;PLATFORM_ARCH_64;UNITY_64;UNITY_INCLUDE_TESTS;ENABLE_AUDIO;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_MICROPHONE;ENABLE_MULTIPLE_DISPLAYS;ENABLE_PHYSICS;ENABLE_TEXTURE_STREAMING;ENABLE_VIRTUALTEXTURING;ENABLE_LZMA;ENABLE_UNITYEVENTS;ENABLE_VR;ENABLE_WEBCAM;ENABLE_UNITYWEBREQUEST;ENABLE_WWW;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_SERVICES_USE_WEBREQUEST;ENABLE_UNITY_CONSENT;ENABLE_UNITY_CLOUD_IDENTIFIERS;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_EDITOR_GAME_SERVICES;ENABLE_UNITY_GAME_SERVICES_ANALYTICS_SUPPORT;ENABLE_CLOUD_LICENSE;ENABLE_EDITOR_HUB_LICENSE;ENABLE_WEBSOCKET_CLIENT;ENABLE_GENERATE_NATIVE_PLUGINS_FOR_ASSEMBLIES_API;ENABLE_DIRECTOR_AUDIO;ENABLE_DIRECTOR_TEXTURE;ENABLE_MANAGED_JOBS;ENABLE_MANAGED_TRANSFORM_JOBS;ENABLE_MANAGED_ANIMATION_JOBS;ENABLE_MANAGED_AUDIO_JOBS;ENABLE_MANAGED_UNITYTLS;INCLUDE_DYNAMIC_GI;ENABLE_SCRIPTING_GC_WBARRIERS;PLATFORM_SUPPORTS_MONO;RENDER_SOFTWARE_CURSOR;ENABLE_MARSHALLING_TESTS;ENABLE_VIDEO;ENABLE_NAVIGATION_OFFMESHLINK_TO_NAVMESHLINK;ENABLE_ACCELERATOR_CLIENT_DEBUGGING;TEXTCORE_1_0_OR_NEWER;EDITOR_ONLY_NAVMESH_BUILDER_DEPRECATED;PLATFORM_STANDALONE_LINUX;PLATFORM_STANDALONE;UNITY_STANDALONE_LINUX;UNITY_STANDALONE;UNITY_STANDALONE_LINUX_API;ENABLE_RUNTIME_GI;ENABLE_MOVIES;ENABLE_NETWORK;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_CLUSTER_SYNC;ENABLE_CLUSTERINPUT;ENABLE_SPATIALTRACKING;ENABLE_MODULAR_UNITYENGINE_ASSEMBLIES;PLATFORM_SUPPORTS_SPLIT_GRAPHICS_JOBS;PLATFORM_USES_EXPLICIT_MEMORY_MANAGER_INITIALIZER;ENABLE_MONO;NET_4_6;NET_UNITY_4_8;ENABLE_PROFILER;DEBUG;TRACE;UNITY_ASSERTIONS;UNITY_EDITOR;UNITY_EDITOR_64;UNITY_EDITOR_LINUX;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_BURST_AOT;UNITY_TEAM_LICENSE;ENABLE_CUSTOM_RENDER_TEXTURE;ENABLE_DIRECTOR;ENABLE_LOCALIZATION;ENABLE_SPRITES;ENABLE_TERRAIN;ENABLE_TILEMAP;ENABLE_TIMELINE;ENABLE_INPUT_SYSTEM;TEXTCORE_FONT_ENGINE_1_5_OR_NEWER;TEXTCORE_TEXT_ENGINE_1_5_OR_NEWER;CSHARP_7_OR_LATER;CSHARP_7_3_OR_NEWER False @@ -50,6 +50,7 @@ + @@ -555,492 +556,504 @@ Library/PackageCache/com.unity.collections@aea9d3bd5e19/Unity.Collections.Tests/System.Runtime.CompilerServices.Unsafe/System.Runtime.CompilerServices.Unsafe.dll False - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/ref/2.1.0/netstandard.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/Microsoft.Win32.Primitives.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.AppContext.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Buffers.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Collections.Concurrent.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Collections.NonGeneric.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Collections.Specialized.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Collections.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.ComponentModel.EventBasedAsync.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.ComponentModel.Primitives.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.ComponentModel.TypeConverter.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.ComponentModel.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Console.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Data.Common.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.Contracts.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.Debug.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.FileVersionInfo.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.Process.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.StackTrace.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.TextWriterTraceListener.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.Tools.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.TraceSource.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.Tracing.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Drawing.Primitives.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Dynamic.Runtime.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Globalization.Calendars.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Globalization.Extensions.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Globalization.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.IO.Compression.ZipFile.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.IO.Compression.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.IO.FileSystem.DriveInfo.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.IO.FileSystem.Primitives.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.IO.FileSystem.Watcher.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.IO.FileSystem.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.IO.IsolatedStorage.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.IO.MemoryMappedFiles.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.IO.Pipes.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.IO.UnmanagedMemoryStream.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.IO.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Linq.Expressions.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Linq.Parallel.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Linq.Queryable.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Linq.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Memory.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Net.Http.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Net.NameResolution.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Net.NetworkInformation.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Net.Ping.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Net.Primitives.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Net.Requests.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Net.Security.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Net.Sockets.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Net.WebHeaderCollection.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Net.WebSockets.Client.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Net.WebSockets.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Numerics.Vectors.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.ObjectModel.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.DispatchProxy.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.Emit.ILGeneration.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.Emit.Lightweight.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.Emit.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.Extensions.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.Primitives.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Resources.Reader.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Resources.ResourceManager.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Resources.Writer.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.CompilerServices.VisualC.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Extensions.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Handles.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.InteropServices.RuntimeInformation.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.InteropServices.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Numerics.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Serialization.Formatters.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Serialization.Json.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Serialization.Primitives.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Serialization.Xml.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Claims.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Cryptography.Algorithms.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Cryptography.Csp.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Cryptography.Encoding.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Cryptography.Primitives.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Cryptography.X509Certificates.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Principal.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Security.SecureString.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Text.Encoding.Extensions.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Text.Encoding.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Text.RegularExpressions.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.Overlapped.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.Tasks.Extensions.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.Tasks.Parallel.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.Tasks.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.Thread.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.ThreadPool.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.Timer.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.ValueTuple.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Xml.ReaderWriter.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Xml.XDocument.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Xml.XPath.XDocument.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Xml.XPath.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Xml.XmlDocument.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netstandard/System.Xml.XmlSerializer.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/Extensions/2.0.0/System.Runtime.InteropServices.WindowsRuntime.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netfx/System.ComponentModel.Composition.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netfx/System.Core.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netfx/System.Data.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netfx/System.Drawing.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netfx/System.IO.Compression.FileSystem.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netfx/System.Net.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netfx/System.Numerics.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netfx/System.Runtime.Serialization.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netfx/System.ServiceModel.Web.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netfx/System.Transactions.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netfx/System.Web.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netfx/System.Windows.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netfx/System.Xml.Linq.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netfx/System.Xml.Serialization.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netfx/System.Xml.dll + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/mscorlib.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netfx/System.dll + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.dll False - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/NetStandard/compat/2.1.0/shims/netfx/mscorlib.dll + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Core.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Runtime.Serialization.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Xml.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Xml.Linq.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Numerics.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Numerics.Vectors.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Net.Http.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.IO.Compression.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Microsoft.CSharp.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Data.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Data.DataSetExtensions.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Drawing.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.IO.Compression.FileSystem.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.ComponentModel.Composition.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Transactions.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/Microsoft.Win32.Primitives.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.AppContext.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Buffers.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.Concurrent.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.NonGeneric.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.Specialized.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.Annotations.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.EventBasedAsync.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.Primitives.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.TypeConverter.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Console.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Data.Common.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Contracts.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Debug.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.FileVersionInfo.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Process.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.StackTrace.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.TextWriterTraceListener.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Tools.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.TraceSource.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Drawing.Primitives.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Dynamic.Runtime.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Globalization.Calendars.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Globalization.Extensions.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Globalization.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.Compression.ZipFile.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.DriveInfo.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.Primitives.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.Watcher.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.IsolatedStorage.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.MemoryMappedFiles.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.Pipes.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.UnmanagedMemoryStream.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.Expressions.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.Parallel.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.Queryable.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Memory.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Http.Rtc.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.NameResolution.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.NetworkInformation.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Ping.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Primitives.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Requests.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Security.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Sockets.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.WebHeaderCollection.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.WebSockets.Client.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.WebSockets.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ObjectModel.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.DispatchProxy.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Emit.ILGeneration.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Emit.Lightweight.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Emit.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Extensions.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Primitives.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Resources.Reader.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Resources.ResourceManager.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Resources.Writer.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.CompilerServices.VisualC.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Extensions.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Handles.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.InteropServices.RuntimeInformation.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.InteropServices.WindowsRuntime.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.InteropServices.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Numerics.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Formatters.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Json.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Primitives.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Xml.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Claims.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Algorithms.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Csp.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Encoding.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Primitives.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.X509Certificates.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Principal.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.SecureString.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Duplex.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Http.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.NetTcp.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Primitives.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Security.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Text.Encoding.Extensions.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Text.Encoding.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Text.RegularExpressions.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Overlapped.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Tasks.Extensions.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Tasks.Parallel.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Tasks.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Thread.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.ThreadPool.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Timer.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ValueTuple.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.ReaderWriter.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XDocument.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XPath.XDocument.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XPath.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XmlDocument.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XmlSerializer.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/netstandard.dll False diff --git a/Assets/NanoBrain/SensoryNeuroid.cs b/Assets/NanoBrain/SensoryNeuroid.cs new file mode 100644 index 0000000..e49f64e --- /dev/null +++ b/Assets/NanoBrain/SensoryNeuroid.cs @@ -0,0 +1,19 @@ +using UnityEngine; + +class Receptor { + public SensoryNeuroid neuroid; + public void SetValue(Vector3 value) { + if (neuroid != null) { + neuroid.SetInput(neuroid.id, value); + } + } +} + + +class SensoryNeuroid : Neuroid { + public Receptor receptor; + + public SensoryNeuroid(NeuroidNetwork id) : base(id) { + } + +} \ No newline at end of file diff --git a/Assets/NanoBrain/SensoryNeuroid.cs.meta b/Assets/NanoBrain/SensoryNeuroid.cs.meta new file mode 100644 index 0000000..40e2ec3 --- /dev/null +++ b/Assets/NanoBrain/SensoryNeuroid.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 9e34db6b23aa12477a2f98b9eb0cbbe2 \ No newline at end of file diff --git a/ProjectSettings/GraphicsSettings.asset b/ProjectSettings/GraphicsSettings.asset index 6ac71e3..02f1134 100644 --- a/ProjectSettings/GraphicsSettings.asset +++ b/ProjectSettings/GraphicsSettings.asset @@ -58,7 +58,7 @@ GraphicsSettings: m_FogKeepExp2: 1 m_AlbedoSwatchInfos: [] m_RenderPipelineGlobalSettingsMap: - UnityEngine.Rendering.Universal.UniversalRenderPipeline: {fileID: 11400000, guid: 3064fa2f5c54792e9ad65c7efc82c18d, type: 2} + UnityEngine.Rendering.Universal.UniversalRenderPipeline: {fileID: 11400000, guid: 370d27fa5af5291e18529fa336759ac9, type: 2} m_LightsUseLinearIntensity: 1 m_LightsUseColorTemperature: 1 m_LogWhenShaderIsCompiled: 0 diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset index 5c83bc5..eb3e21f 100644 --- a/ProjectSettings/ProjectSettings.asset +++ b/ProjectSettings/ProjectSettings.asset @@ -70,6 +70,7 @@ PlayerSettings: androidStartInFullscreen: 1 androidRenderOutsideSafeArea: 1 androidUseSwappy: 0 + androidDisplayOptions: 1 androidBlitType: 0 androidResizeableActivity: 1 androidDefaultWindowWidth: 1920 @@ -840,7 +841,7 @@ PlayerSettings: gcIncremental: 1 gcWBarrierValidation: 0 apiCompatibilityLevelPerPlatform: {} - editorAssembliesCompatibilityLevel: 1 + editorAssembliesCompatibilityLevel: 2 m_RenderingPath: 1 m_MobileRenderingPath: 1 metroPackageName: NanoBrain @@ -917,7 +918,7 @@ PlayerSettings: hmiCpuConfiguration: hmiLogStartupTiming: 0 qnxGraphicConfPath: - apiCompatibilityLevel: 6 + apiCompatibilityLevel: 3 captureStartupLogs: {} activeInputHandler: 1 windowsGamepadBackendHint: 0 From 2e803179e3503e24218c90f20505151d02ade663 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 26 Nov 2025 17:40:06 +0100 Subject: [PATCH 005/179] improved sensoryneuroids --- Assets/NanoBrain/Editor/NeuroidWindow.cs | 42 +++---------------- Assets/NanoBrain/Neuroid.cs | 2 + Assets/NanoBrain/SensoryNeuroid.cs | 11 +++-- Assets/Scenes/Boids/Scripts/Boid.cs | 53 ++++++++++++++++-------- NanoBrain-Unity.slnx | 4 ++ 5 files changed, 56 insertions(+), 56 deletions(-) create mode 100644 NanoBrain-Unity.slnx diff --git a/Assets/NanoBrain/Editor/NeuroidWindow.cs b/Assets/NanoBrain/Editor/NeuroidWindow.cs index afef229..e767ea8 100644 --- a/Assets/NanoBrain/Editor/NeuroidWindow.cs +++ b/Assets/NanoBrain/Editor/NeuroidWindow.cs @@ -38,15 +38,18 @@ public class GraphEditorWindow : EditorWindow { foreach (Neuroid neuroid in neuroids) { // If this neuroid is not visited while its output neuroid is visited - if (!neuronVisited.Contains(neuroid) && (neuronVisited.Contains(neuroid.outputNeuroid) || neuroid.outputNeuroid == null)) { + if (!neuronVisited.Contains(neuroid) && (neuroid.outputNeuroid == null || + (neuronVisited.Contains(neuroid.outputNeuroid) && neuroid.outputNeuroid.layerIx == layerIx - 1))) { // Add it to the next layer currentLayer.neuroids.Add(neuroid); + neuroid.layerIx = layerIx; // Register it as visited neuronVisited.Add(neuroid); // Store its position Vector2Int neuroidPosition = new(layerIx, neuroidIx); neuroidPositions[neuroid] = neuroidPosition; neuroidIx++; + Debug.Log($"Layer {layerIx} neuron {neuroidIx} id {neuroid.id} {neuroid.name}"); } } @@ -84,41 +87,8 @@ public class GraphEditorWindow : EditorWindow { foreach (NeuroidLayer layer in layers) DrawLayer(layer); - // int column = 100; - // int row = 200; - // Vector3 parentPos = new(column, row, 0.1f); - // Handles.DrawSolidDisc(parentPos, Vector3.forward, 15); - - // DrawLayer(2, parentPos); } - // private void DrawLayer(int layerIx, Vector3 parentPos) { - // int column = layerIx * 100; - // int nodeCount = currentNeuroid.synapses.Count; - // float maxValue = 0; - // foreach (Synapse synapse in currentNeuroid.synapses.Values) { - // float value = synapse.value.magnitude; - // if (value > maxValue) - // maxValue = value; - // } - - // float spacing = 200f / nodeCount; // Calculate spacing - // float margin = 100 + spacing / 3; - // int i = 0; - // foreach (Synapse synapse in currentNeuroid.synapses.Values) { - // Vector3 pos = new(column, margin + i * spacing); - - // float brightness = synapse.weight / 10.0f; - // Handles.color = new Color(brightness, brightness, brightness); - // Handles.DrawLine(parentPos - Vector3.forward, pos); - - // float size = synapse.value.magnitude / maxValue * 20; - // Handles.color = Color.white; - // Handles.DrawSolidDisc(pos, Vector3.forward, size); - // i++; - // } - // } - private void DrawLayer(NeuroidLayer layer) { int column = layer.ix * 100; int nodeCount = layer.neuroids.Count; @@ -151,7 +121,7 @@ public class GraphEditorWindow : EditorWindow { float size = layerNeuroid.outputValue.magnitude / maxValue * 20; Handles.color = Color.white; Handles.DrawSolidDisc(parentPos, Vector3.forward, size); - Rect neuronRect = new(parentPos.x-size, parentPos.y-size, size*2, size*2); + Rect neuronRect = new(parentPos.x - size, parentPos.y - size, size * 2, size * 2); if (neuronRect.Contains(Event.current.mousePosition)) HandleMouseHover(layerNeuroid, neuronRect); i++; @@ -167,7 +137,7 @@ public class GraphEditorWindow : EditorWindow { // Display tooltip with some offset Vector2 tooltipSize = GUI.skin.box.CalcSize(tooltip); Rect tooltipRect = new Rect(mousePosition.x + 10, mousePosition.y + 10, tooltipSize.x, tooltipSize.y); - + GUI.Box(tooltipRect, tooltip); } diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index 1650c1c..ed0c772 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -26,6 +26,8 @@ public class Neuroid { public int id; public string name; + public int layerIx; + public readonly Dictionary synapses = new(); public Vector3 outputValue; diff --git a/Assets/NanoBrain/SensoryNeuroid.cs b/Assets/NanoBrain/SensoryNeuroid.cs index e49f64e..5dfe556 100644 --- a/Assets/NanoBrain/SensoryNeuroid.cs +++ b/Assets/NanoBrain/SensoryNeuroid.cs @@ -1,6 +1,6 @@ using UnityEngine; -class Receptor { +public class Receptor { public SensoryNeuroid neuroid; public void SetValue(Vector3 value) { if (neuroid != null) { @@ -10,10 +10,15 @@ class Receptor { } -class SensoryNeuroid : Neuroid { +public class SensoryNeuroid : Neuroid { public Receptor receptor; - public SensoryNeuroid(NeuroidNetwork id) : base(id) { + public SensoryNeuroid(NeuroidNetwork net, int id) : base(net) { + this.name = "sensory neuroid"; + this.id = id; + this.receptor = new Receptor { + neuroid = this + }; } } \ No newline at end of file diff --git a/Assets/Scenes/Boids/Scripts/Boid.cs b/Assets/Scenes/Boids/Scripts/Boid.cs index 1f1c5d6..ec83a28 100644 --- a/Assets/Scenes/Boids/Scripts/Boid.cs +++ b/Assets/Scenes/Boids/Scripts/Boid.cs @@ -1,8 +1,7 @@ using UnityEngine; -public class Boid : MonoBehaviour -{ +public class Boid : MonoBehaviour { public float speed = 0.2f; public int neighbourCount = 0; public float inertia = 0.2f; @@ -20,6 +19,8 @@ public class Boid : MonoBehaviour readonly Collider[] results = new Collider[10]; + public SensoryNeuroid[] neighbourSensor = new SensoryNeuroid[6]; + public NeuroidNetwork neuroidNet = new(); public Neuroid bodyVector; public Neuroid cohesion; @@ -32,15 +33,17 @@ public class Boid : MonoBehaviour public int id; - void Awake() - { + void Awake() { this.id = this.GetInstanceID(); sc = FindFirstObjectByType(); bounds = new(sc.transform.position, sc.spaceSize - 2 * sc.boundaryWidth); + //neighbourSensor = new(neuroidNet) { name = "Neighbour", id = 879 }; + cohesion = new(neuroidNet) { name = "Cohesion", mode = Neuroid.Mode.Sum }; + //cohesion.GetInputFrom(neighbourSensor); alignment = new(neuroidNet) { name = "Alignment", mode = Neuroid.Mode.Average }; separation = new(neuroidNet) { name = "Separation", mode = Neuroid.Mode.Sum }; target = new(neuroidNet) { name = "Target", mode = Neuroid.Mode.Sum }; @@ -55,8 +58,7 @@ public class Boid : MonoBehaviour totalForce.GetInputFrom(boundary, sc.boundaryForce); } - void Update() - { + void Update() { Physics.OverlapSphereNonAlloc(this.transform.position, 10, results); neighbourCount = 0; @@ -64,13 +66,11 @@ public class Boid : MonoBehaviour alignment.ResetWeights(); separation.ResetWeights(); - foreach (Collider c in results) - { + foreach (Collider c in results) { if (c == null) continue; - if (c as CapsuleCollider != null) - { + if (c as CapsuleCollider != null) { Boid neighbour = c.GetComponentInParent(); if (neighbour == null || neighbour == this) continue; @@ -79,12 +79,15 @@ public class Boid : MonoBehaviour Vector3 relativeVelocity = neighbour.velocity - this.velocity; int id = neighbour.GetInstanceID(); - + Receptor receptor = GetReceptor(id); + if (receptor != null) { + receptor.SetValue(localPosition); + } Vector3 separationForce = -localPosition / localPosition.sqrMagnitude; // which is equivalent to -(localPosition.normalized / localPosition.magnitude) separation.SetInput(id, separationForce, sc.separationDistance); - cohesion.SetInput(id, localPosition, sc.cohesionForce); + //cohesion.SetInput(id, localPosition, sc.cohesionForce); alignment.SetInput(id, relativeVelocity, sc.alignmentForce); neighbourCount++; @@ -92,8 +95,7 @@ public class Boid : MonoBehaviour } //Vector3 spaceLocalPosition = sc.transform.InverseTransformPoint(this.transform.position); - if (!bounds.Contains(this.transform.position)) - { + if (!bounds.Contains(this.transform.position)) { Vector3 point = this.transform.position; // Vector3 distanceOutside = Vector3.Max(bounds.min - this.transform.position, this.transform.position - bounds.max); // // Ensure value is > 0 (but isn't this already) @@ -109,7 +111,7 @@ public class Boid : MonoBehaviour outside = direction * magnitude; boundary.SetInput(id, outside, sc.boundaryForce); - Debug.Log($"boundary {this.transform.position} {outside} force = {outside * sc.boundaryForce}"); + // Debug.Log($"boundary {this.transform.position} {outside} force = {outside * sc.boundaryForce}"); } Vector3 totalForceVector = totalForce.outputValue; @@ -120,11 +122,28 @@ public class Boid : MonoBehaviour this.transform.position += this.velocity * Time.deltaTime; - if (this.velocity != Vector3.zero) - { + if (this.velocity != Vector3.zero) { Quaternion targetRotation = Quaternion.LookRotation(this.velocity); transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 2f); // Adjust the speed of rotation } } + Receptor GetReceptor(int id) { + int availableIx = -1; + for (int i = 0; i < neighbourSensor.Length; i++) { + if (neighbourSensor[i] == null) + availableIx = i; + else if (neighbourSensor[i].id == id) + return neighbourSensor[i].receptor; + } + if (availableIx != -1) { + Debug.Log($"new receptor for {id}"); + SensoryNeuroid neuroid = new(neuroidNet, id); + cohesion.GetInputFrom(neuroid); + neighbourSensor[availableIx] = neuroid; + return neuroid.receptor; + } + return null; + } + } diff --git a/NanoBrain-Unity.slnx b/NanoBrain-Unity.slnx new file mode 100644 index 0000000..90452ad --- /dev/null +++ b/NanoBrain-Unity.slnx @@ -0,0 +1,4 @@ + + + + From 1771ab7d23a15b1dd83ff2bcdb976670ab827e52 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 27 Nov 2025 14:08:24 +0100 Subject: [PATCH 006/179] Boids seem to work, but don't flock together --- Assets/NanoBrain/Editor/NeuroidWindow.cs | 30 +- Assets/NanoBrain/Neuroid.cs | 12 + Assets/NanoBrain/SensoryNeuroid.cs | 10 +- Assets/Scenes/Boids/Boids.unity | 17 +- Assets/Scenes/Boids/Materials/White.mat | 14 +- Assets/Scenes/Boids/Scripts/Boid.cs | 85 +- Assets/Scenes/Boids/Scripts/SwarmControl.cs | 1 + Assets/_Recovery.meta | 8 + Assets/_Recovery/0.unity | 1123 +++++++++++++++++++ Assets/_Recovery/0.unity.meta | 7 + NanoBrain-Unity.code-workspace | 19 + mono_crash.mem.19211.1.blob | Bin 0 -> 10000001 bytes 12 files changed, 1289 insertions(+), 37 deletions(-) create mode 100644 Assets/_Recovery.meta create mode 100644 Assets/_Recovery/0.unity create mode 100644 Assets/_Recovery/0.unity.meta create mode 100644 NanoBrain-Unity.code-workspace create mode 100644 mono_crash.mem.19211.1.blob diff --git a/Assets/NanoBrain/Editor/NeuroidWindow.cs b/Assets/NanoBrain/Editor/NeuroidWindow.cs index e767ea8..0548e29 100644 --- a/Assets/NanoBrain/Editor/NeuroidWindow.cs +++ b/Assets/NanoBrain/Editor/NeuroidWindow.cs @@ -37,6 +37,11 @@ public class GraphEditorWindow : EditorWindow { int neuroidIx = 0; foreach (Neuroid neuroid in neuroids) { + if (neuroid.IsStale()) { + neuronVisited.Add(neuroid); + continue; + } + // If this neuroid is not visited while its output neuroid is visited if (!neuronVisited.Contains(neuroid) && (neuroid.outputNeuroid == null || (neuronVisited.Contains(neuroid.outputNeuroid) && neuroid.outputNeuroid.layerIx == layerIx - 1))) { @@ -109,17 +114,23 @@ public class GraphEditorWindow : EditorWindow { float inputMargin = 100 + inputSpacing / 2; foreach (Synapse synapse in layerNeuroid.synapses.Values) { if (synapse.neuroid != null) { - Vector2Int inputNeuroidPos = this.neuroidPositions[synapse.neuroid]; - Vector3 pos = new(100 + inputNeuroidPos.x * 100, inputMargin + inputNeuroidPos.y * inputSpacing, 0.0f); + if (this.neuroidPositions.ContainsKey(synapse.neuroid)) { - float brightness = synapse.weight / 10.0f; - Handles.color = new Color(brightness, brightness, brightness); - Handles.DrawLine(parentPos, pos); + Vector2Int inputNeuroidPos = this.neuroidPositions[synapse.neuroid]; + Vector3 pos = new(100 + inputNeuroidPos.x * 100, inputMargin + inputNeuroidPos.y * inputSpacing, 0.0f); + + float brightness = synapse.weight / 10.0f; + Handles.color = new Color(brightness, brightness, brightness); + Handles.DrawLine(parentPos, pos); + } } } float size = layerNeuroid.outputValue.magnitude / maxValue * 20; - Handles.color = Color.white; + if (layerNeuroid.IsStale()) + Handles.color = Color.yellow; + else + Handles.color = Color.white; Handles.DrawSolidDisc(parentPos, Vector3.forward, size); Rect neuronRect = new(parentPos.x - size, parentPos.y - size, size * 2, size * 2); if (neuronRect.Contains(Event.current.mousePosition)) @@ -131,7 +142,12 @@ public class GraphEditorWindow : EditorWindow { private void HandleMouseHover(Neuroid neuroid, Rect rect) { // Draw the tooltip - GUIContent tooltip = new($"{neuroid.name}\n synapse count {neuroid.synapses.Count} \n Value: {neuroid.outputValue}"); + GUIContent tooltip = new( + $"{neuroid.name}" + + $"\nsynapse count {neuroid.synapses.Count}" + + $"\nValue: {neuroid.outputValue}" + + $"\nStale: {neuroid.stale}"); + Vector2 mousePosition = Event.current.mousePosition; // Display tooltip with some offset diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index ed0c772..a098aaa 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -20,6 +20,12 @@ public class NeuroidNetwork { Neuroid neuroid = new(this); return neuroid; } + + public void Update() { + foreach (Neuroid neuroid in neuroids) { + neuroid.stale++; + } + } } public class Neuroid { @@ -27,6 +33,7 @@ public class Neuroid { public string name; public int layerIx; + public int stale = 0; public readonly Dictionary synapses = new(); @@ -97,6 +104,7 @@ public class Neuroid { this.outputValue = Activation(sum); this.outputNeuroid?.SetInput(this.outputNeurix, this.outputValue); + this.stale = 0; } Vector3 Activation(Vector3 sum) { @@ -111,5 +119,9 @@ public class Neuroid { }; //return sum; //(sum.magnitude > 0.5f) ? sum : Vector3.zero; } + + public bool IsStale() { + return this.stale > 2; + } } diff --git a/Assets/NanoBrain/SensoryNeuroid.cs b/Assets/NanoBrain/SensoryNeuroid.cs index 5dfe556..7651d30 100644 --- a/Assets/NanoBrain/SensoryNeuroid.cs +++ b/Assets/NanoBrain/SensoryNeuroid.cs @@ -7,15 +7,23 @@ public class Receptor { neuroid.SetInput(neuroid.id, value); } } + public Vector3 GetValue() { + if (neuroid != null) + return neuroid.synapses[neuroid.id].value; + else + return Vector3.zero; + } } public class SensoryNeuroid : Neuroid { public Receptor receptor; + public int thingId; public SensoryNeuroid(NeuroidNetwork net, int id) : base(net) { this.name = "sensory neuroid"; - this.id = id; + // this.id = id; + this.thingId = id; this.receptor = new Receptor { neuroid = this }; diff --git a/Assets/Scenes/Boids/Boids.unity b/Assets/Scenes/Boids/Boids.unity index 85e18e2..5b7c526 100644 --- a/Assets/Scenes/Boids/Boids.unity +++ b/Assets/Scenes/Boids/Boids.unity @@ -371,14 +371,15 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 0464906885ae3494f8fd0314719fb2db, type: 3} m_Name: m_EditorClassIdentifier: Assembly-CSharp::SwarmControl - speed: 0.5 + speed: 1 inertia: 0.1 - alignmentForce: 1 - cohesionForce: 10 + alignmentForce: 5 + cohesionForce: 5 separationForce: 5 - separationDistance: 0.5 + separationDistance: 0.3 bodyForce: 20 - boundaryForce: 2 + perceptionDistance: 2 + boundaryForce: 5 spaceSize: {x: 10, y: 10, z: 10} boundaryWidth: {x: 1, y: 1, z: 1} --- !u!114 &301943979 @@ -393,11 +394,11 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec888ca5333d45a438f9f417fa5ce135, type: 3} m_Name: m_EditorClassIdentifier: Assembly-CSharp::SwarmSpawn - count: 100 + count: 1000 boidPrefab: {fileID: 8702527964058765413, guid: f9c706268554ce449a8773675b2864b8, type: 3} spawnAreaSize: {x: 0.5, y: 0.5, z: 0.5} - minDelay: 0.1 - maxDelay: 1 + minDelay: 0.05 + maxDelay: 0.2 --- !u!4 &301943980 Transform: m_ObjectHideFlags: 0 diff --git a/Assets/Scenes/Boids/Materials/White.mat b/Assets/Scenes/Boids/Materials/White.mat index 2259a75..26f6b30 100644 --- a/Assets/Scenes/Boids/Materials/White.mat +++ b/Assets/Scenes/Boids/Materials/White.mat @@ -21,17 +21,17 @@ Material: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_Name: White - m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} m_Parent: {fileID: 0} m_ModifiedSerializedProperties: 0 - m_ValidKeywords: [] + m_ValidKeywords: + - _GLOSSYREFLECTIONS_OFF m_InvalidKeywords: [] m_LightmapFlags: 4 m_EnableInstancingVariants: 0 m_DoubleSidedGI: 0 m_CustomRenderQueue: -1 - stringTagMap: - RenderType: Opaque + stringTagMap: {} disabledShaderPasses: - MOTIONVECTORS m_LockedProperties: @@ -115,6 +115,7 @@ Material: - _Glossiness: 0 - _GlossyReflections: 0 - _Metallic: 0 + - _Mode: 0 - _OcclusionStrength: 1 - _Parallax: 0.005 - _QueueOffset: 0 @@ -125,12 +126,13 @@ Material: - _SrcBlend: 1 - _SrcBlendAlpha: 1 - _Surface: 0 + - _UVSec: 0 - _WorkflowMode: 1 - _XRMotionVectorsPass: 1 - _ZWrite: 1 m_Colors: - - _BaseColor: {r: 1, g: 1, b: 1, a: 1} - - _Color: {r: 1, g: 1, b: 1, a: 1} + - _BaseColor: {r: 1, g: 0.9858491, b: 0.9858491, a: 1} + - _Color: {r: 0.41509432, g: 0.41509432, b: 0.41509432, a: 1} - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} m_BuildTextureStacks: [] diff --git a/Assets/Scenes/Boids/Scripts/Boid.cs b/Assets/Scenes/Boids/Scripts/Boid.cs index ec83a28..9b7e00d 100644 --- a/Assets/Scenes/Boids/Scripts/Boid.cs +++ b/Assets/Scenes/Boids/Scripts/Boid.cs @@ -59,12 +59,12 @@ public class Boid : MonoBehaviour { } void Update() { - Physics.OverlapSphereNonAlloc(this.transform.position, 10, results); + Physics.OverlapSphereNonAlloc(this.transform.position, sc.perceptionDistance, results); neighbourCount = 0; cohesion.ResetWeights(); alignment.ResetWeights(); - separation.ResetWeights(); + //separation.ResetWeights(); foreach (Collider c in results) { if (c == null) @@ -79,18 +79,16 @@ public class Boid : MonoBehaviour { Vector3 relativeVelocity = neighbour.velocity - this.velocity; int id = neighbour.GetInstanceID(); - Receptor receptor = GetReceptor(id); - if (receptor != null) { - receptor.SetValue(localPosition); - } + ProcessStimulus(id, localPosition); + Vector3 separationForce = -localPosition / localPosition.sqrMagnitude; // which is equivalent to -(localPosition.normalized / localPosition.magnitude) separation.SetInput(id, separationForce, sc.separationDistance); //cohesion.SetInput(id, localPosition, sc.cohesionForce); alignment.SetInput(id, relativeVelocity, sc.alignmentForce); - neighbourCount++; + } } @@ -126,24 +124,81 @@ public class Boid : MonoBehaviour { Quaternion targetRotation = Quaternion.LookRotation(this.velocity); transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 2f); // Adjust the speed of rotation } + + //Debug.Log($"neighbours: {neighbourCount} synapses: {cohesion.synapses.Count}"); + neuroidNet.Update(); } - Receptor GetReceptor(int id) { + Receptor GetReceptor(Neuroid perceptionNeuroid, int id) { int availableIx = -1; for (int i = 0; i < neighbourSensor.Length; i++) { - if (neighbourSensor[i] == null) + if (neighbourSensor[i] == null || neighbourSensor[i].IsStale()) availableIx = i; - else if (neighbourSensor[i].id == id) + else if (neighbourSensor[i].thingId == id) return neighbourSensor[i].receptor; } if (availableIx != -1) { - Debug.Log($"new receptor for {id}"); - SensoryNeuroid neuroid = new(neuroidNet, id); - cohesion.GetInputFrom(neuroid); - neighbourSensor[availableIx] = neuroid; - return neuroid.receptor; + if (neighbourSensor[availableIx] != null) { + Debug.Log($"revived receptor {availableIx} for {id}"); + neighbourSensor[availableIx].thingId = id; + return neighbourSensor[availableIx].receptor; + } + else { + Debug.Log($"new receptor for {id}"); + SensoryNeuroid neuroid = new(neuroidNet, id); + perceptionNeuroid.GetInputFrom(neuroid); + neighbourSensor[availableIx] = neuroid; + return neuroid.receptor; + } } + + //Debug.LogWarning($"No available receptor for {id}"); return null; } + + + void ProcessStimulus(int thingId, Vector3 value) { + int availableIx = -1; + SensoryNeuroid leastInterestingNeuroid = null; + for (int i = 0; i < neighbourSensor.Length; i++) { + if (neighbourSensor[i] == null || neighbourSensor[i].IsStale()) + availableIx = i; + else if (neighbourSensor[i].thingId == thingId) { + neighbourSensor[i].receptor.SetValue(value); + return; + } + // if (leastInterestingIx == -1 || neighbourSensor[leastInterestingIx].receptor.GetValue().magnitude > neighbourSensor[i].receptor.GetValue().magnitude) + // leastInterestingIx = i; + if (neighbourSensor[i] != null) { + if (leastInterestingNeuroid == null || leastInterestingNeuroid.receptor.GetValue().magnitude > neighbourSensor[i].receptor.GetValue().magnitude) + leastInterestingNeuroid = neighbourSensor[i]; + } + } + if (availableIx != -1) { + if (neighbourSensor[availableIx] != null) { + // Debug.Log($"revived receptor {availableIx} for {thingId}"); + neighbourSensor[availableIx].thingId = thingId; + neighbourSensor[availableIx].receptor.SetValue(value); + } + else { + // Debug.Log($"new receptor for {thingId}"); + SensoryNeuroid neuroid = new(neuroidNet, thingId); + cohesion.GetInputFrom(neuroid); + neighbourSensor[availableIx] = neuroid; + neuroid.receptor.SetValue(value); + } + } + else if (leastInterestingNeuroid != null) { + //Debug.Log($"replaced receptor {leastInterestingNeuroid.thingId} for {thingId}"); + leastInterestingNeuroid.thingId = thingId; + leastInterestingNeuroid.receptor.SetValue(value); + } + + //Debug.LogWarning($"No available receptor for {id}"); + } + + void OnDrawGizmosSelected() { + Gizmos.DrawWireSphere(transform.position, sc.perceptionDistance); + } } diff --git a/Assets/Scenes/Boids/Scripts/SwarmControl.cs b/Assets/Scenes/Boids/Scripts/SwarmControl.cs index b662606..7837162 100644 --- a/Assets/Scenes/Boids/Scripts/SwarmControl.cs +++ b/Assets/Scenes/Boids/Scripts/SwarmControl.cs @@ -11,6 +11,7 @@ public class SwarmControl : MonoBehaviour public float separationForce = 5.0f; public float separationDistance = 0.5f; public float bodyForce = 20; + public float perceptionDistance = 1.0f; public float boundaryForce = 2.0f; public Vector3 spaceSize = new (10, 10, 10); diff --git a/Assets/_Recovery.meta b/Assets/_Recovery.meta new file mode 100644 index 0000000..8077f23 --- /dev/null +++ b/Assets/_Recovery.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 895037c7e323e03ada7f43d011f1390b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Recovery/0.unity b/Assets/_Recovery/0.unity new file mode 100644 index 0000000..d2192f7 --- /dev/null +++ b/Assets/_Recovery/0.unity @@ -0,0 +1,1123 @@ +%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: 10 + 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: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 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_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 13 + m_BakeOnSceneLoad: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + 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_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: 1 + m_PVRFilteringGaussRadiusAO: 1 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 20201, guid: 0000000000000000f000000000000000, type: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 3 + 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 + buildHeightMesh: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &231291185 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 231291186} + - component: {fileID: 231291189} + - component: {fileID: 231291188} + - component: {fileID: 231291187} + m_Layer: 0 + m_Name: Wall (1) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &231291186 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 231291185} + serializedVersion: 2 + m_LocalRotation: {x: 0.5, y: 0.5, z: -0.5, w: 0.5} + m_LocalPosition: {x: -5, y: 5, z: 0} + m_LocalScale: {x: 10, y: 1, z: 10} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1826482027} + m_LocalEulerAnglesHint: {x: 90, y: 90, z: 0} +--- !u!65 &231291187 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 231291185} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &231291188 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 231291185} + m_Enabled: 0 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RayTracingAccelStructBuildFlagsOverride: 0 + m_RayTracingAccelStructBuildFlags: 1 + m_SmallMeshCulling: 1 + m_ForceMeshLod: -1 + m_MeshLodSelectionBias: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_GlobalIlluminationMeshLod: 0 + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &231291189 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 231291185} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &246180153 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 246180154} + - component: {fileID: 246180157} + - component: {fileID: 246180156} + - component: {fileID: 246180155} + m_Layer: 0 + m_Name: Wall (2) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &246180154 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 246180153} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0.7071068, z: -0.7071068, w: 0} + m_LocalPosition: {x: 0, y: 5, z: 5} + m_LocalScale: {x: 10, y: 1, z: 10} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1826482027} + m_LocalEulerAnglesHint: {x: 90, y: 180, z: 0} +--- !u!65 &246180155 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 246180153} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &246180156 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 246180153} + m_Enabled: 0 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RayTracingAccelStructBuildFlagsOverride: 0 + m_RayTracingAccelStructBuildFlags: 1 + m_SmallMeshCulling: 1 + m_ForceMeshLod: -1 + m_MeshLodSelectionBias: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_GlobalIlluminationMeshLod: 0 + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &246180157 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 246180153} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &301943977 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 301943980} + - component: {fileID: 301943979} + - component: {fileID: 301943978} + m_Layer: 0 + m_Name: Swarm + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &301943978 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 301943977} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0464906885ae3494f8fd0314719fb2db, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::SwarmControl + speed: 0.5 + inertia: 0.1 + alignmentForce: 1 + cohesionForce: 10 + separationForce: 5 + separationDistance: 0.5 + bodyForce: 20 + boundaryForce: 5 + spaceSize: {x: 10, y: 10, z: 10} + boundaryWidth: {x: 1, y: 1, z: 1} +--- !u!114 &301943979 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 301943977} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ec888ca5333d45a438f9f417fa5ce135, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::SwarmSpawn + count: 10 + boidPrefab: {fileID: 8702527964058765413, guid: f9c706268554ce449a8773675b2864b8, type: 3} + spawnAreaSize: {x: 0.5, y: 0.5, z: 0.5} + minDelay: 0.1 + maxDelay: 1 +--- !u!4 &301943980 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 301943977} + serializedVersion: 2 + 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_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &704151342 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 704151343} + - component: {fileID: 704151346} + - component: {fileID: 704151345} + - component: {fileID: 704151344} + m_Layer: 0 + m_Name: Ceiling + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &704151343 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 704151342} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 10, z: 0} + m_LocalScale: {x: 10, y: 1, z: 10} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1826482027} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!65 &704151344 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 704151342} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &704151345 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 704151342} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RayTracingAccelStructBuildFlagsOverride: 0 + m_RayTracingAccelStructBuildFlags: 1 + m_SmallMeshCulling: 1 + m_ForceMeshLod: -1 + m_MeshLodSelectionBias: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_GlobalIlluminationMeshLod: 0 + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &704151346 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 704151342} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &837238090 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 837238092} + - component: {fileID: 837238091} + - component: {fileID: 837238093} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &837238091 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 837238090} + m_Enabled: 1 + serializedVersion: 11 + m_Type: 1 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ForceVisible: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 + m_LightUnit: 1 + m_LuxAtDistance: 1 + m_EnableSpotReflector: 1 +--- !u!4 &837238092 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 837238090} + serializedVersion: 2 + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!114 &837238093 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 837238090} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 474bcb49853aa07438625e644c072ee6, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.UniversalAdditionalLightData + m_UsePipelineSettings: 1 + m_AdditionalLightsShadowResolutionTier: 2 + m_CustomShadowLayers: 0 + m_LightCookieSize: {x: 1, y: 1} + m_LightCookieOffset: {x: 0, y: 0} + m_SoftShadowQuality: 0 + m_RenderingLayersMask: + serializedVersion: 0 + m_Bits: 1 + m_ShadowRenderingLayersMask: + serializedVersion: 0 + m_Bits: 1 + m_Version: 4 + m_LightLayerMask: 1 + m_ShadowLayerMask: 1 + m_RenderingLayers: 1 + m_ShadowRenderingLayers: 1 +--- !u!1 &1633626499 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1633626502} + - component: {fileID: 1633626501} + - component: {fileID: 1633626500} + 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 &1633626500 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1633626499} + m_Enabled: 1 +--- !u!20 &1633626501 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1633626499} + 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_Iso: 200 + m_ShutterSpeed: 0.005 + m_Aperture: 16 + m_FocusDistance: 10 + m_FocalLength: 50 + m_BladeCount: 5 + m_Curvature: {x: 2, y: 11} + m_BarrelClipping: 0.25 + m_Anamorphism: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + 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: 0 + 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 &1633626502 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1633626499} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1690670936 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1690670937} + - component: {fileID: 1690670940} + - component: {fileID: 1690670939} + - component: {fileID: 1690670938} + m_Layer: 0 + m_Name: Floor + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1690670937 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1690670936} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 10, y: 1, z: 10} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1826482027} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!65 &1690670938 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1690670936} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &1690670939 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1690670936} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RayTracingAccelStructBuildFlagsOverride: 0 + m_RayTracingAccelStructBuildFlags: 1 + m_SmallMeshCulling: 1 + m_ForceMeshLod: -1 + m_MeshLodSelectionBias: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_GlobalIlluminationMeshLod: 0 + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &1690670940 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1690670936} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1738679977 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1738679978} + - component: {fileID: 1738679981} + - component: {fileID: 1738679980} + - component: {fileID: 1738679979} + m_Layer: 0 + m_Name: Wall + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1738679978 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1738679977} + serializedVersion: 2 + m_LocalRotation: {x: 0.7071068, y: 0, z: 0, w: 0.7071068} + m_LocalPosition: {x: 0, y: 5, z: -5} + m_LocalScale: {x: 10, y: 1, z: 10} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1826482027} + m_LocalEulerAnglesHint: {x: 90, y: 0, z: 0} +--- !u!65 &1738679979 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1738679977} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &1738679980 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1738679977} + m_Enabled: 0 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RayTracingAccelStructBuildFlagsOverride: 0 + m_RayTracingAccelStructBuildFlags: 1 + m_SmallMeshCulling: 1 + m_ForceMeshLod: -1 + m_MeshLodSelectionBias: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_GlobalIlluminationMeshLod: 0 + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &1738679981 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1738679977} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1826482026 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1826482027} + m_Layer: 0 + m_Name: Boundary + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1826482027 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1826482026} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -0, y: -5, z: -0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1690670937} + - {fileID: 1738679978} + - {fileID: 231291186} + - {fileID: 246180154} + - {fileID: 1924016461} + - {fileID: 704151343} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1924016460 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1924016461} + - component: {fileID: 1924016464} + - component: {fileID: 1924016463} + - component: {fileID: 1924016462} + m_Layer: 0 + m_Name: Wall (3) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1924016461 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1924016460} + serializedVersion: 2 + m_LocalRotation: {x: -0.5, y: 0.5, z: -0.5, w: -0.5} + m_LocalPosition: {x: 5, y: 5, z: 0} + m_LocalScale: {x: 10, y: 1, z: 10} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1826482027} + m_LocalEulerAnglesHint: {x: 90, y: 270, z: 0} +--- !u!65 &1924016462 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1924016460} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &1924016463 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1924016460} + m_Enabled: 0 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RayTracingAccelStructBuildFlagsOverride: 0 + m_RayTracingAccelStructBuildFlags: 1 + m_SmallMeshCulling: 1 + m_ForceMeshLod: -1 + m_MeshLodSelectionBias: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_GlobalIlluminationMeshLod: 0 + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &1924016464 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1924016460} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1660057539 &9223372036854775807 +SceneRoots: + m_ObjectHideFlags: 0 + m_Roots: + - {fileID: 1633626502} + - {fileID: 837238092} + - {fileID: 301943980} + - {fileID: 1826482027} diff --git a/Assets/_Recovery/0.unity.meta b/Assets/_Recovery/0.unity.meta new file mode 100644 index 0000000..8162e27 --- /dev/null +++ b/Assets/_Recovery/0.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e5398245724c5668992c64c27db35040 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/NanoBrain-Unity.code-workspace b/NanoBrain-Unity.code-workspace new file mode 100644 index 0000000..2ec905e --- /dev/null +++ b/NanoBrain-Unity.code-workspace @@ -0,0 +1,19 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": { + "files.associations": { + "*.asset": "yaml", + "*.meta": "yaml", + "*.prefab": "yaml", + "*.unity": "yaml" + }, + "dotnet.defaultSolution": "NanoBrain-Unity.sln", + "dotnet.server.useOmnisharp": true, + "omnisharp.useModernNet": false, + "dotnet.automaticallyCreateSolutionInWorkspace": false + } +} \ No newline at end of file diff --git a/mono_crash.mem.19211.1.blob b/mono_crash.mem.19211.1.blob new file mode 100644 index 0000000000000000000000000000000000000000..b4452d03786c823d7f5bf4b096959cbe169e45b1 GIT binary patch literal 10000001 zcmeFtfdBvi0Dz$VsTV1P3IhfV7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjm>oJ0000000P=rrgaii; z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=0qxKM2><{9fS~`c+Y#sl4Hz(Bz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM a7%*VKfB^#r3>YwAz<>b*1`HT5up0=UX#fEL literal 0 HcmV?d00001 From 7ce787f5dbc2c1939d5f700683d1733f4e47ee22 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 27 Nov 2025 17:35:51 +0100 Subject: [PATCH 007/179] Refactoring --- .editorconfig | 3 + Assembly-CSharp.csproj | 1 + Assets/NanoBrain/Editor/NeuroidWindow.cs | 13 ++-- Assets/NanoBrain/Neuroid.cs | 89 +++++++++++++++--------- Assets/NanoBrain/Perception.cs | 83 ++++++++++++++++++++++ Assets/NanoBrain/Perception.cs.meta | 2 + Assets/NanoBrain/SensoryNeuroid.cs | 82 ++++++++++++++++------ Assets/Scenes/Boids/Boids.unity | 4 +- Assets/Scenes/Boids/Scripts/Boid.cs | 26 +++---- 9 files changed, 229 insertions(+), 74 deletions(-) create mode 100644 Assets/NanoBrain/Perception.cs create mode 100644 Assets/NanoBrain/Perception.cs.meta diff --git a/.editorconfig b/.editorconfig index def86c3..64e4e80 100644 --- a/.editorconfig +++ b/.editorconfig @@ -18,3 +18,6 @@ csharp_new_line_between_query_expression_clauses = true # Limit the number of characters in a line max_line_length = 100 # This setting does not enforce it; it's a guideline. + +[*.{cs,vb}] +dotnet_diagnostic.IDE1006.severity = none \ No newline at end of file diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index a3f3720..97530fd 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -52,6 +52,7 @@ + diff --git a/Assets/NanoBrain/Editor/NeuroidWindow.cs b/Assets/NanoBrain/Editor/NeuroidWindow.cs index 0548e29..3560973 100644 --- a/Assets/NanoBrain/Editor/NeuroidWindow.cs +++ b/Assets/NanoBrain/Editor/NeuroidWindow.cs @@ -43,8 +43,9 @@ public class GraphEditorWindow : EditorWindow { } // If this neuroid is not visited while its output neuroid is visited - if (!neuronVisited.Contains(neuroid) && (neuroid.outputNeuroid == null || - (neuronVisited.Contains(neuroid.outputNeuroid) && neuroid.outputNeuroid.layerIx == layerIx - 1))) { + // Note: this does not yet work for multiple outputs yet (see the use of First()) + if (!neuronVisited.Contains(neuroid) && (neuroid.outputNeuroids.Count == 0 || + (neuronVisited.Contains(neuroid.outputNeuroids.First()) && neuroid.outputNeuroids.First().layerIx == layerIx - 1))) { // Add it to the next layer currentLayer.neuroids.Add(neuroid); neuroid.layerIx = layerIx; @@ -54,7 +55,7 @@ public class GraphEditorWindow : EditorWindow { Vector2Int neuroidPosition = new(layerIx, neuroidIx); neuroidPositions[neuroid] = neuroidPosition; neuroidIx++; - Debug.Log($"Layer {layerIx} neuron {neuroidIx} id {neuroid.id} {neuroid.name}"); + Debug.Log($"Layer {layerIx} neuron {neuroidIx} name {neuroid.name}"); } } @@ -110,9 +111,9 @@ public class GraphEditorWindow : EditorWindow { Vector3 parentPos = new(100 + layerNeuroidPos.x * 100, margin + layerNeuroidPos.y * spacing, 0.1f); int i = 0; - float inputSpacing = 200f / layerNeuroid.synapses.Count; + float inputSpacing = 200f / layerNeuroid.newSynapses.Count; float inputMargin = 100 + inputSpacing / 2; - foreach (Synapse synapse in layerNeuroid.synapses.Values) { + foreach (Synapse synapse in layerNeuroid.newSynapses.Values) { if (synapse.neuroid != null) { if (this.neuroidPositions.ContainsKey(synapse.neuroid)) { @@ -144,7 +145,7 @@ public class GraphEditorWindow : EditorWindow { // Draw the tooltip GUIContent tooltip = new( $"{neuroid.name}" + - $"\nsynapse count {neuroid.synapses.Count}" + + $"\nsynapse count {neuroid.newSynapses.Count}" + $"\nValue: {neuroid.outputValue}" + $"\nStale: {neuroid.stale}"); diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index a098aaa..a5d69d3 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -29,17 +29,16 @@ public class NeuroidNetwork { } public class Neuroid { - public int id; + //public int id; public string name; public int layerIx; public int stale = 0; - public readonly Dictionary synapses = new(); + public readonly Dictionary newSynapses = new(); public Vector3 outputValue; - public Neuroid outputNeuroid; - public int outputNeurix; + public HashSet outputNeuroids = new(); public enum Mode { Sum, @@ -52,69 +51,95 @@ public class Neuroid { public Neuroid(NeuroidNetwork net) { this.net = net; - this.net.neuroids.Add(this); + if (this.net != null) + this.net.neuroids.Add(this); } - public void SetOutputTo(Neuroid neuroid) { - this.outputNeuroid = neuroid; - // neuroid.inputNeuroids.Add(this); - this.outputNeurix = this.id; + public void AddSynapse(Neuroid input) { + input.AddReceiver(this); + this.newSynapses[input] = new(input, Vector3.zero, 1.0f); + } + + public void AddReceiver(Neuroid receiver) { + this.outputNeuroids.Add(receiver); } public void ResetWeights() { - foreach (Synapse synapse in synapses.Values) + foreach (Synapse synapse in this.newSynapses.Values) synapse.weight = 1.0f; } public void SetWeight(Neuroid input, float weight) { - if (synapses.ContainsKey(input.id)) - synapses[input.id] = new(input, synapses[input.id].value, weight); - else - synapses[input.id] = new(input, Vector3.zero, weight); + if (this.newSynapses.ContainsKey(input)) { + this.newSynapses[input].weight = weight; + } + else { + this.newSynapses[input] = new(input, Vector3.zero, weight); + } } public void GetInputFrom(Neuroid input, float weight = 1.0f) { - input.id = this.synapses.Count; - input.SetOutputTo(this); - synapses[input.id] = new(input, Vector3.zero, weight); + input.AddReceiver(this); + this.newSynapses[input] = new(input, Vector3.zero, weight); } - public void SetInput(int inputId, Vector3 value) { - if (synapses.ContainsKey(inputId)) - synapses[inputId].value = value; + public void SetInput(Neuroid input, Vector3 value) { + if (this.newSynapses.ContainsKey(input)) { + Synapse synapse = this.newSynapses[input]; + synapse.value = value; + } else - synapses[inputId] = new(null, value, 1.0f); + this.newSynapses[input] = new(null, value, 1.0f); UpdateState(); } - public void SetInput(int inputIx, Vector3 value, float weight) { - if (synapses.ContainsKey(inputIx)) { - Synapse synapse = synapses[inputIx]; + + public void SetInput(Neuroid input, Vector3 value, float weight) { + if (this.newSynapses.ContainsKey(input)) { + Synapse synapse = this.newSynapses[input]; synapse.value = value; synapse.weight = weight; } else - synapses[inputIx] = new(null, value, weight); + this.newSynapses[input] = new(null, value, weight); UpdateState(); } - void UpdateState() { + public readonly Dictionary fakeNeuroids = new(); + public void SetInput(int thingId, Vector3 value, float weight, NeuroidNetwork net) { + if (fakeNeuroids.ContainsKey(thingId)) { + Neuroid fakeInput = fakeNeuroids[thingId]; + Synapse synapse = this.newSynapses[fakeInput]; + synapse.value = value; + synapse.weight = weight; + } + else { + fakeNeuroids[thingId] = new(net); + this.newSynapses[fakeNeuroids[thingId]] = new (null, value, weight); + } + UpdateState(); + } + + + protected virtual void UpdateState() { Vector3 sum = Vector3.zero; - foreach (Synapse synapse in synapses.Values) + foreach (Synapse synapse in this.newSynapses.Values) sum += synapse.value * synapse.weight; this.outputValue = Activation(sum); - this.outputNeuroid?.SetInput(this.outputNeurix, this.outputValue); + foreach (Neuroid neuroid in outputNeuroids) { + neuroid?.SetInput(this, this.outputValue); + } this.stale = 0; } Vector3 Activation(Vector3 sum) { - if (synapses.Count == 0 && mode == Mode.Average) - Debug.LogWarning($"{this.id} {this.name} has zero synapses for average"); + if (this.newSynapses.Count == 0 && mode == Mode.Average) + Debug.LogWarning($"{this.name} has zero synapses for average"); if (float.IsNaN(sum.magnitude)) - Debug.LogWarning($"{this.id} {this.name} sum is nan"); + Debug.LogWarning($"{this.name} sum is nan"); return mode switch { Mode.Sum => sum, - Mode.Average => sum / synapses.Count, + Mode.Average => sum / this.newSynapses.Count, _ => sum, }; //return sum; //(sum.magnitude > 0.5f) ? sum : Vector3.zero; diff --git a/Assets/NanoBrain/Perception.cs b/Assets/NanoBrain/Perception.cs new file mode 100644 index 0000000..bb822fe --- /dev/null +++ b/Assets/NanoBrain/Perception.cs @@ -0,0 +1,83 @@ +using System.Collections.Generic; +using UnityEngine; + +public class Perception { + public SensoryNeuroid[] sensoryNeuroids = new SensoryNeuroid[7]; + //public Neuroid[] velocitySensors = new Neuroid[7]; + public NeuroidNetwork neuroidNet { get; protected set; } + + public HashSet receivers { get; protected set; } + + public Perception(NeuroidNetwork neuroidNet) { + this.neuroidNet = neuroidNet; + this.receivers = new(); + } + + // public void SendOutputTo(Neuroid receiver) { + // foreach (SensoryNeuroid neuroid in sensoryNeuroids) { + // if (neuroid != null) { + // neuroid.AddReceiver(receiver); + // receiver.newSynapses[neuroid] = new (neuroid, Vector3.zero, 1.0f); + // } + // } + // } + + public void SendPositions(Neuroid receiver) { + receivers.Add(receiver); + foreach (SensoryNeuroid neuroid in sensoryNeuroids) { + if (neuroid != null) { + neuroid.AddReceiver(receiver); + receiver.newSynapses[neuroid] = new (neuroid, Vector3.zero, 1.0f); + } + } + } + public void SendVelocities(Neuroid receiver) { + receivers.Add(receiver); + foreach (SensoryNeuroid neuroid in sensoryNeuroids) { + if (neuroid != null && neuroid.velocityNeuroid != null) { + neuroid.velocityNeuroid.AddReceiver(receiver); + receiver.newSynapses[neuroid] = new (neuroid, Vector3.zero, 1.0f); + } + } + } + + public void ProcessStimulus(int thingId, Vector3 localPosition) { + int availableIx = -1; + SensoryNeuroid leastInterestingNeuroid = null; + for (int i = 0; i < sensoryNeuroids.Length; i++) { + if (sensoryNeuroids[i] == null || sensoryNeuroids[i].IsStale()) + availableIx = i; + else if (sensoryNeuroids[i].receptor.thingId == thingId) { + sensoryNeuroids[i].receptor.position = localPosition; + return; + } + if (sensoryNeuroids[i] != null) { + if (leastInterestingNeuroid == null || leastInterestingNeuroid.receptor.position.magnitude > sensoryNeuroids[i].receptor.position.magnitude) + leastInterestingNeuroid = sensoryNeuroids[i]; + } + } + if (availableIx != -1) { + if (sensoryNeuroids[availableIx] != null) { + // Debug.Log($"revived receptor {availableIx} for {thingId}"); + sensoryNeuroids[availableIx].receptor.thingId = thingId; + sensoryNeuroids[availableIx].receptor.position = localPosition; + } + else { + // Debug.Log($"new receptor for {thingId}"); + SensoryNeuroid neuroid = new(neuroidNet, thingId); + foreach (Neuroid receiver in receivers) + receiver.GetInputFrom(neuroid); + + sensoryNeuroids[availableIx] = neuroid; + neuroid.receptor.position = localPosition; + } + } + else if (leastInterestingNeuroid != null) { + //Debug.Log($"replaced receptor {leastInterestingNeuroid.thingId} for {thingId}"); + leastInterestingNeuroid.receptor.thingId = thingId; + leastInterestingNeuroid.receptor.position = localPosition; + } + + //Debug.LogWarning($"No available receptor for {id}"); + } +} \ No newline at end of file diff --git a/Assets/NanoBrain/Perception.cs.meta b/Assets/NanoBrain/Perception.cs.meta new file mode 100644 index 0000000..adfa3db --- /dev/null +++ b/Assets/NanoBrain/Perception.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 37d94d399d30e6eb996236adabad87ee \ No newline at end of file diff --git a/Assets/NanoBrain/SensoryNeuroid.cs b/Assets/NanoBrain/SensoryNeuroid.cs index 7651d30..cf6bc38 100644 --- a/Assets/NanoBrain/SensoryNeuroid.cs +++ b/Assets/NanoBrain/SensoryNeuroid.cs @@ -1,32 +1,70 @@ +using System.Linq; using UnityEngine; -public class Receptor { - public SensoryNeuroid neuroid; - public void SetValue(Vector3 value) { - if (neuroid != null) { - neuroid.SetInput(neuroid.id, value); - } +public class SensoryNeuroid : Neuroid { + // A neuroid which has no neurons as input + // But receives value from a receptor + public Receptor receptor; + public VelocityNeuroid velocityNeuroid; + + public SensoryNeuroid(NeuroidNetwork net, int thingId) : base(net) { + this.name = "sensory neuroid"; + this.receptor = new Receptor { + neuroid = this, + thingId = thingId + }; + this.velocityNeuroid = new(net); + // The velocity neuroid received position data from this + this.AddReceiver(velocityNeuroid); } - public Vector3 GetValue() { - if (neuroid != null) - return neuroid.synapses[neuroid.id].value; - else - return Vector3.zero; + +} + +public class Receptor { + + public SensoryNeuroid neuroid; + + public int thingId; + /// + /// Local position of the thing + /// + public virtual Vector3 position { + get { + if (neuroid != null) + return neuroid.newSynapses[neuroid].value; + else + return Vector3.zero; + } + set { + if (neuroid != null) + neuroid.SetInput(neuroid, value); + } } } +public class VelocityNeuroid : Neuroid { + // Would be best if this was received through a synapse via a loop.... + private Vector3 lastPosition = Vector3.zero; + private float lastValueTime = 0; -public class SensoryNeuroid : Neuroid { - public Receptor receptor; - public int thingId; - - public SensoryNeuroid(NeuroidNetwork net, int id) : base(net) { - this.name = "sensory neuroid"; - // this.id = id; - this.thingId = id; - this.receptor = new Receptor { - neuroid = this - }; + public VelocityNeuroid(NeuroidNetwork net) : base(net) { } + protected override void UpdateState() { + // Assuming only one synapse for now.... + Vector3 currentPosition = this.newSynapses.First().Value.value; + float currentValueTime = Time.time; + + float deltaTime = currentValueTime - lastValueTime; + Vector3 translation = currentPosition - lastPosition; + Vector3 velocity = translation / deltaTime; + + // No activation function... + this.outputValue = velocity; + foreach (Neuroid receiver in outputNeuroids) + receiver?.SetInput(this, this.outputValue); + this.stale = 0; + + this.lastValueTime = Time.time; + } } \ No newline at end of file diff --git a/Assets/Scenes/Boids/Boids.unity b/Assets/Scenes/Boids/Boids.unity index 5b7c526..970b54d 100644 --- a/Assets/Scenes/Boids/Boids.unity +++ b/Assets/Scenes/Boids/Boids.unity @@ -378,7 +378,7 @@ MonoBehaviour: separationForce: 5 separationDistance: 0.3 bodyForce: 20 - perceptionDistance: 2 + perceptionDistance: 1 boundaryForce: 5 spaceSize: {x: 10, y: 10, z: 10} boundaryWidth: {x: 1, y: 1, z: 1} @@ -394,7 +394,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec888ca5333d45a438f9f417fa5ce135, type: 3} m_Name: m_EditorClassIdentifier: Assembly-CSharp::SwarmSpawn - count: 1000 + count: 5 boidPrefab: {fileID: 8702527964058765413, guid: f9c706268554ce449a8773675b2864b8, type: 3} spawnAreaSize: {x: 0.5, y: 0.5, z: 0.5} minDelay: 0.05 diff --git a/Assets/Scenes/Boids/Scripts/Boid.cs b/Assets/Scenes/Boids/Scripts/Boid.cs index 9b7e00d..d0cd02e 100644 --- a/Assets/Scenes/Boids/Scripts/Boid.cs +++ b/Assets/Scenes/Boids/Scripts/Boid.cs @@ -19,7 +19,8 @@ public class Boid : MonoBehaviour { readonly Collider[] results = new Collider[10]; - public SensoryNeuroid[] neighbourSensor = new SensoryNeuroid[6]; + //public SensoryNeuroid[] neighbourSensor = new SensoryNeuroid[6]; + public Perception perception; public NeuroidNetwork neuroidNet = new(); public Neuroid bodyVector; @@ -40,11 +41,14 @@ public class Boid : MonoBehaviour { bounds = new(sc.transform.position, sc.spaceSize - 2 * sc.boundaryWidth); + perception = new Perception(neuroidNet); //neighbourSensor = new(neuroidNet) { name = "Neighbour", id = 879 }; cohesion = new(neuroidNet) { name = "Cohesion", mode = Neuroid.Mode.Sum }; + perception.SendPositions(cohesion); //cohesion.GetInputFrom(neighbourSensor); alignment = new(neuroidNet) { name = "Alignment", mode = Neuroid.Mode.Average }; + //perception.SendVelocities(alignment); separation = new(neuroidNet) { name = "Separation", mode = Neuroid.Mode.Sum }; target = new(neuroidNet) { name = "Target", mode = Neuroid.Mode.Sum }; boundary = new(neuroidNet) { name = "Boundary", mode = Neuroid.Mode.Sum }; @@ -78,15 +82,15 @@ public class Boid : MonoBehaviour { Vector3 localPosition = neighbour.transform.position - this.transform.position; Vector3 relativeVelocity = neighbour.velocity - this.velocity; - int id = neighbour.GetInstanceID(); - ProcessStimulus(id, localPosition); + int thingId = neighbour.GetInstanceID(); + perception.ProcessStimulus(thingId, localPosition); Vector3 separationForce = -localPosition / localPosition.sqrMagnitude; // which is equivalent to -(localPosition.normalized / localPosition.magnitude) - separation.SetInput(id, separationForce, sc.separationDistance); - //cohesion.SetInput(id, localPosition, sc.cohesionForce); - alignment.SetInput(id, relativeVelocity, sc.alignmentForce); + separation.SetInput(thingId, separationForce, sc.separationDistance, neuroidNet); + //cohesion.SetInput(thingId, localPosition, sc.cohesionForce); + alignment.SetInput(thingId, relativeVelocity, sc.alignmentForce, neuroidNet); neighbourCount++; } @@ -108,7 +112,7 @@ public class Boid : MonoBehaviour { Vector3 direction = (sc.transform.position - this.transform.position).normalized; outside = direction * magnitude; - boundary.SetInput(id, outside, sc.boundaryForce); + boundary.SetInput(id, outside, sc.boundaryForce, neuroidNet); // Debug.Log($"boundary {this.transform.position} {outside} force = {outside * sc.boundaryForce}"); } @@ -128,7 +132,7 @@ public class Boid : MonoBehaviour { //Debug.Log($"neighbours: {neighbourCount} synapses: {cohesion.synapses.Count}"); neuroidNet.Update(); } - +/* Receptor GetReceptor(Neuroid perceptionNeuroid, int id) { int availableIx = -1; for (int i = 0; i < neighbourSensor.Length; i++) { @@ -157,7 +161,7 @@ public class Boid : MonoBehaviour { } - +/* void ProcessStimulus(int thingId, Vector3 value) { int availableIx = -1; SensoryNeuroid leastInterestingNeuroid = null; @@ -168,8 +172,6 @@ public class Boid : MonoBehaviour { neighbourSensor[i].receptor.SetValue(value); return; } - // if (leastInterestingIx == -1 || neighbourSensor[leastInterestingIx].receptor.GetValue().magnitude > neighbourSensor[i].receptor.GetValue().magnitude) - // leastInterestingIx = i; if (neighbourSensor[i] != null) { if (leastInterestingNeuroid == null || leastInterestingNeuroid.receptor.GetValue().magnitude > neighbourSensor[i].receptor.GetValue().magnitude) leastInterestingNeuroid = neighbourSensor[i]; @@ -197,7 +199,7 @@ public class Boid : MonoBehaviour { //Debug.LogWarning($"No available receptor for {id}"); } - +*/ void OnDrawGizmosSelected() { Gizmos.DrawWireSphere(transform.position, sc.perceptionDistance); } From fdabad289509f030cd187302e27000a880d5c57a Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Fri, 28 Nov 2025 17:15:49 +0100 Subject: [PATCH 008/179] Move more towards pure neuroids --- Assets/NanoBrain/Editor/NeuroidWindow.cs | 16 ++- Assets/NanoBrain/Neuroid.cs | 107 +++++++------- Assets/NanoBrain/Perception.cs | 31 ++--- Assets/NanoBrain/SensoryNeuroid.cs | 9 +- Assets/Scenes/Boids/Boids.unity | 3 +- Assets/Scenes/Boids/Scripts/Boid.cs | 146 +++++--------------- Assets/Scenes/Boids/Scripts/SwarmControl.cs | 2 +- 7 files changed, 113 insertions(+), 201 deletions(-) diff --git a/Assets/NanoBrain/Editor/NeuroidWindow.cs b/Assets/NanoBrain/Editor/NeuroidWindow.cs index 3560973..b0510df 100644 --- a/Assets/NanoBrain/Editor/NeuroidWindow.cs +++ b/Assets/NanoBrain/Editor/NeuroidWindow.cs @@ -37,15 +37,19 @@ public class GraphEditorWindow : EditorWindow { int neuroidIx = 0; foreach (Neuroid neuroid in neuroids) { + // Skip neurons we already processed + if (neuronVisited.Contains(neuroid)) + continue; + if (neuroid.IsStale()) { neuronVisited.Add(neuroid); continue; } - // If this neuroid is not visited while its output neuroid is visited + // If the output neuroid is visited // Note: this does not yet work for multiple outputs yet (see the use of First()) - if (!neuronVisited.Contains(neuroid) && (neuroid.outputNeuroids.Count == 0 || - (neuronVisited.Contains(neuroid.outputNeuroids.First()) && neuroid.outputNeuroids.First().layerIx == layerIx - 1))) { + if (neuroid.outputNeuroids.Count == 0 // make sure the root neuroids are processed directly + || (neuronVisited.Contains(neuroid.outputNeuroids.First()) && neuroid.outputNeuroids.First().layerIx == layerIx - 1)) { // Add it to the next layer currentLayer.neuroids.Add(neuroid); neuroid.layerIx = layerIx; @@ -111,9 +115,9 @@ public class GraphEditorWindow : EditorWindow { Vector3 parentPos = new(100 + layerNeuroidPos.x * 100, margin + layerNeuroidPos.y * spacing, 0.1f); int i = 0; - float inputSpacing = 200f / layerNeuroid.newSynapses.Count; + float inputSpacing = 200f / layerNeuroid.synapses.Count; float inputMargin = 100 + inputSpacing / 2; - foreach (Synapse synapse in layerNeuroid.newSynapses.Values) { + foreach (Synapse synapse in layerNeuroid.synapses.Values) { if (synapse.neuroid != null) { if (this.neuroidPositions.ContainsKey(synapse.neuroid)) { @@ -145,7 +149,7 @@ public class GraphEditorWindow : EditorWindow { // Draw the tooltip GUIContent tooltip = new( $"{neuroid.name}" + - $"\nsynapse count {neuroid.newSynapses.Count}" + + $"\nsynapse count {neuroid.synapses.Count}" + $"\nValue: {neuroid.outputValue}" + $"\nStale: {neuroid.stale}"); diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index a5d69d3..09c5606 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -16,8 +16,8 @@ public class Synapse { public class NeuroidNetwork { public List neuroids = new(); - public Neuroid AddNeuron() { - Neuroid neuroid = new(this); + public Neuroid AddNeuron(string name) { + Neuroid neuroid = new(this, name); return neuroid; } @@ -29,35 +29,33 @@ public class NeuroidNetwork { } public class Neuroid { - //public int id; public string name; public int layerIx; public int stale = 0; - public readonly Dictionary newSynapses = new(); + public readonly Dictionary synapses = new(); public Vector3 outputValue; public HashSet outputNeuroids = new(); - public enum Mode { - Sum, - Average, - } - public Mode mode = Mode.Sum; - + public bool average = false; + //public bool quadratic = false; + public bool inverse = false; + public float exponent = 1.0f; public NeuroidNetwork net; - public Neuroid(NeuroidNetwork net) { + public Neuroid(NeuroidNetwork net, string name) { this.net = net; + this.name = name; if (this.net != null) this.net.neuroids.Add(this); } public void AddSynapse(Neuroid input) { input.AddReceiver(this); - this.newSynapses[input] = new(input, Vector3.zero, 1.0f); + this.synapses[input] = new(input, Vector3.zero, 1.0f); } public void AddReceiver(Neuroid receiver) { @@ -65,84 +63,77 @@ public class Neuroid { } public void ResetWeights() { - foreach (Synapse synapse in this.newSynapses.Values) + foreach (Synapse synapse in this.synapses.Values) synapse.weight = 1.0f; } public void SetWeight(Neuroid input, float weight) { - if (this.newSynapses.ContainsKey(input)) { - this.newSynapses[input].weight = weight; + if (this.synapses.ContainsKey(input)) { + this.synapses[input].weight = weight; } else { - this.newSynapses[input] = new(input, Vector3.zero, weight); + this.synapses[input] = new(input, Vector3.zero, weight); } } public void GetInputFrom(Neuroid input, float weight = 1.0f) { input.AddReceiver(this); - this.newSynapses[input] = new(input, Vector3.zero, weight); + this.synapses[input] = new(input, Vector3.zero, weight); } public void SetInput(Neuroid input, Vector3 value) { - if (this.newSynapses.ContainsKey(input)) { - Synapse synapse = this.newSynapses[input]; + if (this.synapses.ContainsKey(input)) { + Synapse synapse = this.synapses[input]; synapse.value = value; } else - this.newSynapses[input] = new(null, value, 1.0f); + this.synapses[input] = new(null, value, 1.0f); UpdateState(); } public void SetInput(Neuroid input, Vector3 value, float weight) { - if (this.newSynapses.ContainsKey(input)) { - Synapse synapse = this.newSynapses[input]; + if (this.synapses.ContainsKey(input)) { + Synapse synapse = this.synapses[input]; synapse.value = value; synapse.weight = weight; } else - this.newSynapses[input] = new(null, value, weight); - UpdateState(); - } - - public readonly Dictionary fakeNeuroids = new(); - public void SetInput(int thingId, Vector3 value, float weight, NeuroidNetwork net) { - if (fakeNeuroids.ContainsKey(thingId)) { - Neuroid fakeInput = fakeNeuroids[thingId]; - Synapse synapse = this.newSynapses[fakeInput]; - synapse.value = value; - synapse.weight = weight; - } - else { - fakeNeuroids[thingId] = new(net); - this.newSynapses[fakeNeuroids[thingId]] = new (null, value, weight); - } + this.synapses[input] = new(null, value, weight); UpdateState(); } + // public readonly Dictionary fakeNeuroids = new(); + // public void SetInput(int thingId, Vector3 value, float weight, NeuroidNetwork net) { + // if (fakeNeuroids.ContainsKey(thingId)) { + // Neuroid fakeInput = fakeNeuroids[thingId]; + // Synapse synapse = this.synapses[fakeInput]; + // synapse.value = value; + // synapse.weight = weight; + // } + // else { + // fakeNeuroids[thingId] = new(net); + // this.synapses[fakeNeuroids[thingId]] = new(null, value, weight); + // } + // UpdateState(); + // } protected virtual void UpdateState() { - Vector3 sum = Vector3.zero; - foreach (Synapse synapse in this.newSynapses.Values) - sum += synapse.value * synapse.weight; - - this.outputValue = Activation(sum); - foreach (Neuroid neuroid in outputNeuroids) { - neuroid?.SetInput(this, this.outputValue); + Vector3 result = Vector3.zero; + foreach (Synapse synapse in this.synapses.Values) { + Vector3 direction = synapse.value.normalized; + float magnitude = synapse.value.magnitude; + magnitude = synapse.weight * Mathf.Pow(magnitude, exponent); + if (inverse) + magnitude = 1 / magnitude; + result += direction * magnitude; } - this.stale = 0; - } + if (average && this.synapses.Count > 0) + result /= this.synapses.Count; - Vector3 Activation(Vector3 sum) { - if (this.newSynapses.Count == 0 && mode == Mode.Average) - Debug.LogWarning($"{this.name} has zero synapses for average"); - if (float.IsNaN(sum.magnitude)) - Debug.LogWarning($"{this.name} sum is nan"); - return mode switch { - Mode.Sum => sum, - Mode.Average => sum / this.newSynapses.Count, - _ => sum, - }; - //return sum; //(sum.magnitude > 0.5f) ? sum : Vector3.zero; + this.outputValue = result; + foreach (Neuroid neuroid in outputNeuroids) + neuroid.SetInput(this, this.outputValue); + this.stale = 0; } public bool IsStale() { diff --git a/Assets/NanoBrain/Perception.cs b/Assets/NanoBrain/Perception.cs index bb822fe..99729c3 100644 --- a/Assets/NanoBrain/Perception.cs +++ b/Assets/NanoBrain/Perception.cs @@ -3,40 +3,33 @@ using UnityEngine; public class Perception { public SensoryNeuroid[] sensoryNeuroids = new SensoryNeuroid[7]; - //public Neuroid[] velocitySensors = new Neuroid[7]; + public NeuroidNetwork neuroidNet { get; protected set; } - public HashSet receivers { get; protected set; } + public HashSet positionReceivers { get; protected set; } + public HashSet velocityReceivers { get; protected set; } public Perception(NeuroidNetwork neuroidNet) { this.neuroidNet = neuroidNet; - this.receivers = new(); + this.positionReceivers = new(); + this.velocityReceivers = new(); } - // public void SendOutputTo(Neuroid receiver) { - // foreach (SensoryNeuroid neuroid in sensoryNeuroids) { - // if (neuroid != null) { - // neuroid.AddReceiver(receiver); - // receiver.newSynapses[neuroid] = new (neuroid, Vector3.zero, 1.0f); - // } - // } - // } - - public void SendPositions(Neuroid receiver) { - receivers.Add(receiver); + public void SendPositions(Neuroid receiver, float weight = 1.0f) { + positionReceivers.Add(receiver); foreach (SensoryNeuroid neuroid in sensoryNeuroids) { if (neuroid != null) { neuroid.AddReceiver(receiver); - receiver.newSynapses[neuroid] = new (neuroid, Vector3.zero, 1.0f); + receiver.synapses[neuroid] = new (neuroid, Vector3.zero, weight); } } } public void SendVelocities(Neuroid receiver) { - receivers.Add(receiver); + velocityReceivers.Add(receiver); foreach (SensoryNeuroid neuroid in sensoryNeuroids) { if (neuroid != null && neuroid.velocityNeuroid != null) { neuroid.velocityNeuroid.AddReceiver(receiver); - receiver.newSynapses[neuroid] = new (neuroid, Vector3.zero, 1.0f); + receiver.synapses[neuroid] = new (neuroid, Vector3.zero, 1.0f); } } } @@ -65,8 +58,10 @@ public class Perception { else { // Debug.Log($"new receptor for {thingId}"); SensoryNeuroid neuroid = new(neuroidNet, thingId); - foreach (Neuroid receiver in receivers) + foreach (Neuroid receiver in positionReceivers) receiver.GetInputFrom(neuroid); + foreach (Neuroid receiver in velocityReceivers) + receiver.GetInputFrom(neuroid.velocityNeuroid); sensoryNeuroids[availableIx] = neuroid; neuroid.receptor.position = localPosition; diff --git a/Assets/NanoBrain/SensoryNeuroid.cs b/Assets/NanoBrain/SensoryNeuroid.cs index cf6bc38..50558ec 100644 --- a/Assets/NanoBrain/SensoryNeuroid.cs +++ b/Assets/NanoBrain/SensoryNeuroid.cs @@ -7,8 +7,7 @@ public class SensoryNeuroid : Neuroid { public Receptor receptor; public VelocityNeuroid velocityNeuroid; - public SensoryNeuroid(NeuroidNetwork net, int thingId) : base(net) { - this.name = "sensory neuroid"; + public SensoryNeuroid(NeuroidNetwork net, int thingId) : base(net, "sensory neuroid") { this.receptor = new Receptor { neuroid = this, thingId = thingId @@ -31,7 +30,7 @@ public class Receptor { public virtual Vector3 position { get { if (neuroid != null) - return neuroid.newSynapses[neuroid].value; + return neuroid.synapses[neuroid].value; else return Vector3.zero; } @@ -47,12 +46,12 @@ public class VelocityNeuroid : Neuroid { private Vector3 lastPosition = Vector3.zero; private float lastValueTime = 0; - public VelocityNeuroid(NeuroidNetwork net) : base(net) { + public VelocityNeuroid(NeuroidNetwork net) : base(net, "Velocity") { } protected override void UpdateState() { // Assuming only one synapse for now.... - Vector3 currentPosition = this.newSynapses.First().Value.value; + Vector3 currentPosition = this.synapses.First().Value.value; float currentValueTime = Time.time; float deltaTime = currentValueTime - lastValueTime; diff --git a/Assets/Scenes/Boids/Boids.unity b/Assets/Scenes/Boids/Boids.unity index 970b54d..0f3df0d 100644 --- a/Assets/Scenes/Boids/Boids.unity +++ b/Assets/Scenes/Boids/Boids.unity @@ -377,7 +377,6 @@ MonoBehaviour: cohesionForce: 5 separationForce: 5 separationDistance: 0.3 - bodyForce: 20 perceptionDistance: 1 boundaryForce: 5 spaceSize: {x: 10, y: 10, z: 10} @@ -394,7 +393,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec888ca5333d45a438f9f417fa5ce135, type: 3} m_Name: m_EditorClassIdentifier: Assembly-CSharp::SwarmSpawn - count: 5 + count: 10 boidPrefab: {fileID: 8702527964058765413, guid: f9c706268554ce449a8773675b2864b8, type: 3} spawnAreaSize: {x: 0.5, y: 0.5, z: 0.5} minDelay: 0.05 diff --git a/Assets/Scenes/Boids/Scripts/Boid.cs b/Assets/Scenes/Boids/Scripts/Boid.cs index d0cd02e..1375e50 100644 --- a/Assets/Scenes/Boids/Scripts/Boid.cs +++ b/Assets/Scenes/Boids/Scripts/Boid.cs @@ -11,6 +11,8 @@ public class Boid : MonoBehaviour { public float separationDistance = 0.5f; public float bodyForce = 1; + public bool debug = false; + public SwarmControl sc; public Vector3 velocity = Vector3.zero; public Vector3 acceleration = Vector3.zero; @@ -27,7 +29,7 @@ public class Boid : MonoBehaviour { public Neuroid cohesion; public Neuroid alignment; public Neuroid separation; - public Neuroid target; + // public Neuroid target; public Neuroid boundary; public Neuroid totalForce; @@ -42,34 +44,28 @@ public class Boid : MonoBehaviour { bounds = new(sc.transform.position, sc.spaceSize - 2 * sc.boundaryWidth); perception = new Perception(neuroidNet); - //neighbourSensor = new(neuroidNet) { name = "Neighbour", id = 879 }; - cohesion = new(neuroidNet) { name = "Cohesion", mode = Neuroid.Mode.Sum }; + cohesion = new(neuroidNet, "Cohesion"); perception.SendPositions(cohesion); - //cohesion.GetInputFrom(neighbourSensor); - alignment = new(neuroidNet) { name = "Alignment", mode = Neuroid.Mode.Average }; - //perception.SendVelocities(alignment); - separation = new(neuroidNet) { name = "Separation", mode = Neuroid.Mode.Sum }; - target = new(neuroidNet) { name = "Target", mode = Neuroid.Mode.Sum }; - boundary = new(neuroidNet) { name = "Boundary", mode = Neuroid.Mode.Sum }; + + alignment = new(neuroidNet, "Alignment") { average = true }; + perception.SendVelocities(alignment); + + separation = new(neuroidNet, "Separation") { inverse = true, exponent = 2 }; + perception.SendPositions(separation, sc.separationForce); + + boundary = new(neuroidNet, "Boundary"); - totalForce = new(neuroidNet) { name = "Total force", mode = Neuroid.Mode.Sum }; + totalForce = new(neuroidNet, "Total"); totalForce.GetInputFrom(alignment, sc.alignmentForce); totalForce.GetInputFrom(cohesion, sc.cohesionForce); - totalForce.GetInputFrom(separation, sc.separationForce); - totalForce.GetInputFrom(target, sc.bodyForce); + totalForce.GetInputFrom(separation, -sc.separationForce); totalForce.GetInputFrom(boundary, sc.boundaryForce); } void Update() { Physics.OverlapSphereNonAlloc(this.transform.position, sc.perceptionDistance, results); - neighbourCount = 0; - - cohesion.ResetWeights(); - alignment.ResetWeights(); - //separation.ResetWeights(); - foreach (Collider c in results) { if (c == null) continue; @@ -80,45 +76,40 @@ public class Boid : MonoBehaviour { continue; Vector3 localPosition = neighbour.transform.position - this.transform.position; - Vector3 relativeVelocity = neighbour.velocity - this.velocity; + if (debug) + Debug.Log($" distance {localPosition.magnitude}"); int thingId = neighbour.GetInstanceID(); perception.ProcessStimulus(thingId, localPosition); - - Vector3 separationForce = -localPosition / localPosition.sqrMagnitude; - // which is equivalent to -(localPosition.normalized / localPosition.magnitude) - - separation.SetInput(thingId, separationForce, sc.separationDistance, neuroidNet); - //cohesion.SetInput(thingId, localPosition, sc.cohesionForce); - alignment.SetInput(thingId, relativeVelocity, sc.alignmentForce, neuroidNet); - neighbourCount++; - } } - //Vector3 spaceLocalPosition = sc.transform.InverseTransformPoint(this.transform.position); - if (!bounds.Contains(this.transform.position)) { - Vector3 point = this.transform.position; - // Vector3 distanceOutside = Vector3.Max(bounds.min - this.transform.position, this.transform.position - bounds.max); - // // Ensure value is > 0 (but isn't this already) - // Vector3 outside = distanceOutside; // Vector3.Max(Vector3.zero, distanceOutside); + // if (!bounds.Contains(this.transform.position)) { + // Vector3 point = this.transform.position; + // // Vector3 distanceOutside = Vector3.Max(bounds.min - this.transform.position, this.transform.position - bounds.max); + // // // Ensure value is > 0 (but isn't this already) + // // Vector3 outside = distanceOutside; // Vector3.Max(Vector3.zero, distanceOutside); - Vector3 below = bounds.min - point; // positive where point < min - Vector3 above = point - bounds.max; // positive where point > max + // Vector3 below = bounds.min - point; // positive where point < min + // Vector3 above = point - bounds.max; // positive where point > max - // outside distances per axis (0 if inside on that axis) - Vector3 outside = Vector3.Max(Vector3.zero, Vector3.Max(below, above)); - float magnitude = outside.magnitude; - Vector3 direction = (sc.transform.position - this.transform.position).normalized; - outside = direction * magnitude; + // // outside distances per axis (0 if inside on that axis) + // Vector3 outside = Vector3.Max(Vector3.zero, Vector3.Max(below, above)); + // float magnitude = outside.magnitude; + // Vector3 direction = (sc.transform.position - this.transform.position).normalized; + // outside = direction * magnitude; - boundary.SetInput(id, outside, sc.boundaryForce, neuroidNet); - // Debug.Log($"boundary {this.transform.position} {outside} force = {outside * sc.boundaryForce}"); - } + // boundary.SetInput(id, outside, sc.boundaryForce, neuroidNet); + // // Debug.Log($"boundary {this.transform.position} {outside} force = {outside * sc.boundaryForce}"); + // } Vector3 totalForceVector = totalForce.outputValue; //Debug.DrawRay(this.transform.position, totalForceVector, Color.magenta); + if (this.debug) { + Debug.Log($"Cohesion {cohesion.outputValue.magnitude} separation {separation.outputValue.magnitude} alignment {alignment.outputValue.magnitude}"); + } + this.velocity = (1 - sc.inertia) * (totalForceVector * Time.deltaTime) + sc.inertia * velocity + (sc.speed * transform.forward); //this.velocity = Vector3.ClampMagnitude(this.velocity, sc.speed); @@ -132,74 +123,7 @@ public class Boid : MonoBehaviour { //Debug.Log($"neighbours: {neighbourCount} synapses: {cohesion.synapses.Count}"); neuroidNet.Update(); } -/* - Receptor GetReceptor(Neuroid perceptionNeuroid, int id) { - int availableIx = -1; - for (int i = 0; i < neighbourSensor.Length; i++) { - if (neighbourSensor[i] == null || neighbourSensor[i].IsStale()) - availableIx = i; - else if (neighbourSensor[i].thingId == id) - return neighbourSensor[i].receptor; - } - if (availableIx != -1) { - if (neighbourSensor[availableIx] != null) { - Debug.Log($"revived receptor {availableIx} for {id}"); - neighbourSensor[availableIx].thingId = id; - return neighbourSensor[availableIx].receptor; - } - else { - Debug.Log($"new receptor for {id}"); - SensoryNeuroid neuroid = new(neuroidNet, id); - perceptionNeuroid.GetInputFrom(neuroid); - neighbourSensor[availableIx] = neuroid; - return neuroid.receptor; - } - } - //Debug.LogWarning($"No available receptor for {id}"); - return null; - } - - -/* - void ProcessStimulus(int thingId, Vector3 value) { - int availableIx = -1; - SensoryNeuroid leastInterestingNeuroid = null; - for (int i = 0; i < neighbourSensor.Length; i++) { - if (neighbourSensor[i] == null || neighbourSensor[i].IsStale()) - availableIx = i; - else if (neighbourSensor[i].thingId == thingId) { - neighbourSensor[i].receptor.SetValue(value); - return; - } - if (neighbourSensor[i] != null) { - if (leastInterestingNeuroid == null || leastInterestingNeuroid.receptor.GetValue().magnitude > neighbourSensor[i].receptor.GetValue().magnitude) - leastInterestingNeuroid = neighbourSensor[i]; - } - } - if (availableIx != -1) { - if (neighbourSensor[availableIx] != null) { - // Debug.Log($"revived receptor {availableIx} for {thingId}"); - neighbourSensor[availableIx].thingId = thingId; - neighbourSensor[availableIx].receptor.SetValue(value); - } - else { - // Debug.Log($"new receptor for {thingId}"); - SensoryNeuroid neuroid = new(neuroidNet, thingId); - cohesion.GetInputFrom(neuroid); - neighbourSensor[availableIx] = neuroid; - neuroid.receptor.SetValue(value); - } - } - else if (leastInterestingNeuroid != null) { - //Debug.Log($"replaced receptor {leastInterestingNeuroid.thingId} for {thingId}"); - leastInterestingNeuroid.thingId = thingId; - leastInterestingNeuroid.receptor.SetValue(value); - } - - //Debug.LogWarning($"No available receptor for {id}"); - } -*/ void OnDrawGizmosSelected() { Gizmos.DrawWireSphere(transform.position, sc.perceptionDistance); } diff --git a/Assets/Scenes/Boids/Scripts/SwarmControl.cs b/Assets/Scenes/Boids/Scripts/SwarmControl.cs index 7837162..fa502ab 100644 --- a/Assets/Scenes/Boids/Scripts/SwarmControl.cs +++ b/Assets/Scenes/Boids/Scripts/SwarmControl.cs @@ -10,7 +10,7 @@ public class SwarmControl : MonoBehaviour public float cohesionForce = 10.0f; public float separationForce = 5.0f; public float separationDistance = 0.5f; - public float bodyForce = 20; + // public float bodyForce = 20; public float perceptionDistance = 1.0f; public float boundaryForce = 2.0f; From bb5939b6ab73ae8168da352f16d310767e0e454e Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 1 Dec 2025 17:37:43 +0100 Subject: [PATCH 009/179] new boundary perception --- Assembly-CSharp.csproj | 1 + Assets/NanoBrain/Neuroid.cs | 12 ++- Assets/NanoBrain/Nucleus.cs | 7 ++ Assets/NanoBrain/Nucleus.cs.meta | 2 + Assets/NanoBrain/Perception.cs | 58 ++++++++--- Assets/Scenes/Boids/Boids.unity | 2 +- Assets/Scenes/Boids/Scripts/Boid.cs | 110 +++++++++++--------- Assets/Scenes/Boids/Scripts/SwarmControl.cs | 2 +- 8 files changed, 130 insertions(+), 64 deletions(-) create mode 100644 Assets/NanoBrain/Nucleus.cs create mode 100644 Assets/NanoBrain/Nucleus.cs.meta diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index 97530fd..526dc5f 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -55,6 +55,7 @@ + diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index 09c5606..2eb26d8 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -102,6 +102,16 @@ public class Neuroid { UpdateState(); } + public void RemoveInputFrom(Neuroid input) { + this.synapses.Remove(input); + if (this.synapses.Count == 0) { + // In case this was the last synapse, we reset the output because in this case no updates from synapses will follow. + this.outputValue = Vector3.zero; + foreach (Neuroid neuroid in this.outputNeuroids) + neuroid.SetInput(this, this.outputValue); + } + } + // public readonly Dictionary fakeNeuroids = new(); // public void SetInput(int thingId, Vector3 value, float weight, NeuroidNetwork net) { // if (fakeNeuroids.ContainsKey(thingId)) { @@ -131,7 +141,7 @@ public class Neuroid { result /= this.synapses.Count; this.outputValue = result; - foreach (Neuroid neuroid in outputNeuroids) + foreach (Neuroid neuroid in this.outputNeuroids) neuroid.SetInput(this, this.outputValue); this.stale = 0; } diff --git a/Assets/NanoBrain/Nucleus.cs b/Assets/NanoBrain/Nucleus.cs new file mode 100644 index 0000000..e3a398d --- /dev/null +++ b/Assets/NanoBrain/Nucleus.cs @@ -0,0 +1,7 @@ +public class Nucleus { + public class State { + + } + + public State state; +} \ No newline at end of file diff --git a/Assets/NanoBrain/Nucleus.cs.meta b/Assets/NanoBrain/Nucleus.cs.meta new file mode 100644 index 0000000..e520090 --- /dev/null +++ b/Assets/NanoBrain/Nucleus.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 750748f3f0e7d472fbf88ab02987074c \ No newline at end of file diff --git a/Assets/NanoBrain/Perception.cs b/Assets/NanoBrain/Perception.cs index 99729c3..b83b402 100644 --- a/Assets/NanoBrain/Perception.cs +++ b/Assets/NanoBrain/Perception.cs @@ -1,13 +1,19 @@ using System.Collections.Generic; using UnityEngine; -public class Perception { + +public class Perception : Nucleus { public SensoryNeuroid[] sensoryNeuroids = new SensoryNeuroid[7]; public NeuroidNetwork neuroidNet { get; protected set; } - public HashSet positionReceivers { get; protected set; } - public HashSet velocityReceivers { get; protected set; } + public class Receiver { + public int thingType = 0; + public Neuroid neuroid; + } + + public HashSet positionReceivers { get; protected set; } + public HashSet velocityReceivers { get; protected set; } public Perception(NeuroidNetwork neuroidNet) { this.neuroidNet = neuroidNet; @@ -15,26 +21,34 @@ public class Perception { this.velocityReceivers = new(); } - public void SendPositions(Neuroid receiver, float weight = 1.0f) { + public void SendPositions(Neuroid receivingNeuroid, float weight = 1.0f, int thingType = 0) { + Receiver receiver = new() { + thingType = thingType, + neuroid = receivingNeuroid + }; positionReceivers.Add(receiver); foreach (SensoryNeuroid neuroid in sensoryNeuroids) { if (neuroid != null) { - neuroid.AddReceiver(receiver); - receiver.synapses[neuroid] = new (neuroid, Vector3.zero, weight); + neuroid.AddReceiver(receivingNeuroid); + receivingNeuroid.synapses[neuroid] = new(neuroid, Vector3.zero, weight); } } } - public void SendVelocities(Neuroid receiver) { + public void SendVelocities(Neuroid receivingNeuroid, float weight = 1.0f, int thingType = 0) { + Receiver receiver = new() { + thingType = thingType, + neuroid = receivingNeuroid + }; velocityReceivers.Add(receiver); foreach (SensoryNeuroid neuroid in sensoryNeuroids) { if (neuroid != null && neuroid.velocityNeuroid != null) { - neuroid.velocityNeuroid.AddReceiver(receiver); - receiver.synapses[neuroid] = new (neuroid, Vector3.zero, 1.0f); + neuroid.velocityNeuroid.AddReceiver(receivingNeuroid); + receivingNeuroid.synapses[neuroid] = new(neuroid, Vector3.zero, 1.0f); } } } - public void ProcessStimulus(int thingId, Vector3 localPosition) { + public void ProcessStimulus(int thingId, int thingType, Vector3 localPosition) { int availableIx = -1; SensoryNeuroid leastInterestingNeuroid = null; for (int i = 0; i < sensoryNeuroids.Length; i++) { @@ -58,10 +72,14 @@ public class Perception { else { // Debug.Log($"new receptor for {thingId}"); SensoryNeuroid neuroid = new(neuroidNet, thingId); - foreach (Neuroid receiver in positionReceivers) - receiver.GetInputFrom(neuroid); - foreach (Neuroid receiver in velocityReceivers) - receiver.GetInputFrom(neuroid.velocityNeuroid); + foreach (Receiver receiver in positionReceivers) { + if (receiver.thingType == 0 || receiver.thingType == thingType) + receiver.neuroid.GetInputFrom(neuroid); + } + foreach (Receiver receiver in velocityReceivers) { + if (receiver.thingType == 0 || receiver.thingType == thingType) + receiver.neuroid.GetInputFrom(neuroid.velocityNeuroid); + } sensoryNeuroids[availableIx] = neuroid; neuroid.receptor.position = localPosition; @@ -75,4 +93,16 @@ public class Perception { //Debug.LogWarning($"No available receptor for {id}"); } + + public void RemoveStimulus(int thingId) { + for (int i = 0; i < sensoryNeuroids.Length; i++) { + if (sensoryNeuroids[i] != null && sensoryNeuroids[i].receptor.thingId == thingId) { + foreach (Neuroid outputNeuroid in sensoryNeuroids[i].outputNeuroids) + outputNeuroid.RemoveInputFrom(sensoryNeuroids[i]); + sensoryNeuroids[i] = null; + return; + } + } + + } } \ No newline at end of file diff --git a/Assets/Scenes/Boids/Boids.unity b/Assets/Scenes/Boids/Boids.unity index 0f3df0d..ee7a797 100644 --- a/Assets/Scenes/Boids/Boids.unity +++ b/Assets/Scenes/Boids/Boids.unity @@ -393,7 +393,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec888ca5333d45a438f9f417fa5ce135, type: 3} m_Name: m_EditorClassIdentifier: Assembly-CSharp::SwarmSpawn - count: 10 + count: 2 boidPrefab: {fileID: 8702527964058765413, guid: f9c706268554ce449a8773675b2864b8, type: 3} spawnAreaSize: {x: 0.5, y: 0.5, z: 0.5} minDelay: 0.05 diff --git a/Assets/Scenes/Boids/Scripts/Boid.cs b/Assets/Scenes/Boids/Scripts/Boid.cs index 1375e50..f239e3e 100644 --- a/Assets/Scenes/Boids/Scripts/Boid.cs +++ b/Assets/Scenes/Boids/Scripts/Boid.cs @@ -11,13 +11,17 @@ public class Boid : MonoBehaviour { public float separationDistance = 0.5f; public float bodyForce = 1; + public const int BoundaryType = 1; + public const int BoidType = 2; + public bool debug = false; public SwarmControl sc; public Vector3 velocity = Vector3.zero; public Vector3 acceleration = Vector3.zero; - private Bounds bounds; + private Bounds innerBounds; + private Bounds outerBounds; readonly Collider[] results = new Collider[10]; @@ -28,7 +32,7 @@ public class Boid : MonoBehaviour { public Neuroid bodyVector; public Neuroid cohesion; public Neuroid alignment; - public Neuroid separation; + public Neuroid avoidance; // public Neuroid target; public Neuroid boundary; @@ -41,76 +45,73 @@ public class Boid : MonoBehaviour { sc = FindFirstObjectByType(); - bounds = new(sc.transform.position, sc.spaceSize - 2 * sc.boundaryWidth); + innerBounds = new(sc.transform.position, sc.spaceSize - 2 * sc.boundaryWidth); + outerBounds = new(sc.transform.position, sc.spaceSize); perception = new Perception(neuroidNet); cohesion = new(neuroidNet, "Cohesion"); - perception.SendPositions(cohesion); + perception.SendPositions(cohesion, 1.0f, BoidType); - alignment = new(neuroidNet, "Alignment") { average = true }; - perception.SendVelocities(alignment); + // alignment = new(neuroidNet, "Alignment") { average = true }; + // perception.SendVelocities(alignment); - separation = new(neuroidNet, "Separation") { inverse = true, exponent = 2 }; - perception.SendPositions(separation, sc.separationForce); + avoidance = new(neuroidNet, "Separation") { inverse = true }; + perception.SendPositions(avoidance, sc.avoidanceForce); boundary = new(neuroidNet, "Boundary"); totalForce = new(neuroidNet, "Total"); - totalForce.GetInputFrom(alignment, sc.alignmentForce); - totalForce.GetInputFrom(cohesion, sc.cohesionForce); - totalForce.GetInputFrom(separation, -sc.separationForce); - totalForce.GetInputFrom(boundary, sc.boundaryForce); + //totalForce.GetInputFrom(alignment, sc.alignmentForce); + //totalForce.GetInputFrom(cohesion, sc.cohesionForce); + totalForce.GetInputFrom(avoidance, -sc.avoidanceForce); + //totalForce.GetInputFrom(boundary, sc.boundaryForce); } void Update() { Physics.OverlapSphereNonAlloc(this.transform.position, sc.perceptionDistance, results); - foreach (Collider c in results) { - if (c == null) - continue; + // foreach (Collider c in results) { + // if (c == null) + // continue; - if (c as CapsuleCollider != null) { - Boid neighbour = c.GetComponentInParent(); - if (neighbour == null || neighbour == this) - continue; + // if (c as CapsuleCollider != null) { + // Boid neighbour = c.GetComponentInParent(); + // if (neighbour == null || neighbour == this) + // continue; - Vector3 localPosition = neighbour.transform.position - this.transform.position; - if (debug) - Debug.Log($" distance {localPosition.magnitude}"); + // Vector3 localPosition = neighbour.transform.position - this.transform.position; + // if (debug) + // Debug.Log($" distance {localPosition.magnitude}"); - int thingId = neighbour.GetInstanceID(); - perception.ProcessStimulus(thingId, localPosition); - } - } - - // if (!bounds.Contains(this.transform.position)) { - // Vector3 point = this.transform.position; - // // Vector3 distanceOutside = Vector3.Max(bounds.min - this.transform.position, this.transform.position - bounds.max); - // // // Ensure value is > 0 (but isn't this already) - // // Vector3 outside = distanceOutside; // Vector3.Max(Vector3.zero, distanceOutside); - - // Vector3 below = bounds.min - point; // positive where point < min - // Vector3 above = point - bounds.max; // positive where point > max - - // // outside distances per axis (0 if inside on that axis) - // Vector3 outside = Vector3.Max(Vector3.zero, Vector3.Max(below, above)); - // float magnitude = outside.magnitude; - // Vector3 direction = (sc.transform.position - this.transform.position).normalized; - // outside = direction * magnitude; - - // boundary.SetInput(id, outside, sc.boundaryForce, neuroidNet); - // // Debug.Log($"boundary {this.transform.position} {outside} force = {outside * sc.boundaryForce}"); + // int thingId = neighbour.GetInstanceID(); + // perception.ProcessStimulus(thingId, localPosition); + // } // } + if (!innerBounds.Contains(this.transform.position)) { + Vector3 point = this.transform.position; + Vector3 toBounds; + if (outerBounds.Contains(this.transform.position)) { + Vector3 pointOnBounds = ClosestPointOnBoundsSurface(outerBounds, point); + toBounds = this.transform.InverseTransformPoint(pointOnBounds); + } + else { + Vector3 pointOnBounds = innerBounds.ClosestPoint(point); + toBounds = -this.transform.InverseTransformPoint(pointOnBounds); + } + perception.ProcessStimulus(777, BoundaryType, toBounds); + } else + perception.RemoveStimulus(777); + Vector3 totalForceVector = totalForce.outputValue; - //Debug.DrawRay(this.transform.position, totalForceVector, Color.magenta); if (this.debug) { - Debug.Log($"Cohesion {cohesion.outputValue.magnitude} separation {separation.outputValue.magnitude} alignment {alignment.outputValue.magnitude}"); + Debug.Log($"Cohesion {cohesion.outputValue.magnitude} separation {avoidance.outputValue.magnitude} alignment {alignment.outputValue.magnitude}"); } - this.velocity = (1 - sc.inertia) * (totalForceVector * Time.deltaTime) + sc.inertia * velocity + (sc.speed * transform.forward); + Vector3 worldForce = this.transform.TransformDirection(totalForceVector); + this.velocity = (1 - sc.inertia) * (worldForce * Time.deltaTime) + sc.inertia * velocity + (sc.speed * transform.forward); //this.velocity = Vector3.ClampMagnitude(this.velocity, sc.speed); this.transform.position += this.velocity * Time.deltaTime; @@ -124,7 +125,22 @@ public class Boid : MonoBehaviour { neuroidNet.Update(); } + Vector3 ClosestPointOnBoundsSurface(Bounds b, Vector3 p) { + if (!b.Contains(p)) return b.ClosestPoint(p); + Vector3 d = p - b.center; + Vector3 ext = b.extents; + float sx = ext.x / Mathf.Abs(d.x); + float sy = ext.y / Mathf.Abs(d.y); + float sz = ext.z / Mathf.Abs(d.z); + float m = Mathf.Min(sx, Mathf.Min(sy, sz)); + return b.center + d * m; + } + void OnDrawGizmosSelected() { Gizmos.DrawWireSphere(transform.position, sc.perceptionDistance); + Gizmos.color = Color.yellow; + Gizmos.DrawRay(transform.position, this.transform.TransformDirection(totalForce.outputValue) * 10); + Gizmos.color = Color.magenta; + Gizmos.DrawRay(transform.position, this.transform.TransformDirection(avoidance.outputValue) * 10); } } diff --git a/Assets/Scenes/Boids/Scripts/SwarmControl.cs b/Assets/Scenes/Boids/Scripts/SwarmControl.cs index fa502ab..c98a403 100644 --- a/Assets/Scenes/Boids/Scripts/SwarmControl.cs +++ b/Assets/Scenes/Boids/Scripts/SwarmControl.cs @@ -8,7 +8,7 @@ public class SwarmControl : MonoBehaviour public float inertia = 0.1f; public float alignmentForce = 0.0f; public float cohesionForce = 10.0f; - public float separationForce = 5.0f; + public float avoidanceForce = 5.0f; public float separationDistance = 0.5f; // public float bodyForce = 20; public float perceptionDistance = 1.0f; From 2bae70fae26e8929c7dfa0cbb8be68be2df4fd3b Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Tue, 2 Dec 2025 11:15:29 +0100 Subject: [PATCH 010/179] boundary using Avoidance Nucleus --- Assembly-CSharp.csproj | 2 + Assets/NanoBrain/Nucleus.cs | 10 +++ Assets/NanoBrain/Perception.cs | 2 +- Assets/Scenes/Boids/Boids.unity | 8 +- Assets/Scenes/Boids/Prefabs/Boid.prefab | 3 +- Assets/Scenes/Boids/Scripts/Boid.cs | 87 +++++++++---------- Assets/Scenes/Boids/Scripts/RoamingNucleus.cs | 14 +++ .../Boids/Scripts/RoamingNucleus.cs.meta | 2 + .../Scenes/Boids/Scripts/SwarmingNucleus.cs | 29 +++++++ .../Boids/Scripts/SwarmingNucleus.cs.meta | 2 + 10 files changed, 107 insertions(+), 52 deletions(-) create mode 100644 Assets/Scenes/Boids/Scripts/RoamingNucleus.cs create mode 100644 Assets/Scenes/Boids/Scripts/RoamingNucleus.cs.meta create mode 100644 Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs create mode 100644 Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs.meta diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index 526dc5f..cc63681 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -52,7 +52,9 @@ + + diff --git a/Assets/NanoBrain/Nucleus.cs b/Assets/NanoBrain/Nucleus.cs index e3a398d..e4b4a66 100644 --- a/Assets/NanoBrain/Nucleus.cs +++ b/Assets/NanoBrain/Nucleus.cs @@ -4,4 +4,14 @@ public class Nucleus { } public State state; + + public Neuroid output; + + public Nucleus(NeuroidNetwork neuroidNet) { + this.output = new(neuroidNet, "Nucleus output"); + } + + public void AddReceiver(Neuroid receiver) { + this.output.AddReceiver(receiver); + } } \ No newline at end of file diff --git a/Assets/NanoBrain/Perception.cs b/Assets/NanoBrain/Perception.cs index b83b402..5516459 100644 --- a/Assets/NanoBrain/Perception.cs +++ b/Assets/NanoBrain/Perception.cs @@ -15,7 +15,7 @@ public class Perception : Nucleus { public HashSet positionReceivers { get; protected set; } public HashSet velocityReceivers { get; protected set; } - public Perception(NeuroidNetwork neuroidNet) { + public Perception(NeuroidNetwork neuroidNet) : base(neuroidNet) { this.neuroidNet = neuroidNet; this.positionReceivers = new(); this.velocityReceivers = new(); diff --git a/Assets/Scenes/Boids/Boids.unity b/Assets/Scenes/Boids/Boids.unity index ee7a797..e7ee4e7 100644 --- a/Assets/Scenes/Boids/Boids.unity +++ b/Assets/Scenes/Boids/Boids.unity @@ -375,7 +375,7 @@ MonoBehaviour: inertia: 0.1 alignmentForce: 5 cohesionForce: 5 - separationForce: 5 + avoidanceForce: 5 separationDistance: 0.3 perceptionDistance: 1 boundaryForce: 5 @@ -393,7 +393,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec888ca5333d45a438f9f417fa5ce135, type: 3} m_Name: m_EditorClassIdentifier: Assembly-CSharp::SwarmSpawn - count: 2 + count: 1 boidPrefab: {fileID: 8702527964058765413, guid: f9c706268554ce449a8773675b2864b8, type: 3} spawnAreaSize: {x: 0.5, y: 0.5, z: 0.5} minDelay: 0.05 @@ -442,7 +442,7 @@ Transform: serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 10, z: 0} - m_LocalScale: {x: 10, y: 1, z: 10} + m_LocalScale: {x: 10, y: 0.1, z: 10} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 1826482027} @@ -772,7 +772,7 @@ Transform: serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 10, y: 1, z: 10} + m_LocalScale: {x: 10, y: 0.1, z: 10} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 1826482027} diff --git a/Assets/Scenes/Boids/Prefabs/Boid.prefab b/Assets/Scenes/Boids/Prefabs/Boid.prefab index 7f21df2..89241e9 100644 --- a/Assets/Scenes/Boids/Prefabs/Boid.prefab +++ b/Assets/Scenes/Boids/Prefabs/Boid.prefab @@ -160,12 +160,13 @@ MonoBehaviour: m_EditorClassIdentifier: speed: 0.2 neighbourCount: 0 - inertia: 0.2 + inertia: 0 alignmentForce: 1 cohesionForce: 1 separationForce: 1 separationDistance: 0.5 bodyForce: 1 + debug: 0 sc: {fileID: 0} velocity: {x: 0, y: 0, z: 0} acceleration: {x: 0, y: 0, z: 0} diff --git a/Assets/Scenes/Boids/Scripts/Boid.cs b/Assets/Scenes/Boids/Scripts/Boid.cs index f239e3e..b3326fe 100644 --- a/Assets/Scenes/Boids/Scripts/Boid.cs +++ b/Assets/Scenes/Boids/Scripts/Boid.cs @@ -2,20 +2,18 @@ using UnityEngine; public class Boid : MonoBehaviour { - public float speed = 0.2f; - public int neighbourCount = 0; - public float inertia = 0.2f; - public float alignmentForce = 1.0f; - public float cohesionForce = 1.0f; - public float separationForce = 1.0f; - public float separationDistance = 0.5f; - public float bodyForce = 1; + // public float speed = 0.2f; + // public int neighbourCount = 0; + // public float inertia = 0.2f; + // public float alignmentForce = 1.0f; + // public float cohesionForce = 1.0f; + // public float separationForce = 1.0f; + // public float separationDistance = 0.5f; + // public float bodyForce = 1; public const int BoundaryType = 1; public const int BoidType = 2; - public bool debug = false; - public SwarmControl sc; public Vector3 velocity = Vector3.zero; public Vector3 acceleration = Vector3.zero; @@ -25,16 +23,13 @@ public class Boid : MonoBehaviour { readonly Collider[] results = new Collider[10]; - //public SensoryNeuroid[] neighbourSensor = new SensoryNeuroid[6]; - public Perception perception; - public NeuroidNetwork neuroidNet = new(); - public Neuroid bodyVector; + public Perception perception; public Neuroid cohesion; public Neuroid alignment; public Neuroid avoidance; - // public Neuroid target; - public Neuroid boundary; + // public Neuroid boundary; + public Roaming roaming; public Neuroid totalForce; @@ -50,27 +45,29 @@ public class Boid : MonoBehaviour { perception = new Perception(neuroidNet); - cohesion = new(neuroidNet, "Cohesion"); - perception.SendPositions(cohesion, 1.0f, BoidType); + // cohesion = new(neuroidNet, "Cohesion"); + // perception.SendPositions(cohesion, 1.0f, BoidType); // alignment = new(neuroidNet, "Alignment") { average = true }; // perception.SendVelocities(alignment); - avoidance = new(neuroidNet, "Separation") { inverse = true }; - perception.SendPositions(avoidance, sc.avoidanceForce); + // avoidance = new(neuroidNet, "Separation") { inverse = true }; + // perception.SendPositions(avoidance, sc.avoidanceForce); - boundary = new(neuroidNet, "Boundary"); + //boundary = new(neuroidNet, "Boundary"); + roaming = new(neuroidNet, perception, sc); totalForce = new(neuroidNet, "Total"); //totalForce.GetInputFrom(alignment, sc.alignmentForce); //totalForce.GetInputFrom(cohesion, sc.cohesionForce); - totalForce.GetInputFrom(avoidance, -sc.avoidanceForce); + // totalForce.GetInputFrom(avoidance, -sc.avoidanceForce); //totalForce.GetInputFrom(boundary, sc.boundaryForce); + roaming.AddReceiver(totalForce); } void Update() { - Physics.OverlapSphereNonAlloc(this.transform.position, sc.perceptionDistance, results); + // Physics.OverlapSphereNonAlloc(this.transform.position, sc.perceptionDistance, results); // foreach (Collider c in results) { // if (c == null) // continue; @@ -91,28 +88,22 @@ public class Boid : MonoBehaviour { if (!innerBounds.Contains(this.transform.position)) { Vector3 point = this.transform.position; - Vector3 toBounds; - if (outerBounds.Contains(this.transform.position)) { - Vector3 pointOnBounds = ClosestPointOnBoundsSurface(outerBounds, point); - toBounds = this.transform.InverseTransformPoint(pointOnBounds); - } - else { - Vector3 pointOnBounds = innerBounds.ClosestPoint(point); - toBounds = -this.transform.InverseTransformPoint(pointOnBounds); - } - perception.ProcessStimulus(777, BoundaryType, toBounds); - } else + Vector3 pointOnBounds = innerBounds.ClosestPoint(point); + Vector3 desiredWorldSpace = (pointOnBounds - point).normalized * sc.speed; + Vector3 desiredLocalSpace = -this.transform.InverseTransformPoint(desiredWorldSpace); + perception.ProcessStimulus(777, BoundaryType, desiredLocalSpace); + } + else { perception.RemoveStimulus(777); - - Vector3 totalForceVector = totalForce.outputValue; - - if (this.debug) { - Debug.Log($"Cohesion {cohesion.outputValue.magnitude} separation {avoidance.outputValue.magnitude} alignment {alignment.outputValue.magnitude}"); } - Vector3 worldForce = this.transform.TransformDirection(totalForceVector); - this.velocity = (1 - sc.inertia) * (worldForce * Time.deltaTime) + sc.inertia * velocity + (sc.speed * transform.forward); - //this.velocity = Vector3.ClampMagnitude(this.velocity, sc.speed); + Vector3 worldForce = this.transform.TransformDirection(totalForce.outputValue); + + this.velocity = (1 - sc.inertia) * (worldForce * Time.deltaTime) + sc.inertia * velocity; + if (this.velocity.magnitude > 0) + this.velocity = this.velocity.normalized * sc.speed; + else + this.velocity = this.transform.forward * sc.speed; this.transform.position += this.velocity * Time.deltaTime; @@ -121,7 +112,6 @@ public class Boid : MonoBehaviour { transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 2f); // Adjust the speed of rotation } - //Debug.Log($"neighbours: {neighbourCount} synapses: {cohesion.synapses.Count}"); neuroidNet.Update(); } @@ -139,8 +129,13 @@ public class Boid : MonoBehaviour { void OnDrawGizmosSelected() { Gizmos.DrawWireSphere(transform.position, sc.perceptionDistance); Gizmos.color = Color.yellow; - Gizmos.DrawRay(transform.position, this.transform.TransformDirection(totalForce.outputValue) * 10); - Gizmos.color = Color.magenta; - Gizmos.DrawRay(transform.position, this.transform.TransformDirection(avoidance.outputValue) * 10); + Vector3 worldForce = this.transform.TransformDirection(totalForce.outputValue); + Gizmos.DrawRay(transform.position, worldForce * 10); + // Gizmos.color = Color.magenta; + // Gizmos.DrawRay(transform.position, this.transform.TransformDirection(avoidance.outputValue) * 10); + // Debug.Log($"Avoidance {roaming.avoidance.outputValue} Roaming {roaming.output.outputValue} Total {totalForce.outputValue}"); + // Debug.Log($"WorldForce {worldForce} velocity {velocity} inertia {sc.inertia}"); + Gizmos.color = Color.blue; + Gizmos.DrawRay(transform.position, this.velocity * 10); } } diff --git a/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs b/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs new file mode 100644 index 0000000..aacd705 --- /dev/null +++ b/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs @@ -0,0 +1,14 @@ +public class Roaming : Nucleus { + + public Neuroid avoidance; + + public const int BoundaryType = 1; + public const int BoidType = 2; + + public Roaming(NeuroidNetwork neuroidNet, Perception perception, SwarmControl sc) : base(neuroidNet) { + avoidance = new(neuroidNet, "Separation") { inverse = true }; + perception.SendPositions(avoidance); + + output.GetInputFrom(avoidance, -sc.avoidanceForce); + } +} \ No newline at end of file diff --git a/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs.meta b/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs.meta new file mode 100644 index 0000000..27a0198 --- /dev/null +++ b/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 2c0f5292293252943b1d45dbd1d14515 \ No newline at end of file diff --git a/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs b/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs new file mode 100644 index 0000000..b40f1c6 --- /dev/null +++ b/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs @@ -0,0 +1,29 @@ +public class Swarming : Nucleus { + //public Perception perception; + + public Neuroid cohesion; + public Neuroid alignment; + public Neuroid avoidance; + public Neuroid boundary; + + public const int BoundaryType = 1; + public const int BoidType = 2; + + public Swarming(NeuroidNetwork neuroidNet, Perception perception, SwarmControl sc) : base(neuroidNet) { + cohesion = new(neuroidNet, "Cohesion"); + perception.SendPositions(cohesion, 1.0f, BoidType); + + alignment = new(neuroidNet, "Alignment") { average = true }; + perception.SendVelocities(alignment); + + avoidance = new(neuroidNet, "Separation") { inverse = true }; + perception.SendPositions(avoidance, sc.avoidanceForce); + + boundary = new(neuroidNet, "Boundary"); + + output.GetInputFrom(alignment, sc.alignmentForce); + output.GetInputFrom(cohesion, sc.cohesionForce); + output.GetInputFrom(avoidance, -sc.avoidanceForce); + output.GetInputFrom(boundary, sc.boundaryForce); + } +} \ No newline at end of file diff --git a/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs.meta b/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs.meta new file mode 100644 index 0000000..f303111 --- /dev/null +++ b/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 14b1bfd5a5b0784e098fc5e47b1720a1 \ No newline at end of file From 88bf20b9c267a098633297b5c8110ac57becf534 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Tue, 2 Dec 2025 12:26:13 +0100 Subject: [PATCH 011/179] Neuroid is a Nucleus --- Assets/NanoBrain/Neuroid.cs | 15 ++++++----- Assets/NanoBrain/Nucleus.cs | 25 +++++++++++++------ Assets/Scenes/Boids/Scripts/RoamingNucleus.cs | 14 +++++++++-- .../Scenes/Boids/Scripts/SwarmingNucleus.cs | 6 +++-- 4 files changed, 40 insertions(+), 20 deletions(-) diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index 2eb26d8..e214df4 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -28,16 +28,15 @@ public class NeuroidNetwork { } } -public class Neuroid { +public class Neuroid : Nucleus { public string name; - public int layerIx; public int stale = 0; - public readonly Dictionary synapses = new(); + // public readonly Dictionary synapses = new(); public Vector3 outputValue; - public HashSet outputNeuroids = new(); + // public HashSet outputNeuroids = new(); public bool average = false; //public bool quadratic = false; @@ -46,7 +45,7 @@ public class Neuroid { public NeuroidNetwork net; - public Neuroid(NeuroidNetwork net, string name) { + public Neuroid(NeuroidNetwork net, string name) : base(net) { this.net = net; this.name = name; if (this.net != null) @@ -58,9 +57,9 @@ public class Neuroid { this.synapses[input] = new(input, Vector3.zero, 1.0f); } - public void AddReceiver(Neuroid receiver) { - this.outputNeuroids.Add(receiver); - } + // public void AddReceiver(Neuroid receiver) { + // this.outputNeuroids.Add(receiver); + // } public void ResetWeights() { foreach (Synapse synapse in this.synapses.Values) diff --git a/Assets/NanoBrain/Nucleus.cs b/Assets/NanoBrain/Nucleus.cs index e4b4a66..4272ae4 100644 --- a/Assets/NanoBrain/Nucleus.cs +++ b/Assets/NanoBrain/Nucleus.cs @@ -1,17 +1,26 @@ +using System.Collections.Generic; + public class Nucleus { - public class State { - - } + //public Neuroid output; + public readonly Dictionary synapses = new(); - public State state; + public HashSet outputNeuroids = new(); + + public int layerIx; - public Neuroid output; public Nucleus(NeuroidNetwork neuroidNet) { - this.output = new(neuroidNet, "Nucleus output"); + //this.output = new(neuroidNet, "Nucleus output"); } - public void AddReceiver(Neuroid receiver) { - this.output.AddReceiver(receiver); + public virtual void AddReceiver(Neuroid receiver) { + //this.output.AddReceiver(receiver); + this.outputNeuroids.Add(receiver); } + + // public void GetInputFrom(Neuroid input, float weight = 1.0f) { + // input.AddReceiver(this); + // this.synapses[input] = new(input, Vector3.zero, weight); + // } + } \ No newline at end of file diff --git a/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs b/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs index aacd705..a8889c6 100644 --- a/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs +++ b/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs @@ -1,14 +1,24 @@ public class Roaming : Nucleus { - + public float avoidanceForce; public Neuroid avoidance; + public Neuroid output; + + public const int BoundaryType = 1; public const int BoidType = 2; public Roaming(NeuroidNetwork neuroidNet, Perception perception, SwarmControl sc) : base(neuroidNet) { - avoidance = new(neuroidNet, "Separation") { inverse = true }; + this.avoidanceForce = sc.avoidanceForce; + + avoidance = new(neuroidNet, "Avoidance") { inverse = true }; perception.SendPositions(avoidance); + this.output = new(neuroidNet, "Roaming"); output.GetInputFrom(avoidance, -sc.avoidanceForce); } + + public override void AddReceiver(Neuroid receiver) { + output.AddReceiver(receiver); + } } \ No newline at end of file diff --git a/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs b/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs index b40f1c6..f6ec099 100644 --- a/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs +++ b/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs @@ -6,6 +6,8 @@ public class Swarming : Nucleus { public Neuroid avoidance; public Neuroid boundary; + public Neuroid output; + public const int BoundaryType = 1; public const int BoidType = 2; @@ -21,9 +23,9 @@ public class Swarming : Nucleus { boundary = new(neuroidNet, "Boundary"); + this.output = new(neuroidNet, "Swarming"); output.GetInputFrom(alignment, sc.alignmentForce); output.GetInputFrom(cohesion, sc.cohesionForce); output.GetInputFrom(avoidance, -sc.avoidanceForce); output.GetInputFrom(boundary, sc.boundaryForce); - } -} \ No newline at end of file + }} \ No newline at end of file From 9a6ae0e071d8f913e639dba7a3c1b9565ae2a190 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Tue, 2 Dec 2025 17:34:05 +0100 Subject: [PATCH 012/179] More nucleus like neurons --- Assets/NanoBrain/Editor/NeuroidWindow.cs | 188 +++++++++++++----- Assets/NanoBrain/Neuroid.cs | 26 ++- Assets/NanoBrain/Nucleus.cs | 19 +- Assets/NanoBrain/Perception.cs | 51 ++--- Assets/Scenes/Boids/Boids.unity | 2 +- Assets/Scenes/Boids/Scripts/Boid.cs | 58 ++---- Assets/Scenes/Boids/Scripts/RoamingNucleus.cs | 13 +- .../Scenes/Boids/Scripts/SwarmingNucleus.cs | 37 ++-- 8 files changed, 221 insertions(+), 173 deletions(-) diff --git a/Assets/NanoBrain/Editor/NeuroidWindow.cs b/Assets/NanoBrain/Editor/NeuroidWindow.cs index b0510df..72f9a9b 100644 --- a/Assets/NanoBrain/Editor/NeuroidWindow.cs +++ b/Assets/NanoBrain/Editor/NeuroidWindow.cs @@ -5,13 +5,13 @@ using System.Collections.Generic; public class NeuroidLayer { public int ix = 0; - public List neuroids = new(); + public List neuroids = new(); } public class GraphEditorWindow : EditorWindow { - private Neuroid currentNeuroid; + private Nucleus currentNucleus; private List allNeuroids; - private Dictionary neuroidPositions = new(); + private Dictionary neuroidPositions = new(); private List layers = new(); @@ -21,7 +21,58 @@ public class GraphEditorWindow : EditorWindow { SelectNeuron(); } - private void BuildLayers(List neuroids) { + private void AddToLayer(NeuroidLayer layer, Nucleus nucleus) { + layer.neuroids.Add(nucleus); + nucleus.layerIx = layer.ix; + // Store its position + Vector2Int neuroidPosition = new(layer.ix, layer.neuroids.Count - 1); + neuroidPositions[nucleus] = neuroidPosition; + + } + + private void BuildLayers() { + // A temporary list to track what's been added to layers + this.layers = new(); + int layerIx = 0; + + Nucleus selectedNucleus = this.currentNucleus; + NeuroidLayer currentLayer = new() { ix = layerIx }; + + foreach (Neuroid outputNeuroid in selectedNucleus.outputNeuroids) { + if (outputNeuroid != null) { + AddToLayer(currentLayer, outputNeuroid); + Debug.Log($"layer {layerIx} nucleus {outputNeuroid.name}"); + } + } + if (currentLayer.neuroids.Count > 0) { + this.layers.Add(currentLayer); + layerIx++; + currentLayer = new() { ix = layerIx }; + } + + AddToLayer(currentLayer, selectedNucleus); + this.layers.Add(currentLayer); + Debug.Log($"layer {layerIx} nucleus {selectedNucleus.name}"); + + layerIx++; + currentLayer = new() { ix = layerIx }; + + int six = 0; + foreach (Synapse synapse in selectedNucleus.synapses.Values) { + Debug.Log($"Synapse {six}"); + Nucleus input = synapse.neuroid; + if (input != null) { + AddToLayer(currentLayer, input); + Debug.Log($"layer {layerIx} nucleus {input.name}"); + } + six++; + } + if (currentLayer.neuroids.Count > 0) { + this.layers.Add(currentLayer); + } + } + + private void BuildLayers_old(List neuroids) { if (neuroids == null) return; @@ -41,10 +92,11 @@ public class GraphEditorWindow : EditorWindow { if (neuronVisited.Contains(neuroid)) continue; - if (neuroid.IsStale()) { - neuronVisited.Add(neuroid); - continue; - } + // if (neuroid.IsStale()) { + // Debug.Log($"neuron {neuroid.name} is stale {neuroid.stale}"); + // neuronVisited.Add(neuroid); + // continue; + // } // If the output neuroid is visited // Note: this does not yet work for multiple outputs yet (see the use of First()) @@ -92,7 +144,7 @@ public class GraphEditorWindow : EditorWindow { } private void DrawGraph() { - if (currentNeuroid == null) + if (currentNucleus == null) return; foreach (NeuroidLayer layer in layers) @@ -103,56 +155,88 @@ public class GraphEditorWindow : EditorWindow { int column = layer.ix * 100; int nodeCount = layer.neuroids.Count; float maxValue = 0; - foreach (Neuroid neuroid in layer.neuroids) { - float value = neuroid.outputValue.magnitude; - if (value > maxValue) - maxValue = value; + foreach (Nucleus nucleus in layer.neuroids) { + if (nucleus is Neuroid neuroid) { + float value = neuroid.outputValue.magnitude; + if (value > maxValue) + maxValue = value; + } } - float spacing = 200f / nodeCount; + float spacing = 400f / nodeCount; float margin = 100 + spacing / 2; - foreach (Neuroid layerNeuroid in layer.neuroids) { - Vector2Int layerNeuroidPos = this.neuroidPositions[layerNeuroid]; - Vector3 parentPos = new(100 + layerNeuroidPos.x * 100, margin + layerNeuroidPos.y * spacing, 0.1f); + foreach (Nucleus layerNucleus in layer.neuroids) { + if (layerNucleus is Neuroid layerNeuroid) { + Vector2Int layerNeuroidPos = this.neuroidPositions[layerNeuroid]; + Vector3 parentPos = new(100 + layerNeuroidPos.x * 100, margin + layerNeuroidPos.y * spacing, 0.1f); - int i = 0; - float inputSpacing = 200f / layerNeuroid.synapses.Count; - float inputMargin = 100 + inputSpacing / 2; - foreach (Synapse synapse in layerNeuroid.synapses.Values) { - if (synapse.neuroid != null) { - if (this.neuroidPositions.ContainsKey(synapse.neuroid)) { + int i = 0; + float inputSpacing = 400f / layerNeuroid.synapses.Count; + float inputMargin = 100 + inputSpacing / 2; + foreach (Synapse synapse in layerNeuroid.synapses.Values) { + if (synapse.neuroid != null) { + if (this.neuroidPositions.ContainsKey(synapse.neuroid)) { - Vector2Int inputNeuroidPos = this.neuroidPositions[synapse.neuroid]; - Vector3 pos = new(100 + inputNeuroidPos.x * 100, inputMargin + inputNeuroidPos.y * inputSpacing, 0.0f); + Vector2Int inputNeuroidPos = this.neuroidPositions[synapse.neuroid]; + if (inputNeuroidPos.x == layerNeuroidPos.x + 1) { + Vector3 pos = new(100 + inputNeuroidPos.x * 100, inputMargin + inputNeuroidPos.y * inputSpacing, 0.0f); - float brightness = synapse.weight / 10.0f; - Handles.color = new Color(brightness, brightness, brightness); - Handles.DrawLine(parentPos, pos); + float brightness = synapse.weight / 10.0f; + Handles.color = new Color(brightness, brightness, brightness); + Handles.DrawLine(parentPos, pos); + } + } } } + + float size = 20; + if (layerNeuroid.IsStale()) + Handles.color = Color.black; + else { + float brightness = layerNeuroid.outputValue.magnitude / maxValue; + Handles.color = new Color(brightness, brightness, brightness); + } + Handles.DrawSolidDisc(parentPos, Vector3.forward, size); + Vector3 labelPos = parentPos - Vector3.down * (size + 0.2f); // below disc along up axis + GUIStyle style = new GUIStyle(EditorStyles.label) { + alignment = TextAnchor.UpperCenter, + normal = { textColor = Color.white }, + fontStyle = FontStyle.Bold + }; + Handles.Label(labelPos, layerNeuroid.name, style); + + Rect neuronRect = new(parentPos.x - size, parentPos.y - size, size * 2, size * 2); + Event e = Event.current; + if (e != null && neuronRect.Contains(e.mousePosition)) { + HandleMouseHover(layerNeuroid, neuronRect); + // Process click + if (e.type == EventType.MouseDown && e.button == 0) { + // Consume the event so the scene doesn't also handle it + e.Use(); + HandleDiscClicked(layerNeuroid); + } + } + i++; } - - float size = layerNeuroid.outputValue.magnitude / maxValue * 20; - if (layerNeuroid.IsStale()) - Handles.color = Color.yellow; - else - Handles.color = Color.white; - Handles.DrawSolidDisc(parentPos, Vector3.forward, size); - Rect neuronRect = new(parentPos.x - size, parentPos.y - size, size * 2, size * 2); - if (neuronRect.Contains(Event.current.mousePosition)) - HandleMouseHover(layerNeuroid, neuronRect); - i++; - } } private void HandleMouseHover(Neuroid neuroid, Rect rect) { - // Draw the tooltip - GUIContent tooltip = new( - $"{neuroid.name}" + - $"\nsynapse count {neuroid.synapses.Count}" + - $"\nValue: {neuroid.outputValue}" + - $"\nStale: {neuroid.stale}"); - + GUIContent tooltip; + if (neuroid is SensoryNeuroid sensoryNeuroid) { + tooltip = new( + $"{sensoryNeuroid.name}" + + $"\nThing {sensoryNeuroid.receptor.thingId}" + + $"\nValue: {neuroid.outputValue}" + + $"\nStale: {neuroid.stale}"); + } + else { + tooltip = new( + $"{neuroid.name}" + + $"\nsynapse count {neuroid.synapses.Count}" + + $"\nValue: {neuroid.outputValue}" + + $"\nStale: {neuroid.stale}"); + } + Vector2 mousePosition = Event.current.mousePosition; // Display tooltip with some offset @@ -162,6 +246,10 @@ public class GraphEditorWindow : EditorWindow { GUI.Box(tooltipRect, tooltip); } + private void HandleDiscClicked(Nucleus nucleus) { + this.currentNucleus = nucleus; + BuildLayers(); + } // Update node colors based on selected GameObjects private void SelectNeuron() { @@ -175,15 +263,15 @@ public class GraphEditorWindow : EditorWindow { return; Neuroid neuroid = boid.totalForce; - this.currentNeuroid = neuroid; + this.currentNucleus = neuroid; if (neuroid == null) this.allNeuroids = new(); else this.allNeuroids = neuroid.net.neuroids; - //Debug.Log($"Neuroncount = {this.allNeuroids.Count}"); - BuildLayers(this.allNeuroids); + Debug.Log($"Neuroncount = {this.allNeuroids.Count}"); + BuildLayers(); Debug.Log($"Layercount = {this.layers.Count}"); } diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index e214df4..f4ff48b 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -3,12 +3,12 @@ using UnityEngine; using System.Linq; public class Synapse { - public Synapse(Neuroid neuroid, Vector3 value, float weight) { + public Synapse(Nucleus neuroid, Vector3 value, float weight) { this.neuroid = neuroid; this.value = value; this.weight = weight; } - public Neuroid neuroid; + public Nucleus neuroid; public Vector3 value; public float weight; } @@ -23,20 +23,17 @@ public class NeuroidNetwork { public void Update() { foreach (Neuroid neuroid in neuroids) { - neuroid.stale++; + neuroid.stale++; + if (neuroid.IsStale()) + neuroid.outputValue = Vector3.zero; } } } public class Neuroid : Nucleus { - public string name; - public int stale = 0; - // public readonly Dictionary synapses = new(); - - public Vector3 outputValue; - // public HashSet outputNeuroids = new(); + //public Vector3 outputValue; public bool average = false; //public bool quadratic = false; @@ -45,11 +42,12 @@ public class Neuroid : Nucleus { public NeuroidNetwork net; - public Neuroid(NeuroidNetwork net, string name) : base(net) { + public Neuroid(NeuroidNetwork net, string name) : base(name) { this.net = net; - this.name = name; if (this.net != null) this.net.neuroids.Add(this); + else + Debug.LogError("No neuroid network"); } public void AddSynapse(Neuroid input) { @@ -129,8 +127,14 @@ public class Neuroid : Nucleus { protected virtual void UpdateState() { Vector3 result = Vector3.zero; foreach (Synapse synapse in this.synapses.Values) { + // if (synapse.neuroid == null) + // continue; Vector3 direction = synapse.value.normalized; float magnitude = synapse.value.magnitude; + + // Vector3 direction = synapse.neuroid.outputValue.normalized; + // float magnitude = synapse.neuroid.outputValue.magnitude; + magnitude = synapse.weight * Mathf.Pow(magnitude, exponent); if (inverse) magnitude = 1 / magnitude; diff --git a/Assets/NanoBrain/Nucleus.cs b/Assets/NanoBrain/Nucleus.cs index 4272ae4..6fac46d 100644 --- a/Assets/NanoBrain/Nucleus.cs +++ b/Assets/NanoBrain/Nucleus.cs @@ -1,26 +1,21 @@ using System.Collections.Generic; +using UnityEngine; public class Nucleus { - //public Neuroid output; - public readonly Dictionary synapses = new(); + public string name; + public readonly Dictionary synapses = new(); public HashSet outputNeuroids = new(); + public virtual Vector3 outputValue {get; set; } public int layerIx; - - public Nucleus(NeuroidNetwork neuroidNet) { - //this.output = new(neuroidNet, "Nucleus output"); + public Nucleus(string name) { + this.name = name; } public virtual void AddReceiver(Neuroid receiver) { - //this.output.AddReceiver(receiver); this.outputNeuroids.Add(receiver); + receiver.synapses[this] = new(this, Vector3.zero, 1.0f); } - - // public void GetInputFrom(Neuroid input, float weight = 1.0f) { - // input.AddReceiver(this); - // this.synapses[input] = new(input, Vector3.zero, weight); - // } - } \ No newline at end of file diff --git a/Assets/NanoBrain/Perception.cs b/Assets/NanoBrain/Perception.cs index 5516459..c38f12b 100644 --- a/Assets/NanoBrain/Perception.cs +++ b/Assets/NanoBrain/Perception.cs @@ -15,7 +15,7 @@ public class Perception : Nucleus { public HashSet positionReceivers { get; protected set; } public HashSet velocityReceivers { get; protected set; } - public Perception(NeuroidNetwork neuroidNet) : base(neuroidNet) { + public Perception(NeuroidNetwork neuroidNet) : base("Perception") { this.neuroidNet = neuroidNet; this.positionReceivers = new(); this.velocityReceivers = new(); @@ -48,9 +48,9 @@ public class Perception : Nucleus { } } - public void ProcessStimulus(int thingId, int thingType, Vector3 localPosition) { + public void ProcessStimulus(int thingId, int thingType, Vector3 localPosition, string name = "Sensing") { int availableIx = -1; - SensoryNeuroid leastInterestingNeuroid = null; + int leastInterestingIx = -1; for (int i = 0; i < sensoryNeuroids.Length; i++) { if (sensoryNeuroids[i] == null || sensoryNeuroids[i].IsStale()) availableIx = i; @@ -59,39 +59,28 @@ public class Perception : Nucleus { return; } if (sensoryNeuroids[i] != null) { - if (leastInterestingNeuroid == null || leastInterestingNeuroid.receptor.position.magnitude > sensoryNeuroids[i].receptor.position.magnitude) - leastInterestingNeuroid = sensoryNeuroids[i]; + if (leastInterestingIx == -1 || sensoryNeuroids[leastInterestingIx].receptor.position.magnitude > sensoryNeuroids[i].receptor.position.magnitude) + leastInterestingIx = i; } } + if (availableIx == -1) + availableIx = leastInterestingIx; + if (availableIx != -1) { - if (sensoryNeuroids[availableIx] != null) { - // Debug.Log($"revived receptor {availableIx} for {thingId}"); - sensoryNeuroids[availableIx].receptor.thingId = thingId; - sensoryNeuroids[availableIx].receptor.position = localPosition; + // Debug.Log($"new receptor for {thingId}"); + SensoryNeuroid neuroid = new(neuroidNet, thingId) { name = name }; + foreach (Receiver receiver in positionReceivers) { + if (receiver.thingType == 0 || receiver.thingType == thingType) + receiver.neuroid.GetInputFrom(neuroid); } - else { - // Debug.Log($"new receptor for {thingId}"); - SensoryNeuroid neuroid = new(neuroidNet, thingId); - foreach (Receiver receiver in positionReceivers) { - if (receiver.thingType == 0 || receiver.thingType == thingType) - receiver.neuroid.GetInputFrom(neuroid); - } - foreach (Receiver receiver in velocityReceivers) { - if (receiver.thingType == 0 || receiver.thingType == thingType) - receiver.neuroid.GetInputFrom(neuroid.velocityNeuroid); - } - - sensoryNeuroids[availableIx] = neuroid; - neuroid.receptor.position = localPosition; + foreach (Receiver receiver in velocityReceivers) { + if (receiver.thingType == 0 || receiver.thingType == thingType) + receiver.neuroid.GetInputFrom(neuroid.velocityNeuroid); } - } - else if (leastInterestingNeuroid != null) { - //Debug.Log($"replaced receptor {leastInterestingNeuroid.thingId} for {thingId}"); - leastInterestingNeuroid.receptor.thingId = thingId; - leastInterestingNeuroid.receptor.position = localPosition; - } - //Debug.LogWarning($"No available receptor for {id}"); + sensoryNeuroids[availableIx] = neuroid; + neuroid.receptor.position = localPosition; + } } public void RemoveStimulus(int thingId) { @@ -103,6 +92,6 @@ public class Perception : Nucleus { return; } } - + } } \ No newline at end of file diff --git a/Assets/Scenes/Boids/Boids.unity b/Assets/Scenes/Boids/Boids.unity index e7ee4e7..ce4720b 100644 --- a/Assets/Scenes/Boids/Boids.unity +++ b/Assets/Scenes/Boids/Boids.unity @@ -393,7 +393,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec888ca5333d45a438f9f417fa5ce135, type: 3} m_Name: m_EditorClassIdentifier: Assembly-CSharp::SwarmSpawn - count: 1 + count: 2 boidPrefab: {fileID: 8702527964058765413, guid: f9c706268554ce449a8773675b2864b8, type: 3} spawnAreaSize: {x: 0.5, y: 0.5, z: 0.5} minDelay: 0.05 diff --git a/Assets/Scenes/Boids/Scripts/Boid.cs b/Assets/Scenes/Boids/Scripts/Boid.cs index b3326fe..9a2f7c8 100644 --- a/Assets/Scenes/Boids/Scripts/Boid.cs +++ b/Assets/Scenes/Boids/Scripts/Boid.cs @@ -21,15 +21,10 @@ public class Boid : MonoBehaviour { private Bounds innerBounds; private Bounds outerBounds; - readonly Collider[] results = new Collider[10]; - public NeuroidNetwork neuroidNet = new(); public Perception perception; - public Neuroid cohesion; - public Neuroid alignment; - public Neuroid avoidance; - // public Neuroid boundary; - public Roaming roaming; + + public Nucleus behaviour; public Neuroid totalForce; @@ -45,53 +40,34 @@ public class Boid : MonoBehaviour { perception = new Perception(neuroidNet); - // cohesion = new(neuroidNet, "Cohesion"); - // perception.SendPositions(cohesion, 1.0f, BoidType); - - // alignment = new(neuroidNet, "Alignment") { average = true }; - // perception.SendVelocities(alignment); - - // avoidance = new(neuroidNet, "Separation") { inverse = true }; - // perception.SendPositions(avoidance, sc.avoidanceForce); - - //boundary = new(neuroidNet, "Boundary"); - - roaming = new(neuroidNet, perception, sc); + //behaviour = new Roaming(neuroidNet, perception, sc); + behaviour = new Swarming(neuroidNet, perception, sc); totalForce = new(neuroidNet, "Total"); - //totalForce.GetInputFrom(alignment, sc.alignmentForce); - //totalForce.GetInputFrom(cohesion, sc.cohesionForce); - // totalForce.GetInputFrom(avoidance, -sc.avoidanceForce); - //totalForce.GetInputFrom(boundary, sc.boundaryForce); - roaming.AddReceiver(totalForce); + behaviour.AddReceiver(totalForce); } void Update() { - // Physics.OverlapSphereNonAlloc(this.transform.position, sc.perceptionDistance, results); - // foreach (Collider c in results) { - // if (c == null) - // continue; + Collider[] results = Physics.OverlapSphere(this.transform.position, sc.perceptionDistance); + foreach (Collider c in results) { + if (c as CapsuleCollider != null) { + Boid neighbour = c.GetComponentInParent(); + if (neighbour == null || neighbour == this) + continue; - // if (c as CapsuleCollider != null) { - // Boid neighbour = c.GetComponentInParent(); - // if (neighbour == null || neighbour == this) - // continue; + Vector3 localPosition = neighbour.transform.position - this.transform.position; - // Vector3 localPosition = neighbour.transform.position - this.transform.position; - // if (debug) - // Debug.Log($" distance {localPosition.magnitude}"); - - // int thingId = neighbour.GetInstanceID(); - // perception.ProcessStimulus(thingId, localPosition); - // } - // } + int thingId = neighbour.GetInstanceID(); + perception.ProcessStimulus(thingId, BoidType, localPosition); //, neighbour.gameObject.name); + } + } if (!innerBounds.Contains(this.transform.position)) { Vector3 point = this.transform.position; Vector3 pointOnBounds = innerBounds.ClosestPoint(point); Vector3 desiredWorldSpace = (pointOnBounds - point).normalized * sc.speed; Vector3 desiredLocalSpace = -this.transform.InverseTransformPoint(desiredWorldSpace); - perception.ProcessStimulus(777, BoundaryType, desiredLocalSpace); + perception.ProcessStimulus(777, BoundaryType, desiredLocalSpace, "Boundary"); } else { perception.RemoveStimulus(777); diff --git a/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs b/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs index a8889c6..50b6912 100644 --- a/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs +++ b/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs @@ -1,18 +1,11 @@ public class Roaming : Nucleus { - public float avoidanceForce; public Neuroid avoidance; - public Neuroid output; - - - public const int BoundaryType = 1; - public const int BoidType = 2; - - public Roaming(NeuroidNetwork neuroidNet, Perception perception, SwarmControl sc) : base(neuroidNet) { - this.avoidanceForce = sc.avoidanceForce; + public Neuroid output; + public Roaming(NeuroidNetwork neuroidNet, Perception perception, SwarmControl sc) : base("Roaming nucleus") { avoidance = new(neuroidNet, "Avoidance") { inverse = true }; - perception.SendPositions(avoidance); + perception.SendPositions(avoidance, 1.0f, 1); this.output = new(neuroidNet, "Roaming"); output.GetInputFrom(avoidance, -sc.avoidanceForce); diff --git a/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs b/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs index f6ec099..f416c38 100644 --- a/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs +++ b/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs @@ -1,31 +1,34 @@ -public class Swarming : Nucleus { - //public Perception perception; +using UnityEngine; +public class Swarming : Nucleus { public Neuroid cohesion; public Neuroid alignment; public Neuroid avoidance; - public Neuroid boundary; public Neuroid output; + public override Vector3 outputValue { get => output.outputValue; set => output.outputValue = value; } + public const int BoundaryType = 1; public const int BoidType = 2; - public Swarming(NeuroidNetwork neuroidNet, Perception perception, SwarmControl sc) : base(neuroidNet) { - cohesion = new(neuroidNet, "Cohesion"); - perception.SendPositions(cohesion, 1.0f, BoidType); + public Swarming(NeuroidNetwork neuroidNet, Perception perception, SwarmControl sc) : base("Swarming Nucleus") { + this.cohesion = new(neuroidNet, "Cohesion"); + perception.SendPositions(this.cohesion, 1.0f, BoidType); - alignment = new(neuroidNet, "Alignment") { average = true }; - perception.SendVelocities(alignment); + this.alignment = new(neuroidNet, "Alignment") { average = true }; + perception.SendVelocities(this.alignment, 1.0f, BoidType); - avoidance = new(neuroidNet, "Separation") { inverse = true }; - perception.SendPositions(avoidance, sc.avoidanceForce); - - boundary = new(neuroidNet, "Boundary"); + this.avoidance = new(neuroidNet, "Avoidance") { inverse = true }; + perception.SendPositions(this.avoidance); this.output = new(neuroidNet, "Swarming"); - output.GetInputFrom(alignment, sc.alignmentForce); - output.GetInputFrom(cohesion, sc.cohesionForce); - output.GetInputFrom(avoidance, -sc.avoidanceForce); - output.GetInputFrom(boundary, sc.boundaryForce); - }} \ No newline at end of file + //this.output.GetInputFrom(alignment, sc.alignmentForce); + this.output.GetInputFrom(cohesion, sc.cohesionForce); + this.output.GetInputFrom(avoidance, -sc.avoidanceForce); + } + + public override void AddReceiver(Neuroid receiver) { + this.output.AddReceiver(receiver); + } +} \ No newline at end of file From 145e033d4c3389f729e2fd0096805108581619ca Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 3 Dec 2025 10:16:36 +0100 Subject: [PATCH 013/179] Simplified synapses, NanoBrain component --- Assembly-CSharp-Editor.csproj | 1 + Assembly-CSharp.csproj | 1 + Assets/NanoBrain/Editor/NanoBrain_Editor.cs | 203 ++++++++++++++++++ .../NanoBrain/Editor/NanoBrain_Editor.cs.meta | 2 + Assets/NanoBrain/Editor/NeuroidWindow.cs | 21 +- Assets/NanoBrain/NanoBrain.cs | 19 ++ Assets/NanoBrain/NanoBrain.cs.meta | 2 + Assets/NanoBrain/Neuroid.cs | 103 ++++----- Assets/NanoBrain/Nucleus.cs | 2 +- Assets/NanoBrain/Perception.cs | 10 +- Assets/NanoBrain/SensoryNeuroid.cs | 80 ++++--- Assets/Scenes/Boids/Boids.unity | 2 +- Assets/Scenes/Boids/Scripts/Boid.cs | 22 +- Assets/Scenes/Boids/Scripts/RoamingNucleus.cs | 3 +- .../Scenes/Boids/Scripts/SwarmingNucleus.cs | 5 +- 15 files changed, 364 insertions(+), 112 deletions(-) create mode 100644 Assets/NanoBrain/Editor/NanoBrain_Editor.cs create mode 100644 Assets/NanoBrain/Editor/NanoBrain_Editor.cs.meta create mode 100644 Assets/NanoBrain/NanoBrain.cs create mode 100644 Assets/NanoBrain/NanoBrain.cs.meta diff --git a/Assembly-CSharp-Editor.csproj b/Assembly-CSharp-Editor.csproj index 584a691..23e17fc 100644 --- a/Assembly-CSharp-Editor.csproj +++ b/Assembly-CSharp-Editor.csproj @@ -48,6 +48,7 @@ + diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index cc63681..06d6dd6 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -50,6 +50,7 @@ + diff --git a/Assets/NanoBrain/Editor/NanoBrain_Editor.cs b/Assets/NanoBrain/Editor/NanoBrain_Editor.cs new file mode 100644 index 0000000..39d8287 --- /dev/null +++ b/Assets/NanoBrain/Editor/NanoBrain_Editor.cs @@ -0,0 +1,203 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; + +[CustomEditor(typeof(NanoBrain))] +public class NanoBrain_Editor : Editor { + private Nucleus currentNucleus; + private List layers = new(); + private Dictionary neuroidPositions = new(); + + #region Start + + private void OnEnable() { + SelectNeuron(); + } + + private void SelectNeuron() { + GameObject selectedObject = ((NanoBrain)target).gameObject; + if (!selectedObject.TryGetComponent(out Boid boid)) + return; + + Neuroid neuroid = boid.totalForce; + this.currentNucleus = neuroid; + + BuildLayers(); + Debug.Log($"Layercount = {this.layers.Count}"); + } + + #endregion Start + + #region Update + + public override void OnInspectorGUI() { + DrawGraph(); + + DrawDefaultInspector(); + } + + private void BuildLayers() { + // A temporary list to track what's been added to layers + this.layers = new(); + int layerIx = 0; + + Nucleus selectedNucleus = this.currentNucleus; + if (selectedNucleus == null) + return; + NeuroidLayer currentLayer = new() { ix = layerIx }; + + foreach (Neuroid outputNeuroid in selectedNucleus.outputNeuroids) { + if (outputNeuroid != null) { + AddToLayer(currentLayer, outputNeuroid); + Debug.Log($"layer {layerIx} nucleus {outputNeuroid.name}"); + } + } + if (currentLayer.neuroids.Count > 0) { + this.layers.Add(currentLayer); + layerIx++; + currentLayer = new() { ix = layerIx }; + } + + AddToLayer(currentLayer, selectedNucleus); + this.layers.Add(currentLayer); + Debug.Log($"layer {layerIx} nucleus {selectedNucleus.name}"); + + layerIx++; + currentLayer = new() { ix = layerIx }; + + foreach (Nucleus input in selectedNucleus.synapses.Keys) { + AddToLayer(currentLayer, input); + Debug.Log($"layer {layerIx} nucleus {input.name}"); + } + if (currentLayer.neuroids.Count > 0) { + this.layers.Add(currentLayer); + } + } + + private void AddToLayer(NeuroidLayer layer, Nucleus nucleus) { + layer.neuroids.Add(nucleus); + nucleus.layerIx = layer.ix; + // Store its position + Vector2Int neuroidPosition = new(layer.ix, layer.neuroids.Count - 1); + neuroidPositions[nucleus] = neuroidPosition; + + } + + private void DrawGraph() { + if (currentNucleus == null) + return; + Rect outer = EditorGUILayout.GetControlRect(false, 400); + GUI.BeginGroup(outer); + foreach (NeuroidLayer layer in layers) + DrawLayer(layer); + GUI.EndGroup(); + } + + private void DrawLayer(NeuroidLayer layer) { + int nodeCount = layer.neuroids.Count; + float maxValue = 0; + foreach (Nucleus nucleus in layer.neuroids) { + if (nucleus is Neuroid neuroid) { + float value = neuroid.outputValue.magnitude; + if (value > maxValue) + maxValue = value; + } + } + float spacing = 400f / nodeCount; + float margin = 10 + spacing / 2; + foreach (Nucleus layerNucleus in layer.neuroids) { + if (layerNucleus is Neuroid layerNeuroid) { + Vector2Int layerNeuroidPos = this.neuroidPositions[layerNeuroid]; + Vector3 parentPos = new(100 + layerNeuroidPos.x * 100, margin + layerNeuroidPos.y * spacing, 0.1f); + + int i = 0; + float inputSpacing = 400f / layerNeuroid.synapses.Count; + float inputMargin = 10 + inputSpacing / 2; + // foreach (Synapse synapse in layerNeuroid.synapses.Values) { + // if (synapse.neuroid != null) { + // if (this.neuroidPositions.ContainsKey(synapse.neuroid)) { + + // Vector2Int inputNeuroidPos = this.neuroidPositions[synapse.neuroid]; + foreach ((Nucleus neuroid, Synapse synapse) in layerNeuroid.synapses) { + if (neuroid != null) { + if (this.neuroidPositions.ContainsKey(neuroid)) { + Vector2Int inputNeuroidPos = this.neuroidPositions[neuroid]; + if (inputNeuroidPos.x == layerNeuroidPos.x + 1) { + Vector3 pos = new(100 + inputNeuroidPos.x * 100, inputMargin + inputNeuroidPos.y * inputSpacing, 0.0f); + + float brightness = synapse.weight / 10.0f; + Handles.color = new Color(brightness, brightness, brightness); + Handles.DrawLine(parentPos, pos); + } + } + } + } + + float size = 20; + if (layerNeuroid.IsStale()) + Handles.color = Color.black; + else { + float brightness = layerNeuroid.outputValue.magnitude / maxValue; + Handles.color = new Color(brightness, brightness, brightness); + } + Handles.DrawSolidDisc(parentPos, Vector3.forward, size); + Vector3 labelPos = parentPos - Vector3.down * (size + 0.2f); // below disc along up axis + GUIStyle style = new GUIStyle(EditorStyles.label) { + alignment = TextAnchor.UpperCenter, + normal = { textColor = Color.white }, + fontStyle = FontStyle.Bold + }; + Handles.Label(labelPos, layerNeuroid.name, style); + + Rect neuronRect = new(parentPos.x - size, parentPos.y - size, size * 2, size * 2); + int id = GUIUtility.GetControlID(FocusType.Passive); + Event e = Event.current; + EventType et = e.GetTypeForControl(id); + if (e != null && neuronRect.Contains(e.mousePosition)) { + HandleMouseHover(layerNeuroid, neuronRect); + // Process click + Debug.Log($"{et}"); + if (et == EventType.MouseDown && e.button == 0) { + // Consume the event so the scene doesn't also handle it + e.Use(); + HandleDiscClicked(layerNeuroid); + } + } + i++; + } + } + } + + private void HandleMouseHover(Neuroid neuroid, Rect rect) { + GUIContent tooltip; + if (neuroid is SensoryNeuroid sensoryNeuroid) { + tooltip = new( + $"{sensoryNeuroid.name}" + + $"\nThing {sensoryNeuroid.receptor.thingId}" + + $"\nValue: {neuroid.outputValue}" + + $"\nStale: {neuroid.stale}"); + } + else { + tooltip = new( + $"{neuroid.name}" + + $"\nsynapse count {neuroid.synapses.Count}" + + $"\nValue: {neuroid.outputValue}" + + $"\nStale: {neuroid.stale}"); + } + + Vector2 mousePosition = Event.current.mousePosition; + + // Display tooltip with some offset + Vector2 tooltipSize = GUI.skin.box.CalcSize(tooltip); + Rect tooltipRect = new Rect(mousePosition.x + 10, mousePosition.y + 10, tooltipSize.x, tooltipSize.y); + + GUI.Box(tooltipRect, tooltip); + } + + private void HandleDiscClicked(Nucleus nucleus) { + this.currentNucleus = nucleus; + BuildLayers(); + } + + #endregion Update +} diff --git a/Assets/NanoBrain/Editor/NanoBrain_Editor.cs.meta b/Assets/NanoBrain/Editor/NanoBrain_Editor.cs.meta new file mode 100644 index 0000000..ebb08bb --- /dev/null +++ b/Assets/NanoBrain/Editor/NanoBrain_Editor.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 2299b68d073cc5c31915f591deb79ddc \ No newline at end of file diff --git a/Assets/NanoBrain/Editor/NeuroidWindow.cs b/Assets/NanoBrain/Editor/NeuroidWindow.cs index 72f9a9b..62db660 100644 --- a/Assets/NanoBrain/Editor/NeuroidWindow.cs +++ b/Assets/NanoBrain/Editor/NeuroidWindow.cs @@ -36,6 +36,8 @@ public class GraphEditorWindow : EditorWindow { int layerIx = 0; Nucleus selectedNucleus = this.currentNucleus; + if (selectedNucleus == null) + return; NeuroidLayer currentLayer = new() { ix = layerIx }; foreach (Neuroid outputNeuroid in selectedNucleus.outputNeuroids) { @@ -58,9 +60,10 @@ public class GraphEditorWindow : EditorWindow { currentLayer = new() { ix = layerIx }; int six = 0; - foreach (Synapse synapse in selectedNucleus.synapses.Values) { - Debug.Log($"Synapse {six}"); - Nucleus input = synapse.neuroid; + // foreach (Synapse synapse in selectedNucleus.synapses.Values) { + // Debug.Log($"Synapse {six}"); + // Nucleus input = synapse.neuroid; + foreach ((Nucleus input, Synapse synapse) in selectedNucleus.synapses) { if (input != null) { AddToLayer(currentLayer, input); Debug.Log($"layer {layerIx} nucleus {input.name}"); @@ -172,11 +175,15 @@ public class GraphEditorWindow : EditorWindow { int i = 0; float inputSpacing = 400f / layerNeuroid.synapses.Count; float inputMargin = 100 + inputSpacing / 2; - foreach (Synapse synapse in layerNeuroid.synapses.Values) { - if (synapse.neuroid != null) { - if (this.neuroidPositions.ContainsKey(synapse.neuroid)) { + // foreach (Synapse synapse in layerNeuroid.synapses.Values) { + // if (synapse.neuroid != null) { + // if (this.neuroidPositions.ContainsKey(synapse.neuroid)) { - Vector2Int inputNeuroidPos = this.neuroidPositions[synapse.neuroid]; + // Vector2Int inputNeuroidPos = this.neuroidPositions[synapse.neuroid]; + foreach ((Nucleus neuroid, Synapse synapse) in layerNeuroid.synapses) { + if (neuroid != null) { + if (this.neuroidPositions.ContainsKey(neuroid)) { + Vector2Int inputNeuroidPos = this.neuroidPositions[neuroid]; if (inputNeuroidPos.x == layerNeuroidPos.x + 1) { Vector3 pos = new(100 + inputNeuroidPos.x * 100, inputMargin + inputNeuroidPos.y * inputSpacing, 0.0f); diff --git a/Assets/NanoBrain/NanoBrain.cs b/Assets/NanoBrain/NanoBrain.cs new file mode 100644 index 0000000..43a9e33 --- /dev/null +++ b/Assets/NanoBrain/NanoBrain.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using UnityEngine; + +public class NanoBrain : MonoBehaviour { + public List neuroids = new(); + + public Neuroid AddNeuron(string name) { + Neuroid neuroid = new(this, name); + return neuroid; + } + + public void Update() { + foreach (Neuroid neuroid in neuroids) { + neuroid.stale++; + if (neuroid.IsStale()) + neuroid.outputValue = Vector3.zero; + } + } +} diff --git a/Assets/NanoBrain/NanoBrain.cs.meta b/Assets/NanoBrain/NanoBrain.cs.meta new file mode 100644 index 0000000..078dc8f --- /dev/null +++ b/Assets/NanoBrain/NanoBrain.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 74e1478743ac3bc078cbe8501c287e98 \ No newline at end of file diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index f4ff48b..3589f4d 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -3,32 +3,30 @@ using UnityEngine; using System.Linq; public class Synapse { - public Synapse(Nucleus neuroid, Vector3 value, float weight) { - this.neuroid = neuroid; - this.value = value; + public Synapse(Nucleus neuroid, float weight = 1.0f) { + //this.neuroid = neuroid; this.weight = weight; } - public Nucleus neuroid; - public Vector3 value; + //public Nucleus neuroid; public float weight; } -public class NeuroidNetwork { - public List neuroids = new(); +// public class NeuroidNetwork { +// public List neuroids = new(); - public Neuroid AddNeuron(string name) { - Neuroid neuroid = new(this, name); - return neuroid; - } +// public Neuroid AddNeuron(string name) { +// Neuroid neuroid = new(this, name); +// return neuroid; +// } - public void Update() { - foreach (Neuroid neuroid in neuroids) { - neuroid.stale++; - if (neuroid.IsStale()) - neuroid.outputValue = Vector3.zero; - } - } -} +// public void Update() { +// foreach (Neuroid neuroid in neuroids) { +// neuroid.stale++; +// if (neuroid.IsStale()) +// neuroid.outputValue = Vector3.zero; +// } +// } +// } public class Neuroid : Nucleus { public int stale = 0; @@ -40,19 +38,21 @@ public class Neuroid : Nucleus { public bool inverse = false; public float exponent = 1.0f; - public NeuroidNetwork net; + //public NeuroidNetwork net; + public NanoBrain net; - public Neuroid(NeuroidNetwork net, string name) : base(name) { + // public Neuroid(NeuroidNetwork net, string name) : base(name) { + public Neuroid(NanoBrain net, string name) : base(name) { this.net = net; if (this.net != null) this.net.neuroids.Add(this); - else + else Debug.LogError("No neuroid network"); } public void AddSynapse(Neuroid input) { input.AddReceiver(this); - this.synapses[input] = new(input, Vector3.zero, 1.0f); + this.synapses[input] = new(input); } // public void AddReceiver(Neuroid receiver) { @@ -69,33 +69,28 @@ public class Neuroid : Nucleus { this.synapses[input].weight = weight; } else { - this.synapses[input] = new(input, Vector3.zero, weight); + this.synapses[input] = new(input, weight); } } public void GetInputFrom(Neuroid input, float weight = 1.0f) { input.AddReceiver(this); - this.synapses[input] = new(input, Vector3.zero, weight); + this.synapses[input] = new(input, weight); } - public void SetInput(Neuroid input, Vector3 value) { - if (this.synapses.ContainsKey(input)) { - Synapse synapse = this.synapses[input]; - synapse.value = value; - } - else - this.synapses[input] = new(null, value, 1.0f); + public void SetInput(Neuroid input) { + if (this.synapses.ContainsKey(input) == false) + this.synapses[input] = new(input); UpdateState(); } - public void SetInput(Neuroid input, Vector3 value, float weight) { + public void SetInput(Neuroid input, float weight) { if (this.synapses.ContainsKey(input)) { Synapse synapse = this.synapses[input]; - synapse.value = value; synapse.weight = weight; } else - this.synapses[input] = new(null, value, weight); + this.synapses[input] = new(input, weight); UpdateState(); } @@ -105,38 +100,28 @@ public class Neuroid : Nucleus { // In case this was the last synapse, we reset the output because in this case no updates from synapses will follow. this.outputValue = Vector3.zero; foreach (Neuroid neuroid in this.outputNeuroids) - neuroid.SetInput(this, this.outputValue); + neuroid.SetInput(this); } } - // public readonly Dictionary fakeNeuroids = new(); - // public void SetInput(int thingId, Vector3 value, float weight, NeuroidNetwork net) { - // if (fakeNeuroids.ContainsKey(thingId)) { - // Neuroid fakeInput = fakeNeuroids[thingId]; - // Synapse synapse = this.synapses[fakeInput]; - // synapse.value = value; - // synapse.weight = weight; - // } - // else { - // fakeNeuroids[thingId] = new(net); - // this.synapses[fakeNeuroids[thingId]] = new(null, value, weight); - // } - // UpdateState(); - // } - - protected virtual void UpdateState() { + public virtual void UpdateState() { Vector3 result = Vector3.zero; - foreach (Synapse synapse in this.synapses.Values) { - // if (synapse.neuroid == null) - // continue; - Vector3 direction = synapse.value.normalized; - float magnitude = synapse.value.magnitude; + foreach ((Nucleus nucleus, Synapse synapse) in this.synapses) { + // foreach (Synapse synapse in this.synapses.Values) { + // if (synapse.neuroid == null) + // Debug.LogWarning(" disconnected synapse"); + // if (synapse.value != synapse.neuroid.outputValue) + // Debug.LogWarning("synapse value error"); + // Vector3 direction = synapse.value.normalized; + // float magnitude = synapse.value.magnitude; // Vector3 direction = synapse.neuroid.outputValue.normalized; // float magnitude = synapse.neuroid.outputValue.magnitude; + Vector3 direction = nucleus.outputValue.normalized; + float magnitude = nucleus.outputValue.magnitude; magnitude = synapse.weight * Mathf.Pow(magnitude, exponent); - if (inverse) + if (inverse && magnitude > 0) magnitude = 1 / magnitude; result += direction * magnitude; } @@ -145,7 +130,7 @@ public class Neuroid : Nucleus { this.outputValue = result; foreach (Neuroid neuroid in this.outputNeuroids) - neuroid.SetInput(this, this.outputValue); + neuroid.SetInput(this); this.stale = 0; } diff --git a/Assets/NanoBrain/Nucleus.cs b/Assets/NanoBrain/Nucleus.cs index 6fac46d..b8e4a15 100644 --- a/Assets/NanoBrain/Nucleus.cs +++ b/Assets/NanoBrain/Nucleus.cs @@ -16,6 +16,6 @@ public class Nucleus { public virtual void AddReceiver(Neuroid receiver) { this.outputNeuroids.Add(receiver); - receiver.synapses[this] = new(this, Vector3.zero, 1.0f); + receiver.synapses[this] = new(this); } } \ No newline at end of file diff --git a/Assets/NanoBrain/Perception.cs b/Assets/NanoBrain/Perception.cs index c38f12b..bd9cfe4 100644 --- a/Assets/NanoBrain/Perception.cs +++ b/Assets/NanoBrain/Perception.cs @@ -5,7 +5,8 @@ using UnityEngine; public class Perception : Nucleus { public SensoryNeuroid[] sensoryNeuroids = new SensoryNeuroid[7]; - public NeuroidNetwork neuroidNet { get; protected set; } + // public NeuroidNetwork neuroidNet { get; protected set; } + public NanoBrain neuroidNet { get; protected set; } public class Receiver { public int thingType = 0; @@ -15,7 +16,8 @@ public class Perception : Nucleus { public HashSet positionReceivers { get; protected set; } public HashSet velocityReceivers { get; protected set; } - public Perception(NeuroidNetwork neuroidNet) : base("Perception") { + // public Perception(NeuroidNetwork neuroidNet) : base("Perception") { + public Perception(NanoBrain neuroidNet) : base("Perception") { this.neuroidNet = neuroidNet; this.positionReceivers = new(); this.velocityReceivers = new(); @@ -30,7 +32,7 @@ public class Perception : Nucleus { foreach (SensoryNeuroid neuroid in sensoryNeuroids) { if (neuroid != null) { neuroid.AddReceiver(receivingNeuroid); - receivingNeuroid.synapses[neuroid] = new(neuroid, Vector3.zero, weight); + receivingNeuroid.synapses[neuroid] = new(neuroid, weight); } } } @@ -43,7 +45,7 @@ public class Perception : Nucleus { foreach (SensoryNeuroid neuroid in sensoryNeuroids) { if (neuroid != null && neuroid.velocityNeuroid != null) { neuroid.velocityNeuroid.AddReceiver(receivingNeuroid); - receivingNeuroid.synapses[neuroid] = new(neuroid, Vector3.zero, 1.0f); + receivingNeuroid.synapses[neuroid] = new(neuroid); } } } diff --git a/Assets/NanoBrain/SensoryNeuroid.cs b/Assets/NanoBrain/SensoryNeuroid.cs index 50558ec..a55fa02 100644 --- a/Assets/NanoBrain/SensoryNeuroid.cs +++ b/Assets/NanoBrain/SensoryNeuroid.cs @@ -1,13 +1,36 @@ +using System.Collections.Generic; using System.Linq; using UnityEngine; +public class Receptor { + + public SensoryNeuroid neuroid; + + public int thingId; + public Vector3 value; + + /// + /// Local position of the thing + /// + public virtual Vector3 position { + get { + return this.value; + } + set { + this.value = value; + neuroid.UpdateState(); + } + } +} + public class SensoryNeuroid : Neuroid { // A neuroid which has no neurons as input // But receives value from a receptor public Receptor receptor; public VelocityNeuroid velocityNeuroid; - public SensoryNeuroid(NeuroidNetwork net, int thingId) : base(net, "sensory neuroid") { + // public SensoryNeuroid(NeuroidNetwork net, int thingId) : base(net, "sensory neuroid") { + public SensoryNeuroid(NanoBrain net, int thingId) : base(net, "sensory neuroid") { this.receptor = new Receptor { neuroid = this, thingId = thingId @@ -17,27 +40,34 @@ public class SensoryNeuroid : Neuroid { this.AddReceiver(velocityNeuroid); } -} + public override void UpdateState() { + Vector3 result = receptor.value; + // SensoryNeuroid normally do not have synapses... + // foreach (Synapse synapse in this.synapses.Values) { + // if (synapse.neuroid == null) + // Debug.LogWarning(" disconnected synapse"); + // // if (synapse.value != synapse.neuroid.outputValue) + // // Debug.LogWarning("synapse value error"); + // // Vector3 direction = synapse.value.normalized; + // // float magnitude = synapse.value.magnitude; -public class Receptor { - - public SensoryNeuroid neuroid; - - public int thingId; - /// - /// Local position of the thing - /// - public virtual Vector3 position { - get { - if (neuroid != null) - return neuroid.synapses[neuroid].value; - else - return Vector3.zero; - } - set { - if (neuroid != null) - neuroid.SetInput(neuroid, value); + // Vector3 direction = synapse.neuroid.outputValue.normalized; + // float magnitude = synapse.neuroid.outputValue.magnitude; + foreach ((Nucleus nucleus, Synapse synapse) in this.synapses) { + Vector3 direction = nucleus.outputValue.normalized; + float magnitude = nucleus.outputValue.magnitude; + magnitude = synapse.weight * Mathf.Pow(magnitude, exponent); + if (inverse) + magnitude = 1 / magnitude; + result += direction * magnitude; } + if (average && this.synapses.Count > 0) + result /= this.synapses.Count + 1; + + this.outputValue = result; + foreach (Neuroid neuroid in this.outputNeuroids) + neuroid.SetInput(this); + this.stale = 0; } } @@ -46,12 +76,14 @@ public class VelocityNeuroid : Neuroid { private Vector3 lastPosition = Vector3.zero; private float lastValueTime = 0; - public VelocityNeuroid(NeuroidNetwork net) : base(net, "Velocity") { + // public VelocityNeuroid(NeuroidNetwork net) : base(net, "Velocity") { + public VelocityNeuroid(NanoBrain net) : base(net, "Velocity") { } - protected override void UpdateState() { + public override void UpdateState() { // Assuming only one synapse for now.... - Vector3 currentPosition = this.synapses.First().Value.value; + //Vector3 currentPosition = this.synapses.First().Value.neuroid.outputValue; + Vector3 currentPosition = this.synapses.First().Key.outputValue; float currentValueTime = Time.time; float deltaTime = currentValueTime - lastValueTime; @@ -61,7 +93,7 @@ public class VelocityNeuroid : Neuroid { // No activation function... this.outputValue = velocity; foreach (Neuroid receiver in outputNeuroids) - receiver?.SetInput(this, this.outputValue); + receiver?.SetInput(this); this.stale = 0; this.lastValueTime = Time.time; diff --git a/Assets/Scenes/Boids/Boids.unity b/Assets/Scenes/Boids/Boids.unity index ce4720b..9827fcf 100644 --- a/Assets/Scenes/Boids/Boids.unity +++ b/Assets/Scenes/Boids/Boids.unity @@ -371,7 +371,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 0464906885ae3494f8fd0314719fb2db, type: 3} m_Name: m_EditorClassIdentifier: Assembly-CSharp::SwarmControl - speed: 1 + speed: 2 inertia: 0.1 alignmentForce: 5 cohesionForce: 5 diff --git a/Assets/Scenes/Boids/Scripts/Boid.cs b/Assets/Scenes/Boids/Scripts/Boid.cs index 9a2f7c8..4b66dd9 100644 --- a/Assets/Scenes/Boids/Scripts/Boid.cs +++ b/Assets/Scenes/Boids/Scripts/Boid.cs @@ -1,16 +1,7 @@ using UnityEngine; - +[RequireComponent(typeof(NanoBrain))] public class Boid : MonoBehaviour { - // public float speed = 0.2f; - // public int neighbourCount = 0; - // public float inertia = 0.2f; - // public float alignmentForce = 1.0f; - // public float cohesionForce = 1.0f; - // public float separationForce = 1.0f; - // public float separationDistance = 0.5f; - // public float bodyForce = 1; - public const int BoundaryType = 1; public const int BoidType = 2; @@ -21,7 +12,8 @@ public class Boid : MonoBehaviour { private Bounds innerBounds; private Bounds outerBounds; - public NeuroidNetwork neuroidNet = new(); + //public NeuroidNetwork neuroidNet = new(); + public NanoBrain neuroidNet; public Perception perception; public Nucleus behaviour; @@ -31,6 +23,8 @@ public class Boid : MonoBehaviour { public int id; void Awake() { + neuroidNet = GetComponent(); + this.id = this.GetInstanceID(); sc = FindFirstObjectByType(); @@ -48,7 +42,7 @@ public class Boid : MonoBehaviour { } void Update() { - Collider[] results = Physics.OverlapSphere(this.transform.position, sc.perceptionDistance); + Collider[] results = Physics.OverlapSphere(this.transform.position, sc.perceptionDistance); foreach (Collider c in results) { if (c as CapsuleCollider != null) { Boid neighbour = c.GetComponentInParent(); @@ -103,7 +97,9 @@ public class Boid : MonoBehaviour { } void OnDrawGizmosSelected() { - Gizmos.DrawWireSphere(transform.position, sc.perceptionDistance); + if (sc == null) + return; + Gizmos.DrawWireSphere(this.transform.position, sc.perceptionDistance); Gizmos.color = Color.yellow; Vector3 worldForce = this.transform.TransformDirection(totalForce.outputValue); Gizmos.DrawRay(transform.position, worldForce * 10); diff --git a/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs b/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs index 50b6912..ac510bf 100644 --- a/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs +++ b/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs @@ -3,7 +3,8 @@ public class Roaming : Nucleus { public Neuroid output; - public Roaming(NeuroidNetwork neuroidNet, Perception perception, SwarmControl sc) : base("Roaming nucleus") { + // public Roaming(NeuroidNetwork neuroidNet, Perception perception, SwarmControl sc) : base("Roaming nucleus") { + public Roaming(NanoBrain neuroidNet, Perception perception, SwarmControl sc) : base("Roaming nucleus") { avoidance = new(neuroidNet, "Avoidance") { inverse = true }; perception.SendPositions(avoidance, 1.0f, 1); diff --git a/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs b/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs index f416c38..23831bf 100644 --- a/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs +++ b/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs @@ -12,7 +12,8 @@ public class Swarming : Nucleus { public const int BoundaryType = 1; public const int BoidType = 2; - public Swarming(NeuroidNetwork neuroidNet, Perception perception, SwarmControl sc) : base("Swarming Nucleus") { + // public Swarming(NeuroidNetwork neuroidNet, Perception perception, SwarmControl sc) : base("Swarming Nucleus") { + public Swarming(NanoBrain neuroidNet, Perception perception, SwarmControl sc) : base("Swarming Nucleus") { this.cohesion = new(neuroidNet, "Cohesion"); perception.SendPositions(this.cohesion, 1.0f, BoidType); @@ -23,7 +24,7 @@ public class Swarming : Nucleus { perception.SendPositions(this.avoidance); this.output = new(neuroidNet, "Swarming"); - //this.output.GetInputFrom(alignment, sc.alignmentForce); + this.output.GetInputFrom(alignment, sc.alignmentForce); this.output.GetInputFrom(cohesion, sc.cohesionForce); this.output.GetInputFrom(avoidance, -sc.avoidanceForce); } From a3d49e330f3d129bccb2eaae34e9bf2301b27787 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 3 Dec 2025 15:15:42 +0100 Subject: [PATCH 014/179] removed synapse type --- Assets/NanoBrain/Editor/NanoBrain_Editor.cs | 61 +++++++----- Assets/NanoBrain/Editor/NeuroidWindow.cs | 17 ++-- Assets/NanoBrain/NanoBrain.cs | 2 +- Assets/NanoBrain/Neuroid.cs | 105 ++++++-------------- Assets/NanoBrain/Nucleus.cs | 12 ++- Assets/NanoBrain/Perception.cs | 60 +++++++---- Assets/NanoBrain/SensoryNeuroid.cs | 32 +++--- Assets/Scenes/Boids/Scripts/Boid.cs | 38 +++---- 8 files changed, 161 insertions(+), 166 deletions(-) diff --git a/Assets/NanoBrain/Editor/NanoBrain_Editor.cs b/Assets/NanoBrain/Editor/NanoBrain_Editor.cs index 39d8287..008646d 100644 --- a/Assets/NanoBrain/Editor/NanoBrain_Editor.cs +++ b/Assets/NanoBrain/Editor/NanoBrain_Editor.cs @@ -26,6 +26,7 @@ public class NanoBrain_Editor : Editor { Debug.Log($"Layercount = {this.layers.Count}"); } + #endregion Start #region Update @@ -46,10 +47,10 @@ public class NanoBrain_Editor : Editor { return; NeuroidLayer currentLayer = new() { ix = layerIx }; - foreach (Neuroid outputNeuroid in selectedNucleus.outputNeuroids) { + foreach (Neuroid outputNeuroid in selectedNucleus.receivers) { if (outputNeuroid != null) { AddToLayer(currentLayer, outputNeuroid); - Debug.Log($"layer {layerIx} nucleus {outputNeuroid.name}"); + // Debug.Log($"layer {layerIx} nucleus {outputNeuroid.name}"); } } if (currentLayer.neuroids.Count > 0) { @@ -60,14 +61,14 @@ public class NanoBrain_Editor : Editor { AddToLayer(currentLayer, selectedNucleus); this.layers.Add(currentLayer); - Debug.Log($"layer {layerIx} nucleus {selectedNucleus.name}"); + // Debug.Log($"layer {layerIx} nucleus {selectedNucleus.name}"); layerIx++; currentLayer = new() { ix = layerIx }; foreach (Nucleus input in selectedNucleus.synapses.Keys) { AddToLayer(currentLayer, input); - Debug.Log($"layer {layerIx} nucleus {input.name}"); + // Debug.Log($"layer {layerIx} nucleus {input.name}"); } if (currentLayer.neuroids.Count > 0) { this.layers.Add(currentLayer); @@ -110,32 +111,32 @@ public class NanoBrain_Editor : Editor { Vector2Int layerNeuroidPos = this.neuroidPositions[layerNeuroid]; Vector3 parentPos = new(100 + layerNeuroidPos.x * 100, margin + layerNeuroidPos.y * spacing, 0.1f); - int i = 0; + //int i = 0; float inputSpacing = 400f / layerNeuroid.synapses.Count; float inputMargin = 10 + inputSpacing / 2; - // foreach (Synapse synapse in layerNeuroid.synapses.Values) { - // if (synapse.neuroid != null) { - // if (this.neuroidPositions.ContainsKey(synapse.neuroid)) { + int minStale = 10000; + foreach ((Nucleus nucleus, float weight) in layerNeuroid.synapses) { + if (this.neuroidPositions.ContainsKey(nucleus)) { + Vector2Int inputNeuroidPos = this.neuroidPositions[nucleus]; + if (inputNeuroidPos.x == layerNeuroidPos.x + 1) { + Vector3 pos = new(100 + inputNeuroidPos.x * 100, inputMargin + inputNeuroidPos.y * inputSpacing, 0.0f); - // Vector2Int inputNeuroidPos = this.neuroidPositions[synapse.neuroid]; - foreach ((Nucleus neuroid, Synapse synapse) in layerNeuroid.synapses) { - if (neuroid != null) { - if (this.neuroidPositions.ContainsKey(neuroid)) { - Vector2Int inputNeuroidPos = this.neuroidPositions[neuroid]; - if (inputNeuroidPos.x == layerNeuroidPos.x + 1) { - Vector3 pos = new(100 + inputNeuroidPos.x * 100, inputMargin + inputNeuroidPos.y * inputSpacing, 0.0f); - - float brightness = synapse.weight / 10.0f; - Handles.color = new Color(brightness, brightness, brightness); - Handles.DrawLine(parentPos, pos); - } + float brightness = weight / 10.0f; + Handles.color = new Color(brightness, brightness, brightness); + Handles.DrawLine(parentPos, pos); } } + if (nucleus is Neuroid neuroid && neuroid.stale < minStale) + minStale = neuroid.stale; } + if (layerNeuroid.synapses.Count > 0 && minStale > 2 && layerNeuroid.stale < 3) + Debug.LogWarning($"Strange {minStale} is big duing update"); + + float size = 20; if (layerNeuroid.IsStale()) - Handles.color = Color.black; + Handles.color = Color.darkCyan; else { float brightness = layerNeuroid.outputValue.magnitude / maxValue; Handles.color = new Color(brightness, brightness, brightness); @@ -154,16 +155,16 @@ public class NanoBrain_Editor : Editor { Event e = Event.current; EventType et = e.GetTypeForControl(id); if (e != null && neuronRect.Contains(e.mousePosition)) { + // Process Hover HandleMouseHover(layerNeuroid, neuronRect); // Process click - Debug.Log($"{et}"); if (et == EventType.MouseDown && e.button == 0) { // Consume the event so the scene doesn't also handle it e.Use(); HandleDiscClicked(layerNeuroid); } } - i++; + //i++; } } } @@ -199,5 +200,19 @@ public class NanoBrain_Editor : Editor { BuildLayers(); } + protected virtual void OnSceneGUI() { + NanoBrain brain = target as NanoBrain; + if (brain == null) + return; + + // Debug.DrawRay(brain.transform.position, Vector3.forward, Color.magenta); + // Handles.color = Color.green; + // Handles.DrawLine(brain.transform.position, brain.transform.position + Vector3.up); + Vector3 position = brain.transform.position; + Handles.color = Color.yellow; + Vector3 worldForce = brain.transform.TransformDirection(this.currentNucleus.outputValue); + Debug.DrawRay(position, worldForce * 10, Color.yellow); + } + #endregion Update } diff --git a/Assets/NanoBrain/Editor/NeuroidWindow.cs b/Assets/NanoBrain/Editor/NeuroidWindow.cs index 62db660..69d8a34 100644 --- a/Assets/NanoBrain/Editor/NeuroidWindow.cs +++ b/Assets/NanoBrain/Editor/NeuroidWindow.cs @@ -40,7 +40,7 @@ public class GraphEditorWindow : EditorWindow { return; NeuroidLayer currentLayer = new() { ix = layerIx }; - foreach (Neuroid outputNeuroid in selectedNucleus.outputNeuroids) { + foreach (Neuroid outputNeuroid in selectedNucleus.receivers) { if (outputNeuroid != null) { AddToLayer(currentLayer, outputNeuroid); Debug.Log($"layer {layerIx} nucleus {outputNeuroid.name}"); @@ -63,7 +63,8 @@ public class GraphEditorWindow : EditorWindow { // foreach (Synapse synapse in selectedNucleus.synapses.Values) { // Debug.Log($"Synapse {six}"); // Nucleus input = synapse.neuroid; - foreach ((Nucleus input, Synapse synapse) in selectedNucleus.synapses) { + //foreach ((Nucleus input, Synapse synapse) in selectedNucleus.synapses) { + foreach ((Nucleus input, float weight) in selectedNucleus.synapses) { if (input != null) { AddToLayer(currentLayer, input); Debug.Log($"layer {layerIx} nucleus {input.name}"); @@ -103,8 +104,8 @@ public class GraphEditorWindow : EditorWindow { // If the output neuroid is visited // Note: this does not yet work for multiple outputs yet (see the use of First()) - if (neuroid.outputNeuroids.Count == 0 // make sure the root neuroids are processed directly - || (neuronVisited.Contains(neuroid.outputNeuroids.First()) && neuroid.outputNeuroids.First().layerIx == layerIx - 1)) { + if (neuroid.receivers.Count == 0 // make sure the root neuroids are processed directly + || (neuronVisited.Contains(neuroid.receivers.First()) && neuroid.receivers.First().layerIx == layerIx - 1)) { // Add it to the next layer currentLayer.neuroids.Add(neuroid); neuroid.layerIx = layerIx; @@ -180,14 +181,16 @@ public class GraphEditorWindow : EditorWindow { // if (this.neuroidPositions.ContainsKey(synapse.neuroid)) { // Vector2Int inputNeuroidPos = this.neuroidPositions[synapse.neuroid]; - foreach ((Nucleus neuroid, Synapse synapse) in layerNeuroid.synapses) { + //foreach ((Nucleus neuroid, Synapse synapse) in layerNeuroid.synapses) { + foreach ((Nucleus neuroid, float weight) in layerNeuroid.synapses) { if (neuroid != null) { if (this.neuroidPositions.ContainsKey(neuroid)) { Vector2Int inputNeuroidPos = this.neuroidPositions[neuroid]; if (inputNeuroidPos.x == layerNeuroidPos.x + 1) { Vector3 pos = new(100 + inputNeuroidPos.x * 100, inputMargin + inputNeuroidPos.y * inputSpacing, 0.0f); - float brightness = synapse.weight / 10.0f; + //float brightness = synapse.weight / 10.0f; + float brightness = weight / 10.0f; Handles.color = new Color(brightness, brightness, brightness); Handles.DrawLine(parentPos, pos); } @@ -274,7 +277,7 @@ public class GraphEditorWindow : EditorWindow { if (neuroid == null) this.allNeuroids = new(); else - this.allNeuroids = neuroid.net.neuroids; + this.allNeuroids = neuroid.brain.neuroids; Debug.Log($"Neuroncount = {this.allNeuroids.Count}"); diff --git a/Assets/NanoBrain/NanoBrain.cs b/Assets/NanoBrain/NanoBrain.cs index 43a9e33..df9ef3b 100644 --- a/Assets/NanoBrain/NanoBrain.cs +++ b/Assets/NanoBrain/NanoBrain.cs @@ -9,7 +9,7 @@ public class NanoBrain : MonoBehaviour { return neuroid; } - public void Update() { + public void UpdateNeurons() { foreach (Neuroid neuroid in neuroids) { neuroid.stale++; if (neuroid.IsStale()) diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index 3589f4d..6f2e6dc 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -1,137 +1,90 @@ -using System.Collections.Generic; using UnityEngine; -using System.Linq; - -public class Synapse { - public Synapse(Nucleus neuroid, float weight = 1.0f) { - //this.neuroid = neuroid; - this.weight = weight; - } - //public Nucleus neuroid; - public float weight; -} - -// public class NeuroidNetwork { -// public List neuroids = new(); - -// public Neuroid AddNeuron(string name) { -// Neuroid neuroid = new(this, name); -// return neuroid; -// } - -// public void Update() { -// foreach (Neuroid neuroid in neuroids) { -// neuroid.stale++; -// if (neuroid.IsStale()) -// neuroid.outputValue = Vector3.zero; -// } -// } -// } public class Neuroid : Nucleus { public int stale = 0; - //public Vector3 outputValue; public bool average = false; - //public bool quadratic = false; public bool inverse = false; public float exponent = 1.0f; - //public NeuroidNetwork net; - public NanoBrain net; + public NanoBrain brain; - // public Neuroid(NeuroidNetwork net, string name) : base(name) { - public Neuroid(NanoBrain net, string name) : base(name) { - this.net = net; - if (this.net != null) - this.net.neuroids.Add(this); + public Neuroid(NanoBrain brain, string name) : base(name) { + this.brain = brain; + if (this.brain != null) + this.brain.neuroids.Add(this); else Debug.LogError("No neuroid network"); } public void AddSynapse(Neuroid input) { input.AddReceiver(this); - this.synapses[input] = new(input); - } - - // public void AddReceiver(Neuroid receiver) { - // this.outputNeuroids.Add(receiver); - // } - - public void ResetWeights() { - foreach (Synapse synapse in this.synapses.Values) - synapse.weight = 1.0f; + this.synapses[input] = 1.0f; } public void SetWeight(Neuroid input, float weight) { - if (this.synapses.ContainsKey(input)) { - this.synapses[input].weight = weight; - } - else { - this.synapses[input] = new(input, weight); - } + this.synapses[input] = weight; } public void GetInputFrom(Neuroid input, float weight = 1.0f) { input.AddReceiver(this); - this.synapses[input] = new(input, weight); + this.synapses[input] = weight; } public void SetInput(Neuroid input) { if (this.synapses.ContainsKey(input) == false) - this.synapses[input] = new(input); + this.synapses[input] = 1.0f; UpdateState(); } public void SetInput(Neuroid input, float weight) { - if (this.synapses.ContainsKey(input)) { - Synapse synapse = this.synapses[input]; - synapse.weight = weight; - } - else - this.synapses[input] = new(input, weight); + this.synapses[input] = weight; UpdateState(); } public void RemoveInputFrom(Neuroid input) { + if (this.synapses.Count == 0) + return; + this.synapses.Remove(input); if (this.synapses.Count == 0) { // In case this was the last synapse, we reset the output because in this case no updates from synapses will follow. this.outputValue = Vector3.zero; - foreach (Neuroid neuroid in this.outputNeuroids) + foreach (Neuroid neuroid in this.receivers) neuroid.SetInput(this); } } public virtual void UpdateState() { + // int minStale = 10000; Vector3 result = Vector3.zero; - foreach ((Nucleus nucleus, Synapse synapse) in this.synapses) { - // foreach (Synapse synapse in this.synapses.Values) { - // if (synapse.neuroid == null) - // Debug.LogWarning(" disconnected synapse"); - // if (synapse.value != synapse.neuroid.outputValue) - // Debug.LogWarning("synapse value error"); - // Vector3 direction = synapse.value.normalized; - // float magnitude = synapse.value.magnitude; - - // Vector3 direction = synapse.neuroid.outputValue.normalized; - // float magnitude = synapse.neuroid.outputValue.magnitude; + foreach ((Nucleus nucleus, float weight) in this.synapses) { + if (nucleus is Neuroid neuroid && neuroid.IsStale()) + continue; + Vector3 direction = nucleus.outputValue.normalized; float magnitude = nucleus.outputValue.magnitude; - magnitude = synapse.weight * Mathf.Pow(magnitude, exponent); + magnitude = weight * Mathf.Pow(magnitude, exponent); if (inverse && magnitude > 0) magnitude = 1 / magnitude; result += direction * magnitude; + + // if (nucleus is Neuroid neuroid && neuroid.stale < minStale) + // minStale = neuroid.stale; } if (average && this.synapses.Count > 0) result /= this.synapses.Count; this.outputValue = result; - foreach (Neuroid neuroid in this.outputNeuroids) - neuroid.SetInput(this); + + // if (minStale > 2) + // Debug.LogWarning($"Strange {minStale} is big duing update"); this.stale = 0; + + foreach (Neuroid receiver in this.receivers) + receiver.SetInput(this); } public bool IsStale() { diff --git a/Assets/NanoBrain/Nucleus.cs b/Assets/NanoBrain/Nucleus.cs index b8e4a15..0683d79 100644 --- a/Assets/NanoBrain/Nucleus.cs +++ b/Assets/NanoBrain/Nucleus.cs @@ -4,9 +4,9 @@ using UnityEngine; public class Nucleus { public string name; - public readonly Dictionary synapses = new(); - public HashSet outputNeuroids = new(); - public virtual Vector3 outputValue {get; set; } + public readonly Dictionary synapses = new(); + public HashSet receivers = new(); + public virtual Vector3 outputValue { get; set; } public int layerIx; @@ -15,7 +15,9 @@ public class Nucleus { } public virtual void AddReceiver(Neuroid receiver) { - this.outputNeuroids.Add(receiver); - receiver.synapses[this] = new(this); + //Debug.Log($"add receiver to {this} for {receiver} {receiver.GetHashCode()} {this.receivers.Count} {receiver.synapses.Count}"); + this.receivers.Add(receiver); + receiver.synapses[this] = 1.0f; // new(this); + //Debug.Log($"receiver # {this.receivers.Count} synapse count {receiver.synapses.Count}"); } } \ No newline at end of file diff --git a/Assets/NanoBrain/Perception.cs b/Assets/NanoBrain/Perception.cs index bd9cfe4..efc7970 100644 --- a/Assets/NanoBrain/Perception.cs +++ b/Assets/NanoBrain/Perception.cs @@ -32,7 +32,7 @@ public class Perception : Nucleus { foreach (SensoryNeuroid neuroid in sensoryNeuroids) { if (neuroid != null) { neuroid.AddReceiver(receivingNeuroid); - receivingNeuroid.synapses[neuroid] = new(neuroid, weight); + receivingNeuroid.synapses[neuroid] = weight; // new(neuroid, weight); } } } @@ -45,7 +45,7 @@ public class Perception : Nucleus { foreach (SensoryNeuroid neuroid in sensoryNeuroids) { if (neuroid != null && neuroid.velocityNeuroid != null) { neuroid.velocityNeuroid.AddReceiver(receivingNeuroid); - receivingNeuroid.synapses[neuroid] = new(neuroid); + receivingNeuroid.synapses[neuroid] = 1.0f; //new(neuroid); } } } @@ -54,42 +54,64 @@ public class Perception : Nucleus { int availableIx = -1; int leastInterestingIx = -1; for (int i = 0; i < sensoryNeuroids.Length; i++) { - if (sensoryNeuroids[i] == null || sensoryNeuroids[i].IsStale()) + if (sensoryNeuroids[i] == null) availableIx = i; else if (sensoryNeuroids[i].receptor.thingId == thingId) { sensoryNeuroids[i].receptor.position = localPosition; return; } - if (sensoryNeuroids[i] != null) { - if (leastInterestingIx == -1 || sensoryNeuroids[leastInterestingIx].receptor.position.magnitude > sensoryNeuroids[i].receptor.position.magnitude) + if (availableIx == -1) { + if (sensoryNeuroids[i].IsStale()) leastInterestingIx = i; + else if (sensoryNeuroids[i] != null) { + if (leastInterestingIx == -1 || sensoryNeuroids[leastInterestingIx].receptor.position.magnitude > sensoryNeuroids[i].receptor.position.magnitude) + leastInterestingIx = i; + } } } if (availableIx == -1) availableIx = leastInterestingIx; if (availableIx != -1) { - // Debug.Log($"new receptor for {thingId}"); - SensoryNeuroid neuroid = new(neuroidNet, thingId) { name = name }; - foreach (Receiver receiver in positionReceivers) { - if (receiver.thingType == 0 || receiver.thingType == thingType) - receiver.neuroid.GetInputFrom(neuroid); - } - foreach (Receiver receiver in velocityReceivers) { - if (receiver.thingType == 0 || receiver.thingType == thingType) - receiver.neuroid.GetInputFrom(neuroid.velocityNeuroid); - } + if (sensoryNeuroids[availableIx] != null) { + Debug.Log($"replace receptor for {thingId} at {availableIx}"); + SensoryNeuroid neuroid = sensoryNeuroids[availableIx]; + neuroid.Replace(thingId); + neuroid.name = name; + foreach (Receiver receiver in positionReceivers) { + if (receiver.thingType == 0 || receiver.thingType == thingType) + receiver.neuroid.GetInputFrom(neuroid); + } + foreach (Receiver receiver in velocityReceivers) { + if (receiver.thingType == 0 || receiver.thingType == thingType) + receiver.neuroid.GetInputFrom(neuroid.velocityNeuroid); + } + neuroid.receptor.position = localPosition; - sensoryNeuroids[availableIx] = neuroid; - neuroid.receptor.position = localPosition; + } + else { + Debug.Log($"new receptor for {thingId} at {availableIx}"); + SensoryNeuroid neuroid = new(neuroidNet, thingId) { name = name }; + foreach (Receiver receiver in positionReceivers) { + if (receiver.thingType == 0 || receiver.thingType == thingType) + receiver.neuroid.GetInputFrom(neuroid); + } + foreach (Receiver receiver in velocityReceivers) { + if (receiver.thingType == 0 || receiver.thingType == thingType) + receiver.neuroid.GetInputFrom(neuroid.velocityNeuroid); + } + + sensoryNeuroids[availableIx] = neuroid; + neuroid.receptor.position = localPosition; + } } } public void RemoveStimulus(int thingId) { for (int i = 0; i < sensoryNeuroids.Length; i++) { if (sensoryNeuroids[i] != null && sensoryNeuroids[i].receptor.thingId == thingId) { - foreach (Neuroid outputNeuroid in sensoryNeuroids[i].outputNeuroids) - outputNeuroid.RemoveInputFrom(sensoryNeuroids[i]); + foreach (Neuroid receiver in sensoryNeuroids[i].receivers) + receiver.RemoveInputFrom(sensoryNeuroids[i]); sensoryNeuroids[i] = null; return; } diff --git a/Assets/NanoBrain/SensoryNeuroid.cs b/Assets/NanoBrain/SensoryNeuroid.cs index a55fa02..c6c0bc7 100644 --- a/Assets/NanoBrain/SensoryNeuroid.cs +++ b/Assets/NanoBrain/SensoryNeuroid.cs @@ -40,23 +40,23 @@ public class SensoryNeuroid : Neuroid { this.AddReceiver(velocityNeuroid); } + public void Replace(int thingId) { + this.name = "sensory neuroid"; + this.receptor.thingId = thingId; + this.receptor.value = Vector3.zero; + this.outputValue = Vector3.zero; + this.receivers = new(); + this.AddReceiver(velocityNeuroid); + } + public override void UpdateState() { Vector3 result = receptor.value; - // SensoryNeuroid normally do not have synapses... - // foreach (Synapse synapse in this.synapses.Values) { - // if (synapse.neuroid == null) - // Debug.LogWarning(" disconnected synapse"); - // // if (synapse.value != synapse.neuroid.outputValue) - // // Debug.LogWarning("synapse value error"); - // // Vector3 direction = synapse.value.normalized; - // // float magnitude = synapse.value.magnitude; - - // Vector3 direction = synapse.neuroid.outputValue.normalized; - // float magnitude = synapse.neuroid.outputValue.magnitude; - foreach ((Nucleus nucleus, Synapse synapse) in this.synapses) { + //foreach ((Nucleus nucleus, Synapse synapse) in this.synapses) { + foreach ((Nucleus nucleus, float weight) in this.synapses) { Vector3 direction = nucleus.outputValue.normalized; float magnitude = nucleus.outputValue.magnitude; - magnitude = synapse.weight * Mathf.Pow(magnitude, exponent); + //magnitude = synapse.weight * Mathf.Pow(magnitude, exponent); + magnitude = weight * Mathf.Pow(magnitude, exponent); if (inverse) magnitude = 1 / magnitude; result += direction * magnitude; @@ -65,7 +65,7 @@ public class SensoryNeuroid : Neuroid { result /= this.synapses.Count + 1; this.outputValue = result; - foreach (Neuroid neuroid in this.outputNeuroids) + foreach (Neuroid neuroid in this.receivers) neuroid.SetInput(this); this.stale = 0; } @@ -82,7 +82,6 @@ public class VelocityNeuroid : Neuroid { public override void UpdateState() { // Assuming only one synapse for now.... - //Vector3 currentPosition = this.synapses.First().Value.neuroid.outputValue; Vector3 currentPosition = this.synapses.First().Key.outputValue; float currentValueTime = Time.time; @@ -92,10 +91,11 @@ public class VelocityNeuroid : Neuroid { // No activation function... this.outputValue = velocity; - foreach (Neuroid receiver in outputNeuroids) + foreach (Neuroid receiver in receivers) receiver?.SetInput(this); this.stale = 0; this.lastValueTime = Time.time; + this.lastPosition = currentPosition; } } \ No newline at end of file diff --git a/Assets/Scenes/Boids/Scripts/Boid.cs b/Assets/Scenes/Boids/Scripts/Boid.cs index 4b66dd9..0fdebd6 100644 --- a/Assets/Scenes/Boids/Scripts/Boid.cs +++ b/Assets/Scenes/Boids/Scripts/Boid.cs @@ -52,7 +52,7 @@ public class Boid : MonoBehaviour { Vector3 localPosition = neighbour.transform.position - this.transform.position; int thingId = neighbour.GetInstanceID(); - perception.ProcessStimulus(thingId, BoidType, localPosition); //, neighbour.gameObject.name); + perception.ProcessStimulus(thingId, BoidType, localPosition, neighbour.gameObject.name); } } @@ -63,9 +63,9 @@ public class Boid : MonoBehaviour { Vector3 desiredLocalSpace = -this.transform.InverseTransformPoint(desiredWorldSpace); perception.ProcessStimulus(777, BoundaryType, desiredLocalSpace, "Boundary"); } - else { - perception.RemoveStimulus(777); - } + // else { + // perception.RemoveStimulus(777); + // } Vector3 worldForce = this.transform.TransformDirection(totalForce.outputValue); @@ -82,7 +82,7 @@ public class Boid : MonoBehaviour { transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 2f); // Adjust the speed of rotation } - neuroidNet.Update(); + neuroidNet.UpdateNeurons(); } Vector3 ClosestPointOnBoundsSurface(Bounds b, Vector3 p) { @@ -96,18 +96,18 @@ public class Boid : MonoBehaviour { return b.center + d * m; } - void OnDrawGizmosSelected() { - if (sc == null) - return; - Gizmos.DrawWireSphere(this.transform.position, sc.perceptionDistance); - Gizmos.color = Color.yellow; - Vector3 worldForce = this.transform.TransformDirection(totalForce.outputValue); - Gizmos.DrawRay(transform.position, worldForce * 10); - // Gizmos.color = Color.magenta; - // Gizmos.DrawRay(transform.position, this.transform.TransformDirection(avoidance.outputValue) * 10); - // Debug.Log($"Avoidance {roaming.avoidance.outputValue} Roaming {roaming.output.outputValue} Total {totalForce.outputValue}"); - // Debug.Log($"WorldForce {worldForce} velocity {velocity} inertia {sc.inertia}"); - Gizmos.color = Color.blue; - Gizmos.DrawRay(transform.position, this.velocity * 10); - } + // void OnDrawGizmosSelected() { + // if (sc == null) + // return; + // Gizmos.DrawWireSphere(this.transform.position, sc.perceptionDistance); + // Gizmos.color = Color.yellow; + // Vector3 worldForce = this.transform.TransformDirection(totalForce.outputValue); + // Gizmos.DrawRay(transform.position, worldForce * 10); + // // Gizmos.color = Color.magenta; + // // Gizmos.DrawRay(transform.position, this.transform.TransformDirection(avoidance.outputValue) * 10); + // // Debug.Log($"Avoidance {roaming.avoidance.outputValue} Roaming {roaming.output.outputValue} Total {totalForce.outputValue}"); + // // Debug.Log($"WorldForce {worldForce} velocity {velocity} inertia {sc.inertia}"); + // Gizmos.color = Color.blue; + // Gizmos.DrawRay(transform.position, this.velocity * 10); + // } } From fc4e1ea8894cbe96af1368bbc4dfa97e473f16af Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 3 Dec 2025 15:54:16 +0100 Subject: [PATCH 015/179] Fix boundary velocityneuroid to alignment --- Assets/NanoBrain/Editor/NanoBrain_Editor.cs | 11 +++- Assets/NanoBrain/Neuroid.cs | 30 ++------- Assets/NanoBrain/Nucleus.cs | 2 + Assets/NanoBrain/Perception.cs | 63 ++++++------------- Assets/NanoBrain/SensoryNeuroid.cs | 15 ++--- Assets/Scenes/Boids/Boids.unity | 6 +- Assets/Scenes/Boids/Scripts/Boid.cs | 18 ------ Assets/Scenes/Boids/Scripts/RoamingNucleus.cs | 1 - Assets/Scenes/Boids/Scripts/SwarmSpawner.cs | 3 +- .../Scenes/Boids/Scripts/SwarmingNucleus.cs | 1 - 10 files changed, 47 insertions(+), 103 deletions(-) diff --git a/Assets/NanoBrain/Editor/NanoBrain_Editor.cs b/Assets/NanoBrain/Editor/NanoBrain_Editor.cs index 008646d..74bd49a 100644 --- a/Assets/NanoBrain/Editor/NanoBrain_Editor.cs +++ b/Assets/NanoBrain/Editor/NanoBrain_Editor.cs @@ -26,7 +26,6 @@ public class NanoBrain_Editor : Editor { Debug.Log($"Layercount = {this.layers.Count}"); } - #endregion Start #region Update @@ -205,10 +204,18 @@ public class NanoBrain_Editor : Editor { if (brain == null) return; + Vector3 position = brain.transform.position; + float radius = 1; + + + Handles.DrawWireDisc(position, Vector3.up, radius); // horizontal circle + Handles.DrawWireDisc(position, Vector3.right, radius); // X-plane + Handles.DrawWireDisc(position, Vector3.forward, radius); // Z-plane + + // Debug.DrawRay(brain.transform.position, Vector3.forward, Color.magenta); // Handles.color = Color.green; // Handles.DrawLine(brain.transform.position, brain.transform.position + Vector3.up); - Vector3 position = brain.transform.position; Handles.color = Color.yellow; Vector3 worldForce = brain.transform.TransformDirection(this.currentNucleus.outputValue); Debug.DrawRay(position, worldForce * 10, Color.yellow); diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index 6f2e6dc..852f8b5 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -3,13 +3,10 @@ using UnityEngine; public class Neuroid : Nucleus { public int stale = 0; - public bool average = false; public bool inverse = false; public float exponent = 1.0f; - public NanoBrain brain; - public Neuroid(NanoBrain brain, string name) : base(name) { this.brain = brain; if (this.brain != null) @@ -18,10 +15,10 @@ public class Neuroid : Nucleus { Debug.LogError("No neuroid network"); } - public void AddSynapse(Neuroid input) { - input.AddReceiver(this); - this.synapses[input] = 1.0f; - } + // public void AddSynapse(Neuroid input) { + // input.AddReceiver(this); + // this.synapses[input] = 1.0f; + // } public void SetWeight(Neuroid input, float weight) { this.synapses[input] = weight; @@ -43,21 +40,7 @@ public class Neuroid : Nucleus { UpdateState(); } - public void RemoveInputFrom(Neuroid input) { - if (this.synapses.Count == 0) - return; - - this.synapses.Remove(input); - if (this.synapses.Count == 0) { - // In case this was the last synapse, we reset the output because in this case no updates from synapses will follow. - this.outputValue = Vector3.zero; - foreach (Neuroid neuroid in this.receivers) - neuroid.SetInput(this); - } - } - public virtual void UpdateState() { - // int minStale = 10000; Vector3 result = Vector3.zero; foreach ((Nucleus nucleus, float weight) in this.synapses) { if (nucleus is Neuroid neuroid && neuroid.IsStale()) @@ -71,16 +54,11 @@ public class Neuroid : Nucleus { magnitude = 1 / magnitude; result += direction * magnitude; - // if (nucleus is Neuroid neuroid && neuroid.stale < minStale) - // minStale = neuroid.stale; } if (average && this.synapses.Count > 0) result /= this.synapses.Count; this.outputValue = result; - - // if (minStale > 2) - // Debug.LogWarning($"Strange {minStale} is big duing update"); this.stale = 0; foreach (Neuroid receiver in this.receivers) diff --git a/Assets/NanoBrain/Nucleus.cs b/Assets/NanoBrain/Nucleus.cs index 0683d79..c34b8ed 100644 --- a/Assets/NanoBrain/Nucleus.cs +++ b/Assets/NanoBrain/Nucleus.cs @@ -2,6 +2,8 @@ using System.Collections.Generic; using UnityEngine; public class Nucleus { + public NanoBrain brain { get; protected set; } + public string name; public readonly Dictionary synapses = new(); diff --git a/Assets/NanoBrain/Perception.cs b/Assets/NanoBrain/Perception.cs index efc7970..fd5dfeb 100644 --- a/Assets/NanoBrain/Perception.cs +++ b/Assets/NanoBrain/Perception.cs @@ -5,9 +5,6 @@ using UnityEngine; public class Perception : Nucleus { public SensoryNeuroid[] sensoryNeuroids = new SensoryNeuroid[7]; - // public NeuroidNetwork neuroidNet { get; protected set; } - public NanoBrain neuroidNet { get; protected set; } - public class Receiver { public int thingType = 0; public Neuroid neuroid; @@ -16,9 +13,8 @@ public class Perception : Nucleus { public HashSet positionReceivers { get; protected set; } public HashSet velocityReceivers { get; protected set; } - // public Perception(NeuroidNetwork neuroidNet) : base("Perception") { public Perception(NanoBrain neuroidNet) : base("Perception") { - this.neuroidNet = neuroidNet; + this.brain = neuroidNet; this.positionReceivers = new(); this.velocityReceivers = new(); } @@ -32,7 +28,7 @@ public class Perception : Nucleus { foreach (SensoryNeuroid neuroid in sensoryNeuroids) { if (neuroid != null) { neuroid.AddReceiver(receivingNeuroid); - receivingNeuroid.synapses[neuroid] = weight; // new(neuroid, weight); + receivingNeuroid.synapses[neuroid] = weight; } } } @@ -45,7 +41,7 @@ public class Perception : Nucleus { foreach (SensoryNeuroid neuroid in sensoryNeuroids) { if (neuroid != null && neuroid.velocityNeuroid != null) { neuroid.velocityNeuroid.AddReceiver(receivingNeuroid); - receivingNeuroid.synapses[neuroid] = 1.0f; //new(neuroid); + receivingNeuroid.synapses[neuroid] = weight; } } } @@ -73,49 +69,28 @@ public class Perception : Nucleus { availableIx = leastInterestingIx; if (availableIx != -1) { + SensoryNeuroid neuroid; if (sensoryNeuroids[availableIx] != null) { - Debug.Log($"replace receptor for {thingId} at {availableIx}"); - SensoryNeuroid neuroid = sensoryNeuroids[availableIx]; - neuroid.Replace(thingId); - neuroid.name = name; - foreach (Receiver receiver in positionReceivers) { - if (receiver.thingType == 0 || receiver.thingType == thingType) - receiver.neuroid.GetInputFrom(neuroid); - } - foreach (Receiver receiver in velocityReceivers) { - if (receiver.thingType == 0 || receiver.thingType == thingType) - receiver.neuroid.GetInputFrom(neuroid.velocityNeuroid); - } - neuroid.receptor.position = localPosition; - + // Debug.Log($"replace receptor for {thingId} at {availableIx}"); + neuroid = sensoryNeuroids[availableIx]; + neuroid.Replace(thingId, name); } else { - Debug.Log($"new receptor for {thingId} at {availableIx}"); - SensoryNeuroid neuroid = new(neuroidNet, thingId) { name = name }; - foreach (Receiver receiver in positionReceivers) { - if (receiver.thingType == 0 || receiver.thingType == thingType) - receiver.neuroid.GetInputFrom(neuroid); - } - foreach (Receiver receiver in velocityReceivers) { - if (receiver.thingType == 0 || receiver.thingType == thingType) - receiver.neuroid.GetInputFrom(neuroid.velocityNeuroid); - } - + // Debug.Log($"new receptor for {thingId} at {availableIx}"); + neuroid = new(brain, thingId) { name = name }; sensoryNeuroids[availableIx] = neuroid; - neuroid.receptor.position = localPosition; } + foreach (Receiver receiver in positionReceivers) { + if (receiver.thingType == 0 || receiver.thingType == thingType) + receiver.neuroid.GetInputFrom(neuroid); + } + foreach (Receiver receiver in velocityReceivers) { + if (receiver.thingType == 0 || receiver.thingType == thingType) + receiver.neuroid.GetInputFrom(neuroid.velocityNeuroid); + } + + neuroid.receptor.position = localPosition; } } - public void RemoveStimulus(int thingId) { - for (int i = 0; i < sensoryNeuroids.Length; i++) { - if (sensoryNeuroids[i] != null && sensoryNeuroids[i].receptor.thingId == thingId) { - foreach (Neuroid receiver in sensoryNeuroids[i].receivers) - receiver.RemoveInputFrom(sensoryNeuroids[i]); - sensoryNeuroids[i] = null; - return; - } - } - - } } \ No newline at end of file diff --git a/Assets/NanoBrain/SensoryNeuroid.cs b/Assets/NanoBrain/SensoryNeuroid.cs index c6c0bc7..72985e5 100644 --- a/Assets/NanoBrain/SensoryNeuroid.cs +++ b/Assets/NanoBrain/SensoryNeuroid.cs @@ -7,17 +7,17 @@ public class Receptor { public SensoryNeuroid neuroid; public int thingId; - public Vector3 value; + public Vector3 localPosition; /// /// Local position of the thing /// public virtual Vector3 position { get { - return this.value; + return this.localPosition; } set { - this.value = value; + this.localPosition = value; neuroid.UpdateState(); } } @@ -40,17 +40,18 @@ public class SensoryNeuroid : Neuroid { this.AddReceiver(velocityNeuroid); } - public void Replace(int thingId) { - this.name = "sensory neuroid"; + public void Replace(int thingId, string name = "sensory neuroid") { + this.name = name; this.receptor.thingId = thingId; - this.receptor.value = Vector3.zero; + this.receptor.localPosition = Vector3.zero; this.outputValue = Vector3.zero; this.receivers = new(); this.AddReceiver(velocityNeuroid); + this.velocityNeuroid.receivers = new(); } public override void UpdateState() { - Vector3 result = receptor.value; + Vector3 result = receptor.localPosition; //foreach ((Nucleus nucleus, Synapse synapse) in this.synapses) { foreach ((Nucleus nucleus, float weight) in this.synapses) { Vector3 direction = nucleus.outputValue.normalized; diff --git a/Assets/Scenes/Boids/Boids.unity b/Assets/Scenes/Boids/Boids.unity index 9827fcf..1c9b8ef 100644 --- a/Assets/Scenes/Boids/Boids.unity +++ b/Assets/Scenes/Boids/Boids.unity @@ -373,8 +373,8 @@ MonoBehaviour: m_EditorClassIdentifier: Assembly-CSharp::SwarmControl speed: 2 inertia: 0.1 - alignmentForce: 5 - cohesionForce: 5 + alignmentForce: 3 + cohesionForce: 3 avoidanceForce: 5 separationDistance: 0.3 perceptionDistance: 1 @@ -393,7 +393,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec888ca5333d45a438f9f417fa5ce135, type: 3} m_Name: m_EditorClassIdentifier: Assembly-CSharp::SwarmSpawn - count: 2 + count: 5 boidPrefab: {fileID: 8702527964058765413, guid: f9c706268554ce449a8773675b2864b8, type: 3} spawnAreaSize: {x: 0.5, y: 0.5, z: 0.5} minDelay: 0.05 diff --git a/Assets/Scenes/Boids/Scripts/Boid.cs b/Assets/Scenes/Boids/Scripts/Boid.cs index 0fdebd6..0ac0c98 100644 --- a/Assets/Scenes/Boids/Scripts/Boid.cs +++ b/Assets/Scenes/Boids/Scripts/Boid.cs @@ -63,9 +63,6 @@ public class Boid : MonoBehaviour { Vector3 desiredLocalSpace = -this.transform.InverseTransformPoint(desiredWorldSpace); perception.ProcessStimulus(777, BoundaryType, desiredLocalSpace, "Boundary"); } - // else { - // perception.RemoveStimulus(777); - // } Vector3 worldForce = this.transform.TransformDirection(totalForce.outputValue); @@ -95,19 +92,4 @@ public class Boid : MonoBehaviour { float m = Mathf.Min(sx, Mathf.Min(sy, sz)); return b.center + d * m; } - - // void OnDrawGizmosSelected() { - // if (sc == null) - // return; - // Gizmos.DrawWireSphere(this.transform.position, sc.perceptionDistance); - // Gizmos.color = Color.yellow; - // Vector3 worldForce = this.transform.TransformDirection(totalForce.outputValue); - // Gizmos.DrawRay(transform.position, worldForce * 10); - // // Gizmos.color = Color.magenta; - // // Gizmos.DrawRay(transform.position, this.transform.TransformDirection(avoidance.outputValue) * 10); - // // Debug.Log($"Avoidance {roaming.avoidance.outputValue} Roaming {roaming.output.outputValue} Total {totalForce.outputValue}"); - // // Debug.Log($"WorldForce {worldForce} velocity {velocity} inertia {sc.inertia}"); - // Gizmos.color = Color.blue; - // Gizmos.DrawRay(transform.position, this.velocity * 10); - // } } diff --git a/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs b/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs index ac510bf..2499b5d 100644 --- a/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs +++ b/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs @@ -3,7 +3,6 @@ public class Roaming : Nucleus { public Neuroid output; - // public Roaming(NeuroidNetwork neuroidNet, Perception perception, SwarmControl sc) : base("Roaming nucleus") { public Roaming(NanoBrain neuroidNet, Perception perception, SwarmControl sc) : base("Roaming nucleus") { avoidance = new(neuroidNet, "Avoidance") { inverse = true }; perception.SendPositions(avoidance, 1.0f, 1); diff --git a/Assets/Scenes/Boids/Scripts/SwarmSpawner.cs b/Assets/Scenes/Boids/Scripts/SwarmSpawner.cs index 241969a..48a08d4 100644 --- a/Assets/Scenes/Boids/Scripts/SwarmSpawner.cs +++ b/Assets/Scenes/Boids/Scripts/SwarmSpawner.cs @@ -26,7 +26,8 @@ public class SwarmSpawn : MonoBehaviour { ); // Instantiate the prefab at the random position relative to the spawner - Instantiate(boidPrefab, transform.position + randomPosition, Random.rotation); + GameObject boid = Instantiate(boidPrefab, transform.position + randomPosition, Random.rotation); + boid.name = "Boid " + i; } } } diff --git a/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs b/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs index 23831bf..f8c7bef 100644 --- a/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs +++ b/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs @@ -12,7 +12,6 @@ public class Swarming : Nucleus { public const int BoundaryType = 1; public const int BoidType = 2; - // public Swarming(NeuroidNetwork neuroidNet, Perception perception, SwarmControl sc) : base("Swarming Nucleus") { public Swarming(NanoBrain neuroidNet, Perception perception, SwarmControl sc) : base("Swarming Nucleus") { this.cohesion = new(neuroidNet, "Cohesion"); perception.SendPositions(this.cohesion, 1.0f, BoidType); From ca48381dc2a6cc5740168848c0ada2f2a37d4ba9 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 3 Dec 2025 16:00:53 +0100 Subject: [PATCH 016/179] Add neuroid details in inspector --- Assets/NanoBrain/Editor/NanoBrain_Editor.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Assets/NanoBrain/Editor/NanoBrain_Editor.cs b/Assets/NanoBrain/Editor/NanoBrain_Editor.cs index 74bd49a..1f0c46f 100644 --- a/Assets/NanoBrain/Editor/NanoBrain_Editor.cs +++ b/Assets/NanoBrain/Editor/NanoBrain_Editor.cs @@ -31,9 +31,15 @@ public class NanoBrain_Editor : Editor { #region Update public override void OnInspectorGUI() { + if (this.currentNucleus == null) + return; + DrawGraph(); - DrawDefaultInspector(); + //DrawDefaultInspector(); + EditorGUILayout.TextField("Name", currentNucleus.name); + EditorGUILayout.FloatField("Output Value", currentNucleus.outputValue.magnitude); + EditorGUILayout.IntField("# synapses", currentNucleus.synapses.Count); } private void BuildLayers() { @@ -86,7 +92,7 @@ public class NanoBrain_Editor : Editor { private void DrawGraph() { if (currentNucleus == null) return; - Rect outer = EditorGUILayout.GetControlRect(false, 400); + Rect outer = EditorGUILayout.GetControlRect(false, 420); GUI.BeginGroup(outer); foreach (NeuroidLayer layer in layers) DrawLayer(layer); From 69c6b1e2b7903f67a4e52e8af6bb05e63641cd67 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 3 Dec 2025 18:02:25 +0100 Subject: [PATCH 017/179] Almost flocking --- Assets/NanoBrain/Editor/NanoBrain_Editor.cs | 35 ++++++++++--- Assets/NanoBrain/Editor/NeuroidWindow.cs | 4 +- Assets/NanoBrain/NanoBrain.cs | 2 +- Assets/NanoBrain/Neuroid.cs | 15 ++---- Assets/NanoBrain/Nucleus.cs | 11 +++- Assets/NanoBrain/Perception.cs | 8 +-- Assets/NanoBrain/SensoryNeuroid.cs | 50 ++++++++++++------- Assets/Scenes/Boids/Boids.unity | 10 ++-- Assets/Scenes/Boids/Scripts/Boid.cs | 23 +++------ Assets/Scenes/Boids/Scripts/RoamingNucleus.cs | 2 +- .../Scenes/Boids/Scripts/SwarmingNucleus.cs | 14 +++--- 11 files changed, 102 insertions(+), 72 deletions(-) diff --git a/Assets/NanoBrain/Editor/NanoBrain_Editor.cs b/Assets/NanoBrain/Editor/NanoBrain_Editor.cs index 1f0c46f..58e4ff5 100644 --- a/Assets/NanoBrain/Editor/NanoBrain_Editor.cs +++ b/Assets/NanoBrain/Editor/NanoBrain_Editor.cs @@ -8,6 +8,8 @@ public class NanoBrain_Editor : Editor { private List layers = new(); private Dictionary neuroidPositions = new(); + protected bool breakOnWake = false; + #region Start private void OnEnable() { @@ -19,7 +21,7 @@ public class NanoBrain_Editor : Editor { if (!selectedObject.TryGetComponent(out Boid boid)) return; - Neuroid neuroid = boid.totalForce; + Nucleus neuroid = boid.totalForce; this.currentNucleus = neuroid; BuildLayers(); @@ -34,12 +36,32 @@ public class NanoBrain_Editor : Editor { if (this.currentNucleus == null) return; + breakOnWake = EditorGUILayout.Toggle("Break on wake", breakOnWake); + if (breakOnWake && currentNucleus is Neuroid currentNeuroid) { + if (!currentNeuroid.isSleeping) + Debug.Break(); + } + DrawGraph(); //DrawDefaultInspector(); EditorGUILayout.TextField("Name", currentNucleus.name); - EditorGUILayout.FloatField("Output Value", currentNucleus.outputValue.magnitude); - EditorGUILayout.IntField("# synapses", currentNucleus.synapses.Count); + EditorGUILayout.Vector3Field("Output Value", currentNucleus.outputValue); + if (currentNucleus.synapses.Count > 0) { + EditorGUI.indentLevel++; + foreach ((Nucleus nucleus, float weight) in currentNucleus.synapses) { + EditorGUI.BeginDisabledGroup(nucleus.isSleeping); + + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.Vector3Field(nucleus.name, nucleus.outputValue); + EditorGUILayout.FloatField(weight, GUILayout.Width(50)); + EditorGUILayout.EndHorizontal(); + + EditorGUI.EndDisabledGroup(); + + } + EditorGUI.indentLevel--; + } } private void BuildLayers() { @@ -140,8 +162,8 @@ public class NanoBrain_Editor : Editor { float size = 20; - if (layerNeuroid.IsStale()) - Handles.color = Color.darkCyan; + if (layerNeuroid.isSleeping) + Handles.color = Color.darkRed; else { float brightness = layerNeuroid.outputValue.magnitude / maxValue; Handles.color = new Color(brightness, brightness, brightness); @@ -224,7 +246,8 @@ public class NanoBrain_Editor : Editor { // Handles.DrawLine(brain.transform.position, brain.transform.position + Vector3.up); Handles.color = Color.yellow; Vector3 worldForce = brain.transform.TransformDirection(this.currentNucleus.outputValue); - Debug.DrawRay(position, worldForce * 10, Color.yellow); + //Debug.DrawRay(position, worldForce * 10, Color.yellow); + Handles.DrawLine(position, position + worldForce * 10); } #endregion Update diff --git a/Assets/NanoBrain/Editor/NeuroidWindow.cs b/Assets/NanoBrain/Editor/NeuroidWindow.cs index 69d8a34..248e0e4 100644 --- a/Assets/NanoBrain/Editor/NeuroidWindow.cs +++ b/Assets/NanoBrain/Editor/NeuroidWindow.cs @@ -199,7 +199,7 @@ public class GraphEditorWindow : EditorWindow { } float size = 20; - if (layerNeuroid.IsStale()) + if (layerNeuroid.isSleeping) Handles.color = Color.black; else { float brightness = layerNeuroid.outputValue.magnitude / maxValue; @@ -272,7 +272,7 @@ public class GraphEditorWindow : EditorWindow { if (boid == null) return; - Neuroid neuroid = boid.totalForce; + Nucleus neuroid = boid.behaviour; this.currentNucleus = neuroid; if (neuroid == null) this.allNeuroids = new(); diff --git a/Assets/NanoBrain/NanoBrain.cs b/Assets/NanoBrain/NanoBrain.cs index df9ef3b..437f0b2 100644 --- a/Assets/NanoBrain/NanoBrain.cs +++ b/Assets/NanoBrain/NanoBrain.cs @@ -12,7 +12,7 @@ public class NanoBrain : MonoBehaviour { public void UpdateNeurons() { foreach (Neuroid neuroid in neuroids) { neuroid.stale++; - if (neuroid.IsStale()) + if (neuroid.isSleeping) neuroid.outputValue = Vector3.zero; } } diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index 852f8b5..7e03903 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -1,8 +1,6 @@ using UnityEngine; public class Neuroid : Nucleus { - public int stale = 0; - public bool average = false; public bool inverse = false; public float exponent = 1.0f; @@ -15,11 +13,6 @@ public class Neuroid : Nucleus { Debug.LogError("No neuroid network"); } - // public void AddSynapse(Neuroid input) { - // input.AddReceiver(this); - // this.synapses[input] = 1.0f; - // } - public void SetWeight(Neuroid input, float weight) { this.synapses[input] = weight; } @@ -43,7 +36,7 @@ public class Neuroid : Nucleus { public virtual void UpdateState() { Vector3 result = Vector3.zero; foreach ((Nucleus nucleus, float weight) in this.synapses) { - if (nucleus is Neuroid neuroid && neuroid.IsStale()) + if (nucleus is Neuroid neuroid && neuroid.isSleeping) continue; Vector3 direction = nucleus.outputValue.normalized; @@ -65,8 +58,8 @@ public class Neuroid : Nucleus { receiver.SetInput(this); } - public bool IsStale() { - return this.stale > 2; - } + // public bool IsStale() { + // return this.stale > 2; + // } } diff --git a/Assets/NanoBrain/Nucleus.cs b/Assets/NanoBrain/Nucleus.cs index c34b8ed..ce38a1d 100644 --- a/Assets/NanoBrain/Nucleus.cs +++ b/Assets/NanoBrain/Nucleus.cs @@ -2,9 +2,11 @@ using System.Collections.Generic; using UnityEngine; public class Nucleus { + public int stale = 0; + public NanoBrain brain { get; protected set; } - public string name; + public virtual string name { get; set; } public readonly Dictionary synapses = new(); public HashSet receivers = new(); @@ -22,4 +24,11 @@ public class Nucleus { receiver.synapses[this] = 1.0f; // new(this); //Debug.Log($"receiver # {this.receivers.Count} synapse count {receiver.synapses.Count}"); } + + public bool isSleeping { + get { + return this.stale > 2; + } + } + } \ No newline at end of file diff --git a/Assets/NanoBrain/Perception.cs b/Assets/NanoBrain/Perception.cs index fd5dfeb..3353d62 100644 --- a/Assets/NanoBrain/Perception.cs +++ b/Assets/NanoBrain/Perception.cs @@ -19,7 +19,7 @@ public class Perception : Nucleus { this.velocityReceivers = new(); } - public void SendPositions(Neuroid receivingNeuroid, float weight = 1.0f, int thingType = 0) { + public void SendPositions(Neuroid receivingNeuroid, int thingType = 0, float weight = 1.0f) { Receiver receiver = new() { thingType = thingType, neuroid = receivingNeuroid @@ -32,7 +32,7 @@ public class Perception : Nucleus { } } } - public void SendVelocities(Neuroid receivingNeuroid, float weight = 1.0f, int thingType = 0) { + public void SendVelocities(Neuroid receivingNeuroid, int thingType = 0, float weight = 1.0f) { Receiver receiver = new() { thingType = thingType, neuroid = receivingNeuroid @@ -57,7 +57,7 @@ public class Perception : Nucleus { return; } if (availableIx == -1) { - if (sensoryNeuroids[i].IsStale()) + if (sensoryNeuroids[i].isSleeping) leastInterestingIx = i; else if (sensoryNeuroids[i] != null) { if (leastInterestingIx == -1 || sensoryNeuroids[leastInterestingIx].receptor.position.magnitude > sensoryNeuroids[i].receptor.position.magnitude) @@ -77,7 +77,7 @@ public class Perception : Nucleus { } else { // Debug.Log($"new receptor for {thingId} at {availableIx}"); - neuroid = new(brain, thingId) { name = name }; + neuroid = new(brain, thingId, name); sensoryNeuroids[availableIx] = neuroid; } foreach (Receiver receiver in positionReceivers) { diff --git a/Assets/NanoBrain/SensoryNeuroid.cs b/Assets/NanoBrain/SensoryNeuroid.cs index 72985e5..02b6865 100644 --- a/Assets/NanoBrain/SensoryNeuroid.cs +++ b/Assets/NanoBrain/SensoryNeuroid.cs @@ -30,33 +30,38 @@ public class SensoryNeuroid : Neuroid { public VelocityNeuroid velocityNeuroid; // public SensoryNeuroid(NeuroidNetwork net, int thingId) : base(net, "sensory neuroid") { - public SensoryNeuroid(NanoBrain net, int thingId) : base(net, "sensory neuroid") { + public SensoryNeuroid(NanoBrain net, int thingId, string name = "sensor") : base(net, name) { + this.name = name + ": position"; this.receptor = new Receptor { neuroid = this, thingId = thingId }; - this.velocityNeuroid = new(net); + this.velocityNeuroid = new(net, name + ": velocity"); // The velocity neuroid received position data from this this.AddReceiver(velocityNeuroid); } - public void Replace(int thingId, string name = "sensory neuroid") { - this.name = name; + public void Replace(int thingId, string name = "sensor") { + this.name = name + ": position"; + this.receptor.thingId = thingId; this.receptor.localPosition = Vector3.zero; + this.outputValue = Vector3.zero; this.receivers = new(); this.AddReceiver(velocityNeuroid); - this.velocityNeuroid.receivers = new(); + + // this.velocityNeuroid.name = name + ": velocity"; + // this.velocityNeuroid.receivers = new(); + this.velocityNeuroid.Replace(name + ": velocity"); } public override void UpdateState() { Vector3 result = receptor.localPosition; - //foreach ((Nucleus nucleus, Synapse synapse) in this.synapses) { foreach ((Nucleus nucleus, float weight) in this.synapses) { Vector3 direction = nucleus.outputValue.normalized; float magnitude = nucleus.outputValue.magnitude; - //magnitude = synapse.weight * Mathf.Pow(magnitude, exponent); + magnitude = weight * Mathf.Pow(magnitude, exponent); if (inverse) magnitude = 1 / magnitude; @@ -77,8 +82,14 @@ public class VelocityNeuroid : Neuroid { private Vector3 lastPosition = Vector3.zero; private float lastValueTime = 0; - // public VelocityNeuroid(NeuroidNetwork net) : base(net, "Velocity") { - public VelocityNeuroid(NanoBrain net) : base(net, "Velocity") { + public VelocityNeuroid(NanoBrain net, string name = "velocity") : base(net, name) { + } + + public void Replace(string name = "velocity") { + this.name = name; + this.receivers = new(); + this.lastPosition = Vector3.zero; + this.lastValueTime = 0; } public override void UpdateState() { @@ -86,17 +97,20 @@ public class VelocityNeuroid : Neuroid { Vector3 currentPosition = this.synapses.First().Key.outputValue; float currentValueTime = Time.time; - float deltaTime = currentValueTime - lastValueTime; - Vector3 translation = currentPosition - lastPosition; - Vector3 velocity = translation / deltaTime; + if (lastValueTime != 0) { + float deltaTime = currentValueTime - lastValueTime; + Vector3 translation = currentPosition - lastPosition; + Vector3 velocity = translation / deltaTime; - // No activation function... - this.outputValue = velocity; - foreach (Neuroid receiver in receivers) - receiver?.SetInput(this); - this.stale = 0; + // No activation function... + this.outputValue = velocity; + this.stale = 0; - this.lastValueTime = Time.time; + foreach (Neuroid receiver in receivers) + receiver?.SetInput(this); + } + + this.lastValueTime = currentValueTime; this.lastPosition = currentPosition; } } \ No newline at end of file diff --git a/Assets/Scenes/Boids/Boids.unity b/Assets/Scenes/Boids/Boids.unity index 1c9b8ef..2c5cb28 100644 --- a/Assets/Scenes/Boids/Boids.unity +++ b/Assets/Scenes/Boids/Boids.unity @@ -372,10 +372,10 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: Assembly-CSharp::SwarmControl speed: 2 - inertia: 0.1 - alignmentForce: 3 - cohesionForce: 3 - avoidanceForce: 5 + inertia: 0.5 + alignmentForce: 2 + cohesionForce: 2 + avoidanceForce: 1 separationDistance: 0.3 perceptionDistance: 1 boundaryForce: 5 @@ -393,7 +393,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec888ca5333d45a438f9f417fa5ce135, type: 3} m_Name: m_EditorClassIdentifier: Assembly-CSharp::SwarmSpawn - count: 5 + count: 20 boidPrefab: {fileID: 8702527964058765413, guid: f9c706268554ce449a8773675b2864b8, type: 3} spawnAreaSize: {x: 0.5, y: 0.5, z: 0.5} minDelay: 0.05 diff --git a/Assets/Scenes/Boids/Scripts/Boid.cs b/Assets/Scenes/Boids/Scripts/Boid.cs index 0ac0c98..0fb20f7 100644 --- a/Assets/Scenes/Boids/Scripts/Boid.cs +++ b/Assets/Scenes/Boids/Scripts/Boid.cs @@ -2,17 +2,15 @@ using UnityEngine; [RequireComponent(typeof(NanoBrain))] public class Boid : MonoBehaviour { - public const int BoundaryType = 1; - public const int BoidType = 2; + public static int BoundaryType = 1; + public static int BoidType = 2; public SwarmControl sc; public Vector3 velocity = Vector3.zero; public Vector3 acceleration = Vector3.zero; private Bounds innerBounds; - private Bounds outerBounds; - //public NeuroidNetwork neuroidNet = new(); public NanoBrain neuroidNet; public Perception perception; @@ -30,7 +28,6 @@ public class Boid : MonoBehaviour { sc = FindFirstObjectByType(); innerBounds = new(sc.transform.position, sc.spaceSize - 2 * sc.boundaryWidth); - outerBounds = new(sc.transform.position, sc.spaceSize); perception = new Perception(neuroidNet); @@ -49,7 +46,8 @@ public class Boid : MonoBehaviour { if (neighbour == null || neighbour == this) continue; - Vector3 localPosition = neighbour.transform.position - this.transform.position; + Vector3 localPosition = this.transform.InverseTransformPoint(neighbour.transform.position); + //Debug.DrawRay(this.transform.position, this.transform.TransformDirection(localPosition), Color.magenta); int thingId = neighbour.GetInstanceID(); perception.ProcessStimulus(thingId, BoidType, localPosition, neighbour.gameObject.name); @@ -64,13 +62,14 @@ public class Boid : MonoBehaviour { perception.ProcessStimulus(777, BoundaryType, desiredLocalSpace, "Boundary"); } - Vector3 worldForce = this.transform.TransformDirection(totalForce.outputValue); + Vector3 worldForce = this.transform.TransformDirection(behaviour.outputValue); this.velocity = (1 - sc.inertia) * (worldForce * Time.deltaTime) + sc.inertia * velocity; if (this.velocity.magnitude > 0) this.velocity = this.velocity.normalized * sc.speed; else this.velocity = this.transform.forward * sc.speed; + Debug.DrawRay(this.transform.position, this.velocity, Color.blue); this.transform.position += this.velocity * Time.deltaTime; @@ -82,14 +81,4 @@ public class Boid : MonoBehaviour { neuroidNet.UpdateNeurons(); } - Vector3 ClosestPointOnBoundsSurface(Bounds b, Vector3 p) { - if (!b.Contains(p)) return b.ClosestPoint(p); - Vector3 d = p - b.center; - Vector3 ext = b.extents; - float sx = ext.x / Mathf.Abs(d.x); - float sy = ext.y / Mathf.Abs(d.y); - float sz = ext.z / Mathf.Abs(d.z); - float m = Mathf.Min(sx, Mathf.Min(sy, sz)); - return b.center + d * m; - } } diff --git a/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs b/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs index 2499b5d..7fbb301 100644 --- a/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs +++ b/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs @@ -5,7 +5,7 @@ public class Roaming : Nucleus { public Roaming(NanoBrain neuroidNet, Perception perception, SwarmControl sc) : base("Roaming nucleus") { avoidance = new(neuroidNet, "Avoidance") { inverse = true }; - perception.SendPositions(avoidance, 1.0f, 1); + perception.SendPositions(avoidance, Boid.BoundaryType); this.output = new(neuroidNet, "Roaming"); output.GetInputFrom(avoidance, -sc.avoidanceForce); diff --git a/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs b/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs index f8c7bef..580761f 100644 --- a/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs +++ b/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs @@ -4,28 +4,30 @@ public class Swarming : Nucleus { public Neuroid cohesion; public Neuroid alignment; public Neuroid avoidance; + public Neuroid boundary; public Neuroid output; public override Vector3 outputValue { get => output.outputValue; set => output.outputValue = value; } - public const int BoundaryType = 1; - public const int BoidType = 2; - public Swarming(NanoBrain neuroidNet, Perception perception, SwarmControl sc) : base("Swarming Nucleus") { - this.cohesion = new(neuroidNet, "Cohesion"); - perception.SendPositions(this.cohesion, 1.0f, BoidType); + this.cohesion = new(neuroidNet, "Cohesion") { inverse = false }; + perception.SendPositions(this.cohesion, Boid.BoidType); this.alignment = new(neuroidNet, "Alignment") { average = true }; - perception.SendVelocities(this.alignment, 1.0f, BoidType); + perception.SendVelocities(this.alignment, Boid.BoidType); this.avoidance = new(neuroidNet, "Avoidance") { inverse = true }; perception.SendPositions(this.avoidance); + this.boundary = new(neuroidNet, "Boundary"); + perception.SendPositions(this.boundary, Boid.BoundaryType); + this.output = new(neuroidNet, "Swarming"); this.output.GetInputFrom(alignment, sc.alignmentForce); this.output.GetInputFrom(cohesion, sc.cohesionForce); this.output.GetInputFrom(avoidance, -sc.avoidanceForce); + this.output.GetInputFrom(boundary, -sc.avoidanceForce); } public override void AddReceiver(Neuroid receiver) { From 5a9aa7161b3b8dc62cbbd6a4d5276b7c54fae15e Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 4 Dec 2025 12:55:55 +0100 Subject: [PATCH 018/179] Scriptable Object nanobrain editor --- Assembly-CSharp-Editor.csproj | 1 + Assembly-CSharp.csproj | 6 + Assets/NanoBrain/Editor/NanoBrain_Editor.cs | 11 +- Assets/NanoBrain/Editor/NeuroidWindow.cs | 2 +- Assets/NanoBrain/NanoBrain.cs | 3 + Assets/NanoBrain/Neuroid.cs | 8 + Assets/NanoBrain/Nucleus.cs | 5 +- .../VisualEditor.meta} | 2 +- .../VisualEditor/Editor.meta} | 3 +- .../VisualEditor/Editor/NanoBrainEditor.cs | 477 +++++++ .../Editor/NanoBrainEditor.cs.meta | 2 + Assets/NanoBrain/VisualEditor/NanoBrainObj.cs | 22 + .../VisualEditor/NanoBrainObj.cs.meta | 2 + .../NanoBrain/VisualEditor/NeuroidObject.cs | 0 .../VisualEditor/NeuroidObject.cs.meta | 2 + .../NanoBrain/VisualEditor/NucleusObject.cs | 28 + .../VisualEditor/NucleusObject.cs.meta | 2 + Assets/NanoBrain/VisualEditor/Resources.meta | 8 + .../VisualEditor/Resources/GraphStyles.uss | 15 + .../Resources/GraphStyles.uss.meta | 11 + Assets/Scenes/Boids/Scripts/RoamingNucleus.cs | 2 +- .../Scenes/Boids/Scripts/SwarmingNucleus.cs | 2 +- Assets/_Recovery/0.unity | 1123 ----------------- NanoBrain-Unity.slnx | 2 +- 24 files changed, 607 insertions(+), 1132 deletions(-) rename Assets/{_Recovery.meta => NanoBrain/VisualEditor.meta} (77%) rename Assets/{_Recovery/0.unity.meta => NanoBrain/VisualEditor/Editor.meta} (67%) create mode 100644 Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs create mode 100644 Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs.meta create mode 100644 Assets/NanoBrain/VisualEditor/NanoBrainObj.cs create mode 100644 Assets/NanoBrain/VisualEditor/NanoBrainObj.cs.meta create mode 100644 Assets/NanoBrain/VisualEditor/NeuroidObject.cs create mode 100644 Assets/NanoBrain/VisualEditor/NeuroidObject.cs.meta create mode 100644 Assets/NanoBrain/VisualEditor/NucleusObject.cs create mode 100644 Assets/NanoBrain/VisualEditor/NucleusObject.cs.meta create mode 100644 Assets/NanoBrain/VisualEditor/Resources.meta create mode 100644 Assets/NanoBrain/VisualEditor/Resources/GraphStyles.uss create mode 100644 Assets/NanoBrain/VisualEditor/Resources/GraphStyles.uss.meta delete mode 100644 Assets/_Recovery/0.unity diff --git a/Assembly-CSharp-Editor.csproj b/Assembly-CSharp-Editor.csproj index 23e17fc..e94da31 100644 --- a/Assembly-CSharp-Editor.csproj +++ b/Assembly-CSharp-Editor.csproj @@ -48,6 +48,7 @@ + diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index 06d6dd6..af65fe2 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -48,6 +48,7 @@ + @@ -57,9 +58,14 @@ + + + + + /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.dll diff --git a/Assets/NanoBrain/Editor/NanoBrain_Editor.cs b/Assets/NanoBrain/Editor/NanoBrain_Editor.cs index 58e4ff5..79fed6a 100644 --- a/Assets/NanoBrain/Editor/NanoBrain_Editor.cs +++ b/Assets/NanoBrain/Editor/NanoBrain_Editor.cs @@ -13,6 +13,15 @@ public class NanoBrain_Editor : Editor { #region Start private void OnEnable() { + // NanoBrain brain = target as NanoBrain; + // if (brain == null) + // return; + + // if (brain.rootNucleus == null) { + // brain.rootNucleus = CreateInstance(); + // EditorUtility.SetDirty(brain.rootNucleus); + // } + SelectNeuron(); } @@ -44,7 +53,6 @@ public class NanoBrain_Editor : Editor { DrawGraph(); - //DrawDefaultInspector(); EditorGUILayout.TextField("Name", currentNucleus.name); EditorGUILayout.Vector3Field("Output Value", currentNucleus.outputValue); if (currentNucleus.synapses.Count > 0) { @@ -62,6 +70,7 @@ public class NanoBrain_Editor : Editor { } EditorGUI.indentLevel--; } + DrawDefaultInspector(); } private void BuildLayers() { diff --git a/Assets/NanoBrain/Editor/NeuroidWindow.cs b/Assets/NanoBrain/Editor/NeuroidWindow.cs index 248e0e4..a725c97 100644 --- a/Assets/NanoBrain/Editor/NeuroidWindow.cs +++ b/Assets/NanoBrain/Editor/NeuroidWindow.cs @@ -40,7 +40,7 @@ public class GraphEditorWindow : EditorWindow { return; NeuroidLayer currentLayer = new() { ix = layerIx }; - foreach (Neuroid outputNeuroid in selectedNucleus.receivers) { + foreach (Nucleus outputNeuroid in selectedNucleus.receivers) { if (outputNeuroid != null) { AddToLayer(currentLayer, outputNeuroid); Debug.Log($"layer {layerIx} nucleus {outputNeuroid.name}"); diff --git a/Assets/NanoBrain/NanoBrain.cs b/Assets/NanoBrain/NanoBrain.cs index 437f0b2..a8e557b 100644 --- a/Assets/NanoBrain/NanoBrain.cs +++ b/Assets/NanoBrain/NanoBrain.cs @@ -2,6 +2,9 @@ using System.Collections.Generic; using UnityEngine; public class NanoBrain : MonoBehaviour { + +// public NucleusObj rootNucleus; + public List neuroids = new(); public Neuroid AddNeuron(string name) { diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index 7e03903..33bb553 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -13,6 +13,14 @@ public class Neuroid : Nucleus { Debug.LogError("No neuroid network"); } + public Neuroid(NanoBrainObj brain, string name) : base(name) { + this.newBrain = brain; + if (this.newBrain != null) + this.newBrain.neuroids.Add(this); + else + Debug.LogError("No neuroid network"); + } + public void SetWeight(Neuroid input, float weight) { this.synapses[input] = weight; } diff --git a/Assets/NanoBrain/Nucleus.cs b/Assets/NanoBrain/Nucleus.cs index ce38a1d..e5646e7 100644 --- a/Assets/NanoBrain/Nucleus.cs +++ b/Assets/NanoBrain/Nucleus.cs @@ -5,11 +5,12 @@ public class Nucleus { public int stale = 0; public NanoBrain brain { get; protected set; } + public NanoBrainObj newBrain { get; protected set; } public virtual string name { get; set; } public readonly Dictionary synapses = new(); - public HashSet receivers = new(); + public HashSet receivers = new(); public virtual Vector3 outputValue { get; set; } public int layerIx; @@ -18,7 +19,7 @@ public class Nucleus { this.name = name; } - public virtual void AddReceiver(Neuroid receiver) { + public virtual void AddReceiver(Nucleus receiver) { //Debug.Log($"add receiver to {this} for {receiver} {receiver.GetHashCode()} {this.receivers.Count} {receiver.synapses.Count}"); this.receivers.Add(receiver); receiver.synapses[this] = 1.0f; // new(this); diff --git a/Assets/_Recovery.meta b/Assets/NanoBrain/VisualEditor.meta similarity index 77% rename from Assets/_Recovery.meta rename to Assets/NanoBrain/VisualEditor.meta index 8077f23..d012778 100644 --- a/Assets/_Recovery.meta +++ b/Assets/NanoBrain/VisualEditor.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 895037c7e323e03ada7f43d011f1390b +guid: 62a58c801eda0c9eab7a49fb1d0840cb folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/_Recovery/0.unity.meta b/Assets/NanoBrain/VisualEditor/Editor.meta similarity index 67% rename from Assets/_Recovery/0.unity.meta rename to Assets/NanoBrain/VisualEditor/Editor.meta index 8162e27..c068f8e 100644 --- a/Assets/_Recovery/0.unity.meta +++ b/Assets/NanoBrain/VisualEditor/Editor.meta @@ -1,5 +1,6 @@ fileFormatVersion: 2 -guid: e5398245724c5668992c64c27db35040 +guid: e47ea55fc051fcdcb8ae6197d1105cc0 +folderAsset: yes DefaultImporter: externalObjects: {} userData: diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs new file mode 100644 index 0000000..c496504 --- /dev/null +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs @@ -0,0 +1,477 @@ +using UnityEditor; +using UnityEngine; +using UnityEngine.UIElements; +using System.Linq; +using System.Collections.Generic; + +public class NucleusLayer { + public int ix = 0; + public List neuroids = new(); +} + +public class NanoBrainEditor : EditorWindow { + public static NanoBrainObj brain; + + public static VisualElement inspectorContainer; + + [MenuItem("Window/NanoBrain Editor")] + public static void ShowWindow() { + GetWindow("NanoBrain Editor"); + } + + GraphBoardView board; + + private void OnEnable() { + if (brain == null) { + brain = CreateInstance(); + EditorUtility.SetDirty(brain); + } + + VisualElement root = rootVisualElement; + root.styleSheets.Add(Resources.Load("GraphStyles")); + + root.Add(board); + root.Add(inspectorContainer); + + VisualElement main = new() { + name = "main", + style = { + flexDirection = FlexDirection.Row, + flexGrow = 1 + } + }; + board = new GraphBoardView(); + board.style.flexGrow = 1; + inspectorContainer = new VisualElement { + name = "inspector", + style = { + width = 400 + } + }; + + main.Add(board); + main.Add(inspectorContainer); + root.Add(main); + + board.SetGraph(brain.rootNucleus); + } +} + +public class GraphBoardView : VisualElement { + Nucleus currentNucleus; + private List layers = new(); + private Dictionary neuroidPositions = new(); + + Vector2 pan = Vector2.zero; + //float zoom = 1f; + bool draggingCanvas = false; + Vector2 lastMouse; + GraphNodeWrapper currentWrapper; + + public GraphBoardView() { + name = "content"; + style.flexGrow = 1; + + IMGUIContainer imguiContainer = new(OnIMGUI); + imguiContainer.style.position = Position.Absolute; + imguiContainer.style.left = 0; imguiContainer.style.top = 0; + imguiContainer.style.right = 0; imguiContainer.style.bottom = 0; + imguiContainer.pickingMode = PickingMode.Position; + imguiContainer.focusable = true; + Add(imguiContainer); + + //RegisterCallback(OnWheel); + RegisterCallback(OnMouseDown); + RegisterCallback(OnMouseMove); + RegisterCallback(OnMouseUp); + } + + public void SetGraph(Nucleus nucleus) { + this.currentNucleus = nucleus; + Rebuild(); + } + + void Rebuild() { + BuildLayers(); + + if (currentNucleus == null) { + NanoBrainEditor.inspectorContainer.Clear(); + return; + } + + if (currentWrapper != null) + Object.DestroyImmediate(currentWrapper); + currentWrapper = ScriptableObject.CreateInstance().Init(currentNucleus, NanoBrainEditor.brain); + DrawInspector(); + } + + private void BuildLayers() { + // A temporary list to track what's been added to layers + this.layers = new(); + int layerIx = 0; + + Nucleus selectedNucleus = this.currentNucleus; + if (selectedNucleus == null) + return; + NeuroidLayer currentLayer = new() { ix = layerIx }; + + foreach (Nucleus outputNeuroid in selectedNucleus.receivers) { + if (outputNeuroid != null) { + AddToLayer(currentLayer, outputNeuroid); + // Debug.Log($"layer {layerIx} nucleus {outputNeuroid.name}"); + } + } + if (currentLayer.neuroids.Count > 0) { + this.layers.Add(currentLayer); + layerIx++; + currentLayer = new() { ix = layerIx }; + } + + AddToLayer(currentLayer, selectedNucleus); + this.layers.Add(currentLayer); + // Debug.Log($"layer {layerIx} nucleus {selectedNucleus.name}"); + + layerIx++; + currentLayer = new() { ix = layerIx }; + + foreach (Nucleus input in selectedNucleus.synapses.Keys) { + AddToLayer(currentLayer, input); + // Debug.Log($"layer {layerIx} nucleus {input.name}"); + } + if (currentLayer.neuroids.Count > 0) { + this.layers.Add(currentLayer); + } + } + + private void AddToLayer(NeuroidLayer layer, Nucleus nucleus) { + layer.neuroids.Add(nucleus); + nucleus.layerIx = layer.ix; + // Store its position + Vector2Int neuroidPosition = new(layer.ix, layer.neuroids.Count - 1); + neuroidPositions[nucleus] = neuroidPosition; + + } + + // basic pan/zoom handling + // void OnWheel(WheelEvent e) { + // if (e.ctrlKey) { + // float delta = -e.delta.y * 0.001f; + // zoom = Mathf.Clamp(zoom + delta, 0.25f, 2f); + // content.transform.rotation = Quaternion.identity; // keep transform accessible + // content.transform.scale = new Vector3(zoom, zoom, 1); + // e.StopPropagation(); + // } + // else { + // pan += e.delta; + // content.style.left = pan.x; + // content.style.top = pan.y; + // } + // } + + void OnMouseDown(MouseDownEvent e) { + if (e.button == 2) { draggingCanvas = true; lastMouse = e.mousePosition; e.StopPropagation(); } + } + void OnMouseMove(MouseMoveEvent e) { + if (draggingCanvas) { + var delta = e.mousePosition - lastMouse; + pan += delta; + //content.style.left = pan.x; + //content.style.top = pan.y; + lastMouse = e.mousePosition; + } + } + void OnMouseUp(MouseUpEvent e) { if (e.button == 2) draggingCanvas = false; } + + void OnIMGUI() { + if (currentNucleus == null) + return; + + Handles.BeginGUI(); + foreach (NeuroidLayer layer in layers) + DrawLayer(layer); + Handles.EndGUI(); + } + + private void DrawLayer(NeuroidLayer layer) { + int nodeCount = layer.neuroids.Count; + float maxValue = 0; + foreach (Nucleus nucleus in layer.neuroids) { + if (nucleus is Neuroid neuroid) { + float value = neuroid.outputValue.magnitude; + if (value > maxValue) + maxValue = value; + } + } + float spacing = 400f / nodeCount; + float margin = 10 + spacing / 2; + foreach (Nucleus layerNucleus in layer.neuroids) { + Vector2Int layerNeuroidPos = this.neuroidPositions[layerNucleus]; + Vector3 parentPos = new(100 + layerNeuroidPos.x * 100, margin + layerNeuroidPos.y * spacing, 0.1f); + + //int i = 0; + float inputSpacing = 400f / layerNucleus.synapses.Count; + float inputMargin = 10 + inputSpacing / 2; + int minStale = 10000; + foreach ((Nucleus nucleus, float weight) in layerNucleus.synapses) { + if (this.neuroidPositions.ContainsKey(nucleus)) { + Vector2Int inputNeuroidPos = this.neuroidPositions[nucleus]; + if (inputNeuroidPos.x == layerNeuroidPos.x + 1) { + Vector3 pos = new(100 + inputNeuroidPos.x * 100, inputMargin + inputNeuroidPos.y * inputSpacing, 0.0f); + + float brightness = weight / 10.0f; + Handles.color = new Color(brightness, brightness, brightness); + Handles.DrawLine(parentPos, pos); + } + } + if (nucleus is Neuroid neuroid && neuroid.stale < minStale) + minStale = neuroid.stale; + } + + if (layerNucleus.synapses.Count > 0 && minStale > 2 && layerNucleus.stale < 3) + Debug.LogWarning($"Strange {minStale} is big duing update"); + + + float size = 20; + if (layerNucleus.isSleeping) + Handles.color = Color.darkRed; + else { + float brightness = layerNucleus.outputValue.magnitude / maxValue; + Handles.color = new Color(brightness, brightness, brightness); + } + Handles.DrawSolidDisc(parentPos, Vector3.forward, size); + Vector3 labelPos = parentPos - Vector3.down * (size + 0.2f); // below disc along up axis + GUIStyle style = new GUIStyle(EditorStyles.label) { + alignment = TextAnchor.UpperCenter, + normal = { textColor = Color.white }, + fontStyle = FontStyle.Bold + }; + Handles.Label(labelPos, layerNucleus.name, style); + + Rect neuronRect = new(parentPos.x - size, parentPos.y - size, size * 2, size * 2); + int id = GUIUtility.GetControlID(FocusType.Passive); + Event e = Event.current; + EventType et = e.GetTypeForControl(id); + if (e != null && neuronRect.Contains(e.mousePosition)) { + // Process Hover + HandleMouseHover(layerNucleus, neuronRect); + // Process click + Debug.Log($"{et} {e.type}"); + if (e.type == EventType.MouseDown && e.button == 0) { + // Consume the event so the scene doesn't also handle it + e.Use(); + HandleDiscClicked(layerNucleus); + } + } + } + } + + private void HandleMouseHover(Nucleus neuroid, Rect rect) { + GUIContent tooltip; + if (neuroid is SensoryNeuroid sensoryNeuroid) { + tooltip = new( + $"{sensoryNeuroid.name}" + + $"\nThing {sensoryNeuroid.receptor.thingId}" + + $"\nValue: {neuroid.outputValue}" + + $"\nStale: {neuroid.stale}"); + } + else { + tooltip = new( + $"{neuroid.name}" + + $"\nsynapse count {neuroid.synapses.Count}" + + $"\nValue: {neuroid.outputValue}" + + $"\nStale: {neuroid.stale}"); + } + + Vector2 mousePosition = Event.current.mousePosition; + + // Display tooltip with some offset + Vector2 tooltipSize = GUI.skin.box.CalcSize(tooltip); + Rect tooltipRect = new Rect(mousePosition.x + 10, mousePosition.y + 10, tooltipSize.x, tooltipSize.y); + + GUI.Box(tooltipRect, tooltip); + } + + private void HandleDiscClicked(Nucleus nucleus) { + this.currentNucleus = nucleus; + BuildLayers(); + } + + + void DrawInspector() { + NanoBrainEditor.inspectorContainer.Clear(); + if (this.currentNucleus == null) + return; + + // create a SerializedObject wrapper so Unity inspector controls work (and Undo) + SerializedObject so = new SerializedObject(currentWrapper); + IMGUIContainer container = new IMGUIContainer(() => { + so.Update(); + currentNucleus.name = EditorGUILayout.TextField(currentNucleus.name); + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Output Value", GUILayout.Width(100)); + EditorGUILayout.Vector3Field(GUIContent.none, currentNucleus.outputValue); + EditorGUILayout.EndHorizontal(); + if (currentNucleus.synapses.Count > 0) { + EditorGUILayout.LabelField("Synapses"); + EditorGUI.indentLevel++; + + List nuclei = currentNucleus.synapses.Keys.ToList(); + foreach (Nucleus nucleus in nuclei) { + EditorGUI.BeginDisabledGroup(nucleus.isSleeping); + + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField(nucleus.name, GUILayout.Width(120)); + EditorGUI.indentLevel--; + EditorGUILayout.LabelField("Weight", GUILayout.Width(45)); + float weight = currentNucleus.synapses[nucleus]; + currentNucleus.synapses[nucleus] = EditorGUILayout.FloatField(weight, GUILayout.Width(40)); + EditorGUI.indentLevel++; + EditorGUILayout.Vector3Field(GUIContent.none, nucleus.outputValue, GUILayout.Width(180)); + EditorGUILayout.EndHorizontal(); + + EditorGUI.EndDisabledGroup(); + } + EditorGUI.indentLevel--; + } + if (GUILayout.Button("Add Neuron")) + AddInputNeuron(currentNucleus); + + }); + NanoBrainEditor.inspectorContainer.Add(container); + } + + protected virtual void AddInputNeuron(Nucleus receiver) { + Neuroid newNeuroid = new(NanoBrainEditor.brain, "New neuron"); + newNeuroid.AddReceiver(receiver); + Rebuild(); + } + + private Vector3 NodePosition(Nucleus nucleus, int layerNodeCount = 1) { + if (this.neuroidPositions.ContainsKey(nucleus)) { + Vector2Int nucleusPos = this.neuroidPositions[nucleus]; + return NodePosition(nucleusPos, layerNodeCount); + } + else { + return Vector3.zero; + } + } + private Vector3 NodePosition(Vector2Int location, int layerNodeCount = 1) { + float spacing = 400f / layerNodeCount; + float margin = 10 + spacing / 2; + float size = 20; + Vector3 parentPos = new(100 + location.x * 100 - size, margin + location.y * spacing - size, 0.1f); + return parentPos; + } + + // helper to save node position back to graph + // public void UpdateNodePosition(NucleusObj node, Vector2 worldPos) { + // Undo.RecordObject(graph, "Move Node"); + // node.position = (worldPos - pan) / zoom; + // EditorUtility.SetDirty(graph); + // } + + // create & delete APIs called by NodeView or toolbar + public void CreateNode(Vector2 worldPos) { + // Undo.RecordObject(graph, "Create Node"); + // var n = new NucleusObj("New Node"); //, position = (worldPos - pan) / zoom }; + // graph.nodes.Add(n); + // EditorUtility.SetDirty(graph); + // Rebuild(); + } + + // public void CreateEdge(string fromId, string toId) { + // if (fromId == toId) return; + // Undo.RecordObject(graph, "Create Edge"); + // graph.edges.Add(new GraphEdge { fromNodeId = fromId, toNodeId = toId }); + // EditorUtility.SetDirty(graph); + // Rebuild(); + // } +} + +/* +public class NodeView : VisualElement { + Nucleus data; + GraphBoardView board; + Label titleLabel; + //bool dragging = false; + Vector2 localDragStart; + + public NodeView(Nucleus node, GraphBoardView boardView) { + data = node; + board = boardView; + name = "node"; + style.width = 20; //node.size.x; + style.height = 20; //node.size.y; + + titleLabel = new Label(node.name) { name = "title" }; + Add(titleLabel); + + // ports + // var outPort = new Button(() => StartEdgeDrag(true)) { text = "◀", name = "out" }; + // var inPort = new Button(() => StartEdgeDrag(false)) { text = "▶", name = "in" }; + // Add(outPort); + // Add(inPort); + + RegisterCallback(OnMouseDown); + // RegisterCallback(OnMouseMove); + RegisterCallback(OnMouseUp); + //RegisterCallback(e => dragging = false); + } + + // void StartEdgeDrag(bool isOutput) { + // // simplified: on first click store source; on second click on target port call board.CreateEdge + // if (EdgeDragState.active == null) EdgeDragState.active = new EdgeDragState { fromNode = data, fromIsOutput = isOutput }; + // else { + // var src = EdgeDragState.active.fromNode; + // if (src != null && src.id != data.id) board.CreateEdge(src.id, data.id); + // EdgeDragState.active = null; + // } + // } + + void OnMouseDown(MouseDownEvent e) { + if (e.button == 0 && e.target == this) { + //dragging = true; + localDragStart = e.mousePosition; + e.StopPropagation(); + } + } + // void OnMouseMove(MouseMoveEvent e) { + // if (!dragging) return; + // var delta = e.mousePosition - localDragStart; + // var worldPos = new Vector2(layout.x + delta.x, layout.y + delta.y); + // style.left = worldPos.x; + // style.top = worldPos.y; + // // commit on every move + // board.UpdateNodePosition(data, worldPos); + // } + void OnMouseUp(MouseUpEvent e) { + //dragging = false; + } +} +*/ + +public class GraphNodeWrapper : ScriptableObject { + // expose fields that map to GraphNode + public string title; + public Vector2 position; + Nucleus node; + NanoBrainObj graph; // needed to write back and mark dirty + + public GraphNodeWrapper Init(Nucleus node, NanoBrainObj graphAsset) { + this.node = node; + this.graph = graphAsset; + this.title = " A " + node.name; + //position = node.position; + return this; + } + void OnValidate() { + if (node != null) { + node.name = title; + //node.position = position; +#if UNITY_EDITOR + UnityEditor.EditorUtility.SetDirty(graph); +#endif + } + } +} +//static class EdgeDragState { public static EdgeDragState active; public GraphNode fromNode; public bool fromIsOutput; } \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs.meta b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs.meta new file mode 100644 index 0000000..99dedcd --- /dev/null +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c57f78e25f0e55b96a50fd5592b26317 \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs b/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs new file mode 100644 index 0000000..751854b --- /dev/null +++ b/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using UnityEngine; + +public class NanoBrainObj : ScriptableObject { + public Nucleus rootNucleus = new("root"); + + public List neuroids = new(); + + public Neuroid AddNeuron(string name) { + Neuroid neuroid = new(this, name); + return neuroid; + } + + public void UpdateNeurons() { + foreach (Neuroid neuroid in neuroids) { + neuroid.stale++; + if (neuroid.isSleeping) + neuroid.outputValue = Vector3.zero; + } + } + +} \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs.meta b/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs.meta new file mode 100644 index 0000000..40e85f2 --- /dev/null +++ b/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 36081359186edfec998d891a1feeb17b \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/NeuroidObject.cs b/Assets/NanoBrain/VisualEditor/NeuroidObject.cs new file mode 100644 index 0000000..e69de29 diff --git a/Assets/NanoBrain/VisualEditor/NeuroidObject.cs.meta b/Assets/NanoBrain/VisualEditor/NeuroidObject.cs.meta new file mode 100644 index 0000000..8d0614f --- /dev/null +++ b/Assets/NanoBrain/VisualEditor/NeuroidObject.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d14e756f390f41a1c9923a0015329389 \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/NucleusObject.cs b/Assets/NanoBrain/VisualEditor/NucleusObject.cs new file mode 100644 index 0000000..989f603 --- /dev/null +++ b/Assets/NanoBrain/VisualEditor/NucleusObject.cs @@ -0,0 +1,28 @@ +// using System.Collections.Generic; +// using UnityEngine; + +// public class NucleusObj : ScriptableObject { +// public virtual string objName { get; set; } + +// public readonly Dictionary synapses = new(); +// public HashSet receivers = new(); +// public virtual Vector3 outputValue { get; set; } + +// public int stale = 0; + +// public NucleusObj(string name) { +// this.objName = name; +// } + +// public virtual void AddReceiver(NucleusObj receiver) { +// this.receivers.Add(receiver); +// receiver.synapses[this] = 1.0f; +// } + +// public bool isSleeping { +// get { +// return this.stale > 2; +// } +// } + +// } \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/NucleusObject.cs.meta b/Assets/NanoBrain/VisualEditor/NucleusObject.cs.meta new file mode 100644 index 0000000..e867330 --- /dev/null +++ b/Assets/NanoBrain/VisualEditor/NucleusObject.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ca2a41cdae50b5005b5cf10cebb28de6 \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/Resources.meta b/Assets/NanoBrain/VisualEditor/Resources.meta new file mode 100644 index 0000000..e9c19e4 --- /dev/null +++ b/Assets/NanoBrain/VisualEditor/Resources.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7b61a93fc9332d2adae74fe4abe92d53 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/NanoBrain/VisualEditor/Resources/GraphStyles.uss b/Assets/NanoBrain/VisualEditor/Resources/GraphStyles.uss new file mode 100644 index 0000000..d059194 --- /dev/null +++ b/Assets/NanoBrain/VisualEditor/Resources/GraphStyles.uss @@ -0,0 +1,15 @@ +#main { + +} +#content { + background-color: #2b2b2b, + position: absolute; +} +#inspector { + border-left-width: 1px; + border-left-color: #000; + border-left_style: solid; + padding: 3px; +} +.node { background-color: #222; border-radius:4px; padding:6px; } +#title { unity-font-style: bold; color: white; } diff --git a/Assets/NanoBrain/VisualEditor/Resources/GraphStyles.uss.meta b/Assets/NanoBrain/VisualEditor/Resources/GraphStyles.uss.meta new file mode 100644 index 0000000..2546c45 --- /dev/null +++ b/Assets/NanoBrain/VisualEditor/Resources/GraphStyles.uss.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 28268b644fa8f3948851b25e41f5b03b +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} + disableValidation: 0 diff --git a/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs b/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs index 7fbb301..f8a119d 100644 --- a/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs +++ b/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs @@ -11,7 +11,7 @@ public class Roaming : Nucleus { output.GetInputFrom(avoidance, -sc.avoidanceForce); } - public override void AddReceiver(Neuroid receiver) { + public override void AddReceiver(Nucleus receiver) { output.AddReceiver(receiver); } } \ No newline at end of file diff --git a/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs b/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs index 580761f..64f675f 100644 --- a/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs +++ b/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs @@ -30,7 +30,7 @@ public class Swarming : Nucleus { this.output.GetInputFrom(boundary, -sc.avoidanceForce); } - public override void AddReceiver(Neuroid receiver) { + public override void AddReceiver(Nucleus receiver) { this.output.AddReceiver(receiver); } } \ No newline at end of file diff --git a/Assets/_Recovery/0.unity b/Assets/_Recovery/0.unity deleted file mode 100644 index d2192f7..0000000 --- a/Assets/_Recovery/0.unity +++ /dev/null @@ -1,1123 +0,0 @@ -%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: 10 - 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: 0 - m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} - m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 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_UseRadianceAmbientProbe: 0 ---- !u!157 &3 -LightmapSettings: - m_ObjectHideFlags: 0 - serializedVersion: 13 - m_BakeOnSceneLoad: 0 - m_GISettings: - serializedVersion: 2 - m_BounceScale: 1 - m_IndirectOutputScale: 1 - m_AlbedoBoost: 1 - m_EnvironmentLightingMode: 0 - m_EnableBakedLightmaps: 1 - 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_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: 1 - m_PVRFilteringGaussRadiusAO: 1 - m_PVRFilteringAtrousPositionSigmaDirect: 0.5 - m_PVRFilteringAtrousPositionSigmaIndirect: 2 - m_PVRFilteringAtrousPositionSigmaAO: 1 - m_ExportTrainingData: 0 - m_TrainingDataDestination: TrainingData - m_LightProbeSampleCountMultiplier: 4 - m_LightingDataAsset: {fileID: 20201, guid: 0000000000000000f000000000000000, type: 0} - m_LightingSettings: {fileID: 0} ---- !u!196 &4 -NavMeshSettings: - serializedVersion: 2 - m_ObjectHideFlags: 0 - m_BuildSettings: - serializedVersion: 3 - 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 - buildHeightMesh: 0 - maxJobWorkers: 0 - preserveTilesOutsideBounds: 0 - debug: - m_Flags: 0 - m_NavMeshData: {fileID: 0} ---- !u!1 &231291185 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 231291186} - - component: {fileID: 231291189} - - component: {fileID: 231291188} - - component: {fileID: 231291187} - m_Layer: 0 - m_Name: Wall (1) - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &231291186 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 231291185} - serializedVersion: 2 - m_LocalRotation: {x: 0.5, y: 0.5, z: -0.5, w: 0.5} - m_LocalPosition: {x: -5, y: 5, z: 0} - m_LocalScale: {x: 10, y: 1, z: 10} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 1826482027} - m_LocalEulerAnglesHint: {x: 90, y: 90, z: 0} ---- !u!65 &231291187 -BoxCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 231291185} - m_Material: {fileID: 0} - m_IncludeLayers: - serializedVersion: 2 - m_Bits: 0 - m_ExcludeLayers: - serializedVersion: 2 - m_Bits: 0 - m_LayerOverridePriority: 0 - m_IsTrigger: 0 - m_ProvidesContacts: 0 - m_Enabled: 1 - serializedVersion: 3 - m_Size: {x: 1, y: 1, z: 1} - m_Center: {x: 0, y: 0, z: 0} ---- !u!23 &231291188 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 231291185} - m_Enabled: 0 - m_CastShadows: 1 - m_ReceiveShadows: 1 - m_DynamicOccludee: 1 - m_StaticShadowCaster: 0 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 2 - m_RayTraceProcedural: 0 - m_RayTracingAccelStructBuildFlagsOverride: 0 - m_RayTracingAccelStructBuildFlags: 1 - m_SmallMeshCulling: 1 - m_ForceMeshLod: -1 - m_MeshLodSelectionBias: 0 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_GlobalIlluminationMeshLod: 0 - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_AdditionalVertexStreams: {fileID: 0} ---- !u!33 &231291189 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 231291185} - m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} ---- !u!1 &246180153 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 246180154} - - component: {fileID: 246180157} - - component: {fileID: 246180156} - - component: {fileID: 246180155} - m_Layer: 0 - m_Name: Wall (2) - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &246180154 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 246180153} - serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0.7071068, z: -0.7071068, w: 0} - m_LocalPosition: {x: 0, y: 5, z: 5} - m_LocalScale: {x: 10, y: 1, z: 10} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 1826482027} - m_LocalEulerAnglesHint: {x: 90, y: 180, z: 0} ---- !u!65 &246180155 -BoxCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 246180153} - m_Material: {fileID: 0} - m_IncludeLayers: - serializedVersion: 2 - m_Bits: 0 - m_ExcludeLayers: - serializedVersion: 2 - m_Bits: 0 - m_LayerOverridePriority: 0 - m_IsTrigger: 0 - m_ProvidesContacts: 0 - m_Enabled: 1 - serializedVersion: 3 - m_Size: {x: 1, y: 1, z: 1} - m_Center: {x: 0, y: 0, z: 0} ---- !u!23 &246180156 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 246180153} - m_Enabled: 0 - m_CastShadows: 1 - m_ReceiveShadows: 1 - m_DynamicOccludee: 1 - m_StaticShadowCaster: 0 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 2 - m_RayTraceProcedural: 0 - m_RayTracingAccelStructBuildFlagsOverride: 0 - m_RayTracingAccelStructBuildFlags: 1 - m_SmallMeshCulling: 1 - m_ForceMeshLod: -1 - m_MeshLodSelectionBias: 0 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_GlobalIlluminationMeshLod: 0 - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_AdditionalVertexStreams: {fileID: 0} ---- !u!33 &246180157 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 246180153} - m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} ---- !u!1 &301943977 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 301943980} - - component: {fileID: 301943979} - - component: {fileID: 301943978} - m_Layer: 0 - m_Name: Swarm - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &301943978 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 301943977} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 0464906885ae3494f8fd0314719fb2db, type: 3} - m_Name: - m_EditorClassIdentifier: Assembly-CSharp::SwarmControl - speed: 0.5 - inertia: 0.1 - alignmentForce: 1 - cohesionForce: 10 - separationForce: 5 - separationDistance: 0.5 - bodyForce: 20 - boundaryForce: 5 - spaceSize: {x: 10, y: 10, z: 10} - boundaryWidth: {x: 1, y: 1, z: 1} ---- !u!114 &301943979 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 301943977} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: ec888ca5333d45a438f9f417fa5ce135, type: 3} - m_Name: - m_EditorClassIdentifier: Assembly-CSharp::SwarmSpawn - count: 10 - boidPrefab: {fileID: 8702527964058765413, guid: f9c706268554ce449a8773675b2864b8, type: 3} - spawnAreaSize: {x: 0.5, y: 0.5, z: 0.5} - minDelay: 0.1 - maxDelay: 1 ---- !u!4 &301943980 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 301943977} - serializedVersion: 2 - 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_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &704151342 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 704151343} - - component: {fileID: 704151346} - - component: {fileID: 704151345} - - component: {fileID: 704151344} - m_Layer: 0 - m_Name: Ceiling - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &704151343 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 704151342} - serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 10, z: 0} - m_LocalScale: {x: 10, y: 1, z: 10} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 1826482027} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!65 &704151344 -BoxCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 704151342} - m_Material: {fileID: 0} - m_IncludeLayers: - serializedVersion: 2 - m_Bits: 0 - m_ExcludeLayers: - serializedVersion: 2 - m_Bits: 0 - m_LayerOverridePriority: 0 - m_IsTrigger: 0 - m_ProvidesContacts: 0 - m_Enabled: 1 - serializedVersion: 3 - m_Size: {x: 1, y: 1, z: 1} - m_Center: {x: 0, y: 0, z: 0} ---- !u!23 &704151345 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 704151342} - m_Enabled: 1 - m_CastShadows: 1 - m_ReceiveShadows: 1 - m_DynamicOccludee: 1 - m_StaticShadowCaster: 0 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 2 - m_RayTraceProcedural: 0 - m_RayTracingAccelStructBuildFlagsOverride: 0 - m_RayTracingAccelStructBuildFlags: 1 - m_SmallMeshCulling: 1 - m_ForceMeshLod: -1 - m_MeshLodSelectionBias: 0 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_GlobalIlluminationMeshLod: 0 - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_AdditionalVertexStreams: {fileID: 0} ---- !u!33 &704151346 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 704151342} - m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} ---- !u!1 &837238090 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 837238092} - - component: {fileID: 837238091} - - component: {fileID: 837238093} - m_Layer: 0 - m_Name: Directional Light - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!108 &837238091 -Light: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 837238090} - m_Enabled: 1 - serializedVersion: 11 - m_Type: 1 - m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} - m_Intensity: 1 - m_Range: 10 - m_SpotAngle: 30 - m_InnerSpotAngle: 21.80208 - m_CookieSize: 10 - m_Shadows: - m_Type: 2 - m_Resolution: -1 - m_CustomResolution: -1 - m_Strength: 1 - m_Bias: 0.05 - m_NormalBias: 0.4 - m_NearPlane: 0.2 - m_CullingMatrixOverride: - e00: 1 - e01: 0 - e02: 0 - e03: 0 - e10: 0 - e11: 1 - e12: 0 - e13: 0 - e20: 0 - e21: 0 - e22: 1 - e23: 0 - e30: 0 - e31: 0 - e32: 0 - e33: 1 - m_UseCullingMatrixOverride: 0 - m_Cookie: {fileID: 0} - m_DrawHalo: 0 - m_Flare: {fileID: 0} - m_RenderMode: 0 - m_CullingMask: - serializedVersion: 2 - m_Bits: 4294967295 - m_RenderingLayerMask: 1 - m_Lightmapping: 4 - m_LightShadowCasterMode: 0 - m_AreaSize: {x: 1, y: 1} - m_BounceIntensity: 1 - m_ColorTemperature: 6570 - m_UseColorTemperature: 0 - m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} - m_UseBoundingSphereOverride: 0 - m_UseViewFrustumForShadowCasterCull: 1 - m_ForceVisible: 0 - m_ShadowRadius: 0 - m_ShadowAngle: 0 - m_LightUnit: 1 - m_LuxAtDistance: 1 - m_EnableSpotReflector: 1 ---- !u!4 &837238092 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 837238090} - serializedVersion: 2 - m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} - m_LocalPosition: {x: 0, y: 3, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} ---- !u!114 &837238093 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 837238090} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 474bcb49853aa07438625e644c072ee6, type: 3} - m_Name: - m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.UniversalAdditionalLightData - m_UsePipelineSettings: 1 - m_AdditionalLightsShadowResolutionTier: 2 - m_CustomShadowLayers: 0 - m_LightCookieSize: {x: 1, y: 1} - m_LightCookieOffset: {x: 0, y: 0} - m_SoftShadowQuality: 0 - m_RenderingLayersMask: - serializedVersion: 0 - m_Bits: 1 - m_ShadowRenderingLayersMask: - serializedVersion: 0 - m_Bits: 1 - m_Version: 4 - m_LightLayerMask: 1 - m_ShadowLayerMask: 1 - m_RenderingLayers: 1 - m_ShadowRenderingLayers: 1 ---- !u!1 &1633626499 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1633626502} - - component: {fileID: 1633626501} - - component: {fileID: 1633626500} - 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 &1633626500 -AudioListener: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1633626499} - m_Enabled: 1 ---- !u!20 &1633626501 -Camera: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1633626499} - 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_Iso: 200 - m_ShutterSpeed: 0.005 - m_Aperture: 16 - m_FocusDistance: 10 - m_FocalLength: 50 - m_BladeCount: 5 - m_Curvature: {x: 2, y: 11} - m_BarrelClipping: 0.25 - m_Anamorphism: 0 - m_SensorSize: {x: 36, y: 24} - m_LensShift: {x: 0, y: 0} - 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: 0 - 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 &1633626502 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1633626499} - serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 1, z: -10} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &1690670936 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1690670937} - - component: {fileID: 1690670940} - - component: {fileID: 1690670939} - - component: {fileID: 1690670938} - m_Layer: 0 - m_Name: Floor - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &1690670937 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1690670936} - serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 10, y: 1, z: 10} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 1826482027} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!65 &1690670938 -BoxCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1690670936} - m_Material: {fileID: 0} - m_IncludeLayers: - serializedVersion: 2 - m_Bits: 0 - m_ExcludeLayers: - serializedVersion: 2 - m_Bits: 0 - m_LayerOverridePriority: 0 - m_IsTrigger: 0 - m_ProvidesContacts: 0 - m_Enabled: 1 - serializedVersion: 3 - m_Size: {x: 1, y: 1, z: 1} - m_Center: {x: 0, y: 0, z: 0} ---- !u!23 &1690670939 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1690670936} - m_Enabled: 1 - m_CastShadows: 1 - m_ReceiveShadows: 1 - m_DynamicOccludee: 1 - m_StaticShadowCaster: 0 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 2 - m_RayTraceProcedural: 0 - m_RayTracingAccelStructBuildFlagsOverride: 0 - m_RayTracingAccelStructBuildFlags: 1 - m_SmallMeshCulling: 1 - m_ForceMeshLod: -1 - m_MeshLodSelectionBias: 0 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_GlobalIlluminationMeshLod: 0 - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_AdditionalVertexStreams: {fileID: 0} ---- !u!33 &1690670940 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1690670936} - m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} ---- !u!1 &1738679977 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1738679978} - - component: {fileID: 1738679981} - - component: {fileID: 1738679980} - - component: {fileID: 1738679979} - m_Layer: 0 - m_Name: Wall - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &1738679978 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1738679977} - serializedVersion: 2 - m_LocalRotation: {x: 0.7071068, y: 0, z: 0, w: 0.7071068} - m_LocalPosition: {x: 0, y: 5, z: -5} - m_LocalScale: {x: 10, y: 1, z: 10} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 1826482027} - m_LocalEulerAnglesHint: {x: 90, y: 0, z: 0} ---- !u!65 &1738679979 -BoxCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1738679977} - m_Material: {fileID: 0} - m_IncludeLayers: - serializedVersion: 2 - m_Bits: 0 - m_ExcludeLayers: - serializedVersion: 2 - m_Bits: 0 - m_LayerOverridePriority: 0 - m_IsTrigger: 0 - m_ProvidesContacts: 0 - m_Enabled: 1 - serializedVersion: 3 - m_Size: {x: 1, y: 1, z: 1} - m_Center: {x: 0, y: 0, z: 0} ---- !u!23 &1738679980 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1738679977} - m_Enabled: 0 - m_CastShadows: 1 - m_ReceiveShadows: 1 - m_DynamicOccludee: 1 - m_StaticShadowCaster: 0 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 2 - m_RayTraceProcedural: 0 - m_RayTracingAccelStructBuildFlagsOverride: 0 - m_RayTracingAccelStructBuildFlags: 1 - m_SmallMeshCulling: 1 - m_ForceMeshLod: -1 - m_MeshLodSelectionBias: 0 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_GlobalIlluminationMeshLod: 0 - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_AdditionalVertexStreams: {fileID: 0} ---- !u!33 &1738679981 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1738679977} - m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} ---- !u!1 &1826482026 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1826482027} - m_Layer: 0 - m_Name: Boundary - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &1826482027 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1826482026} - serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: -0, y: -5, z: -0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 1690670937} - - {fileID: 1738679978} - - {fileID: 231291186} - - {fileID: 246180154} - - {fileID: 1924016461} - - {fileID: 704151343} - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &1924016460 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1924016461} - - component: {fileID: 1924016464} - - component: {fileID: 1924016463} - - component: {fileID: 1924016462} - m_Layer: 0 - m_Name: Wall (3) - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &1924016461 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1924016460} - serializedVersion: 2 - m_LocalRotation: {x: -0.5, y: 0.5, z: -0.5, w: -0.5} - m_LocalPosition: {x: 5, y: 5, z: 0} - m_LocalScale: {x: 10, y: 1, z: 10} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 1826482027} - m_LocalEulerAnglesHint: {x: 90, y: 270, z: 0} ---- !u!65 &1924016462 -BoxCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1924016460} - m_Material: {fileID: 0} - m_IncludeLayers: - serializedVersion: 2 - m_Bits: 0 - m_ExcludeLayers: - serializedVersion: 2 - m_Bits: 0 - m_LayerOverridePriority: 0 - m_IsTrigger: 0 - m_ProvidesContacts: 0 - m_Enabled: 1 - serializedVersion: 3 - m_Size: {x: 1, y: 1, z: 1} - m_Center: {x: 0, y: 0, z: 0} ---- !u!23 &1924016463 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1924016460} - m_Enabled: 0 - m_CastShadows: 1 - m_ReceiveShadows: 1 - m_DynamicOccludee: 1 - m_StaticShadowCaster: 0 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 2 - m_RayTraceProcedural: 0 - m_RayTracingAccelStructBuildFlagsOverride: 0 - m_RayTracingAccelStructBuildFlags: 1 - m_SmallMeshCulling: 1 - m_ForceMeshLod: -1 - m_MeshLodSelectionBias: 0 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_GlobalIlluminationMeshLod: 0 - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_AdditionalVertexStreams: {fileID: 0} ---- !u!33 &1924016464 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1924016460} - m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} ---- !u!1660057539 &9223372036854775807 -SceneRoots: - m_ObjectHideFlags: 0 - m_Roots: - - {fileID: 1633626502} - - {fileID: 837238092} - - {fileID: 301943980} - - {fileID: 1826482027} diff --git a/NanoBrain-Unity.slnx b/NanoBrain-Unity.slnx index 90452ad..398dc64 100644 --- a/NanoBrain-Unity.slnx +++ b/NanoBrain-Unity.slnx @@ -1,4 +1,4 @@  - + From 605bdfc62906ab8759043a4c26a0629aa3d4df79 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Fri, 5 Dec 2025 15:29:18 +0100 Subject: [PATCH 019/179] Scriptable nanobrain --- Assembly-CSharp-Editor.csproj | 2 + Assembly-CSharp.csproj | 1 + Assets/NanoBrain/Editor/NanoBrain_Editor.cs | 33 +- Assets/NanoBrain/Editor/NeuroidWindow.cs | 35 +- Assets/NanoBrain/Neuroid.cs | 43 +- Assets/NanoBrain/Nucleus.cs | 154 +++++- Assets/NanoBrain/Perception.cs | 19 +- Assets/NanoBrain/SensoryNeuroid.cs | 23 +- .../Editor/NanoBrainComponent_Editor.cs | 94 ++++ .../Editor/NanoBrainComponent_Editor.cs.meta | 2 + .../VisualEditor/Editor/NanoBrainEditor.cs | 130 +++-- .../VisualEditor/Editor/NanoBrainInspector.cs | 484 ++++++++++++++++++ .../Editor/NanoBrainInspector.cs.meta | 2 + .../VisualEditor/NanoBrainComponent.cs | 15 + .../VisualEditor/NanoBrainComponent.cs.meta | 2 + Assets/NanoBrain/VisualEditor/NanoBrainObj.cs | 39 +- Assets/Scenes/Boids/Boid Graph.asset | 17 - Assets/Scenes/Boids/New Nano Brain Obj.asset | 28 + ...set.meta => New Nano Brain Obj.asset.meta} | 2 +- Assets/Scenes/Boids/Prefabs/Boid.prefab | 24 +- Assets/Scenes/Boids/Scripts/Boid.cs | 35 +- Assets/Scenes/Boids/Scripts/RoamingNucleus.cs | 2 +- .../Scenes/Boids/Scripts/SwarmingNucleus.cs | 2 +- 23 files changed, 1024 insertions(+), 164 deletions(-) create mode 100644 Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs create mode 100644 Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs.meta create mode 100644 Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs create mode 100644 Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs.meta create mode 100644 Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs create mode 100644 Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs.meta delete mode 100644 Assets/Scenes/Boids/Boid Graph.asset create mode 100644 Assets/Scenes/Boids/New Nano Brain Obj.asset rename Assets/Scenes/Boids/{Boid Graph.asset.meta => New Nano Brain Obj.asset.meta} (79%) diff --git a/Assembly-CSharp-Editor.csproj b/Assembly-CSharp-Editor.csproj index e94da31..08fa44b 100644 --- a/Assembly-CSharp-Editor.csproj +++ b/Assembly-CSharp-Editor.csproj @@ -49,8 +49,10 @@ + + diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index af65fe2..4067143 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -53,6 +53,7 @@ + diff --git a/Assets/NanoBrain/Editor/NanoBrain_Editor.cs b/Assets/NanoBrain/Editor/NanoBrain_Editor.cs index 79fed6a..b877b32 100644 --- a/Assets/NanoBrain/Editor/NanoBrain_Editor.cs +++ b/Assets/NanoBrain/Editor/NanoBrain_Editor.cs @@ -26,15 +26,15 @@ public class NanoBrain_Editor : Editor { } private void SelectNeuron() { - GameObject selectedObject = ((NanoBrain)target).gameObject; - if (!selectedObject.TryGetComponent(out Boid boid)) - return; + // GameObject selectedObject = ((NanoBrain)target).gameObject; + // if (!selectedObject.TryGetComponent(out Boid boid)) + // return; - Nucleus neuroid = boid.totalForce; - this.currentNucleus = neuroid; + // Nucleus neuroid = boid.totalForce; + // this.currentNucleus = neuroid; - BuildLayers(); - Debug.Log($"Layercount = {this.layers.Count}"); + // BuildLayers(); + // Debug.Log($"Layercount = {this.layers.Count}"); } #endregion Start @@ -57,7 +57,11 @@ public class NanoBrain_Editor : Editor { EditorGUILayout.Vector3Field("Output Value", currentNucleus.outputValue); if (currentNucleus.synapses.Count > 0) { EditorGUI.indentLevel++; - foreach ((Nucleus nucleus, float weight) in currentNucleus.synapses) { + //foreach ((Nucleus nucleus, float weight) in currentNucleus.synapses) { + foreach (Synapse synapse in currentNucleus.synapses) { + Nucleus nucleus = synapse.nucleus; + float weight = synapse.weight; + EditorGUI.BeginDisabledGroup(nucleus.isSleeping); EditorGUILayout.BeginHorizontal(); @@ -83,7 +87,9 @@ public class NanoBrain_Editor : Editor { return; NeuroidLayer currentLayer = new() { ix = layerIx }; - foreach (Neuroid outputNeuroid in selectedNucleus.receivers) { + //foreach (Neuroid outputNeuroid in selectedNucleus.receivers) { + foreach (Receiver receiver in selectedNucleus.receivers) { + Nucleus outputNeuroid = receiver.nucleus; if (outputNeuroid != null) { AddToLayer(currentLayer, outputNeuroid); // Debug.Log($"layer {layerIx} nucleus {outputNeuroid.name}"); @@ -102,7 +108,9 @@ public class NanoBrain_Editor : Editor { layerIx++; currentLayer = new() { ix = layerIx }; - foreach (Nucleus input in selectedNucleus.synapses.Keys) { + //foreach (Nucleus input in selectedNucleus.synapses.Keys) { + foreach (Synapse synapse in selectedNucleus.synapses) { + Nucleus input = synapse.nucleus; AddToLayer(currentLayer, input); // Debug.Log($"layer {layerIx} nucleus {input.name}"); } @@ -151,7 +159,10 @@ public class NanoBrain_Editor : Editor { float inputSpacing = 400f / layerNeuroid.synapses.Count; float inputMargin = 10 + inputSpacing / 2; int minStale = 10000; - foreach ((Nucleus nucleus, float weight) in layerNeuroid.synapses) { + //foreach ((Nucleus nucleus, float weight) in layerNeuroid.synapses) { + foreach (Synapse synapse in layerNeuroid.synapses) { + Nucleus nucleus = synapse.nucleus; + float weight = synapse.weight; if (this.neuroidPositions.ContainsKey(nucleus)) { Vector2Int inputNeuroidPos = this.neuroidPositions[nucleus]; if (inputNeuroidPos.x == layerNeuroidPos.x + 1) { diff --git a/Assets/NanoBrain/Editor/NeuroidWindow.cs b/Assets/NanoBrain/Editor/NeuroidWindow.cs index a725c97..b3e17a2 100644 --- a/Assets/NanoBrain/Editor/NeuroidWindow.cs +++ b/Assets/NanoBrain/Editor/NeuroidWindow.cs @@ -40,7 +40,9 @@ public class GraphEditorWindow : EditorWindow { return; NeuroidLayer currentLayer = new() { ix = layerIx }; - foreach (Nucleus outputNeuroid in selectedNucleus.receivers) { + //foreach (Nucleus outputNeuroid in selectedNucleus.receivers) { + foreach (Receiver receiver in selectedNucleus.receivers) { + Nucleus outputNeuroid = receiver.nucleus; if (outputNeuroid != null) { AddToLayer(currentLayer, outputNeuroid); Debug.Log($"layer {layerIx} nucleus {outputNeuroid.name}"); @@ -64,7 +66,9 @@ public class GraphEditorWindow : EditorWindow { // Debug.Log($"Synapse {six}"); // Nucleus input = synapse.neuroid; //foreach ((Nucleus input, Synapse synapse) in selectedNucleus.synapses) { - foreach ((Nucleus input, float weight) in selectedNucleus.synapses) { + //foreach ((Nucleus input, float weight) in selectedNucleus.synapses) { + foreach (Synapse synapse in selectedNucleus.synapses) { + Nucleus input = synapse.nucleus; if (input != null) { AddToLayer(currentLayer, input); Debug.Log($"layer {layerIx} nucleus {input.name}"); @@ -104,8 +108,10 @@ public class GraphEditorWindow : EditorWindow { // If the output neuroid is visited // Note: this does not yet work for multiple outputs yet (see the use of First()) + // if (neuroid.receivers.Count == 0 // make sure the root neuroids are processed directly + // || (neuronVisited.Contains(neuroid.receivers.First()) && neuroid.receivers.First().layerIx == layerIx - 1)) { if (neuroid.receivers.Count == 0 // make sure the root neuroids are processed directly - || (neuronVisited.Contains(neuroid.receivers.First()) && neuroid.receivers.First().layerIx == layerIx - 1)) { + || (neuronVisited.Contains(neuroid.receivers.First().nucleus) && neuroid.receivers.First().nucleus.layerIx == layerIx - 1)) { // Add it to the next layer currentLayer.neuroids.Add(neuroid); neuroid.layerIx = layerIx; @@ -182,7 +188,10 @@ public class GraphEditorWindow : EditorWindow { // Vector2Int inputNeuroidPos = this.neuroidPositions[synapse.neuroid]; //foreach ((Nucleus neuroid, Synapse synapse) in layerNeuroid.synapses) { - foreach ((Nucleus neuroid, float weight) in layerNeuroid.synapses) { + //foreach ((Nucleus neuroid, float weight) in layerNeuroid.synapses) { + foreach (Synapse synapse in layerNeuroid.synapses) { + Nucleus neuroid = synapse.nucleus; + float weight = synapse.weight; if (neuroid != null) { if (this.neuroidPositions.ContainsKey(neuroid)) { Vector2Int inputNeuroidPos = this.neuroidPositions[neuroid]; @@ -272,17 +281,17 @@ public class GraphEditorWindow : EditorWindow { if (boid == null) return; - Nucleus neuroid = boid.behaviour; - this.currentNucleus = neuroid; - if (neuroid == null) - this.allNeuroids = new(); - else - this.allNeuroids = neuroid.brain.neuroids; + // Nucleus neuroid = boid.behaviour; + // this.currentNucleus = neuroid; + // if (neuroid == null) + // this.allNeuroids = new(); + // else + // this.allNeuroids = neuroid.brain.neuroids; - Debug.Log($"Neuroncount = {this.allNeuroids.Count}"); - BuildLayers(); - Debug.Log($"Layercount = {this.layers.Count}"); + // Debug.Log($"Neuroncount = {this.allNeuroids.Count}"); + // BuildLayers(); + // Debug.Log($"Layercount = {this.layers.Count}"); } diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index 33bb553..3c45ddd 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -5,7 +5,7 @@ public class Neuroid : Nucleus { public bool inverse = false; public float exponent = 1.0f; - public Neuroid(NanoBrain brain, string name) : base(name) { + public Neuroid(NanoBrain brain, string name) : base(null, name) { this.brain = brain; if (this.brain != null) this.brain.neuroids.Add(this); @@ -13,43 +13,46 @@ public class Neuroid : Nucleus { Debug.LogError("No neuroid network"); } - public Neuroid(NanoBrainObj brain, string name) : base(name) { - this.newBrain = brain; - if (this.newBrain != null) - this.newBrain.neuroids.Add(this); - else - Debug.LogError("No neuroid network"); + public Neuroid(NanoBrainObj brain, string name) : base(brain, name) { } public void SetWeight(Neuroid input, float weight) { - this.synapses[input] = weight; + //this.synapses[input] = weight; + this.SetWeight((Nucleus)input, weight); } - public void GetInputFrom(Neuroid input, float weight = 1.0f) { - input.AddReceiver(this); - this.synapses[input] = weight; - } + // public void GetInputFrom(Neuroid input, float weight = 1.0f) { + // input.AddReceiver(this); + // //this.synapses[input] = weight; + // this.SetWeight((Nucleus)input, weight); + // } public void SetInput(Neuroid input) { - if (this.synapses.ContainsKey(input) == false) - this.synapses[input] = 1.0f; + // if (this.synapses.ContainsKey(input) == false) + // this.synapses[input] = 1.0f; + if (this.SynapseExists(input)) + this.SetWeight(input, 1.0f); UpdateState(); } public void SetInput(Neuroid input, float weight) { - this.synapses[input] = weight; + //this.synapses[input] = weight; + this.SetWeight(input, weight); UpdateState(); } public virtual void UpdateState() { Vector3 result = Vector3.zero; - foreach ((Nucleus nucleus, float weight) in this.synapses) { + //foreach ((Nucleus nucleus, float weight) in this.synapses) { + foreach (Synapse synapse in this.synapses) { + Nucleus nucleus = synapse.nucleus; if (nucleus is Neuroid neuroid && neuroid.isSleeping) continue; - + Vector3 direction = nucleus.outputValue.normalized; float magnitude = nucleus.outputValue.magnitude; + float weight = synapse.weight; magnitude = weight * Mathf.Pow(magnitude, exponent); if (inverse && magnitude > 0) magnitude = 1 / magnitude; @@ -62,8 +65,10 @@ public class Neuroid : Nucleus { this.outputValue = result; this.stale = 0; - foreach (Neuroid receiver in this.receivers) - receiver.SetInput(this); + foreach (Receiver receiver in this.receivers) { + if (receiver.nucleus is Neuroid neuroid) + neuroid.SetInput(this); + } } // public bool IsStale() { diff --git a/Assets/NanoBrain/Nucleus.cs b/Assets/NanoBrain/Nucleus.cs index e5646e7..034e304 100644 --- a/Assets/NanoBrain/Nucleus.cs +++ b/Assets/NanoBrain/Nucleus.cs @@ -1,35 +1,169 @@ using System.Collections.Generic; using UnityEngine; +[System.Serializable] public class Nucleus { - public int stale = 0; + + public int id; // hash code + + [SerializeField] + protected string _name; + public virtual string name { + get => _name; + set => _name = value; + } + + //public readonly Dictionary synapses = new(); + [SerializeField] + public List synapses = new(); + //public HashSet receivers = new(); + [SerializeField] + public List receivers = new(); + + #region Serialization + + public void Rebuild(NanoBrainObj brain) { + if (this.synapses != null) { + foreach (Synapse synapse in synapses) + synapse.Rebuild(brain); + } + if (this.receivers == null) + this.receivers = new(); + else + foreach (Receiver receiver in receivers) + receiver.Rebuild(brain); + } + + #endregion + + #region Runtime state (not serialized) public NanoBrain brain { get; protected set; } public NanoBrainObj newBrain { get; protected set; } - public virtual string name { get; set; } - - public readonly Dictionary synapses = new(); - public HashSet receivers = new(); public virtual Vector3 outputValue { get; set; } + [System.NonSerialized] + public int stale = 0; + [System.NonSerialized] public int layerIx; - public Nucleus(string name) { - this.name = name; + #endregion Runtime state + + public Nucleus(NanoBrainObj brain, string name) { + this.newBrain = brain; + if (this.newBrain != null) + this.newBrain.nuclei.Add(this); + else + Debug.LogError("No neuroid network"); + + this._name = name; + this.id = this.GetHashCode(); } public virtual void AddReceiver(Nucleus receiver) { - //Debug.Log($"add receiver to {this} for {receiver} {receiver.GetHashCode()} {this.receivers.Count} {receiver.synapses.Count}"); - this.receivers.Add(receiver); - receiver.synapses[this] = 1.0f; // new(this); + this.receivers.Add(new Receiver(receiver)); + //receiver.synapses[this] = 1.0f; // new(this); + receiver.SetWeight(this, 1.0f); //Debug.Log($"receiver # {this.receivers.Count} synapse count {receiver.synapses.Count}"); } + public static void Delete(Nucleus nucleus) { + foreach (Synapse synapse in nucleus.synapses) { + if (synapse.nucleus.receivers.Count > 1) { + // there is another nucleus feeding into this input nucleus + synapse.nucleus.receivers.RemoveAll(r => r.nucleus == nucleus); + } else { + // No other links, delete it. + Nucleus.Delete(synapse.nucleus); + } + } + foreach (Receiver receiver in nucleus.receivers) + receiver.nucleus.synapses.RemoveAll(s => s.nucleus == nucleus); + + nucleus.newBrain.nuclei.RemoveAll(n => n == nucleus); + } + + public void GetInputFrom(Nucleus input, float weight = 1.0f) { + input.AddReceiver(this); + this.SetWeight(input, weight); + } + public bool isSleeping { get { return this.stale > 2; } } + public bool SynapseExists(Nucleus nucleus) { + foreach (Synapse synapse in synapses) { + if (synapse.nucleus == nucleus) + return true; + } + return false; + } + + public void SetWeight(Nucleus nucleus, float weight) { + foreach (Synapse synapse in synapses) { + if (synapse.nucleus == nucleus) { + synapse.weight = weight; + return; + } + } + Synapse newSynapse = new(nucleus, weight); + synapses.Add(newSynapse); + } +} + +[System.Serializable] +public class Synapse { + [System.NonSerialized] + public Nucleus nucleus; + public int nucleusId; + public float weight; + + public Synapse(Nucleus nucleus, float weight) { + this.nucleus = nucleus; + this.nucleusId = nucleus.id; + this.weight = weight; + } + + public void Rebuild(NanoBrainObj brain) { + if (brain == null) { + return; + } + + foreach (Nucleus nucleus in brain.nuclei) { + if (nucleus.id == this.nucleusId) { + this.nucleus = nucleus; + return; + } + } + Debug.LogError($"Synapse deserialization error: could not find nucleus with id {this.nucleusId}"); + } +} + +[System.Serializable] +public class Receiver { + [System.NonSerialized] + public Nucleus nucleus; + public int nucleusId; + + public Receiver(Nucleus nucleus) { + this.nucleus = nucleus; + this.nucleusId = nucleus.id; + } + + public void Rebuild(NanoBrainObj brain) { + if (brain == null) + return; + + foreach (Nucleus nucleus in brain.nuclei) { + if (nucleus.id == this.nucleusId) { + this.nucleus = nucleus; + return; + } + } + Debug.LogError($"Synapse deserialization error: could not find nucleus with id {this.nucleusId}"); + } } \ No newline at end of file diff --git a/Assets/NanoBrain/Perception.cs b/Assets/NanoBrain/Perception.cs index 3353d62..11f917b 100644 --- a/Assets/NanoBrain/Perception.cs +++ b/Assets/NanoBrain/Perception.cs @@ -7,19 +7,26 @@ public class Perception : Nucleus { public class Receiver { public int thingType = 0; - public Neuroid neuroid; + public Nucleus neuroid; } public HashSet positionReceivers { get; protected set; } public HashSet velocityReceivers { get; protected set; } - public Perception(NanoBrain neuroidNet) : base("Perception") { + public Perception(NanoBrainObj brain) : base(brain, "Perception") { + //this.brain = brain; + this.positionReceivers = new(); + this.velocityReceivers = new(); + } + + + public Perception(NanoBrain neuroidNet) : base(null, "Perception") { this.brain = neuroidNet; this.positionReceivers = new(); this.velocityReceivers = new(); } - public void SendPositions(Neuroid receivingNeuroid, int thingType = 0, float weight = 1.0f) { + public void SendPositions(Nucleus receivingNeuroid, int thingType = 0, float weight = 1.0f) { Receiver receiver = new() { thingType = thingType, neuroid = receivingNeuroid @@ -28,11 +35,11 @@ public class Perception : Nucleus { foreach (SensoryNeuroid neuroid in sensoryNeuroids) { if (neuroid != null) { neuroid.AddReceiver(receivingNeuroid); - receivingNeuroid.synapses[neuroid] = weight; + receivingNeuroid.SetWeight(neuroid, weight); } } } - public void SendVelocities(Neuroid receivingNeuroid, int thingType = 0, float weight = 1.0f) { + public void SendVelocities(Nucleus receivingNeuroid, int thingType = 0, float weight = 1.0f) { Receiver receiver = new() { thingType = thingType, neuroid = receivingNeuroid @@ -41,7 +48,7 @@ public class Perception : Nucleus { foreach (SensoryNeuroid neuroid in sensoryNeuroids) { if (neuroid != null && neuroid.velocityNeuroid != null) { neuroid.velocityNeuroid.AddReceiver(receivingNeuroid); - receivingNeuroid.synapses[neuroid] = weight; + receivingNeuroid.SetWeight(neuroid, weight); } } } diff --git a/Assets/NanoBrain/SensoryNeuroid.cs b/Assets/NanoBrain/SensoryNeuroid.cs index 02b6865..0129717 100644 --- a/Assets/NanoBrain/SensoryNeuroid.cs +++ b/Assets/NanoBrain/SensoryNeuroid.cs @@ -58,7 +58,10 @@ public class SensoryNeuroid : Neuroid { public override void UpdateState() { Vector3 result = receptor.localPosition; - foreach ((Nucleus nucleus, float weight) in this.synapses) { + //foreach ((Nucleus nucleus, float weight) in this.synapses) { + foreach (Synapse synapse in this.synapses) { + Nucleus nucleus = synapse.nucleus; + float weight = synapse.weight; Vector3 direction = nucleus.outputValue.normalized; float magnitude = nucleus.outputValue.magnitude; @@ -71,8 +74,10 @@ public class SensoryNeuroid : Neuroid { result /= this.synapses.Count + 1; this.outputValue = result; - foreach (Neuroid neuroid in this.receivers) - neuroid.SetInput(this); + //foreach (Neuroid neuroid in this.receivers) + foreach (Receiver receiver in this.receivers) + if (receiver.nucleus is Neuroid neuroid) + neuroid.SetInput(this); this.stale = 0; } } @@ -87,14 +92,15 @@ public class VelocityNeuroid : Neuroid { public void Replace(string name = "velocity") { this.name = name; - this.receivers = new(); + this.receivers = new(); this.lastPosition = Vector3.zero; this.lastValueTime = 0; } public override void UpdateState() { // Assuming only one synapse for now.... - Vector3 currentPosition = this.synapses.First().Key.outputValue; + //Vector3 currentPosition = this.synapses.First().Key.outputValue; + Vector3 currentPosition = this.synapses.First().nucleus.outputValue; float currentValueTime = Time.time; if (lastValueTime != 0) { @@ -106,8 +112,11 @@ public class VelocityNeuroid : Neuroid { this.outputValue = velocity; this.stale = 0; - foreach (Neuroid receiver in receivers) - receiver?.SetInput(this); + //foreach (Neuroid receiver in receivers) + foreach(Receiver receiver in receivers) { + if (receiver.nucleus is Neuroid neuroid) + neuroid.SetInput(this); + } } this.lastValueTime = currentValueTime; diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs new file mode 100644 index 0000000..e762a1e --- /dev/null +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs @@ -0,0 +1,94 @@ +using UnityEditor; +using UnityEditor.UIElements; +using UnityEngine; +using UnityEngine.UIElements; + +[CustomEditor(typeof(NanoBrainComponent))] +public class NanoBrainComponent_Editor : Editor { + protected static VisualElement mainContainer; + protected static VisualElement inspectorContainer; + + private SerializedProperty brainProp; + + public void OnEnable() { + brainProp = serializedObject.FindProperty(nameof(NanoBrainComponent.brain)); + } + + public override VisualElement CreateInspectorGUI() { + NanoBrainComponent component = target as NanoBrainComponent; + NanoBrainObj brain = component.brain; + + serializedObject.Update(); + + + VisualElement root = new(); + root.style.flexDirection = FlexDirection.Column; // side-by-side layout + root.style.flexGrow = 1; + root.style.minHeight = 600; + root.style.paddingLeft = 0; + root.style.paddingRight = 0; + root.style.paddingTop = 0; + root.style.paddingBottom = 0; + + root.styleSheets.Add(Resources.Load("GraphStyles")); + + PropertyField brainField = new(brainProp); + brainField.label = "Nano Brain"; + root.Add(brainField); + + mainContainer = new() { + name = "main", + style = { + flexDirection = FlexDirection.Row, + flexGrow = 1, + minHeight = 500, + } + }; + NanoBrainInspector.GraphView board; + board = new NanoBrainInspector.GraphView(); + board.style.flexGrow = 1; + + inspectorContainer = new VisualElement { + name = "inspector", + style = { + width = 400, + } + }; + + mainContainer.Add(board); + mainContainer.Add(inspectorContainer); + root.Add(mainContainer); + + // Run once for initial state (use resolved style width if available) + float initialWidth = root.layout.width > 0 ? root.layout.width : root.contentRect.width; + UpdateLayout(initialWidth); + + // React to size changes of root (or parent if appropriate) + root.RegisterCallback(evt => { + UpdateLayout(evt.newRect.width); + }); + + if (brain != null) + board.SetGraph(brain, brain.root, inspectorContainer); + else + Debug.LogWarning(" No brain!"); + + serializedObject.ApplyModifiedProperties(); + return root; + } + + private void UpdateLayout(float containerWidth) { + if (containerWidth > 800f) { + mainContainer.style.flexDirection = FlexDirection.Row; + inspectorContainer.style.width = 400; // fixed sidebar width + inspectorContainer.style.flexGrow = 0; + } + else { + mainContainer.style.flexDirection = FlexDirection.Column; + inspectorContainer.style.width = Length.Percent(100); // full width below + inspectorContainer.style.flexDirection = FlexDirection.Column; + inspectorContainer.style.flexGrow = 1; // can set 0 or keep as needed + } + } + +} \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs.meta b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs.meta new file mode 100644 index 0000000..eaf830b --- /dev/null +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f05072314d39990639a2dbf99f322664 \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs index c496504..2e38c69 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs @@ -1,6 +1,7 @@ using UnityEditor; using UnityEngine; using UnityEngine.UIElements; +using UnityEditor.Callbacks; using System.Linq; using System.Collections.Generic; @@ -10,7 +11,7 @@ public class NucleusLayer { } public class NanoBrainEditor : EditorWindow { - public static NanoBrainObj brain; + public NanoBrainObj brain; public static VisualElement inspectorContainer; @@ -19,20 +20,28 @@ public class NanoBrainEditor : EditorWindow { GetWindow("NanoBrain Editor"); } + public static void Open(NanoBrainObj asset) { + NanoBrainEditor editor = GetWindow("NanoBrain Editor"); + editor.brain = asset; + editor.Show(); + } + GraphBoardView board; private void OnEnable() { + OnFocus(); + } + private void OnFocus() { if (brain == null) { - brain = CreateInstance(); - EditorUtility.SetDirty(brain); + // brain = CreateInstance(); + // EditorUtility.SetDirty(brain); + return; } VisualElement root = rootVisualElement; + root.Clear(); root.styleSheets.Add(Resources.Load("GraphStyles")); - root.Add(board); - root.Add(inspectorContainer); - VisualElement main = new() { name = "main", style = { @@ -53,11 +62,15 @@ public class NanoBrainEditor : EditorWindow { main.Add(inspectorContainer); root.Add(main); - board.SetGraph(brain.rootNucleus); + board.SetGraph(brain, brain.root); + } + } public class GraphBoardView : VisualElement { + NanoBrainObj brain; + SerializedObject serializedBrain; Nucleus currentNucleus; private List layers = new(); private Dictionary neuroidPositions = new(); @@ -86,7 +99,9 @@ public class GraphBoardView : VisualElement { RegisterCallback(OnMouseUp); } - public void SetGraph(Nucleus nucleus) { + public void SetGraph(NanoBrainObj brain, Nucleus nucleus) { + this.brain = brain; + this.serializedBrain = new SerializedObject(brain); this.currentNucleus = nucleus; Rebuild(); } @@ -101,7 +116,7 @@ public class GraphBoardView : VisualElement { if (currentWrapper != null) Object.DestroyImmediate(currentWrapper); - currentWrapper = ScriptableObject.CreateInstance().Init(currentNucleus, NanoBrainEditor.brain); + currentWrapper = ScriptableObject.CreateInstance().Init(currentNucleus, brain); DrawInspector(); } @@ -115,7 +130,9 @@ public class GraphBoardView : VisualElement { return; NeuroidLayer currentLayer = new() { ix = layerIx }; - foreach (Nucleus outputNeuroid in selectedNucleus.receivers) { + //foreach (Nucleus outputNeuroid in selectedNucleus.receivers) { + foreach (Receiver receiver in selectedNucleus.receivers) { + Nucleus outputNeuroid = receiver.nucleus; if (outputNeuroid != null) { AddToLayer(currentLayer, outputNeuroid); // Debug.Log($"layer {layerIx} nucleus {outputNeuroid.name}"); @@ -134,7 +151,9 @@ public class GraphBoardView : VisualElement { layerIx++; currentLayer = new() { ix = layerIx }; - foreach (Nucleus input in selectedNucleus.synapses.Keys) { + //foreach (Nucleus input in selectedNucleus.synapses.Keys) { + foreach (Synapse synapse in selectedNucleus.synapses) { + Nucleus input = synapse.nucleus; AddToLayer(currentLayer, input); // Debug.Log($"layer {layerIx} nucleus {input.name}"); } @@ -144,6 +163,8 @@ public class GraphBoardView : VisualElement { } private void AddToLayer(NeuroidLayer layer, Nucleus nucleus) { + if (nucleus == null) + return; layer.neuroids.Add(nucleus); nucleus.layerIx = layer.ix; // Store its position @@ -186,10 +207,13 @@ public class GraphBoardView : VisualElement { if (currentNucleus == null) return; + serializedBrain.Update(); + Handles.BeginGUI(); foreach (NeuroidLayer layer in layers) DrawLayer(layer); Handles.EndGUI(); + } private void DrawLayer(NeuroidLayer layer) { @@ -212,19 +236,24 @@ public class GraphBoardView : VisualElement { float inputSpacing = 400f / layerNucleus.synapses.Count; float inputMargin = 10 + inputSpacing / 2; int minStale = 10000; - foreach ((Nucleus nucleus, float weight) in layerNucleus.synapses) { - if (this.neuroidPositions.ContainsKey(nucleus)) { - Vector2Int inputNeuroidPos = this.neuroidPositions[nucleus]; - if (inputNeuroidPos.x == layerNeuroidPos.x + 1) { - Vector3 pos = new(100 + inputNeuroidPos.x * 100, inputMargin + inputNeuroidPos.y * inputSpacing, 0.0f); + //foreach ((Nucleus nucleus, float weight) in layerNucleus.synapses) { + foreach (Synapse synapse in layerNucleus.synapses) { + Nucleus nucleus = synapse.nucleus; + if (nucleus != null) { + float weight = synapse.weight; + if (this.neuroidPositions.ContainsKey(nucleus)) { + Vector2Int inputNeuroidPos = this.neuroidPositions[nucleus]; + if (inputNeuroidPos.x == layerNeuroidPos.x + 1) { + Vector3 pos = new(100 + inputNeuroidPos.x * 100, inputMargin + inputNeuroidPos.y * inputSpacing, 0.0f); - float brightness = weight / 10.0f; - Handles.color = new Color(brightness, brightness, brightness); - Handles.DrawLine(parentPos, pos); + float brightness = weight / 10.0f; + Handles.color = new Color(brightness, brightness, brightness); + Handles.DrawLine(parentPos, pos); + } } + if (nucleus is Neuroid neuroid && neuroid.stale < minStale) + minStale = neuroid.stale; } - if (nucleus is Neuroid neuroid && neuroid.stale < minStale) - minStale = neuroid.stale; } if (layerNucleus.synapses.Count > 0 && minStale > 2 && layerNucleus.stale < 3) @@ -255,7 +284,7 @@ public class GraphBoardView : VisualElement { // Process Hover HandleMouseHover(layerNucleus, neuronRect); // Process click - Debug.Log($"{et} {e.type}"); + // Debug.Log($"{et} {e.type}"); if (e.type == EventType.MouseDown && e.button == 0) { // Consume the event so the scene doesn't also handle it e.Use(); @@ -298,6 +327,9 @@ public class GraphBoardView : VisualElement { void DrawInspector() { + if (NanoBrainEditor.inspectorContainer == null) + return; + NanoBrainEditor.inspectorContainer.Clear(); if (this.currentNucleus == null) return; @@ -315,18 +347,20 @@ public class GraphBoardView : VisualElement { EditorGUILayout.LabelField("Synapses"); EditorGUI.indentLevel++; - List nuclei = currentNucleus.synapses.Keys.ToList(); - foreach (Nucleus nucleus in nuclei) { - EditorGUI.BeginDisabledGroup(nucleus.isSleeping); + //List nuclei = currentNucleus.synapses.Keys.ToList(); + // foreach (Nucleus nucleus in nuclei) { + foreach (Synapse synapse in currentNucleus.synapses) { + EditorGUI.BeginDisabledGroup(synapse.nucleus.isSleeping); EditorGUILayout.BeginHorizontal(); - EditorGUILayout.LabelField(nucleus.name, GUILayout.Width(120)); + EditorGUILayout.LabelField(synapse.nucleus.name, GUILayout.Width(120)); EditorGUI.indentLevel--; EditorGUILayout.LabelField("Weight", GUILayout.Width(45)); - float weight = currentNucleus.synapses[nucleus]; - currentNucleus.synapses[nucleus] = EditorGUILayout.FloatField(weight, GUILayout.Width(40)); + // float weight = currentNucleus.synapses[nucleus]; + // currentNucleus.synapses[nucleus] = EditorGUILayout.FloatField(weight, GUILayout.Width(40)); + synapse.weight = EditorGUILayout.FloatField(synapse.weight, GUILayout.Width(40)); EditorGUI.indentLevel++; - EditorGUILayout.Vector3Field(GUIContent.none, nucleus.outputValue, GUILayout.Width(180)); + EditorGUILayout.Vector3Field(GUIContent.none, synapse.nucleus.outputValue, GUILayout.Width(180)); EditorGUILayout.EndHorizontal(); EditorGUI.EndDisabledGroup(); @@ -334,14 +368,15 @@ public class GraphBoardView : VisualElement { EditorGUI.indentLevel--; } if (GUILayout.Button("Add Neuron")) - AddInputNeuron(currentNucleus); + AddInputNeuron(currentNucleus); }); + NanoBrainEditor.inspectorContainer.Add(container); } protected virtual void AddInputNeuron(Nucleus receiver) { - Neuroid newNeuroid = new(NanoBrainEditor.brain, "New neuron"); + Neuroid newNeuroid = new(brain, "New neuron"); newNeuroid.AddReceiver(receiver); Rebuild(); } @@ -363,21 +398,6 @@ public class GraphBoardView : VisualElement { return parentPos; } - // helper to save node position back to graph - // public void UpdateNodePosition(NucleusObj node, Vector2 worldPos) { - // Undo.RecordObject(graph, "Move Node"); - // node.position = (worldPos - pan) / zoom; - // EditorUtility.SetDirty(graph); - // } - - // create & delete APIs called by NodeView or toolbar - public void CreateNode(Vector2 worldPos) { - // Undo.RecordObject(graph, "Create Node"); - // var n = new NucleusObj("New Node"); //, position = (worldPos - pan) / zoom }; - // graph.nodes.Add(n); - // EditorUtility.SetDirty(graph); - // Rebuild(); - } // public void CreateEdge(string fromId, string toId) { // if (fromId == toId) return; @@ -469,9 +489,23 @@ public class GraphNodeWrapper : ScriptableObject { node.name = title; //node.position = position; #if UNITY_EDITOR - UnityEditor.EditorUtility.SetDirty(graph); + if (graph != null) + UnityEditor.EditorUtility.SetDirty(graph); #endif } } } -//static class EdgeDragState { public static EdgeDragState active; public GraphNode fromNode; public bool fromIsOutput; } \ No newline at end of file +//static class EdgeDragState { public static EdgeDragState active; public GraphNode fromNode; public bool fromIsOutput; } + +public static class OpenAssetHandler { + // Called when an asset is double-clicked or opened. + [OnOpenAsset] + public static bool OpenMyScriptableObject(int instanceID, int line) { + NanoBrainObj obj = EditorUtility.InstanceIDToObject(instanceID) as NanoBrainObj; + if (obj != null) { + NanoBrainEditor.Open(obj); + return true; // handled + } + return false; // let Unity open normally + } +} diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs new file mode 100644 index 0000000..2b36ad9 --- /dev/null +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs @@ -0,0 +1,484 @@ +using System.Collections.Generic; + +using UnityEditor; + +using UnityEngine; +using UnityEngine.UIElements; + +[CustomEditor(typeof(NanoBrainObj))] +public class NanoBrainInspector : Editor { + protected static VisualElement mainContainer; + protected static VisualElement inspectorContainer; + + //private Nucleus currentNucleus = null; + private List layers = new(); + private Dictionary neuroidPositions = new(); + + protected bool breakOnWake = false; + + #region Start + + public override VisualElement CreateInspectorGUI() { + NanoBrainObj brain = target as NanoBrainObj; + + serializedObject.Update(); + + VisualElement root = new(); + root.style.flexDirection = FlexDirection.Column; // side-by-side layout + root.style.flexGrow = 1; + root.style.minHeight = 600; + root.style.paddingLeft = 0; + root.style.paddingRight = 0; + root.style.paddingTop = 0; + root.style.paddingBottom = 0; + + root.styleSheets.Add(Resources.Load("GraphStyles")); + + mainContainer = new() { + name = "main", + style = { + flexDirection = FlexDirection.Row, + flexGrow = 1, + minHeight = 500, + } + }; + GraphView board; + board = new GraphView(); + board.style.flexGrow = 1; + + inspectorContainer = new VisualElement { + name = "inspector", + style = { + width = 400, + } + }; + + mainContainer.Add(board); + mainContainer.Add(inspectorContainer); + root.Add(mainContainer); + + // Run once for initial state (use resolved style width if available) + float initialWidth = root.layout.width > 0 ? root.layout.width : root.contentRect.width; + UpdateLayout(initialWidth); + + // React to size changes of root (or parent if appropriate) + root.RegisterCallback(evt => { + UpdateLayout(evt.newRect.width); + }); + + if (brain != null) + board.SetGraph(brain, brain.root, inspectorContainer); + else + Debug.LogWarning(" No brain!"); + + serializedObject.ApplyModifiedProperties(); + return root; + } + + public class GraphView : VisualElement { + NanoBrainObj brain; + SerializedObject serializedBrain; + Nucleus currentNucleus; + private List layers = new(); + private readonly Dictionary neuroidPositions = new(); + + Vector2 pan = Vector2.zero; + //float zoom = 1f; + bool draggingCanvas = false; + Vector2 lastMouse; + GraphNodeWrapper currentWrapper; + + public GraphView() { + name = "content"; + style.flexGrow = 1; + + IMGUIContainer imguiContainer = new(OnIMGUI); + imguiContainer.style.position = Position.Absolute; + imguiContainer.style.left = 0; imguiContainer.style.top = 0; + imguiContainer.style.right = 0; imguiContainer.style.bottom = 0; + imguiContainer.pickingMode = PickingMode.Position; + imguiContainer.focusable = true; + Add(imguiContainer); + + //RegisterCallback(OnWheel); + RegisterCallback(OnMouseDown); + RegisterCallback(OnMouseMove); + RegisterCallback(OnMouseUp); + } + + public void SetGraph(NanoBrainObj brain, Nucleus nucleus, VisualElement inspectorContainer) { + this.brain = brain; + this.serializedBrain = new SerializedObject(brain); + this.currentNucleus = nucleus; + Rebuild(inspectorContainer); + } + + void Rebuild(VisualElement inspectorContainer) { + BuildLayers(); + + if (this.currentNucleus == null) { + inspectorContainer.Clear(); + return; + } + + if (currentWrapper != null) + DestroyImmediate(currentWrapper); + currentWrapper = CreateInstance().Init(this.currentNucleus, brain); + DrawInspector(inspectorContainer); + } + + private void BuildLayers() { + // A temporary list to track what's been added to layers + this.layers = new(); + int layerIx = 0; + + Nucleus selectedNucleus = this.currentNucleus; + if (selectedNucleus == null) + return; + NeuroidLayer currentLayer = new() { ix = layerIx }; + + if (selectedNucleus.receivers != null) { + foreach (Receiver receiver in selectedNucleus.receivers) { + Nucleus outputNeuroid = receiver.nucleus; + if (outputNeuroid != null) { + AddToLayer(currentLayer, outputNeuroid); + // Debug.Log($"layer {layerIx} nucleus {outputNeuroid.name}"); + } + } + } + if (currentLayer.neuroids.Count > 0) { + this.layers.Add(currentLayer); + layerIx++; + currentLayer = new() { ix = layerIx }; + } + + AddToLayer(currentLayer, selectedNucleus); + this.layers.Add(currentLayer); + // Debug.Log($"layer {layerIx} nucleus {selectedNucleus.name}"); + + layerIx++; + currentLayer = new() { ix = layerIx }; + + if (selectedNucleus.synapses != null) { + foreach (Synapse synapse in selectedNucleus.synapses) { + Nucleus input = synapse.nucleus; + AddToLayer(currentLayer, input); + // Debug.Log($"layer {layerIx} nucleus {input.name}"); + } + } + if (currentLayer.neuroids.Count > 0) { + this.layers.Add(currentLayer); + } + } + + private void AddToLayer(NeuroidLayer layer, Nucleus nucleus) { + if (nucleus == null) + return; + layer.neuroids.Add(nucleus); + nucleus.layerIx = layer.ix; + // Store its position + Vector2Int neuroidPosition = new(layer.ix, layer.neuroids.Count - 1); + neuroidPositions[nucleus] = neuroidPosition; + + } + + // basic pan/zoom handling + // void OnWheel(WheelEvent e) { + // if (e.ctrlKey) { + // float delta = -e.delta.y * 0.001f; + // zoom = Mathf.Clamp(zoom + delta, 0.25f, 2f); + // content.transform.rotation = Quaternion.identity; // keep transform accessible + // content.transform.scale = new Vector3(zoom, zoom, 1); + // e.StopPropagation(); + // } + // else { + // pan += e.delta; + // content.style.left = pan.x; + // content.style.top = pan.y; + // } + // } + + void OnMouseDown(MouseDownEvent e) { + if (e.button == 2) { draggingCanvas = true; lastMouse = e.mousePosition; e.StopPropagation(); } + } + void OnMouseMove(MouseMoveEvent e) { + if (draggingCanvas) { + var delta = e.mousePosition - lastMouse; + pan += delta; + //content.style.left = pan.x; + //content.style.top = pan.y; + lastMouse = e.mousePosition; + } + } + void OnMouseUp(MouseUpEvent e) { if (e.button == 2) draggingCanvas = false; } + + void OnIMGUI() { + if (currentNucleus == null) + return; + + serializedBrain.Update(); + + Handles.BeginGUI(); + foreach (NeuroidLayer layer in layers) + DrawLayer(layer); + Handles.EndGUI(); + + } + + private void DrawLayer(NeuroidLayer layer) { + int nodeCount = layer.neuroids.Count; + float maxValue = 0; + foreach (Nucleus nucleus in layer.neuroids) { + if (nucleus is Neuroid neuroid) { + float value = neuroid.outputValue.magnitude; + if (value > maxValue) + maxValue = value; + } + } + float spacing = 400f / nodeCount; + float margin = 10 + spacing / 2; + foreach (Nucleus layerNucleus in layer.neuroids) { + Vector2Int layerNeuroidPos = this.neuroidPositions[layerNucleus]; + Vector3 parentPos = new(100 + layerNeuroidPos.x * 100, margin + layerNeuroidPos.y * spacing, 0.1f); + + //int i = 0; + float inputSpacing = 400f / layerNucleus.synapses.Count; + float inputMargin = 10 + inputSpacing / 2; + int minStale = 10000; + //foreach ((Nucleus nucleus, float weight) in layerNucleus.synapses) { + foreach (Synapse synapse in layerNucleus.synapses) { + Nucleus nucleus = synapse.nucleus; + if (nucleus != null) { + float weight = synapse.weight; + if (this.neuroidPositions.ContainsKey(nucleus)) { + Vector2Int inputNeuroidPos = this.neuroidPositions[nucleus]; + if (inputNeuroidPos.x == layerNeuroidPos.x + 1) { + Vector3 pos = new(100 + inputNeuroidPos.x * 100, inputMargin + inputNeuroidPos.y * inputSpacing, 0.0f); + + //float brightness = weight / 10.0f; + Handles.color = Color.white; //new Color(brightness, brightness, brightness); + Handles.DrawLine(parentPos, pos); + } + } + if (nucleus is Neuroid neuroid && neuroid.stale < minStale) + minStale = neuroid.stale; + } + } + + // if (layerNucleus.synapses.Count > 0 && minStale > 2 && layerNucleus.stale < 3) + // Debug.LogWarning($"Strange {minStale} is big duing update"); + + + float size = 20; + if (layerNucleus.isSleeping) + Handles.color = Color.darkRed; + else { + float brightness = layerNucleus.outputValue.magnitude / maxValue; + Handles.color = new Color(brightness, brightness, brightness); + } + Handles.DrawSolidDisc(parentPos, Vector3.forward, size); + Vector3 labelPos = parentPos - Vector3.down * (size + 0.2f); // below disc along up axis + GUIStyle style = new GUIStyle(EditorStyles.label) { + alignment = TextAnchor.UpperCenter, + normal = { textColor = Color.white }, + fontStyle = FontStyle.Bold + }; + Handles.Label(labelPos, layerNucleus.name, style); + + Rect neuronRect = new(parentPos.x - size, parentPos.y - size, size * 2, size * 2); + int id = GUIUtility.GetControlID(FocusType.Passive); + Event e = Event.current; + EventType et = e.GetTypeForControl(id); + if (e != null && neuronRect.Contains(e.mousePosition)) { + // Process Hover + HandleMouseHover(layerNucleus, neuronRect); + // Process click + // Debug.Log($"{et} {e.type}"); + if (e.type == EventType.MouseDown && e.button == 0) { + // Consume the event so the scene doesn't also handle it + e.Use(); + HandleClicked(layerNucleus); + } + } + } + } + + private void HandleMouseHover(Nucleus neuroid, Rect rect) { + GUIContent tooltip; + if (neuroid is SensoryNeuroid sensoryNeuroid) { + tooltip = new( + $"{sensoryNeuroid.name}" + + $"\nThing {sensoryNeuroid.receptor.thingId}" + + $"\nValue: {neuroid.outputValue}" + + $"\nStale: {neuroid.stale}"); + } + else { + tooltip = new( + $"{neuroid.name}" + + $"\nsynapse count {neuroid.synapses.Count}" + + $"\nValue: {neuroid.outputValue}" + + $"\nStale: {neuroid.stale}"); + } + + Vector2 mousePosition = Event.current.mousePosition; + + // Display tooltip with some offset + Vector2 tooltipSize = GUI.skin.box.CalcSize(tooltip); + Rect tooltipRect = new Rect(mousePosition.x + 10, mousePosition.y + 10, tooltipSize.x, tooltipSize.y); + + GUI.Box(tooltipRect, tooltip); + } + + private void HandleClicked(Nucleus nucleus) { + this.currentNucleus = nucleus; + BuildLayers(); + } + + + void DrawInspector(VisualElement inspectorContainer) { + if (inspectorContainer == null) + return; + + inspectorContainer.Clear(); + if (this.currentNucleus == null) + return; + + // create a SerializedObject wrapper so Unity inspector controls work (and Undo) + SerializedObject so = new(currentWrapper); + IMGUIContainer container = new(() => { + if (so.targetObject == null) + return; + so.Update(); + this.currentNucleus.name = EditorGUILayout.TextField(this.currentNucleus.name); + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Output Value", GUILayout.Width(100)); + EditorGUILayout.Vector3Field(GUIContent.none, this.currentNucleus.outputValue); + EditorGUILayout.EndHorizontal(); + if (this.currentNucleus.synapses.Count > 0) { + EditorGUILayout.LabelField("Synapses"); + EditorGUI.indentLevel++; + + foreach (Synapse synapse in this.currentNucleus.synapses) { + if (synapse.nucleus != null) { + EditorGUI.BeginDisabledGroup(synapse.nucleus.isSleeping); + + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField(synapse.nucleus.name, GUILayout.Width(120)); + EditorGUI.indentLevel--; + EditorGUILayout.LabelField("Weight", GUILayout.Width(45)); + synapse.weight = EditorGUILayout.FloatField(synapse.weight, GUILayout.Width(40)); + EditorGUI.indentLevel++; + EditorGUILayout.Vector3Field(GUIContent.none, synapse.nucleus.outputValue, GUILayout.Width(180)); + EditorGUILayout.EndHorizontal(); + + EditorGUI.EndDisabledGroup(); + } + } + EditorGUI.indentLevel--; + } + if (GUILayout.Button("Add Neuron")) + AddInputNeuron(this.currentNucleus); + if (GUILayout.Button("Add Position Perception")) + AddPositionPerception(this.currentNucleus); + if (GUILayout.Button("Add Velocity Perception")) + AddVelocityPerception(this.currentNucleus); + if (GUILayout.Button("Delete this neuron")) + DeleteNeuron(this.currentNucleus); + + }); + + inspectorContainer.Add(container); + } + + protected virtual void AddInputNeuron(Nucleus receiver) { + Neuroid newNeuroid = new(this.brain, "New neuron"); + newNeuroid.AddReceiver(receiver); + //Rebuild(inspectorContainer); + BuildLayers(); + } + + protected virtual void DeleteNeuron(Nucleus nucleus) { + this.currentNucleus = nucleus.receivers[0].nucleus; + Nucleus.Delete(nucleus); + //Rebuild(inspectorContainer); + BuildLayers(); + } + + protected virtual void AddPositionPerception(Nucleus receiver) { + this.brain.perception.SendPositions(receiver); + } + protected virtual void AddVelocityPerception(Nucleus receiver) { + this.brain.perception.SendVelocities(receiver); + } + + private Vector3 NodePosition(Nucleus nucleus, int layerNodeCount = 1) { + if (this.neuroidPositions.ContainsKey(nucleus)) { + Vector2Int nucleusPos = this.neuroidPositions[nucleus]; + return NodePosition(nucleusPos, layerNodeCount); + } + else { + return Vector3.zero; + } + } + private Vector3 NodePosition(Vector2Int location, int layerNodeCount = 1) { + float spacing = 400f / layerNodeCount; + float margin = 10 + spacing / 2; + float size = 20; + Vector3 parentPos = new(100 + location.x * 100 - size, margin + location.y * spacing - size, 0.1f); + return parentPos; + } + + + // public void CreateEdge(string fromId, string toId) { + // if (fromId == toId) return; + // Undo.RecordObject(graph, "Create Edge"); + // graph.edges.Add(new GraphEdge { fromNodeId = fromId, toNodeId = toId }); + // EditorUtility.SetDirty(graph); + // Rebuild(); + // } + } + + #endregion Start + + #region Update + + private void UpdateLayout(float containerWidth) { + if (containerWidth > 800f) { + mainContainer.style.flexDirection = FlexDirection.Row; + inspectorContainer.style.width = 400; // fixed sidebar width + inspectorContainer.style.flexGrow = 0; + } + else { + mainContainer.style.flexDirection = FlexDirection.Column; + inspectorContainer.style.width = Length.Percent(100); // full width below + inspectorContainer.style.flexDirection = FlexDirection.Column; + inspectorContainer.style.flexGrow = 1; // can set 0 or keep as needed + } + } + + protected virtual void OnSceneGUI() { + NanoBrain brain = target as NanoBrain; + if (brain == null) + return; + + Vector3 position = brain.transform.position; + float radius = 1; + + + Handles.DrawWireDisc(position, Vector3.up, radius); // horizontal circle + Handles.DrawWireDisc(position, Vector3.right, radius); // X-plane + Handles.DrawWireDisc(position, Vector3.forward, radius); // Z-plane + + + // Debug.DrawRay(brain.transform.position, Vector3.forward, Color.magenta); + // Handles.color = Color.green; + // Handles.DrawLine(brain.transform.position, brain.transform.position + Vector3.up); + + // Handles.color = Color.yellow; + // Vector3 worldForce = brain.transform.TransformDirection(this.currentNucleus.outputValue); + // //Debug.DrawRay(position, worldForce * 10, Color.yellow); + // Handles.DrawLine(position, position + worldForce * 10); + } + + #endregion Update +} diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs.meta b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs.meta new file mode 100644 index 0000000..e71178e --- /dev/null +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c96ad47c3d4498640b52630789e38573 \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs b/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs new file mode 100644 index 0000000..f4e7090 --- /dev/null +++ b/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs @@ -0,0 +1,15 @@ +using UnityEngine; + +public class NanoBrainComponent : MonoBehaviour { + public NanoBrainObj brain; + public Nucleus root { + get { + return brain.root; + } + } + public Perception perception { + get { + return brain.perception; + } + } +} \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs.meta b/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs.meta new file mode 100644 index 0000000..1666c60 --- /dev/null +++ b/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 92f34a5e4027a1dc39efd8ce63cf6aba \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs b/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs index 751854b..a870d49 100644 --- a/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs +++ b/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs @@ -1,22 +1,49 @@ using System.Collections.Generic; using UnityEngine; -public class NanoBrainObj : ScriptableObject { - public Nucleus rootNucleus = new("root"); - - public List neuroids = new(); +[CreateAssetMenu(menuName = "Passer/NanoBrain")] +public class NanoBrainObj : ScriptableObject, ISerializationCallbackReceiver { + + public string title; + public int count; + public Color color = Color.white; + public Texture2D texture; + + public List nuclei = new(); + + // This is probably always the first element in the nuclei list... + [System.NonSerialized] + public Nucleus root; + public int rootId; + + public Perception perception; + + public NanoBrainObj() { + this.root = new(this, "Root"); + this.perception = new Perception(this); + } public Neuroid AddNeuron(string name) { Neuroid neuroid = new(this, name); return neuroid; } - public void UpdateNeurons() { - foreach (Neuroid neuroid in neuroids) { + public void UpdateNuclei() { + foreach (Neuroid neuroid in nuclei) { neuroid.stale++; if (neuroid.isSleeping) neuroid.outputValue = Vector3.zero; } } + public void OnBeforeSerialize() { + this.rootId = root.id; + } + public void OnAfterDeserialize() { + foreach (Nucleus nucleus in nuclei) { + if (this.rootId == nucleus.id) + this.root = nucleus; + nucleus.Rebuild(this); + } + } } \ No newline at end of file diff --git a/Assets/Scenes/Boids/Boid Graph.asset b/Assets/Scenes/Boids/Boid Graph.asset deleted file mode 100644 index bd6ef42..0000000 --- a/Assets/Scenes/Boids/Boid Graph.asset +++ /dev/null @@ -1,17 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 95e66c6366d904e98bc83428217d4fd7, type: 3} - m_Name: Boid Graph - m_EditorClassIdentifier: Unity.VisualScripting.Flow::Unity.VisualScripting.ScriptGraphAsset - _data: - _json: '{"graph":{"variables":{"Kind":"Flow","collection":{"$content":[],"$version":"A"},"$version":"A"},"controlInputDefinitions":[],"controlOutputDefinitions":[],"valueInputDefinitions":[],"valueOutputDefinitions":[],"title":null,"summary":null,"pan":{"x":0.0,"y":0.0},"zoom":1.0,"elements":[],"$version":"A"}}' - _objectReferences: [] diff --git a/Assets/Scenes/Boids/New Nano Brain Obj.asset b/Assets/Scenes/Boids/New Nano Brain Obj.asset new file mode 100644 index 0000000..1fc53fd --- /dev/null +++ b/Assets/Scenes/Boids/New Nano Brain Obj.asset @@ -0,0 +1,28 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 36081359186edfec998d891a1feeb17b, type: 3} + m_Name: New Nano Brain Obj + m_EditorClassIdentifier: Assembly-CSharp::NanoBrainObj + title: + count: 0 + color: {r: 1, g: 1, b: 1, a: 1} + texture: {fileID: 0} + nuclei: + - id: 257807948 + _name: Root + synapses: [] + receivers: [] + - id: -1868865374 + _name: Perception + synapses: [] + receivers: [] + rootId: 257807948 diff --git a/Assets/Scenes/Boids/Boid Graph.asset.meta b/Assets/Scenes/Boids/New Nano Brain Obj.asset.meta similarity index 79% rename from Assets/Scenes/Boids/Boid Graph.asset.meta rename to Assets/Scenes/Boids/New Nano Brain Obj.asset.meta index 3cefbaf..01cdcae 100644 --- a/Assets/Scenes/Boids/Boid Graph.asset.meta +++ b/Assets/Scenes/Boids/New Nano Brain Obj.asset.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 1a94b234cb4edce40bbe7e748f0508b3 +guid: 55099766f6f09071ab4e8c89b02fa302 NativeFormatImporter: externalObjects: {} mainObjectFileID: 11400000 diff --git a/Assets/Scenes/Boids/Prefabs/Boid.prefab b/Assets/Scenes/Boids/Prefabs/Boid.prefab index 89241e9..039cf86 100644 --- a/Assets/Scenes/Boids/Prefabs/Boid.prefab +++ b/Assets/Scenes/Boids/Prefabs/Boid.prefab @@ -123,6 +123,7 @@ GameObject: m_Component: - component: {fileID: 8702527964058765412} - component: {fileID: 9169912378811971808} + - component: {fileID: 85370558829139006} m_Layer: 0 m_Name: Boid m_TagString: Untagged @@ -158,16 +159,21 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: fe92e8a3728a1e444a25b79acf6b1d00, type: 3} m_Name: m_EditorClassIdentifier: - speed: 0.2 - neighbourCount: 0 - inertia: 0 - alignmentForce: 1 - cohesionForce: 1 - separationForce: 1 - separationDistance: 0.5 - bodyForce: 1 - debug: 0 sc: {fileID: 0} velocity: {x: 0, y: 0, z: 0} acceleration: {x: 0, y: 0, z: 0} + nanoBrain: {fileID: 0} id: 0 +--- !u!114 &85370558829139006 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8702527964058765413} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 92f34a5e4027a1dc39efd8ce63cf6aba, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::NanoBrainComponent + brain: {fileID: 11400000, guid: 55099766f6f09071ab4e8c89b02fa302, type: 2} diff --git a/Assets/Scenes/Boids/Scripts/Boid.cs b/Assets/Scenes/Boids/Scripts/Boid.cs index 0fb20f7..f13d7a9 100644 --- a/Assets/Scenes/Boids/Scripts/Boid.cs +++ b/Assets/Scenes/Boids/Scripts/Boid.cs @@ -1,6 +1,7 @@ using UnityEngine; -[RequireComponent(typeof(NanoBrain))] +//[RequireComponent(typeof(NanoBrain))] +[RequireComponent(typeof(NanoBrainComponent))] public class Boid : MonoBehaviour { public static int BoundaryType = 1; public static int BoidType = 2; @@ -11,17 +12,18 @@ public class Boid : MonoBehaviour { private Bounds innerBounds; - public NanoBrain neuroidNet; - public Perception perception; + public NanoBrainComponent nanoBrain; - public Nucleus behaviour; + // public NanoBrain neuroidNet; + // public Perception perception; - public Neuroid totalForce; + // public Nucleus behaviour; + + // public Neuroid totalForce; public int id; void Awake() { - neuroidNet = GetComponent(); this.id = this.GetInstanceID(); @@ -29,13 +31,14 @@ public class Boid : MonoBehaviour { innerBounds = new(sc.transform.position, sc.spaceSize - 2 * sc.boundaryWidth); - perception = new Perception(neuroidNet); + // neuroidNet = GetComponent(); + // perception = new Perception(neuroidNet); - //behaviour = new Roaming(neuroidNet, perception, sc); - behaviour = new Swarming(neuroidNet, perception, sc); + // //behaviour = new Roaming(neuroidNet, perception, sc); + // behaviour = new Swarming(neuroidNet, perception, sc); - totalForce = new(neuroidNet, "Total"); - behaviour.AddReceiver(totalForce); + // totalForce = new(neuroidNet, "Total"); + // behaviour.AddReceiver(totalForce); } void Update() { @@ -50,7 +53,7 @@ public class Boid : MonoBehaviour { //Debug.DrawRay(this.transform.position, this.transform.TransformDirection(localPosition), Color.magenta); int thingId = neighbour.GetInstanceID(); - perception.ProcessStimulus(thingId, BoidType, localPosition, neighbour.gameObject.name); + nanoBrain.perception.ProcessStimulus(thingId, BoidType, localPosition, neighbour.gameObject.name); } } @@ -59,10 +62,11 @@ public class Boid : MonoBehaviour { Vector3 pointOnBounds = innerBounds.ClosestPoint(point); Vector3 desiredWorldSpace = (pointOnBounds - point).normalized * sc.speed; Vector3 desiredLocalSpace = -this.transform.InverseTransformPoint(desiredWorldSpace); - perception.ProcessStimulus(777, BoundaryType, desiredLocalSpace, "Boundary"); + nanoBrain.perception.ProcessStimulus(777, BoundaryType, desiredLocalSpace, "Boundary"); } - Vector3 worldForce = this.transform.TransformDirection(behaviour.outputValue); + //Vector3 worldForce = this.transform.TransformDirection(behaviour.outputValue); + Vector3 worldForce = this.transform.TransformDirection(nanoBrain.root.outputValue); this.velocity = (1 - sc.inertia) * (worldForce * Time.deltaTime) + sc.inertia * velocity; if (this.velocity.magnitude > 0) @@ -78,7 +82,8 @@ public class Boid : MonoBehaviour { transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 2f); // Adjust the speed of rotation } - neuroidNet.UpdateNeurons(); + //neuroidNet.UpdateNeurons(); + nanoBrain.brain.UpdateNuclei(); } } diff --git a/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs b/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs index f8a119d..2ba38b7 100644 --- a/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs +++ b/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs @@ -3,7 +3,7 @@ public class Roaming : Nucleus { public Neuroid output; - public Roaming(NanoBrain neuroidNet, Perception perception, SwarmControl sc) : base("Roaming nucleus") { + public Roaming(NanoBrain neuroidNet, Perception perception, SwarmControl sc) : base(null, "Roaming nucleus") { avoidance = new(neuroidNet, "Avoidance") { inverse = true }; perception.SendPositions(avoidance, Boid.BoundaryType); diff --git a/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs b/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs index 64f675f..e0ea77b 100644 --- a/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs +++ b/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs @@ -10,7 +10,7 @@ public class Swarming : Nucleus { public override Vector3 outputValue { get => output.outputValue; set => output.outputValue = value; } - public Swarming(NanoBrain neuroidNet, Perception perception, SwarmControl sc) : base("Swarming Nucleus") { + public Swarming(NanoBrain neuroidNet, Perception perception, SwarmControl sc) : base(null, "Swarming Nucleus") { this.cohesion = new(neuroidNet, "Cohesion") { inverse = false }; perception.SendPositions(this.cohesion, Boid.BoidType); From 86b5053383514c2db0d3364c07a2860a0ec02e1a Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Fri, 5 Dec 2025 16:41:11 +0100 Subject: [PATCH 020/179] cleanup --- Assets/NanoBrain/NanoBrain.cs | 24 ++--- Assets/NanoBrain/Neuroid.cs | 14 +-- Assets/NanoBrain/Nucleus.cs | 4 +- Assets/NanoBrain/Perception.cs | 26 +++-- Assets/NanoBrain/SensoryNeuroid.cs | 7 +- .../VisualEditor/Editor/NanoBrainInspector.cs | 20 ++-- Assets/NanoBrain/VisualEditor/NanoBrainObj.cs | 8 +- Assets/Scenes/Boids/Boids.unity | 2 +- Assets/Scenes/Boids/New Nano Brain Obj.asset | 36 ++++++- Assets/Scenes/Boids/Prefabs/Boid.prefab | 2 +- Assets/Scenes/Boids/RoamingBrain.asset | 102 ++++++++++++++++++ Assets/Scenes/Boids/RoamingBrain.asset.meta | 8 ++ Assets/Scenes/Boids/Scripts/Boid.cs | 2 +- Assets/Scenes/Boids/Scripts/RoamingNucleus.cs | 6 +- .../Scenes/Boids/Scripts/SwarmingNucleus.cs | 12 +-- 15 files changed, 203 insertions(+), 70 deletions(-) create mode 100644 Assets/Scenes/Boids/RoamingBrain.asset create mode 100644 Assets/Scenes/Boids/RoamingBrain.asset.meta diff --git a/Assets/NanoBrain/NanoBrain.cs b/Assets/NanoBrain/NanoBrain.cs index a8e557b..9fca89a 100644 --- a/Assets/NanoBrain/NanoBrain.cs +++ b/Assets/NanoBrain/NanoBrain.cs @@ -5,18 +5,18 @@ public class NanoBrain : MonoBehaviour { // public NucleusObj rootNucleus; - public List neuroids = new(); + // public List neuroids = new(); - public Neuroid AddNeuron(string name) { - Neuroid neuroid = new(this, name); - return neuroid; - } + // public Neuroid AddNeuron(string name) { + // Neuroid neuroid = new(this, name); + // return neuroid; + // } - public void UpdateNeurons() { - foreach (Neuroid neuroid in neuroids) { - neuroid.stale++; - if (neuroid.isSleeping) - neuroid.outputValue = Vector3.zero; - } - } + // public void UpdateNeurons() { + // foreach (Neuroid neuroid in neuroids) { + // neuroid.stale++; + // if (neuroid.isSleeping) + // neuroid.outputValue = Vector3.zero; + // } + // } } diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index 3c45ddd..c2a2a30 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -5,13 +5,13 @@ public class Neuroid : Nucleus { public bool inverse = false; public float exponent = 1.0f; - public Neuroid(NanoBrain brain, string name) : base(null, name) { - this.brain = brain; - if (this.brain != null) - this.brain.neuroids.Add(this); - else - Debug.LogError("No neuroid network"); - } + // public Neuroid(NanoBrain brain, string name) : base(null, name) { + // this.brain = brain; + // if (this.brain != null) + // this.brain.neuroids.Add(this); + // else + // Debug.LogError("No neuroid network"); + // } public Neuroid(NanoBrainObj brain, string name) : base(brain, name) { } diff --git a/Assets/NanoBrain/Nucleus.cs b/Assets/NanoBrain/Nucleus.cs index 034e304..d78418e 100644 --- a/Assets/NanoBrain/Nucleus.cs +++ b/Assets/NanoBrain/Nucleus.cs @@ -38,7 +38,7 @@ public class Nucleus { #region Runtime state (not serialized) - public NanoBrain brain { get; protected set; } + // public NanoBrain brain { get; protected set; } public NanoBrainObj newBrain { get; protected set; } public virtual Vector3 outputValue { get; set; } @@ -80,7 +80,7 @@ public class Nucleus { } foreach (Receiver receiver in nucleus.receivers) receiver.nucleus.synapses.RemoveAll(s => s.nucleus == nucleus); - + nucleus.newBrain.nuclei.RemoveAll(n => n == nucleus); } diff --git a/Assets/NanoBrain/Perception.cs b/Assets/NanoBrain/Perception.cs index 11f917b..ccc254e 100644 --- a/Assets/NanoBrain/Perception.cs +++ b/Assets/NanoBrain/Perception.cs @@ -1,31 +1,27 @@ using System.Collections.Generic; using UnityEngine; - +[System.Serializable] public class Perception : Nucleus { public SensoryNeuroid[] sensoryNeuroids = new SensoryNeuroid[7]; + [System.Serializable] public class Receiver { public int thingType = 0; public Nucleus neuroid; } - public HashSet positionReceivers { get; protected set; } - public HashSet velocityReceivers { get; protected set; } + //public HashSet positionReceivers { get; protected set; } + public List positionReceivers; + //public HashSet velocityReceivers { get; protected set; } + public List velocityReceivers; public Perception(NanoBrainObj brain) : base(brain, "Perception") { - //this.brain = brain; this.positionReceivers = new(); this.velocityReceivers = new(); } - public Perception(NanoBrain neuroidNet) : base(null, "Perception") { - this.brain = neuroidNet; - this.positionReceivers = new(); - this.velocityReceivers = new(); - } - public void SendPositions(Nucleus receivingNeuroid, int thingType = 0, float weight = 1.0f) { Receiver receiver = new() { thingType = thingType, @@ -78,18 +74,20 @@ public class Perception : Nucleus { if (availableIx != -1) { SensoryNeuroid neuroid; if (sensoryNeuroids[availableIx] != null) { - // Debug.Log($"replace receptor for {thingId} at {availableIx}"); + Debug.Log($"replace receptor for {thingId} at {availableIx}"); neuroid = sensoryNeuroids[availableIx]; neuroid.Replace(thingId, name); } else { - // Debug.Log($"new receptor for {thingId} at {availableIx}"); - neuroid = new(brain, thingId, name); + Debug.Log($"new receptor for {thingId} at {availableIx}"); + neuroid = new(newBrain, thingId, name); sensoryNeuroids[availableIx] = neuroid; } foreach (Receiver receiver in positionReceivers) { - if (receiver.thingType == 0 || receiver.thingType == thingType) + if (receiver.thingType == 0 || receiver.thingType == thingType) { + Debug.Log("Add position receiver"); receiver.neuroid.GetInputFrom(neuroid); + } } foreach (Receiver receiver in velocityReceivers) { if (receiver.thingType == 0 || receiver.thingType == thingType) diff --git a/Assets/NanoBrain/SensoryNeuroid.cs b/Assets/NanoBrain/SensoryNeuroid.cs index 0129717..78440de 100644 --- a/Assets/NanoBrain/SensoryNeuroid.cs +++ b/Assets/NanoBrain/SensoryNeuroid.cs @@ -29,14 +29,13 @@ public class SensoryNeuroid : Neuroid { public Receptor receptor; public VelocityNeuroid velocityNeuroid; - // public SensoryNeuroid(NeuroidNetwork net, int thingId) : base(net, "sensory neuroid") { - public SensoryNeuroid(NanoBrain net, int thingId, string name = "sensor") : base(net, name) { + public SensoryNeuroid(NanoBrainObj brain, int thingId, string name = "sensor") : base(brain, name) { this.name = name + ": position"; this.receptor = new Receptor { neuroid = this, thingId = thingId }; - this.velocityNeuroid = new(net, name + ": velocity"); + this.velocityNeuroid = new(brain, name + ": velocity"); // The velocity neuroid received position data from this this.AddReceiver(velocityNeuroid); } @@ -87,7 +86,7 @@ public class VelocityNeuroid : Neuroid { private Vector3 lastPosition = Vector3.zero; private float lastValueTime = 0; - public VelocityNeuroid(NanoBrain net, string name = "velocity") : base(net, name) { + public VelocityNeuroid(NanoBrainObj net, string name = "velocity") : base(net, name) { } public void Replace(string name = "velocity") { diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs index 2b36ad9..21b5c83 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs @@ -10,10 +10,6 @@ public class NanoBrainInspector : Editor { protected static VisualElement mainContainer; protected static VisualElement inspectorContainer; - //private Nucleus currentNucleus = null; - private List layers = new(); - private Dictionary neuroidPositions = new(); - protected bool breakOnWake = false; #region Start @@ -241,22 +237,20 @@ public class NanoBrainInspector : Editor { Vector2Int layerNeuroidPos = this.neuroidPositions[layerNucleus]; Vector3 parentPos = new(100 + layerNeuroidPos.x * 100, margin + layerNeuroidPos.y * spacing, 0.1f); - //int i = 0; float inputSpacing = 400f / layerNucleus.synapses.Count; float inputMargin = 10 + inputSpacing / 2; int minStale = 10000; - //foreach ((Nucleus nucleus, float weight) in layerNucleus.synapses) { + Debug.Log($"layer neuron {layerNucleus.name} has {layerNucleus.synapses.Count} synapses"); foreach (Synapse synapse in layerNucleus.synapses) { Nucleus nucleus = synapse.nucleus; if (nucleus != null) { - float weight = synapse.weight; + Debug.Log($"Synapse to {nucleus.name} is valid"); float weight = synapse.weight; if (this.neuroidPositions.ContainsKey(nucleus)) { Vector2Int inputNeuroidPos = this.neuroidPositions[nucleus]; if (inputNeuroidPos.x == layerNeuroidPos.x + 1) { Vector3 pos = new(100 + inputNeuroidPos.x * 100, inputMargin + inputNeuroidPos.y * inputSpacing, 0.0f); - //float brightness = weight / 10.0f; - Handles.color = Color.white; //new Color(brightness, brightness, brightness); + Handles.color = Color.white; Handles.DrawLine(parentPos, pos); } } @@ -265,11 +259,12 @@ public class NanoBrainInspector : Editor { } } - // if (layerNucleus.synapses.Count > 0 && minStale > 2 && layerNucleus.stale < 3) - // Debug.LogWarning($"Strange {minStale} is big duing update"); - float size = 20; + if (layerNucleus == this.currentNucleus) { + Handles.color = Color.white; + Handles.DrawSolidDisc(parentPos, Vector3.forward, size + 2); + } if (layerNucleus.isSleeping) Handles.color = Color.darkRed; else { @@ -293,7 +288,6 @@ public class NanoBrainInspector : Editor { // Process Hover HandleMouseHover(layerNucleus, neuronRect); // Process click - // Debug.Log($"{et} {e.type}"); if (e.type == EventType.MouseDown && e.button == 0) { // Consume the event so the scene doesn't also handle it e.Use(); diff --git a/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs b/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs index a870d49..16f386f 100644 --- a/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs +++ b/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs @@ -29,10 +29,10 @@ public class NanoBrainObj : ScriptableObject, ISerializationCallbackReceiver { } public void UpdateNuclei() { - foreach (Neuroid neuroid in nuclei) { - neuroid.stale++; - if (neuroid.isSleeping) - neuroid.outputValue = Vector3.zero; + foreach (Nucleus nucleus in nuclei) { + nucleus.stale++; + if (nucleus.isSleeping) + nucleus.outputValue = Vector3.zero; } } diff --git a/Assets/Scenes/Boids/Boids.unity b/Assets/Scenes/Boids/Boids.unity index 2c5cb28..5b10cbd 100644 --- a/Assets/Scenes/Boids/Boids.unity +++ b/Assets/Scenes/Boids/Boids.unity @@ -393,7 +393,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec888ca5333d45a438f9f417fa5ce135, type: 3} m_Name: m_EditorClassIdentifier: Assembly-CSharp::SwarmSpawn - count: 20 + count: 1 boidPrefab: {fileID: 8702527964058765413, guid: f9c706268554ce449a8773675b2864b8, type: 3} spawnAreaSize: {x: 0.5, y: 0.5, z: 0.5} minDelay: 0.05 diff --git a/Assets/Scenes/Boids/New Nano Brain Obj.asset b/Assets/Scenes/Boids/New Nano Brain Obj.asset index 1fc53fd..df2a58c 100644 --- a/Assets/Scenes/Boids/New Nano Brain Obj.asset +++ b/Assets/Scenes/Boids/New Nano Brain Obj.asset @@ -13,16 +13,48 @@ MonoBehaviour: m_Name: New Nano Brain Obj m_EditorClassIdentifier: Assembly-CSharp::NanoBrainObj title: - count: 0 + count: -26 color: {r: 1, g: 1, b: 1, a: 1} texture: {fileID: 0} nuclei: - id: 257807948 _name: Root - synapses: [] + synapses: + - nucleusId: -651011940 + weight: 1 + - nucleusId: -1689048724 + weight: 1 receivers: [] - id: -1868865374 _name: Perception synapses: [] receivers: [] + - id: -651011940 + _name: Neuron 1 + synapses: [] + receivers: + - nucleusId: 257807948 + - id: -1689048724 + _name: New neuron + synapses: [] + receivers: + - nucleusId: 257807948 + - id: -152927560 + _name: 'Boundary: position' + synapses: [] + receivers: + - nucleusId: -1462684836 + - id: -1462684836 + _name: 'Boundary: velocity' + synapses: + - nucleusId: -152927560 + weight: 1 + receivers: [] rootId: 257807948 + perception: + id: 1565766940 + _name: Perception + synapses: [] + receivers: [] + positionReceivers: [] + velocityReceivers: [] diff --git a/Assets/Scenes/Boids/Prefabs/Boid.prefab b/Assets/Scenes/Boids/Prefabs/Boid.prefab index 039cf86..1a756c3 100644 --- a/Assets/Scenes/Boids/Prefabs/Boid.prefab +++ b/Assets/Scenes/Boids/Prefabs/Boid.prefab @@ -176,4 +176,4 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 92f34a5e4027a1dc39efd8ce63cf6aba, type: 3} m_Name: m_EditorClassIdentifier: Assembly-CSharp::NanoBrainComponent - brain: {fileID: 11400000, guid: 55099766f6f09071ab4e8c89b02fa302, type: 2} + brain: {fileID: 11400000, guid: af8d90b8b4b9dcad7837130c4143d91c, type: 2} diff --git a/Assets/Scenes/Boids/RoamingBrain.asset b/Assets/Scenes/Boids/RoamingBrain.asset new file mode 100644 index 0000000..e603273 --- /dev/null +++ b/Assets/Scenes/Boids/RoamingBrain.asset @@ -0,0 +1,102 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 36081359186edfec998d891a1feeb17b, type: 3} + m_Name: RoamingBrain + m_EditorClassIdentifier: Assembly-CSharp::NanoBrainObj + title: + count: 0 + color: {r: 1, g: 1, b: 1, a: 1} + texture: {fileID: 0} + nuclei: + - id: -1753291412 + _name: Root + synapses: + - nucleusId: 237822944 + weight: 1 + receivers: [] + - id: 472852910 + _name: Perception + synapses: [] + receivers: [] + - id: 237822944 + _name: Avoidance + synapses: [] + receivers: + - nucleusId: -1753291412 + - id: 983561152 + _name: 'Boundary: position' + synapses: [] + receivers: + - nucleusId: -1818801134 + - id: -1818801134 + _name: 'Boundary: velocity' + synapses: + - nucleusId: 983561152 + weight: 1 + receivers: [] + - id: 1386590800 + _name: 'Boundary: position' + synapses: [] + receivers: + - nucleusId: -1415771486 + - nucleusId: 237822944 + - id: -1415771486 + _name: 'Boundary: velocity' + synapses: + - nucleusId: 1386590800 + weight: 1 + receivers: [] + - id: -213085248 + _name: 'Boundary: position' + synapses: [] + receivers: + - nucleusId: 1279519762 + - nucleusId: 237822944 + - id: 1279519762 + _name: 'Boundary: velocity' + synapses: + - nucleusId: -213085248 + weight: 1 + receivers: [] + - id: 1783940116 + _name: 'Boundary: position' + synapses: [] + receivers: + - nucleusId: -1018422170 + - nucleusId: 237822944 + - id: -1018422170 + _name: 'Boundary: velocity' + synapses: + - nucleusId: 1783940116 + weight: 1 + receivers: [] + rootId: -1753291412 + perception: + id: 2139386530 + _name: Perception + synapses: [] + receivers: [] + positionReceivers: + - thingType: 0 + neuroid: + id: 237822944 + _name: Avoidance + synapses: + - nucleusId: 1386590800 + weight: 1 + - nucleusId: -213085248 + weight: 1 + - nucleusId: 1783940116 + weight: 1 + receivers: + - nucleusId: -1753291412 + velocityReceivers: [] diff --git a/Assets/Scenes/Boids/RoamingBrain.asset.meta b/Assets/Scenes/Boids/RoamingBrain.asset.meta new file mode 100644 index 0000000..74e1c7d --- /dev/null +++ b/Assets/Scenes/Boids/RoamingBrain.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: af8d90b8b4b9dcad7837130c4143d91c +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/Boids/Scripts/Boid.cs b/Assets/Scenes/Boids/Scripts/Boid.cs index f13d7a9..f5a83cf 100644 --- a/Assets/Scenes/Boids/Scripts/Boid.cs +++ b/Assets/Scenes/Boids/Scripts/Boid.cs @@ -24,7 +24,7 @@ public class Boid : MonoBehaviour { public int id; void Awake() { - + nanoBrain = GetComponent(); this.id = this.GetInstanceID(); sc = FindFirstObjectByType(); diff --git a/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs b/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs index 2ba38b7..be2fe61 100644 --- a/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs +++ b/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs @@ -3,11 +3,11 @@ public class Roaming : Nucleus { public Neuroid output; - public Roaming(NanoBrain neuroidNet, Perception perception, SwarmControl sc) : base(null, "Roaming nucleus") { - avoidance = new(neuroidNet, "Avoidance") { inverse = true }; + public Roaming(NanoBrainObj brain, Perception perception, SwarmControl sc) : base(null, "Roaming nucleus") { + avoidance = new(brain, "Avoidance") { inverse = true }; perception.SendPositions(avoidance, Boid.BoundaryType); - this.output = new(neuroidNet, "Roaming"); + this.output = new(brain, "Roaming"); output.GetInputFrom(avoidance, -sc.avoidanceForce); } diff --git a/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs b/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs index e0ea77b..de25135 100644 --- a/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs +++ b/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs @@ -10,20 +10,20 @@ public class Swarming : Nucleus { public override Vector3 outputValue { get => output.outputValue; set => output.outputValue = value; } - public Swarming(NanoBrain neuroidNet, Perception perception, SwarmControl sc) : base(null, "Swarming Nucleus") { - this.cohesion = new(neuroidNet, "Cohesion") { inverse = false }; + public Swarming(NanoBrainObj brain, Perception perception, SwarmControl sc) : base(null, "Swarming Nucleus") { + this.cohesion = new(brain, "Cohesion") { inverse = false }; perception.SendPositions(this.cohesion, Boid.BoidType); - this.alignment = new(neuroidNet, "Alignment") { average = true }; + this.alignment = new(brain, "Alignment") { average = true }; perception.SendVelocities(this.alignment, Boid.BoidType); - this.avoidance = new(neuroidNet, "Avoidance") { inverse = true }; + this.avoidance = new(brain, "Avoidance") { inverse = true }; perception.SendPositions(this.avoidance); - this.boundary = new(neuroidNet, "Boundary"); + this.boundary = new(brain, "Boundary"); perception.SendPositions(this.boundary, Boid.BoundaryType); - this.output = new(neuroidNet, "Swarming"); + this.output = new(brain, "Swarming"); this.output.GetInputFrom(alignment, sc.alignmentForce); this.output.GetInputFrom(cohesion, sc.cohesionForce); this.output.GetInputFrom(avoidance, -sc.avoidanceForce); From 21751f8ceaf93f7d441965320075c6f505b7a02b Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 11 Dec 2025 12:27:55 +0100 Subject: [PATCH 021/179] Brain object --- Assembly-CSharp.csproj | 1 + Assets/NanoBrain/Editor/NanoBrain_Editor.cs | 2 +- Assets/NanoBrain/Editor/NeuroidWindow.cs | 2 +- Assets/NanoBrain/Neuroid.cs | 13 +- Assets/NanoBrain/Nucleus.cs | 87 +++++--- Assets/NanoBrain/Perception.cs | 13 +- Assets/NanoBrain/Perceptoid.cs | 156 ++++++++++++++ Assets/NanoBrain/Perceptoid.cs.meta | 2 + Assets/NanoBrain/SensoryNeuroid.cs | 9 +- .../Editor/NanoBrainComponent_Editor.cs | 25 ++- .../VisualEditor/Editor/NanoBrainEditor.cs | 2 +- .../VisualEditor/Editor/NanoBrainInspector.cs | 196 +++++++++++++++--- .../VisualEditor/NanoBrainComponent.cs | 14 +- Assets/NanoBrain/VisualEditor/NanoBrainObj.cs | 55 ++++- Assets/Scenes/Boids/Boids.unity | 2 +- Assets/Scenes/Boids/New Nano Brain Obj.asset | 60 ------ Assets/Scenes/Boids/Prefabs/Boid.prefab | 2 +- Assets/Scenes/Boids/RoamingBrain.asset | 100 +++------ Assets/Scenes/Boids/Scripts/Boid.cs | 32 +-- Assets/Scenes/Boids/Scripts/RoamingNucleus.cs | 2 +- .../Scenes/Boids/Scripts/SwarmingNucleus.cs | 2 +- Assets/Scenes/Boids/SwarmingBrain.asset | 88 ++++++++ ...bj.asset.meta => SwarmingBrain.asset.meta} | 2 +- 23 files changed, 611 insertions(+), 256 deletions(-) create mode 100644 Assets/NanoBrain/Perceptoid.cs create mode 100644 Assets/NanoBrain/Perceptoid.cs.meta delete mode 100644 Assets/Scenes/Boids/New Nano Brain Obj.asset create mode 100644 Assets/Scenes/Boids/SwarmingBrain.asset rename Assets/Scenes/Boids/{New Nano Brain Obj.asset.meta => SwarmingBrain.asset.meta} (79%) diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index 4067143..6b711a6 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -50,6 +50,7 @@ + diff --git a/Assets/NanoBrain/Editor/NanoBrain_Editor.cs b/Assets/NanoBrain/Editor/NanoBrain_Editor.cs index b877b32..51e6694 100644 --- a/Assets/NanoBrain/Editor/NanoBrain_Editor.cs +++ b/Assets/NanoBrain/Editor/NanoBrain_Editor.cs @@ -221,7 +221,7 @@ public class NanoBrain_Editor : Editor { if (neuroid is SensoryNeuroid sensoryNeuroid) { tooltip = new( $"{sensoryNeuroid.name}" + - $"\nThing {sensoryNeuroid.receptor.thingId}" + + $"\nThing {sensoryNeuroid.receptor.thingType}" + $"\nValue: {neuroid.outputValue}" + $"\nStale: {neuroid.stale}"); } diff --git a/Assets/NanoBrain/Editor/NeuroidWindow.cs b/Assets/NanoBrain/Editor/NeuroidWindow.cs index b3e17a2..133d99c 100644 --- a/Assets/NanoBrain/Editor/NeuroidWindow.cs +++ b/Assets/NanoBrain/Editor/NeuroidWindow.cs @@ -244,7 +244,7 @@ public class GraphEditorWindow : EditorWindow { if (neuroid is SensoryNeuroid sensoryNeuroid) { tooltip = new( $"{sensoryNeuroid.name}" + - $"\nThing {sensoryNeuroid.receptor.thingId}" + + $"\nThing {sensoryNeuroid.receptor.thingType}" + $"\nValue: {neuroid.outputValue}" + $"\nStale: {neuroid.stale}"); } diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index c2a2a30..92cf2f2 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -1,5 +1,6 @@ using UnityEngine; +[System.Serializable] public class Neuroid : Nucleus { public bool average = false; public bool inverse = false; @@ -13,9 +14,17 @@ public class Neuroid : Nucleus { // Debug.LogError("No neuroid network"); // } - public Neuroid(NanoBrainObj brain, string name) : base(brain, name) { + public Neuroid(NanoBrainObj brain, string name) : base(name) { + this.brain = brain; + if (this.brain != null) { + this.brain.nuclei.Add(this); + } + else + Debug.LogError("No neuroid network"); } + public Neuroid(string name): base(name) {} + public void SetWeight(Neuroid input, float weight) { //this.synapses[input] = weight; this.SetWeight((Nucleus)input, weight); @@ -30,7 +39,7 @@ public class Neuroid : Nucleus { public void SetInput(Neuroid input) { // if (this.synapses.ContainsKey(input) == false) // this.synapses[input] = 1.0f; - if (this.SynapseExists(input)) + if (this.SynapseExists(input) == false) this.SetWeight(input, 1.0f); UpdateState(); } diff --git a/Assets/NanoBrain/Nucleus.cs b/Assets/NanoBrain/Nucleus.cs index d78418e..4593628 100644 --- a/Assets/NanoBrain/Nucleus.cs +++ b/Assets/NanoBrain/Nucleus.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using UnityEngine; @@ -13,33 +14,53 @@ public class Nucleus { set => _name = value; } - //public readonly Dictionary synapses = new(); [SerializeField] - public List synapses = new(); - //public HashSet receivers = new(); + public List synapses = new(); [SerializeField] public List receivers = new(); #region Serialization - public void Rebuild(NanoBrainObj brain) { + [SerializeField] + protected string nucleusType; + + public virtual void Rebuild(NanoBrainObj brain) { if (this.synapses != null) { foreach (Synapse synapse in synapses) synapse.Rebuild(brain); } if (this.receivers == null) this.receivers = new(); - else - foreach (Receiver receiver in receivers) - receiver.Rebuild(brain); + else { + foreach (Receiver receiver in receivers.ToArray()) { + if (receiver.Rebuild(brain) == false) { + Debug.Log("Rebuilding failed, removing receiver."); + receivers.Remove(receiver); + } + } + } } - #endregion + public static Nucleus RebuildType(NanoBrainObj brain, Nucleus nucleus) { + if (string.IsNullOrEmpty(nucleus.nucleusType) == false) { + Type nucleusType = Type.GetType(nucleus.nucleusType); + if (nucleusType != null) { + object[] args = new object[] { brain, nucleus.name }; + Nucleus rebuiltNucleus = (Nucleus)Activator.CreateInstance(nucleusType, args); + rebuiltNucleus.Deserialize(nucleus); + return rebuiltNucleus; + } + } + return nucleus; + } + + public virtual void Deserialize(Nucleus nucleus) { } + + #endregion Serialization #region Runtime state (not serialized) - // public NanoBrain brain { get; protected set; } - public NanoBrainObj newBrain { get; protected set; } + public NanoBrainObj brain { get; protected set; } public virtual Vector3 outputValue { get; set; } @@ -50,12 +71,13 @@ public class Nucleus { #endregion Runtime state - public Nucleus(NanoBrainObj brain, string name) { - this.newBrain = brain; - if (this.newBrain != null) - this.newBrain.nuclei.Add(this); - else - Debug.LogError("No neuroid network"); + public Nucleus(string name) { + // this.brain = brain; + // if (this.brain != null) { + // this.brain.nuclei.Add(this); + // } + // else + // Debug.LogError("No neuroid network"); this._name = name; this.id = this.GetHashCode(); @@ -63,9 +85,7 @@ public class Nucleus { public virtual void AddReceiver(Nucleus receiver) { this.receivers.Add(new Receiver(receiver)); - //receiver.synapses[this] = 1.0f; // new(this); receiver.SetWeight(this, 1.0f); - //Debug.Log($"receiver # {this.receivers.Count} synapse count {receiver.synapses.Count}"); } public static void Delete(Nucleus nucleus) { @@ -73,15 +93,19 @@ public class Nucleus { if (synapse.nucleus.receivers.Count > 1) { // there is another nucleus feeding into this input nucleus synapse.nucleus.receivers.RemoveAll(r => r.nucleus == nucleus); - } else { + } + else { // No other links, delete it. Nucleus.Delete(synapse.nucleus); } } - foreach (Receiver receiver in nucleus.receivers) - receiver.nucleus.synapses.RemoveAll(s => s.nucleus == nucleus); + foreach (Receiver receiver in nucleus.receivers) { + if (receiver.nucleus != null && receiver.nucleus.synapses != null) + receiver.nucleus.synapses.RemoveAll(s => s.nucleus == nucleus); + } - nucleus.newBrain.nuclei.RemoveAll(n => n == nucleus); + nucleus.brain.nuclei.RemoveAll(n => n == nucleus); + nucleus.brain.GarbageCollection(); } public void GetInputFrom(Nucleus input, float weight = 1.0f) { @@ -113,6 +137,7 @@ public class Nucleus { Synapse newSynapse = new(nucleus, weight); synapses.Add(newSynapse); } + } [System.Serializable] @@ -139,6 +164,12 @@ public class Synapse { return; } } + foreach (Perceptoid perceptoid in brain.perceptei) { + if (perceptoid.id == this.nucleusId) { + this.nucleus = perceptoid; + return; + } + } Debug.LogError($"Synapse deserialization error: could not find nucleus with id {this.nucleusId}"); } } @@ -154,16 +185,18 @@ public class Receiver { this.nucleusId = nucleus.id; } - public void Rebuild(NanoBrainObj brain) { - if (brain == null) - return; + public bool Rebuild(NanoBrainObj brain) { + if (brain == null) { + return false; + } foreach (Nucleus nucleus in brain.nuclei) { if (nucleus.id == this.nucleusId) { this.nucleus = nucleus; - return; + return true; } } - Debug.LogError($"Synapse deserialization error: could not find nucleus with id {this.nucleusId}"); + Debug.LogWarning($"Receiver deserialization error: could not find nucleus with id {this.nucleusId}"); + return false; } } \ No newline at end of file diff --git a/Assets/NanoBrain/Perception.cs b/Assets/NanoBrain/Perception.cs index ccc254e..d6ee5a7 100644 --- a/Assets/NanoBrain/Perception.cs +++ b/Assets/NanoBrain/Perception.cs @@ -16,11 +16,18 @@ public class Perception : Nucleus { //public HashSet velocityReceivers { get; protected set; } public List velocityReceivers; - public Perception(NanoBrainObj brain) : base(brain, "Perception") { + public Perception(NanoBrainObj brain) : base("Perception") { this.positionReceivers = new(); this.velocityReceivers = new(); } + public Perceptoid GetPerception(int thingType = 0) { + foreach (Nucleus nucleus in this.brain.nuclei) { + if (nucleus is Perceptoid perceptoid && (thingType == 0 || perceptoid.receptor.thingType == thingType)) + return perceptoid; + } + return null; + } public void SendPositions(Nucleus receivingNeuroid, int thingType = 0, float weight = 1.0f) { Receiver receiver = new() { @@ -55,7 +62,7 @@ public class Perception : Nucleus { for (int i = 0; i < sensoryNeuroids.Length; i++) { if (sensoryNeuroids[i] == null) availableIx = i; - else if (sensoryNeuroids[i].receptor.thingId == thingId) { + else if (sensoryNeuroids[i].receptor.thingType == thingId) { sensoryNeuroids[i].receptor.position = localPosition; return; } @@ -80,7 +87,7 @@ public class Perception : Nucleus { } else { Debug.Log($"new receptor for {thingId} at {availableIx}"); - neuroid = new(newBrain, thingId, name); + neuroid = new(brain, thingId, name); sensoryNeuroids[availableIx] = neuroid; } foreach (Receiver receiver in positionReceivers) { diff --git a/Assets/NanoBrain/Perceptoid.cs b/Assets/NanoBrain/Perceptoid.cs new file mode 100644 index 0000000..bea7cce --- /dev/null +++ b/Assets/NanoBrain/Perceptoid.cs @@ -0,0 +1,156 @@ +using UnityEngine; + +[System.Serializable] +public class Perceptoid : Neuroid { + // A neuroid which has no neurons as input + // But receives value from a receptor + public Receptor receptor; + public VelocityNeuroid velocityNeuroid; + + #region Serialization + + [SerializeField] + public int thingType; + + public override void Rebuild(NanoBrainObj brain) { + base.Rebuild(brain); + this.receptor = new Receptor() { + neuroid = this + }; + } + + public override void Deserialize(Nucleus nucleus) { + base.Deserialize(nucleus); + + if (nucleus is Perceptoid perceptoid) + this.receptor.thingType = perceptoid.thingType; + + // Point all receivers to this perceptoid instead of the default nucleus + foreach (Receiver receiver in nucleus.receivers) { + foreach (Synapse synapse in receiver.nucleus.synapses) { + if (synapse.nucleus == nucleus) + synapse.nucleus = this; + } + } + // Point all synapses to this perceptoid instead of the default nucleus + foreach (Synapse synapse in nucleus.synapses) { + foreach (Receiver receiver in synapse.nucleus.receivers) { + if (receiver.nucleus == nucleus) + receiver.nucleus = this; + } + } + // Copy all the synapses + this.synapses = nucleus.synapses; + // Copy all receivers + this.receivers = nucleus.receivers; + } + + #endregion Serialization + + public Perceptoid(NanoBrainObj brain, string name) : base(name) { + this.brain = brain; + if (this.brain != null) { + this.brain.perceptei.Add(this); + } + else + Debug.LogError("No neuroid network"); + + this.nucleusType = nameof(Perceptoid); + this.name = name; + this.receptor = new Receptor { + neuroid = this + }; + } + + public Perceptoid(NanoBrainObj brain, int thingType, string name = "sensor") : base(name) { + this.brain = brain; + if (this.brain != null) { + this.brain.perceptei.Add(this); + } + else + Debug.LogError("No neuroid network"); + + this.nucleusType = nameof(Perceptoid); + this.name = name; + this.thingType = thingType; + this.receptor = new Receptor { + neuroid = this, + thingType = thingType + }; + this.velocityNeuroid = new(brain, name + ": velocity"); + // The velocity neuroid received position data from this + this.AddReceiver(velocityNeuroid); + } + + public void Replace(int thingType, string name = "sensor") { + this.name = name; + + this.thingType = thingType; + this.receptor.thingType = thingType; + this.receptor.localPosition = Vector3.zero; + + this.outputValue = Vector3.zero; + this.receivers = new(); + this.AddReceiver(velocityNeuroid); + + this.velocityNeuroid.Replace(name + ": velocity"); + } + + public override void UpdateState() { + Vector3 result = receptor.localPosition; + foreach (Synapse synapse in this.synapses) { + Nucleus nucleus = synapse.nucleus; + float weight = synapse.weight; + Vector3 direction = nucleus.outputValue.normalized; + float magnitude = nucleus.outputValue.magnitude; + + magnitude = weight * Mathf.Pow(magnitude, exponent); + if (inverse) + magnitude = 1 / magnitude; + result += direction * magnitude; + } + if (average && this.synapses.Count > 0) + result /= this.synapses.Count + 1; + + this.outputValue = result; + foreach (Receiver receiver in this.receivers) + if (receiver.nucleus is Neuroid neuroid) + neuroid.SetInput(this); + this.stale = 0; + } + + public static Perceptoid GetPerception(NanoBrainObj brain, int thingType = 0) { + foreach (Nucleus nucleus in brain.nuclei) { + if (nucleus is Perceptoid perceptoid && (thingType == 0 || perceptoid.thingType == thingType)) + return perceptoid; + } + return null; + } + + public static void ProcessStimulus(NanoBrainObj brain, int thingType, Vector3 lcoalPosition) { + Perceptoid selectedPerceptoid = null; + foreach (Perceptoid nucleus in brain.perceptei) { + if (nucleus is Perceptoid perceptoid && (thingType == 0 || perceptoid.thingType == thingType)) + if (selectedPerceptoid == null) { + selectedPerceptoid = perceptoid; + if (perceptoid.isSleeping) { + break; + } + } + else if (perceptoid.receptor.position.magnitude < selectedPerceptoid.receptor.position.magnitude) + selectedPerceptoid = perceptoid; + } + if (selectedPerceptoid == null) { + Debug.Log("No perceptoid selected, stimulus is ignored"); + return; + } + selectedPerceptoid.receptor.position = lcoalPosition; + } + public static Receptor GetReceptor(NanoBrainObj brain, int thingType) { + foreach (Perceptoid perceptoid in brain.perceptei) { + if (thingType == 0 || perceptoid.thingType == thingType) + return perceptoid.receptor; + } + return null; + } +} diff --git a/Assets/NanoBrain/Perceptoid.cs.meta b/Assets/NanoBrain/Perceptoid.cs.meta new file mode 100644 index 0000000..ebac122 --- /dev/null +++ b/Assets/NanoBrain/Perceptoid.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 702f634001a21a9d7ae1057c8ce356e9 \ No newline at end of file diff --git a/Assets/NanoBrain/SensoryNeuroid.cs b/Assets/NanoBrain/SensoryNeuroid.cs index 78440de..1cdeabb 100644 --- a/Assets/NanoBrain/SensoryNeuroid.cs +++ b/Assets/NanoBrain/SensoryNeuroid.cs @@ -1,12 +1,11 @@ -using System.Collections.Generic; using System.Linq; using UnityEngine; public class Receptor { - public SensoryNeuroid neuroid; + public Neuroid neuroid; - public int thingId; + public int thingType; public Vector3 localPosition; /// @@ -33,7 +32,7 @@ public class SensoryNeuroid : Neuroid { this.name = name + ": position"; this.receptor = new Receptor { neuroid = this, - thingId = thingId + thingType = thingId }; this.velocityNeuroid = new(brain, name + ": velocity"); // The velocity neuroid received position data from this @@ -43,7 +42,7 @@ public class SensoryNeuroid : Neuroid { public void Replace(int thingId, string name = "sensor") { this.name = name + ": position"; - this.receptor.thingId = thingId; + this.receptor.thingType = thingId; this.receptor.localPosition = Vector3.zero; this.outputValue = Vector3.zero; diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs index e762a1e..2229cdb 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs @@ -11,14 +11,16 @@ public class NanoBrainComponent_Editor : Editor { private SerializedProperty brainProp; public void OnEnable() { - brainProp = serializedObject.FindProperty(nameof(NanoBrainComponent.brain)); + if (Application.isPlaying == false) + brainProp = serializedObject.FindProperty(nameof(NanoBrainComponent.defaultBrain)); } public override VisualElement CreateInspectorGUI() { NanoBrainComponent component = target as NanoBrainComponent; - NanoBrainObj brain = component.brain; + NanoBrainObj brain = Application.isPlaying ? component.brain : component.defaultBrain; - serializedObject.Update(); + if (Application.isPlaying == false) + serializedObject.Update(); VisualElement root = new(); @@ -32,9 +34,11 @@ public class NanoBrainComponent_Editor : Editor { root.styleSheets.Add(Resources.Load("GraphStyles")); - PropertyField brainField = new(brainProp); - brainField.label = "Nano Brain"; - root.Add(brainField); + if (Application.isPlaying == false) { + PropertyField brainField = new(brainProp); + brainField.label = "Nano Brain"; + root.Add(brainField); + } mainContainer = new() { name = "main", @@ -70,14 +74,15 @@ public class NanoBrainComponent_Editor : Editor { if (brain != null) board.SetGraph(brain, brain.root, inspectorContainer); - else - Debug.LogWarning(" No brain!"); + // else + // Debug.LogWarning(" No brain!"); - serializedObject.ApplyModifiedProperties(); + if (Application.isPlaying == false) + serializedObject.ApplyModifiedProperties(); return root; } - private void UpdateLayout(float containerWidth) { + private void UpdateLayout(float containerWidth) { if (containerWidth > 800f) { mainContainer.style.flexDirection = FlexDirection.Row; inspectorContainer.style.width = 400; // fixed sidebar width diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs index 2e38c69..7c86c74 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs @@ -299,7 +299,7 @@ public class GraphBoardView : VisualElement { if (neuroid is SensoryNeuroid sensoryNeuroid) { tooltip = new( $"{sensoryNeuroid.name}" + - $"\nThing {sensoryNeuroid.receptor.thingId}" + + $"\nThing {sensoryNeuroid.receptor.thingType}" + $"\nValue: {neuroid.outputValue}" + $"\nStale: {neuroid.stale}"); } diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs index 21b5c83..e944386 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs @@ -104,7 +104,8 @@ public class NanoBrainInspector : Editor { public void SetGraph(NanoBrainObj brain, Nucleus nucleus, VisualElement inspectorContainer) { this.brain = brain; - this.serializedBrain = new SerializedObject(brain); + if (Application.isPlaying == false) + this.serializedBrain = new SerializedObject(brain); this.currentNucleus = nucleus; Rebuild(inspectorContainer); } @@ -212,17 +213,130 @@ public class NanoBrainInspector : Editor { if (currentNucleus == null) return; - serializedBrain.Update(); + if (Application.isPlaying == false) + serializedBrain.Update(); Handles.BeginGUI(); - foreach (NeuroidLayer layer in layers) - DrawLayer(layer); + DrawGraph(); + // foreach (NeuroidLayer layer in layers) + // DrawLayer(layer); Handles.EndGUI(); } + private void DrawGraph() { + float size = 20; + Vector3 position = new(200, 210, 0); + + DrawReceivers(this.currentNucleus, position, size); + DrawSynapses(this.currentNucleus, position, size); + + // Draw selected Nucleus + Handles.color = Color.white; + Handles.DrawSolidDisc(position, Vector3.forward, size + 2); + DrawNucleus(this.currentNucleus, position, this.currentNucleus.outputValue.magnitude, 20); + } + + private void DrawNucleus(Nucleus nucleus, Vector3 position, float maxValue, float size) { + if (nucleus.isSleeping) + Handles.color = Color.darkRed; + else { + float brightness = nucleus.outputValue.magnitude / maxValue; + Handles.color = new Color(brightness, brightness, brightness); + } + Handles.DrawSolidDisc(position, Vector3.forward, size); + Vector3 labelPos = position - Vector3.down * (size + 0.2f); // below disc along up axis + GUIStyle style = new GUIStyle(EditorStyles.label) { + alignment = TextAnchor.UpperCenter, + normal = { textColor = Color.white }, + fontStyle = FontStyle.Bold + }; + Handles.Label(labelPos, nucleus.name, style); + + Rect neuronRect = new(position.x - size, position.y - size, size * 2, size * 2); + int id = GUIUtility.GetControlID(FocusType.Passive); + Event e = Event.current; + EventType et = e.GetTypeForControl(id); + if (e != null && neuronRect.Contains(e.mousePosition)) { + // Process Hover + HandleMouseHover(nucleus, neuronRect); + // Process click + if (e.type == EventType.MouseDown && e.button == 0) { + // Consume the event so the scene doesn't also handle it + e.Use(); + HandleClicked(nucleus); + } + } + } + + private void DrawReceivers(Nucleus nucleus, Vector3 parentPos, float size) { + int nodeCount = nucleus.receivers.Count; + + // Determine the maximum value in this layer + // This is used to 'scale' the output value colors of the nuclei + float maxValue = 0; + foreach (Receiver receiver in nucleus.receivers) { + if (receiver.nucleus is Neuroid neuroid) { + float value = neuroid.outputValue.magnitude; + if (value > maxValue) + maxValue = value; + } + } + + // Determine the spacing of the nuclei in the layer + float spacing = 400f / nodeCount; + float margin = 10 + spacing / 2; + + int row = 0; + foreach (Receiver receiver in nucleus.receivers) { + Nucleus receiverNucleus = receiver.nucleus; + + Vector3 pos = new(100, margin + row * spacing, 0.0f); + Handles.color = Color.white; + Handles.DrawLine(parentPos, pos); + + DrawNucleus(receiverNucleus, pos, maxValue, size); + row++; + } + } + + private void DrawSynapses(Nucleus nucleus, Vector3 parentPos, float size) { + int nodeCount = nucleus.synapses.Count; + + // Determine the maximum value in this layer + // This is used to 'scale' the output value colors of the nuclei + float maxValue = 0; + foreach (Synapse receiver in nucleus.synapses) { + if (receiver.nucleus is Neuroid neuroid) { + float value = neuroid.outputValue.magnitude; + if (value > maxValue) + maxValue = value; + } + } + + // Determine the spacing of the nuclei in the layer + float spacing = 400f / nodeCount; + float margin = 10 + spacing / 2; + + int row = 0; + foreach (Synapse receiver in nucleus.synapses) { + Nucleus receiverNucleus = receiver.nucleus; + + Vector3 pos = new(300, margin + row * spacing, 0.0f); + Handles.color = Color.white; + Handles.DrawLine(parentPos, pos); + + DrawNucleus(receiverNucleus, pos, maxValue, size); + row++; + } + } + + /* private void DrawLayer(NeuroidLayer layer) { int nodeCount = layer.neuroids.Count; + + // Determine the maximum value in this layer + // This is used to 'scale' the output value colors of the nuclei float maxValue = 0; foreach (Nucleus nucleus in layer.neuroids) { if (nucleus is Neuroid neuroid) { @@ -231,8 +345,11 @@ public class NanoBrainInspector : Editor { maxValue = value; } } + + // Determine the spacing of the nuclei in the layer float spacing = 400f / nodeCount; float margin = 10 + spacing / 2; + foreach (Nucleus layerNucleus in layer.neuroids) { Vector2Int layerNeuroidPos = this.neuroidPositions[layerNucleus]; Vector3 parentPos = new(100 + layerNeuroidPos.x * 100, margin + layerNeuroidPos.y * spacing, 0.1f); @@ -240,11 +357,9 @@ public class NanoBrainInspector : Editor { float inputSpacing = 400f / layerNucleus.synapses.Count; float inputMargin = 10 + inputSpacing / 2; int minStale = 10000; - Debug.Log($"layer neuron {layerNucleus.name} has {layerNucleus.synapses.Count} synapses"); foreach (Synapse synapse in layerNucleus.synapses) { Nucleus nucleus = synapse.nucleus; if (nucleus != null) { - Debug.Log($"Synapse to {nucleus.name} is valid"); float weight = synapse.weight; if (this.neuroidPositions.ContainsKey(nucleus)) { Vector2Int inputNeuroidPos = this.neuroidPositions[nucleus]; if (inputNeuroidPos.x == layerNeuroidPos.x + 1) { @@ -265,20 +380,21 @@ public class NanoBrainInspector : Editor { Handles.color = Color.white; Handles.DrawSolidDisc(parentPos, Vector3.forward, size + 2); } - if (layerNucleus.isSleeping) - Handles.color = Color.darkRed; - else { - float brightness = layerNucleus.outputValue.magnitude / maxValue; - Handles.color = new Color(brightness, brightness, brightness); - } - Handles.DrawSolidDisc(parentPos, Vector3.forward, size); - Vector3 labelPos = parentPos - Vector3.down * (size + 0.2f); // below disc along up axis - GUIStyle style = new GUIStyle(EditorStyles.label) { - alignment = TextAnchor.UpperCenter, - normal = { textColor = Color.white }, - fontStyle = FontStyle.Bold - }; - Handles.Label(labelPos, layerNucleus.name, style); + DrawNucleus(layerNucleus, parentPos, maxValue, size); + // if (layerNucleus.isSleeping) + // Handles.color = Color.darkRed; + // else { + // float brightness = layerNucleus.outputValue.magnitude / maxValue; + // Handles.color = new Color(brightness, brightness, brightness); + // } + // Handles.DrawSolidDisc(parentPos, Vector3.forward, size); + // Vector3 labelPos = parentPos - Vector3.down * (size + 0.2f); // below disc along up axis + // GUIStyle style = new GUIStyle(EditorStyles.label) { + // alignment = TextAnchor.UpperCenter, + // normal = { textColor = Color.white }, + // fontStyle = FontStyle.Bold + // }; + // Handles.Label(labelPos, layerNucleus.name, style); Rect neuronRect = new(parentPos.x - size, parentPos.y - size, size * 2, size * 2); int id = GUIUtility.GetControlID(FocusType.Passive); @@ -296,13 +412,14 @@ public class NanoBrainInspector : Editor { } } } + */ private void HandleMouseHover(Nucleus neuroid, Rect rect) { GUIContent tooltip; if (neuroid is SensoryNeuroid sensoryNeuroid) { tooltip = new( $"{sensoryNeuroid.name}" + - $"\nThing {sensoryNeuroid.receptor.thingId}" + + $"\nThing {sensoryNeuroid.receptor.thingType}" + $"\nValue: {neuroid.outputValue}" + $"\nStale: {neuroid.stale}"); } @@ -343,7 +460,11 @@ public class NanoBrainInspector : Editor { if (so.targetObject == null) return; so.Update(); + if (this.currentNucleus == null) + return; this.currentNucleus.name = EditorGUILayout.TextField(this.currentNucleus.name); + if (this.currentNucleus is Perceptoid currentPerceptoid) + currentPerceptoid.thingType = EditorGUILayout.IntField("Thing Type", currentPerceptoid.thingType); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Output Value", GUILayout.Width(100)); EditorGUILayout.Vector3Field(GUIContent.none, this.currentNucleus.outputValue); @@ -359,8 +480,15 @@ public class NanoBrainInspector : Editor { EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField(synapse.nucleus.name, GUILayout.Width(120)); EditorGUI.indentLevel--; + // if (synapse.nucleus is Perceptoid perceptoid) { + // EditorGUILayout.LabelField("Thing", GUILayout.Width(45)); + // perceptoid.thingType = EditorGUILayout.IntField(perceptoid.thingType, GUILayout.Width(40)); + + // } + // else { EditorGUILayout.LabelField("Weight", GUILayout.Width(45)); synapse.weight = EditorGUILayout.FloatField(synapse.weight, GUILayout.Width(40)); + // } EditorGUI.indentLevel++; EditorGUILayout.Vector3Field(GUIContent.none, synapse.nucleus.outputValue, GUILayout.Width(180)); EditorGUILayout.EndHorizontal(); @@ -372,10 +500,8 @@ public class NanoBrainInspector : Editor { } if (GUILayout.Button("Add Neuron")) AddInputNeuron(this.currentNucleus); - if (GUILayout.Button("Add Position Perception")) - AddPositionPerception(this.currentNucleus); - if (GUILayout.Button("Add Velocity Perception")) - AddVelocityPerception(this.currentNucleus); + if (GUILayout.Button("Add Perceptoid")) + AddPerceptoid(this.currentNucleus); if (GUILayout.Button("Delete this neuron")) DeleteNeuron(this.currentNucleus); @@ -384,9 +510,9 @@ public class NanoBrainInspector : Editor { inspectorContainer.Add(container); } - protected virtual void AddInputNeuron(Nucleus receiver) { + protected virtual void AddInputNeuron(Nucleus nucleus) { Neuroid newNeuroid = new(this.brain, "New neuron"); - newNeuroid.AddReceiver(receiver); + newNeuroid.AddReceiver(nucleus); //Rebuild(inspectorContainer); BuildLayers(); } @@ -398,13 +524,19 @@ public class NanoBrainInspector : Editor { BuildLayers(); } - protected virtual void AddPositionPerception(Nucleus receiver) { - this.brain.perception.SendPositions(receiver); - } - protected virtual void AddVelocityPerception(Nucleus receiver) { - this.brain.perception.SendVelocities(receiver); + protected virtual void AddPerceptoid(Nucleus nucleus) { + Perceptoid newPerceptoid = new(this.brain, 0, "New Perceptoid"); + newPerceptoid.AddReceiver(nucleus); + BuildLayers(); } + // protected virtual void AddPositionPerception(Nucleus receiver) { + // this.brain.perception.SendPositions(receiver); + // } + // protected virtual void AddVelocityPerception(Nucleus receiver) { + // this.brain.perception.SendVelocities(receiver); + // } + private Vector3 NodePosition(Nucleus nucleus, int layerNodeCount = 1) { if (this.neuroidPositions.ContainsKey(nucleus)) { Vector2Int nucleusPos = this.neuroidPositions[nucleus]; diff --git a/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs b/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs index f4e7090..79a25d2 100644 --- a/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs +++ b/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs @@ -1,15 +1,21 @@ using UnityEngine; public class NanoBrainComponent : MonoBehaviour { - public NanoBrainObj brain; + public NanoBrainObj defaultBrain; + private NanoBrainObj brainInstance; + public Nucleus root { get { - return brain.root; + return brainInstance.root; } } - public Perception perception { + public NanoBrainObj brain { get { - return brain.perception; + if (brainInstance == null && defaultBrain != null) { + brainInstance = Instantiate(defaultBrain); + brainInstance.name = defaultBrain.name + " (Instance)"; + } + return brainInstance; } } } \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs b/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs index 16f386f..3d913bb 100644 --- a/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs +++ b/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs @@ -9,18 +9,19 @@ public class NanoBrainObj : ScriptableObject, ISerializationCallbackReceiver { public Color color = Color.white; public Texture2D texture; - public List nuclei = new(); + public List nuclei = new(); + public List perceptei = new(); // This is probably always the first element in the nuclei list... [System.NonSerialized] public Nucleus root; public int rootId; - public Perception perception; + // public Perception perception; public NanoBrainObj() { - this.root = new(this, "Root"); - this.perception = new Perception(this); + this.root = new Neuroid(this, "Root"); + // this.perception = new Perception(this); } public Neuroid AddNeuron(string name) { @@ -40,10 +41,48 @@ public class NanoBrainObj : ScriptableObject, ISerializationCallbackReceiver { this.rootId = root.id; } public void OnAfterDeserialize() { - foreach (Nucleus nucleus in nuclei) { - if (this.rootId == nucleus.id) - this.root = nucleus; - nucleus.Rebuild(this); + try { + foreach (Nucleus nucleus in this.nuclei.ToArray()) { + if (this.rootId == nucleus.id) + this.root = nucleus; + nucleus.Rebuild(this); + } + + // List rebuildNuclei = new(); + // foreach (Nucleus nucleus in this.nuclei.ToArray()) { + // rebuildNuclei.Add(Nucleus.RebuildType(this, nucleus)); + // } + // this.nuclei = rebuildNuclei; + foreach (Perceptoid perceptoid in this.perceptei.ToArray()) { + perceptoid.Rebuild(this); + } + } + catch (System.Exception) { } + this.GarbageCollection(); + } + + public void GarbageCollection() { + HashSet visitedNuclei = new(); + MarkNuclei(visitedNuclei, this.root); + Debug.Log($"Garbage collection found {visitedNuclei.Count} Nuclei"); + this.nuclei.RemoveAll(nucleus => visitedNuclei.Contains(nucleus) == false); + this.perceptei.RemoveAll(perceptoid => visitedNuclei.Contains(perceptoid) == false); + } + + public void MarkNuclei(HashSet visitedNuclei, Nucleus nucleus) { + if (nucleus is null) + return; + + visitedNuclei.Add(nucleus); + if (nucleus.synapses != null) { + HashSet visitedSynapses = new(); + foreach (Synapse synapse in nucleus.synapses) { + if (synapse != null && synapse.nucleus != null) { + visitedSynapses.Add(synapse); + MarkNuclei(visitedNuclei, synapse.nucleus); + } + } + nucleus.synapses.RemoveAll(synapse => visitedSynapses.Contains(synapse) == false); } } } \ No newline at end of file diff --git a/Assets/Scenes/Boids/Boids.unity b/Assets/Scenes/Boids/Boids.unity index 5b10cbd..5515d90 100644 --- a/Assets/Scenes/Boids/Boids.unity +++ b/Assets/Scenes/Boids/Boids.unity @@ -393,7 +393,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec888ca5333d45a438f9f417fa5ce135, type: 3} m_Name: m_EditorClassIdentifier: Assembly-CSharp::SwarmSpawn - count: 1 + count: 3 boidPrefab: {fileID: 8702527964058765413, guid: f9c706268554ce449a8773675b2864b8, type: 3} spawnAreaSize: {x: 0.5, y: 0.5, z: 0.5} minDelay: 0.05 diff --git a/Assets/Scenes/Boids/New Nano Brain Obj.asset b/Assets/Scenes/Boids/New Nano Brain Obj.asset deleted file mode 100644 index df2a58c..0000000 --- a/Assets/Scenes/Boids/New Nano Brain Obj.asset +++ /dev/null @@ -1,60 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 36081359186edfec998d891a1feeb17b, type: 3} - m_Name: New Nano Brain Obj - m_EditorClassIdentifier: Assembly-CSharp::NanoBrainObj - title: - count: -26 - color: {r: 1, g: 1, b: 1, a: 1} - texture: {fileID: 0} - nuclei: - - id: 257807948 - _name: Root - synapses: - - nucleusId: -651011940 - weight: 1 - - nucleusId: -1689048724 - weight: 1 - receivers: [] - - id: -1868865374 - _name: Perception - synapses: [] - receivers: [] - - id: -651011940 - _name: Neuron 1 - synapses: [] - receivers: - - nucleusId: 257807948 - - id: -1689048724 - _name: New neuron - synapses: [] - receivers: - - nucleusId: 257807948 - - id: -152927560 - _name: 'Boundary: position' - synapses: [] - receivers: - - nucleusId: -1462684836 - - id: -1462684836 - _name: 'Boundary: velocity' - synapses: - - nucleusId: -152927560 - weight: 1 - receivers: [] - rootId: 257807948 - perception: - id: 1565766940 - _name: Perception - synapses: [] - receivers: [] - positionReceivers: [] - velocityReceivers: [] diff --git a/Assets/Scenes/Boids/Prefabs/Boid.prefab b/Assets/Scenes/Boids/Prefabs/Boid.prefab index 1a756c3..31be0f5 100644 --- a/Assets/Scenes/Boids/Prefabs/Boid.prefab +++ b/Assets/Scenes/Boids/Prefabs/Boid.prefab @@ -176,4 +176,4 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 92f34a5e4027a1dc39efd8ce63cf6aba, type: 3} m_Name: m_EditorClassIdentifier: Assembly-CSharp::NanoBrainComponent - brain: {fileID: 11400000, guid: af8d90b8b4b9dcad7837130c4143d91c, type: 2} + defaultBrain: {fileID: 11400000, guid: fc1a4800a8c531eb4855b436bc9084ae, type: 2} diff --git a/Assets/Scenes/Boids/RoamingBrain.asset b/Assets/Scenes/Boids/RoamingBrain.asset index e603273..0d13ed5 100644 --- a/Assets/Scenes/Boids/RoamingBrain.asset +++ b/Assets/Scenes/Boids/RoamingBrain.asset @@ -17,86 +17,36 @@ MonoBehaviour: color: {r: 1, g: 1, b: 1, a: 1} texture: {fileID: 0} nuclei: - - id: -1753291412 + - id: -1707533328 _name: Root synapses: - - nucleusId: 237822944 + - nucleusId: -112538112 weight: 1 receivers: [] - - id: 472852910 - _name: Perception - synapses: [] - receivers: [] - - id: 237822944 + nucleusType: + average: 0 + inverse: 0 + exponent: 1 + - id: -112538112 _name: Avoidance - synapses: [] - receivers: - - nucleusId: -1753291412 - - id: 983561152 - _name: 'Boundary: position' - synapses: [] - receivers: - - nucleusId: -1818801134 - - id: -1818801134 - _name: 'Boundary: velocity' synapses: - - nucleusId: 983561152 - weight: 1 - receivers: [] - - id: 1386590800 - _name: 'Boundary: position' + - nucleusId: 407735232 + weight: -1 + receivers: + - nucleusId: -1707533328 + nucleusType: + average: 0 + inverse: 0 + exponent: 1 + perceptei: + - id: 407735232 + _name: Boundary synapses: [] receivers: - - nucleusId: -1415771486 - - nucleusId: 237822944 - - id: -1415771486 - _name: 'Boundary: velocity' - synapses: - - nucleusId: 1386590800 - weight: 1 - receivers: [] - - id: -213085248 - _name: 'Boundary: position' - synapses: [] - receivers: - - nucleusId: 1279519762 - - nucleusId: 237822944 - - id: 1279519762 - _name: 'Boundary: velocity' - synapses: - - nucleusId: -213085248 - weight: 1 - receivers: [] - - id: 1783940116 - _name: 'Boundary: position' - synapses: [] - receivers: - - nucleusId: -1018422170 - - nucleusId: 237822944 - - id: -1018422170 - _name: 'Boundary: velocity' - synapses: - - nucleusId: 1783940116 - weight: 1 - receivers: [] - rootId: -1753291412 - perception: - id: 2139386530 - _name: Perception - synapses: [] - receivers: [] - positionReceivers: - - thingType: 0 - neuroid: - id: 237822944 - _name: Avoidance - synapses: - - nucleusId: 1386590800 - weight: 1 - - nucleusId: -213085248 - weight: 1 - - nucleusId: 1783940116 - weight: 1 - receivers: - - nucleusId: -1753291412 - velocityReceivers: [] + - nucleusId: -112538112 + nucleusType: Perceptoid + average: 0 + inverse: 0 + exponent: 1 + thingType: 1 + rootId: -1707533328 diff --git a/Assets/Scenes/Boids/Scripts/Boid.cs b/Assets/Scenes/Boids/Scripts/Boid.cs index f5a83cf..2f557be 100644 --- a/Assets/Scenes/Boids/Scripts/Boid.cs +++ b/Assets/Scenes/Boids/Scripts/Boid.cs @@ -13,32 +13,21 @@ public class Boid : MonoBehaviour { private Bounds innerBounds; public NanoBrainComponent nanoBrain; - - // public NanoBrain neuroidNet; - // public Perception perception; - - // public Nucleus behaviour; - - // public Neuroid totalForce; + public Receptor boundaryReceptor; + public Receptor boidReceptor; public int id; void Awake() { - nanoBrain = GetComponent(); this.id = this.GetInstanceID(); + nanoBrain = GetComponent(); + boundaryReceptor = Perceptoid.GetReceptor(nanoBrain.brain, BoundaryType); + boidReceptor = Perceptoid.GetReceptor(nanoBrain.brain, BoidType); + sc = FindFirstObjectByType(); innerBounds = new(sc.transform.position, sc.spaceSize - 2 * sc.boundaryWidth); - - // neuroidNet = GetComponent(); - // perception = new Perception(neuroidNet); - - // //behaviour = new Roaming(neuroidNet, perception, sc); - // behaviour = new Swarming(neuroidNet, perception, sc); - - // totalForce = new(neuroidNet, "Total"); - // behaviour.AddReceiver(totalForce); } void Update() { @@ -52,8 +41,9 @@ public class Boid : MonoBehaviour { Vector3 localPosition = this.transform.InverseTransformPoint(neighbour.transform.position); //Debug.DrawRay(this.transform.position, this.transform.TransformDirection(localPosition), Color.magenta); - int thingId = neighbour.GetInstanceID(); - nanoBrain.perception.ProcessStimulus(thingId, BoidType, localPosition, neighbour.gameObject.name); + //int thingId = neighbour.GetInstanceID(); + // nanoBrain.perception.ProcessStimulus(thingId, BoidType, localPosition, neighbour.gameObject.name); + boidReceptor.position = localPosition; } } @@ -62,10 +52,9 @@ public class Boid : MonoBehaviour { Vector3 pointOnBounds = innerBounds.ClosestPoint(point); Vector3 desiredWorldSpace = (pointOnBounds - point).normalized * sc.speed; Vector3 desiredLocalSpace = -this.transform.InverseTransformPoint(desiredWorldSpace); - nanoBrain.perception.ProcessStimulus(777, BoundaryType, desiredLocalSpace, "Boundary"); + boundaryReceptor.position = desiredLocalSpace; } - //Vector3 worldForce = this.transform.TransformDirection(behaviour.outputValue); Vector3 worldForce = this.transform.TransformDirection(nanoBrain.root.outputValue); this.velocity = (1 - sc.inertia) * (worldForce * Time.deltaTime) + sc.inertia * velocity; @@ -82,7 +71,6 @@ public class Boid : MonoBehaviour { transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 2f); // Adjust the speed of rotation } - //neuroidNet.UpdateNeurons(); nanoBrain.brain.UpdateNuclei(); } diff --git a/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs b/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs index be2fe61..513f05e 100644 --- a/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs +++ b/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs @@ -3,7 +3,7 @@ public class Roaming : Nucleus { public Neuroid output; - public Roaming(NanoBrainObj brain, Perception perception, SwarmControl sc) : base(null, "Roaming nucleus") { + public Roaming(NanoBrainObj brain, Perception perception, SwarmControl sc) : base("Roaming nucleus") { avoidance = new(brain, "Avoidance") { inverse = true }; perception.SendPositions(avoidance, Boid.BoundaryType); diff --git a/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs b/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs index de25135..92f9950 100644 --- a/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs +++ b/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs @@ -10,7 +10,7 @@ public class Swarming : Nucleus { public override Vector3 outputValue { get => output.outputValue; set => output.outputValue = value; } - public Swarming(NanoBrainObj brain, Perception perception, SwarmControl sc) : base(null, "Swarming Nucleus") { + public Swarming(NanoBrainObj brain, Perception perception, SwarmControl sc) : base("Swarming Nucleus") { this.cohesion = new(brain, "Cohesion") { inverse = false }; perception.SendPositions(this.cohesion, Boid.BoidType); diff --git a/Assets/Scenes/Boids/SwarmingBrain.asset b/Assets/Scenes/Boids/SwarmingBrain.asset new file mode 100644 index 0000000..4228d29 --- /dev/null +++ b/Assets/Scenes/Boids/SwarmingBrain.asset @@ -0,0 +1,88 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 36081359186edfec998d891a1feeb17b, type: 3} + m_Name: SwarmingBrain + m_EditorClassIdentifier: Assembly-CSharp::NanoBrainObj + title: + count: 0 + color: {r: 1, g: 1, b: 1, a: 1} + texture: {fileID: 0} + nuclei: + - id: -1707533328 + _name: Root + synapses: + - nucleusId: -112538112 + weight: 1 + - nucleusId: 1938577052 + weight: 1 + receivers: [] + nucleusType: + average: 0 + inverse: 0 + exponent: 1 + - id: -112538112 + _name: Avoidance + synapses: + - nucleusId: 407735232 + weight: -1 + receivers: + - nucleusId: -1707533328 + nucleusType: + average: 0 + inverse: 0 + exponent: 1 + - id: 1938577052 + _name: Cohesion + synapses: + - nucleusId: -1408496896 + weight: 1 + - nucleusId: -133566816 + weight: 1 + receivers: + - nucleusId: -1707533328 + nucleusType: + average: 0 + inverse: 0 + exponent: 1 + perceptei: + - id: 407735232 + _name: Boundary + synapses: [] + receivers: + - nucleusId: -112538112 + nucleusType: Perceptoid + average: 0 + inverse: 0 + exponent: 1 + thingType: 1 + - id: -1408496896 + _name: Boid1 + synapses: [] + receivers: + - nucleusId: 1938577052 + nucleusType: Perceptoid + average: 0 + inverse: 0 + exponent: 1 + thingType: 2 + - id: -133566816 + _name: Boid2 + synapses: [] + receivers: + - nucleusId: 27651644 + - nucleusId: 1938577052 + nucleusType: Perceptoid + average: 0 + inverse: 0 + exponent: 1 + thingType: 2 + rootId: -1707533328 diff --git a/Assets/Scenes/Boids/New Nano Brain Obj.asset.meta b/Assets/Scenes/Boids/SwarmingBrain.asset.meta similarity index 79% rename from Assets/Scenes/Boids/New Nano Brain Obj.asset.meta rename to Assets/Scenes/Boids/SwarmingBrain.asset.meta index 01cdcae..a12ec48 100644 --- a/Assets/Scenes/Boids/New Nano Brain Obj.asset.meta +++ b/Assets/Scenes/Boids/SwarmingBrain.asset.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 55099766f6f09071ab4e8c89b02fa302 +guid: fc1a4800a8c531eb4855b436bc9084ae NativeFormatImporter: externalObjects: {} mainObjectFileID: 11400000 From dc8ac7ef9bbf36997dfcd2dfb306f84ff3659b19 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 11 Dec 2025 15:19:24 +0100 Subject: [PATCH 022/179] Improved receptor, percepoid sleep --- Assembly-CSharp.csproj | 1 + Assets/NanoBrain/Perception.cs | 6 ++- Assets/NanoBrain/Perceptoid.cs | 5 +- Assets/NanoBrain/Receptor.cs | 33 +++++++++++++ Assets/NanoBrain/Receptor.cs.meta | 2 + Assets/NanoBrain/SensoryNeuroid.cs | 47 ++++++++++++------- Assets/NanoBrain/VisualEditor/NanoBrainObj.cs | 5 ++ Assets/Scenes/Boids/Scripts/Boid.cs | 7 ++- 8 files changed, 80 insertions(+), 26 deletions(-) create mode 100644 Assets/NanoBrain/Receptor.cs create mode 100644 Assets/NanoBrain/Receptor.cs.meta diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index 6b711a6..173cb6d 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -52,6 +52,7 @@ + diff --git a/Assets/NanoBrain/Perception.cs b/Assets/NanoBrain/Perception.cs index d6ee5a7..ee77960 100644 --- a/Assets/NanoBrain/Perception.cs +++ b/Assets/NanoBrain/Perception.cs @@ -63,7 +63,8 @@ public class Perception : Nucleus { if (sensoryNeuroids[i] == null) availableIx = i; else if (sensoryNeuroids[i].receptor.thingType == thingId) { - sensoryNeuroids[i].receptor.position = localPosition; + //sensoryNeuroids[i].receptor.position = localPosition; + sensoryNeuroids[i].receptor.ProcessStimulus(999, localPosition); return; } if (availableIx == -1) { @@ -101,7 +102,8 @@ public class Perception : Nucleus { receiver.neuroid.GetInputFrom(neuroid.velocityNeuroid); } - neuroid.receptor.position = localPosition; + //neuroid.receptor.position = localPosition; + neuroid.receptor.ProcessStimulus(333, localPosition); } } diff --git a/Assets/NanoBrain/Perceptoid.cs b/Assets/NanoBrain/Perceptoid.cs index bea7cce..3808936 100644 --- a/Assets/NanoBrain/Perceptoid.cs +++ b/Assets/NanoBrain/Perceptoid.cs @@ -127,7 +127,7 @@ public class Perceptoid : Neuroid { return null; } - public static void ProcessStimulus(NanoBrainObj brain, int thingType, Vector3 lcoalPosition) { + public static void ProcessStimulus(NanoBrainObj brain, int thingType, Vector3 localPosition) { Perceptoid selectedPerceptoid = null; foreach (Perceptoid nucleus in brain.perceptei) { if (nucleus is Perceptoid perceptoid && (thingType == 0 || perceptoid.thingType == thingType)) @@ -144,7 +144,8 @@ public class Perceptoid : Neuroid { Debug.Log("No perceptoid selected, stimulus is ignored"); return; } - selectedPerceptoid.receptor.position = lcoalPosition; + //selectedPerceptoid.receptor.position = localPosition; + selectedPerceptoid.receptor.ProcessStimulus(888, localPosition); } public static Receptor GetReceptor(NanoBrainObj brain, int thingType) { foreach (Perceptoid perceptoid in brain.perceptei) { diff --git a/Assets/NanoBrain/Receptor.cs b/Assets/NanoBrain/Receptor.cs new file mode 100644 index 0000000..7c9ccc7 --- /dev/null +++ b/Assets/NanoBrain/Receptor.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +public class Receptor { + + public Neuroid neuroid; + public List perceptoids; + + public int thingId; + public int thingType; + public Vector3 localPosition; + + /// + /// Local position of the thing + /// + public virtual Vector3 position { + get { + return this.localPosition; + } + // set { + // this.localPosition = value; + // neuroid.UpdateState(); + // } + } + + public virtual void ProcessStimulus(int thingId, Vector3 localPosition) { + this.thingId = thingId; + this.localPosition = localPosition; + neuroid.UpdateState(); + //perceptoids[0].UpdateState(); + } +} \ No newline at end of file diff --git a/Assets/NanoBrain/Receptor.cs.meta b/Assets/NanoBrain/Receptor.cs.meta new file mode 100644 index 0000000..56793ae --- /dev/null +++ b/Assets/NanoBrain/Receptor.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: cfb9734aebc3ab85aacf87d26fb92e55 \ No newline at end of file diff --git a/Assets/NanoBrain/SensoryNeuroid.cs b/Assets/NanoBrain/SensoryNeuroid.cs index 1cdeabb..6bfb5df 100644 --- a/Assets/NanoBrain/SensoryNeuroid.cs +++ b/Assets/NanoBrain/SensoryNeuroid.cs @@ -1,26 +1,36 @@ +using System.Collections.Generic; using System.Linq; using UnityEngine; -public class Receptor { +// public class Receptor { - public Neuroid neuroid; +// public Neuroid neuroid; +// public List perceptoids; - public int thingType; - public Vector3 localPosition; +// public int thingId; +// public int thingType; +// public Vector3 localPosition; - /// - /// Local position of the thing - /// - public virtual Vector3 position { - get { - return this.localPosition; - } - set { - this.localPosition = value; - neuroid.UpdateState(); - } - } -} +// /// +// /// Local position of the thing +// /// +// public virtual Vector3 position { +// get { +// return this.localPosition; +// } +// set { +// this.localPosition = value; +// neuroid.UpdateState(); +// } +// } + +// public virtual void ProcessStimulus(int thingId, Vector3 localPosition) { +// this.thingId = thingId; +// this.localPosition = localPosition; +// neuroid.UpdateState(); + +// } +// } public class SensoryNeuroid : Neuroid { // A neuroid which has no neurons as input @@ -32,6 +42,7 @@ public class SensoryNeuroid : Neuroid { this.name = name + ": position"; this.receptor = new Receptor { neuroid = this, + //perceptoids[0] = this, thingType = thingId }; this.velocityNeuroid = new(brain, name + ": velocity"); @@ -111,7 +122,7 @@ public class VelocityNeuroid : Neuroid { this.stale = 0; //foreach (Neuroid receiver in receivers) - foreach(Receiver receiver in receivers) { + foreach (Receiver receiver in receivers) { if (receiver.nucleus is Neuroid neuroid) neuroid.SetInput(this); } diff --git a/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs b/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs index 3d913bb..00fc89e 100644 --- a/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs +++ b/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs @@ -35,6 +35,11 @@ public class NanoBrainObj : ScriptableObject, ISerializationCallbackReceiver { if (nucleus.isSleeping) nucleus.outputValue = Vector3.zero; } + foreach (Perceptoid perception in perceptei) { + perception.stale++; + if (perception.isSleeping) + perception.outputValue = Vector3.zero; + } } public void OnBeforeSerialize() { diff --git a/Assets/Scenes/Boids/Scripts/Boid.cs b/Assets/Scenes/Boids/Scripts/Boid.cs index 2f557be..fe2deea 100644 --- a/Assets/Scenes/Boids/Scripts/Boid.cs +++ b/Assets/Scenes/Boids/Scripts/Boid.cs @@ -41,9 +41,8 @@ public class Boid : MonoBehaviour { Vector3 localPosition = this.transform.InverseTransformPoint(neighbour.transform.position); //Debug.DrawRay(this.transform.position, this.transform.TransformDirection(localPosition), Color.magenta); - //int thingId = neighbour.GetInstanceID(); - // nanoBrain.perception.ProcessStimulus(thingId, BoidType, localPosition, neighbour.gameObject.name); - boidReceptor.position = localPosition; + int thingId = neighbour.GetInstanceID(); + boidReceptor.ProcessStimulus(thingId, localPosition); } } @@ -52,7 +51,7 @@ public class Boid : MonoBehaviour { Vector3 pointOnBounds = innerBounds.ClosestPoint(point); Vector3 desiredWorldSpace = (pointOnBounds - point).normalized * sc.speed; Vector3 desiredLocalSpace = -this.transform.InverseTransformPoint(desiredWorldSpace); - boundaryReceptor.position = desiredLocalSpace; + boundaryReceptor.ProcessStimulus(777, desiredLocalSpace); } Vector3 worldForce = this.transform.TransformDirection(nanoBrain.root.outputValue); From 4e8d10f1bd609f328fbac6b234dc168b999eac8c Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 11 Dec 2025 16:50:03 +0100 Subject: [PATCH 023/179] Perceptoid pool starts to work --- Assets/NanoBrain/Perceptoid.cs | 42 ++++- Assets/NanoBrain/Receptor.cs | 35 +++- Assets/NanoBrain/SensoryNeuroid.cs | 8 +- .../VisualEditor/Editor/NanoBrainInspector.cs | 178 ++++++------------ Assets/Scenes/Boids/Boids.unity | 2 +- Assets/Scenes/Boids/RoamingBrain.asset | 1 + Assets/Scenes/Boids/SwarmingBrain.asset | 14 +- 7 files changed, 136 insertions(+), 144 deletions(-) diff --git a/Assets/NanoBrain/Perceptoid.cs b/Assets/NanoBrain/Perceptoid.cs index 3808936..2802128 100644 --- a/Assets/NanoBrain/Perceptoid.cs +++ b/Assets/NanoBrain/Perceptoid.cs @@ -11,12 +11,16 @@ public class Perceptoid : Neuroid { [SerializeField] public int thingType; + public int thingId; public override void Rebuild(NanoBrainObj brain) { base.Rebuild(brain); - this.receptor = new Receptor() { - neuroid = this - }; + //this.receptor = new Receptor(this); + this.receptor = Perceptoid.GetReceptor(brain, thingType); + if (this.receptor == null) + this.receptor = new Receptor(this); + else + this.receptor.perceptei.Add(this); } public override void Deserialize(Nucleus nucleus) { @@ -57,9 +61,7 @@ public class Perceptoid : Neuroid { this.nucleusType = nameof(Perceptoid); this.name = name; - this.receptor = new Receptor { - neuroid = this - }; + this.receptor = new Receptor(this); } public Perceptoid(NanoBrainObj brain, int thingType, string name = "sensor") : base(name) { @@ -73,8 +75,7 @@ public class Perceptoid : Neuroid { this.nucleusType = nameof(Perceptoid); this.name = name; this.thingType = thingType; - this.receptor = new Receptor { - neuroid = this, + this.receptor = new Receptor(this) { thingType = thingType }; this.velocityNeuroid = new(brain, name + ": velocity"); @@ -119,6 +120,31 @@ public class Perceptoid : Neuroid { this.stale = 0; } + public void UpdateState(int thingId, Vector3 receptorValue) { + this.thingId = thingId; + Vector3 result = receptorValue; + foreach (Synapse synapse in this.synapses) { + Nucleus nucleus = synapse.nucleus; + float weight = synapse.weight; + Vector3 direction = nucleus.outputValue.normalized; + float magnitude = nucleus.outputValue.magnitude; + + magnitude = weight * Mathf.Pow(magnitude, exponent); + if (inverse) + magnitude = 1 / magnitude; + result += direction * magnitude; + } + if (average && this.synapses.Count > 0) + result /= this.synapses.Count + 1; + + this.outputValue = result; + foreach (Receiver receiver in this.receivers) + if (receiver.nucleus is Neuroid neuroid) + neuroid.SetInput(this); + this.stale = 0; + } + + public static Perceptoid GetPerception(NanoBrainObj brain, int thingType = 0) { foreach (Nucleus nucleus in brain.nuclei) { if (nucleus is Perceptoid perceptoid && (thingType == 0 || perceptoid.thingType == thingType)) diff --git a/Assets/NanoBrain/Receptor.cs b/Assets/NanoBrain/Receptor.cs index 7c9ccc7..92b7d67 100644 --- a/Assets/NanoBrain/Receptor.cs +++ b/Assets/NanoBrain/Receptor.cs @@ -4,13 +4,18 @@ using UnityEngine; public class Receptor { - public Neuroid neuroid; - public List perceptoids; + private Neuroid neuroid; + public List perceptei = new(); public int thingId; public int thingType; public Vector3 localPosition; + public Receptor(Perceptoid perceptoid) { + this.neuroid = perceptoid; + this.perceptei.Add(perceptoid); + } + /// /// Local position of the thing /// @@ -27,7 +32,29 @@ public class Receptor { public virtual void ProcessStimulus(int thingId, Vector3 localPosition) { this.thingId = thingId; this.localPosition = localPosition; - neuroid.UpdateState(); - //perceptoids[0].UpdateState(); + ///neuroid.UpdateState(); + + Perceptoid selectedPerceptoid = null; + foreach (Perceptoid perceptoid in this.perceptei) { + if (perceptoid.thingId == this.thingId) { + selectedPerceptoid = perceptoid; + break; + } + else if (perceptoid.isSleeping) + selectedPerceptoid = perceptoid; + else if (selectedPerceptoid == null) { + selectedPerceptoid = perceptoid; + } + else if (selectedPerceptoid.isSleeping == false) { + if (perceptoid.receptor.position.magnitude < selectedPerceptoid.receptor.position.magnitude) + selectedPerceptoid = perceptoid; + } + } + if (selectedPerceptoid == null) { + Debug.Log("No perceptoid selected, stimulus is ignored"); + return; + } + Debug.Log($"Stimulus {thingId} {selectedPerceptoid.thingId}"); + selectedPerceptoid.UpdateState(this.thingId, this.localPosition); } } \ No newline at end of file diff --git a/Assets/NanoBrain/SensoryNeuroid.cs b/Assets/NanoBrain/SensoryNeuroid.cs index 6bfb5df..c716cca 100644 --- a/Assets/NanoBrain/SensoryNeuroid.cs +++ b/Assets/NanoBrain/SensoryNeuroid.cs @@ -40,11 +40,9 @@ public class SensoryNeuroid : Neuroid { public SensoryNeuroid(NanoBrainObj brain, int thingId, string name = "sensor") : base(brain, name) { this.name = name + ": position"; - this.receptor = new Receptor { - neuroid = this, - //perceptoids[0] = this, - thingType = thingId - }; + // this.receptor = new Receptor(this) { + // thingType = thingId + // }; this.velocityNeuroid = new(brain, name + ": velocity"); // The velocity neuroid received position data from this this.AddReceiver(velocityNeuroid); diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs index e944386..f86e0f3 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs @@ -237,38 +237,6 @@ public class NanoBrainInspector : Editor { DrawNucleus(this.currentNucleus, position, this.currentNucleus.outputValue.magnitude, 20); } - private void DrawNucleus(Nucleus nucleus, Vector3 position, float maxValue, float size) { - if (nucleus.isSleeping) - Handles.color = Color.darkRed; - else { - float brightness = nucleus.outputValue.magnitude / maxValue; - Handles.color = new Color(brightness, brightness, brightness); - } - Handles.DrawSolidDisc(position, Vector3.forward, size); - Vector3 labelPos = position - Vector3.down * (size + 0.2f); // below disc along up axis - GUIStyle style = new GUIStyle(EditorStyles.label) { - alignment = TextAnchor.UpperCenter, - normal = { textColor = Color.white }, - fontStyle = FontStyle.Bold - }; - Handles.Label(labelPos, nucleus.name, style); - - Rect neuronRect = new(position.x - size, position.y - size, size * 2, size * 2); - int id = GUIUtility.GetControlID(FocusType.Passive); - Event e = Event.current; - EventType et = e.GetTypeForControl(id); - if (e != null && neuronRect.Contains(e.mousePosition)) { - // Process Hover - HandleMouseHover(nucleus, neuronRect); - // Process click - if (e.type == EventType.MouseDown && e.button == 0) { - // Consume the event so the scene doesn't also handle it - e.Use(); - HandleClicked(nucleus); - } - } - } - private void DrawReceivers(Nucleus nucleus, Vector3 parentPos, float size) { int nodeCount = nucleus.receivers.Count; @@ -290,6 +258,8 @@ public class NanoBrainInspector : Editor { int row = 0; foreach (Receiver receiver in nucleus.receivers) { Nucleus receiverNucleus = receiver.nucleus; + if (receiverNucleus == null) + continue; Vector3 pos = new(100, margin + row * spacing, 0.0f); Handles.color = Color.white; @@ -331,104 +301,68 @@ public class NanoBrainInspector : Editor { } } - /* - private void DrawLayer(NeuroidLayer layer) { - int nodeCount = layer.neuroids.Count; - - // Determine the maximum value in this layer - // This is used to 'scale' the output value colors of the nuclei - float maxValue = 0; - foreach (Nucleus nucleus in layer.neuroids) { - if (nucleus is Neuroid neuroid) { - float value = neuroid.outputValue.magnitude; - if (value > maxValue) - maxValue = value; - } + private void DrawNucleus(Nucleus nucleus, Vector3 position, float maxValue, float size) { + if (nucleus.isSleeping) + Handles.color = Color.darkRed; + else { + float brightness = nucleus.outputValue.magnitude / maxValue; + Handles.color = new Color(brightness, brightness, brightness); } + Handles.DrawSolidDisc(position, Vector3.forward, size); + Vector3 labelPos = position - Vector3.down * (size + 0.2f); // below disc along up axis + GUIStyle style = new GUIStyle(EditorStyles.label) { + alignment = TextAnchor.UpperCenter, + normal = { textColor = Color.white }, + fontStyle = FontStyle.Bold + }; + Handles.Label(labelPos, nucleus.name, style); - // Determine the spacing of the nuclei in the layer - float spacing = 400f / nodeCount; - float margin = 10 + spacing / 2; - - foreach (Nucleus layerNucleus in layer.neuroids) { - Vector2Int layerNeuroidPos = this.neuroidPositions[layerNucleus]; - Vector3 parentPos = new(100 + layerNeuroidPos.x * 100, margin + layerNeuroidPos.y * spacing, 0.1f); - - float inputSpacing = 400f / layerNucleus.synapses.Count; - float inputMargin = 10 + inputSpacing / 2; - int minStale = 10000; - foreach (Synapse synapse in layerNucleus.synapses) { - Nucleus nucleus = synapse.nucleus; - if (nucleus != null) { - if (this.neuroidPositions.ContainsKey(nucleus)) { - Vector2Int inputNeuroidPos = this.neuroidPositions[nucleus]; - if (inputNeuroidPos.x == layerNeuroidPos.x + 1) { - Vector3 pos = new(100 + inputNeuroidPos.x * 100, inputMargin + inputNeuroidPos.y * inputSpacing, 0.0f); - - Handles.color = Color.white; - Handles.DrawLine(parentPos, pos); - } - } - if (nucleus is Neuroid neuroid && neuroid.stale < minStale) - minStale = neuroid.stale; - } - } - - - float size = 20; - if (layerNucleus == this.currentNucleus) { - Handles.color = Color.white; - Handles.DrawSolidDisc(parentPos, Vector3.forward, size + 2); - } - DrawNucleus(layerNucleus, parentPos, maxValue, size); - // if (layerNucleus.isSleeping) - // Handles.color = Color.darkRed; - // else { - // float brightness = layerNucleus.outputValue.magnitude / maxValue; - // Handles.color = new Color(brightness, brightness, brightness); - // } - // Handles.DrawSolidDisc(parentPos, Vector3.forward, size); - // Vector3 labelPos = parentPos - Vector3.down * (size + 0.2f); // below disc along up axis - // GUIStyle style = new GUIStyle(EditorStyles.label) { - // alignment = TextAnchor.UpperCenter, - // normal = { textColor = Color.white }, - // fontStyle = FontStyle.Bold - // }; - // Handles.Label(labelPos, layerNucleus.name, style); - - Rect neuronRect = new(parentPos.x - size, parentPos.y - size, size * 2, size * 2); - int id = GUIUtility.GetControlID(FocusType.Passive); - Event e = Event.current; - EventType et = e.GetTypeForControl(id); - if (e != null && neuronRect.Contains(e.mousePosition)) { - // Process Hover - HandleMouseHover(layerNucleus, neuronRect); - // Process click - if (e.type == EventType.MouseDown && e.button == 0) { - // Consume the event so the scene doesn't also handle it - e.Use(); - HandleClicked(layerNucleus); - } + Rect neuronRect = new(position.x - size, position.y - size, size * 2, size * 2); + int id = GUIUtility.GetControlID(FocusType.Passive); + Event e = Event.current; + EventType et = e.GetTypeForControl(id); + if (e != null && neuronRect.Contains(e.mousePosition)) { + // Process Hover + HandleMouseHover(nucleus, neuronRect); + // Process click + if (e.type == EventType.MouseDown && e.button == 0) { + // Consume the event so the scene doesn't also handle it + e.Use(); + HandleClicked(nucleus); } } } - */ - private void HandleMouseHover(Nucleus neuroid, Rect rect) { + private void HandleMouseHover(Nucleus nucleus, Rect rect) { GUIContent tooltip; - if (neuroid is SensoryNeuroid sensoryNeuroid) { + if (nucleus is SensoryNeuroid sensoryNeuroid) { tooltip = new( $"{sensoryNeuroid.name}" + $"\nThing {sensoryNeuroid.receptor.thingType}" + - $"\nValue: {neuroid.outputValue}" + - $"\nStale: {neuroid.stale}"); + $"\nValue: {nucleus.outputValue}" + + $"\nStale: {nucleus.stale}"); + } + else if (nucleus is Perceptoid perceptoid) { + if (perceptoid.receptor != null) { + tooltip = new( + $"{perceptoid.name}" + + $"\nType {perceptoid.receptor.thingType}" + + $" Thing {perceptoid.thingId}" + + $"\nValue: {nucleus.outputValue}"); + } + else { + tooltip = new( + $"{perceptoid.name}" + + $"\nThing {perceptoid.thingId}" + + $"\nValue: {nucleus.outputValue}"); + } } else { tooltip = new( - $"{neuroid.name}" + - $"\nsynapse count {neuroid.synapses.Count}" + - $"\nValue: {neuroid.outputValue}" + - $"\nStale: {neuroid.stale}"); + $"{nucleus.name}" + + $"\nsynapse count {nucleus.synapses.Count}" + + $"\nValue: {nucleus.outputValue}" + + $"\nStale: {nucleus.stale}"); } Vector2 mousePosition = Event.current.mousePosition; @@ -445,7 +379,6 @@ public class NanoBrainInspector : Editor { BuildLayers(); } - void DrawInspector(VisualElement inspectorContainer) { if (inspectorContainer == null) return; @@ -518,9 +451,14 @@ public class NanoBrainInspector : Editor { } protected virtual void DeleteNeuron(Nucleus nucleus) { - this.currentNucleus = nucleus.receivers[0].nucleus; + this.currentNucleus = nucleus.brain.root; + foreach (Receiver receiver in nucleus.receivers) { + if (receiver.nucleus != null) { + this.currentNucleus = receiver.nucleus; + break; + } + } Nucleus.Delete(nucleus); - //Rebuild(inspectorContainer); BuildLayers(); } diff --git a/Assets/Scenes/Boids/Boids.unity b/Assets/Scenes/Boids/Boids.unity index 5515d90..f0e9d7c 100644 --- a/Assets/Scenes/Boids/Boids.unity +++ b/Assets/Scenes/Boids/Boids.unity @@ -393,7 +393,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec888ca5333d45a438f9f417fa5ce135, type: 3} m_Name: m_EditorClassIdentifier: Assembly-CSharp::SwarmSpawn - count: 3 + count: 30 boidPrefab: {fileID: 8702527964058765413, guid: f9c706268554ce449a8773675b2864b8, type: 3} spawnAreaSize: {x: 0.5, y: 0.5, z: 0.5} minDelay: 0.05 diff --git a/Assets/Scenes/Boids/RoamingBrain.asset b/Assets/Scenes/Boids/RoamingBrain.asset index 0d13ed5..02830cf 100644 --- a/Assets/Scenes/Boids/RoamingBrain.asset +++ b/Assets/Scenes/Boids/RoamingBrain.asset @@ -49,4 +49,5 @@ MonoBehaviour: inverse: 0 exponent: 1 thingType: 1 + thingId: 0 rootId: -1707533328 diff --git a/Assets/Scenes/Boids/SwarmingBrain.asset b/Assets/Scenes/Boids/SwarmingBrain.asset index 4228d29..ab81e1e 100644 --- a/Assets/Scenes/Boids/SwarmingBrain.asset +++ b/Assets/Scenes/Boids/SwarmingBrain.asset @@ -23,7 +23,7 @@ MonoBehaviour: - nucleusId: -112538112 weight: 1 - nucleusId: 1938577052 - weight: 1 + weight: 10 receivers: [] nucleusType: average: 0 @@ -43,9 +43,9 @@ MonoBehaviour: - id: 1938577052 _name: Cohesion synapses: - - nucleusId: -1408496896 + - nucleusId: -1420275136 weight: 1 - - nucleusId: -133566816 + - nucleusId: -1266532688 weight: 1 receivers: - nucleusId: -1707533328 @@ -64,7 +64,8 @@ MonoBehaviour: inverse: 0 exponent: 1 thingType: 1 - - id: -1408496896 + thingId: 0 + - id: -1420275136 _name: Boid1 synapses: [] receivers: @@ -74,15 +75,16 @@ MonoBehaviour: inverse: 0 exponent: 1 thingType: 2 - - id: -133566816 + thingId: 0 + - id: -1266532688 _name: Boid2 synapses: [] receivers: - - nucleusId: 27651644 - nucleusId: 1938577052 nucleusType: Perceptoid average: 0 inverse: 0 exponent: 1 thingType: 2 + thingId: 0 rootId: -1707533328 From 0adb71f3060b132ae6e740457778285245b3bdb1 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 11 Dec 2025 17:37:01 +0100 Subject: [PATCH 024/179] (Dis)connect perceptoids --- Assets/NanoBrain/Nucleus.cs | 5 ++ Assets/NanoBrain/Perception.cs | 2 +- Assets/NanoBrain/Perceptoid.cs | 2 +- Assets/NanoBrain/Receptor.cs | 18 +---- .../VisualEditor/Editor/NanoBrainInspector.cs | 79 +++++++++++++------ 5 files changed, 66 insertions(+), 40 deletions(-) diff --git a/Assets/NanoBrain/Nucleus.cs b/Assets/NanoBrain/Nucleus.cs index 4593628..ae4b0c6 100644 --- a/Assets/NanoBrain/Nucleus.cs +++ b/Assets/NanoBrain/Nucleus.cs @@ -88,6 +88,11 @@ public class Nucleus { receiver.SetWeight(this, 1.0f); } + public void RemoveReceiver(Nucleus receiverNucleus) { + this.receivers.RemoveAll(receiver => receiver.nucleus == receiverNucleus); + receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); + } + public static void Delete(Nucleus nucleus) { foreach (Synapse synapse in nucleus.synapses) { if (synapse.nucleus.receivers.Count > 1) { diff --git a/Assets/NanoBrain/Perception.cs b/Assets/NanoBrain/Perception.cs index ee77960..46ca2ab 100644 --- a/Assets/NanoBrain/Perception.cs +++ b/Assets/NanoBrain/Perception.cs @@ -71,7 +71,7 @@ public class Perception : Nucleus { if (sensoryNeuroids[i].isSleeping) leastInterestingIx = i; else if (sensoryNeuroids[i] != null) { - if (leastInterestingIx == -1 || sensoryNeuroids[leastInterestingIx].receptor.position.magnitude > sensoryNeuroids[i].receptor.position.magnitude) + if (leastInterestingIx == -1 || sensoryNeuroids[leastInterestingIx].receptor.localPosition.magnitude > sensoryNeuroids[i].receptor.localPosition.magnitude) leastInterestingIx = i; } } diff --git a/Assets/NanoBrain/Perceptoid.cs b/Assets/NanoBrain/Perceptoid.cs index 2802128..02b3ccd 100644 --- a/Assets/NanoBrain/Perceptoid.cs +++ b/Assets/NanoBrain/Perceptoid.cs @@ -163,7 +163,7 @@ public class Perceptoid : Neuroid { break; } } - else if (perceptoid.receptor.position.magnitude < selectedPerceptoid.receptor.position.magnitude) + else if (perceptoid.receptor.localPosition.magnitude < selectedPerceptoid.receptor.localPosition.magnitude) selectedPerceptoid = perceptoid; } if (selectedPerceptoid == null) { diff --git a/Assets/NanoBrain/Receptor.cs b/Assets/NanoBrain/Receptor.cs index 92b7d67..4c0f770 100644 --- a/Assets/NanoBrain/Receptor.cs +++ b/Assets/NanoBrain/Receptor.cs @@ -4,7 +4,7 @@ using UnityEngine; public class Receptor { - private Neuroid neuroid; + public List perceptei = new(); public int thingId; @@ -12,27 +12,13 @@ public class Receptor { public Vector3 localPosition; public Receptor(Perceptoid perceptoid) { - this.neuroid = perceptoid; this.perceptei.Add(perceptoid); } - /// - /// Local position of the thing - /// - public virtual Vector3 position { - get { - return this.localPosition; - } - // set { - // this.localPosition = value; - // neuroid.UpdateState(); - // } - } public virtual void ProcessStimulus(int thingId, Vector3 localPosition) { this.thingId = thingId; this.localPosition = localPosition; - ///neuroid.UpdateState(); Perceptoid selectedPerceptoid = null; foreach (Perceptoid perceptoid in this.perceptei) { @@ -46,7 +32,7 @@ public class Receptor { selectedPerceptoid = perceptoid; } else if (selectedPerceptoid.isSleeping == false) { - if (perceptoid.receptor.position.magnitude < selectedPerceptoid.receptor.position.magnitude) + if (perceptoid.receptor.localPosition.magnitude < selectedPerceptoid.receptor.localPosition.magnitude) selectedPerceptoid = perceptoid; } } diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs index f86e0f3..7897927 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; - +using System.Linq; using UnityEditor; using UnityEngine; @@ -437,6 +437,23 @@ public class NanoBrainInspector : Editor { AddPerceptoid(this.currentNucleus); if (GUILayout.Button("Delete this neuron")) DeleteNeuron(this.currentNucleus); + // if (GUILayout.Button("Connect to...")) + // ConnectNucleus(this.currentNucleus); + + ConnectNucleus(this.currentNucleus); + DisconnectNucleus(this.currentNucleus); + // GUIStyle toggleButton = new("Button"); + // if (connecting) { + // toggleButton.normal = toggleButton.active; + // } + // if (GUILayout.Button(connecting ? "Connecting..." : "Connect to...", toggleButton)) { + // connecting = !connecting; + // if (connecting) { + // names = this.currentNucleus.brain.perceptei.Select(i => i.name).ToArray(); + // } + // } + // if (connecting) + // ConnectNucleus(this.currentNucleus); }); @@ -446,7 +463,6 @@ public class NanoBrainInspector : Editor { protected virtual void AddInputNeuron(Nucleus nucleus) { Neuroid newNeuroid = new(this.brain, "New neuron"); newNeuroid.AddReceiver(nucleus); - //Rebuild(inspectorContainer); BuildLayers(); } @@ -468,29 +484,48 @@ public class NanoBrainInspector : Editor { BuildLayers(); } - // protected virtual void AddPositionPerception(Nucleus receiver) { - // this.brain.perception.SendPositions(receiver); - // } - // protected virtual void AddVelocityPerception(Nucleus receiver) { - // this.brain.perception.SendVelocities(receiver); - // } + protected virtual void ConnectNucleus(Nucleus nucleus) { + if (this.currentNucleus.brain == null) + return; + string[] names = this.currentNucleus.brain.perceptei.Select(i => i.name).ToArray(); + int selectedIndex = -1; + selectedIndex = EditorGUILayout.Popup("Connect to", selectedIndex, names); + if (selectedIndex >= 0 && selectedIndex < this.currentNucleus.brain.perceptei.Count) { + Nucleus n = this.currentNucleus.brain.perceptei[selectedIndex]; + n.AddReceiver(this.currentNucleus); + } + } - private Vector3 NodePosition(Nucleus nucleus, int layerNodeCount = 1) { - if (this.neuroidPositions.ContainsKey(nucleus)) { - Vector2Int nucleusPos = this.neuroidPositions[nucleus]; - return NodePosition(nucleusPos, layerNodeCount); - } - else { - return Vector3.zero; + protected virtual void DisconnectNucleus(Nucleus nucleus) { + if (this.currentNucleus.brain == null) + return; + string[] names = this.currentNucleus.synapses.Select(synapse => synapse.nucleus.name).ToArray(); + int selectedIndex = -1; + selectedIndex = EditorGUILayout.Popup("Disconnect from", selectedIndex, names); + if (selectedIndex >= 0 && selectedIndex < this.currentNucleus.brain.perceptei.Count) { + Synapse synapse =this.currentNucleus.synapses[selectedIndex]; + //n.AddReceiver(this.currentNucleus); + synapse.nucleus.RemoveReceiver(this.currentNucleus); + //BuildLayers(); } } - private Vector3 NodePosition(Vector2Int location, int layerNodeCount = 1) { - float spacing = 400f / layerNodeCount; - float margin = 10 + spacing / 2; - float size = 20; - Vector3 parentPos = new(100 + location.x * 100 - size, margin + location.y * spacing - size, 0.1f); - return parentPos; - } + + // private Vector3 NodePosition(Nucleus nucleus, int layerNodeCount = 1) { + // if (this.neuroidPositions.ContainsKey(nucleus)) { + // Vector2Int nucleusPos = this.neuroidPositions[nucleus]; + // return NodePosition(nucleusPos, layerNodeCount); + // } + // else { + // return Vector3.zero; + // } + // } + // private Vector3 NodePosition(Vector2Int location, int layerNodeCount = 1) { + // float spacing = 400f / layerNodeCount; + // float margin = 10 + spacing / 2; + // float size = 20; + // Vector3 parentPos = new(100 + location.x * 100 - size, margin + location.y * spacing - size, 0.1f); + // return parentPos; + // } // public void CreateEdge(string fromId, string toId) { From 76af037a01ffb3a09bfe47a2b1f77a4e81990995 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Fri, 12 Dec 2025 16:00:23 +0100 Subject: [PATCH 025/179] Added curves --- Assets/NanoBrain/Neuroid.cs | 14 ---- Assets/NanoBrain/Nucleus.cs | 80 ++++++++++++++++++- .../VisualEditor/Editor/NanoBrainInspector.cs | 51 ++++-------- Assets/Scenes/Boids/SwarmingBrain.asset | 17 ++++ 4 files changed, 111 insertions(+), 51 deletions(-) diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index 92cf2f2..ac417e7 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -6,13 +6,6 @@ public class Neuroid : Nucleus { public bool inverse = false; public float exponent = 1.0f; - // public Neuroid(NanoBrain brain, string name) : base(null, name) { - // this.brain = brain; - // if (this.brain != null) - // this.brain.neuroids.Add(this); - // else - // Debug.LogError("No neuroid network"); - // } public Neuroid(NanoBrainObj brain, string name) : base(name) { this.brain = brain; @@ -26,16 +19,9 @@ public class Neuroid : Nucleus { public Neuroid(string name): base(name) {} public void SetWeight(Neuroid input, float weight) { - //this.synapses[input] = weight; this.SetWeight((Nucleus)input, weight); } - // public void GetInputFrom(Neuroid input, float weight = 1.0f) { - // input.AddReceiver(this); - // //this.synapses[input] = weight; - // this.SetWeight((Nucleus)input, weight); - // } - public void SetInput(Neuroid input) { // if (this.synapses.ContainsKey(input) == false) // this.synapses[input] = 1.0f; diff --git a/Assets/NanoBrain/Nucleus.cs b/Assets/NanoBrain/Nucleus.cs index ae4b0c6..340d3c0 100644 --- a/Assets/NanoBrain/Nucleus.cs +++ b/Assets/NanoBrain/Nucleus.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using UnityEngine; +using UnityEditor; [System.Serializable] public class Nucleus { @@ -15,7 +16,7 @@ public class Nucleus { } [SerializeField] - public List synapses = new(); + public List synapses = new(); [SerializeField] public List receivers = new(); @@ -54,7 +55,7 @@ public class Nucleus { return nucleus; } - public virtual void Deserialize(Nucleus nucleus) { } + public virtual void Deserialize(Nucleus nucleus) { } #endregion Serialization @@ -152,6 +153,17 @@ public class Synapse { public int nucleusId; public float weight; + public enum CurvePresets { + Linear, + Power, + Sqrt, + Reciprocal, + Custom + } + public CurvePresets curvePreset; + public AnimationCurve curve; + public float curveMax = 1.0f; + public Synapse(Nucleus nucleus, float weight) { this.nucleus = nucleus; this.nucleusId = nucleus.id; @@ -177,6 +189,70 @@ public class Synapse { } Debug.LogError($"Synapse deserialization error: could not find nucleus with id {this.nucleusId}"); } + + public AnimationCurve GenerateCurve() { + switch (this.curvePreset) { + case CurvePresets.Linear: + this.curveMax = this.weight; + return Presets.Linear(this.weight); + case CurvePresets.Power: + this.curveMax = this.weight; + return Presets.Power(2.0f, this.weight); + case CurvePresets.Sqrt: + this.curveMax = this.weight; + return Presets.Power(0.5f, this.weight); + case CurvePresets.Reciprocal: + this.curveMax = 1 / 0.01f * this.weight; + return Presets.Reciprocal(this.weight); + default: + this.curveMax = weight; + return AnimationCurve.Constant(0, 1, weight); + } + } + + public static class Presets { + private const int samples = 32; + public static AnimationCurve Linear(float weight) { + return AnimationCurve.Linear(0f, 0f, 1f, weight); + } + public static AnimationCurve Power(float exponent, float weight) { + // build keyframes + Keyframe[] keys = new Keyframe[samples]; + for (int i = 0; i < samples; i++) { + float t = i / (float)(samples - 1); + float v = Mathf.Pow(t, exponent) * weight; + keys[i] = new Keyframe(t, v); + } + + AnimationCurve curve = new(keys); + + // set tangent modes for each key to Auto (smooth). Use Linear if you prefer straight segments. + for (int i = 0; i < curve.length; i++) { + AnimationUtility.SetKeyLeftTangentMode(curve, i, AnimationUtility.TangentMode.Auto); + AnimationUtility.SetKeyRightTangentMode(curve, i, AnimationUtility.TangentMode.Auto); + } + + return curve; + } + public static AnimationCurve Reciprocal(float weight) { + int samples = 128; + float xMin = 0.001f; + float xMax = 1; + var keys = new Keyframe[samples]; + for (int i = 0; i < samples; i++) { + float t = i / (float)(samples - 1); + float x = Mathf.Lerp(xMin, xMax, t); + float y = 1f / x * weight; + keys[i] = new Keyframe(x, y); + } + var curve = new AnimationCurve(keys); + for (int i = 0; i < curve.length; i++) { + AnimationUtility.SetKeyLeftTangentMode(curve, i, AnimationUtility.TangentMode.Linear); + AnimationUtility.SetKeyRightTangentMode(curve, i, AnimationUtility.TangentMode.Linear); + } + return curve; + } + } } [System.Serializable] diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs index 7897927..f9ff10a 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs @@ -403,33 +403,31 @@ public class NanoBrainInspector : Editor { EditorGUILayout.Vector3Field(GUIContent.none, this.currentNucleus.outputValue); EditorGUILayout.EndHorizontal(); if (this.currentNucleus.synapses.Count > 0) { - EditorGUILayout.LabelField("Synapses"); - EditorGUI.indentLevel++; foreach (Synapse synapse in this.currentNucleus.synapses) { if (synapse.nucleus != null) { EditorGUI.BeginDisabledGroup(synapse.nucleus.isSleeping); - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.LabelField(synapse.nucleus.name, GUILayout.Width(120)); - EditorGUI.indentLevel--; - // if (synapse.nucleus is Perceptoid perceptoid) { - // EditorGUILayout.LabelField("Thing", GUILayout.Width(45)); - // perceptoid.thingType = EditorGUILayout.IntField(perceptoid.thingType, GUILayout.Width(40)); - - // } - // else { - EditorGUILayout.LabelField("Weight", GUILayout.Width(45)); - synapse.weight = EditorGUILayout.FloatField(synapse.weight, GUILayout.Width(40)); - // } - EditorGUI.indentLevel++; - EditorGUILayout.Vector3Field(GUIContent.none, synapse.nucleus.outputValue, GUILayout.Width(180)); + EditorGUILayout.LabelField(synapse.nucleus.name, GUILayout.Width(150)); + EditorGUILayout.Vector3Field(GUIContent.none, synapse.nucleus.outputValue); //, GUILayout.Width(180)); EditorGUILayout.EndHorizontal(); + EditorGUI.indentLevel++; + EditorGUI.BeginChangeCheck(); + synapse.weight = EditorGUILayout.FloatField("Weight", synapse.weight); + synapse.curvePreset = (Synapse.CurvePresets)EditorGUILayout.EnumPopup("Preset", synapse.curvePreset); + if (EditorGUI.EndChangeCheck()) { + synapse.curve = synapse.GenerateCurve(); + } + if (synapse.curveMax > 0) + EditorGUILayout.CurveField("Curve", synapse.curve, Color.cyan, new Rect(0, 0, 1, synapse.curveMax)); + else + EditorGUILayout.CurveField("Curve", synapse.curve, Color.cyan, new Rect(0, synapse.curveMax, 1, -synapse.curveMax)); + EditorGUI.indentLevel--; EditorGUI.EndDisabledGroup(); } } - EditorGUI.indentLevel--; + //EditorGUI.indentLevel--; } if (GUILayout.Button("Add Neuron")) AddInputNeuron(this.currentNucleus); @@ -437,24 +435,9 @@ public class NanoBrainInspector : Editor { AddPerceptoid(this.currentNucleus); if (GUILayout.Button("Delete this neuron")) DeleteNeuron(this.currentNucleus); - // if (GUILayout.Button("Connect to...")) - // ConnectNucleus(this.currentNucleus); ConnectNucleus(this.currentNucleus); DisconnectNucleus(this.currentNucleus); - // GUIStyle toggleButton = new("Button"); - // if (connecting) { - // toggleButton.normal = toggleButton.active; - // } - // if (GUILayout.Button(connecting ? "Connecting..." : "Connect to...", toggleButton)) { - // connecting = !connecting; - // if (connecting) { - // names = this.currentNucleus.brain.perceptei.Select(i => i.name).ToArray(); - // } - // } - // if (connecting) - // ConnectNucleus(this.currentNucleus); - }); inspectorContainer.Add(container); @@ -503,10 +486,8 @@ public class NanoBrainInspector : Editor { int selectedIndex = -1; selectedIndex = EditorGUILayout.Popup("Disconnect from", selectedIndex, names); if (selectedIndex >= 0 && selectedIndex < this.currentNucleus.brain.perceptei.Count) { - Synapse synapse =this.currentNucleus.synapses[selectedIndex]; - //n.AddReceiver(this.currentNucleus); + Synapse synapse = this.currentNucleus.synapses[selectedIndex]; synapse.nucleus.RemoveReceiver(this.currentNucleus); - //BuildLayers(); } } diff --git a/Assets/Scenes/Boids/SwarmingBrain.asset b/Assets/Scenes/Boids/SwarmingBrain.asset index ab81e1e..0784a70 100644 --- a/Assets/Scenes/Boids/SwarmingBrain.asset +++ b/Assets/Scenes/Boids/SwarmingBrain.asset @@ -24,6 +24,8 @@ MonoBehaviour: weight: 1 - nucleusId: 1938577052 weight: 10 + - nucleusId: 1641120128 + weight: -5 receivers: [] nucleusType: average: 0 @@ -53,6 +55,19 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 + - id: 1641120128 + _name: Separation + synapses: + - nucleusId: -1420275136 + weight: 1 + - nucleusId: -1266532688 + weight: 1 + receivers: + - nucleusId: -1707533328 + nucleusType: + average: 0 + inverse: 0 + exponent: 1 perceptei: - id: 407735232 _name: Boundary @@ -70,6 +85,7 @@ MonoBehaviour: synapses: [] receivers: - nucleusId: 1938577052 + - nucleusId: 1641120128 nucleusType: Perceptoid average: 0 inverse: 0 @@ -81,6 +97,7 @@ MonoBehaviour: synapses: [] receivers: - nucleusId: 1938577052 + - nucleusId: 1641120128 nucleusType: Perceptoid average: 0 inverse: 0 From 0cee652110aa6e0fb6a4d0bdd978cb6d61d52235 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 17 Dec 2025 09:28:34 +0100 Subject: [PATCH 026/179] Separation/Cohesion curve --- Assets/NanoBrain/Neuroid.cs | 57 +- .../Editor/NanoBrainComponent_Editor.cs | 2 +- .../VisualEditor/Editor/NanoBrainInspector.cs | 61 +- Assets/Scenes/Boids/SwarmingBrain.asset | 2526 ++++++++++++++++- 4 files changed, 2611 insertions(+), 35 deletions(-) diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index ac417e7..2ec6156 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -2,6 +2,46 @@ using UnityEngine; [System.Serializable] public class Neuroid : Nucleus { + public enum CurvePresets { + Linear, + Power, + Sqrt, + Reciprocal, + Custom + } + [SerializeField] + private CurvePresets _curvePreset; + public CurvePresets curvePreset { + get { return _curvePreset; } + set { + _curvePreset = value; + this.curve = GenerateCurve(); + } + } + public AnimationCurve curve; + public float curveMax = 1.0f; + + public AnimationCurve GenerateCurve() { + switch (this.curvePreset) { + case CurvePresets.Linear: + this.curveMax = 1; + return Synapse.Presets.Linear(1); + case CurvePresets.Power: + this.curveMax = 1; + return Synapse.Presets.Power(2.0f, 1); + case CurvePresets.Sqrt: + this.curveMax = 1; + return Synapse.Presets.Power(0.5f, 1); + case CurvePresets.Reciprocal: + this.curveMax = 1 / 0.01f * 1; + return Synapse.Presets.Reciprocal(1); + default: + this.curveMax = 1; + //return AnimationCurve.Constant(0, 1, 1); + return this.curve; + } + } + public bool average = false; public bool inverse = false; public float exponent = 1.0f; @@ -16,7 +56,7 @@ public class Neuroid : Nucleus { Debug.LogError("No neuroid network"); } - public Neuroid(string name): base(name) {} + public Neuroid(string name) : base(name) { } public void SetWeight(Neuroid input, float weight) { this.SetWeight((Nucleus)input, weight); @@ -40,17 +80,18 @@ public class Neuroid : Nucleus { Vector3 result = Vector3.zero; //foreach ((Nucleus nucleus, float weight) in this.synapses) { foreach (Synapse synapse in this.synapses) { - Nucleus nucleus = synapse.nucleus; - if (nucleus is Neuroid neuroid && neuroid.isSleeping) + Nucleus synapseNucleus = synapse.nucleus; + if (synapseNucleus is Neuroid neuroid && neuroid.isSleeping) continue; - Vector3 direction = nucleus.outputValue.normalized; - float magnitude = nucleus.outputValue.magnitude; + Vector3 direction = synapseNucleus.outputValue.normalized; + float magnitude = synapseNucleus.outputValue.magnitude; float weight = synapse.weight; - magnitude = weight * Mathf.Pow(magnitude, exponent); - if (inverse && magnitude > 0) - magnitude = 1 / magnitude; + magnitude = weight * curve.Evaluate(synapseNucleus.outputValue.magnitude); + // magnitude = weight * Mathf.Pow(magnitude, exponent); + // if (inverse && magnitude > 0) + // magnitude = 1 / magnitude; result += direction * magnitude; } diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs index 2229cdb..895092f 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs @@ -73,7 +73,7 @@ public class NanoBrainComponent_Editor : Editor { }); if (brain != null) - board.SetGraph(brain, brain.root, inspectorContainer); + board.SetGraph(component.gameObject, brain, brain.root, inspectorContainer); // else // Debug.LogWarning(" No brain!"); diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs index f9ff10a..3b8edd5 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs @@ -63,7 +63,7 @@ public class NanoBrainInspector : Editor { }); if (brain != null) - board.SetGraph(brain, brain.root, inspectorContainer); + board.SetGraph(null, brain, brain.root, inspectorContainer); else Debug.LogWarning(" No brain!"); @@ -75,6 +75,7 @@ public class NanoBrainInspector : Editor { NanoBrainObj brain; SerializedObject serializedBrain; Nucleus currentNucleus; + GameObject gameObject; private List layers = new(); private readonly Dictionary neuroidPositions = new(); @@ -102,7 +103,8 @@ public class NanoBrainInspector : Editor { RegisterCallback(OnMouseUp); } - public void SetGraph(NanoBrainObj brain, Nucleus nucleus, VisualElement inspectorContainer) { + public void SetGraph(GameObject gameObject, NanoBrainObj brain, Nucleus nucleus, VisualElement inspectorContainer) { + this.gameObject = gameObject; this.brain = brain; if (Application.isPlaying == false) this.serializedBrain = new SerializedObject(brain); @@ -398,31 +400,45 @@ public class NanoBrainInspector : Editor { this.currentNucleus.name = EditorGUILayout.TextField(this.currentNucleus.name); if (this.currentNucleus is Perceptoid currentPerceptoid) currentPerceptoid.thingType = EditorGUILayout.IntField("Thing Type", currentPerceptoid.thingType); - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.LabelField("Output Value", GUILayout.Width(100)); - EditorGUILayout.Vector3Field(GUIContent.none, this.currentNucleus.outputValue); - EditorGUILayout.EndHorizontal(); - if (this.currentNucleus.synapses.Count > 0) { + if (this.currentNucleus is Neuroid neuroid) { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Activation Curve", GUILayout.Width(150)); + if (neuroid.curveMax > 0) + EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, 0, 1, neuroid.curveMax)); + else + EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, neuroid.curveMax, 1, -neuroid.curveMax)); + neuroid.curvePreset = (Neuroid.CurvePresets)EditorGUILayout.EnumPopup(neuroid.curvePreset, GUILayout.Width(100)); + EditorGUILayout.EndHorizontal(); + } + + if (Application.isPlaying) + EditorGUILayout.FloatField("Output", this.currentNucleus.outputValue.magnitude); + else + EditorGUILayout.LabelField(" "); + + if (this.currentNucleus.synapses.Count > 0) { foreach (Synapse synapse in this.currentNucleus.synapses) { if (synapse.nucleus != null) { + EditorGUILayout.Space(); EditorGUI.BeginDisabledGroup(synapse.nucleus.isSleeping); - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.LabelField(synapse.nucleus.name, GUILayout.Width(150)); - EditorGUILayout.Vector3Field(GUIContent.none, synapse.nucleus.outputValue); //, GUILayout.Width(180)); - EditorGUILayout.EndHorizontal(); + if (Application.isPlaying) + EditorGUILayout.FloatField(synapse.nucleus.name, synapse.nucleus.outputValue.magnitude * synapse.weight); + else + EditorGUILayout.LabelField(synapse.nucleus.name); + EditorGUI.indentLevel++; - EditorGUI.BeginChangeCheck(); + // EditorGUI.BeginChangeCheck(); synapse.weight = EditorGUILayout.FloatField("Weight", synapse.weight); - synapse.curvePreset = (Synapse.CurvePresets)EditorGUILayout.EnumPopup("Preset", synapse.curvePreset); - if (EditorGUI.EndChangeCheck()) { - synapse.curve = synapse.GenerateCurve(); - } - if (synapse.curveMax > 0) - EditorGUILayout.CurveField("Curve", synapse.curve, Color.cyan, new Rect(0, 0, 1, synapse.curveMax)); - else - EditorGUILayout.CurveField("Curve", synapse.curve, Color.cyan, new Rect(0, synapse.curveMax, 1, -synapse.curveMax)); + // synapse.curvePreset = (Synapse.CurvePresets)EditorGUILayout.EnumPopup("Preset", synapse.curvePreset); + // if (EditorGUI.EndChangeCheck()) { + // synapse.curve = synapse.GenerateCurve(); + // } + // if (synapse.curveMax > 0) + // EditorGUILayout.CurveField("Curve", synapse.curve, Color.cyan, new Rect(0, 0, 1, synapse.curveMax)); + // else + // EditorGUILayout.CurveField("Curve", synapse.curve, Color.cyan, new Rect(0, synapse.curveMax, 1, -synapse.curveMax)); EditorGUI.indentLevel--; EditorGUI.EndDisabledGroup(); } @@ -438,6 +454,11 @@ public class NanoBrainInspector : Editor { ConnectNucleus(this.currentNucleus); DisconnectNucleus(this.currentNucleus); + + if (this.gameObject != null) { + Vector3 worldVector = this.gameObject.transform.TransformVector(this.currentNucleus.outputValue); + Debug.DrawRay(this.gameObject.transform.position, worldVector, Color.yellow ); + } }); inspectorContainer.Add(container); diff --git a/Assets/Scenes/Boids/SwarmingBrain.asset b/Assets/Scenes/Boids/SwarmingBrain.asset index 0784a70..6264b47 100644 --- a/Assets/Scenes/Boids/SwarmingBrain.asset +++ b/Assets/Scenes/Boids/SwarmingBrain.asset @@ -21,13 +21,1251 @@ MonoBehaviour: _name: Root synapses: - nucleusId: -112538112 - weight: 1 + weight: -1 + curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: -10 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: -10 + inSlope: -10 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: -10 - nucleusId: 1938577052 - weight: 10 + weight: 0 + curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 10 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 10 + inSlope: 10 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 10 - nucleusId: 1641120128 - weight: -5 + weight: 0 + curvePreset: 3 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.001 + value: 10000 + inSlope: 0 + outSlope: -1127886.4 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.008866142 + value: 1127.8864 + inSlope: -1127886.4 + outSlope: -67407.8 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.016732283 + value: 597.6471 + inSlope: -67407.8 + outSlope: -24296.154 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.024598425 + value: 406.5301 + inSlope: -24296.154 + outSlope: -12522.27 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.032464568 + value: 308.02814 + inSlope: -12522.27 + outSlope: -7637.5586 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.040330708 + value: 247.95003 + inSlope: -7637.5586 + outSlope: -5144.5273 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.04819685 + value: 207.48245 + inSlope: -5144.5273 + outSlope: -3700.881 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.056062993 + value: 178.37079 + inSlope: -3700.881 + outSlope: -2790.134 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.06392913 + value: 156.4232 + inSlope: -2790.134 + outSlope: -2178.739 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.07179528 + value: 139.28493 + inSlope: -2178.739 + outSlope: -1748.4618 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.079661414 + value: 125.53129 + inSlope: -1748.4618 + outSlope: -1434.1919 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.087527566 + value: 114.24972 + inSlope: -1434.1919 + outSlope: -1197.6652 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.0953937 + value: 104.82872 + inSlope: -1197.6652 + outSlope: -1015.1933 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.10325985 + value: 96.84306 + inSlope: -1015.1933 + outSlope: -871.471 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.11112598 + value: 89.98795 + inSlope: -871.471 + outSlope: -756.2516 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.11899213 + value: 84.03917 + inSlope: -756.2516 + outSlope: -662.46454 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.12685826 + value: 78.82813 + inSlope: -662.46454 + outSlope: -585.10645 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.13472441 + value: 74.2256 + inSlope: -585.10645 + outSlope: -520.55066 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.14259055 + value: 70.130875 + inSlope: -520.55066 + outSlope: -466.11972 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.1504567 + value: 66.46431 + inSlope: -466.11972 + outSlope: -419.80298 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.15832284 + value: 63.16208 + inSlope: -419.80298 + outSlope: -380.06146 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.16618897 + value: 60.172466 + inSlope: -380.06146 + outSlope: -345.70953 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.17405513 + value: 57.45306 + inSlope: -345.70953 + outSlope: -315.81256 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.18192126 + value: 54.968838 + inSlope: -315.81256 + outSlope: -289.6338 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.1897874 + value: 52.690536 + inSlope: -289.6338 + outSlope: -266.5802 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.19765353 + value: 50.593582 + inSlope: -266.5802 + outSlope: -246.17393 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.20551969 + value: 48.65714 + inSlope: -246.17393 + outSlope: -228.02412 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.21338584 + value: 46.86347 + inSlope: -228.02412 + outSlope: -211.81067 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.22125196 + value: 45.19734 + inSlope: -211.81067 + outSlope: -197.26657 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.22911811 + value: 43.64561 + inSlope: -197.26657 + outSlope: -184.17094 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.23698425 + value: 42.196896 + inSlope: -184.17094 + outSlope: -172.33716 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2448504 + value: 40.841267 + inSlope: -172.33716 + outSlope: -161.60907 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.25271654 + value: 39.570026 + inSlope: -161.60907 + outSlope: -151.85233 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2605827 + value: 38.375534 + inSlope: -151.85233 + outSlope: -142.95256 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2684488 + value: 37.251053 + inSlope: -142.95256 + outSlope: -134.81406 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.27631494 + value: 36.190586 + inSlope: -134.81406 + outSlope: -127.35017 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.28418112 + value: 35.188828 + inSlope: -127.35017 + outSlope: -120.49053 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.29204726 + value: 34.24103 + inSlope: -120.49053 + outSlope: -114.16967 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2999134 + value: 33.342957 + inSlope: -114.16967 + outSlope: -108.333694 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.30777952 + value: 32.49079 + inSlope: -108.333694 + outSlope: -102.93456 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.31564566 + value: 31.681093 + inSlope: -102.93456 + outSlope: -97.92865 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.3235118 + value: 30.910772 + inSlope: -97.92865 + outSlope: -93.27943 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.33137795 + value: 30.177023 + inSlope: -93.27943 + outSlope: -88.95375 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.33924407 + value: 29.477303 + inSlope: -88.95375 + outSlope: -84.921936 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.34711024 + value: 28.809292 + inSlope: -84.921936 + outSlope: -81.15831 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.3549764 + value: 28.170889 + inSlope: -81.15831 + outSlope: -77.639496 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.36284253 + value: 27.560165 + inSlope: -77.639496 + outSlope: -74.3445 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.37070867 + value: 26.97536 + inSlope: -74.3445 + outSlope: -71.25514 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.3785748 + value: 26.41486 + inSlope: -71.25514 + outSlope: -68.35413 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.38644093 + value: 25.877176 + inSlope: -68.35413 + outSlope: -65.627014 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.39430708 + value: 25.360945 + inSlope: -65.627014 + outSlope: -63.05968 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.40217322 + value: 24.864908 + inSlope: -63.05968 + outSlope: -60.64027 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4100394 + value: 24.387901 + inSlope: -60.64027 + outSlope: -58.35757 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4179055 + value: 23.928854 + inSlope: -58.35757 + outSlope: -56.20101 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.42577165 + value: 23.486769 + inSlope: -56.20101 + outSlope: -54.162277 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4336378 + value: 23.06072 + inSlope: -54.162277 + outSlope: -52.23217 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.44150394 + value: 22.649855 + inSlope: -52.23217 + outSlope: -50.40366 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4493701 + value: 22.253372 + inSlope: -50.40366 + outSlope: -48.669174 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4572362 + value: 21.870535 + inSlope: -48.669174 + outSlope: -47.023064 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.46510234 + value: 21.500645 + inSlope: -47.023064 + outSlope: -45.458923 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.47296852 + value: 21.143057 + inSlope: -45.458923 + outSlope: -43.971752 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.48083466 + value: 20.797169 + inSlope: -43.971752 + outSlope: -42.555935 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4887008 + value: 20.462418 + inSlope: -42.555935 + outSlope: -41.207684 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.49656692 + value: 20.138273 + inSlope: -41.207684 + outSlope: -39.92274 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5044331 + value: 19.824234 + inSlope: -39.92274 + outSlope: -38.696503 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5122992 + value: 19.519844 + inSlope: -38.696503 + outSlope: -37.526264 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5201653 + value: 19.224657 + inSlope: -37.526264 + outSlope: -36.408207 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.52803147 + value: 18.938265 + inSlope: -36.408207 + outSlope: -35.339375 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5358976 + value: 18.66028 + inSlope: -35.339375 + outSlope: -34.316856 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.54376376 + value: 18.390339 + inSlope: -34.316856 + outSlope: -33.338223 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5516299 + value: 18.128096 + inSlope: -33.338223 + outSlope: -32.40057 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.55949605 + value: 17.873228 + inSlope: -32.40057 + outSlope: -31.502443 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.56736225 + value: 17.625423 + inSlope: -31.502443 + outSlope: -30.640682 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5752284 + value: 17.3844 + inSlope: -30.640682 + outSlope: -29.814081 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.58309454 + value: 17.149878 + inSlope: -29.814081 + outSlope: -29.020437 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5909606 + value: 16.9216 + inSlope: -29.020437 + outSlope: -28.257874 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.59882677 + value: 16.69932 + inSlope: -28.257874 + outSlope: -27.525112 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6066929 + value: 16.482803 + inSlope: -27.525112 + outSlope: -26.820477 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.61455905 + value: 16.27183 + inSlope: -26.820477 + outSlope: -26.142757 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6224252 + value: 16.066187 + inSlope: -26.142757 + outSlope: -25.490013 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.63029134 + value: 15.865679 + inSlope: -25.490013 + outSlope: -24.861637 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6381575 + value: 15.670114 + inSlope: -24.861637 + outSlope: -24.256296 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.64602363 + value: 15.47931 + inSlope: -24.256296 + outSlope: -23.672657 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6538898 + value: 15.2930975 + inSlope: -23.672657 + outSlope: -23.109926 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.66175586 + value: 15.111313 + inSlope: -23.109926 + outSlope: -22.566847 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.669622 + value: 14.933799 + inSlope: -22.566847 + outSlope: -22.042978 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.67748815 + value: 14.760406 + inSlope: -22.042978 + outSlope: -21.53681 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6853543 + value: 14.590994 + inSlope: -21.53681 + outSlope: -21.048183 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6932205 + value: 14.425425 + inSlope: -21.048183 + outSlope: -20.575758 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.70108664 + value: 14.263573 + inSlope: -20.575758 + outSlope: -20.119299 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7089528 + value: 14.105311 + inSlope: -20.119299 + outSlope: -19.67763 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7168189 + value: 13.950524 + inSlope: -19.67763 + outSlope: -19.250507 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7246851 + value: 13.799097 + inSlope: -19.250507 + outSlope: -18.836966 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7325512 + value: 13.650923 + inSlope: -18.836966 + outSlope: -18.436777 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7404173 + value: 13.5058975 + inSlope: -18.436777 + outSlope: -18.049162 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.74828345 + value: 13.36392 + inSlope: -18.049162 + outSlope: -17.673689 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7561496 + value: 13.224896 + inSlope: -17.673689 + outSlope: -17.309732 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.76401573 + value: 13.088736 + inSlope: -17.309732 + outSlope: -16.95693 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7718819 + value: 12.95535 + inSlope: -16.95693 + outSlope: -16.614798 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.779748 + value: 12.824656 + inSlope: -16.614798 + outSlope: -16.282848 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.78761417 + value: 12.696572 + inSlope: -16.282848 + outSlope: -15.960961 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7954803 + value: 12.571021 + inSlope: -15.960961 + outSlope: -15.648289 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.80334646 + value: 12.447929 + inSlope: -15.648289 + outSlope: -15.344826 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.81121254 + value: 12.327226 + inSlope: -15.344826 + outSlope: -15.050109 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.81907874 + value: 12.208838 + inSlope: -15.050109 + outSlope: -14.763738 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8269449 + value: 12.092705 + inSlope: -14.763738 + outSlope: -14.485619 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.83481103 + value: 11.978759 + inSlope: -14.485619 + outSlope: -14.215137 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8426772 + value: 11.8669405 + inSlope: -14.215137 + outSlope: -13.952171 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8505433 + value: 11.757191 + inSlope: -13.952171 + outSlope: -13.696481 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.85840946 + value: 11.649452 + inSlope: -13.696481 + outSlope: -13.447701 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8662756 + value: 11.543671 + inSlope: -13.447701 + outSlope: -13.20571 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.87414175 + value: 11.439793 + inSlope: -13.20571 + outSlope: -12.970266 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8820079 + value: 11.337767 + inSlope: -12.970266 + outSlope: -12.74086 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.889874 + value: 11.237546 + inSlope: -12.74086 + outSlope: -12.517565 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8977401 + value: 11.139081 + inSlope: -12.517565 + outSlope: -12.300185 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.90560627 + value: 11.042326 + inSlope: -12.300185 + outSlope: -12.088262 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9134724 + value: 10.947238 + inSlope: -12.088262 + outSlope: -11.881914 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.92133856 + value: 10.853773 + inSlope: -11.881914 + outSlope: -11.680659 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9292047 + value: 10.761891 + inSlope: -11.680659 + outSlope: -11.484618 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.93707085 + value: 10.671552 + inSlope: -11.484618 + outSlope: -11.293341 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.94493705 + value: 10.582716 + inSlope: -11.293341 + outSlope: -11.106962 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9528032 + value: 10.495347 + inSlope: -11.106962 + outSlope: -10.925105 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.96066934 + value: 10.409409 + inSlope: -10.925105 + outSlope: -10.747573 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9685354 + value: 10.324867 + inSlope: -10.747573 + outSlope: -10.574365 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.97640157 + value: 10.241688 + inSlope: -10.574365 + outSlope: -10.405358 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9842677 + value: 10.159838 + inSlope: -10.405358 + outSlope: -10.240476 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.99213386 + value: 10.079285 + inSlope: -10.240476 + outSlope: -10.079229 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 10 + inSlope: -10.079229 + outSlope: 0 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1000 receivers: [] nucleusType: + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 average: 0 inverse: 0 exponent: 1 @@ -35,10 +1273,44 @@ MonoBehaviour: _name: Avoidance synapses: - nucleusId: 407735232 - weight: -1 + weight: 1 + curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 0 receivers: - nucleusId: -1707533328 nucleusType: + _curvePreset: 4 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: -0.9985466 + outSlope: -0.9985466 + tangentMode: 34 + weightedMode: 0 + inWeight: 0 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0.0014533997 + inSlope: -0.9985466 + outSlope: -0.9985466 + tangentMode: 34 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 average: 0 inverse: 0 exponent: 1 @@ -47,11 +1319,53 @@ MonoBehaviour: synapses: - nucleusId: -1420275136 weight: 1 + curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 0 - nucleusId: -1266532688 weight: 1 + curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 0 receivers: - nucleusId: -1707533328 nucleusType: + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 average: 0 inverse: 0 exponent: 1 @@ -59,12 +1373,1188 @@ MonoBehaviour: _name: Separation synapses: - nucleusId: -1420275136 - weight: 1 + weight: 0.1 + curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 0 - nucleusId: -1266532688 - weight: 1 + weight: 0.1 + curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 0 receivers: - nucleusId: -1707533328 nucleusType: + _curvePreset: 3 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.001 + value: 999.99994 + inSlope: 0 + outSlope: -112788.63 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.008866142 + value: 112.788635 + inSlope: -112788.63 + outSlope: -6740.78 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.016732283 + value: 59.76471 + inSlope: -6740.78 + outSlope: -2429.6155 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.024598425 + value: 40.653008 + inSlope: -2429.6155 + outSlope: -1252.2269 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.032464568 + value: 30.802813 + inSlope: -1252.2269 + outSlope: -763.7558 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.040330708 + value: 24.795002 + inSlope: -763.7558 + outSlope: -514.45264 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.04819685 + value: 20.748245 + inSlope: -514.45264 + outSlope: -370.0882 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.056062993 + value: 17.837078 + inSlope: -370.0882 + outSlope: -279.01324 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.06392913 + value: 15.642321 + inSlope: -279.01324 + outSlope: -217.87398 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.07179528 + value: 13.928493 + inSlope: -217.87398 + outSlope: -174.8461 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.079661414 + value: 12.553129 + inSlope: -174.8461 + outSlope: -143.41913 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.087527566 + value: 11.424973 + inSlope: -143.41913 + outSlope: -119.76661 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.0953937 + value: 10.482872 + inSlope: -119.76661 + outSlope: -101.519356 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.10325985 + value: 9.684306 + inSlope: -101.519356 + outSlope: -87.14706 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.11112598 + value: 8.9987955 + inSlope: -87.14706 + outSlope: -75.62513 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.11899213 + value: 8.403917 + inSlope: -75.62513 + outSlope: -66.24654 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.12685826 + value: 7.882813 + inSlope: -66.24654 + outSlope: -58.510654 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.13472441 + value: 7.4225597 + inSlope: -58.510654 + outSlope: -52.055042 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.14259055 + value: 7.0130873 + inSlope: -52.055042 + outSlope: -46.612007 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.1504567 + value: 6.6464305 + inSlope: -46.612007 + outSlope: -41.98024 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.15832284 + value: 6.316208 + inSlope: -41.98024 + outSlope: -38.006134 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.16618897 + value: 6.0172467 + inSlope: -38.006134 + outSlope: -34.570965 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.17405513 + value: 5.745306 + inSlope: -34.570965 + outSlope: -31.581244 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.18192126 + value: 5.496884 + inSlope: -31.581244 + outSlope: -28.963417 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.1897874 + value: 5.2690535 + inSlope: -28.963417 + outSlope: -26.658009 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.19765353 + value: 5.059358 + inSlope: -26.658009 + outSlope: -24.617418 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.20551969 + value: 4.8657136 + inSlope: -24.617418 + outSlope: -22.802412 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.21338584 + value: 4.6863465 + inSlope: -22.802412 + outSlope: -21.181019 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.22125196 + value: 4.519734 + inSlope: -21.181019 + outSlope: -19.72667 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.22911811 + value: 4.364561 + inSlope: -19.72667 + outSlope: -18.417059 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.23698425 + value: 4.21969 + inSlope: -18.417059 + outSlope: -17.233776 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2448504 + value: 4.0841265 + inSlope: -17.233776 + outSlope: -16.160883 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.25271654 + value: 3.9570026 + inSlope: -16.160883 + outSlope: -15.185221 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2605827 + value: 3.8375535 + inSlope: -15.185221 + outSlope: -14.295299 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2684488 + value: 3.725105 + inSlope: -14.295299 + outSlope: -13.481375 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.27631494 + value: 3.6190586 + inSlope: -13.481375 + outSlope: -12.735047 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.28418112 + value: 3.5188825 + inSlope: -12.735047 + outSlope: -12.04901 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.29204726 + value: 3.4241033 + inSlope: -12.04901 + outSlope: -11.416967 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2999134 + value: 3.3342957 + inSlope: -11.416967 + outSlope: -10.8334 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.30777952 + value: 3.249079 + inSlope: -10.8334 + outSlope: -10.293426 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.31564566 + value: 3.1681094 + inSlope: -10.293426 + outSlope: -9.792865 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.3235118 + value: 3.0910773 + inSlope: -9.792865 + outSlope: -9.327949 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.33137795 + value: 3.0177023 + inSlope: -9.327949 + outSlope: -8.895375 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.33924407 + value: 2.9477303 + inSlope: -8.895375 + outSlope: -8.492224 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.34711024 + value: 2.880929 + inSlope: -8.492224 + outSlope: -8.115812 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.3549764 + value: 2.8170888 + inSlope: -8.115812 + outSlope: -7.76395 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.36284253 + value: 2.7560165 + inSlope: -7.76395 + outSlope: -7.434456 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.37070867 + value: 2.697536 + inSlope: -7.434456 + outSlope: -7.1255083 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.3785748 + value: 2.641486 + inSlope: -7.1255083 + outSlope: -6.8354197 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.38644093 + value: 2.5877175 + inSlope: -6.8354197 + outSlope: -6.562695 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.39430708 + value: 2.5360944 + inSlope: -6.562695 + outSlope: -6.305974 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.40217322 + value: 2.4864907 + inSlope: -6.305974 + outSlope: -6.064021 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4100394 + value: 2.43879 + inSlope: -6.064021 + outSlope: -5.835745 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4179055 + value: 2.3928854 + inSlope: -5.835745 + outSlope: -5.6201315 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.42577165 + value: 2.3486767 + inSlope: -5.6201315 + outSlope: -5.4162097 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4336378 + value: 2.306072 + inSlope: -5.4162097 + outSlope: -5.223229 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.44150394 + value: 2.2649853 + inSlope: -5.223229 + outSlope: -5.040342 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4493701 + value: 2.2253373 + inSlope: -5.040342 + outSlope: -4.8669295 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4572362 + value: 2.1870534 + inSlope: -4.8669295 + outSlope: -4.7023005 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.46510234 + value: 2.1500645 + inSlope: -4.7023005 + outSlope: -4.5458865 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.47296852 + value: 2.1143057 + inSlope: -4.5458865 + outSlope: -4.3971753 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.48083466 + value: 2.079717 + inSlope: -4.3971753 + outSlope: -4.2555995 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4887008 + value: 2.0462418 + inSlope: -4.2555995 + outSlope: -4.1207685 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.49656692 + value: 2.0138273 + inSlope: -4.1207685 + outSlope: -3.9922712 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5044331 + value: 1.9824234 + inSlope: -3.9922712 + outSlope: -3.8696532 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5122992 + value: 1.9519844 + inSlope: -3.8696532 + outSlope: -3.7526293 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5201653 + value: 1.9224657 + inSlope: -3.7526293 + outSlope: -3.6408176 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.52803147 + value: 1.8938265 + inSlope: -3.6408176 + outSlope: -3.5339315 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5358976 + value: 1.8660281 + inSlope: -3.5339315 + outSlope: -3.4316826 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.54376376 + value: 1.839034 + inSlope: -3.4316826 + outSlope: -3.3338284 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5516299 + value: 1.8128096 + inSlope: -3.3338284 + outSlope: -3.240066 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.55949605 + value: 1.7873228 + inSlope: -3.240066 + outSlope: -3.1502352 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.56736225 + value: 1.7625424 + inSlope: -3.1502352 + outSlope: -3.0640743 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5752284 + value: 1.7384399 + inSlope: -3.0640743 + outSlope: -2.9814053 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.58309454 + value: 1.7149878 + inSlope: -2.9814053 + outSlope: -2.9020314 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5909606 + value: 1.6921601 + inSlope: -2.9020314 + outSlope: -2.8257964 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.59882677 + value: 1.669932 + inSlope: -2.8257964 + outSlope: -2.7525082 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6066929 + value: 1.6482804 + inSlope: -2.7525082 + outSlope: -2.6820538 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.61455905 + value: 1.627183 + inSlope: -2.6820538 + outSlope: -2.6142666 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6224252 + value: 1.6066188 + inSlope: -2.6142666 + outSlope: -2.5490105 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.63029134 + value: 1.5865679 + inSlope: -2.5490105 + outSlope: -2.4861636 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6381575 + value: 1.5670114 + inSlope: -2.4861636 + outSlope: -2.4256358 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.64602363 + value: 1.547931 + inSlope: -2.4256358 + outSlope: -2.3672597 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6538898 + value: 1.5293097 + inSlope: -2.3672597 + outSlope: -2.3109925 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.66175586 + value: 1.5111313 + inSlope: -2.3109925 + outSlope: -2.2566907 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.669622 + value: 1.4933798 + inSlope: -2.2566907 + outSlope: -2.2042859 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.67748815 + value: 1.4760406 + inSlope: -2.2042859 + outSlope: -2.1536992 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6853543 + value: 1.4590993 + inSlope: -2.1536992 + outSlope: -2.1048093 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6932205 + value: 1.4425424 + inSlope: -2.1048093 + outSlope: -2.0575728 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.70108664 + value: 1.4263573 + inSlope: -2.0575728 + outSlope: -2.011927 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7089528 + value: 1.4105312 + inSlope: -2.011927 + outSlope: -1.9677659 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7168189 + value: 1.3950524 + inSlope: -1.9677659 + outSlope: -1.9250447 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7246851 + value: 1.3799098 + inSlope: -1.9250447 + outSlope: -1.8837026 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7325512 + value: 1.3650923 + inSlope: -1.8837026 + outSlope: -1.8436778 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7404173 + value: 1.3505898 + inSlope: -1.8436778 + outSlope: -1.8049132 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.74828345 + value: 1.336392 + inSlope: -1.8049132 + outSlope: -1.7673749 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7561496 + value: 1.3224896 + inSlope: -1.7673749 + outSlope: -1.7309732 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.76401573 + value: 1.3088735 + inSlope: -1.7309732 + outSlope: -1.695693 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7718819 + value: 1.295535 + inSlope: -1.695693 + outSlope: -1.6614736 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.779748 + value: 1.2824656 + inSlope: -1.6614736 + outSlope: -1.6282848 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.78761417 + value: 1.2696573 + inSlope: -1.6282848 + outSlope: -1.5960962 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7954803 + value: 1.2571021 + inSlope: -1.5960962 + outSlope: -1.564832 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.80334646 + value: 1.2447929 + inSlope: -1.564832 + outSlope: -1.5344887 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.81121254 + value: 1.2327225 + inSlope: -1.5344887 + outSlope: -1.5050048 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.81907874 + value: 1.2208838 + inSlope: -1.5050048 + outSlope: -1.4763738 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8269449 + value: 1.2092705 + inSlope: -1.4763738 + outSlope: -1.4485649 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.83481103 + value: 1.1978759 + inSlope: -1.4485649 + outSlope: -1.4215137 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8426772 + value: 1.186694 + inSlope: -1.4215137 + outSlope: -1.3952202 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8505433 + value: 1.175719 + inSlope: -1.3952202 + outSlope: -1.369639 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.85840946 + value: 1.1649452 + inSlope: -1.369639 + outSlope: -1.3447852 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8662756 + value: 1.154367 + inSlope: -1.3447852 + outSlope: -1.320568 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.87414175 + value: 1.1439792 + inSlope: -1.320568 + outSlope: -1.2970176 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8820079 + value: 1.1337767 + inSlope: -1.2970176 + outSlope: -1.2740829 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.889874 + value: 1.1237546 + inSlope: -1.2740829 + outSlope: -1.2517655 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8977401 + value: 1.113908 + inSlope: -1.2517655 + outSlope: -1.2300034 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.90560627 + value: 1.1042327 + inSlope: -1.2300034 + outSlope: -1.2088321 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9134724 + value: 1.0947238 + inSlope: -1.2088321 + outSlope: -1.1881914 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.92133856 + value: 1.0853773 + inSlope: -1.1881914 + outSlope: -1.1680659 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9292047 + value: 1.0761892 + inSlope: -1.1680659 + outSlope: -1.1484709 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.93707085 + value: 1.0671551 + inSlope: -1.1484709 + outSlope: -1.1293371 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.94493705 + value: 1.0582715 + inSlope: -1.1293371 + outSlope: -1.1106901 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9528032 + value: 1.0495347 + inSlope: -1.1106901 + outSlope: -1.0925045 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.96066934 + value: 1.0409409 + inSlope: -1.0925045 + outSlope: -1.0747513 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9685354 + value: 1.0324868 + inSlope: -1.0747513 + outSlope: -1.0574516 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.97640157 + value: 1.0241687 + inSlope: -1.0574516 + outSlope: -1.0405389 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9842677 + value: 1.0159837 + inSlope: -1.0405389 + outSlope: -1.0240355 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.99213386 + value: 1.0079285 + inSlope: -1.0240355 + outSlope: -1.0079259 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: -1.0079259 + outSlope: 0 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 100 average: 0 inverse: 0 exponent: 1 @@ -75,6 +2565,14 @@ MonoBehaviour: receivers: - nucleusId: -112538112 nucleusType: Perceptoid + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 0 average: 0 inverse: 0 exponent: 1 @@ -87,6 +2585,14 @@ MonoBehaviour: - nucleusId: 1938577052 - nucleusId: 1641120128 nucleusType: Perceptoid + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 0 average: 0 inverse: 0 exponent: 1 @@ -99,6 +2605,14 @@ MonoBehaviour: - nucleusId: 1938577052 - nucleusId: 1641120128 nucleusType: Perceptoid + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 0 average: 0 inverse: 0 exponent: 1 From 65359ecbfaa5dfe20ccd8cf768ae08c75995beb9 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 17 Dec 2025 12:41:25 +0100 Subject: [PATCH 027/179] Needs tuning --- Assets/NanoBrain/Nucleus.cs | 8 +- Assets/NanoBrain/Perceptoid.cs | 24 +- Assets/NanoBrain/Receptor.cs | 2 +- .../VisualEditor/Editor/NanoBrainInspector.cs | 38 +- Assets/NanoBrain/VisualEditor/NanoBrainObj.cs | 16 +- Assets/Scenes/Boids/Boids.unity | 8 +- Assets/Scenes/Boids/RoamingBrain.asset | 58 + Assets/Scenes/Boids/Scripts/Boid.cs | 5 +- Assets/Scenes/Boids/SwarmingBrain.asset | 2021 +++++++---------- 9 files changed, 973 insertions(+), 1207 deletions(-) diff --git a/Assets/NanoBrain/Nucleus.cs b/Assets/NanoBrain/Nucleus.cs index 340d3c0..33e8493 100644 --- a/Assets/NanoBrain/Nucleus.cs +++ b/Assets/NanoBrain/Nucleus.cs @@ -61,7 +61,7 @@ public class Nucleus { #region Runtime state (not serialized) - public NanoBrainObj brain { get; protected set; } + public NanoBrainObj brain { get; set; } public virtual Vector3 outputValue { get; set; } @@ -110,8 +110,10 @@ public class Nucleus { receiver.nucleus.synapses.RemoveAll(s => s.nucleus == nucleus); } - nucleus.brain.nuclei.RemoveAll(n => n == nucleus); - nucleus.brain.GarbageCollection(); + if (nucleus.brain != null) { + nucleus.brain.nuclei.RemoveAll(n => n == nucleus); + nucleus.brain.GarbageCollection(); + } } public void GetInputFrom(Nucleus input, float weight = 1.0f) { diff --git a/Assets/NanoBrain/Perceptoid.cs b/Assets/NanoBrain/Perceptoid.cs index 02b3ccd..b6be740 100644 --- a/Assets/NanoBrain/Perceptoid.cs +++ b/Assets/NanoBrain/Perceptoid.cs @@ -123,19 +123,19 @@ public class Perceptoid : Neuroid { public void UpdateState(int thingId, Vector3 receptorValue) { this.thingId = thingId; Vector3 result = receptorValue; - foreach (Synapse synapse in this.synapses) { - Nucleus nucleus = synapse.nucleus; - float weight = synapse.weight; - Vector3 direction = nucleus.outputValue.normalized; - float magnitude = nucleus.outputValue.magnitude; + // foreach (Synapse synapse in this.synapses) { + // Nucleus nucleus = synapse.nucleus; + // float weight = synapse.weight; + // Vector3 direction = nucleus.outputValue.normalized; + // float magnitude = nucleus.outputValue.magnitude; - magnitude = weight * Mathf.Pow(magnitude, exponent); - if (inverse) - magnitude = 1 / magnitude; - result += direction * magnitude; - } - if (average && this.synapses.Count > 0) - result /= this.synapses.Count + 1; + // magnitude = weight * Mathf.Pow(magnitude, exponent); + // if (inverse) + // magnitude = 1 / magnitude; + // result += direction * magnitude; + // } + // if (average && this.synapses.Count > 0) + // result /= this.synapses.Count + 1; this.outputValue = result; foreach (Receiver receiver in this.receivers) diff --git a/Assets/NanoBrain/Receptor.cs b/Assets/NanoBrain/Receptor.cs index 4c0f770..9f5fbce 100644 --- a/Assets/NanoBrain/Receptor.cs +++ b/Assets/NanoBrain/Receptor.cs @@ -40,7 +40,7 @@ public class Receptor { Debug.Log("No perceptoid selected, stimulus is ignored"); return; } - Debug.Log($"Stimulus {thingId} {selectedPerceptoid.thingId}"); + //Debug.Log($"Stimulus {thingId} {selectedPerceptoid.thingId}"); selectedPerceptoid.UpdateState(this.thingId, this.localPosition); } } \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs index 3b8edd5..43a2af7 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs @@ -228,7 +228,7 @@ public class NanoBrainInspector : Editor { private void DrawGraph() { float size = 20; - Vector3 position = new(200, 210, 0); + Vector3 position = new(150, 210, 0); DrawReceivers(this.currentNucleus, position, size); DrawSynapses(this.currentNucleus, position, size); @@ -263,7 +263,7 @@ public class NanoBrainInspector : Editor { if (receiverNucleus == null) continue; - Vector3 pos = new(100, margin + row * spacing, 0.0f); + Vector3 pos = new(50, margin + row * spacing, 0.0f); Handles.color = Color.white; Handles.DrawLine(parentPos, pos); @@ -294,7 +294,7 @@ public class NanoBrainInspector : Editor { foreach (Synapse receiver in nucleus.synapses) { Nucleus receiverNucleus = receiver.nucleus; - Vector3 pos = new(300, margin + row * spacing, 0.0f); + Vector3 pos = new(250, margin + row * spacing, 0.0f); Handles.color = Color.white; Handles.DrawLine(parentPos, pos); @@ -400,8 +400,7 @@ public class NanoBrainInspector : Editor { this.currentNucleus.name = EditorGUILayout.TextField(this.currentNucleus.name); if (this.currentNucleus is Perceptoid currentPerceptoid) currentPerceptoid.thingType = EditorGUILayout.IntField("Thing Type", currentPerceptoid.thingType); - - if (this.currentNucleus is Neuroid neuroid) { + else if (this.currentNucleus is Neuroid neuroid) { EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Activation Curve", GUILayout.Width(150)); if (neuroid.curveMax > 0) @@ -457,7 +456,7 @@ public class NanoBrainInspector : Editor { if (this.gameObject != null) { Vector3 worldVector = this.gameObject.transform.TransformVector(this.currentNucleus.outputValue); - Debug.DrawRay(this.gameObject.transform.position, worldVector, Color.yellow ); + Debug.DrawRay(this.gameObject.transform.position, worldVector, Color.yellow); } }); @@ -467,11 +466,15 @@ public class NanoBrainInspector : Editor { protected virtual void AddInputNeuron(Nucleus nucleus) { Neuroid newNeuroid = new(this.brain, "New neuron"); newNeuroid.AddReceiver(nucleus); + this.currentNucleus = newNeuroid; BuildLayers(); } protected virtual void DeleteNeuron(Nucleus nucleus) { - this.currentNucleus = nucleus.brain.root; + if (nucleus == null) + return; + if (nucleus.brain != null) + this.currentNucleus = nucleus.brain.root; foreach (Receiver receiver in nucleus.receivers) { if (receiver.nucleus != null) { this.currentNucleus = receiver.nucleus; @@ -485,18 +488,29 @@ public class NanoBrainInspector : Editor { protected virtual void AddPerceptoid(Nucleus nucleus) { Perceptoid newPerceptoid = new(this.brain, 0, "New Perceptoid"); newPerceptoid.AddReceiver(nucleus); + this.currentNucleus = newPerceptoid; BuildLayers(); } protected virtual void ConnectNucleus(Nucleus nucleus) { if (this.currentNucleus.brain == null) return; - string[] names = this.currentNucleus.brain.perceptei.Select(i => i.name).ToArray(); + + //string[] names = this.currentNucleus.brain.perceptei.Select(i => i.name).ToArray(); + IEnumerable perceptei = this.currentNucleus.brain.perceptei.Select(i => i.name); + IEnumerable nuclei = this.currentNucleus.brain.nuclei.Select(i => i.name); + string[] names = perceptei.Concat(nuclei).ToArray(); int selectedIndex = -1; selectedIndex = EditorGUILayout.Popup("Connect to", selectedIndex, names); - if (selectedIndex >= 0 && selectedIndex < this.currentNucleus.brain.perceptei.Count) { - Nucleus n = this.currentNucleus.brain.perceptei[selectedIndex]; - n.AddReceiver(this.currentNucleus); + if (selectedIndex >= 0) { + if (selectedIndex < perceptei.Count()) { + Nucleus n = this.currentNucleus.brain.perceptei[selectedIndex]; + n.AddReceiver(this.currentNucleus); + } + else { + Nucleus n = this.currentNucleus.brain.nuclei[selectedIndex - perceptei.Count()]; + n.AddReceiver(this.currentNucleus); + } } } @@ -544,7 +558,7 @@ public class NanoBrainInspector : Editor { #region Update private void UpdateLayout(float containerWidth) { - if (containerWidth > 800f) { + if (containerWidth > 700f) { mainContainer.style.flexDirection = FlexDirection.Row; inspectorContainer.style.width = 400; // fixed sidebar width inspectorContainer.style.flexGrow = 0; diff --git a/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs b/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs index 00fc89e..137125a 100644 --- a/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs +++ b/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs @@ -71,13 +71,16 @@ public class NanoBrainObj : ScriptableObject, ISerializationCallbackReceiver { MarkNuclei(visitedNuclei, this.root); Debug.Log($"Garbage collection found {visitedNuclei.Count} Nuclei"); this.nuclei.RemoveAll(nucleus => visitedNuclei.Contains(nucleus) == false); - this.perceptei.RemoveAll(perceptoid => visitedNuclei.Contains(perceptoid) == false); + this.perceptei.RemoveAll(perceptoid => visitedNuclei.Contains(perceptoid) == false); } public void MarkNuclei(HashSet visitedNuclei, Nucleus nucleus) { if (nucleus is null) return; + if (nucleus.brain == null) + nucleus.brain = this; + visitedNuclei.Add(nucleus); if (nucleus.synapses != null) { HashSet visitedSynapses = new(); @@ -89,5 +92,16 @@ public class NanoBrainObj : ScriptableObject, ISerializationCallbackReceiver { } nucleus.synapses.RemoveAll(synapse => visitedSynapses.Contains(synapse) == false); } + if (nucleus.receivers != null) { + HashSet visitedReceivers = new(); + foreach (Receiver receiver in nucleus.receivers) { + if (receiver != null && receiver.nucleus != null) { + visitedReceivers.Add(receiver); + visitedNuclei.Add(receiver.nucleus); + //MarkNuclei(visitedNuclei, receiver.nucleus); + } + } + nucleus.receivers.RemoveAll(receiver => visitedReceivers.Contains(receiver) == false); + } } } \ No newline at end of file diff --git a/Assets/Scenes/Boids/Boids.unity b/Assets/Scenes/Boids/Boids.unity index f0e9d7c..9df0ef9 100644 --- a/Assets/Scenes/Boids/Boids.unity +++ b/Assets/Scenes/Boids/Boids.unity @@ -371,13 +371,13 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 0464906885ae3494f8fd0314719fb2db, type: 3} m_Name: m_EditorClassIdentifier: Assembly-CSharp::SwarmControl - speed: 2 - inertia: 0.5 + speed: 1 + inertia: 0.8 alignmentForce: 2 cohesionForce: 2 avoidanceForce: 1 separationDistance: 0.3 - perceptionDistance: 1 + perceptionDistance: 2 boundaryForce: 5 spaceSize: {x: 10, y: 10, z: 10} boundaryWidth: {x: 1, y: 1, z: 1} @@ -393,7 +393,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec888ca5333d45a438f9f417fa5ce135, type: 3} m_Name: m_EditorClassIdentifier: Assembly-CSharp::SwarmSpawn - count: 30 + count: 100 boidPrefab: {fileID: 8702527964058765413, guid: f9c706268554ce449a8773675b2864b8, type: 3} spawnAreaSize: {x: 0.5, y: 0.5, z: 0.5} minDelay: 0.05 diff --git a/Assets/Scenes/Boids/RoamingBrain.asset b/Assets/Scenes/Boids/RoamingBrain.asset index 02830cf..2ca9ea7 100644 --- a/Assets/Scenes/Boids/RoamingBrain.asset +++ b/Assets/Scenes/Boids/RoamingBrain.asset @@ -22,8 +22,42 @@ MonoBehaviour: synapses: - nucleusId: -112538112 weight: 1 + curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 0 receivers: [] nucleusType: + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 average: 0 inverse: 0 exponent: 1 @@ -32,9 +66,25 @@ MonoBehaviour: synapses: - nucleusId: 407735232 weight: -1 + curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 0 receivers: - nucleusId: -1707533328 nucleusType: + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 0 average: 0 inverse: 0 exponent: 1 @@ -45,6 +95,14 @@ MonoBehaviour: receivers: - nucleusId: -112538112 nucleusType: Perceptoid + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 0 average: 0 inverse: 0 exponent: 1 diff --git a/Assets/Scenes/Boids/Scripts/Boid.cs b/Assets/Scenes/Boids/Scripts/Boid.cs index fe2deea..c2cc778 100644 --- a/Assets/Scenes/Boids/Scripts/Boid.cs +++ b/Assets/Scenes/Boids/Scripts/Boid.cs @@ -39,6 +39,7 @@ public class Boid : MonoBehaviour { continue; Vector3 localPosition = this.transform.InverseTransformPoint(neighbour.transform.position); + localPosition = localPosition.normalized * (localPosition.magnitude - sc.separationDistance); //Debug.DrawRay(this.transform.position, this.transform.TransformDirection(localPosition), Color.magenta); int thingId = neighbour.GetInstanceID(); @@ -61,13 +62,13 @@ public class Boid : MonoBehaviour { this.velocity = this.velocity.normalized * sc.speed; else this.velocity = this.transform.forward * sc.speed; - Debug.DrawRay(this.transform.position, this.velocity, Color.blue); + //Debug.DrawRay(this.transform.position, this.velocity, Color.blue); this.transform.position += this.velocity * Time.deltaTime; if (this.velocity != Vector3.zero) { Quaternion targetRotation = Quaternion.LookRotation(this.velocity); - transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 2f); // Adjust the speed of rotation + transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 5f); // Adjust the speed of rotation } nanoBrain.brain.UpdateNuclei(); diff --git a/Assets/Scenes/Boids/SwarmingBrain.asset b/Assets/Scenes/Boids/SwarmingBrain.asset index 6264b47..9213d2b 100644 --- a/Assets/Scenes/Boids/SwarmingBrain.asset +++ b/Assets/Scenes/Boids/SwarmingBrain.asset @@ -21,7 +21,7 @@ MonoBehaviour: _name: Root synapses: - nucleusId: -112538112 - weight: -1 + weight: -5 curvePreset: 0 curve: serializedVersion: 2 @@ -49,7 +49,7 @@ MonoBehaviour: m_RotationOrder: 4 curveMax: -10 - nucleusId: 1938577052 - weight: 0 + weight: 4 curvePreset: 0 curve: serializedVersion: 2 @@ -77,7 +77,7 @@ MonoBehaviour: m_RotationOrder: 4 curveMax: 10 - nucleusId: 1641120128 - weight: 0 + weight: -10 curvePreset: 3 curve: serializedVersion: 2 @@ -1238,6 +1238,16 @@ MonoBehaviour: m_PostInfinity: 2 m_RotationOrder: 4 curveMax: 1000 + - nucleusId: -1857835930 + weight: 9 + curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 receivers: [] nucleusType: _curvePreset: 0 @@ -1270,7 +1280,7 @@ MonoBehaviour: inverse: 0 exponent: 1 - id: -112538112 - _name: Avoidance + _name: Boundary Avoidance synapses: - nucleusId: 407735232 weight: 1 @@ -1285,27 +1295,27 @@ MonoBehaviour: receivers: - nucleusId: -1707533328 nucleusType: - _curvePreset: 4 + _curvePreset: 0 curve: serializedVersion: 2 m_Curve: - serializedVersion: 3 time: 0 - value: 1 - inSlope: -0.9985466 - outSlope: -0.9985466 - tangentMode: 34 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 weightedMode: 0 inWeight: 0 - outWeight: 0.33333334 + outWeight: 0 - serializedVersion: 3 time: 1 - value: 0.0014533997 - inSlope: -0.9985466 - outSlope: -0.9985466 - tangentMode: 34 + value: 1 + inSlope: 1 + outSlope: 0 + tangentMode: 0 weightedMode: 0 - inWeight: 0.33333334 + inWeight: 0 outWeight: 0 m_PreInfinity: 2 m_PostInfinity: 2 @@ -1317,7 +1327,7 @@ MonoBehaviour: - id: 1938577052 _name: Cohesion synapses: - - nucleusId: -1420275136 + - nucleusId: 1302452224 weight: 1 curvePreset: 0 curve: @@ -1326,8 +1336,8 @@ MonoBehaviour: m_PreInfinity: 2 m_PostInfinity: 2 m_RotationOrder: 4 - curveMax: 0 - - nucleusId: -1266532688 + curveMax: 1 + - nucleusId: 10881140 weight: 1 curvePreset: 0 curve: @@ -1336,7 +1346,47 @@ MonoBehaviour: m_PreInfinity: 2 m_PostInfinity: 2 m_RotationOrder: 4 - curveMax: 0 + curveMax: 1 + - nucleusId: 2020437392 + weight: 1 + curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + - nucleusId: -1530763258 + weight: 1 + curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + - nucleusId: 1790226608 + weight: 1 + curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + - nucleusId: 626548796 + weight: 1 + curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 receivers: - nucleusId: -1707533328 nucleusType: @@ -1372,8 +1422,8 @@ MonoBehaviour: - id: 1641120128 _name: Separation synapses: - - nucleusId: -1420275136 - weight: 0.1 + - nucleusId: 1302452224 + weight: 1 curvePreset: 0 curve: serializedVersion: 2 @@ -1381,9 +1431,9 @@ MonoBehaviour: m_PreInfinity: 2 m_PostInfinity: 2 m_RotationOrder: 4 - curveMax: 0 - - nucleusId: -1266532688 - weight: 0.1 + curveMax: 1 + - nucleusId: 10881140 + weight: 1 curvePreset: 0 curve: serializedVersion: 2 @@ -1391,1170 +1441,711 @@ MonoBehaviour: m_PreInfinity: 2 m_PostInfinity: 2 m_RotationOrder: 4 - curveMax: 0 + curveMax: 1 + - nucleusId: 2020437392 + weight: 1 + curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + - nucleusId: -1530763258 + weight: 1 + curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + - nucleusId: 1790226608 + weight: 1 + curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + - nucleusId: 626548796 + weight: 1 + curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 receivers: - nucleusId: -1707533328 nucleusType: - _curvePreset: 3 + _curvePreset: 2 curve: serializedVersion: 2 m_Curve: - serializedVersion: 3 - time: 0.001 - value: 999.99994 + time: 0 + value: 0 + inSlope: 5.5677648 + outSlope: 5.5677648 + tangentMode: 35 + weightedMode: 0 + inWeight: 0 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.032258064 + value: 0.1796053 + inSlope: 3.937004 + outSlope: 3.937004 + tangentMode: 35 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.06451613 + value: 0.25400025 + inSlope: 2.037943 + outSlope: 2.037943 + tangentMode: 35 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.09677419 + value: 0.3110855 + inSlope: 1.6307607 + outSlope: 1.6307607 + tangentMode: 35 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.12903225 + value: 0.3592106 + inSlope: 1.4031246 + outSlope: 1.4031246 + tangentMode: 35 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.16129032 + value: 0.40160966 + inSlope: 1.2513264 + outSlope: 1.2513264 + tangentMode: 35 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.19354838 + value: 0.43994135 + inSlope: 1.1405103 + outSlope: 1.1405103 + tangentMode: 35 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.22580644 + value: 0.47519097 + inSlope: 1.0549169 + outSlope: 1.0549169 + tangentMode: 35 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.2580645 + value: 0.5080005 + inSlope: 0.98618674 + outSlope: 0.98618674 + tangentMode: 35 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.29032257 + value: 0.5388159 + inSlope: 0.92940044 + outSlope: 0.92940044 + tangentMode: 35 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.32258064 + value: 0.5679618 + inSlope: 0.88144594 + outSlope: 0.88144594 + tangentMode: 35 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.3548387 + value: 0.5956834 + inSlope: 0.84024215 + outSlope: 0.84024215 + tangentMode: 35 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.38709676 + value: 0.622171 + inSlope: 0.8043368 + outSlope: 0.8043368 + tangentMode: 35 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41935483 + value: 0.6475761 + inSlope: 0.77268314 + outSlope: 0.77268314 + tangentMode: 35 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.4516129 + value: 0.6720215 + inSlope: 0.74449944 + outSlope: 0.74449944 + tangentMode: 35 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.48387095 + value: 0.6956083 + inSlope: 0.71919554 + outSlope: 0.71919554 + tangentMode: 35 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.516129 + value: 0.7184212 + inSlope: 0.69631094 + outSlope: 0.69631094 + tangentMode: 35 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.5483871 + value: 0.7405316 + inSlope: 0.6754826 + outSlope: 0.6754826 + tangentMode: 35 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.58064514 + value: 0.76200074 + inSlope: 0.65642124 + outSlope: 0.65642124 + tangentMode: 35 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.61290324 + value: 0.7828814 + inSlope: 0.638888 + outSlope: 0.638888 + tangentMode: 35 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.6451613 + value: 0.8032193 + inSlope: 0.6226897 + outSlope: 0.6226897 + tangentMode: 35 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.67741936 + value: 0.8230549 + inSlope: 0.6076648 + outSlope: 0.6076648 + tangentMode: 35 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.7096774 + value: 0.8424235 + inSlope: 0.59367925 + outSlope: 0.59367925 + tangentMode: 35 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.7419355 + value: 0.8613568 + inSlope: 0.58061755 + outSlope: 0.58061755 + tangentMode: 35 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.7741935 + value: 0.8798827 + inSlope: 0.56838083 + outSlope: 0.56838083 + tangentMode: 35 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8064516 + value: 0.8980265 + inSlope: 0.55688787 + outSlope: 0.55688787 + tangentMode: 35 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.83870965 + value: 0.91581094 + inSlope: 0.54606473 + outSlope: 0.54606473 + tangentMode: 35 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.87096775 + value: 0.9332565 + inSlope: 0.5358504 + outSlope: 0.5358504 + tangentMode: 35 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.9032258 + value: 0.95038193 + inSlope: 0.5261885 + outSlope: 0.5261885 + tangentMode: 35 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.9354839 + value: 0.96720415 + inSlope: 0.5170302 + outSlope: 0.5170302 + tangentMode: 35 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.9677419 + value: 0.9837387 + inSlope: 0.5083356 + outSlope: 0.5083356 + tangentMode: 35 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0.5040992 + outSlope: 0.5040992 + tangentMode: 35 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + - id: -1857835930 + _name: Alignment + synapses: + - nucleusId: -176251552 + weight: 1 + curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + - nucleusId: 1164040656 + weight: 1 + curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + - nucleusId: -1679360144 + weight: 1 + curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + - nucleusId: -1513426512 + weight: 1 + curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + - nucleusId: 1708725840 + weight: 1 + curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + - nucleusId: -1645785904 + weight: 1 + curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + receivers: + - nucleusId: -1707533328 + nucleusType: + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 inSlope: 0 - outSlope: -112788.63 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.008866142 - value: 112.788635 - inSlope: -112788.63 - outSlope: -6740.78 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.016732283 - value: 59.76471 - inSlope: -6740.78 - outSlope: -2429.6155 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.024598425 - value: 40.653008 - inSlope: -2429.6155 - outSlope: -1252.2269 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.032464568 - value: 30.802813 - inSlope: -1252.2269 - outSlope: -763.7558 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.040330708 - value: 24.795002 - inSlope: -763.7558 - outSlope: -514.45264 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.04819685 - value: 20.748245 - inSlope: -514.45264 - outSlope: -370.0882 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.056062993 - value: 17.837078 - inSlope: -370.0882 - outSlope: -279.01324 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.06392913 - value: 15.642321 - inSlope: -279.01324 - outSlope: -217.87398 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.07179528 - value: 13.928493 - inSlope: -217.87398 - outSlope: -174.8461 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.079661414 - value: 12.553129 - inSlope: -174.8461 - outSlope: -143.41913 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.087527566 - value: 11.424973 - inSlope: -143.41913 - outSlope: -119.76661 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.0953937 - value: 10.482872 - inSlope: -119.76661 - outSlope: -101.519356 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.10325985 - value: 9.684306 - inSlope: -101.519356 - outSlope: -87.14706 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.11112598 - value: 8.9987955 - inSlope: -87.14706 - outSlope: -75.62513 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.11899213 - value: 8.403917 - inSlope: -75.62513 - outSlope: -66.24654 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.12685826 - value: 7.882813 - inSlope: -66.24654 - outSlope: -58.510654 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.13472441 - value: 7.4225597 - inSlope: -58.510654 - outSlope: -52.055042 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.14259055 - value: 7.0130873 - inSlope: -52.055042 - outSlope: -46.612007 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.1504567 - value: 6.6464305 - inSlope: -46.612007 - outSlope: -41.98024 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.15832284 - value: 6.316208 - inSlope: -41.98024 - outSlope: -38.006134 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.16618897 - value: 6.0172467 - inSlope: -38.006134 - outSlope: -34.570965 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.17405513 - value: 5.745306 - inSlope: -34.570965 - outSlope: -31.581244 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.18192126 - value: 5.496884 - inSlope: -31.581244 - outSlope: -28.963417 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.1897874 - value: 5.2690535 - inSlope: -28.963417 - outSlope: -26.658009 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.19765353 - value: 5.059358 - inSlope: -26.658009 - outSlope: -24.617418 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.20551969 - value: 4.8657136 - inSlope: -24.617418 - outSlope: -22.802412 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.21338584 - value: 4.6863465 - inSlope: -22.802412 - outSlope: -21.181019 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.22125196 - value: 4.519734 - inSlope: -21.181019 - outSlope: -19.72667 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.22911811 - value: 4.364561 - inSlope: -19.72667 - outSlope: -18.417059 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.23698425 - value: 4.21969 - inSlope: -18.417059 - outSlope: -17.233776 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.2448504 - value: 4.0841265 - inSlope: -17.233776 - outSlope: -16.160883 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.25271654 - value: 3.9570026 - inSlope: -16.160883 - outSlope: -15.185221 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.2605827 - value: 3.8375535 - inSlope: -15.185221 - outSlope: -14.295299 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.2684488 - value: 3.725105 - inSlope: -14.295299 - outSlope: -13.481375 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.27631494 - value: 3.6190586 - inSlope: -13.481375 - outSlope: -12.735047 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.28418112 - value: 3.5188825 - inSlope: -12.735047 - outSlope: -12.04901 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.29204726 - value: 3.4241033 - inSlope: -12.04901 - outSlope: -11.416967 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.2999134 - value: 3.3342957 - inSlope: -11.416967 - outSlope: -10.8334 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.30777952 - value: 3.249079 - inSlope: -10.8334 - outSlope: -10.293426 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.31564566 - value: 3.1681094 - inSlope: -10.293426 - outSlope: -9.792865 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.3235118 - value: 3.0910773 - inSlope: -9.792865 - outSlope: -9.327949 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.33137795 - value: 3.0177023 - inSlope: -9.327949 - outSlope: -8.895375 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.33924407 - value: 2.9477303 - inSlope: -8.895375 - outSlope: -8.492224 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.34711024 - value: 2.880929 - inSlope: -8.492224 - outSlope: -8.115812 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.3549764 - value: 2.8170888 - inSlope: -8.115812 - outSlope: -7.76395 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.36284253 - value: 2.7560165 - inSlope: -7.76395 - outSlope: -7.434456 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.37070867 - value: 2.697536 - inSlope: -7.434456 - outSlope: -7.1255083 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.3785748 - value: 2.641486 - inSlope: -7.1255083 - outSlope: -6.8354197 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.38644093 - value: 2.5877175 - inSlope: -6.8354197 - outSlope: -6.562695 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.39430708 - value: 2.5360944 - inSlope: -6.562695 - outSlope: -6.305974 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.40217322 - value: 2.4864907 - inSlope: -6.305974 - outSlope: -6.064021 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4100394 - value: 2.43879 - inSlope: -6.064021 - outSlope: -5.835745 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4179055 - value: 2.3928854 - inSlope: -5.835745 - outSlope: -5.6201315 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.42577165 - value: 2.3486767 - inSlope: -5.6201315 - outSlope: -5.4162097 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4336378 - value: 2.306072 - inSlope: -5.4162097 - outSlope: -5.223229 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.44150394 - value: 2.2649853 - inSlope: -5.223229 - outSlope: -5.040342 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4493701 - value: 2.2253373 - inSlope: -5.040342 - outSlope: -4.8669295 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4572362 - value: 2.1870534 - inSlope: -4.8669295 - outSlope: -4.7023005 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.46510234 - value: 2.1500645 - inSlope: -4.7023005 - outSlope: -4.5458865 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.47296852 - value: 2.1143057 - inSlope: -4.5458865 - outSlope: -4.3971753 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.48083466 - value: 2.079717 - inSlope: -4.3971753 - outSlope: -4.2555995 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4887008 - value: 2.0462418 - inSlope: -4.2555995 - outSlope: -4.1207685 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.49656692 - value: 2.0138273 - inSlope: -4.1207685 - outSlope: -3.9922712 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5044331 - value: 1.9824234 - inSlope: -3.9922712 - outSlope: -3.8696532 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5122992 - value: 1.9519844 - inSlope: -3.8696532 - outSlope: -3.7526293 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5201653 - value: 1.9224657 - inSlope: -3.7526293 - outSlope: -3.6408176 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.52803147 - value: 1.8938265 - inSlope: -3.6408176 - outSlope: -3.5339315 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5358976 - value: 1.8660281 - inSlope: -3.5339315 - outSlope: -3.4316826 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.54376376 - value: 1.839034 - inSlope: -3.4316826 - outSlope: -3.3338284 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5516299 - value: 1.8128096 - inSlope: -3.3338284 - outSlope: -3.240066 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.55949605 - value: 1.7873228 - inSlope: -3.240066 - outSlope: -3.1502352 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.56736225 - value: 1.7625424 - inSlope: -3.1502352 - outSlope: -3.0640743 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5752284 - value: 1.7384399 - inSlope: -3.0640743 - outSlope: -2.9814053 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.58309454 - value: 1.7149878 - inSlope: -2.9814053 - outSlope: -2.9020314 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5909606 - value: 1.6921601 - inSlope: -2.9020314 - outSlope: -2.8257964 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.59882677 - value: 1.669932 - inSlope: -2.8257964 - outSlope: -2.7525082 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6066929 - value: 1.6482804 - inSlope: -2.7525082 - outSlope: -2.6820538 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.61455905 - value: 1.627183 - inSlope: -2.6820538 - outSlope: -2.6142666 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6224252 - value: 1.6066188 - inSlope: -2.6142666 - outSlope: -2.5490105 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.63029134 - value: 1.5865679 - inSlope: -2.5490105 - outSlope: -2.4861636 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6381575 - value: 1.5670114 - inSlope: -2.4861636 - outSlope: -2.4256358 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.64602363 - value: 1.547931 - inSlope: -2.4256358 - outSlope: -2.3672597 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6538898 - value: 1.5293097 - inSlope: -2.3672597 - outSlope: -2.3109925 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.66175586 - value: 1.5111313 - inSlope: -2.3109925 - outSlope: -2.2566907 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.669622 - value: 1.4933798 - inSlope: -2.2566907 - outSlope: -2.2042859 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.67748815 - value: 1.4760406 - inSlope: -2.2042859 - outSlope: -2.1536992 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6853543 - value: 1.4590993 - inSlope: -2.1536992 - outSlope: -2.1048093 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6932205 - value: 1.4425424 - inSlope: -2.1048093 - outSlope: -2.0575728 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.70108664 - value: 1.4263573 - inSlope: -2.0575728 - outSlope: -2.011927 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7089528 - value: 1.4105312 - inSlope: -2.011927 - outSlope: -1.9677659 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7168189 - value: 1.3950524 - inSlope: -1.9677659 - outSlope: -1.9250447 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7246851 - value: 1.3799098 - inSlope: -1.9250447 - outSlope: -1.8837026 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7325512 - value: 1.3650923 - inSlope: -1.8837026 - outSlope: -1.8436778 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7404173 - value: 1.3505898 - inSlope: -1.8436778 - outSlope: -1.8049132 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.74828345 - value: 1.336392 - inSlope: -1.8049132 - outSlope: -1.7673749 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7561496 - value: 1.3224896 - inSlope: -1.7673749 - outSlope: -1.7309732 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.76401573 - value: 1.3088735 - inSlope: -1.7309732 - outSlope: -1.695693 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7718819 - value: 1.295535 - inSlope: -1.695693 - outSlope: -1.6614736 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.779748 - value: 1.2824656 - inSlope: -1.6614736 - outSlope: -1.6282848 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.78761417 - value: 1.2696573 - inSlope: -1.6282848 - outSlope: -1.5960962 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7954803 - value: 1.2571021 - inSlope: -1.5960962 - outSlope: -1.564832 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.80334646 - value: 1.2447929 - inSlope: -1.564832 - outSlope: -1.5344887 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.81121254 - value: 1.2327225 - inSlope: -1.5344887 - outSlope: -1.5050048 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.81907874 - value: 1.2208838 - inSlope: -1.5050048 - outSlope: -1.4763738 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8269449 - value: 1.2092705 - inSlope: -1.4763738 - outSlope: -1.4485649 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.83481103 - value: 1.1978759 - inSlope: -1.4485649 - outSlope: -1.4215137 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8426772 - value: 1.186694 - inSlope: -1.4215137 - outSlope: -1.3952202 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8505433 - value: 1.175719 - inSlope: -1.3952202 - outSlope: -1.369639 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.85840946 - value: 1.1649452 - inSlope: -1.369639 - outSlope: -1.3447852 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8662756 - value: 1.154367 - inSlope: -1.3447852 - outSlope: -1.320568 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.87414175 - value: 1.1439792 - inSlope: -1.320568 - outSlope: -1.2970176 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8820079 - value: 1.1337767 - inSlope: -1.2970176 - outSlope: -1.2740829 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.889874 - value: 1.1237546 - inSlope: -1.2740829 - outSlope: -1.2517655 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8977401 - value: 1.113908 - inSlope: -1.2517655 - outSlope: -1.2300034 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.90560627 - value: 1.1042327 - inSlope: -1.2300034 - outSlope: -1.2088321 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9134724 - value: 1.0947238 - inSlope: -1.2088321 - outSlope: -1.1881914 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.92133856 - value: 1.0853773 - inSlope: -1.1881914 - outSlope: -1.1680659 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9292047 - value: 1.0761892 - inSlope: -1.1680659 - outSlope: -1.1484709 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.93707085 - value: 1.0671551 - inSlope: -1.1484709 - outSlope: -1.1293371 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.94493705 - value: 1.0582715 - inSlope: -1.1293371 - outSlope: -1.1106901 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9528032 - value: 1.0495347 - inSlope: -1.1106901 - outSlope: -1.0925045 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.96066934 - value: 1.0409409 - inSlope: -1.0925045 - outSlope: -1.0747513 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9685354 - value: 1.0324868 - inSlope: -1.0747513 - outSlope: -1.0574516 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.97640157 - value: 1.0241687 - inSlope: -1.0574516 - outSlope: -1.0405389 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9842677 - value: 1.0159837 - inSlope: -1.0405389 - outSlope: -1.0240355 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.99213386 - value: 1.0079285 - inSlope: -1.0240355 - outSlope: -1.0079259 - tangentMode: 69 + outSlope: 1 + tangentMode: 0 weightedMode: 0 inWeight: 0 outWeight: 0 - serializedVersion: 3 time: 1 value: 1 - inSlope: -1.0079259 + inSlope: 1 outSlope: 0 - tangentMode: 69 + tangentMode: 0 weightedMode: 0 inWeight: 0 outWeight: 0 m_PreInfinity: 2 m_PostInfinity: 2 m_RotationOrder: 4 - curveMax: 100 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + - id: 1164040656 + _name: Boid3 Velocity + synapses: + - nucleusId: 2020437392 + weight: 1 + curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + receivers: + - nucleusId: -1857835930 + nucleusType: + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + - id: -176251552 + _name: Boid2 Velocity + synapses: + - nucleusId: 10881140 + weight: 1 + curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + receivers: + - nucleusId: -1857835930 + nucleusType: + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + - id: -1679360144 + _name: Boid1 Velocity + synapses: + - nucleusId: 1302452224 + weight: 1 + curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + receivers: + - nucleusId: -1857835930 + nucleusType: + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + - id: -1513426512 + _name: Boid4 Velocity + synapses: + - nucleusId: -1530763258 + weight: 1 + curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + receivers: + - nucleusId: -1857835930 + nucleusType: + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + - id: 1708725840 + _name: Boid5 Velocity + synapses: + - nucleusId: 1790226608 + weight: 1 + curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + receivers: + - nucleusId: -1857835930 + nucleusType: + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + - id: -1645785904 + _name: Boid6 Velocity + synapses: + - nucleusId: 626548796 + weight: 1 + curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + receivers: + - nucleusId: -1857835930 + nucleusType: + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 average: 0 inverse: 0 exponent: 1 @@ -2578,10 +2169,11 @@ MonoBehaviour: exponent: 1 thingType: 1 thingId: 0 - - id: -1420275136 - _name: Boid1 + - id: 2020437392 + _name: Boid3 synapses: [] receivers: + - nucleusId: 1164040656 - nucleusId: 1938577052 - nucleusId: 1641120128 nucleusType: Perceptoid @@ -2592,16 +2184,17 @@ MonoBehaviour: m_PreInfinity: 2 m_PostInfinity: 2 m_RotationOrder: 4 - curveMax: 0 + curveMax: 1 average: 0 inverse: 0 exponent: 1 thingType: 2 thingId: 0 - - id: -1266532688 + - id: 10881140 _name: Boid2 synapses: [] receivers: + - nucleusId: -176251552 - nucleusId: 1938577052 - nucleusId: 1641120128 nucleusType: Perceptoid @@ -2612,7 +2205,91 @@ MonoBehaviour: m_PreInfinity: 2 m_PostInfinity: 2 m_RotationOrder: 4 - curveMax: 0 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + thingType: 2 + thingId: 0 + - id: 1302452224 + _name: Boid1 + synapses: [] + receivers: + - nucleusId: -1679360144 + - nucleusId: 1938577052 + - nucleusId: 1641120128 + nucleusType: Perceptoid + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + thingType: 2 + thingId: 0 + - id: -1530763258 + _name: Boid4 + synapses: [] + receivers: + - nucleusId: -1513426512 + - nucleusId: 1938577052 + - nucleusId: 1641120128 + nucleusType: Perceptoid + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + thingType: 2 + thingId: 0 + - id: 1790226608 + _name: Boid5 + synapses: [] + receivers: + - nucleusId: 1708725840 + - nucleusId: 1938577052 + - nucleusId: 1641120128 + nucleusType: Perceptoid + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + thingType: 2 + thingId: 0 + - id: 626548796 + _name: Boid6 + synapses: [] + receivers: + - nucleusId: -1645785904 + - nucleusId: 1938577052 + - nucleusId: 1641120128 + nucleusType: Perceptoid + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 average: 0 inverse: 0 exponent: 1 From a500a9e16e1c984504e782c6733724099b0c82f9 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Tue, 23 Dec 2025 09:19:05 +0100 Subject: [PATCH 028/179] Move to Spherical outputvalue --- Assembly-CSharp-Editor.csproj | 614 ++++++++++-------- Assembly-CSharp.csproj | 609 +++++++++-------- Assets/NanoBrain/Editor/NanoBrain_Editor.cs | 6 +- Assets/NanoBrain/LinearAlgebra-csharp.meta | 8 + .../NanoBrain/NanoBrain-Unity.code-workspace | 12 + .../NanoBrain-Unity.code-workspace.meta | 7 + Assets/NanoBrain/Neuroid.cs | 21 +- Assets/NanoBrain/Nucleus.cs | 3 +- Assets/NanoBrain/Perceptoid.cs | 15 +- Assets/NanoBrain/Receptor.cs | 5 +- Assets/NanoBrain/SensoryNeuroid.cs | 23 +- .../VisualEditor/Editor/NanoBrainEditor.cs | 4 +- .../VisualEditor/Editor/NanoBrainInspector.cs | 2 +- Assets/NanoBrain/VisualEditor/NanoBrainObj.cs | 5 +- Assets/Scenes/Boids/Scripts/Boid.cs | 2 +- .../Scenes/Boids/Scripts/SwarmingNucleus.cs | 3 +- Packages/manifest.json | 8 +- Packages/packages-lock.json | 59 +- ProjectSettings/GraphicsSettings.asset | 4 +- .../MultiplayerRolesSettings.asset | 17 + ProjectSettings/ProjectVersion.txt | 4 +- 21 files changed, 805 insertions(+), 626 deletions(-) create mode 100644 Assets/NanoBrain/LinearAlgebra-csharp.meta create mode 100644 Assets/NanoBrain/NanoBrain-Unity.code-workspace create mode 100644 Assets/NanoBrain/NanoBrain-Unity.code-workspace.meta create mode 100644 ProjectSettings/Packages/com.unity.dedicated-server/MultiplayerRolesSettings.asset diff --git a/Assembly-CSharp-Editor.csproj b/Assembly-CSharp-Editor.csproj index 08fa44b..6886476 100644 --- a/Assembly-CSharp-Editor.csproj +++ b/Assembly-CSharp-Editor.csproj @@ -23,7 +23,7 @@ 0169;USG0001 - UNITY_6000_2_13;UNITY_6000_2;UNITY_6000;UNITY_5_3_OR_NEWER;UNITY_5_4_OR_NEWER;UNITY_5_5_OR_NEWER;UNITY_5_6_OR_NEWER;UNITY_2017_1_OR_NEWER;UNITY_2017_2_OR_NEWER;UNITY_2017_3_OR_NEWER;UNITY_2017_4_OR_NEWER;UNITY_2018_1_OR_NEWER;UNITY_2018_2_OR_NEWER;UNITY_2018_3_OR_NEWER;UNITY_2018_4_OR_NEWER;UNITY_2019_1_OR_NEWER;UNITY_2019_2_OR_NEWER;UNITY_2019_3_OR_NEWER;UNITY_2019_4_OR_NEWER;UNITY_2020_1_OR_NEWER;UNITY_2020_2_OR_NEWER;UNITY_2020_3_OR_NEWER;UNITY_2021_1_OR_NEWER;UNITY_2021_2_OR_NEWER;UNITY_2021_3_OR_NEWER;UNITY_2022_1_OR_NEWER;UNITY_2022_2_OR_NEWER;UNITY_2022_3_OR_NEWER;UNITY_2023_1_OR_NEWER;UNITY_2023_2_OR_NEWER;UNITY_2023_3_OR_NEWER;UNITY_6000_0_OR_NEWER;UNITY_6000_1_OR_NEWER;UNITY_6000_2_OR_NEWER;PLATFORM_ARCH_64;UNITY_64;UNITY_INCLUDE_TESTS;ENABLE_AUDIO;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_MICROPHONE;ENABLE_MULTIPLE_DISPLAYS;ENABLE_PHYSICS;ENABLE_TEXTURE_STREAMING;ENABLE_VIRTUALTEXTURING;ENABLE_LZMA;ENABLE_UNITYEVENTS;ENABLE_VR;ENABLE_WEBCAM;ENABLE_UNITYWEBREQUEST;ENABLE_WWW;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_SERVICES_USE_WEBREQUEST;ENABLE_UNITY_CONSENT;ENABLE_UNITY_CLOUD_IDENTIFIERS;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_EDITOR_GAME_SERVICES;ENABLE_UNITY_GAME_SERVICES_ANALYTICS_SUPPORT;ENABLE_CLOUD_LICENSE;ENABLE_EDITOR_HUB_LICENSE;ENABLE_WEBSOCKET_CLIENT;ENABLE_GENERATE_NATIVE_PLUGINS_FOR_ASSEMBLIES_API;ENABLE_DIRECTOR_AUDIO;ENABLE_DIRECTOR_TEXTURE;ENABLE_MANAGED_JOBS;ENABLE_MANAGED_TRANSFORM_JOBS;ENABLE_MANAGED_ANIMATION_JOBS;ENABLE_MANAGED_AUDIO_JOBS;ENABLE_MANAGED_UNITYTLS;INCLUDE_DYNAMIC_GI;ENABLE_SCRIPTING_GC_WBARRIERS;PLATFORM_SUPPORTS_MONO;RENDER_SOFTWARE_CURSOR;ENABLE_MARSHALLING_TESTS;ENABLE_VIDEO;ENABLE_NAVIGATION_OFFMESHLINK_TO_NAVMESHLINK;ENABLE_ACCELERATOR_CLIENT_DEBUGGING;TEXTCORE_1_0_OR_NEWER;EDITOR_ONLY_NAVMESH_BUILDER_DEPRECATED;PLATFORM_STANDALONE_LINUX;PLATFORM_STANDALONE;UNITY_STANDALONE_LINUX;UNITY_STANDALONE;UNITY_STANDALONE_LINUX_API;ENABLE_RUNTIME_GI;ENABLE_MOVIES;ENABLE_NETWORK;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_CLUSTER_SYNC;ENABLE_CLUSTERINPUT;ENABLE_SPATIALTRACKING;ENABLE_MODULAR_UNITYENGINE_ASSEMBLIES;PLATFORM_SUPPORTS_SPLIT_GRAPHICS_JOBS;PLATFORM_USES_EXPLICIT_MEMORY_MANAGER_INITIALIZER;ENABLE_MONO;NET_4_6;NET_UNITY_4_8;ENABLE_PROFILER;DEBUG;TRACE;UNITY_ASSERTIONS;UNITY_EDITOR;UNITY_EDITOR_64;UNITY_EDITOR_LINUX;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_BURST_AOT;UNITY_TEAM_LICENSE;ENABLE_CUSTOM_RENDER_TEXTURE;ENABLE_DIRECTOR;ENABLE_LOCALIZATION;ENABLE_SPRITES;ENABLE_TERRAIN;ENABLE_TILEMAP;ENABLE_TIMELINE;ENABLE_INPUT_SYSTEM;TEXTCORE_FONT_ENGINE_1_5_OR_NEWER;TEXTCORE_TEXT_ENGINE_1_5_OR_NEWER;CSHARP_7_OR_LATER;CSHARP_7_3_OR_NEWER;UNITY_EDITOR_ONLY_COMPILATION + UNITY_6000_3_2;UNITY_6000_3;UNITY_6000;UNITY_5_3_OR_NEWER;UNITY_5_4_OR_NEWER;UNITY_5_5_OR_NEWER;UNITY_5_6_OR_NEWER;UNITY_2017_1_OR_NEWER;UNITY_2017_2_OR_NEWER;UNITY_2017_3_OR_NEWER;UNITY_2017_4_OR_NEWER;UNITY_2018_1_OR_NEWER;UNITY_2018_2_OR_NEWER;UNITY_2018_3_OR_NEWER;UNITY_2018_4_OR_NEWER;UNITY_2019_1_OR_NEWER;UNITY_2019_2_OR_NEWER;UNITY_2019_3_OR_NEWER;UNITY_2019_4_OR_NEWER;UNITY_2020_1_OR_NEWER;UNITY_2020_2_OR_NEWER;UNITY_2020_3_OR_NEWER;UNITY_2021_1_OR_NEWER;UNITY_2021_2_OR_NEWER;UNITY_2021_3_OR_NEWER;UNITY_2022_1_OR_NEWER;UNITY_2022_2_OR_NEWER;UNITY_2022_3_OR_NEWER;UNITY_2023_1_OR_NEWER;UNITY_2023_2_OR_NEWER;UNITY_2023_3_OR_NEWER;UNITY_6000_0_OR_NEWER;UNITY_6000_1_OR_NEWER;UNITY_6000_2_OR_NEWER;UNITY_6000_3_OR_NEWER;PLATFORM_ARCH_64;UNITY_64;UNITY_INCLUDE_TESTS;ENABLE_AUDIO;ENABLE_AUDIO_SCRIPTABLE_PIPELINE;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_MICROPHONE;ENABLE_MULTIPLE_DISPLAYS;ENABLE_PHYSICS;ENABLE_TEXTURE_STREAMING;ENABLE_VIRTUALTEXTURING;ENABLE_LZMA;ENABLE_UNITYEVENTS;ENABLE_VR;ENABLE_WEBCAM;ENABLE_UNITYWEBREQUEST;ENABLE_WWW;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_SERVICES_USE_WEBREQUEST;ENABLE_UNITY_CONSENT;ENABLE_UNITY_CLOUD_IDENTIFIERS;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_EDITOR_GAME_SERVICES;ENABLE_UNITY_GAME_SERVICES_ANALYTICS_SUPPORT;ENABLE_CLOUD_LICENSE;ENABLE_EDITOR_HUB_LICENSE;ENABLE_WEBSOCKET_CLIENT;ENABLE_GENERATE_NATIVE_PLUGINS_FOR_ASSEMBLIES_API;ENABLE_DIRECTOR_AUDIO;ENABLE_DIRECTOR_TEXTURE;ENABLE_MANAGED_JOBS;ENABLE_MANAGED_TRANSFORM_JOBS;ENABLE_MANAGED_ANIMATION_JOBS;ENABLE_MANAGED_AUDIO_JOBS;ENABLE_MANAGED_UNITYTLS;INCLUDE_DYNAMIC_GI;ENABLE_SCRIPTING_GC_WBARRIERS;PLATFORM_SUPPORTS_MONO;RENDER_SOFTWARE_CURSOR;ENABLE_MARSHALLING_TESTS;ENABLE_VIDEO;ENABLE_NAVIGATION_OFFMESHLINK_TO_NAVMESHLINK;ENABLE_ACCELERATOR_CLIENT_DEBUGGING;TEXTCORE_1_0_OR_NEWER;EDITOR_ONLY_NAVMESH_BUILDER_DEPRECATED;PLATFORM_STANDALONE_LINUX;PLATFORM_STANDALONE;UNITY_STANDALONE_LINUX;UNITY_STANDALONE;UNITY_STANDALONE_LINUX_API;ENABLE_RUNTIME_GI;ENABLE_MOVIES;ENABLE_NETWORK;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_CLUSTER_SYNC;ENABLE_CLUSTERINPUT;ENABLE_SPATIALTRACKING;ENABLE_MODULAR_UNITYENGINE_ASSEMBLIES;PLATFORM_SUPPORTS_SPLIT_GRAPHICS_JOBS;PLATFORM_USES_EXPLICIT_MEMORY_MANAGER_INITIALIZER;PLATFORM_SUPPORTS_DISPLAYINFO_API;ENABLE_MONO;NET_4_6;NET_UNITY_4_8;ENABLE_PROFILER;DEBUG;TRACE;UNITY_ASSERTIONS;UNITY_EDITOR;UNITY_EDITOR_64;UNITY_EDITOR_LINUX;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_BURST_AOT;UNITY_TEAM_LICENSE;ENABLE_CUSTOM_RENDER_TEXTURE;ENABLE_DIRECTOR;ENABLE_LOCALIZATION;ENABLE_SPRITES;ENABLE_TERRAIN;ENABLE_TILEMAP;ENABLE_TIMELINE;ENABLE_INPUT_SYSTEM;TEXTCORE_FONT_ENGINE_1_5_OR_NEWER;TEXTCORE_TEXT_ENGINE_1_5_OR_NEWER;TEXTCORE_FONT_ENGINE_1_6_OR_NEWER;CSHARP_7_OR_LATER;CSHARP_7_3_OR_NEWER;UNITY_EDITOR_ONLY_COMPILATION False @@ -39,13 +39,13 @@ SDK Editor:5 StandaloneLinux64:24 - 6000.2.13f1 + 6000.3.2f1 - - - + + + @@ -56,511 +56,559 @@ - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.AIModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.AIModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.AMDModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.AMDModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.ARModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.ARModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.AccessibilityModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.AccessibilityModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.AdaptivePerformanceModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.AndroidJNIModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.AndroidJNIModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.AnimationModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.AnimationModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.AssetBundleModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.AssetBundleModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.AudioModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.AudioModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.ClothModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.ClothModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.ClusterInputModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.ClusterInputModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.ClusterRendererModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.ClusterRendererModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.ContentLoadModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.ContentLoadModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.CoreModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.CoreModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.CrashReportingModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.CrashReportingModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.DSPGraphModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.DSPGraphModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.DirectorModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.DirectorModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.GIModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.GIModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.GameCenterModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.GameCenterModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.GraphicsStateCollectionSerializerModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.GraphicsStateCollectionSerializerModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.GridModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.GridModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.HierarchyModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.HierarchyCoreModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.HierarchyCoreModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.HotReloadModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.HotReloadModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.IMGUIModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.IMGUIModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.IdentifiersModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.IdentifiersModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.ImageConversionModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.ImageConversionModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.InputModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.InputModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.InputForUIModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.InputForUIModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.InputLegacyModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.InputLegacyModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.InsightsModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.InsightsModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.JSONSerializeModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.JSONSerializeModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.LocalizationModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.LocalizationModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.MarshallingModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.MarshallingModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.MultiplayerModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.MultiplayerModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.NVIDIAModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.NVIDIAModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.ParticleSystemModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.ParticleSystemModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.PerformanceReportingModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.PerformanceReportingModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.PhysicsModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.PhysicsModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.Physics2DModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.Physics2DModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.PhysicsBackendPhysXModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.PropertiesModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.PropertiesModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.RenderAs2DModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.RuntimeInitializeOnLoadManagerInitializerModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.RuntimeInitializeOnLoadManagerInitializerModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.ScreenCaptureModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.ScreenCaptureModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.ShaderRuntimeModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.ShaderVariantAnalyticsModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.ShaderVariantAnalyticsModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.SharedInternalsModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.SharedInternalsModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.SpriteMaskModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.SpriteMaskModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.SpriteShapeModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.SpriteShapeModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.StreamingModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.StreamingModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.SubstanceModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.SubstanceModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.SubsystemsModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.SubsystemsModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.TLSModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.TLSModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.TerrainModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.TerrainModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.TerrainPhysicsModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.TerrainPhysicsModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.TextCoreFontEngineModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.TextCoreFontEngineModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.TextCoreTextEngineModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.TextCoreTextEngineModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.TextRenderingModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.TextRenderingModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.TilemapModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.TilemapModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UIModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.UIModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UIElementsModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.UIElementsModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UmbraModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.UmbraModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityAnalyticsModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityAnalyticsModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityAnalyticsCommonModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityAnalyticsCommonModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityConnectModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityConnectModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityConsentModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityConsentModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityCurlModule.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityTestProtocolModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityCurlModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityWebRequestModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityWebRequestModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityWebRequestAssetBundleModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityWebRequestAssetBundleModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityWebRequestAudioModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityWebRequestAudioModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityWebRequestTextureModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityWebRequestTextureModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityWebRequestWWWModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityWebRequestWWWModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.VFXModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.VFXModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.VRModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.VRModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.VectorGraphicsModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.VehiclesModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.VehiclesModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.VideoModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.VideoModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.VirtualTexturingModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.VirtualTexturingModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.WindModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.WindModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.XRModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.XRModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.AccessibilityModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.AccessibilityModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.AdaptivePerformanceModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.AdaptivePerformanceModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.AssetComplianceModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.BuildProfileModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.BuildProfileModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.ClothModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.ClothModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.CoreBusinessMetricsModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.CoreBusinessMetricsModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.CoreModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.CoreModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.DeviceSimulatorModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.DeviceSimulatorModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.DiagnosticsModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.DiagnosticsModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.EditorToolbarModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.EditorToolbarModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.EmbreeModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.EmbreeModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.GIModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.GIModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.GraphViewModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.GraphViewModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.GraphicsStateCollectionSerializerModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.GraphicsStateCollectionSerializerModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.GridAndSnapModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.GridAndSnapModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.GridModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.GridModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.HierarchyModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.InAppPurchasingModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.InAppPurchasingModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.LevelPlayModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.LevelPlayModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.MediaModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.MultiplayerModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.MultiplayerModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.Physics2DModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.Physics2DModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.PhysicsModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.PhysicsModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.PlayModeModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.PresetsUIModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.PresetsUIModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.PropertiesModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.PropertiesModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.QuickSearchModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.QuickSearchModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.SafeModeModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.SafeModeModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.SceneTemplateModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.SceneTemplateModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.SceneViewModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.SceneViewModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.ShaderBuildSettingsModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.ShaderCompilationModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.ShaderFoundryModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.ShaderFoundryModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.SketchUpModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.SketchUpModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.SpriteMaskModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.SpriteMaskModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.SpriteShapeModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.SpriteShapeModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.SubstanceModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.SubstanceModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.TerrainModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.TerrainModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.TextCoreFontEngineModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.TextCoreFontEngineModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.TextCoreTextEngineModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.TextCoreTextEngineModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.TextRenderingModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.TextRenderingModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.TilemapModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.TilemapModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.TreeModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.TreeModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.UIAutomationModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.UIAutomationModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.UIBuilderModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.UIBuilderModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.UIElementsModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.UIElementsModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.UIElementsSamplesModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.UIElementsSamplesModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.UIToolkitAuthoringModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.UmbraModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.UmbraModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.UnityConnectModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.UnityConnectModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.VFXModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.VFXModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.VectorGraphicsModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.VideoModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.VideoModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.XRModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.XRModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEditor.Graphs.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/PlaybackEngines/WebGLSupport/UnityEditor.WebGL.Extensions.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEditor.Graphs.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/PlaybackEngines/LinuxStandaloneSupport/UnityEditor.LinuxStandalone.Extensions.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/PlaybackEngines/LinuxStandaloneSupport/UnityEditor.LinuxStandalone.Extensions.dll False @@ -568,7 +616,7 @@ False - Library/PackageCache/com.unity.ext.nunit@b16e6d09cd93/net40/unity-custom/nunit.framework.dll + Library/PackageCache/com.unity.ext.nunit@ec2d0043d6fc/net40/unity-custom/nunit.framework.dll False @@ -592,7 +640,7 @@ False - Library/PackageCache/com.unity.nuget.mono-cecil@d78732e851eb/Mono.Cecil.dll + Library/PackageCache/com.unity.nuget.mono-cecil@ecb9724e46ff/Mono.Cecil.dll False @@ -600,503 +648,503 @@ False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/mscorlib.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/mscorlib.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Core.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Core.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Runtime.Serialization.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Runtime.Serialization.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Xml.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Xml.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Xml.Linq.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Xml.Linq.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Numerics.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Numerics.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Numerics.Vectors.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Numerics.Vectors.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Net.Http.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Net.Http.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.IO.Compression.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.IO.Compression.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Microsoft.CSharp.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Microsoft.CSharp.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Data.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Data.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Data.DataSetExtensions.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Data.DataSetExtensions.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Drawing.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Drawing.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.IO.Compression.FileSystem.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.IO.Compression.FileSystem.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.ComponentModel.Composition.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.ComponentModel.Composition.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Transactions.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Transactions.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/Microsoft.Win32.Primitives.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/Microsoft.Win32.Primitives.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.AppContext.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.AppContext.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Buffers.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Buffers.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.Concurrent.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.Concurrent.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.NonGeneric.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.NonGeneric.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.Specialized.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.Specialized.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.Annotations.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.Annotations.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.EventBasedAsync.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.EventBasedAsync.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.Primitives.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.Primitives.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.TypeConverter.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.TypeConverter.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Console.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Console.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Data.Common.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Data.Common.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Contracts.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Contracts.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Debug.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Debug.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.FileVersionInfo.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.FileVersionInfo.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Process.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Process.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.StackTrace.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.StackTrace.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.TextWriterTraceListener.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.TextWriterTraceListener.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Tools.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Tools.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.TraceSource.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.TraceSource.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Drawing.Primitives.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Drawing.Primitives.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Dynamic.Runtime.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Dynamic.Runtime.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Globalization.Calendars.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Globalization.Calendars.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Globalization.Extensions.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Globalization.Extensions.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Globalization.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Globalization.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.Compression.ZipFile.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.Compression.ZipFile.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.DriveInfo.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.DriveInfo.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.Primitives.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.Primitives.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.Watcher.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.Watcher.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.IsolatedStorage.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.IsolatedStorage.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.MemoryMappedFiles.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.MemoryMappedFiles.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.Pipes.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.Pipes.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.UnmanagedMemoryStream.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.UnmanagedMemoryStream.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.Expressions.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.Expressions.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.Parallel.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.Parallel.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.Queryable.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.Queryable.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Memory.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Memory.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Http.Rtc.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Http.Rtc.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.NameResolution.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.NameResolution.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.NetworkInformation.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.NetworkInformation.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Ping.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Ping.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Primitives.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Primitives.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Requests.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Requests.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Security.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Security.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Sockets.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Sockets.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.WebHeaderCollection.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.WebHeaderCollection.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.WebSockets.Client.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.WebSockets.Client.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.WebSockets.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.WebSockets.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ObjectModel.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ObjectModel.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.DispatchProxy.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.DispatchProxy.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Emit.ILGeneration.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Emit.ILGeneration.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Emit.Lightweight.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Emit.Lightweight.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Emit.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Emit.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Extensions.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Extensions.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Primitives.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Primitives.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Resources.Reader.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Resources.Reader.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Resources.ResourceManager.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Resources.ResourceManager.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Resources.Writer.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Resources.Writer.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.CompilerServices.VisualC.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.CompilerServices.VisualC.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Extensions.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Extensions.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Handles.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Handles.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.InteropServices.RuntimeInformation.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.InteropServices.RuntimeInformation.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.InteropServices.WindowsRuntime.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.InteropServices.WindowsRuntime.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.InteropServices.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.InteropServices.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Numerics.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Numerics.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Formatters.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Formatters.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Json.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Json.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Primitives.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Primitives.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Xml.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Xml.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Claims.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Claims.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Algorithms.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Algorithms.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Csp.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Csp.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Encoding.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Encoding.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Primitives.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Primitives.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.X509Certificates.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.X509Certificates.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Principal.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Principal.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.SecureString.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.SecureString.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Duplex.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Duplex.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Http.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Http.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.NetTcp.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.NetTcp.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Primitives.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Primitives.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Security.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Security.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Text.Encoding.Extensions.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Text.Encoding.Extensions.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Text.Encoding.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Text.Encoding.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Text.RegularExpressions.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Text.RegularExpressions.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Overlapped.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Overlapped.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Tasks.Extensions.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Tasks.Extensions.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Tasks.Parallel.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Tasks.Parallel.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Tasks.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Tasks.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Thread.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Thread.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.ThreadPool.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.ThreadPool.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Timer.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Timer.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ValueTuple.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ValueTuple.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.ReaderWriter.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.ReaderWriter.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XDocument.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XDocument.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XPath.XDocument.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XPath.XDocument.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XPath.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XPath.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XmlDocument.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XmlDocument.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XmlSerializer.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XmlSerializer.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/netstandard.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/netstandard.dll False @@ -1115,6 +1163,10 @@ Library/ScriptAssemblies/Unity.RenderPipelines.Core.Editor.dll False + + Library/ScriptAssemblies/Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary.dll + False + Library/ScriptAssemblies/Unity.TextMeshPro.Editor.dll False @@ -1127,6 +1179,10 @@ Library/ScriptAssemblies/Unity.VisualStudio.Editor.dll False + + Library/ScriptAssemblies/Unity.Rendering.LightTransport.Editor.dll + False + Library/ScriptAssemblies/Unity.AI.Navigation.dll False @@ -1159,8 +1215,8 @@ Library/ScriptAssemblies/Unity.RenderPipelines.Universal.Shaders.dll False - - Library/ScriptAssemblies/UnityEngine.UI.dll + + Library/ScriptAssemblies/Unity.RenderPipelines.Universal.2D.Editor.Overrides.dll False @@ -1187,10 +1243,18 @@ Library/ScriptAssemblies/Unity.AI.Navigation.Editor.dll False + + Library/ScriptAssemblies/UnityEngine.UI.dll + False + Library/ScriptAssemblies/PPv2URPConverters.dll False + + Library/ScriptAssemblies/Unity.InternalAPIEngineBridge.004.dll + False + Library/ScriptAssemblies/Unity.RenderPipelines.Core.Runtime.Shared.dll False @@ -1219,10 +1283,6 @@ Library/ScriptAssemblies/Unity.Burst.Editor.dll False - - Library/ScriptAssemblies/Unity.Rendering.LightTransport.Runtime.dll - False - Library/ScriptAssemblies/Unity.Mathematics.Editor.dll False @@ -1231,8 +1291,8 @@ Library/ScriptAssemblies/Unity.RenderPipelines.Universal.Config.Runtime.dll False - - Library/ScriptAssemblies/Unity.RenderPipeline.Universal.ShaderLibrary.dll + + Library/ScriptAssemblies/Unity.UnifiedRayTracing.Runtime.dll False @@ -1243,8 +1303,8 @@ Library/ScriptAssemblies/Unity.ShaderGraph.Editor.dll False - - Library/ScriptAssemblies/Unity.Rendering.LightTransport.Editor.dll + + Library/ScriptAssemblies/Unity.RenderPipeline.Universal.ShaderLibrary.dll False @@ -1267,10 +1327,6 @@ Library/ScriptAssemblies/UnityEditor.UI.dll False - - Library/ScriptAssemblies/Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary.dll - False - diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index 173cb6d..4f41e1b 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -23,7 +23,7 @@ 0169;USG0001 - UNITY_6000_2_13;UNITY_6000_2;UNITY_6000;UNITY_5_3_OR_NEWER;UNITY_5_4_OR_NEWER;UNITY_5_5_OR_NEWER;UNITY_5_6_OR_NEWER;UNITY_2017_1_OR_NEWER;UNITY_2017_2_OR_NEWER;UNITY_2017_3_OR_NEWER;UNITY_2017_4_OR_NEWER;UNITY_2018_1_OR_NEWER;UNITY_2018_2_OR_NEWER;UNITY_2018_3_OR_NEWER;UNITY_2018_4_OR_NEWER;UNITY_2019_1_OR_NEWER;UNITY_2019_2_OR_NEWER;UNITY_2019_3_OR_NEWER;UNITY_2019_4_OR_NEWER;UNITY_2020_1_OR_NEWER;UNITY_2020_2_OR_NEWER;UNITY_2020_3_OR_NEWER;UNITY_2021_1_OR_NEWER;UNITY_2021_2_OR_NEWER;UNITY_2021_3_OR_NEWER;UNITY_2022_1_OR_NEWER;UNITY_2022_2_OR_NEWER;UNITY_2022_3_OR_NEWER;UNITY_2023_1_OR_NEWER;UNITY_2023_2_OR_NEWER;UNITY_2023_3_OR_NEWER;UNITY_6000_0_OR_NEWER;UNITY_6000_1_OR_NEWER;UNITY_6000_2_OR_NEWER;PLATFORM_ARCH_64;UNITY_64;UNITY_INCLUDE_TESTS;ENABLE_AUDIO;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_MICROPHONE;ENABLE_MULTIPLE_DISPLAYS;ENABLE_PHYSICS;ENABLE_TEXTURE_STREAMING;ENABLE_VIRTUALTEXTURING;ENABLE_LZMA;ENABLE_UNITYEVENTS;ENABLE_VR;ENABLE_WEBCAM;ENABLE_UNITYWEBREQUEST;ENABLE_WWW;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_SERVICES_USE_WEBREQUEST;ENABLE_UNITY_CONSENT;ENABLE_UNITY_CLOUD_IDENTIFIERS;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_EDITOR_GAME_SERVICES;ENABLE_UNITY_GAME_SERVICES_ANALYTICS_SUPPORT;ENABLE_CLOUD_LICENSE;ENABLE_EDITOR_HUB_LICENSE;ENABLE_WEBSOCKET_CLIENT;ENABLE_GENERATE_NATIVE_PLUGINS_FOR_ASSEMBLIES_API;ENABLE_DIRECTOR_AUDIO;ENABLE_DIRECTOR_TEXTURE;ENABLE_MANAGED_JOBS;ENABLE_MANAGED_TRANSFORM_JOBS;ENABLE_MANAGED_ANIMATION_JOBS;ENABLE_MANAGED_AUDIO_JOBS;ENABLE_MANAGED_UNITYTLS;INCLUDE_DYNAMIC_GI;ENABLE_SCRIPTING_GC_WBARRIERS;PLATFORM_SUPPORTS_MONO;RENDER_SOFTWARE_CURSOR;ENABLE_MARSHALLING_TESTS;ENABLE_VIDEO;ENABLE_NAVIGATION_OFFMESHLINK_TO_NAVMESHLINK;ENABLE_ACCELERATOR_CLIENT_DEBUGGING;TEXTCORE_1_0_OR_NEWER;EDITOR_ONLY_NAVMESH_BUILDER_DEPRECATED;PLATFORM_STANDALONE_LINUX;PLATFORM_STANDALONE;UNITY_STANDALONE_LINUX;UNITY_STANDALONE;UNITY_STANDALONE_LINUX_API;ENABLE_RUNTIME_GI;ENABLE_MOVIES;ENABLE_NETWORK;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_CLUSTER_SYNC;ENABLE_CLUSTERINPUT;ENABLE_SPATIALTRACKING;ENABLE_MODULAR_UNITYENGINE_ASSEMBLIES;PLATFORM_SUPPORTS_SPLIT_GRAPHICS_JOBS;PLATFORM_USES_EXPLICIT_MEMORY_MANAGER_INITIALIZER;ENABLE_MONO;NET_4_6;NET_UNITY_4_8;ENABLE_PROFILER;DEBUG;TRACE;UNITY_ASSERTIONS;UNITY_EDITOR;UNITY_EDITOR_64;UNITY_EDITOR_LINUX;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_BURST_AOT;UNITY_TEAM_LICENSE;ENABLE_CUSTOM_RENDER_TEXTURE;ENABLE_DIRECTOR;ENABLE_LOCALIZATION;ENABLE_SPRITES;ENABLE_TERRAIN;ENABLE_TILEMAP;ENABLE_TIMELINE;ENABLE_INPUT_SYSTEM;TEXTCORE_FONT_ENGINE_1_5_OR_NEWER;TEXTCORE_TEXT_ENGINE_1_5_OR_NEWER;CSHARP_7_OR_LATER;CSHARP_7_3_OR_NEWER + UNITY_6000_3_2;UNITY_6000_3;UNITY_6000;UNITY_5_3_OR_NEWER;UNITY_5_4_OR_NEWER;UNITY_5_5_OR_NEWER;UNITY_5_6_OR_NEWER;UNITY_2017_1_OR_NEWER;UNITY_2017_2_OR_NEWER;UNITY_2017_3_OR_NEWER;UNITY_2017_4_OR_NEWER;UNITY_2018_1_OR_NEWER;UNITY_2018_2_OR_NEWER;UNITY_2018_3_OR_NEWER;UNITY_2018_4_OR_NEWER;UNITY_2019_1_OR_NEWER;UNITY_2019_2_OR_NEWER;UNITY_2019_3_OR_NEWER;UNITY_2019_4_OR_NEWER;UNITY_2020_1_OR_NEWER;UNITY_2020_2_OR_NEWER;UNITY_2020_3_OR_NEWER;UNITY_2021_1_OR_NEWER;UNITY_2021_2_OR_NEWER;UNITY_2021_3_OR_NEWER;UNITY_2022_1_OR_NEWER;UNITY_2022_2_OR_NEWER;UNITY_2022_3_OR_NEWER;UNITY_2023_1_OR_NEWER;UNITY_2023_2_OR_NEWER;UNITY_2023_3_OR_NEWER;UNITY_6000_0_OR_NEWER;UNITY_6000_1_OR_NEWER;UNITY_6000_2_OR_NEWER;UNITY_6000_3_OR_NEWER;PLATFORM_ARCH_64;UNITY_64;UNITY_INCLUDE_TESTS;ENABLE_AUDIO;ENABLE_AUDIO_SCRIPTABLE_PIPELINE;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_MICROPHONE;ENABLE_MULTIPLE_DISPLAYS;ENABLE_PHYSICS;ENABLE_TEXTURE_STREAMING;ENABLE_VIRTUALTEXTURING;ENABLE_LZMA;ENABLE_UNITYEVENTS;ENABLE_VR;ENABLE_WEBCAM;ENABLE_UNITYWEBREQUEST;ENABLE_WWW;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_SERVICES_USE_WEBREQUEST;ENABLE_UNITY_CONSENT;ENABLE_UNITY_CLOUD_IDENTIFIERS;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_EDITOR_GAME_SERVICES;ENABLE_UNITY_GAME_SERVICES_ANALYTICS_SUPPORT;ENABLE_CLOUD_LICENSE;ENABLE_EDITOR_HUB_LICENSE;ENABLE_WEBSOCKET_CLIENT;ENABLE_GENERATE_NATIVE_PLUGINS_FOR_ASSEMBLIES_API;ENABLE_DIRECTOR_AUDIO;ENABLE_DIRECTOR_TEXTURE;ENABLE_MANAGED_JOBS;ENABLE_MANAGED_TRANSFORM_JOBS;ENABLE_MANAGED_ANIMATION_JOBS;ENABLE_MANAGED_AUDIO_JOBS;ENABLE_MANAGED_UNITYTLS;INCLUDE_DYNAMIC_GI;ENABLE_SCRIPTING_GC_WBARRIERS;PLATFORM_SUPPORTS_MONO;RENDER_SOFTWARE_CURSOR;ENABLE_MARSHALLING_TESTS;ENABLE_VIDEO;ENABLE_NAVIGATION_OFFMESHLINK_TO_NAVMESHLINK;ENABLE_ACCELERATOR_CLIENT_DEBUGGING;TEXTCORE_1_0_OR_NEWER;EDITOR_ONLY_NAVMESH_BUILDER_DEPRECATED;PLATFORM_STANDALONE_LINUX;PLATFORM_STANDALONE;UNITY_STANDALONE_LINUX;UNITY_STANDALONE;UNITY_STANDALONE_LINUX_API;ENABLE_RUNTIME_GI;ENABLE_MOVIES;ENABLE_NETWORK;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_CLUSTER_SYNC;ENABLE_CLUSTERINPUT;ENABLE_SPATIALTRACKING;ENABLE_MODULAR_UNITYENGINE_ASSEMBLIES;PLATFORM_SUPPORTS_SPLIT_GRAPHICS_JOBS;PLATFORM_USES_EXPLICIT_MEMORY_MANAGER_INITIALIZER;PLATFORM_SUPPORTS_DISPLAYINFO_API;ENABLE_MONO;NET_4_6;NET_UNITY_4_8;ENABLE_PROFILER;DEBUG;TRACE;UNITY_ASSERTIONS;UNITY_EDITOR;UNITY_EDITOR_64;UNITY_EDITOR_LINUX;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_BURST_AOT;UNITY_TEAM_LICENSE;ENABLE_CUSTOM_RENDER_TEXTURE;ENABLE_DIRECTOR;ENABLE_LOCALIZATION;ENABLE_SPRITES;ENABLE_TERRAIN;ENABLE_TILEMAP;ENABLE_TIMELINE;ENABLE_INPUT_SYSTEM;TEXTCORE_FONT_ENGINE_1_5_OR_NEWER;TEXTCORE_TEXT_ENGINE_1_5_OR_NEWER;TEXTCORE_FONT_ENGINE_1_6_OR_NEWER;CSHARP_7_OR_LATER;CSHARP_7_3_OR_NEWER False @@ -39,30 +39,45 @@ SDK Game:1 StandaloneLinux64:24 - 6000.2.13f1 + 6000.3.2f1 - - - + + + + + + + + + + + + + + + + + + @@ -71,483 +86,531 @@ - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.AIModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.AIModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.AccessibilityModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.AccessibilityModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.AdaptivePerformanceModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.AndroidJNIModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.AndroidJNIModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.AnimationModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.AnimationModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.AssetBundleModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.AssetBundleModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.AudioModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.AudioModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.ClothModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.ClothModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.ClusterInputModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.ClusterInputModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.ClusterRendererModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.ClusterRendererModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.ContentLoadModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.ContentLoadModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.CoreModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.CoreModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.CrashReportingModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.CrashReportingModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.DSPGraphModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.DSPGraphModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.DirectorModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.DirectorModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.GIModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.GIModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.GameCenterModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.GameCenterModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.GraphicsStateCollectionSerializerModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.GraphicsStateCollectionSerializerModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.GridModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.GridModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.HierarchyCoreModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.HierarchyCoreModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.HotReloadModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.HotReloadModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.IMGUIModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.IMGUIModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.IdentifiersModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.IdentifiersModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.ImageConversionModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.ImageConversionModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.InputModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.InputModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.InputForUIModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.InputForUIModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.InputLegacyModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.InputLegacyModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.JSONSerializeModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.JSONSerializeModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.LocalizationModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.LocalizationModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.MarshallingModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.MarshallingModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.MultiplayerModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.MultiplayerModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.ParticleSystemModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.ParticleSystemModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.PerformanceReportingModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.PerformanceReportingModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.PhysicsModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.PhysicsModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.Physics2DModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.Physics2DModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.PhysicsBackendPhysXModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.PropertiesModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.PropertiesModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.RenderAs2DModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.RuntimeInitializeOnLoadManagerInitializerModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.RuntimeInitializeOnLoadManagerInitializerModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.ScreenCaptureModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.ScreenCaptureModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.ShaderRuntimeModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.ShaderVariantAnalyticsModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.ShaderVariantAnalyticsModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.SharedInternalsModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.SharedInternalsModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.SpriteMaskModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.SpriteMaskModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.SpriteShapeModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.SpriteShapeModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.StreamingModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.StreamingModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.SubstanceModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.SubstanceModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.SubsystemsModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.SubsystemsModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.TLSModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.TLSModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.TerrainModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.TerrainModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.TerrainPhysicsModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.TerrainPhysicsModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.TextCoreFontEngineModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.TextCoreFontEngineModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.TextCoreTextEngineModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.TextCoreTextEngineModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.TextRenderingModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.TextRenderingModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.TilemapModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.TilemapModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UIModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.UIModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UIElementsModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.UIElementsModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UmbraModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.UmbraModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityAnalyticsModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityAnalyticsModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityAnalyticsCommonModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityAnalyticsCommonModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityConnectModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityConnectModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityConsentModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityConsentModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityCurlModule.dll - False - - - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityTestProtocolModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityCurlModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityWebRequestModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityWebRequestModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityWebRequestAssetBundleModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityWebRequestAssetBundleModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityWebRequestAudioModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityWebRequestAudioModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityWebRequestTextureModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityWebRequestTextureModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityWebRequestWWWModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityWebRequestWWWModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.VFXModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.VFXModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.VRModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.VRModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.VectorGraphicsModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.VehiclesModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.VehiclesModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.VideoModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.VideoModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.VirtualTexturingModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.VirtualTexturingModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.WindModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.WindModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEngine.XRModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEngine.XRModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.AccessibilityModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.AccessibilityModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.AdaptivePerformanceModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.AdaptivePerformanceModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.AssetComplianceModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.BuildProfileModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.BuildProfileModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.ClothModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.ClothModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.CoreBusinessMetricsModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.CoreBusinessMetricsModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.CoreModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.CoreModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.DeviceSimulatorModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.DeviceSimulatorModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.DiagnosticsModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.DiagnosticsModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.EditorToolbarModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.EditorToolbarModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.EmbreeModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.EmbreeModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.GIModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.GIModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.GraphViewModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.GraphViewModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.GraphicsStateCollectionSerializerModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.GraphicsStateCollectionSerializerModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.GridAndSnapModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.GridAndSnapModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.GridModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.GridModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.HierarchyModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.InAppPurchasingModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.InAppPurchasingModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.LevelPlayModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.LevelPlayModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.MediaModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.MultiplayerModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.MultiplayerModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.Physics2DModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.Physics2DModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.PhysicsModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.PhysicsModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.PlayModeModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.PresetsUIModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.PresetsUIModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.PropertiesModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.PropertiesModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.QuickSearchModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.QuickSearchModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.SafeModeModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.SafeModeModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.SceneTemplateModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.SceneTemplateModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.SceneViewModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.SceneViewModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.ShaderBuildSettingsModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.ShaderCompilationModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.ShaderFoundryModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.ShaderFoundryModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.SketchUpModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.SketchUpModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.SpriteMaskModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.SpriteMaskModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.SpriteShapeModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.SpriteShapeModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.SubstanceModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.SubstanceModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.TerrainModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.TerrainModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.TextCoreFontEngineModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.TextCoreFontEngineModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.TextCoreTextEngineModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.TextCoreTextEngineModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.TextRenderingModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.TextRenderingModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.TilemapModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.TilemapModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.TreeModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.TreeModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.UIAutomationModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.UIAutomationModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.UIBuilderModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.UIBuilderModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.UIElementsModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.UIElementsModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.UIElementsSamplesModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.UIElementsSamplesModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.UIToolkitAuthoringModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.UmbraModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.UmbraModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.UnityConnectModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.UnityConnectModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.VFXModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.VFXModule.dll + False + + + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.VectorGraphicsModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.VideoModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.VideoModule.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/Managed/UnityEngine/UnityEditor.XRModule.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/Managed/UnityEngine/UnityEditor.XRModule.dll False @@ -555,7 +618,7 @@ False - Library/PackageCache/com.unity.ext.nunit@b16e6d09cd93/net40/unity-custom/nunit.framework.dll + Library/PackageCache/com.unity.ext.nunit@ec2d0043d6fc/net40/unity-custom/nunit.framework.dll False @@ -563,7 +626,7 @@ False - Library/PackageCache/com.unity.nuget.mono-cecil@d78732e851eb/Mono.Cecil.dll + Library/PackageCache/com.unity.nuget.mono-cecil@ecb9724e46ff/Mono.Cecil.dll False @@ -571,503 +634,503 @@ False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/mscorlib.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/mscorlib.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Core.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Core.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Runtime.Serialization.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Runtime.Serialization.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Xml.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Xml.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Xml.Linq.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Xml.Linq.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Numerics.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Numerics.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Numerics.Vectors.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Numerics.Vectors.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Net.Http.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Net.Http.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.IO.Compression.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.IO.Compression.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Microsoft.CSharp.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Microsoft.CSharp.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Data.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Data.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Data.DataSetExtensions.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Data.DataSetExtensions.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Drawing.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Drawing.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.IO.Compression.FileSystem.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.IO.Compression.FileSystem.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.ComponentModel.Composition.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.ComponentModel.Composition.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Transactions.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/System.Transactions.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/Microsoft.Win32.Primitives.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/Microsoft.Win32.Primitives.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.AppContext.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.AppContext.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Buffers.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Buffers.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.Concurrent.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.Concurrent.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.NonGeneric.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.NonGeneric.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.Specialized.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.Specialized.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.Annotations.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.Annotations.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.EventBasedAsync.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.EventBasedAsync.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.Primitives.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.Primitives.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.TypeConverter.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.TypeConverter.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Console.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Console.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Data.Common.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Data.Common.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Contracts.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Contracts.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Debug.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Debug.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.FileVersionInfo.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.FileVersionInfo.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Process.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Process.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.StackTrace.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.StackTrace.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.TextWriterTraceListener.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.TextWriterTraceListener.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Tools.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Tools.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.TraceSource.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.TraceSource.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Drawing.Primitives.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Drawing.Primitives.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Dynamic.Runtime.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Dynamic.Runtime.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Globalization.Calendars.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Globalization.Calendars.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Globalization.Extensions.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Globalization.Extensions.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Globalization.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Globalization.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.Compression.ZipFile.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.Compression.ZipFile.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.DriveInfo.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.DriveInfo.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.Primitives.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.Primitives.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.Watcher.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.Watcher.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.IsolatedStorage.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.IsolatedStorage.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.MemoryMappedFiles.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.MemoryMappedFiles.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.Pipes.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.Pipes.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.UnmanagedMemoryStream.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.UnmanagedMemoryStream.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.Expressions.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.Expressions.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.Parallel.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.Parallel.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.Queryable.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.Queryable.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Memory.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Memory.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Http.Rtc.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Http.Rtc.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.NameResolution.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.NameResolution.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.NetworkInformation.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.NetworkInformation.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Ping.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Ping.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Primitives.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Primitives.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Requests.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Requests.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Security.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Security.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Sockets.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Sockets.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.WebHeaderCollection.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.WebHeaderCollection.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.WebSockets.Client.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.WebSockets.Client.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.WebSockets.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.WebSockets.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ObjectModel.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ObjectModel.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.DispatchProxy.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.DispatchProxy.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Emit.ILGeneration.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Emit.ILGeneration.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Emit.Lightweight.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Emit.Lightweight.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Emit.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Emit.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Extensions.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Extensions.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Primitives.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Primitives.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Resources.Reader.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Resources.Reader.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Resources.ResourceManager.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Resources.ResourceManager.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Resources.Writer.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Resources.Writer.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.CompilerServices.VisualC.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.CompilerServices.VisualC.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Extensions.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Extensions.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Handles.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Handles.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.InteropServices.RuntimeInformation.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.InteropServices.RuntimeInformation.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.InteropServices.WindowsRuntime.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.InteropServices.WindowsRuntime.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.InteropServices.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.InteropServices.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Numerics.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Numerics.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Formatters.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Formatters.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Json.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Json.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Primitives.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Primitives.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Xml.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Xml.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Claims.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Claims.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Algorithms.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Algorithms.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Csp.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Csp.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Encoding.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Encoding.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Primitives.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Primitives.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.X509Certificates.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.X509Certificates.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Principal.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Principal.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.SecureString.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.SecureString.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Duplex.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Duplex.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Http.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Http.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.NetTcp.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.NetTcp.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Primitives.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Primitives.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Security.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Security.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Text.Encoding.Extensions.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Text.Encoding.Extensions.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Text.Encoding.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Text.Encoding.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Text.RegularExpressions.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Text.RegularExpressions.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Overlapped.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Overlapped.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Tasks.Extensions.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Tasks.Extensions.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Tasks.Parallel.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Tasks.Parallel.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Tasks.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Tasks.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Thread.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Thread.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.ThreadPool.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.ThreadPool.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Timer.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Timer.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ValueTuple.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ValueTuple.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.ReaderWriter.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.ReaderWriter.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XDocument.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XDocument.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XPath.XDocument.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XPath.XDocument.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XPath.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XPath.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XmlDocument.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XmlDocument.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XmlSerializer.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XmlSerializer.dll False - /home/pascal/Unity/Hub/Editor/6000.2.13f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/netstandard.dll + /home/pascal/Unity/Hub/Editor/6000.3.2f1/Editor/Data/UnityReferenceAssemblies/unity-4.8-api/Facades/netstandard.dll False @@ -1078,6 +1141,10 @@ Library/ScriptAssemblies/Unity.RenderPipelines.Core.Editor.dll False + + Library/ScriptAssemblies/Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary.dll + False + Library/ScriptAssemblies/Unity.TextMeshPro.Editor.dll False @@ -1090,6 +1157,10 @@ Library/ScriptAssemblies/Unity.VisualStudio.Editor.dll False + + Library/ScriptAssemblies/Unity.Rendering.LightTransport.Editor.dll + False + Library/ScriptAssemblies/Unity.AI.Navigation.dll False @@ -1122,8 +1193,8 @@ Library/ScriptAssemblies/Unity.RenderPipelines.Universal.Shaders.dll False - - Library/ScriptAssemblies/UnityEngine.UI.dll + + Library/ScriptAssemblies/Unity.RenderPipelines.Universal.2D.Editor.Overrides.dll False @@ -1150,10 +1221,18 @@ Library/ScriptAssemblies/Unity.AI.Navigation.Editor.dll False + + Library/ScriptAssemblies/UnityEngine.UI.dll + False + Library/ScriptAssemblies/PPv2URPConverters.dll False + + Library/ScriptAssemblies/Unity.InternalAPIEngineBridge.004.dll + False + Library/ScriptAssemblies/Unity.RenderPipelines.Core.Runtime.Shared.dll False @@ -1182,10 +1261,6 @@ Library/ScriptAssemblies/Unity.Burst.Editor.dll False - - Library/ScriptAssemblies/Unity.Rendering.LightTransport.Runtime.dll - False - Library/ScriptAssemblies/Unity.Mathematics.Editor.dll False @@ -1194,8 +1269,8 @@ Library/ScriptAssemblies/Unity.RenderPipelines.Universal.Config.Runtime.dll False - - Library/ScriptAssemblies/Unity.RenderPipeline.Universal.ShaderLibrary.dll + + Library/ScriptAssemblies/Unity.UnifiedRayTracing.Runtime.dll False @@ -1206,8 +1281,8 @@ Library/ScriptAssemblies/Unity.ShaderGraph.Editor.dll False - - Library/ScriptAssemblies/Unity.Rendering.LightTransport.Editor.dll + + Library/ScriptAssemblies/Unity.RenderPipeline.Universal.ShaderLibrary.dll False @@ -1230,10 +1305,6 @@ Library/ScriptAssemblies/UnityEditor.UI.dll False - - Library/ScriptAssemblies/Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary.dll - False - diff --git a/Assets/NanoBrain/Editor/NanoBrain_Editor.cs b/Assets/NanoBrain/Editor/NanoBrain_Editor.cs index 51e6694..b070c5e 100644 --- a/Assets/NanoBrain/Editor/NanoBrain_Editor.cs +++ b/Assets/NanoBrain/Editor/NanoBrain_Editor.cs @@ -54,7 +54,7 @@ public class NanoBrain_Editor : Editor { DrawGraph(); EditorGUILayout.TextField("Name", currentNucleus.name); - EditorGUILayout.Vector3Field("Output Value", currentNucleus.outputValue); + EditorGUILayout.Vector3Field("Output Value", currentNucleus.outputValue.ToVector3()); if (currentNucleus.synapses.Count > 0) { EditorGUI.indentLevel++; //foreach ((Nucleus nucleus, float weight) in currentNucleus.synapses) { @@ -65,7 +65,7 @@ public class NanoBrain_Editor : Editor { EditorGUI.BeginDisabledGroup(nucleus.isSleeping); EditorGUILayout.BeginHorizontal(); - EditorGUILayout.Vector3Field(nucleus.name, nucleus.outputValue); + EditorGUILayout.Vector3Field(nucleus.name, nucleus.outputValue.ToVector3()); EditorGUILayout.FloatField(weight, GUILayout.Width(50)); EditorGUILayout.EndHorizontal(); @@ -265,7 +265,7 @@ public class NanoBrain_Editor : Editor { // Handles.color = Color.green; // Handles.DrawLine(brain.transform.position, brain.transform.position + Vector3.up); Handles.color = Color.yellow; - Vector3 worldForce = brain.transform.TransformDirection(this.currentNucleus.outputValue); + Vector3 worldForce = brain.transform.TransformDirection(this.currentNucleus.outputValue.ToVector3()); //Debug.DrawRay(position, worldForce * 10, Color.yellow); Handles.DrawLine(position, position + worldForce * 10); } diff --git a/Assets/NanoBrain/LinearAlgebra-csharp.meta b/Assets/NanoBrain/LinearAlgebra-csharp.meta new file mode 100644 index 0000000..38d4620 --- /dev/null +++ b/Assets/NanoBrain/LinearAlgebra-csharp.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b011ef22eaa3add3591b513363fbbd0a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/NanoBrain/NanoBrain-Unity.code-workspace b/Assets/NanoBrain/NanoBrain-Unity.code-workspace new file mode 100644 index 0000000..5194438 --- /dev/null +++ b/Assets/NanoBrain/NanoBrain-Unity.code-workspace @@ -0,0 +1,12 @@ +{ + "folders": [ + { + "path": "../.." + }, + { + "name": "LinearAlgebra-csharp", + "path": "LinearAlgebra-csharp" + } + ], + "settings": {} +} \ No newline at end of file diff --git a/Assets/NanoBrain/NanoBrain-Unity.code-workspace.meta b/Assets/NanoBrain/NanoBrain-Unity.code-workspace.meta new file mode 100644 index 0000000..65bb132 --- /dev/null +++ b/Assets/NanoBrain/NanoBrain-Unity.code-workspace.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: cfec45da5945b94d684a763d86b0dcf8 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index 2ec6156..5468235 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -1,4 +1,5 @@ using UnityEngine; +using LinearAlgebra; [System.Serializable] public class Neuroid : Nucleus { @@ -37,7 +38,6 @@ public class Neuroid : Nucleus { return Synapse.Presets.Reciprocal(1); default: this.curveMax = 1; - //return AnimationCurve.Constant(0, 1, 1); return this.curve; } } @@ -63,42 +63,34 @@ public class Neuroid : Nucleus { } public void SetInput(Neuroid input) { - // if (this.synapses.ContainsKey(input) == false) - // this.synapses[input] = 1.0f; if (this.SynapseExists(input) == false) this.SetWeight(input, 1.0f); UpdateState(); } public void SetInput(Neuroid input, float weight) { - //this.synapses[input] = weight; this.SetWeight(input, weight); UpdateState(); } public virtual void UpdateState() { Vector3 result = Vector3.zero; - //foreach ((Nucleus nucleus, float weight) in this.synapses) { foreach (Synapse synapse in this.synapses) { Nucleus synapseNucleus = synapse.nucleus; if (synapseNucleus is Neuroid neuroid && neuroid.isSleeping) continue; - Vector3 direction = synapseNucleus.outputValue.normalized; - float magnitude = synapseNucleus.outputValue.magnitude; + Vector3 direction = synapseNucleus.outputValue.direction.ToVector3(); float weight = synapse.weight; - magnitude = weight * curve.Evaluate(synapseNucleus.outputValue.magnitude); - // magnitude = weight * Mathf.Pow(magnitude, exponent); - // if (inverse && magnitude > 0) - // magnitude = 1 / magnitude; - result += direction * magnitude; + float magnitude = weight * curve.Evaluate(synapseNucleus.outputValue.magnitude); + result += direction * magnitude; } if (average && this.synapses.Count > 0) result /= this.synapses.Count; - this.outputValue = result; + this.outputValue = Spherical.FromVector3(result); this.stale = 0; foreach (Receiver receiver in this.receivers) { @@ -107,8 +99,5 @@ public class Neuroid : Nucleus { } } - // public bool IsStale() { - // return this.stale > 2; - // } } diff --git a/Assets/NanoBrain/Nucleus.cs b/Assets/NanoBrain/Nucleus.cs index 33e8493..9c195ca 100644 --- a/Assets/NanoBrain/Nucleus.cs +++ b/Assets/NanoBrain/Nucleus.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using UnityEngine; using UnityEditor; +using LinearAlgebra; [System.Serializable] public class Nucleus { @@ -63,7 +64,7 @@ public class Nucleus { public NanoBrainObj brain { get; set; } - public virtual Vector3 outputValue { get; set; } + public virtual Spherical outputValue { get; set; } [System.NonSerialized] public int stale = 0; diff --git a/Assets/NanoBrain/Perceptoid.cs b/Assets/NanoBrain/Perceptoid.cs index b6be740..c2acb1f 100644 --- a/Assets/NanoBrain/Perceptoid.cs +++ b/Assets/NanoBrain/Perceptoid.cs @@ -1,4 +1,5 @@ using UnityEngine; +using LinearAlgebra; [System.Serializable] public class Perceptoid : Neuroid { @@ -88,9 +89,9 @@ public class Perceptoid : Neuroid { this.thingType = thingType; this.receptor.thingType = thingType; - this.receptor.localPosition = Vector3.zero; + this.receptor.localPosition = Spherical.zero; - this.outputValue = Vector3.zero; + this.outputValue = Spherical.zero; this.receivers = new(); this.AddReceiver(velocityNeuroid); @@ -98,11 +99,11 @@ public class Perceptoid : Neuroid { } public override void UpdateState() { - Vector3 result = receptor.localPosition; + Vector3 result = receptor.localPosition.ToVector3(); foreach (Synapse synapse in this.synapses) { Nucleus nucleus = synapse.nucleus; float weight = synapse.weight; - Vector3 direction = nucleus.outputValue.normalized; + Vector3 direction = nucleus.outputValue.normalized.ToVector3(); float magnitude = nucleus.outputValue.magnitude; magnitude = weight * Mathf.Pow(magnitude, exponent); @@ -113,16 +114,16 @@ public class Perceptoid : Neuroid { if (average && this.synapses.Count > 0) result /= this.synapses.Count + 1; - this.outputValue = result; + this.outputValue = Spherical.FromVector3(result); foreach (Receiver receiver in this.receivers) if (receiver.nucleus is Neuroid neuroid) neuroid.SetInput(this); this.stale = 0; } - public void UpdateState(int thingId, Vector3 receptorValue) { + public void UpdateState(int thingId, Spherical receptorValue) { this.thingId = thingId; - Vector3 result = receptorValue; + Spherical result = receptorValue; // foreach (Synapse synapse in this.synapses) { // Nucleus nucleus = synapse.nucleus; // float weight = synapse.weight; diff --git a/Assets/NanoBrain/Receptor.cs b/Assets/NanoBrain/Receptor.cs index 9f5fbce..5f64972 100644 --- a/Assets/NanoBrain/Receptor.cs +++ b/Assets/NanoBrain/Receptor.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Linq; using UnityEngine; +using LinearAlgebra; public class Receptor { @@ -9,7 +10,7 @@ public class Receptor { public int thingId; public int thingType; - public Vector3 localPosition; + public Spherical localPosition; public Receptor(Perceptoid perceptoid) { this.perceptei.Add(perceptoid); @@ -18,7 +19,7 @@ public class Receptor { public virtual void ProcessStimulus(int thingId, Vector3 localPosition) { this.thingId = thingId; - this.localPosition = localPosition; + this.localPosition = Spherical.FromVector3(localPosition); Perceptoid selectedPerceptoid = null; foreach (Perceptoid perceptoid in this.perceptei) { diff --git a/Assets/NanoBrain/SensoryNeuroid.cs b/Assets/NanoBrain/SensoryNeuroid.cs index c716cca..d0948a7 100644 --- a/Assets/NanoBrain/SensoryNeuroid.cs +++ b/Assets/NanoBrain/SensoryNeuroid.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Linq; using UnityEngine; +using LinearAlgebra; // public class Receptor { @@ -52,9 +53,9 @@ public class SensoryNeuroid : Neuroid { this.name = name + ": position"; this.receptor.thingType = thingId; - this.receptor.localPosition = Vector3.zero; + this.receptor.localPosition = Spherical.zero; - this.outputValue = Vector3.zero; + this.outputValue = Spherical.zero; this.receivers = new(); this.AddReceiver(velocityNeuroid); @@ -64,13 +65,14 @@ public class SensoryNeuroid : Neuroid { } public override void UpdateState() { - Vector3 result = receptor.localPosition; + Vector3 result = receptor.localPosition.ToVector3(); //foreach ((Nucleus nucleus, float weight) in this.synapses) { foreach (Synapse synapse in this.synapses) { Nucleus nucleus = synapse.nucleus; float weight = synapse.weight; - Vector3 direction = nucleus.outputValue.normalized; - float magnitude = nucleus.outputValue.magnitude; + Vector3 outputV3 = nucleus.outputValue.ToVector3(); + Vector3 direction = outputV3.normalized; + float magnitude = outputV3.magnitude; magnitude = weight * Mathf.Pow(magnitude, exponent); if (inverse) @@ -80,7 +82,7 @@ public class SensoryNeuroid : Neuroid { if (average && this.synapses.Count > 0) result /= this.synapses.Count + 1; - this.outputValue = result; + this.outputValue = Spherical.FromVector3(result); //foreach (Neuroid neuroid in this.receivers) foreach (Receiver receiver in this.receivers) if (receiver.nucleus is Neuroid neuroid) @@ -107,16 +109,17 @@ public class VelocityNeuroid : Neuroid { public override void UpdateState() { // Assuming only one synapse for now.... //Vector3 currentPosition = this.synapses.First().Key.outputValue; - Vector3 currentPosition = this.synapses.First().nucleus.outputValue; + Spherical currentPosition = this.synapses.First().nucleus.outputValue; + Vector3 currentPositionV3 = currentPosition.ToVector3(); float currentValueTime = Time.time; if (lastValueTime != 0) { float deltaTime = currentValueTime - lastValueTime; - Vector3 translation = currentPosition - lastPosition; + Vector3 translation = currentPositionV3 - lastPosition; Vector3 velocity = translation / deltaTime; // No activation function... - this.outputValue = velocity; + this.outputValue = Spherical.FromVector3(velocity); this.stale = 0; //foreach (Neuroid receiver in receivers) @@ -127,6 +130,6 @@ public class VelocityNeuroid : Neuroid { } this.lastValueTime = currentValueTime; - this.lastPosition = currentPosition; + this.lastPosition = currentPositionV3; } } \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs index 7c86c74..f1946f3 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs @@ -341,7 +341,7 @@ public class GraphBoardView : VisualElement { currentNucleus.name = EditorGUILayout.TextField(currentNucleus.name); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Output Value", GUILayout.Width(100)); - EditorGUILayout.Vector3Field(GUIContent.none, currentNucleus.outputValue); + EditorGUILayout.Vector3Field(GUIContent.none, currentNucleus.outputValue.ToVector3()); EditorGUILayout.EndHorizontal(); if (currentNucleus.synapses.Count > 0) { EditorGUILayout.LabelField("Synapses"); @@ -360,7 +360,7 @@ public class GraphBoardView : VisualElement { // currentNucleus.synapses[nucleus] = EditorGUILayout.FloatField(weight, GUILayout.Width(40)); synapse.weight = EditorGUILayout.FloatField(synapse.weight, GUILayout.Width(40)); EditorGUI.indentLevel++; - EditorGUILayout.Vector3Field(GUIContent.none, synapse.nucleus.outputValue, GUILayout.Width(180)); + EditorGUILayout.Vector3Field(GUIContent.none, synapse.nucleus.outputValue.ToVector3(), GUILayout.Width(180)); EditorGUILayout.EndHorizontal(); EditorGUI.EndDisabledGroup(); diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs index 43a2af7..8db7231 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs @@ -455,7 +455,7 @@ public class NanoBrainInspector : Editor { DisconnectNucleus(this.currentNucleus); if (this.gameObject != null) { - Vector3 worldVector = this.gameObject.transform.TransformVector(this.currentNucleus.outputValue); + Vector3 worldVector = this.gameObject.transform.TransformVector(this.currentNucleus.outputValue.ToVector3()); Debug.DrawRay(this.gameObject.transform.position, worldVector, Color.yellow); } }); diff --git a/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs b/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs index 137125a..145e14d 100644 --- a/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs +++ b/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using UnityEngine; +using LinearAlgebra; [CreateAssetMenu(menuName = "Passer/NanoBrain")] public class NanoBrainObj : ScriptableObject, ISerializationCallbackReceiver { @@ -33,12 +34,12 @@ public class NanoBrainObj : ScriptableObject, ISerializationCallbackReceiver { foreach (Nucleus nucleus in nuclei) { nucleus.stale++; if (nucleus.isSleeping) - nucleus.outputValue = Vector3.zero; + nucleus.outputValue = Spherical.zero; } foreach (Perceptoid perception in perceptei) { perception.stale++; if (perception.isSleeping) - perception.outputValue = Vector3.zero; + perception.outputValue = Spherical.zero; } } diff --git a/Assets/Scenes/Boids/Scripts/Boid.cs b/Assets/Scenes/Boids/Scripts/Boid.cs index c2cc778..43da333 100644 --- a/Assets/Scenes/Boids/Scripts/Boid.cs +++ b/Assets/Scenes/Boids/Scripts/Boid.cs @@ -55,7 +55,7 @@ public class Boid : MonoBehaviour { boundaryReceptor.ProcessStimulus(777, desiredLocalSpace); } - Vector3 worldForce = this.transform.TransformDirection(nanoBrain.root.outputValue); + Vector3 worldForce = this.transform.TransformDirection(nanoBrain.root.outputValue.ToVector3()); this.velocity = (1 - sc.inertia) * (worldForce * Time.deltaTime) + sc.inertia * velocity; if (this.velocity.magnitude > 0) diff --git a/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs b/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs index 92f9950..bbe6200 100644 --- a/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs +++ b/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs @@ -1,4 +1,5 @@ using UnityEngine; +using LinearAlgebra; public class Swarming : Nucleus { public Neuroid cohesion; @@ -8,7 +9,7 @@ public class Swarming : Nucleus { public Neuroid output; - public override Vector3 outputValue { get => output.outputValue; set => output.outputValue = value; } + public override Spherical outputValue { get => output.outputValue; set => output.outputValue = value; } public Swarming(NanoBrainObj brain, Perception perception, SwarmControl sc) : base("Swarming Nucleus") { this.cohesion = new(brain, "Cohesion") { inverse = false }; diff --git a/Packages/manifest.json b/Packages/manifest.json index 4e3816e..e74462a 100644 --- a/Packages/manifest.json +++ b/Packages/manifest.json @@ -4,13 +4,14 @@ "com.unity.collab-proxy": "2.10.2", "com.unity.ide.rider": "3.0.38", "com.unity.ide.visualstudio": "2.0.25", - "com.unity.inputsystem": "1.14.2", - "com.unity.multiplayer.center": "1.0.0", - "com.unity.render-pipelines.universal": "17.2.0", + "com.unity.inputsystem": "1.17.0", + "com.unity.multiplayer.center": "1.0.1", + "com.unity.render-pipelines.universal": "17.3.0", "com.unity.test-framework": "1.6.0", "com.unity.timeline": "1.8.9", "com.unity.ugui": "2.0.0", "com.unity.modules.accessibility": "1.0.0", + "com.unity.modules.adaptiveperformance": "1.0.0", "com.unity.modules.ai": "1.0.0", "com.unity.modules.androidjni": "1.0.0", "com.unity.modules.animation": "1.0.0", @@ -37,6 +38,7 @@ "com.unity.modules.unitywebrequestaudio": "1.0.0", "com.unity.modules.unitywebrequesttexture": "1.0.0", "com.unity.modules.unitywebrequestwww": "1.0.0", + "com.unity.modules.vectorgraphics": "1.0.0", "com.unity.modules.vehicles": "1.0.0", "com.unity.modules.video": "1.0.0", "com.unity.modules.vr": "1.0.0", diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json index a197b82..8bcb908 100644 --- a/Packages/packages-lock.json +++ b/Packages/packages-lock.json @@ -10,7 +10,7 @@ "url": "https://packages.unity.com" }, "com.unity.burst": { - "version": "1.8.25", + "version": "1.8.26", "depth": 2, "source": "registry", "dependencies": { @@ -33,8 +33,8 @@ "dependencies": { "com.unity.burst": "1.8.23", "com.unity.mathematics": "1.3.2", - "com.unity.nuget.mono-cecil": "1.11.5", "com.unity.test-framework": "1.4.6", + "com.unity.nuget.mono-cecil": "1.11.5", "com.unity.test-framework.performance": "3.0.3" }, "url": "https://packages.unity.com" @@ -64,7 +64,7 @@ "url": "https://packages.unity.com" }, "com.unity.inputsystem": { - "version": "1.14.2", + "version": "1.17.0", "depth": 0, "source": "registry", "dependencies": { @@ -73,14 +73,14 @@ "url": "https://packages.unity.com" }, "com.unity.mathematics": { - "version": "1.3.2", + "version": "1.3.3", "depth": 2, "source": "registry", "dependencies": {}, "url": "https://packages.unity.com" }, "com.unity.multiplayer.center": { - "version": "1.0.0", + "version": "1.0.1", "depth": 0, "source": "builtin", "dependencies": { @@ -88,14 +88,14 @@ } }, "com.unity.nuget.mono-cecil": { - "version": "1.11.5", + "version": "1.11.6", "depth": 3, "source": "registry", "dependencies": {}, "url": "https://packages.unity.com" }, "com.unity.render-pipelines.core": { - "version": "17.2.0", + "version": "17.3.0", "depth": 1, "source": "builtin", "dependencies": { @@ -105,17 +105,16 @@ "com.unity.collections": "2.4.3", "com.unity.modules.physics": "1.0.0", "com.unity.modules.terrain": "1.0.0", - "com.unity.modules.jsonserialize": "1.0.0", - "com.unity.rendering.light-transport": "1.0.1" + "com.unity.modules.jsonserialize": "1.0.0" } }, "com.unity.render-pipelines.universal": { - "version": "17.2.0", + "version": "17.3.0", "depth": 0, "source": "builtin", "dependencies": { - "com.unity.render-pipelines.core": "17.2.0", - "com.unity.shadergraph": "17.2.0", + "com.unity.render-pipelines.core": "17.3.0", + "com.unity.shadergraph": "17.3.0", "com.unity.render-pipelines.universal-config": "17.0.3" } }, @@ -127,29 +126,19 @@ "com.unity.render-pipelines.core": "17.0.3" } }, - "com.unity.rendering.light-transport": { - "version": "1.0.1", - "depth": 2, - "source": "builtin", - "dependencies": { - "com.unity.collections": "2.2.0", - "com.unity.mathematics": "1.2.4", - "com.unity.modules.terrain": "1.0.0" - } - }, "com.unity.searcher": { - "version": "4.9.3", + "version": "4.9.4", "depth": 2, "source": "registry", "dependencies": {}, "url": "https://packages.unity.com" }, "com.unity.shadergraph": { - "version": "17.2.0", + "version": "17.3.0", "depth": 1, "source": "builtin", "dependencies": { - "com.unity.render-pipelines.core": "17.2.0", + "com.unity.render-pipelines.core": "17.3.0", "com.unity.searcher": "4.9.3" } }, @@ -178,9 +167,9 @@ "depth": 0, "source": "registry", "dependencies": { + "com.unity.modules.audio": "1.0.0", "com.unity.modules.director": "1.0.0", "com.unity.modules.animation": "1.0.0", - "com.unity.modules.audio": "1.0.0", "com.unity.modules.particlesystem": "1.0.0" }, "url": "https://packages.unity.com" @@ -200,6 +189,14 @@ "source": "builtin", "dependencies": {} }, + "com.unity.modules.adaptiveperformance": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.subsystems": "1.0.0" + } + }, "com.unity.modules.ai": { "version": "1.0.0", "depth": 0, @@ -407,6 +404,16 @@ "com.unity.modules.imageconversion": "1.0.0" } }, + "com.unity.modules.vectorgraphics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.uielements": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0", + "com.unity.modules.imgui": "1.0.0" + } + }, "com.unity.modules.vehicles": { "version": "1.0.0", "depth": 0, diff --git a/ProjectSettings/GraphicsSettings.asset b/ProjectSettings/GraphicsSettings.asset index 02f1134..abe4fcd 100644 --- a/ProjectSettings/GraphicsSettings.asset +++ b/ProjectSettings/GraphicsSettings.asset @@ -58,7 +58,9 @@ GraphicsSettings: m_FogKeepExp2: 1 m_AlbedoSwatchInfos: [] m_RenderPipelineGlobalSettingsMap: - UnityEngine.Rendering.Universal.UniversalRenderPipeline: {fileID: 11400000, guid: 370d27fa5af5291e18529fa336759ac9, type: 2} + UnityEngine.Rendering.Universal.UniversalRenderPipeline: {fileID: 11400000, guid: 2acc6984d25d4a508a6d7042927d3083, type: 2} + m_ShaderBuildSettings: + keywordDeclarationOverrides: [] m_LightsUseLinearIntensity: 1 m_LightsUseColorTemperature: 1 m_LogWhenShaderIsCompiled: 0 diff --git a/ProjectSettings/Packages/com.unity.dedicated-server/MultiplayerRolesSettings.asset b/ProjectSettings/Packages/com.unity.dedicated-server/MultiplayerRolesSettings.asset new file mode 100644 index 0000000..d72800d --- /dev/null +++ b/ProjectSettings/Packages/com.unity.dedicated-server/MultiplayerRolesSettings.asset @@ -0,0 +1,17 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &1 +MonoBehaviour: + m_ObjectHideFlags: 53 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 15023, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: UnityEditor.MultiplayerModule.dll::UnityEditor.Multiplayer.Internal.MultiplayerRolesSettings + m_MultiplayerRoleForClassicProfile: + m_Keys: [] + m_Values: diff --git a/ProjectSettings/ProjectVersion.txt b/ProjectSettings/ProjectVersion.txt index 48c0834..879b68f 100644 --- a/ProjectSettings/ProjectVersion.txt +++ b/ProjectSettings/ProjectVersion.txt @@ -1,2 +1,2 @@ -m_EditorVersion: 6000.2.13f1 -m_EditorVersionWithRevision: 6000.2.13f1 (abdb44fca7f7) +m_EditorVersion: 6000.3.2f1 +m_EditorVersionWithRevision: 6000.3.2f1 (a9779f353c9b) From de74789cb5b3dae3e73c010e391068d42f824ca4 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 5 Jan 2026 10:55:01 +0100 Subject: [PATCH 029/179] Removed linearAlgebra submodule --- Assembly-CSharp-Editor.csproj | 7 ++----- Assembly-CSharp.csproj | 19 ++++++++++++------- Assets/NanoBrain/LinearAlgebra-csharp.meta | 8 -------- Packages/manifest.json | 4 +--- Packages/packages-lock.json | 17 ++++------------- 5 files changed, 19 insertions(+), 36 deletions(-) delete mode 100644 Assets/NanoBrain/LinearAlgebra-csharp.meta diff --git a/Assembly-CSharp-Editor.csproj b/Assembly-CSharp-Editor.csproj index 6886476..99bbb27 100644 --- a/Assembly-CSharp-Editor.csproj +++ b/Assembly-CSharp-Editor.csproj @@ -10,6 +10,7 @@ + false @@ -35,7 +36,7 @@ Package - 2.0.25 + 2.0.26 SDK Editor:5 StandaloneLinux64:24 @@ -1315,10 +1316,6 @@ Library/ScriptAssemblies/Unity.InputSystem.dll False - - Library/ScriptAssemblies/Unity.Rider.Editor.dll - False - Library/ScriptAssemblies/Unity.AI.Navigation.Editor.ConversionSystem.dll False diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index 4f41e1b..f174f82 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -10,6 +10,7 @@ + false @@ -35,7 +36,7 @@ Package - 2.0.25 + 2.0.26 SDK Game:1 StandaloneLinux64:24 @@ -51,23 +52,31 @@ - + + + + - + + + + + + @@ -1293,10 +1302,6 @@ Library/ScriptAssemblies/Unity.InputSystem.dll False - - Library/ScriptAssemblies/Unity.Rider.Editor.dll - False - Library/ScriptAssemblies/Unity.AI.Navigation.Editor.ConversionSystem.dll False diff --git a/Assets/NanoBrain/LinearAlgebra-csharp.meta b/Assets/NanoBrain/LinearAlgebra-csharp.meta deleted file mode 100644 index 38d4620..0000000 --- a/Assets/NanoBrain/LinearAlgebra-csharp.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: b011ef22eaa3add3591b513363fbbd0a -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/manifest.json b/Packages/manifest.json index e74462a..7a7080d 100644 --- a/Packages/manifest.json +++ b/Packages/manifest.json @@ -2,12 +2,10 @@ "dependencies": { "com.unity.ai.navigation": "2.0.9", "com.unity.collab-proxy": "2.10.2", - "com.unity.ide.rider": "3.0.38", - "com.unity.ide.visualstudio": "2.0.25", + "com.unity.ide.visualstudio": "2.0.26", "com.unity.inputsystem": "1.17.0", "com.unity.multiplayer.center": "1.0.1", "com.unity.render-pipelines.universal": "17.3.0", - "com.unity.test-framework": "1.6.0", "com.unity.timeline": "1.8.9", "com.unity.ugui": "2.0.0", "com.unity.modules.accessibility": "1.0.0", diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json index 8bcb908..1b5c786 100644 --- a/Packages/packages-lock.json +++ b/Packages/packages-lock.json @@ -41,25 +41,16 @@ }, "com.unity.ext.nunit": { "version": "2.0.5", - "depth": 1, + "depth": 2, "source": "builtin", "dependencies": {} }, - "com.unity.ide.rider": { - "version": "3.0.38", - "depth": 0, - "source": "registry", - "dependencies": { - "com.unity.ext.nunit": "1.0.6" - }, - "url": "https://packages.unity.com" - }, "com.unity.ide.visualstudio": { - "version": "2.0.25", + "version": "2.0.26", "depth": 0, "source": "registry", "dependencies": { - "com.unity.test-framework": "1.1.31" + "com.unity.test-framework": "1.1.33" }, "url": "https://packages.unity.com" }, @@ -144,7 +135,7 @@ }, "com.unity.test-framework": { "version": "1.6.0", - "depth": 0, + "depth": 1, "source": "builtin", "dependencies": { "com.unity.ext.nunit": "2.0.3", From 220e1e4ead6d3b8a75c515d83995e6e5a4ec42bc Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 5 Jan 2026 10:55:07 +0100 Subject: [PATCH 030/179] Squashed 'Assets/NanoBrain/LinearAlgebra/' content from commit 15c08f2 git-subtree-dir: Assets/NanoBrain/LinearAlgebra git-subtree-split: 15c08f215655988682ecc6207c2783fa047b65e3 --- .editorconfig | 19 + .gitea/workflows/unit_tests.yaml | 37 ++ .gitignore | 5 + LinearAlgebra-csharp.sln | 30 ++ src/Angle.cs | 332 +++++++++++++++ src/Decomposition.cs | 287 +++++++++++++ src/Direction.cs | 181 ++++++++ src/Float.cs | 41 ++ src/LinearAlgebra.csproj | 14 + src/Matrix.cs | 689 +++++++++++++++++++++++++++++++ src/Quat32.cs | 87 ++++ src/Quaternion.cs | 608 +++++++++++++++++++++++++++ src/Spherical.cs | 185 +++++++++ src/SwingTwist.cs | 116 ++++++ src/Vector2Float.cs | 483 ++++++++++++++++++++++ src/Vector2Int.cs | 176 ++++++++ src/Vector3Float.cs | 399 ++++++++++++++++++ src/Vector3Int.cs | 273 ++++++++++++ src/float16.cs | 322 +++++++++++++++ test/AngleTest.cs | 497 ++++++++++++++++++++++ test/DirectionTest.cs | 201 +++++++++ test/LinearAlgebra_Test.csproj | 19 + test/QuaternionTest.cs | 185 +++++++++ test/SphericalTest.cs | 53 +++ test/SwingTwistTest.cs | 131 ++++++ test/Vector2FloatTest.cs | 364 ++++++++++++++++ test/Vector2IntTest.cs | 270 ++++++++++++ test/Vector3FloatTest.cs | 581 ++++++++++++++++++++++++++ test/Vector3IntTest.cs | 349 ++++++++++++++++ 29 files changed, 6934 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitea/workflows/unit_tests.yaml create mode 100644 .gitignore create mode 100644 LinearAlgebra-csharp.sln create mode 100644 src/Angle.cs create mode 100644 src/Decomposition.cs create mode 100644 src/Direction.cs create mode 100644 src/Float.cs create mode 100644 src/LinearAlgebra.csproj create mode 100644 src/Matrix.cs create mode 100644 src/Quat32.cs create mode 100644 src/Quaternion.cs create mode 100644 src/Spherical.cs create mode 100644 src/SwingTwist.cs create mode 100644 src/Vector2Float.cs create mode 100644 src/Vector2Int.cs create mode 100644 src/Vector3Float.cs create mode 100644 src/Vector3Int.cs create mode 100644 src/float16.cs create mode 100644 test/AngleTest.cs create mode 100644 test/DirectionTest.cs create mode 100644 test/LinearAlgebra_Test.csproj create mode 100644 test/QuaternionTest.cs create mode 100644 test/SphericalTest.cs create mode 100644 test/SwingTwistTest.cs create mode 100644 test/Vector2FloatTest.cs create mode 100644 test/Vector2IntTest.cs create mode 100644 test/Vector3FloatTest.cs create mode 100644 test/Vector3IntTest.cs diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..1ec7f97 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,19 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = crlf +charset = utf-8 +trim_trailing_whitespace = false +insert_final_newline = false +max_line_length = 80 + +[*.cs] +csharp_new_line_before_open_brace = none +# Suppress warnings everywhere +dotnet_diagnostic.IDE1006.severity = none +dotnet_diagnostic.IDE0130.severity = none \ No newline at end of file diff --git a/.gitea/workflows/unit_tests.yaml b/.gitea/workflows/unit_tests.yaml new file mode 100644 index 0000000..e98b26e --- /dev/null +++ b/.gitea/workflows/unit_tests.yaml @@ -0,0 +1,37 @@ +name: Build and Run C# Unit Tests + +on: + push: + branches: + - '**' + pull_request: + branches: + - '**' + +jobs: + build-and-test: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Setup .NET + uses: actions/setup-dotnet@v1 + with: + dotnet-version: '8.0.x' # Specify the .NET SDK version + + - name: Check Current Directory + run: pwd # Logs the current working directory + + - name: List Files + run: ls -la # Lists all files in the current directory + + - name: Restore Dependencies + run: dotnet restore ./LinearAlgebra-csharp.sln # Restore NuGet packages + + - name: Build the Project + run: dotnet build ./LinearAlgebra-csharp.sln --configuration Release # Build the C# project + + - name: Run Unit Tests + run: dotnet test ./test/LinearAlgebra_Test.csproj --configuration Release # Execute unit tests diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b32a30c --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +DoxyGen/DoxyWarnLogfile.txt +.vscode/settings.json +**bin +**obj +**.meta diff --git a/LinearAlgebra-csharp.sln b/LinearAlgebra-csharp.sln new file mode 100644 index 0000000..4b13b2b --- /dev/null +++ b/LinearAlgebra-csharp.sln @@ -0,0 +1,30 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.2.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LinearAlgebra", "src\LinearAlgebra.csproj", "{ECB58727-0354-924D-AE7B-22F6B21097EB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LinearAlgebra_Test", "test\LinearAlgebra_Test.csproj", "{715BB399-5FC4-2AC9-3757-177CA0C80774}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {ECB58727-0354-924D-AE7B-22F6B21097EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ECB58727-0354-924D-AE7B-22F6B21097EB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ECB58727-0354-924D-AE7B-22F6B21097EB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ECB58727-0354-924D-AE7B-22F6B21097EB}.Release|Any CPU.Build.0 = Release|Any CPU + {715BB399-5FC4-2AC9-3757-177CA0C80774}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {715BB399-5FC4-2AC9-3757-177CA0C80774}.Debug|Any CPU.Build.0 = Debug|Any CPU + {715BB399-5FC4-2AC9-3757-177CA0C80774}.Release|Any CPU.ActiveCfg = Release|Any CPU + {715BB399-5FC4-2AC9-3757-177CA0C80774}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {E93B8294-87D4-4887-83B7-182A623D5833} + EndGlobalSection +EndGlobal diff --git a/src/Angle.cs b/src/Angle.cs new file mode 100644 index 0000000..694d1b7 --- /dev/null +++ b/src/Angle.cs @@ -0,0 +1,332 @@ +using System; + +namespace LinearAlgebra { + + public struct AngleFloat { + public const float Rad2Deg = 360.0f / ((float)Math.PI * 2); //0.0174532924F; + public const float Deg2Rad = (float)Math.PI * 2 / 360.0f; //57.29578F; + + private AngleFloat(float degrees) { + this.value = degrees; + } + private readonly float value; + + public static AngleFloat Degrees(float degrees) { + // Reduce it to (-180..180] + if (float.IsFinite(degrees)) { + while (degrees < -180) + degrees += 360; + while (degrees >= 180) + degrees -= 360; + } + return new AngleFloat(degrees); + } + + public static AngleFloat Radians(float radians) { + // Reduce it to (-pi..pi] + if (float.IsFinite(radians)) { + while (radians <= -Math.PI) + radians += 2 * (float)Math.PI; + while (radians > Math.PI) + radians -= 2 * (float)Math.PI; + } + + return new AngleFloat(radians * Rad2Deg); + + } + + public static AngleFloat Revolutions(float revolutions) { + // reduce it to (-0.5 .. 0.5] + if (float.IsFinite(revolutions)) { + // Get the integer part + int integerPart = (int)revolutions; + + // Get the decimal part + revolutions -= integerPart; + if (revolutions < -0.5) + revolutions += 1; + if (revolutions >= 0.5) + revolutions -= 1; + } + return new AngleFloat(revolutions * 360); + } + + public float inDegrees { + get { return this.value; } + } + + public float inRadians { + get { return this.value * Deg2Rad; } + } + + public float inRevolutions { + get { return this.value / 360.0f; } + } + + public static readonly AngleFloat zero = Degrees(0); + public static readonly AngleFloat deg90 = Degrees(90); + public static readonly AngleFloat deg180 = Degrees(180); + + /// + /// Get the sign of the angle + /// + /// The angle + /// -1 when the angle is negative, 1 when it is positive and 0 in all other cases + public static int Sign(AngleFloat a) { + if (a.value < 0) + return -1; + if (a.value > 0) + return 1; + return 0; + } + + /// + /// Returns the magnitude of the angle + /// + /// The angle + /// The positive magnitude of the angle + /// Negative values are negated to get a positive result + public static AngleFloat Abs(AngleFloat a) { + if (Sign(a) < 0) + return -a; + else + return a; + } + + /// + /// Tests the equality of two angles + /// + /// + /// + /// True when the angles are equal, false otherwise + /// The equality is determine within the limits of precision of a float + public static bool operator ==(AngleFloat a1, AngleFloat a2) { + return a1.value == a2.value; + } + + /// + /// Tests the inequality of two angles + /// + /// + /// + /// True when the angles are not equal, false otherwise + /// The equality is determine within the limits of precision of a float + public static bool operator !=(AngleFloat a1, AngleFloat a2) { + return a1.value != a2.value; + } + + /// + /// Tests if the first angle is greater than the second + /// + /// + /// + /// True when a1 is greater than a2, False otherwise + public static bool operator >(AngleFloat a1, AngleFloat a2) { + return a1.value > a2.value; + } + + /// + /// Tests if the first angle is greater than or equal to the second + /// + /// + /// + /// True when a1 is greater than or equal to a2, False otherwise + public static bool operator >=(AngleFloat a1, AngleFloat a2) { + return a1.value >= a2.value; + } + + /// + /// Tests if the first angle is less than the second + /// + /// + /// + /// True when a1 is less than a2, False otherwise + public static bool operator <(AngleFloat a1, AngleFloat a2) { + return a1.value < a2.value; + } + + /// + /// Tests if the first angle is less than or equal to the second + /// + /// + /// + /// True when a1 is less than or equal to a2, False otherwise + public static bool operator <=(AngleFloat a1, AngleFloat a2) { + return a1.value <= a2.value; + } + + /// + /// Negate the angle + /// + /// The angle + /// The negated angle + /// The negation of -180 is still -180 because the range is (-180..180] + public static AngleFloat operator -(AngleFloat a) { + AngleFloat r = new(-a.value); + return r; + } + + /// + /// Subtract two angles + /// + /// Angle 1 + /// Angle 2 + /// The result of the subtraction + public static AngleFloat operator -(AngleFloat a1, AngleFloat a2) { + AngleFloat r = new(a1.value - a2.value); + return r; + } + /// + /// Add two angles + /// + /// Angle 1 + /// Angle 2 + /// The result of the addition + public static AngleFloat operator +(AngleFloat a1, AngleFloat a2) { + AngleFloat r = new(a1.value + a2.value); + return r; + } + + /// + /// Multiplies the angle + /// + /// The angle to multiply + /// The factor by which the angle is multiplied + /// The multiplied angle + public static AngleFloat operator *(AngleFloat a, float factor) { + return Degrees(a.inDegrees * factor); + } + public static AngleFloat operator *(float factor, AngleFloat a) { + return Degrees(factor * a.inDegrees); + } + + /// + /// Clamp the angle between the given min and max values + /// + /// The angle to clamp + /// The minimum angle + /// The maximum angle + /// The clamped angle + /// Angles are normalized + public static float Clamp(AngleFloat angle, AngleFloat min, AngleFloat max) { + return Float.Clamp(angle.inDegrees, min.inDegrees, max.inDegrees); + } + + /// @brief Calculates the cosine of an angle + /// @param angle The given angle + /// @return The cosine of the angle + public static float Cos(AngleFloat angle) { + return MathF.Cos(angle.inRadians); + } + /// @brief Calculates the sine of an angle + /// @param angle The given angle + /// @return The sine of the angle + public static float Sin(AngleFloat angle) { + return MathF.Sin(angle.inRadians); + } + /// @brief Calculates the tangent of an angle + /// @param angle The given angle + /// @return The tangent of the angle + public static float Tan(AngleFloat angle) { + return MathF.Tan(angle.inRadians); + } + + /// @brief Calculates the arc cosine angle + /// @param f The value + /// @return The arc cosine for the given value + public static AngleFloat Acos(float f) { + return Radians(MathF.Acos(f)); + } + /// @brief Calculates the arc sine angle + /// @param f The value + /// @return The arc sine for the given value + public static AngleFloat Asin(float f) { + return Radians(MathF.Asin(f)); + } + /// @brief Calculates the arc tangent angle + /// @param f The value + /// @return The arc tangent for the given value + public static AngleFloat Atan(float f) { + return Radians(MathF.Atan(f)); + } + /// @brief Calculates the tangent for the given values + /// @param y The vertical value + /// @param x The horizontal value + /// @return The tanget for the given values + /// Uses the y and x signs to compute the quadrant + public static AngleFloat Atan2(float y, float x) { + return Radians(MathF.Atan2(y, x)); + } + + /// + /// Rotate from one angle to the other with a maximum degrees + /// + /// Starting angle + /// Target angle + /// Maximum angle to rotate + /// The resulting angle + /// This function is compatible with radian and degrees angles + public static AngleFloat MoveTowards(AngleFloat fromAngle, AngleFloat toAngle, float maxDegrees) { + maxDegrees = Math.Max(0, maxDegrees); // filter out negative distances + AngleFloat d = toAngle - fromAngle; + float dDegrees = Abs(d).inDegrees; + d = Degrees(Float.Clamp(dDegrees, 0, maxDegrees)); + if (Sign(d) < 0) + d = -d; + return fromAngle + d; + } + } + + + /// + /// %Angle utilities + /// + public static class Angles { + public const float pi = 3.1415927410125732421875F; + // public static float Rad2Deg = 360.0f / ((float)Math.PI * 2); + // public static float Deg2Rad = ((float)Math.PI * 2) / 360.0f; + + + /// + /// Determine the angle difference, result is a normalized angle + /// + /// First first angle + /// The second angle + /// the angle between the two angles + /// Angle values should be degrees + public static float Difference(float a, float b) { + float r = Normalize(b - a); + return r; + } + + /// + /// Normalize an angle to the range -180 < angle <= 180 + /// + /// The angle to normalize + /// The normalized angle in interval (-180..180] + /// Angle values should be in degrees + public static float Normalize(float angle) { + if (float.IsInfinity(angle)) + return angle; + + while (angle <= -180) angle += 360; + while (angle > 180) angle -= 360; + return angle; + } + + /// + /// Map interval of angles between vectors [0..Pi] to interval [0..1] + /// + /// The first vector + /// The second vector + /// The resulting factor in interval [0..1] + /// Vectors a and b must be normalized + /// \deprecated Please use Vector2.ToFactor instead. + // [Obsolete("Please use Vector2.ToFactor instead.")] + // public static float ToFactor(Vector2Float v1, Vector2Float v2) { + // return (1 - Vector2Float.Dot(v1, v2)) / 2; + // } + + } + +} \ No newline at end of file diff --git a/src/Decomposition.cs b/src/Decomposition.cs new file mode 100644 index 0000000..ddaf434 --- /dev/null +++ b/src/Decomposition.cs @@ -0,0 +1,287 @@ +using System; +namespace LinearAlgebra { + class QR { + // QR Decomposition of a matrix A + public static (Matrix2 Q, Matrix2 R) Decomposition(Matrix2 A) { + int nRows = A.nRows; + int nCols = A.nCols; + + float[,] Q = new float[nRows, nCols]; + float[,] R = new float[nCols, nCols]; + + // Perform Gram-Schmidt orthogonalization + for (uint colIx = 0; colIx < nCols; colIx++) { + + // Step 1: v = column(ix) of A + float[] v = new float[nRows]; + for (int rowIx = 0; rowIx < nRows; rowIx++) + v[rowIx] = A.data[rowIx, colIx]; + + // Step 2: Subtract projections of v onto previous q's (orthogonalize) + for (uint colIx2 = 0; colIx2 < colIx; colIx2++) { + float dotProd = 0; + for (int i = 0; i < nRows; i++) + dotProd += Q[i, colIx2] * v[i]; + for (int i = 0; i < nRows; i++) + v[i] -= dotProd * Q[i, colIx2]; + } + + // Step 3: Normalize v to get column(ix) of Q + float norm = 0; + for (int rowIx = 0; rowIx < nRows; rowIx++) + norm += v[rowIx] * v[rowIx]; + norm = (float)Math.Sqrt(norm); + + for (int rowIx = 0; rowIx < nRows; rowIx++) + Q[rowIx, colIx] = v[rowIx] / norm; + + // Store the coefficients of R + for (int colIx2 = 0; colIx2 <= colIx; colIx2++) { + R[colIx2, colIx] = 0; + for (int k = 0; k < nRows; k++) + R[colIx2, colIx] += Q[k, colIx2] * A.data[k, colIx]; + } + } + return (new Matrix2(Q), new Matrix2(R)); + } + + // Reduced QR Decomposition of a matrix A + public static (Matrix2 Q, Matrix2 R) ReducedDecomposition(Matrix2 A) { + int nRows = A.nRows; + int nCols = A.nCols; + + float[,] Q = new float[nRows, nCols]; + float[,] R = new float[nCols, nCols]; + + // Perform Gram-Schmidt orthogonalization + for (int colIx = 0; colIx < nCols; colIx++) { + + // Step 1: v = column(colIx) of A + float[] columnIx = new float[nRows]; + bool isZeroColumn = true; + for (int rowIx = 0; rowIx < nRows; rowIx++) { + columnIx[rowIx] = A.data[rowIx, colIx]; + if (columnIx[rowIx] != 0) + isZeroColumn = false; + } + if (isZeroColumn) { + for (int rowIx = 0; rowIx < nRows; rowIx++) + Q[rowIx, colIx] = 0; + // Set corresponding R element to 0 + R[colIx, colIx] = 0; + + Console.WriteLine($"zero column {colIx}"); + + continue; + } + + // Step 2: Subtract projections of v onto previous q's (orthogonalize) + for (int colIx2 = 0; colIx2 < colIx; colIx2++) { + // Compute the dot product of v and column(colIx2) of Q + float dotProduct = 0; + for (int rowIx2 = 0; rowIx2 < nRows; rowIx2++) + dotProduct += columnIx[rowIx2] * Q[rowIx2, colIx2]; + // Subtract the projection from v + for (int rowIx2 = 0; rowIx2 < nRows; rowIx2++) + columnIx[rowIx2] -= dotProduct * Q[rowIx2, colIx2]; + } + + // Step 3: Normalize v to get column(colIx) of Q + float norm = 0; + for (int rowIx = 0; rowIx < nRows; rowIx++) + norm += columnIx[rowIx] * columnIx[rowIx]; + if (norm == 0) + throw new Exception("invalid value"); + + norm = (float)Math.Sqrt(norm); + + for (int rowIx = 0; rowIx < nRows; rowIx++) + Q[rowIx, colIx] = columnIx[rowIx] / norm; + + // Here is where it deviates from the Full QR Decomposition ! + + // Step 4: Compute the row(colIx) of R + for (int colIx2 = colIx; colIx2 < nCols; colIx2++) { + float dotProduct = 0; + for (int rowIx2 = 0; rowIx2 < nRows; rowIx2++) + dotProduct += Q[rowIx2, colIx] * A.data[rowIx2, colIx2]; + R[colIx, colIx2] = dotProduct; + } + } + if (!float.IsFinite(R[0, 0])) + throw new Exception("invalid value"); + + return (new Matrix2(Q), new Matrix2(R)); + } + } + + class SVD { + // According to ChatGPT, Mathnet uses Golub-Reinsch SVD algorithm + // 1. Bidiagonalization: The input matrix AA is reduced to a bidiagonal form using Golub-Kahan bidiagonalization. + // This process involves applying a sequence of Householder reflections to AA to create a bidiagonal matrix. + // This step reduces the complexity by making the matrix simpler while retaining the essential structure needed for SVD. + // + // 2. Diagonalization: Once the matrix is in bidiagonal form, + // the singular values are computed using an iterative process + // (typically involving QR factorization or Jacobi rotations) until convergence. + // This process diagonalizes the bidiagonal matrix and allows extraction of the singular values. + // + // 3. Computing UU and VTVT: After obtaining the singular values, + // the left singular vectors UU and right singular vectors VTVT are computed + // using the accumulated transformations (such as Householder reflections) from the bidiagonalization step. + + // Bidiagnolizations through Householder transformations + public static (Matrix2 U1, Matrix2 B, Matrix2 V1) Bidiagonalization(Matrix2 A) { + int m = A.nRows; // Rows of A + int n = A.nCols; // Columns of A + float[,] U1 = new float[m, m]; // Left orthogonal matrix + float[,] V1 = new float[n, n]; // Right orthogonal matrix + float[,] B = A.Clone().data; // Copy A to B for transformation + + // Initialize U1 and V1 as identity matrices + for (int i = 0; i < m; i++) + U1[i, i] = 1; + for (int i = 0; i < n; i++) + V1[i, i] = 1; + + // Perform Householder reflections to create a bidiagonal matrix B + for (int j = 0; j < n; j++) { + // Step 1: Construct the Householder vector y + float[] y = new float[m - j]; + for (int i = j; i < m; i++) + y[i - j] = B[i, j]; + + // Step 2: Compute the norm and scalar alpha + float norm = 0; + for (int i = 0; i < y.Length; i++) + norm += y[i] * y[i]; + norm = (float)Math.Sqrt(norm); + + if (B[j, j] > 0) + norm = -norm; + + float alpha = (float)Math.Sqrt(0.5 * (norm * (norm - B[j, j]))); + float r = (float)Math.Sqrt(0.5 * (norm * (norm + B[j, j]))); + + // Step 3: Apply the reflection to zero out below diagonal + for (int k = j; k < n; k++) { + float dot = 0; + for (int i = j; i < m; i++) + dot += y[i - j] * B[i, k]; + dot /= r; + + for (int i = j; i < m; i++) + B[i, k] -= 2 * dot * y[i - j]; + } + + // Step 4: Update U1 with the Householder reflection (U1 * Householder) + for (int i = j; i < m; i++) + U1[i, j] = y[i - j] / alpha; + + // Step 5: Update V1 (storing the Householder vector y) + // Correct indexing: we only need to store part of y in V1 from index j to n + for (int i = j; i < n; i++) + V1[j, i] = B[j, i]; + + // Repeat steps for further columns if necessary + } + return (new Matrix2(U1), new Matrix2(B), new Matrix2(V1)); + } + + public static Matrix2 Bidiagonalize(Matrix2 A) { + int m = A.nRows; // Rows of A + int n = A.nCols; // Columns of A + float[,] B = A.Clone().data; // Copy A to B for transformation + + // Perform Householder reflections to create a bidiagonal matrix B + for (int j = 0; j < n; j++) { + // Step 1: Construct the Householder vector y + float[] y = new float[m - j]; + for (int i = j; i < m; i++) + y[i - j] = B[i, j]; + + // Step 2: Compute the norm and scalar alpha + float norm = 0; + for (int i = 0; i < y.Length; i++) + norm += y[i] * y[i]; + norm = (float)Math.Sqrt(norm); + + if (B[j, j] > 0) + norm = -norm; + + float r = (float)Math.Sqrt(0.5 * (norm * (norm + B[j, j]))); + + // Step 3: Apply the reflection to zero out below diagonal + for (int k = j; k < n; k++) { + float dot = 0; + for (int i = j; i < m; i++) + dot += y[i - j] * B[i, k]; + dot /= r; + + for (int i = j; i < m; i++) + B[i, k] -= 2 * dot * y[i - j]; + } + + // Repeat steps for further columns if necessary + } + return new Matrix2(B); + } + + // QR Iteration for diagonalization of a bidiagonal matrix B + public static (Matrix1 singularValues, Matrix2 U, Matrix2 Vt) QRIteration(Matrix2 B) { + int m = B.nRows; + int n = B.nCols; + + Matrix2 U = new(m, m); // Left singular vectors (U) + Matrix2 Vt = new(n, n); // Right singular vectors (V^T) + float[] singularValues = new float[Math.Min(m, n)]; // Singular values + + // Initialize U and Vt as identity matrices + for (int i = 0; i < m; i++) + U.data[i, i] = 1; + for (int i = 0; i < n; i++) + Vt.data[i, i] = 1; + + // Perform QR iterations + float tolerance = 1e-7f; //1e-12f; for double + bool converged = false; + while (!converged) { + // Perform QR decomposition on the matrix B + (Matrix2 Q, Matrix2 R) = QR.Decomposition(B); + + // Update B to be the product Q * R //R * Q + B = R * Q; + + // Accumulate the transformations in U and Vt + U *= Q; + Vt *= R; + + // Check convergence by looking at the off-diagonal elements of B + converged = true; + for (int i = 0; i < m - 1; i++) { + for (int j = i + 1; j < n; j++) { + if (Math.Abs(B.data[i, j]) > tolerance) { + converged = false; + break; + } + } + } + } + + // Extract singular values (diagonal elements of B) + for (int i = 0; i < Math.Min(m, n); i++) + singularValues[i] = B.data[i, i]; + + return (new Matrix1(singularValues), U, Vt); + } + + public static (Matrix2 U, Matrix1 S, Matrix2 Vt) Decomposition(Matrix2 A) { + if (A.nRows != A.nCols) + throw new ArgumentException("SVD: matrix A has to be square."); + + Matrix2 B = Bidiagonalize(A); + (Matrix1 S, Matrix2 U, Matrix2 Vt) = QRIteration(B); + return (U, S, Vt); + } + } +} \ No newline at end of file diff --git a/src/Direction.cs b/src/Direction.cs new file mode 100644 index 0000000..ed82901 --- /dev/null +++ b/src/Direction.cs @@ -0,0 +1,181 @@ +using System; +#if UNITY_5_3_OR_NEWER +using Vector3Float = UnityEngine.Vector3; +#endif + +namespace LinearAlgebra { + + /// + /// A direction in 3D space + /// + /// A direction is represented using two angles: + /// * The horizontal angle ranging from -180 (inclusive) to 180 (exclusive) + /// degrees which is a rotation in the horizontal plane + /// * A vertical angle ranging from -90 (inclusive) to 90 (exclusive) degrees + /// which is the rotation in the up/down direction applied after the horizontal + /// rotation has been applied. + /// The angles are automatically normalized to stay within the abovenmentioned + /// ranges. + public struct Direction { + /// @brief horizontal angle, range = (-180..180] degrees + public AngleFloat horizontal; + /// @brief vertical angle, range in degrees = (-90..90] degrees + public AngleFloat vertical; + + /// + /// Create a new direction + /// + /// The horizontal angle + /// The vertical angle + /// The direction will be normalized automatically + /// to ensure the angles are within the allowed ranges + public Direction(AngleFloat horizontal, AngleFloat vertical) { + this.horizontal = horizontal; + this.vertical = vertical; + this.Normalize(); + } + + /// + /// Create a direction using angle values in degrees + /// + /// The horizontal angle in degrees + /// The vertical angle in degrees + /// The direction + /// The direction will be normalized automatically + /// to ensure the angles are within the allowed ranges + public static Direction Degrees(float horizontal, float vertical) { + Direction d = new() { + horizontal = AngleFloat.Degrees(horizontal), + vertical = AngleFloat.Degrees(vertical) + }; + d.Normalize(); + return d; + } + /// + /// Create a direction using angle values in radians + /// + /// The horizontal angle in radians + /// The vertical angle in radians + /// The direction + public static Direction Radians(float horizontal, float vertical) { + Direction d = new() { + horizontal = AngleFloat.Radians(horizontal), + vertical = AngleFloat.Radians(vertical) + }; + d.Normalize(); + return d; + } + + /// + /// A forward direction with zero for both angles + /// + public readonly static Direction forward = Degrees(0, 0); + /// + /// A backward direction with horizontal angle -180 and zero vertical + /// angle + /// + public readonly static Direction backward = Degrees(-180, 0); + /// + /// A upward direction with zero horizontal angle and vertical angle 90 + /// + public readonly static Direction up = Degrees(0, 90); + /// + /// A downward direction with zero horizontal angle and vertical angle + /// -90 + /// + public readonly static Direction down = Degrees(0, -90); + /// + /// A left-pointing direction with horizontal angle -90 and zero + /// vertical angle + /// + public readonly static Direction left = Degrees(-90, 0); + /// + /// A right-pointing direction with horizontal angle 90 and zero + /// vertical angle + /// + public readonly static Direction right = Degrees(90, 0); + + private void Normalize() { + if (this.vertical > AngleFloat.deg90 || this.vertical < -AngleFloat.deg90) { + this.horizontal += AngleFloat.deg180; + this.vertical = AngleFloat.deg180 - this.vertical; + } + } + +#if !UNITY_5_3_OR_NEWER + /// + /// Convert the direction into a carthesian vector + /// + /// The carthesian vector corresponding to this direction. + public Vector3Float ToVector3Float() { + Quaternion q = Quaternion.Euler(90 - this.vertical.inDegrees, this.horizontal.inDegrees, 0); + Vector3Float v = q * Vector3Float.forward; + return v; + } +#else + /// + /// Convert the direction into a carthesian vector + /// + /// The carthesian vector corresponding to this direction. + public UnityEngine.Vector3 ToVector3() { + UnityEngine.Quaternion q = UnityEngine.Quaternion.Euler(90 - this.vertical.inDegrees, this.horizontal.inDegrees, 0); + UnityEngine.Vector3 v = q * UnityEngine.Vector3.forward; + return v; + } +#endif + + /// + /// Convert a carthesian vector into a direction + /// + /// The carthesian vector + /// The direction + /// Information about the length of the carthesian vector is not + /// included in this transformation + public static Direction FromVector3(Vector3Float v) { + AngleFloat horizontal = AngleFloat.Atan2(v.horizontal, v.depth); + AngleFloat vertical = AngleFloat.deg90 - AngleFloat.Acos(v.vertical); + Direction d = new(horizontal, vertical); + return d; + } + + /// + /// Tests the equality of two directions + /// + /// + /// + /// True when the direction angles are equal, false otherwise. + public static bool operator ==(Direction d1, Direction d2) { + bool horizontalEq = d1.horizontal == d2.horizontal; + bool verticalEq = d1.vertical == d2.vertical; + return horizontalEq && verticalEq; + } + + /// + /// Tests the inequality of two directions + /// + /// + /// + /// True when the direction angles are not equal, false otherwise. + public static bool operator !=(Direction d1, Direction d2) { + bool horizontalNEq = d1.horizontal != d2.horizontal; + bool verticalNEq = d1.vertical != d2.vertical; + return horizontalNEq || verticalNEq; + } + + public override readonly bool Equals(object obj) { + if (obj is not Direction d) + return false; + + bool horizontalEq = this.horizontal == d.horizontal; + bool verticalEq = this.vertical == d.vertical; + return horizontalEq && verticalEq; + } + + + public override readonly int GetHashCode() { + return HashCode.Combine(horizontal, vertical); + } + + } + +} \ No newline at end of file diff --git a/src/Float.cs b/src/Float.cs new file mode 100644 index 0000000..2217b84 --- /dev/null +++ b/src/Float.cs @@ -0,0 +1,41 @@ +namespace LinearAlgebra { + + /// + /// Float number utilities + /// + public class Float { + /// + /// The precision of float numbers + /// + public const float epsilon = 1E-05f; + /// + /// The square of the float number precision + /// + public const float sqrEpsilon = 1e-10f; + + /// + /// Clamp the value between the given minimum and maximum values + /// + /// The value to clamp + /// The minimum value + /// The maximum value + /// The clamped value + public static float Clamp(float f, float min, float max) { + if (f < min) + return min; + if (f > max) + return max; + return f; + } + + /// + /// Clamp the value between to the interval [0..1] + /// + /// The value to clamp + /// The clamped value + public static float Clamp01(float f) { + return Clamp(f, 0, 1); + } + } + +} \ No newline at end of file diff --git a/src/LinearAlgebra.csproj b/src/LinearAlgebra.csproj new file mode 100644 index 0000000..d2d5a85 --- /dev/null +++ b/src/LinearAlgebra.csproj @@ -0,0 +1,14 @@ + + + + false + false + net8.0 + + + + + + + + diff --git a/src/Matrix.cs b/src/Matrix.cs new file mode 100644 index 0000000..37c6c24 --- /dev/null +++ b/src/Matrix.cs @@ -0,0 +1,689 @@ +using System; +#if UNITY_5_3_OR_NEWER +using Vector3Float = UnityEngine.Vector3; +using Vector2Float = UnityEngine.Vector2; +using Quaternion = UnityEngine.Quaternion; +#endif + +namespace LinearAlgebra { + + public readonly struct Slice + { + public int start { get; } + public int stop { get; } + public Slice(int start, int stop) + { + this.start = start; + this.stop = stop; + } + } + + public class Matrix2 { + public float[,] data { get; } + + public int nRows => data.GetLength(0); + public int nCols => data.GetLength(1); + + public Matrix2(int nRows, int nCols) + { + this.data = new float[nRows, nCols]; + } + public Matrix2(float[,] data) { + this.data = data; + } + + public Matrix2 Clone() { + float[,] data = new float[this.nRows, nCols]; + for (int rowIx = 0; rowIx < this.nRows; rowIx++) { + for (int colIx = 0; colIx < this.nCols; colIx++) + data[rowIx, colIx] = this.data[rowIx, colIx]; + } + return new Matrix2(data); + } + + public static Matrix2 Zero(int nRows, int nCols) + { + return new Matrix2(nRows, nCols); + } + + public static Matrix2 FromVector3(Vector3Float v) { + float[,] result = new float[3, 1]; + result[0, 0] = v.horizontal; + result[1, 0] = v.vertical; + result[2, 0] = v.depth; + return new Matrix2(result); + } + + public static Matrix2 Identity(int size) + { + return Diagonal(1, size); + } + public static Matrix2 Identity(int nRows, int nCols) + { + Matrix2 m = Zero(nRows, nCols); + m.FillDiagonal(1); + return m; + } + + public static Matrix2 Diagonal(Matrix1 v) { + float[,] resultData = new float[v.size, v.size]; + for (int ix = 0; ix < v.size; ix++) + resultData[ix, ix] = v.data[ix]; + return new Matrix2(resultData); + } + public static Matrix2 Diagonal(float f, int size) + { + float[,] resultData = new float[size, size]; + for (int ix = 0; ix < size; ix++) + resultData[ix, ix] = f; + return new Matrix2(resultData); + } + public void FillDiagonal(Matrix1 v) + { + int n = (int)Math.Min(Math.Min(this.nRows, this.nCols), v.size); + for (int ix = 0; ix < n; ix++) + this.data[ix, ix] = v.data[ix]; + } + public void FillDiagonal(float f) + { + int n = Math.Min(this.nRows, this.nCols); + for (int ix = 0; ix < n; ix++) + this.data[ix, ix] = f; + } + + public static Matrix2 SkewMatrix(Vector3Float v) { + float[,] result = new float[3, 3] { + {0, -v.depth, v.vertical}, + {v.depth, 0, -v.horizontal}, + {-v.vertical, v.horizontal, 0} + }; + return new Matrix2(result); + } + + public Matrix1 GetRow(int rowIx) { + float[] row = new float[this.nCols]; + for (int colIx = 0; colIx < this.nCols; colIx++) { + row[colIx] = this.data[rowIx, colIx]; + } + return new Matrix1(row); + } + +#if UNITY_5_3_OR_NEWER + public UnityEngine.Vector3 GetRow3(int rowIx) { + int cols = this.nCols; + UnityEngine.Vector3 row = new() { + x = this.data[rowIx, 0], + y = this.data[rowIx, 1], + z = this.data[rowIx, 2] + }; + return row; + } +#endif + public void SetRow(int rowIx, Matrix1 v) { + for (uint ix = 0; ix < v.size; ix++) + this.data[rowIx, ix] = v.data[ix]; + } + public void SetRow3(int rowIx, Vector3Float v) { + this.data[rowIx, 0] = v.horizontal; + this.data[rowIx, 1] = v.vertical; + this.data[rowIx, 2] = v.depth; + } + + public void SwapRows(int row1, int row2) { + for (uint ix = 0; ix < this.nCols; ix++) { + float temp = this.data[row1, ix]; + this.data[row1, ix] = this.data[row2, ix]; + this.data[row2, ix] = temp; + } + } + + public Matrix1 GetColumn(int colIx) + { + float[] column = new float[this.nRows]; + for (int i = 0; i < this.nRows; i++) { + column[i] = this.data[i, colIx]; + } + return new Matrix1(column); + } + public void SetColumn(int colIx, Matrix1 v) { + for (uint ix = 0; ix < v.size; ix++) + this.data[ix, colIx] = v.data[ix]; + } + public void SetColumn(int colIx, Vector3Float v) { + this.data[0, colIx] = v.horizontal; + this.data[1, colIx] = v.vertical; + this.data[2, colIx] = v.depth; + } + + public static bool AllClose(Matrix2 A, Matrix2 B, float atol = 1e-08f) { + for (int i = 0; i < A.nRows; i++) { + for (int j = 0; j < A.nCols; j++) { + float d = MathF.Abs(A.data[i, j] - B.data[i, j]); + if (d > atol) + return false; + } + } + return true; + } + + public Matrix2 Transpose() { + float[,] resultData = new float[this.nCols, this.nRows]; + for (uint rowIx = 0; rowIx < this.nRows; rowIx++) { + for (uint colIx = 0; colIx < this.nCols; colIx++) + resultData[colIx, rowIx] = this.data[rowIx, colIx]; + } + return new Matrix2(resultData); + // double checked code + } + public Matrix2 transposed { + get => Transpose(); + } + + public static Matrix2 operator -(Matrix2 m) { + float[,] result = new float[m.nRows, m.nCols]; + + for (int i = 0; i < m.nRows; i++) { + for (int j = 0; j < m.nCols; j++) + result[i, j] = -m.data[i, j]; + } + return new Matrix2(result); + } + + public static Matrix2 operator -(Matrix2 A, Matrix2 B) { + if (A.nRows != B.nRows || A.nCols != B.nCols) + throw new System.ArgumentException("Size of A must match size of B."); + + float[,] result = new float[A.nRows, B.nCols]; + + for (int i = 0; i < A.nRows; i++) { + for (int j = 0; j < A.nCols; j++) + result[i, j] = A.data[i, j] - B.data[i, j]; + } + return new Matrix2(result); + } + + public static Matrix2 operator +(Matrix2 A, Matrix2 B) { + if (A.nRows != B.nRows || A.nCols != B.nCols) + throw new System.ArgumentException("Size of A must match size of B."); + + float[,] result = new float[A.nRows, B.nCols]; + + for (int i = 0; i < A.nRows; i++) { + for (int j = 0; j < A.nCols; j++) + result[i, j] = A.data[i, j] + B.data[i, j]; + } + return new Matrix2(result); + } + + public static Matrix2 operator *(Matrix2 A, Matrix2 B) { + if (A.nCols != B.nRows) + throw new System.ArgumentException("Number of columns in A must match number of rows in B."); + + float[,] result = new float[A.nRows, B.nCols]; + + for (int i = 0; i < A.nRows; i++) { + for (int j = 0; j < B.nCols; j++) { + float sum = 0.0f; + for (int k = 0; k < A.nCols; k++) + sum += A.data[i, k] * B.data[k, j]; + + result[i, j] = sum; + } + } + + return new Matrix2(result); + // double checked code + } + + public static Matrix1 operator *(Matrix2 A, Matrix1 v) { + float[] result = new float[A.nRows]; + + for (int i = 0; i < A.nRows; i++) { + for (int j = 0; j < A.nCols; j++) { + result[i] += A.data[i, j] * v.data[j]; + } + } + + return new Matrix1(result); + } + + public static Vector3Float operator *(Matrix2 A, Vector3Float v) { + return new Vector3Float( + A.data[0, 0] * v.horizontal + A.data[0, 1] * v.vertical + A.data[0, 2] * v.depth, + A.data[1, 0] * v.horizontal + A.data[1, 1] * v.vertical + A.data[1, 2] * v.depth, + A.data[2, 0] * v.horizontal + A.data[2, 1] * v.vertical + A.data[2, 2] * v.depth + ); + } + + public static Matrix2 operator *(Matrix2 A, float s) { + float[,] result = new float[A.nRows, A.nCols]; + + for (int i = 0; i < A.nRows; i++) { + for (int j = 0; j < A.nCols; j++) + result[i, j] = A.data[i, j] * s; + } + + return new Matrix2(result); + } + public static Matrix2 operator *(float s, Matrix2 A) { + return A * s; + } + + public static Matrix2 operator /(Matrix2 A, float s) { + float[,] result = new float[A.nRows, A.nCols]; + + for (int i = 0; i < A.nRows; i++) { + for (int j = 0; j < A.nCols; j++) + result[i, j] = A.data[i, j] / s; + } + + return new Matrix2(result); + } + public static Matrix2 operator /(float s, Matrix2 A) { + float[,] result = new float[A.nRows, A.nCols]; + + for (int i = 0; i < A.nRows; i++) { + for (int j = 0; j < A.nCols; j++) + result[i, j] = s / A.data[i, j]; + } + + return new Matrix2(result); + } + + public Matrix2 GetRows(Slice slice) { + return GetRows(slice.start, slice.stop); + } + public Matrix2 GetRows(int from, int to) { + if (from < 0 || to >= this.nRows) + throw new System.ArgumentException("Slice index out of range."); + + float[,] result = new float[to - from, this.nCols]; + int resultRowIx = 0; + for (int rowIx = from; rowIx < to; rowIx++) { + for (int colIx = 0; colIx < this.nCols; colIx++) + result[resultRowIx, colIx] = this.data[rowIx, colIx]; + + resultRowIx++; + } + + return new Matrix2(result); + } + + public Matrix2 Slice(Slice slice) + { + return Slice(slice.start, slice.stop); + } + public Matrix2 Slice(int from, int to) + { + if (from < 0 || to >= this.nRows) + throw new System.ArgumentException("Slice index out of range."); + + float[,] result = new float[to - from, this.nCols]; + int resultRowIx = 0; + for (int rowIx = from; rowIx < to; rowIx++) + { + for (int colIx = 0; colIx < this.nCols; colIx++) + { + result[resultRowIx, colIx] = this.data[rowIx, colIx]; + } + resultRowIx++; + } + + return new Matrix2(result); + } + public Matrix2 Slice(Slice rowRange, Slice colRange) { + return Slice((rowRange.start, rowRange.stop), (colRange.start, colRange.stop)); + } + public Matrix2 Slice((int start, int stop) rowRange, (int start, int stop) colRange) + { + float[,] result = new float[rowRange.stop - rowRange.start, colRange.stop - colRange.start]; + + int resultRowIx = 0; + int resultColIx = 0; + for (int i = rowRange.start; i < rowRange.stop; i++) + { + for (int j = colRange.start; j < colRange.stop; j++) + result[resultRowIx, resultColIx] = this.data[i, j]; + } + return new Matrix2(result); + } + + public void UpdateSlice(Slice slice, Matrix2 m) { + UpdateSlice((slice.start, slice.stop), m); + } + public void UpdateSlice((int start, int stop) slice, Matrix2 m) { + // if (slice.start == slice.stop) + // Console.WriteLine("WARNING: no data is updates when start equals stop in a slice!"); + int mRowIx = 0; + for (int rowIx = slice.start; rowIx < slice.stop; rowIx++, mRowIx++) { + for (int colIx = 0; colIx < this.nCols; colIx++) + this.data[rowIx, colIx] = m.data[mRowIx, colIx]; + } + } + + public void UpdateSlice(Slice rowRange, Slice colRange, Matrix2 m) + { + UpdateSlice((rowRange.start, rowRange.stop), (colRange.start, colRange.stop), m); + } + public void UpdateSlice((int start, int stop) rowRange, (int start, int stop) colRange, Matrix2 m) + { + for (int i = rowRange.start; i < rowRange.stop; i++) + { + for (int j = colRange.start; j < colRange.stop; j++) + this.data[i, j] = m.data[i - rowRange.start, j - colRange.start]; + } + } + + public Matrix2 Inverse() { + Matrix2 A = this; + // unchecked + int n = A.nRows; + + // Create an identity matrix of the same size as the original matrix + float[,] augmentedMatrix = new float[n, 2 * n]; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + augmentedMatrix[i, j] = A.data[i, j]; + augmentedMatrix[i, j + n] = (i == j) ? 1 : 0; // Identity matrix + } + } + + // Perform Gaussian elimination + for (int i = 0; i < n; i++) { + // Find the pivot row + float pivot = augmentedMatrix[i, i]; + if (Math.Abs(pivot) < 1e-10) // Check for singular matrix + throw new InvalidOperationException("Matrix is singular and cannot be inverted."); + + // Normalize the pivot row + for (int j = 0; j < 2 * n; j++) + augmentedMatrix[i, j] /= pivot; + + // Eliminate the column below the pivot + for (int j = i + 1; j < n; j++) { + float factor = augmentedMatrix[j, i]; + for (int k = 0; k < 2 * n; k++) + augmentedMatrix[j, k] -= factor * augmentedMatrix[i, k]; + } + } + + // Back substitution + for (int i = n - 1; i >= 0; i--) + { + // Eliminate the column above the pivot + for (int j = i - 1; j >= 0; j--) + { + float factor = augmentedMatrix[j, i]; + for (int k = 0; k < 2 * n; k++) + augmentedMatrix[j, k] -= factor * augmentedMatrix[i, k]; + } + } + + // Extract the inverse matrix from the augmented matrix + float[,] inverse = new float[n, n]; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) + inverse[i, j] = augmentedMatrix[i, j + n]; + } + + return new Matrix2(inverse); + } + + public float Determinant() + { + int n = this.nRows; + if (n != this.nCols) + throw new System.ArgumentException("Matrix must be square."); + + if (n == 1) + return this.data[0, 0]; // Base case for 1x1 matrix + + if (n == 2) // Base case for 2x2 matrix + return this.data[0, 0] * this.data[1, 1] - this.data[0, 1] * this.data[1, 0]; + + float det = 0; + for (int col = 0; col < n; col++) + det += (col % 2 == 0 ? 1 : -1) * this.data[0, col] * this.Minor(0, col).Determinant(); + + return det; + } + + // Helper function to compute the minor of a matrix + private Matrix2 Minor(int rowToRemove, int colToRemove) + { + int n = this.nRows; + float[,] minor = new float[n - 1, n - 1]; + + int r = 0, c = 0; + for (int i = 0; i < n; i++) { + if (i == rowToRemove) continue; + + c = 0; + for (int j = 0; j < n; j++) { + if (j == colToRemove) continue; + + minor[r, c] = this.data[i, j]; + c++; + } + r++; + } + + return new Matrix2(minor); + } + + public static Matrix2 DeleteRows(Matrix2 A, Slice rowRange) { + float[,] result = new float[A.nRows - (rowRange.stop - rowRange.start), A.nCols]; + + int resultRowIx = 0; + for (int i = 0; i < A.nRows; i++) { + if (i >= rowRange.start && i < rowRange.stop) + continue; + + for (int j = 0; j < A.nCols; j++) + result[resultRowIx, j] = A.data[i, j]; + + resultRowIx++; + } + return new Matrix2(result); + } + + internal static Matrix2 DeleteColumns(Matrix2 A, Slice colRange) { + float[,] result = new float[A.nRows, A.nCols - (colRange.stop - colRange.start)]; + + for (int i = 0; i < A.nRows; i++) { + int resultColIx = 0; + for (int j = 0; j < A.nCols; j++) { + if (j >= colRange.start && j < colRange.stop) + continue; + + result[i, resultColIx++] = A.data[i, j]; + } + } + return new Matrix2(result); + } + } + + public class Matrix1 + { + public float[] data { get; } + + public int size => data.GetLength(0); + + public Matrix1(int size) + { + this.data = new float[size]; + } + + public Matrix1(float[] data) { + this.data = data; + } + + public static Matrix1 Zero(int size) + { + return new Matrix1(size); + } + + public static Matrix1 FromVector2(Vector2Float v) { + float[] result = new float[2]; + result[0] = v.horizontal; + result[1] = v.vertical; + return new Matrix1(result); + } + + public static Matrix1 FromVector3(Vector3Float v) { + float[] result = new float[3]; + result[0] = v.horizontal; + result[1] = v.vertical; + result[2] = v.depth; + return new Matrix1(result); + } + +#if UNITY_5_3_OR_NEWER + public static Matrix1 FromQuaternion(Quaternion q) { + float[] result = new float[4]; + result[0] = q.x; + result[1] = q.y; + result[2] = q.z; + result[3] = q.w; + return new Matrix1(result); + } +#endif + + public Vector2Float vector2 { + get { + if (this.size != 2) + throw new System.ArgumentException("Matrix1 must be of size 2"); + return new Vector2Float(this.data[0], this.data[1]); + } + } + public Vector3Float vector3 { + get { + if (this.size != 3) + throw new System.ArgumentException("Matrix1 must be of size 3"); + return new Vector3Float(this.data[0], this.data[1], this.data[2]); + } + } + +#if UNITY_5_3_OR_NEWER + public Quaternion quaternion { + get { + if (this.size != 4) + throw new System.ArgumentException("Matrix1 must be of size 4"); + return new Quaternion(this.data[0], this.data[1], this.data[2], this.data[3]); + } + } +#endif + + public Matrix1 Clone() { + float[] data = new float[this.size]; + for (int rowIx = 0; rowIx < this.size; rowIx++) + data[rowIx] = this.data[rowIx]; + return new Matrix1(data); + } + + + public float magnitude { + get { + float sum = 0; + foreach (var elm in data) + sum += elm; + return sum / data.Length; + } + } + public static Matrix1 operator +(Matrix1 A, Matrix1 B) { + if (A.size != B.size) + throw new System.ArgumentException("Size of A must match size of B."); + + float[] result = new float[A.size]; + + for (int i = 0; i < A.size; i++) { + result[i] = A.data[i] + B.data[i]; + } + return new Matrix1(result); + } + + public Matrix2 Transpose() { + float[,] r = new float[1, this.size]; + for (uint colIx = 0; colIx < this.size; colIx++) + r[1, colIx] = this.data[colIx]; + + return new Matrix2(r); + } + + public static float Dot(Matrix1 a, Matrix1 b) { + if (a.size != b.size) + throw new System.ArgumentException("Vectors must be of the same length."); + + float result = 0.0f; + for (int i = 0; i < a.size; i++) { + result += a.data[i] * b.data[i]; + } + return result; + } + + public static Matrix1 operator -(Matrix1 A, Matrix1 B) { + if (A.size != B.size) + throw new System.ArgumentException("Size of A must match size of B."); + + float[] result = new float[A.size]; + + for (int i = 0; i < A.size; i++) { + result[i] = A.data[i] - B.data[i]; + } + return new Matrix1(result); + } + + public static Matrix1 operator *(Matrix1 A, float f) + { + float[] result = new float[A.size]; + + for (int i = 0; i < A.size; i++) + result[i] += A.data[i] * f; + + return new Matrix1(result); + } + public static Matrix1 operator *(float f, Matrix1 A) { + return A * f; + } + + public static Matrix1 operator /(Matrix1 A, float f) { + float[] result = new float[A.size]; + + for (int i = 0; i < A.size; i++) + result[i] = A.data[i] / f; + + return new Matrix1(result); + } + public static Matrix1 operator /(float f, Matrix1 A) { + float[] result = new float[A.size]; + + for (int i = 0; i < A.size; i++) + result[i] = f / A.data[i]; + + return new Matrix1(result); + } + + public Matrix1 Slice(Slice range) + { + return Slice(range.start, range.stop); + } + public Matrix1 Slice(int from, int to) + { + if (from < 0 || to >= this.size) + throw new System.ArgumentException("Slice index out of range."); + + float[] result = new float[to - from]; + int resultIx = 0; + for (int ix = from; ix < to; ix++) + result[resultIx++] = this.data[ix]; + + return new Matrix1(result); + } + public void UpdateSlice(Slice slice, Matrix1 v) { + int vIx = 0; + for (int ix = slice.start; ix < slice.stop; ix++, vIx++) + this.data[ix] = v.data[vIx]; + } + } + +} \ No newline at end of file diff --git a/src/Quat32.cs b/src/Quat32.cs new file mode 100644 index 0000000..19ee9bc --- /dev/null +++ b/src/Quat32.cs @@ -0,0 +1,87 @@ +using System; + +namespace LinearAlgebra { + public class Quat32 { + public float x; + public float y; + public float z; + public float w; + + public Quat32() { + this.x = 0; + this.y = 0; + this.z = 0; + this.w = 1; + } + + public Quat32(float x, float y, float z, float w) { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + + public static Quat32 FromSwingTwist(SwingTwist s) { + Quat32 q32 = Quat32.Euler(-s.swing.vertical.inDegrees, s.swing.horizontal.inDegrees, s.twist.inDegrees); + return q32; + } + + public static Quat32 Euler(float yaw, float pitch, float roll) { + float rollOver2 = roll * AngleFloat.Deg2Rad * 0.5f; + float sinRollOver2 = (float)Math.Sin((float)rollOver2); + float cosRollOver2 = (float)Math.Cos((float)rollOver2); + float pitchOver2 = pitch * 0.5f; + float sinPitchOver2 = (float)Math.Sin((float)pitchOver2); + float cosPitchOver2 = (float)Math.Cos((float)pitchOver2); + float yawOver2 = yaw * 0.5f; + float sinYawOver2 = (float)Math.Sin((float)yawOver2); + float cosYawOver2 = (float)Math.Cos((float)yawOver2); + Quat32 result = new Quat32() { + w = cosYawOver2 * cosPitchOver2 * cosRollOver2 + + sinYawOver2 * sinPitchOver2 * sinRollOver2, + x = sinYawOver2 * cosPitchOver2 * cosRollOver2 + + cosYawOver2 * sinPitchOver2 * sinRollOver2, + y = cosYawOver2 * sinPitchOver2 * cosRollOver2 - + sinYawOver2 * cosPitchOver2 * sinRollOver2, + z = cosYawOver2 * cosPitchOver2 * sinRollOver2 - + sinYawOver2 * sinPitchOver2 * cosRollOver2 + }; + return result; + } + + public void ToAngles(out float right, out float up, out float forward) { + float test = this.x * this.y + this.z * this.w; + if (test > 0.499f) { // singularity at north pole + right = 0; + up = 2 * (float)Math.Atan2(this.x, this.w) * AngleFloat.Rad2Deg; + forward = 90; + return; + //return Vector3(0, 2 * (float)atan2(this.x, this.w) * Angle.Rad2Deg, 90); + } + else if (test < -0.499f) { // singularity at south pole + right = 0; + up = -2 * (float)Math.Atan2(this.x, this.w) * AngleFloat.Rad2Deg; + forward = -90; + return; + //return Vector3(0, -2 * (float)atan2(this.x, this.w) * Angle.Rad2Deg, -90); + } + else { + float sqx = this.x * this.x; + float sqy = this.y * this.y; + float sqz = this.z * this.z; + + right = (float)Math.Atan2(2 * this.x * this.w - 2 * this.y * this.z, 1 - 2 * sqx - 2 * sqz) * AngleFloat.Rad2Deg; + up = (float)Math.Atan2(2 * this.y * this.w - 2 * this.x * this.z, 1 - 2 * sqy - 2 * sqz) * AngleFloat.Rad2Deg; + forward = (float)Math.Asin(2 * test) * AngleFloat.Rad2Deg; + return; + // return Vector3( + // atan2f(2 * this.x * this.w - 2 * this.y * this.z, 1 - 2 * sqx - 2 * sqz) * + // Rad2Deg, + // atan2f(2 * this.y * this.w - 2 * this.x * this.z, 1 - 2 * sqy - 2 * sqz) * + // Rad2Deg, + // asinf(2 * test) * Angle.Rad2Deg); + } + } + + } +} \ No newline at end of file diff --git a/src/Quaternion.cs b/src/Quaternion.cs new file mode 100644 index 0000000..670c0a4 --- /dev/null +++ b/src/Quaternion.cs @@ -0,0 +1,608 @@ +using System; +#if UNITY_5_3_OR_NEWER +using Quaternion = UnityEngine.Quaternion; +#endif + +namespace LinearAlgebra { + +#if UNITY_5_3_OR_NEWER + public class QuaternionExtensions { + public static Quaternion Reflect(Quaternion q) { + return new(-q.x, -q.y, -q.z, q.w); + } + + public static Matrix2 ToRotationMatrix(Quaternion q) { + float w = q.x, x = q.y, y = q.z, z = q.w; + + float[,] result = new float[,] + { + { 1 - 2 * (y * y + z * z), 2 * (x * y - w * z), 2 * (x * z + w * y) }, + { 2 * (x * y + w * z), 1 - 2 * (x * x + z * z), 2 * (y * z - w * x) }, + { 2 * (x * z - w * y), 2 * (y * z + w * x), 1 - 2 * (x * x + y * y) } + }; + return new Matrix2(result); + } + + public static Quaternion FromRotationMatrix(Matrix2 m) { + float trace = m.data[0, 0] + m.data[1, 1] + m.data[2, 2]; + float w, x, y, z; + + if (trace > 0) { + float s = 0.5f / (float)Math.Sqrt(trace + 1.0f); + w = 0.25f / s; + x = (m.data[2, 1] - m.data[1, 2]) * s; + y = (m.data[0, 2] - m.data[2, 0]) * s; + z = (m.data[1, 0] - m.data[0, 1]) * s; + } + else { + if (m.data[0, 0] > m.data[1, 1] && m.data[0, 0] > m.data[2, 2]) { + float s = 2.0f * (float)Math.Sqrt(1.0f + m.data[0, 0] - m.data[1, 1] - m.data[2, 2]); + w = (m.data[2, 1] - m.data[1, 2]) / s; + x = 0.25f * s; + y = (m.data[0, 1] + m.data[1, 0]) / s; + z = (m.data[0, 2] + m.data[2, 0]) / s; + } + else if (m.data[1, 1] > m.data[2, 2]) { + float s = 2.0f * (float)Math.Sqrt(1.0f + m.data[1, 1] - m.data[0, 0] - m.data[2, 2]); + w = (m.data[0, 2] - m.data[2, 0]) / s; + x = (m.data[0, 1] + m.data[1, 0]) / s; + y = 0.25f * s; + z = (m.data[1, 2] + m.data[2, 1]) / s; + } + else { + float s = 2.0f * (float)Math.Sqrt(1.0f + m.data[2, 2] - m.data[0, 0] - m.data[1, 1]); + w = (m.data[1, 0] - m.data[0, 1]) / s; + x = (m.data[0, 2] + m.data[2, 0]) / s; + y = (m.data[1, 2] + m.data[2, 1]) / s; + z = 0.25f * s; + } + } + + return new Quaternion(x, y, z, w); + } + } +#else + public struct Quaternion { + public float x; + public float y; + public float z; + public float w; + + /// + /// create a new quaternion with the given values + /// + /// x component + /// y component + /// z component + /// w component + public Quaternion(float x, float y, float z, float w) { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + + /// + /// An identity quaternion + /// + public static readonly Quaternion identity = new(0, 0, 0, 1); + + private readonly Vector3Float xyz => new(x, y, z); + + private readonly float magnitude => MathF.Sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w); + + private readonly float sqrMagnitude => x * x + y * y + z * z + w * w; + + /// + /// Convert to unit quaternion + /// + /// This will preserve the orientation, + /// but ensures that it is a unit quaternion. + public readonly Quaternion normalized { + get { + float length = this.magnitude; + Quaternion q = new(this.x / length, this.y / length, this.z / length, this.w / length); + return q; + } + } + + /// + /// Convert to unity quaternion + /// + /// The quaternion to convert + /// A unit quaternion + /// This will preserve the orientation, + /// but ensures that it is a unit quaternion. + public static Quaternion Normalize(Quaternion q) { + return q.normalized; + } + + /// + /// Convert to euler angles + /// + /// The quaternion to convert + /// A vector containing euler angles + /// The euler angles performed in the order: Z, X, Y + public static Vector3Float ToAngles(Quaternion q) { + // Extract Euler angles in Unity order (X = pitch, Y = yaw, Z = roll), returned in degrees as (x,pitch),(y,yaw),(z,roll) + // Handle singularities/gimbal lock + float test = 2f * (q.w * q.x - q.y * q.z); + // clamp + if (test >= 1f) test = 1f; + if (test <= -1f) test = -1f; + + float pitch = MathF.Asin(test); // X + + float roll = MathF.Atan2(2f * (q.w * q.z + q.x * q.y), + 1f - 2f * (q.x * q.x + q.z * q.z)); // Z + + float yaw = MathF.Atan2(2f * (q.w * q.y + q.x * q.z), + 1f - 2f * (q.y * q.y + q.x * q.x)); // Y + + const float rad2deg = 180f / MathF.PI; + return new Vector3Float(pitch * rad2deg, yaw * rad2deg, roll * rad2deg); + // float test = q.x * q.y + q.z * q.w; + // if (test > 0.499f) // singularity at north pole + // return new Vector3Float(0, 2 * MathF.Atan2(q.x, q.w) * AngleFloat.Rad2Deg, 90); + + // else if (test < -0.499f) // singularity at south pole + // return new Vector3Float(0, -2 * MathF.Atan2(q.x, q.w) * AngleFloat.Rad2Deg, -90); + + // else { + // float sqx = q.x * q.x; + // float sqy = q.y * q.y; + // float sqz = q.z * q.z; + + // return new Vector3Float( + // MathF.Atan2(2 * q.x * q.w - 2 * q.y * q.z, 1 - 2 * sqx - 2 * sqz) * + // AngleFloat.Rad2Deg, + // MathF.Atan2(2 * q.y * q.w - 2 * q.x * q.z, 1 - 2 * sqy - 2 * sqz) * + // AngleFloat.Rad2Deg, + // MathF.Asin(2 * test) * AngleFloat.Rad2Deg); + // } + } + + /// + /// Create a rotation from euler angles + /// + /// The angle around the right axis + /// The angle around the upward axis + /// The angle around the forward axis + /// The resulting quaternion + /// Rotation are appied in the order Z, X, Y. + public static Quaternion Euler(float x, float y, float z) { + return Quaternion.Euler(new Vector3Float(x, y, z)); + } + /// + /// Create a rotation from a vector containing euler angles + /// + /// Vector with the euler angles + /// The resulting quaternion + /// Rotation are appied in the order Z, X, Y. + public static Quaternion Euler(Vector3Float angles) { + // return Quaternion.FromEulerRad(angles * AngleFloat.Deg2Rad); + // } + // private static Quaternion FromEulerRad(Vector3Float euler) { + Vector3Float euler = angles * AngleFloat.Deg2Rad; + // euler.x = pitch, euler.y = yaw, euler.z = roll (radians) + float cx = MathF.Cos(euler.horizontal * 0.5f); + float sx = MathF.Sin(euler.horizontal * 0.5f); + float cy = MathF.Cos(euler.vertical * 0.5f); + float sy = MathF.Sin(euler.vertical * 0.5f); + float cz = MathF.Cos(euler.depth * 0.5f); + float sz = MathF.Sin(euler.depth * 0.5f); + + // Unity uses intrinsic Z, then X, then Y -> q = Qy * Qx * Qz + Quaternion q; + q.w = cy * cx * cz + sy * sx * sz; + q.x = cy * sx * cz + sy * cx * sz; + q.y = sy * cx * cz - cy * sx * sz; + q.z = cy * cx * sz - sy * sx * cz; + return q; + // float yaw = euler.horizontal; + // float pitch = euler.vertical; + // float roll = euler.depth; + // float rollOver2 = roll * 0.5f; + // float sinRollOver2 = MathF.Sin(rollOver2); + // float cosRollOver2 = MathF.Cos(rollOver2); + // float pitchOver2 = pitch * 0.5f; + // float sinPitchOver2 = MathF.Sin(pitchOver2); + // float cosPitchOver2 = MathF.Cos(pitchOver2); + // float yawOver2 = yaw * 0.5f; + // float sinYawOver2 = MathF.Sin(yawOver2); + // float cosYawOver2 = MathF.Cos(yawOver2); + // Quaternion result; + // result.w = cosYawOver2 * cosPitchOver2 * cosRollOver2 + + // sinYawOver2 * sinPitchOver2 * sinRollOver2; + // result.x = sinYawOver2 * cosPitchOver2 * cosRollOver2 + + // cosYawOver2 * sinPitchOver2 * sinRollOver2; + // result.y = cosYawOver2 * sinPitchOver2 * cosRollOver2 - + // sinYawOver2 * cosPitchOver2 * sinRollOver2; + // result.z = cosYawOver2 * cosPitchOver2 * sinRollOver2 - + // sinYawOver2 * sinPitchOver2 * cosRollOver2; + // return result; + } + + /// + /// Multiply two quaternions + /// + /// + /// + /// The resulting rotation + public static Quaternion operator *(Quaternion q1, Quaternion q2) { + return new Quaternion( + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y + q1.w * q2.x, + -q1.x * q2.z + q1.y * q2.w + q1.z * q2.x + q1.w * q2.y, + q1.x * q2.y - q1.y * q2.x + q1.z * q2.w + q1.w * q2.z, + -q1.x * q2.x - q1.y * q2.y - q1.z * q2.z + q1.w * q2.w); + } + + /// + /// Rotate a vector using this quaterion + /// + /// The rotation + /// The vector to rotate + /// The rotated vector + public static Vector3Float operator *(Quaternion q, Vector3Float v) { + float num = q.x * 2; + float num2 = q.y * 2; + float num3 = q.z * 2; + float num4 = q.x * num; + float num5 = q.y * num2; + float num6 = q.z * num3; + float num7 = q.x * num2; + float num8 = q.x * num3; + float num9 = q.y * num3; + float num10 = q.w * num; + float num11 = q.w * num2; + float num12 = q.w * num3; + + float px = v.horizontal; + float py = v.vertical; + float pz = v.depth; + float rx = + (1 - (num5 + num6)) * px + (num7 - num12) * py + (num8 + num11) * pz; + float ry = + (num7 + num12) * px + (1 - (num4 + num6)) * py + (num9 - num10) * pz; + float rz = + (num8 - num11) * px + (num9 + num10) * py + (1 - (num4 + num5)) * pz; + Vector3Float result = new(rx, ry, rz); + return result; + } + + /// + /// The inverse of quaterion + /// + /// The quaternion for which the inverse is + /// needed The inverted quaternion + public static Quaternion Inverse(Quaternion q) { + float n = MathF.Sqrt(q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w); + return new Quaternion(-q.x / n, -q.y / n, -q.z / n, q.w / n); + } + + /// + /// A rotation which looks in the given direction + /// + /// The look direction + /// The up direction + /// The look rotation + public static Quaternion LookRotation(Vector3Float forward, Vector3Float up) { + Vector3Float nForward = forward.normalized; + Vector3Float nRight = Vector3Float.Normalize(Vector3Float.Cross(up, nForward)); + Vector3Float nUp = Vector3Float.Cross(nForward, nRight); + float m00 = nRight.horizontal; // x; + float m01 = nRight.vertical; // y; + float m02 = nRight.depth; // z; + float m10 = nUp.horizontal; // x; + float m11 = nUp.vertical; // y; + float m12 = nUp.depth; // z; + float m20 = nForward.horizontal; // x; + float m21 = nForward.vertical; // y; + float m22 = nForward.depth; // z; + + float num8 = (m00 + m11) + m22; + float x, y, z, w; + if (num8 > 0) { + float num = MathF.Sqrt(num8 + 1); + w = num * 0.5f; + num = 0.5f / num; + x = (m12 - m21) * num; + y = (m20 - m02) * num; + z = (m01 - m10) * num; + return new Quaternion(x, y, z, w); + } + if ((m00 >= m11) && (m00 >= m22)) { + float num7 = MathF.Sqrt(((1 + m00) - m11) - m22); + float num4 = 0.5F / num7; + x = 0.5f * num7; + y = (m01 + m10) * num4; + z = (m02 + m20) * num4; + w = (m12 - m21) * num4; + return new Quaternion(x, y, z, w); + } + if (m11 > m22) { + float num6 = MathF.Sqrt(((1 + m11) - m00) - m22); + float num3 = 0.5F / num6; + x = (m10 + m01) * num3; + y = 0.5F * num6; + z = (m21 + m12) * num3; + w = (m20 - m02) * num3; + return new Quaternion(x, y, z, w); + } + float num5 = MathF.Sqrt(((1 + m22) - m00) - m11); + float num2 = 0.5F / num5; + x = (m20 + m02) * num2; + y = (m21 + m12) * num2; + z = 0.5F * num5; + w = (m01 - m10) * num2; + return new Quaternion(x, y, z, w); + } + + /// + /// Creates a quaternion with the given forward direction with up = + /// Vector3::up + /// + /// The look direction + /// The rotation for this direction + /// For the rotation, Vector::up is used for the up direction. + /// Note: if the forward direction == Vector3::up, the result is + /// Quaternion::identity + public static Quaternion LookRotation(Vector3Float forward) { + Vector3Float up = new(0, 1, 0); + return LookRotation(forward, up); + } + + /// + /// Calculat the rotation from on vector to another + /// + /// The from direction + /// The to direction + /// The rotation from the first to the second vector + public static Quaternion FromToRotation(Vector3Float fromDirection, Vector3Float toDirection) { + Vector3Float axis = Vector3Float.Cross(fromDirection, toDirection); + axis = axis.normalized; + AngleFloat angle = Vector3Float.SignedAngle(fromDirection, toDirection, axis); + Quaternion rotation = AngleAxis(angle, axis); + return rotation; + + } + + /// + /// Rotate form one orientation to anther with a maximum amount of degrees + /// + /// The from rotation + /// The destination rotation + /// The maximum amount of degrees to + /// rotate The possibly limited rotation + public static Quaternion RotateTowards(Quaternion from, Quaternion to, + float maxDegreesDelta) { + float num = Quaternion.UnsignedAngle(from, to); + if (num == 0) { + return to; + } + float t = MathF.Min(1, maxDegreesDelta / num); + return SlerpUnclamped(from, to, t); + + } + + /// + /// Convert an angle/axis representation to a quaternion + /// + /// The angle + /// The axis + /// The resulting quaternion + public static Quaternion AngleAxis(AngleFloat angle, Vector3Float axis) { + if (axis.sqrMagnitude == 0.0f) + return Quaternion.identity; + + float radians = angle.inRadians; + radians *= 0.5f; + + Vector3Float axis2 = axis * MathF.Sin(radians); + float x = axis2.horizontal; // x; + float y = axis2.vertical; // y; + float z = axis2.depth; // z; + float w = MathF.Cos(radians); + + return new Quaternion(x, y, z, w).normalized; + } + /// + /// Convert this quaternion to angle/axis representation + /// + /// A pointer to the angle for the result + /// A pointer to the axis for the result + public readonly void ToAngleAxis(out AngleFloat angle, out Vector3Float axis) { + Quaternion q1 = (MathF.Abs(this.w) > 1.0f) ? this.normalized : this; + angle = AngleFloat.Radians(2.0f * MathF.Acos(q1.w)); // angle + float den = MathF.Sqrt(1.0F - q1.w * q1.w); + if (den > 0.0001f) { + axis = Vector3Float.Normalize(q1.xyz / den); + } + else { + // This occurs when the angle is zero. + // Not a problem: just set an arbitrary normalized axis. + axis = Vector3Float.right; + } + } + + /// + /// Get the angle between two orientations + /// + /// The first orientation + /// The second orientation + /// The smallest angle in degrees between the two + /// orientations + public static float UnsignedAngle(Quaternion q1, Quaternion q2) { + // float f = Dot(q1, q2); + // return MathF.Acos(MathF.Min(MathF.Abs(f), 1)) * 2 * AngleFloat.Rad2Deg; + + float dot = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w; + dot = MathF.Min(MathF.Max(dot, -1f), 1f); + return 2f * MathF.Acos(MathF.Abs(dot)) * (180f / MathF.PI); + } + + /// + /// Sherical lerp between two rotations + /// + /// The first rotation + /// The second rotation + /// The factor between 0 and 1. + /// The resulting rotation + /// A factor 0 returns rotation1, factor1 returns rotation2. + public static Quaternion Slerp(Quaternion a, + Quaternion b, float t) { + if (t > 1) + t = 1; + if (t < 0) + t = 0; + return SlerpUnclamped(a, b, t); + } + + /// + /// Unclamped sherical lerp between two rotations + /// + /// The first rotation + /// The second rotation + /// The factor + /// The resulting rotation + /// A factor 0 returns rotation1, factor1 returns rotation2. + /// Values outside the 0..1 range will result in extrapolated rotations + public static Quaternion SlerpUnclamped(Quaternion a, + Quaternion b, float t) { + // if either input is zero, return the other. + if (a.sqrMagnitude == 0.0f) { + if (b.sqrMagnitude == 0.0f) { + return identity; + } + return b; + } + else if (b.sqrMagnitude == 0.0f) { + return a; + } + + Vector3Float axyz = a.xyz; + Vector3Float bxyz = b.xyz; + float cosHalfAngle = a.w * b.w + Vector3Float.Dot(axyz, bxyz); + + Quaternion b2 = b; + if (cosHalfAngle >= 1.0f || cosHalfAngle <= -1.0f) { + // angle = 0.0f, so just return one input. + return a; + } + else if (cosHalfAngle < 0.0f) { + b2.x = -b.x; + b2.y = -b.y; + b2.z = -b.z; + b2.w = -b.w; + cosHalfAngle = -cosHalfAngle; + } + + float blendA; + float blendB; + if (cosHalfAngle < 0.99f) { + // do proper slerp for big angles + float halfAngle = MathF.Acos(cosHalfAngle); + float sinHalfAngle = MathF.Sin(halfAngle); + float oneOverSinHalfAngle = 1.0F / sinHalfAngle; + blendA = MathF.Sin(halfAngle * (1.0F - t)) * oneOverSinHalfAngle; + blendB = MathF.Sin(halfAngle * t) * oneOverSinHalfAngle; + } + else { + // do lerp if angle is really small. + blendA = 1.0f - t; + blendB = t; + } + Vector3Float v = axyz * blendA + b2.xyz * blendB; + Quaternion result = + new(v.horizontal, v.vertical, v.depth, blendA * a.w + blendB * b2.w); + if (result.sqrMagnitude > 0.0f) + return result.normalized; + else + return Quaternion.identity; + } + + /// + /// Convert this quaternion to angle/axis representation + /// + /// A pointer to the angle for the result + /// A pointer to the axis for the result + public readonly void ToAngleAxis(out float angle, out Vector3Float axis) { + ToAxisAngleRad(this, out axis, out angle); + angle *= AngleFloat.Rad2Deg; + } + private static void ToAxisAngleRad(Quaternion q, + out Vector3Float axis, + out float angle) { + Quaternion q1 = (MathF.Abs(q.w) > 1.0f) ? Quaternion.Normalize(q) : q; + angle = 2.0f * MathF.Acos(q1.w); // angle + float den = MathF.Sqrt(1.0F - q1.w * q1.w); + if (den > 0.0001f) { + axis = (q1.xyz / den).normalized; + } + else { + // This occurs when the angle is zero. + // Not a problem: just set an arbitrary normalized axis. + axis = new Vector3Float(1, 0, 0); + } + } + + /// + /// Returns the angle of around the give axis for a rotation + /// + /// The axis around which the angle should be + /// computed The source rotation + /// The signed angle around the axis + public static float GetAngleAround(Vector3Float axis, Quaternion rotation) { + Quaternion secondaryRotation = GetRotationAround(axis, rotation); + secondaryRotation.ToAngleAxis(out float rotationAngle, out Vector3Float rotationAxis); + + // Do the axis point in opposite directions? + if (Vector3Float.Dot(axis, rotationAxis) < 0) + rotationAngle = -rotationAngle; + + return rotationAngle; + } + + /// + /// Returns the rotation limited around the given axis + /// + /// The axis which which the rotation should be + /// limited The source rotation + /// The rotation around the given axis + public static Quaternion GetRotationAround(Vector3Float axis, Quaternion rotation) { + Vector3Float ra = new(rotation.x, rotation.y, rotation.z); // rotation axis + Vector3Float p = Vector3Float.Project( + ra, axis); // return projection ra on to axis (parallel component) + Quaternion twist = new(p.horizontal, p.vertical, p.depth, rotation.w); + twist = Normalize(twist); + return twist; + + } + + /// + /// Swing-twist decomposition of a rotation + /// + /// The base direction for the decomposition + /// The source rotation + /// A pointer to the quaternion for the swing + /// result A pointer to the quaternion for the + /// twist result + static void GetSwingTwist(Vector3Float axis, Quaternion q, + out Quaternion swing, out Quaternion twist) { + twist = GetRotationAround(axis, q); + swing = q * Inverse(twist); + } + + /// + /// Calculate the dot product of two quaternions + /// + /// The first rotation + /// The second rotation + /// + public static float Dot(Quaternion q1, Quaternion q2) { + return q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w; + } + } +#endif + +} \ No newline at end of file diff --git a/src/Spherical.cs b/src/Spherical.cs new file mode 100644 index 0000000..de06d24 --- /dev/null +++ b/src/Spherical.cs @@ -0,0 +1,185 @@ +using System; +#if UNITY_5_3_OR_NEWER +using Vector3 = UnityEngine.Vector3; +#endif + +namespace LinearAlgebra +{ + /// + /// A spherical vector + /// + /// This is a struct such that it is a value type and cannot be null + public struct Spherical + { + /// + /// Create a spherical vector + /// + /// The distance in meters + /// The direction of the vector + public Spherical(float distance, Direction direction) + { + this.distance = distance; + this.direction = direction; + } + + /// + /// Create spherical vector. All given angles are in degrees + /// + /// The distance in meters + /// The horizontal angle in degrees + /// The vertical angle in degrees + /// + public static Spherical Degrees(float distance, float horizontal, float vertical) + { + Direction direction = Direction.Degrees(horizontal, vertical); + Spherical s = new(distance, direction); + return s; + } + + public static Spherical Radians(float distance, float horizontal, float vertical) + { + Direction direction = Direction.Radians(horizontal, vertical); + Spherical s = new(distance, direction); + return s; + } + + /// + /// The distance in meters + /// + /// @remark The distance should never be negative + public float distance; + /// + /// The direction of the vector + /// + public Direction direction; + + /// + /// A spherical vector with zero degree angles and distance + /// + public readonly static Spherical zero = new(0, Direction.forward); + /// + /// A normalized forward-oriented vector + /// + public readonly static Spherical forward = new(1, Direction.forward); + + + // public static Spherical FromVector3Float(Vector3Float v) { + // float distance = v.magnitude; + // if (distance == 0.0f) + // return Spherical.zero; + // else { + // float verticalAngle = (float)((Angle.pi / 2 - Math.Acos(v.y / distance)) * Angle.Rad2Deg); + // float horizontalAngle = (float)Math.Atan2(v.x, v.z) * Angle.Rad2Deg; + // return Spherical.Degrees(distance, horizontalAngle, verticalAngle); + // } + // } + + public static Spherical FromVector3Float(Vector3Float v) + { + float distance = v.magnitude; + if (distance == 0.0f) + return Spherical.zero; + else + { + float verticalAngle = (float)(Math.PI / 2 - Math.Acos(v.vertical / distance)) * AngleFloat.Rad2Deg; + float horizontalAngle = (float)Math.Atan2(v.horizontal, v.depth) * AngleFloat.Rad2Deg; + return Degrees(distance, horizontalAngle, verticalAngle); + } + } + + // public Vector3Float ToVector3Float() { + // float verticalRad = (Angle.pi / 2) - this.direction.vertical * Angle.Deg2Rad; + // float horizontalRad = this.direction.horizontal * Angle.Deg2Rad; + // float cosVertical = (float)Math.Cos(verticalRad); + // float sinVertical = (float)Math.Sin(verticalRad); + // float cosHorizontal = (float)Math.Cos(horizontalRad); + // float sinHorizontal = (float)Math.Sin(horizontalRad); + + // float x = this.distance * sinVertical * sinHorizontal; + // float y = this.distance * cosVertical; + // float z = this.distance * sinVertical * cosHorizontal; + + // Vector3Float v = new(x, y, z); + // return v; + // } + + public Vector3Float ToVector3Float() + { + float verticalRad = (AngleFloat.deg90 - this.direction.vertical).inRadians; + float horizontalRad = this.direction.horizontal.inRadians; + float cosVertical = (float)Math.Cos(verticalRad); + float sinVertical = (float)Math.Sin(verticalRad); + float cosHorizontal = (float)Math.Cos(horizontalRad); + float sinHorizontal = (float)Math.Sin(horizontalRad); + + float x = this.distance * sinVertical * sinHorizontal; + float y = this.distance * cosVertical; + float z = this.distance * sinVertical * cosHorizontal; + + Vector3Float v = new(x, y, z); + return v; + } +#if UNITY_5_3_OR_NEWER + public static Spherical FromVector3(Vector3 v) + { + float distance = v.magnitude; + if (distance == 0.0f) + return Spherical.zero; + else + { + float verticalAngle = (float)(Math.PI / 2 - Math.Acos(v.y / distance)) * AngleFloat.Rad2Deg; + float horizontalAngle = (float)Math.Atan2(v.x, v.z) * AngleFloat.Rad2Deg; + return Degrees(distance, horizontalAngle, verticalAngle); + } + } + + public Vector3 ToVector3() + { + float verticalRad = (AngleFloat.deg90 - this.direction.vertical).inRadians; + float horizontalRad = this.direction.horizontal.inRadians; + float cosVertical = (float)Math.Cos(verticalRad); + float sinVertical = (float)Math.Sin(verticalRad); + float cosHorizontal = (float)Math.Cos(horizontalRad); + float sinHorizontal = (float)Math.Sin(horizontalRad); + + float x = this.distance * sinVertical * sinHorizontal; + float y = this.distance * cosVertical; + float z = this.distance * sinVertical * cosHorizontal; + + Vector3 v = new(x, y, z); + return v; + } +#endif + + public float magnitude + { + get + { + return this.distance; + } + } + public Spherical normalized + { + get + { + Spherical r = new() + { + distance = 1, + direction = this.direction + }; + return r; + } + } + + public static Spherical operator +(Spherical s1, Spherical s2) + { + // let's do it the easy way... + Vector3Float v1 = s1.ToVector3Float(); + Vector3Float v2 = s2.ToVector3Float(); + Vector3Float v = v1 + v2; + Spherical r = FromVector3Float(v); + return r; + } + + } +} \ No newline at end of file diff --git a/src/SwingTwist.cs b/src/SwingTwist.cs new file mode 100644 index 0000000..4437c4f --- /dev/null +++ b/src/SwingTwist.cs @@ -0,0 +1,116 @@ +#if !UNITY_5_3_OR_NEWER +using UnityEngine; +#endif + +namespace LinearAlgebra { + + /// + /// An orientation using swing and twist angles + /// + /// The swing rotation + /// The twist rotation + public struct SwingTwist { + public Direction swing; + public AngleFloat twist; + + public SwingTwist(Direction swing, AngleFloat twist) { + this.swing = swing; + this.twist = twist; + } + + /// + /// Create a swing/twist rotation using angles in degrees + /// + /// The swing angle in the horizontal plane in degrees + /// The swing angle in the vertical plan in degrees + /// The twist angle in degrees + /// The swing/twist rotation + public static SwingTwist Degrees(float horizontalSwing, float verticalSwing, float twist) { + Direction swing = Direction.Degrees(horizontalSwing, verticalSwing); + AngleFloat twistAngle = AngleFloat.Degrees(twist); + SwingTwist s = new(swing, twistAngle); + return s; + } + + /// + /// Create a swing/twist rotation using angles in degrees + /// + /// The swing angle in the horizontal plane in degrees + /// The swing angle in the vertical plan in degrees + /// The twist angle in degrees + /// The swing/twist rotation + public static SwingTwist Radians(float horizontalSwing, float verticalSwing, float twist) { + Direction swing = Direction.Radians(horizontalSwing, verticalSwing); + AngleFloat twistAngle = AngleFloat.Radians(twist); + SwingTwist s = new(swing, twistAngle); + return s; + } + +#if !UNITY_5_3_OR_NEWER + /// + /// A zero angle rotation + /// + public static readonly SwingTwist zero = Degrees(0, 0, 0); + + public Spherical ToAngleAxis() { + LinearAlgebra.Quaternion q = this.ToQuaternion(); + q.ToAngleAxis(out float angle, out Vector3Float axis); + Direction direction = Direction.FromVector3(axis); + + Spherical r = new(angle, direction); + return r; + } + + public static SwingTwist FromAngleAxis(Spherical r) { + Vector3Float vectorAxis = r.direction.ToVector3(); + LinearAlgebra.Quaternion q = LinearAlgebra.Quaternion.AngleAxis(AngleFloat.Degrees(r.distance), vectorAxis); + return FromQuaternion(q); + } + + /// + /// Convert a quaternion in a swing/twist rotation + /// + /// The quaternion to convert + /// The swing/twist rotation + public static SwingTwist FromQuaternion(LinearAlgebra.Quaternion q) { + Vector3Float v = LinearAlgebra.Quaternion.ToAngles(q); + SwingTwist r = Degrees(v.vertical, v.horizontal, v.depth); + return r; + } + + public LinearAlgebra.Quaternion ToQuaternion() { + LinearAlgebra.Quaternion q = LinearAlgebra.Quaternion.Euler(this.swing.vertical.inDegrees, + this.swing.horizontal.inDegrees, + this.twist.inDegrees); + return q; + + } + + public static SwingTwist FromQuat32(Quat32 q32) { + q32.ToAngles(out float right, out float up, out float forward); + SwingTwist r = Degrees(up, right, forward); + return r; + } +#endif +#if UNITY_5_3_OR_NEWER + /// + /// Convert a quaternion in a swing/twist rotation + /// + /// The quaternion to convert + /// The swing/twist rotation + public static SwingTwist FromQuaternion(UnityEngine.Quaternion q) { + UnityEngine.Vector3 angles = q.eulerAngles; + SwingTwist r = Degrees(angles.y, -angles.x, -angles.z); + return r; + } + + public UnityEngine.Quaternion ToUnityQuaternion() { + UnityEngine.Quaternion q = UnityEngine.Quaternion.Euler(this.swing.vertical.inDegrees, + this.swing.horizontal.inDegrees, + this.twist.inDegrees); + return q; + } +#endif + } + +} \ No newline at end of file diff --git a/src/Vector2Float.cs b/src/Vector2Float.cs new file mode 100644 index 0000000..e0418a8 --- /dev/null +++ b/src/Vector2Float.cs @@ -0,0 +1,483 @@ +using System; +using System.Numerics; + +namespace LinearAlgebra { + + /* + public struct Vector2Int { + public int horizontal; + public int vertical; + + public Vector2Int(int horizontal, int vertical) { + this.horizontal = horizontal; + this.vertical = vertical; + } + + /// + /// A vector with zero for all axis + /// + public static readonly Vector2Int zero = new(0, 0); + /// + /// A vector with values (1, 1) + /// + public static readonly Vector2Int one = new(1, 1); + /// + /// A vector with values (0, 1) + /// + public static readonly Vector2Int up = new(0, 1); + /// + /// A vector with values (0, -1) + /// + public static readonly Vector2Int down = new(0, -1); + /// + /// A vector with values (0, 1) + /// + public static readonly Vector2Int forward = new(0, 1); + /// + /// A vector with values (0, -1) + /// + public static readonly Vector2Int back = new(0, -1); + /// + /// A vector3 with values (-1, 0) + /// + public static readonly Vector2Int left = new(-1, 0); + /// + /// A vector with values (1, 0) + /// + public static readonly Vector2Int right = new(1, 0); + + /// + /// Tests if the vector has equal values as the given vector + /// + /// The vector to compare to + /// true if the vector values are equal + public readonly bool Equals(Vector2Int v) => this.horizontal == v.horizontal && vertical == v.vertical; + + /// + /// Tests if the vector is equal to the given object + /// + /// The object to compare to + /// false when the object is not a Vector2 or does not have equal values + public override readonly bool Equals(object obj) { + if (obj is not Vector2Int v) + return false; + + return (this.horizontal == v.horizontal && this.vertical == v.vertical); + } + + /// + /// Tests if the two vectors have equal values + /// + /// The first vector + /// The second vector + /// truewhen the vectors have equal values + /// Note that this uses a Float equality check which cannot be not exact in all cases. + /// In most cases it is better to check if the Vector2.Distance between the vectors is smaller than Float.epsilon + /// Or more efficient: (v1 - v2).sqrMagnitude < Float.sqrEpsilon + public static bool operator ==(Vector2Int v1, Vector2Int v2) { + return (v1.horizontal == v2.horizontal && v1.vertical == v2.vertical); + } + /// + /// Tests if two vectors have different values + /// + /// The first vector + /// The second vector + /// truewhen the vectors have different values + /// Note that this uses a Float equality check which cannot be not exact in all case. + /// In most cases it is better to check if the Vector2.Distance between the vectors is smaller than Float.epsilon. + /// Or more efficient: (v1 - v2).sqrMagnitude < Float.sqrEpsilon + public static bool operator !=(Vector2Int v1, Vector2Int v2) { + return (v1.horizontal != v2.horizontal || v1.vertical != v2.vertical); + } + public readonly float magnitude { + get { + int h = this.horizontal; + int v = this.vertical; + return MathF.Sqrt(h * h + v * v); + } + } + + public static float MagnitudeOf(Vector2Int v) { + return v.magnitude; + } + + public static Vector2Int operator -(Vector2Int v1, Vector2Int v2) { + return new Vector2Int(v1.horizontal - v2.horizontal, v1.vertical - v2.vertical); + } + public static Vector2Int operator +(Vector2Int v1, Vector2Int v2) { + return new Vector2Int(v1.horizontal + v2.horizontal, v1.vertical + v2.vertical); + } + + public static float Distance(Vector2Int v1, Vector2Int v2) { + return (v1 - v2).magnitude; + } + } + + public struct Vector2Float { + public float horizontal; + public float vertical; + + public Vector2Float(float horizontal, float vertical) { + this.horizontal = horizontal; + this.vertical = vertical; + } + + public readonly float magnitude { + get { + float h = this.horizontal; + float v = this.vertical; + return MathF.Sqrt(h * h + v * v); + } + } + + public static Vector2Float operator -(Vector2Float v1, Vector2Float v2) { + return new Vector2Float(v1.horizontal - v2.horizontal, v1.vertical - v2.vertical); + } + + public static float Distance(Vector2Float v1, Vector2Float v2) { + return (v1 - v2).magnitude; + } + } + */ + + /// + /// 2-dimensional vectors + /// + public struct Vector2Float { + + /// + /// The right axis of the vector + /// + public float horizontal; // left/right + /// + /// The upward/forward axis of the vector + /// + public float vertical; // forward/backward + // directions are to be inline with Vector3 as much as possible... + + /// + /// Create a new 2-dimensional vector + /// + /// x axis value + /// y axis value + public Vector2Float(float x, float y) { + this.horizontal = x; + this.vertical = y; + } + + /// + /// Convert a Vector2Int into a Vector2Float + /// + /// The Vector2Int + public Vector2Float(Vector2Int v) { + this.horizontal = v.horizontal; + this.vertical = v.vertical; + } + + /// + /// A vector with zero for all axis + /// + public static readonly Vector2Float zero = new Vector2Float(0, 0); + /// + /// A vector with values (1, 1) + /// + public static readonly Vector2Float one = new Vector2Float(1, 1); + /// + /// A vector with values (0, 1) + /// + public static readonly Vector2Float up = new Vector2Float(0, 1); + /// + /// A vector with values (0, -1) + /// + public static readonly Vector2Float down = new Vector2Float(0, -1); + /// + /// A vector with values (0, 1) + /// + public static readonly Vector2Float forward = new Vector2Float(0, 1); + /// + /// A vector with values (0, -1) + /// + public static readonly Vector2Float back = new Vector2Float(0, -1); + /// + /// A vector3 with values (-1, 0) + /// + public static readonly Vector2Float left = new Vector2Float(-1, 0); + /// + /// A vector with values (1, 0) + /// + public static readonly Vector2Float right = new Vector2Float(1, 0); + + /// + /// The squared length of this vector + /// + /// The squared length + /// The squared length is computationally simpler than the real length. + /// Think of Pythagoras A^2 + B^2 = C^2. + /// This leaves out the calculation of the squared root of C. + public readonly float sqrMagnitude => horizontal * horizontal + vertical * vertical; + public static float SqrMagnitudeOf(Vector2Float v) { + return v.sqrMagnitude; + } + + /// + /// The length of this vector + /// + /// The length of this vector + public readonly float magnitude => MathF.Sqrt(horizontal * horizontal + vertical * vertical); + public static float MagnitudeOf(Vector2Float v) { + return v.magnitude; + } + + /// + /// Convert the vector to a length of a 1 + /// + /// The vector with length 1 + public Vector2Float normalized { + get { + float l = magnitude; + Vector2Float v = zero; + if (l > Float.epsilon) + v = this / l; + return v; + } + } + public static Vector2Float Normalize(Vector2Float v) { + return v.normalized; + } + + /// + /// Add two vectors + /// + /// The first vector + /// The second vector + /// The result of adding the two vectors + public static Vector2Float operator +(Vector2Float v1, Vector2Float v2) { + Vector2Float v = new Vector2Float(v1.horizontal + v2.horizontal, v1.vertical + v2.vertical); + return v; + } + + /// + /// Subtract two vectors + /// + /// The first vector + /// The second vector + /// The result of adding the two vectors + public static Vector2Float operator -(Vector2Float v1, Vector2Float v2) { + Vector2Float v = new Vector2Float(v1.horizontal - v2.horizontal, v1.vertical - v2.vertical); + return v; + } + + /// + /// Negate the vector + /// + /// The vector to negate + /// The negated vector + /// This will result in a vector pointing in the opposite direction + public static Vector2Float operator -(Vector2Float v1) { + Vector2Float v = new Vector2Float(-v1.horizontal, -v1.vertical); + return v; + } + + /// + /// Scale a vector uniformly down + /// + /// The vector to scale + /// The scaling factor + /// The scaled vector + /// Each component of the vector will be devided by the same factor. + public static Vector2Float operator /(Vector2Float v, float f) { + Vector2Float r = new(v.horizontal / f, v.vertical / f); + return r; + } + + + /// + /// Scale a vector uniformly up + /// + /// The vector to scale + /// The scaling factor + /// The scaled vector + /// Each component of the vector will be multipled with the same factor. + public static Vector2Float operator *(Vector2Float v1, float f) { + Vector2Float v = new Vector2Float(v1.horizontal * f, v1.vertical * f); + return v; + } + + /// + /// Scale a vector uniformly up + /// + /// The scaling factor + /// The vector to scale + /// The scaled vector + /// Each component of the vector will be multipled with the same factor. + public static Vector2Float operator *(float f, Vector2Float v1) { + Vector2Float v = new Vector2Float(f * v1.horizontal, f * v1.vertical); + return v; + } + + /// @brief Scale the vector using another vector + /// @param v1 The vector to scale + /// @param v2 A vector with the scaling factors + /// @return The scaled vector + /// @remark Each component of the vector v1 will be multiplied with the + /// matching component from the scaling vector v2. + public static Vector2Float Scale(Vector2Float v1, Vector2Float v2) { + return new Vector2Float(v1.horizontal * v2.horizontal, v1.vertical * v2.vertical); + } + + /* + /// + /// Tests if the vector has equal values as the given vector + /// + /// The vector to compare to + /// true if the vector values are equal + public bool Equals(Vector2Float v1) => horizontal == v1.horizontal && vertical == v1.vertical; + + /// + /// Tests if the vector is equal to the given object + /// + /// The object to compare to + /// false when the object is not a Vector2 or does not have equal values + public override bool Equals(object obj) { + if (!(obj is Vector2Float v)) + return false; + + return (horizontal == v.horizontal && vertical == v.vertical); + } + */ + + /// + /// Tests if the two vectors have equal values + /// + /// The first vector + /// The second vector + /// truewhen the vectors have equal values + /// Note that this uses a Float equality check which cannot be not exact in all cases. + /// In most cases it is better to check if the Vector2.Distance between the vectors is smaller than Float.epsilon + /// Or more efficient: (v1 - v2).sqrMagnitude < Float.sqrEpsilon + public static bool operator ==(Vector2Float v1, Vector2Float v2) { + return (v1.horizontal == v2.horizontal && v1.vertical == v2.vertical); + } + + /// + /// Tests if two vectors have different values + /// + /// The first vector + /// The second vector + /// truewhen the vectors have different values + /// Note that this uses a Float equality check which cannot be not exact in all case. + /// In most cases it is better to check if the Vector2.Distance between the vectors is smaller than Float.epsilon. + /// Or more efficient: (v1 - v2).sqrMagnitude < Float.sqrEpsilon + public static bool operator !=(Vector2Float v1, Vector2Float v2) { + return (v1.horizontal != v2.horizontal || v1.vertical != v2.vertical); + } + + /* + /// + /// Get an hash code for the vector + /// + /// The hash code + public override int GetHashCode() { + return (horizontal, vertical).GetHashCode(); + } + */ + + /// + /// Get the distance between two vectors + /// + /// The first vector + /// The second vector + /// The distance between the two vectors + public static float Distance(Vector2Float v1, Vector2Float v2) { + float x = v1.horizontal - v2.horizontal; + float y = v1.vertical - v2.vertical; + float d = (float)Math.Sqrt(x * x + y * y); + return d; + } + + /// + /// The dot product of two vectors + /// + /// The first vector + /// The second vector + /// The dot product of the two vectors + public static float Dot(Vector2Float v1, Vector2Float v2) { + return v1.horizontal * v2.horizontal + v1.vertical * v2.vertical; + } + + /// + /// Calculate the signed angle between two vectors. + /// + /// The starting vector + /// The ending vector + /// The axis to rotate around + /// The signed angle in degrees + public static float SignedAngle(Vector2Float from, Vector2Float to) { + //float sign = Math.Sign(v1.y * v2.x - v1.x * v2.y); + //return Vector2.Angle(v1, v2) * sign; + + float sqrMagFrom = from.sqrMagnitude; + float sqrMagTo = to.sqrMagnitude; + + if (sqrMagFrom == 0 || sqrMagTo == 0) + return 0; + //if (!isfinite(sqrMagFrom) || !isfinite(sqrMagTo)) + // return nanf(""); + + float angleFrom = (float)Math.Atan2(from.vertical, from.horizontal); + float angleTo = (float)Math.Atan2(to.vertical, to.horizontal); + return -(angleTo - angleFrom) * AngleFloat.Rad2Deg; + } + + public static float UnsignedAngle(Vector2Float from, Vector2Float to) { + return MathF.Abs(SignedAngle(from, to)); + } + + /// + /// Rotates the vector with the given angle + /// + /// The vector to rotate + /// The angle in degrees + /// + public static Vector2Float Rotate(Vector2Float v1, AngleFloat angle) { + float sin = (float)Math.Sin(angle.inRadians); + float cos = (float)Math.Cos(angle.inRadians); + // float sin = AngleFloat.Sin(angle); + // float cos = AngleFloat.Cos(angle); + + float tx = v1.horizontal; + float ty = v1.vertical; + Vector2Float v = new Vector2Float() { + horizontal = (cos * tx) - (sin * ty), + vertical = (sin * tx) + (cos * ty) + }; + return v; + } + + /// + /// Lerp between two vectors + /// + /// The from vector + /// The to vector + /// The interpolation distance [0..1] + /// The lerped vector + /// The factor f is unclamped. Value 0 matches the *v1* vector, Value 1 + /// matches the *v2* vector Value -1 is *v1* vector minus the difference + /// between *v1* and *v2* etc. + public static Vector2Float Lerp(Vector2Float v1, Vector2Float v2, float f) { + Vector2Float v = v1 + (v2 - v1) * f; + return v; + } + + /// + /// Map interval of angles between vectors [0..Pi] to interval [0..1] + /// + /// The first vector + /// The second vector + /// The resulting factor in interval [0..1] + /// Vectors a and b must be normalized + public static float ToFactor(Vector2Float v1, Vector2Float v2) { + return (1 - Vector2Float.Dot(v1, v2)) / 2; + } + } +} \ No newline at end of file diff --git a/src/Vector2Int.cs b/src/Vector2Int.cs new file mode 100644 index 0000000..0eca7dc --- /dev/null +++ b/src/Vector2Int.cs @@ -0,0 +1,176 @@ +using System; + +namespace LinearAlgebra { + + public struct Vector2Int { + public int horizontal; + public int vertical; + + public Vector2Int(int horizontal, int vertical) { + this.horizontal = horizontal; + this.vertical = vertical; + } + + /// + /// A vector with zero for all axis + /// + public static readonly Vector2Int zero = new(0, 0); + /// + /// A vector with values (1, 1) + /// + public static readonly Vector2Int one = new(1, 1); + /// + /// A vector with values (0, 1) + /// + public static readonly Vector2Int up = new(0, 1); + /// + /// A vector with values (0, -1) + /// + public static readonly Vector2Int down = new(0, -1); + /// + /// A vector with values (0, 1) + /// + public static readonly Vector2Int forward = new(0, 1); + /// + /// A vector with values (0, -1) + /// + public static readonly Vector2Int back = new(0, -1); + /// + /// A vector3 with values (-1, 0) + /// + public static readonly Vector2Int left = new(-1, 0); + /// + /// A vector with values (1, 0) + /// + public static readonly Vector2Int right = new(1, 0); + + /* + /// + /// Get an hash code for the vector + /// + /// The hash code + public override int GetHashCode() { + return (this.horizontal, this.vertical).GetHashCode(); + } + + /// + /// Tests if the vector has equal values as the given vector + /// + /// The vector to compare to + /// true if the vector values are equal + public readonly bool Equals(Vector2Int v) => this.horizontal == v.horizontal && vertical == v.vertical; + + /// + /// Tests if the vector is equal to the given object + /// + /// The object to compare to + /// false when the object is not a Vector2 or does not have equal values + public override readonly bool Equals(object obj) { + if (obj is not Vector2Int v) + return false; + + return (this.horizontal == v.horizontal && this.vertical == v.vertical); + } + */ + + /// + /// Tests if the two vectors have equal values + /// + /// The first vector + /// The second vector + /// truewhen the vectors have equal values + /// Note that this uses a Float equality check which cannot be not exact in all cases. + /// In most cases it is better to check if the Vector2.Distance between the vectors is smaller than Float.epsilon + /// Or more efficient: (v1 - v2).sqrMagnitude < Float.sqrEpsilon + public static bool operator ==(Vector2Int v1, Vector2Int v2) { + return (v1.horizontal == v2.horizontal && v1.vertical == v2.vertical); + } + /// + /// Tests if two vectors have different values + /// + /// The first vector + /// The second vector + /// truewhen the vectors have different values + /// Note that this uses a Float equality check which cannot be not exact in all case. + /// In most cases it is better to check if the Vector2.Distance between the vectors is smaller than Float.epsilon. + /// Or more efficient: (v1 - v2).sqrMagnitude < Float.sqrEpsilon + public static bool operator !=(Vector2Int v1, Vector2Int v2) { + return (v1.horizontal != v2.horizontal || v1.vertical != v2.vertical); + } + + public readonly float sqrMagnitude => this.horizontal * this.horizontal + this.vertical * this.vertical; + + public static float SqrMagnitudeOf(Vector2Int v) { + return v.sqrMagnitude; + } + + public readonly float magnitude => + MathF.Sqrt(this.horizontal * this.horizontal + this.vertical * this.vertical); + + public static float MagnitudeOf(Vector2Int v) { + return v.magnitude; + } + + /// @brief Convert the vector to a length of 1 + /// @return The vector normalized to a length of 1 + public readonly Vector2Float normalized { + get { + float l = magnitude; + Vector2Float v = Vector2Float.zero; + if (l > Float.epsilon) + v = new Vector2Float(this) / l; + return v; + } + } + /// @brief Convert the vector to a length of 1 + /// @param v The vector to convert + /// @return The vector normalized to a length of 1 + public static Vector2Float Normalize(Vector2Int v) { + float num = v.magnitude; + Vector2Float result = Vector2Float.zero; + if (num > Float.epsilon) + result = new Vector2Float(v) / num; + + return result; + } + + public static Vector2Int operator -(Vector2Int v) { + return new Vector2Int(-v.horizontal, -v.vertical); + } + + public static Vector2Int operator -(Vector2Int v1, Vector2Int v2) { + return new Vector2Int(v1.horizontal - v2.horizontal, v1.vertical - v2.vertical); + } + public static Vector2Int operator +(Vector2Int v1, Vector2Int v2) { + return new Vector2Int(v1.horizontal + v2.horizontal, v1.vertical + v2.vertical); + } + + public static Vector2Int operator /(Vector2Int v, int f) { + return new Vector2Int(v.horizontal / f, v.vertical / f); + } + + public static Vector2Int operator *(Vector2Int v1, int d) { + return new Vector2Int(v1.horizontal * d, v1.vertical * d); + } + + public static Vector2Int operator *(int d, Vector2Int v1) { + return new Vector2Int(d * v1.horizontal, d * v1.vertical); + } + + public static Vector2Int Scale(Vector2Int v1, Vector2Int v2) { + return new Vector2Int(v1.horizontal * v2.horizontal, v1.vertical * v2.vertical); + } + + /// @brief The dot product of two vectors + /// @param v1 The first vector + /// @param v2 The second vector + /// @return The dot product of the two vectors + public static int Dot(Vector2Int v1, Vector2Int v2) { + return v1.horizontal * v2.horizontal + v1.vertical * v2.vertical; + } + + public static float Distance(Vector2Int v1, Vector2Int v2) { + return (v1 - v2).magnitude; + } + } +} \ No newline at end of file diff --git a/src/Vector3Float.cs b/src/Vector3Float.cs new file mode 100644 index 0000000..bff0936 --- /dev/null +++ b/src/Vector3Float.cs @@ -0,0 +1,399 @@ +//#if !UNITY_5_3_OR_NEWER +using System; + +namespace LinearAlgebra { + /* + public struct Vector3Float { + public float horizontal; + public float vertical; + public float depth; + + public Vector3Float(float horizontal, float vertical, float depth) { + this.horizontal = horizontal; + this.vertical = vertical; + this.depth = depth; + } + + /// + /// A vector with zero for all axis + /// + public static readonly Vector3Float zero = new(0, 0, 0); + + public readonly float magnitude { + get => (float)Math.Sqrt(this.horizontal * this.horizontal + this.vertical * this.vertical + this.depth * this.depth); + } + + /// + /// Convert the vector to a length of a 1 + /// + /// The vector with length 1 + public readonly Vector3Float normalized { + get { + float l = magnitude; + Vector3Float v = zero; + if (l > Float.epsilon) + v = this / l; + return v; + } + } + + + public static Vector3Float operator *(Vector3Float v, float f) { + Vector3Float r = new(v.horizontal * f, v.vertical * f, v.depth * f); + return r; + } + public static Vector3Float operator /(Vector3Float v, float f) { + Vector3Float r = new(v.horizontal / f, v.vertical / f, v.depth / f); + return r; + } + + public static float Dot(Vector3Float v1, Vector3Float v2) { + return v1.horizontal * v2.horizontal + v1.vertical * v2.vertical + + v1.depth * v2.depth; + } + + const float epsilon = 1E-05f; + public static Vector3Float Project(Vector3Float v, Vector3Float n) { + float sqrMagnitude = Dot(n, n); + if (sqrMagnitude < epsilon) + return zero; + else { + float dot = Dot(v, n); + Vector3Float r = n * dot; + r /= sqrMagnitude; + return r; + } + + } + } + */ + + /// + /// 3-dimensional vectors + /// + /// This uses the right-handed coordinate system. + public struct Vector3Float { + + /// + /// The right axis of the vector + /// + public float horizontal; //> left/right + /// + /// The upward axis of the vector + /// + public float vertical; //> up/down + /// + /// The forward axis of the vector + /// + public float depth; //> forward/backward + + /// + /// Create a new 3-dimensional vector + /// + /// x axis value + /// y axis value + /// z axis value + public Vector3Float(float horizontal, float vertical, float depth) { + this.horizontal = horizontal; + this.vertical = vertical; + this.depth = depth; + } + + public Vector3Float(Vector3Int v) { + this.horizontal = v.horizontal; + this.vertical = v.vertical; + this.depth = v.depth; + } + + public static Vector3Float FromSpherical(Spherical s) { + float verticalRad = (AngleFloat.deg90 - s.direction.vertical).inRadians; + float horizontalRad = s.direction.horizontal.inRadians; + float cosVertical = MathF.Cos(verticalRad); + float sinVertical = MathF.Sin(verticalRad); + float cosHorizontal = MathF.Cos(horizontalRad); + float sinHorizontal = MathF.Sin(horizontalRad); + + float horizontal = s.distance * sinVertical * sinHorizontal; + float vertical = s.distance * cosVertical; + float depth = s.distance * sinVertical * cosHorizontal; + return new Vector3Float(horizontal, vertical, depth); + } + + /// + /// A vector with zero for all axis + /// + public static readonly Vector3Float zero = new Vector3Float(0, 0, 0); + /// + /// A vector with one for all axis + /// + public static readonly Vector3Float one = new Vector3Float(1, 1, 1); + /// + /// A Vector3Float with values (-1, 0, 0) + /// + public static readonly Vector3Float left = new Vector3Float(-1, 0, 0); + /// + /// A vector with values (1, 0, 0) + /// + public static readonly Vector3Float right = new Vector3Float(1, 0, 0); + /// + /// A vector with values (0, -1, 0) + /// + public static readonly Vector3Float down = new Vector3Float(0, -1, 0); + /// + /// A vector with values (0, 1, 0) + /// + public static readonly Vector3Float up = new Vector3Float(0, 1, 0); + /// + /// A vector with values (0, 0, -1) + /// + public static readonly Vector3Float back = new Vector3Float(0, -1, 0); + /// + /// A vector with values (0, 0, 1) + /// + public static readonly Vector3Float forward = new Vector3Float(0, 1, 0); + + /// @brief The vector length + /// @return The vector length + public readonly float magnitude => MathF.Sqrt(horizontal * horizontal + vertical * vertical + depth * depth); + /// + /// The vector length + /// + /// The vector for which you need the length + /// The vector length + public static float MagnitudeOf(Vector3Float v) { + return v.magnitude; + } + + /// @brief The squared vector length + /// @return The squared vector length + /// @remark The squared length is computationally simpler than the real + /// length. Think of Pythagoras A^2 + B^2 = C^2. This leaves out the + /// calculation of the squared root of C. + public readonly float sqrMagnitude => (horizontal * horizontal + vertical * vertical + depth * depth); + + /// + /// The squared vector length + /// + /// The vector for which you need the squared length + /// The squared vector length + /// The squared length is computationally simpler than the real + /// length. Think of Pythagoras A^2 + B^2 = C^2. This leaves out the + /// calculation of the squared root of C. + public static float SqrMagnitudeOf(Vector3Float v) { + return v.sqrMagnitude; + } + + /// @brief Convert the vector to a length of 1 + /// @return The vector normalized to a length of 1 + public readonly Vector3Float normalized { + get { + float l = magnitude; + Vector3Float v = zero; + if (l > Float.epsilon) + v = this / l; + return v; + } + } + /// @brief Convert the vector to a length of 1 + /// @param v The vector to convert + /// @return The vector normalized to a length of 1 + public static Vector3Float Normalize(Vector3Float v) { + float num = v.magnitude; + Vector3Float result = zero; + if (num > Float.epsilon) + result = v / num; + + return result; + } + + /// + /// Negate te vector such that it points in the opposite direction + /// + /// + /// The negated vector + public static Vector3Float operator -(Vector3Float v1) { + Vector3Float v = new(-v1.horizontal, -v1.vertical, -v1.depth); + return v; + } + + /// + /// Subtract two vectors + /// + /// + /// + /// The result of the subtraction + public static Vector3Float operator -(Vector3Float v1, Vector3Float v2) { + Vector3Float v = new(v1.horizontal - v2.horizontal, v1.vertical - v2.vertical, v1.depth - v2.depth); + return v; + } + + /// + /// Add two vectors + /// + /// + /// + /// The result of the addition + public static Vector3Float operator +(Vector3Float v1, Vector3Float v2) { + Vector3Float v = new(v1.horizontal + v2.horizontal, v1.vertical + v2.vertical, v1.depth + v2.depth); + return v; + } + + /// @brief Scale the vector using another vector + /// @param v1 The vector to scale + /// @param v2 A vector with the scaling factors + /// @return The scaled vector + /// @remark Each component of the vector v1 will be multiplied with the + /// matching component from the scaling vector v2. + public static Vector3Float Scale(Vector3Float v1, Vector3Float v2) { + return new Vector3Float(v1.horizontal * v2.horizontal, v1.vertical * v2.vertical, v1.depth * v2.depth); + } + + + public static Vector3Float operator *(Vector3Float v1, float d) { + Vector3Float v = new Vector3Float(v1.horizontal * d, v1.vertical * d, v1.depth * d); + return v; + } + + public static Vector3Float operator *(float d, Vector3Float v1) { + Vector3Float v = new Vector3Float(d * v1.horizontal, d * v1.vertical, d * v1.depth); + return v; + } + + public static Vector3Float operator /(Vector3Float v1, float d) { + Vector3Float v = new Vector3Float(v1.horizontal / d, v1.vertical / d, v1.depth / d); + return v; + } + + /* + public bool Equals(Vector3Float v) => (horizontal == v.horizontal && vertical == v.vertical && depth == v.depth); + + public override bool Equals(object obj) { + if (!(obj is Vector3Float v)) + return false; + + return (horizontal == v.horizontal && vertical == v.vertical && depth == v.depth); + } + */ + + public static bool operator ==(Vector3Float v1, Vector3Float v2) { + return (v1.horizontal == v2.horizontal && v1.vertical == v2.vertical && v1.depth == v2.depth); + } + + public static bool operator !=(Vector3Float v1, Vector3Float v2) { + return (v1.horizontal != v2.horizontal || v1.vertical != v2.vertical || v1.depth != v2.depth); + } + + // public override int GetHashCode() { + // return (horizontal, vertical, depth).GetHashCode(); + // } + + /// @brief The distance between two vectors + /// @param v1 The first vector + /// @param v2 The second vector + /// @return The distance between the two vectors + public static float Distance(Vector3Float v1, Vector3Float v2) { + return (v2 - v1).magnitude; + } + + /// @brief The dot product of two vectors + /// @param v1 The first vector + /// @param v2 The second vector + /// @return The dot product of the two vectors + public static float Dot(Vector3Float v1, Vector3Float v2) { + return v1.horizontal * v2.horizontal + v1.vertical * v2.vertical + v1.depth * v2.depth; + } + + /// @brief The cross product of two vectors + /// @param v1 The first vector + /// @param v2 The second vector + /// @return The cross product of the two vectors + public static Vector3Float Cross(Vector3Float v1, Vector3Float v2) { + return new Vector3Float(v1.vertical * v2.depth - v1.depth * v2.vertical, v1.depth * v2.horizontal - v1.horizontal * v2.depth, + v1.horizontal * v2.vertical - v1.vertical * v2.horizontal); + + } + + /// @brief Project the vector on another vector + /// @param v The vector to project + /// @param n The normal vecto to project on + /// @return The projected vector + public static Vector3Float Project(Vector3Float v, Vector3Float n) { + float sqrMagnitude = Dot(n, n); + if (sqrMagnitude < Float.epsilon) + return zero; + else { + float dot = Dot(v, n); + Vector3Float r = n * dot / sqrMagnitude; + return r; + } + } + + /// @brief Project the vector on a plane defined by a normal orthogonal to the + /// plane. + /// @param v The vector to project + /// @param n The normal of the plane to project on + /// @return Teh projected vector + public static Vector3Float ProjectOnPlane(Vector3Float v, Vector3Float n) { + Vector3Float r = v - Project(v, n); + return r; + } + + /// @brief The angle between two vectors + /// @param v1 The first vector + /// @param v2 The second vector + /// @return The angle between the two vectors + /// @remark This reterns an unsigned angle which is the shortest distance + /// between the two vectors. Use Vector3::SignedAngle if a signed angle is + /// needed. + public static AngleFloat UnsignedAngle(Vector3Float v1, Vector3Float v2) { + float denominator = MathF.Sqrt(v1.sqrMagnitude * v2.sqrMagnitude); + if (denominator < Float.epsilon) + return AngleFloat.zero; + + float dot = Dot(v1, v2); + float fraction = dot / denominator; + if (float.IsNaN(fraction)) + return AngleFloat.Degrees( + fraction); // short cut to returning NaN universally + + float cdot = Float.Clamp(fraction, -1.0f, 1.0f); + float r = MathF.Acos(cdot); + return AngleFloat.Radians(r); + } + /// @brief The signed angle between two vectors + /// @param v1 The starting vector + /// @param v2 The ending vector + /// @param axis The axis to rotate around + /// @return The signed angle between the two vectors + public static AngleFloat SignedAngle(Vector3Float v1, Vector3Float v2, + Vector3Float axis) { + // angle in [0,180] + AngleFloat angle = UnsignedAngle(v1, v2); + + Vector3Float cross = Cross(v1, v2); + float b = Dot(axis, cross); + float signd = b < 0 ? -1.0F : (b > 0 ? 1.0F : 0.0F); + + // angle in [-179,180] + AngleFloat signed_angle = angle * signd; + + return signed_angle; + } + + + /// @brief Lerp (linear interpolation) between two vectors + /// @param v1 The starting vector + /// @param v2 The ending vector + /// @param f The interpolation distance + /// @return The lerped vector + /// @remark The factor f is unclamped. Value 0 matches the vector *v1*, Value + /// 1 matches vector *v2*. Value -1 is vector *v1* minus the difference + /// between *v1* and *v2* etc. + public static Vector3Float Lerp(Vector3Float v1, Vector3Float v2, float f) { + Vector3Float v = v1 + (v2 - v1) * f; + return v; + } + + } +} +//#endif \ No newline at end of file diff --git a/src/Vector3Int.cs b/src/Vector3Int.cs new file mode 100644 index 0000000..18edf40 --- /dev/null +++ b/src/Vector3Int.cs @@ -0,0 +1,273 @@ +//#if !UNITY_5_3_OR_NEWER +using System; + +namespace LinearAlgebra { + + /// + /// 3-dimensional vectors + /// + /// This uses the right-handed coordinate system. + /// + /// Create a new 3-dimensional vector + /// + /// x axis value + /// y axis value + /// z axis value + public struct Vector3Int { + + /// + /// The right axis of the vector + /// + public int horizontal; //> left/right + /// + /// The upward axis of the vector + /// + public int vertical; //> up/down + /// + /// The forward axis of the vector + /// + public int depth; //> forward/backward + + public Vector3Int(int horizontal, int vertical, int depth) { + this.horizontal = horizontal; + this.vertical = vertical; + this.depth = depth; + } + + /// + /// A vector with zero for all axis + /// + public static readonly Vector3Int zero = new(0, 0, 0); + /// + /// A vector with one for all axis + /// + public static readonly Vector3Int one = new(1, 1, 1); + /// + /// A Vector3Int with values (-1, 0, 0) + /// + public static readonly Vector3Int left = new(-1, 0, 0); + /// + /// A vector with values (1, 0, 0) + /// + public static readonly Vector3Int right = new(1, 0, 0); + /// + /// A vector with values (0, -1, 0) + /// + public static readonly Vector3Int down = new(0, -1, 0); + /// + /// A vector with values (0, 1, 0) + /// + public static readonly Vector3Int up = new(0, 1, 0); + /// + /// A vector with values (0, 0, -1) + /// + public static readonly Vector3Int back = new(0, -1, 0); + /// + /// A vector with values (0, 0, 1) + /// + public static readonly Vector3Int forward = new(0, 1, 0); + + /// @brief The vector length + /// @return The vector length + public readonly float magnitude => MathF.Sqrt(horizontal * horizontal + vertical * vertical + depth * depth); + /// + /// The vector length + /// + /// The vector for which you need the length + /// The vector length + public static float MagnitudeOf(Vector3Int v) { + return v.magnitude; + } + + /// @brief The squared vector length + /// @return The squared vector length + /// @remark The squared length is computationally simpler than the real + /// length. Think of Pythagoras A^2 + B^2 = C^2. This leaves out the + /// calculation of the squared root of C. + public readonly float sqrMagnitude => (horizontal * horizontal + vertical * vertical + depth * depth); + + /// + /// The squared vector length + /// + /// The vector for which you need the squared length + /// The squared vector length + /// The squared length is computationally simpler than the real + /// length. Think of Pythagoras A^2 + B^2 = C^2. This leaves out the + /// calculation of the squared root of C. + public static float SqrMagnitudeOf(Vector3Int v) { + return v.sqrMagnitude; + } + + /// @brief Convert the vector to a length of 1 + /// @return The vector normalized to a length of 1 + public readonly Vector3Float normalized { + get { + float l = magnitude; + Vector3Float v = Vector3Float.zero; + if (l > Float.epsilon) + v = new Vector3Float(this) / l; + return v; + } + } + /// @brief Convert the vector to a length of 1 + /// @param v The vector to convert + /// @return The vector normalized to a length of 1 + public static Vector3Float Normalize(Vector3Int v) { + float num = v.magnitude; + Vector3Float result = Vector3Float.zero; + if (num > Float.epsilon) + result = new Vector3Float(v) / num; + + return result; + } + + /// + /// Negate te vector such that it points in the opposite direction + /// + /// + /// The negated vector + public static Vector3Int operator -(Vector3Int v1) { + Vector3Int v = new(-v1.horizontal, -v1.vertical, -v1.depth); + return v; + } + + /// + /// Subtract two vectors + /// + /// + /// + /// The result of the subtraction + public static Vector3Int operator -(Vector3Int v1, Vector3Int v2) { + Vector3Int v = new(v1.horizontal - v2.horizontal, v1.vertical - v2.vertical, v1.depth - v2.depth); + return v; + } + + /// + /// Add two vectors + /// + /// + /// + /// The result of the addition + public static Vector3Int operator +(Vector3Int v1, Vector3Int v2) { + Vector3Int v = new(v1.horizontal + v2.horizontal, v1.vertical + v2.vertical, v1.depth + v2.depth); + return v; + } + + /// @brief Scale the vector using another vector + /// @param v1 The vector to scale + /// @param v2 A vector with the scaling factors + /// @return The scaled vector + /// @remark Each component of the vector v1 will be multiplied with the + /// matching component from the scaling vector v2. + public static Vector3Int Scale(Vector3Int v1, Vector3Int v2) { + return new Vector3Int(v1.horizontal * v2.horizontal, v1.vertical * v2.vertical, v1.depth * v2.depth); + } + + + public static Vector3Int operator *(Vector3Int v1, int d) { + Vector3Int v = new(v1.horizontal * d, v1.vertical * d, v1.depth * d); + return v; + } + + public static Vector3Int operator *(int d, Vector3Int v1) { + Vector3Int v = new(d * v1.horizontal, d * v1.vertical, d * v1.depth); + return v; + } + + public static Vector3Int operator /(Vector3Int v1, int d) { + Vector3Int v = new(v1.horizontal / d, v1.vertical / d, v1.depth / d); + return v; + } + + public bool Equals(Vector3Int v) => (horizontal == v.horizontal && vertical == v.vertical && depth == v.depth); + + public override bool Equals(object obj) { + if (!(obj is Vector3Int v)) + return false; + + return (horizontal == v.horizontal && vertical == v.vertical && depth == v.depth); + } + + public static bool operator ==(Vector3Int v1, Vector3Int v2) { + return (v1.horizontal == v2.horizontal && v1.vertical == v2.vertical && v1.depth == v2.depth); + } + + public static bool operator !=(Vector3Int v1, Vector3Int v2) { + return (v1.horizontal != v2.horizontal || v1.vertical != v2.vertical || v1.depth != v2.depth); + } + + public override int GetHashCode() { + return (horizontal, vertical, depth).GetHashCode(); + } + + /// @brief The distance between two vectors + /// @param v1 The first vector + /// @param v2 The second vector + /// @return The distance between the two vectors + public static float Distance(Vector3Int v1, Vector3Int v2) { + return (v2 - v1).magnitude; + } + + /// @brief The dot product of two vectors + /// @param v1 The first vector + /// @param v2 The second vector + /// @return The dot product of the two vectors + public static float Dot(Vector3Int v1, Vector3Int v2) { + return v1.horizontal * v2.horizontal + v1.vertical * v2.vertical + v1.depth * v2.depth; + } + + /// @brief The cross product of two vectors + /// @param v1 The first vector + /// @param v2 The second vector + /// @return The cross product of the two vectors + public static Vector3Int Cross(Vector3Int v1, Vector3Int v2) { + return new Vector3Int(v1.vertical * v2.depth - v1.depth * v2.vertical, v1.depth * v2.horizontal - v1.horizontal * v2.depth, + v1.horizontal * v2.vertical - v1.vertical * v2.horizontal); + + } + + /// @brief The angle between two vectors + /// @param v1 The first vector + /// @param v2 The second vector + /// @return The angle between the two vectors + /// @remark This reterns an unsigned angle which is the shortest distance + /// between the two vectors. Use Vector3::SignedAngle if a signed angle is + /// needed. + public static AngleFloat UnsignedAngle(Vector3Int v1, Vector3Int v2) { + float denominator = MathF.Sqrt(v1.sqrMagnitude * v2.sqrMagnitude); + if (denominator < Float.epsilon) + return AngleFloat.zero; + + float dot = Dot(v1, v2); + float fraction = dot / denominator; + if (float.IsNaN(fraction)) + return AngleFloat.Degrees( + fraction); // short cut to returning NaN universally + + float cdot = Float.Clamp(fraction, -1.0f, 1.0f); + float r = MathF.Acos(cdot); + return AngleFloat.Radians(r); + } + /// @brief The signed angle between two vectors + /// @param v1 The starting vector + /// @param v2 The ending vector + /// @param axis The axis to rotate around + /// @return The signed angle between the two vectors + public static AngleFloat SignedAngle(Vector3Int v1, Vector3Int v2, + Vector3Int axis) { + // angle in [0,180] + AngleFloat angle = UnsignedAngle(v1, v2); + + Vector3Int cross = Cross(v1, v2); + float b = Dot(axis, cross); + float signd = b < 0 ? -1.0F : (b > 0 ? 1.0F : 0.0F); + + // angle in [-179,180] + AngleFloat signed_angle = angle * signd; + + return signed_angle; + } + + } +} +//#endif \ No newline at end of file diff --git a/src/float16.cs b/src/float16.cs new file mode 100644 index 0000000..4b58cdd --- /dev/null +++ b/src/float16.cs @@ -0,0 +1,322 @@ +using System; + +namespace LinearAlgebra { + + public class float16 { + // + // FILE: float16.cpp + // AUTHOR: Rob Tillaart + // VERSION: 0.1.8 + // PURPOSE: library for Float16s for Arduino + // URL: http://en.wikipedia.org/wiki/Half-precision_floating-point_format + + ushort _value; + + public float16() { _value = 0; } + + public float16(float f) { + //_value = f32tof16(f); + _value = F32ToF16__(f); + } + + public float toFloat() { + return f16tof32(_value); + } + + public ushort GetBinary() { return _value; } + public void SetBinary(ushort value) { _value = value; } + + ////////////////////////////////////////////////////////// + // + // EQUALITIES + // + /* + bool float16::operator ==(const float16 &f) { return (_value == f._value); } + + bool float16::operator !=(const float16 &f) { return (_value != f._value); } + + bool float16::operator >(const float16 &f) { + if ((_value & 0x8000) && (f._value & 0x8000)) + return _value < f._value; + if (_value & 0x8000) + return false; + if (f._value & 0x8000) + return true; + return _value > f._value; + } + + bool float16::operator >=(const float16 &f) { + if ((_value & 0x8000) && (f._value & 0x8000)) + return _value <= f._value; + if (_value & 0x8000) + return false; + if (f._value & 0x8000) + return true; + return _value >= f._value; + } + + bool float16::operator <(const float16 &f) { + if ((_value & 0x8000) && (f._value & 0x8000)) + return _value > f._value; + if (_value & 0x8000) + return true; + if (f._value & 0x8000) + return false; + return _value < f._value; + } + + bool float16::operator <=(const float16 &f) { + if ((_value & 0x8000) && (f._value & 0x8000)) + return _value >= f._value; + if (_value & 0x8000) + return true; + if (f._value & 0x8000) + return false; + return _value <= f._value; + } + + ////////////////////////////////////////////////////////// + // + // NEGATION + // + float16 float16::operator -() { + float16 f16; + f16.setBinary(_value ^ 0x8000); + return f16; + } + + ////////////////////////////////////////////////////////// + // + // MATH + // + float16 float16::operator +(const float16 &f) { + return float16(this->toDouble() + f.toDouble()); + } + + float16 float16::operator -(const float16 &f) { + return float16(this->toDouble() - f.toDouble()); + } + + float16 float16::operator *(const float16 &f) { + return float16(this->toDouble() * f.toDouble()); + } + + float16 float16::operator /(const float16 &f) { + return float16(this->toDouble() / f.toDouble()); + } + + float16 & float16::operator+=(const float16 &f) { + *this = this->toDouble() + f.toDouble(); + return *this; + } + + float16 & float16::operator-=(const float16 &f) { + *this = this->toDouble() - f.toDouble(); + return *this; + } + + float16 & float16::operator*=(const float16 &f) { + *this = this->toDouble() * f.toDouble(); + return *this; + } + + float16 & float16::operator/=(const float16 &f) { + *this = this->toDouble() / f.toDouble(); + return *this; + } + + ////////////////////////////////////////////////////////// + // + // MATH HELPER FUNCTIONS + // + int float16::sign() { + if (_value & 0x8000) + return -1; + if (_value & 0xFFFF) + return 1; + return 0; + } + + bool float16::isZero() { return ((_value & 0x7FFF) == 0x0000); } + + bool float16::isNaN() { + if ((_value & 0x7C00) != 0x7C00) + return false; + if ((_value & 0x03FF) == 0x0000) + return false; + return true; + } + + bool float16::isInf() { return ((_value == 0x7C00) || (_value == 0xFC00)); } + */ + ////////////////////////////////////////////////////////// + // + // CORE CONVERSION + // + float f16tof32(ushort _value) { + //ushort sgn; + ushort man; + int exp; + float f; + + //Debug.Log($"{_value}"); + + bool sgn = (_value & 0x8000) > 0; + exp = (_value & 0x7C00) >> 10; + man = (ushort)(_value & 0x03FF); + + //Debug.Log($"{sgn} {exp} {man}"); + + // ZERO + if ((_value & 0x7FFF) == 0) { + return sgn ? -0 : 0; + } + // NAN & INF + if (exp == 0x001F) { + if (man == 0) + return sgn ? float.NegativeInfinity : float.PositiveInfinity; //-INFINITY : INFINITY; + else + return float.NaN; // NAN; + } + + // SUBNORMAL/NORMAL + if (exp == 0) + f = 0; + else + f = 1; + + // PROCESS MANTISSE + for (int i = 9; i >= 0; i--) { + f *= 2; + if ((man & (1 << i)) != 0) + f = f + 1; + } + //Debug.Log($"{f}"); + f = f * (float)Math.Pow(2.0f, exp - 25); + if (exp == 0) { + f = f * (float)Math.Pow(2.0f, -13); // 5.96046447754e-8; + } + //Debug.Log($"{f}"); + return sgn ? -f : f; + } + + public static uint SingleToInt32Bits(float value) { + byte[] bytes = BitConverter.GetBytes(value); + if (BitConverter.IsLittleEndian) + Array.Reverse(bytes); // If the system is little-endian, reverse the byte order + return BitConverter.ToUInt32(bytes, 0); + } + + public ushort F32ToF16__(float f) { + uint t = BitConverter.ToUInt32(BitConverter.GetBytes(f), 0); + ushort man = (ushort)((t & 0x007FFFFF) >> 12); + int exp = (int)((t & 0x7F800000) >> 23); + bool sgn = (t & 0x80000000) != 0; + + // handle 0 + if ((t & 0x7FFFFFFF) == 0) { + return sgn ? (ushort)0x8000 : (ushort)0x0000; + } + // denormalized float32 does not fit in float16 + if (exp == 0x00) { + return sgn ? (ushort)0x8000 : (ushort)0x0000; + } + // handle infinity & NAN + if (exp == 0x00FF) { + if (man != 0) + return 0xFE00; // NAN + return sgn ? (ushort)0xFC00 : (ushort)0x7C00; // -INF : INF + } + + // normal numbers + exp = exp - 127 + 15; + // overflow does not fit => INF + if (exp > 30) { + return sgn ? (ushort)0xFC00 : (ushort)0x7C00; // -INF : INF + } + // subnormal numbers + if (exp < -38) { + return sgn ? (ushort)0x8000 : (ushort)0x0000; // -0 or 0 ? just 0 ? + } + if (exp <= 0) // subnormal + { + man >>= (exp + 14); + // rounding + man++; + man >>= 1; + if (sgn) + return (ushort)(0x8000 | man); + return man; + } + + // normal + // TODO rounding + exp <<= 10; + man++; + man >>= 1; + if (sgn) + return (ushort)(0x8000 | exp | man); + return (ushort)(exp | man); + } + + //This function is faulty!!!! + ushort f32tof16(float f) { + //uint t = *(uint*)&f; + //uint t = (uint)BitConverter.SingleToInt32Bits(f); + uint t = SingleToInt32Bits(f); + // man bits = 10; but we keep 11 for rounding + ushort man = (ushort)((t & 0x007FFFFF) >> 12); + short exp = (short)((t & 0x7F800000) >> 23); + bool sgn = (t & 0x80000000) != 0; + + // handle 0 + if ((t & 0x7FFFFFFF) == 0) { + return sgn ? (ushort)0x8000 : (ushort)0x0000; + } + // denormalized float32 does not fit in float16 + if (exp == 0x00) { + return sgn ? (ushort)0x8000 : (ushort)0x0000; + } + // handle infinity & NAN + if (exp == 0x00FF) { + if (man != 0) + return 0xFE00; // NAN + return sgn ? (ushort)0xFC00 : (ushort)0x7C00; // -INF : INF + } + + // normal numbers + exp = (short)(exp - 127 + 15); + // overflow does not fit => INF + if (exp > 30) { + return sgn ? (ushort)0xFC00 : (ushort)0x7C00; // -INF : INF + } + // subnormal numbers + if (exp < -38) { + return sgn ? (ushort)0x8000 : (ushort)0x0000; // -0 or 0 ? just 0 ? + } + if (exp <= 0) // subnormal + { + man >>= (exp + 14); + // rounding + man++; + man >>= 1; + if (sgn) + return (ushort)(0x8000 | man); + return man; + } + + // normal + // TODO rounding + exp <<= 10; + man++; + man >>= 1; + ushort uexp = (ushort)exp; + if (sgn) + return (ushort)(0x8000 | uexp | man); + return (ushort)(uexp | man); + } + + // -- END OF FILE -- + } + +} \ No newline at end of file diff --git a/test/AngleTest.cs b/test/AngleTest.cs new file mode 100644 index 0000000..787130d --- /dev/null +++ b/test/AngleTest.cs @@ -0,0 +1,497 @@ +#if !UNITY_5_6_OR_NEWER +using System; +using System.Formats.Asn1; +using NUnit.Framework; + +namespace LinearAlgebra.Test { + public class AngleTests { + [SetUp] + public void Setup() { + } + + [Test] + public void Construct() { + // Degrees + float angle = 0.0f; + AngleFloat a = AngleFloat.Degrees(angle); + Assert.AreEqual(angle, a.inDegrees); + + angle = -180.0f; + a = AngleFloat.Degrees(angle); + Assert.AreEqual(angle, a.inDegrees); + + angle = 270.0f; + a = AngleFloat.Degrees(angle); + Assert.AreEqual(-90, a.inDegrees); + + // Radians + angle = 0.0f; + a = AngleFloat.Radians(angle); + Assert.AreEqual(angle, a.inRadians); + + angle = (float)-Math.PI; + a = AngleFloat.Radians(angle); + Assert.AreEqual(angle, a.inRadians); + + angle = (float)Math.PI * 1.5f; + a = AngleFloat.Radians(angle); + Assert.AreEqual(-Math.PI * 0.5f, a.inRadians, 1.0E-05F); + + // Revolutions + angle = 0.0f; + a = AngleFloat.Revolutions(angle); + Assert.AreEqual(angle, a.inRevolutions); + + angle = -0.5f; + a = AngleFloat.Revolutions(angle); + Assert.AreEqual(angle, a.inRevolutions); + + angle = 0.75f; + a = AngleFloat.Revolutions(angle); + Assert.AreEqual(-0.25f, a.inRevolutions); + + } + + [Test] + public void Revolutions() { + AngleFloat a; + + // Test zero + a = AngleFloat.Revolutions(0.0f); + Assert.AreEqual(0.0f, a.inRevolutions); + + // Test positive values within range + a = AngleFloat.Revolutions(0.25f); + Assert.AreEqual(0.25f, a.inRevolutions); + + a = AngleFloat.Revolutions(0.5f); + Assert.AreEqual(-0.5f, a.inRevolutions); + + // Test negative values within range + a = AngleFloat.Revolutions(-0.25f); + Assert.AreEqual(-0.25f, a.inRevolutions); + + a = AngleFloat.Revolutions(-0.5f); + Assert.AreEqual(-0.5f, a.inRevolutions); + + // Test values outside range (positive) + a = AngleFloat.Revolutions(1.0f); + Assert.AreEqual(0.0f, a.inRevolutions); + + a = AngleFloat.Revolutions(1.25f); + Assert.AreEqual(0.25f, a.inRevolutions); + + a = AngleFloat.Revolutions(1.75f); + Assert.AreEqual(-0.25f, a.inRevolutions); + + // Test values outside range (negative) + a = AngleFloat.Revolutions(-1.0f); + Assert.AreEqual(0.0f, a.inRevolutions); + + a = AngleFloat.Revolutions(-1.25f); + Assert.AreEqual(-0.25f, a.inRevolutions); + + a = AngleFloat.Revolutions(-1.75f); + Assert.AreEqual(0.25f, a.inRevolutions); + + // Test infinity + a = AngleFloat.Revolutions(float.PositiveInfinity); + Assert.AreEqual(float.PositiveInfinity, a.inRevolutions); + + a = AngleFloat.Revolutions(float.NegativeInfinity); + Assert.AreEqual(float.NegativeInfinity, a.inRevolutions); + } + + [Test] + public void Equality() { + // Test equality operator + Assert.IsTrue(AngleFloat.Degrees(90) == AngleFloat.Degrees(90), "90 == 90"); + Assert.IsFalse(AngleFloat.Degrees(90) == AngleFloat.Degrees(45), "90 == 45"); + Assert.IsTrue(AngleFloat.Degrees(0) == AngleFloat.Degrees(0), "0 == 0"); + Assert.IsTrue(AngleFloat.Degrees(-180) == AngleFloat.Degrees(-180), "-180 == -180"); + + // Test inequality operator + Assert.IsTrue(AngleFloat.Degrees(90) != AngleFloat.Degrees(45), "90 != 45"); + Assert.IsFalse(AngleFloat.Degrees(90) != AngleFloat.Degrees(90), "90 != 90"); + Assert.IsTrue(AngleFloat.Degrees(0) != AngleFloat.Degrees(1), "0 != 1"); + + // Test greater than operator + Assert.IsTrue(AngleFloat.Degrees(90) > AngleFloat.Degrees(45), "90 > 45"); + Assert.IsFalse(AngleFloat.Degrees(45) > AngleFloat.Degrees(90), "45 > 90"); + Assert.IsFalse(AngleFloat.Degrees(90) > AngleFloat.Degrees(90), "90 > 90"); + + // Test greater than or equal operator + Assert.IsTrue(AngleFloat.Degrees(90) >= AngleFloat.Degrees(45), "90 >= 45"); + Assert.IsTrue(AngleFloat.Degrees(90) >= AngleFloat.Degrees(90), "90 >= 90"); + Assert.IsFalse(AngleFloat.Degrees(45) >= AngleFloat.Degrees(90), "45 >= 90"); + + // Test less than operator + Assert.IsTrue(AngleFloat.Degrees(45) < AngleFloat.Degrees(90), "45 < 90"); + Assert.IsFalse(AngleFloat.Degrees(90) < AngleFloat.Degrees(45), "90 < 45"); + Assert.IsFalse(AngleFloat.Degrees(90) < AngleFloat.Degrees(90), "90 < 90"); + + // Test less than or equal operator + Assert.IsTrue(AngleFloat.Degrees(45) <= AngleFloat.Degrees(90), "45 <= 90"); + Assert.IsTrue(AngleFloat.Degrees(90) <= AngleFloat.Degrees(90), "90 <= 90"); + Assert.IsFalse(AngleFloat.Degrees(90) <= AngleFloat.Degrees(45), "90 <= 45"); + } + + // [Test] + // public void Normalize() { + // float r = 0; + + // r = Angle.Normalize(90); + // Assert.AreEqual(r, 90, "Normalize 90"); + + // r = Angle.Normalize(-90); + // Assert.AreEqual(r, -90, "Normalize -90"); + + // r = Angle.Normalize(270); + // Assert.AreEqual(r, -90, "Normalize 270"); + + // r = Angle.Normalize(270 + 360); + // Assert.AreEqual(r, -90, "Normalize 270+360"); + + // r = Angle.Normalize(-270); + // Assert.AreEqual(r, 90, "Normalize -270"); + + // r = Angle.Normalize(-270 - 360); + // Assert.AreEqual(r, 90, "Normalize -270-360"); + + // r = Angle.Normalize(0); + // Assert.AreEqual(r, 0, "Normalize 0"); + + // r = Angle.Normalize(float.PositiveInfinity); + // Assert.AreEqual(r, float.PositiveInfinity, "Normalize INFINITY"); + + // r = Angle.Normalize(float.NegativeInfinity); + // Assert.AreEqual(r, float.NegativeInfinity, "Normalize INFINITY"); + // } + + [Test] + public void Clamp() { + float r = 0; + + r = AngleFloat.Clamp(AngleFloat.Degrees(1), AngleFloat.Degrees(0), AngleFloat.Degrees(2)); + Assert.AreEqual(1, r, "Clamp 1 0 2"); + + r = AngleFloat.Clamp(AngleFloat.Degrees(-1), AngleFloat.Degrees(0), AngleFloat.Degrees(2)); + Assert.AreEqual(0, r, "Clamp -1 0 2"); + + r = AngleFloat.Clamp(AngleFloat.Degrees(3), AngleFloat.Degrees(0), AngleFloat.Degrees(2)); + Assert.AreEqual(2, r, "Clamp 3 0 2"); + + r = AngleFloat.Clamp(AngleFloat.Degrees(1), AngleFloat.Degrees(0), AngleFloat.Degrees(0)); + Assert.AreEqual(0, r, "Clamp 1 0 0"); + + r = AngleFloat.Clamp(AngleFloat.Degrees(0), AngleFloat.Degrees(0), AngleFloat.Degrees(0)); + Assert.AreEqual(0, r, "Clamp 0 0 0"); + + r = AngleFloat.Clamp(AngleFloat.Degrees(0), AngleFloat.Degrees(1), AngleFloat.Degrees(-1)); + Assert.AreEqual(1, r, "Clamp 0 1 -1"); + + r = AngleFloat.Clamp(AngleFloat.Degrees(1), AngleFloat.Degrees(0), AngleFloat.Degrees(float.PositiveInfinity)); + Assert.AreEqual(1, r, "Clamp 1 0 INFINITY"); + + r = AngleFloat.Clamp(AngleFloat.Degrees(1), AngleFloat.Degrees(float.NegativeInfinity), AngleFloat.Degrees(1)); + Assert.AreEqual(1, r, "Clamp 1 -INFINITY 1"); + } + + [Test] + public void Cos() { + // Test zero + Assert.AreEqual(1.0f, AngleFloat.Cos(AngleFloat.Degrees(0)), 1.0E-05F, "Cos(0°)"); + + // Test 90 degrees + Assert.AreEqual(0.0f, AngleFloat.Cos(AngleFloat.Degrees(90)), 1.0E-05F, "Cos(90°)"); + + // Test 180 degrees + Assert.AreEqual(-1.0f, AngleFloat.Cos(AngleFloat.Degrees(180)), 1.0E-05F, "Cos(180°)"); + + // Test 270 degrees + Assert.AreEqual(0.0f, AngleFloat.Cos(AngleFloat.Degrees(270)), 1.0E-05F, "Cos(270°)"); + + // Test 45 degrees + Assert.AreEqual(MathF.Sqrt(2) / 2, AngleFloat.Cos(AngleFloat.Degrees(45)), 1.0E-05F, "Cos(45°)"); + + // Test negative angle + Assert.AreEqual(1.0f, AngleFloat.Cos(AngleFloat.Degrees(-360)), 1.0E-05F, "Cos(-360°)"); + + // Test using radians + Assert.AreEqual(1.0f, AngleFloat.Cos(AngleFloat.Radians(0)), 1.0E-05F, "Cos(0 rad)"); + Assert.AreEqual(0.0f, AngleFloat.Cos(AngleFloat.Radians((float)Math.PI / 2)), 1.0E-05F, "Cos(π/2)"); + Assert.AreEqual(-1.0f, AngleFloat.Cos(AngleFloat.Radians((float)Math.PI)), 1.0E-05F, "Cos(π)"); + } + + [Test] + public void Sin() { + // Test zero + Assert.AreEqual(0.0f, AngleFloat.Sin(AngleFloat.Degrees(0)), 1.0E-05F, "Sin(0°)"); + + // Test 90 degrees + Assert.AreEqual(1.0f, AngleFloat.Sin(AngleFloat.Degrees(90)), 1.0E-05F, "Sin(90°)"); + + // Test 180 degrees + Assert.AreEqual(0.0f, AngleFloat.Sin(AngleFloat.Degrees(180)), 1.0E-05F, "Sin(180°)"); + + // Test 270 degrees + Assert.AreEqual(-1.0f, AngleFloat.Sin(AngleFloat.Degrees(270)), 1.0E-05F, "Sin(270°)"); + + // Test 45 degrees + Assert.AreEqual(MathF.Sqrt(2) / 2, AngleFloat.Sin(AngleFloat.Degrees(45)), 1.0E-05F, "Sin(45°)"); + + // Test negative angle + Assert.AreEqual(0.0f, AngleFloat.Sin(AngleFloat.Degrees(-360)), 1.0E-05F, "Sin(-360°)"); + + // Test using radians + Assert.AreEqual(0.0f, AngleFloat.Sin(AngleFloat.Radians(0)), 1.0E-05F, "Sin(0 rad)"); + Assert.AreEqual(1.0f, AngleFloat.Sin(AngleFloat.Radians((float)Math.PI / 2)), 1.0E-05F, "Sin(π/2)"); + Assert.AreEqual(0.0f, AngleFloat.Sin(AngleFloat.Radians((float)Math.PI)), 1.0E-05F, "Sin(π)"); + } + + [Test] + public void Tan() { + // Test zero + Assert.AreEqual(0.0f, AngleFloat.Tan(AngleFloat.Degrees(0)), 1.0E-05F, "Tan(0°)"); + + // Test 45 degrees + Assert.AreEqual(1.0f, AngleFloat.Tan(AngleFloat.Degrees(45)), 1.0E-05F, "Tan(45°)"); + + // Test -45 degrees + Assert.AreEqual(-1.0f, AngleFloat.Tan(AngleFloat.Degrees(-45)), 1.0E-05F, "Tan(-45°)"); + + // Test using radians + Assert.AreEqual(0.0f, AngleFloat.Tan(AngleFloat.Radians(0)), 1.0E-05F, "Tan(0 rad)"); + Assert.AreEqual(1.0f, AngleFloat.Tan(AngleFloat.Radians((float)Math.PI / 4)), 1.0E-05F, "Tan(π/4)"); + } + + [Test] + public void Acos() { + // Test 1 (0 degrees) + Assert.AreEqual(0.0f, AngleFloat.Acos(1.0f).inRadians, 1.0E-05F, "Acos(1)"); + + // Test 0 (90 degrees or π/2 radians) + Assert.AreEqual((float)Math.PI / 2, AngleFloat.Acos(0.0f).inRadians, 1.0E-05F, "Acos(0)"); + + // Test -1 (-180 degrees or π radians) + Assert.AreEqual((float)-Math.PI, AngleFloat.Acos(-1.0f).inRadians, 1.0E-05F, "Acos(-1)"); + + // Test 0.5 (60 degrees or π/3 radians) + Assert.AreEqual((float)Math.PI / 3, AngleFloat.Acos(0.5f).inRadians, 1.0E-05F, "Acos(0.5)"); + + // Test sqrt(2)/2 (45 degrees or π/4 radians) + Assert.AreEqual((float)Math.PI / 4, AngleFloat.Acos(MathF.Sqrt(2) / 2).inRadians, 1.0E-05F, "Acos(√2/2)"); + } + + [Test] + public void Asin() { + // Test 0 (0 degrees) + Assert.AreEqual(0.0f, AngleFloat.Asin(0.0f).inRadians, 1.0E-05F, "Asin(0)"); + + // Test 1 (90 degrees or π/2 radians) + Assert.AreEqual((float)Math.PI / 2, AngleFloat.Asin(1.0f).inRadians, 1.0E-05F, "Asin(1)"); + + // Test -1 (-90 degrees or -π/2 radians) + Assert.AreEqual(-(float)Math.PI / 2, AngleFloat.Asin(-1.0f).inRadians, 1.0E-05F, "Asin(-1)"); + + // Test 0.5 (30 degrees or π/6 radians) + Assert.AreEqual((float)Math.PI / 6, AngleFloat.Asin(0.5f).inRadians, 1.0E-05F, "Asin(0.5)"); + + // Test sqrt(2)/2 (45 degrees or π/4 radians) + Assert.AreEqual((float)Math.PI / 4, AngleFloat.Asin(MathF.Sqrt(2) / 2).inRadians, 1.0E-05F, "Asin(√2/2)"); + } + + + [Test] + public void Atan() { + // Test zero + Assert.AreEqual(0.0f, AngleFloat.Atan(0.0f).inRadians, 1.0E-05F, "Atan(0)"); + + // Test 1 (45 degrees or π/4 radians) + Assert.AreEqual((float)Math.PI / 4, AngleFloat.Atan(1.0f).inRadians, 1.0E-05F, "Atan(1)"); + + // Test -1 (-45 degrees or -π/4 radians) + Assert.AreEqual(-(float)Math.PI / 4, AngleFloat.Atan(-1.0f).inRadians, 1.0E-05F, "Atan(-1)"); + + // Test sqrt(3) (60 degrees or π/3 radians) + Assert.AreEqual((float)Math.PI / 3, AngleFloat.Atan(MathF.Sqrt(3)).inRadians, 1.0E-05F, "Atan(√3)"); + + // Test 1/sqrt(3) (30 degrees or π/6 radians) + Assert.AreEqual((float)Math.PI / 6, AngleFloat.Atan(1.0f / MathF.Sqrt(3)).inRadians, 1.0E-05F, "Atan(1/√3)"); + + // Test positive infinity + Assert.AreEqual((float)Math.PI / 2, AngleFloat.Atan(float.PositiveInfinity).inRadians, 1.0E-05F, "Atan(+∞)"); + + // Test negative infinity + Assert.AreEqual(-(float)Math.PI / 2, AngleFloat.Atan(float.NegativeInfinity).inRadians, 1.0E-05F, "Atan(-∞)"); + } + + [Test] + public void Atan2() { + // Test basic quadrant I + Assert.AreEqual((float)Math.PI / 4, AngleFloat.Atan2(1.0f, 1.0f).inRadians, 1.0E-05F, "Atan2(1, 1)"); + + // Test quadrant II + Assert.AreEqual(3 * (float)Math.PI / 4, AngleFloat.Atan2(1.0f, -1.0f).inRadians, 1.0E-05F, "Atan2(1, -1)"); + + // Test quadrant III + Assert.AreEqual(-(float)Math.PI * 0.75f, AngleFloat.Atan2(-1.0f, -1.0f).inRadians, 1.0E-05F, "Atan2(-1, -1)"); + + // Test quadrant IV + Assert.AreEqual(-(float)Math.PI / 4, AngleFloat.Atan2(-1.0f, 1.0f).inRadians, 1.0E-05F, "Atan2(-1, 1)"); + + // Test positive x-axis + Assert.AreEqual(0.0f, AngleFloat.Atan2(0.0f, 1.0f).inRadians, 1.0E-05F, "Atan2(0, 1)"); + + // Test positive y-axis + Assert.AreEqual((float)Math.PI / 2, AngleFloat.Atan2(1.0f, 0.0f).inRadians, 1.0E-05F, "Atan2(1, 0)"); + + // Test negative y-axis + Assert.AreEqual(-(float)Math.PI / 2, AngleFloat.Atan2(-1.0f, 0.0f).inRadians, 1.0E-05F, "Atan2(-1, 0)"); + + // Test origin + Assert.AreEqual(0.0f, AngleFloat.Atan2(0.0f, 0.0f).inRadians, 1.0E-05F, "Atan2(0, 0)"); + + // Test with different magnitudes + Assert.AreEqual((float)Math.PI / 3, AngleFloat.Atan2(MathF.Sqrt(3), 1.0f).inRadians, 1.0E-05F, "Atan2(√3, 1)"); + + // Test negative x-axis + Assert.AreEqual((float)-Math.PI, AngleFloat.Atan2(0.0f, -1.0f).inRadians, 1.0E-05F, "Atan2(0, -1)"); + } + + [Test] + public void Multiplication() { + AngleFloat r = AngleFloat.zero; + + // Angle * float + r = AngleFloat.Degrees(90) * 2; + Assert.AreEqual(-180, r.inDegrees, "Multiply 90 * 2"); + + r = AngleFloat.Degrees(45) * 0.5f; + Assert.AreEqual(22.5f, r.inDegrees, "Multiply 45 * 0.5"); + + r = AngleFloat.Degrees(90) * 0; + Assert.AreEqual(0, r.inDegrees, "Multiply 90 * 0"); + + r = AngleFloat.Degrees(-90) * 2; + Assert.AreEqual(-180, r.inDegrees, "Multiply -90 * 2"); + + r = AngleFloat.Degrees(270) * 2; + Assert.AreEqual(-180, r.inDegrees, "Multiply 270 * 2 (normalized)"); + + // float * Angle + r = 2 * AngleFloat.Degrees(90); + Assert.AreEqual(-180, r.inDegrees, "Multiply 2 * 90"); + + r = 0.5f * AngleFloat.Degrees(45); + Assert.AreEqual(22.5, r.inDegrees, "Multiply 0.5 * 45"); + + r = 0 * AngleFloat.Degrees(90); + Assert.AreEqual(0, r.inDegrees, "Multiply 0 * 90"); + + r = 2 * AngleFloat.Degrees(-90); + Assert.AreEqual(-180, r.inDegrees, "Multiply 2 * -90"); + + // Negative factor + r = AngleFloat.Degrees(90) * -1; + Assert.AreEqual(-90, r.inDegrees, "Multiply 90 * -1"); + + r = -1 * AngleFloat.Degrees(90); + Assert.AreEqual(-90, r.inDegrees, "Multiply -1 * 90"); + } + + [Test] + public void MoveTowards() { + AngleFloat r = AngleFloat.zero; + + r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(90), 30); + Assert.AreEqual(30, r.inDegrees, "MoveTowards 0 90 30"); + + r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(90), 90); + Assert.AreEqual(90, r.inDegrees, "MoveTowards 0 90 90"); + + r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(90), 180); + Assert.AreEqual(90, r.inDegrees, "MoveTowards 0 90 180"); + + r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(90), 270); + Assert.AreEqual(90, r.inDegrees, "MoveTowrads 0 90 270"); + + r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(90), -30); + Assert.AreEqual(0, r.inDegrees, "MoveTowards 0 90 -30"); + + r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(-90), -30); + Assert.AreEqual(0, r.inDegrees, "MoveTowards 0 -90 -30"); + + r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(-90), -90); + Assert.AreEqual(0, r.inDegrees, "MoveTowards 0 -90 -90"); + + r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(-90), -180); + Assert.AreEqual(0, r.inDegrees, "MoveTowards 0 -90 -180"); + + r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(-90), -270); + Assert.AreEqual(0, r.inDegrees, "MoveTowrads 0 -90 -270"); + + r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(90), 0); + Assert.AreEqual(0, r.inDegrees, "MoveTowards 0 90 0"); + + r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(0), 0); + Assert.AreEqual(0, r.inDegrees, "MoveTowards 0 0 0"); + + r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(0), 30); + Assert.AreEqual(0, r.inDegrees, "MoveTowrads 0 0 30"); + + r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(90), float.PositiveInfinity); + Assert.AreEqual(90, r.inDegrees, "MoveTowards 0 90 INFINITY"); + + r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(float.PositiveInfinity), 30); + Assert.AreEqual(30, r.inDegrees, "MoveTowrads 0 INFINITY 30"); + + r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(-90), float.NegativeInfinity); + Assert.AreEqual(0, r.inDegrees, "MoveTowards 0 -90 -INFINITY"); + + r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(float.NegativeInfinity), -30); + Assert.AreEqual(0, r.inDegrees, "MoveTowrads 0 -INFINITY -30"); + + } + + [Test] + public void Difference() { + float r = 0; + + r = Angles.Difference(0, 90); + Assert.AreEqual(90, r, "Difference 0 90"); + + r = Angles.Difference(0, -90); + Assert.AreEqual(-90, r, "Difference 0 -90"); + + r = Angles.Difference(0, 270); + Assert.AreEqual(-90, r, "Difference 0 270"); + + r = Angles.Difference(0, -270); + Assert.AreEqual(90, r, "Difference 0 -270"); + + r = Angles.Difference(90, 0); + Assert.AreEqual(-90, r, "Difference 90 0"); + + r = Angles.Difference(-90, 0); + Assert.AreEqual(90, r, "Difference -90 0"); + + r = Angles.Difference(0, 0); + Assert.AreEqual(0, r, "Difference 0 0"); + + r = Angles.Difference(90, 90); + Assert.AreEqual(0, r, "Difference 90 90"); + + r = Angles.Difference(0, float.PositiveInfinity); + Assert.AreEqual(float.PositiveInfinity, r, "Difference 0 INFINITY"); + + r = Angles.Difference(0, float.NegativeInfinity); + Assert.AreEqual(float.NegativeInfinity, r, "Difference 0 -INFINITY"); + + r = Angles.Difference(float.NegativeInfinity, float.PositiveInfinity); + Assert.AreEqual(float.PositiveInfinity, r, "Difference -INFINITY INFINITY"); + } + } + +} +#endif diff --git a/test/DirectionTest.cs b/test/DirectionTest.cs new file mode 100644 index 0000000..146c9df --- /dev/null +++ b/test/DirectionTest.cs @@ -0,0 +1,201 @@ +#if !UNITY_5_6_OR_NEWER +using System; +using NUnit.Framework; + +namespace LinearAlgebra.Test { + public class DirectionTest { + + [Test] + public void RadiansForward() { + Direction d = Direction.Radians(0, 0); + Assert.AreEqual(0, d.horizontal.inDegrees, 0.0001f); + Assert.AreEqual(0, d.vertical.inDegrees, 0.0001f); + } + + [Test] + public void RadiansUp() { + Direction d = Direction.Radians(0, (float)Math.PI / 2); + Assert.AreEqual(0, d.horizontal.inDegrees, 0.0001f); + Assert.AreEqual(90, d.vertical.inDegrees, 0.0001f); + } + + [Test] + public void RadiansDown() { + Direction d = Direction.Radians(0, -(float)Math.PI / 2); + Assert.AreEqual(0, d.horizontal.inDegrees, 0.0001f); + Assert.AreEqual(-90, d.vertical.inDegrees, 0.0001f); + } + + [Test] + public void RadiansArbitrary() { + Direction d = Direction.Radians((float)Math.PI / 4, (float)Math.PI / 6); + Assert.AreEqual(45, d.horizontal.inDegrees, 0.0001f); + Assert.AreEqual(30, d.vertical.inDegrees, 0.0001f); + } + + [Test] + public void RadiansEquivalentToDegreesConversion() { + Direction d1 = Direction.Radians((float)Math.PI / 3, (float)Math.PI / 4); + Direction d2 = Direction.Degrees(60, 45); + Assert.AreEqual(d1.horizontal.inDegrees, d2.horizontal.inDegrees, 0.0001f); + Assert.AreEqual(d1.vertical.inDegrees, d2.vertical.inDegrees, 0.0001f); + } + + [Test] + public void ToVector3Forward() { + Direction d = Direction.forward; + Vector3Float v = d.ToVector3(); + Assert.AreEqual(0, v.horizontal, 0.0001f); + Assert.AreEqual(0, v.vertical, 0.0001f); + Assert.AreEqual(1, v.depth, 0.0001f); + } + + [Test] + public void ToVector3Up() { + Direction d = Direction.up; + Vector3Float v = d.ToVector3(); + Assert.AreEqual(0, v.horizontal, 0.0001f); + Assert.AreEqual(1, v.vertical, 0.0001f); + Assert.AreEqual(0, v.depth, 0.0001f); + } + + [Test] + public void ToVector3Down() { + Direction d = Direction.down; + Vector3Float v = d.ToVector3(); + Assert.AreEqual(0, v.horizontal, 0.0001f); + Assert.AreEqual(-1, v.vertical, 0.0001f); + Assert.AreEqual(0, v.depth, 0.0001f); + } + + [Test] + public void FromVector3Forward() { + Vector3Float v = new(0, 0, 1); + Direction d = Direction.FromVector3(v); + Assert.AreEqual(0, d.horizontal.inDegrees, 0.0001f); + Assert.AreEqual(0, d.vertical.inDegrees, 0.0001f); + } + + [Test] + public void ToVector3AndBack() { + Direction d1 = Direction.Degrees(45, 30); + Vector3Float v = d1.ToVector3(); + Direction d2 = Direction.FromVector3(v); + Assert.AreEqual(d1.horizontal.inDegrees, d2.horizontal.inDegrees, 0.0001f); + Assert.AreEqual(d1.vertical.inDegrees, d2.vertical.inDegrees, 0.0001f); + } + + [Test] + public void Compare() { + Direction d1 = Direction.Degrees(45, 135); + Direction d2 = new(AngleFloat.Degrees(45), AngleFloat.Degrees(135)); + bool r; + r = d1 == d2; + Assert.True(r); + Assert.AreEqual(d1, d2); + } + + [Test] + public void NotEqualWithDifferentHorizontal() { + Direction d1 = Direction.Degrees(45, 30); + Direction d2 = Direction.Degrees(90, 30); + Assert.True(d1 != d2); + } + + [Test] + public void NotEqualWithDifferentVertical() { + Direction d1 = Direction.Degrees(45, 30); + Direction d2 = Direction.Degrees(45, 60); + Assert.True(d1 != d2); + } + + [Test] + public void NotEqualWithDifferentBoth() { + Direction d1 = Direction.Degrees(45, 30); + Direction d2 = Direction.Degrees(90, 60); + Assert.True(d1 != d2); + } + + [Test] + public void NotEqualWithSameValues() { + Direction d1 = Direction.Degrees(45, 30); + Direction d2 = Direction.Degrees(45, 30); + Assert.False(d1 != d2); + } + + + [Test] + public void EqualsWithSameValues() { + Direction d1 = Direction.Degrees(45, 30); + Direction d2 = Direction.Degrees(45, 30); + Assert.True(d1.Equals(d2)); + } + + [Test] + public void EqualsWithDifferentHorizontal() { + Direction d1 = Direction.Degrees(45, 30); + Direction d2 = Direction.Degrees(90, 30); + Assert.False(d1.Equals(d2)); + } + + [Test] + public void EqualsWithDifferentVertical() { + Direction d1 = Direction.Degrees(45, 30); + Direction d2 = Direction.Degrees(45, 60); + Assert.False(d1.Equals(d2)); + } + + [Test] + public void EqualsWithDifferentBoth() { + Direction d1 = Direction.Degrees(45, 30); + Direction d2 = Direction.Degrees(90, 60); + Assert.False(d1.Equals(d2)); + } + + [Test] + public void EqualsWithNonDirectionObject() { + Direction d = Direction.Degrees(45, 30); + Assert.False(d.Equals("not a direction")); + } + + [Test] + public void EqualsWithNull() { + Direction d = Direction.Degrees(45, 30); + Assert.False(d.Equals(null)); + } + + [Test] + public void EqualsWithZeros() { + Direction d1 = Direction.forward; + Direction d2 = Direction.Degrees(0, 0); + Assert.True(d1.Equals(d2)); + } + + [Test] + public void HashCode() { + Direction d1 = Direction.Degrees(45, 30); + Direction d2 = Direction.Degrees(45, 30); + Assert.AreEqual(d1.GetHashCode(), d2.GetHashCode()); + + d1 = Direction.Degrees(45, 30); + d2 = Direction.Degrees(90, 30); + Assert.AreNotEqual(d1.GetHashCode(), d2.GetHashCode()); + + d1 = Direction.Degrees(45, 30); + d2 = Direction.Degrees(45, 60); + Assert.AreNotEqual(d1.GetHashCode(), d2.GetHashCode()); + + Direction d = Direction.Degrees(45, 30); + int hash1 = d.GetHashCode(); + int hash2 = d.GetHashCode(); + Assert.AreEqual(hash1, hash2); + + d1 = Direction.forward; + d2 = Direction.Degrees(0, 0); + Assert.AreEqual(d1.GetHashCode(), d2.GetHashCode()); + } + + }; +} +#endif + diff --git a/test/LinearAlgebra_Test.csproj b/test/LinearAlgebra_Test.csproj new file mode 100644 index 0000000..5b48e60 --- /dev/null +++ b/test/LinearAlgebra_Test.csproj @@ -0,0 +1,19 @@ + + + + net8.0 + false + true + + + + + + + + + + + + + diff --git a/test/QuaternionTest.cs b/test/QuaternionTest.cs new file mode 100644 index 0000000..9dd5a96 --- /dev/null +++ b/test/QuaternionTest.cs @@ -0,0 +1,185 @@ +#if !UNITY_5_6_OR_NEWER +using NUnit.Framework; + +namespace LinearAlgebra.Test { + + public class QuaternionTest { + + [SetUp] + public void Setup() { + } + + [Test] + public void Normalize() { + Quaternion q1 = new(0, 0, 0, 1); + Quaternion r = Quaternion.identity; + + r = q1.normalized; + Assert.AreEqual(r, q1, "q.normalized 0 0 0 1"); + + r = Quaternion.Normalize(q1); + Assert.AreEqual(r, q1, "q.normalized 0 0 0 1"); + } + + [Test] + public void ToAngles() { + Quaternion q1 = new(0, 0, 0, 1); + Vector3Float v = Vector3Float.zero; + + v = Quaternion.ToAngles(q1); + Assert.AreEqual(v, new Vector3Float(0, 0, 0), "ToAngles 0 0 0 1"); + + q1 = new(1, 0, 0, 0); + v = Quaternion.ToAngles(q1); + Assert.AreEqual(0, v.horizontal, "1 0 0 0 H"); + Assert.AreEqual(180, v.vertical, "1 0 0 0 V"); + Assert.AreEqual(180, v.depth, "1 0 0 0 D"); + + } + + [Test] + public void Multiplication() { + Quaternion q1 = new(0, 0, 0, 1); + Quaternion q2 = new(1, 0, 0, 0); + Quaternion r; + + r = q1 * q2; + Assert.AreEqual(r, new Quaternion(1, 0, 0, 0), "0 0 0 1 * 1 0 0 0 "); + } + + [Test] + public void MultiplicationVector() { + Quaternion q1 = new(0, 0, 0, 1); + Vector3Float v1 = new(0, 1, 0); + Vector3Float r; + + r = q1 * v1; + Assert.AreEqual(r, new Vector3Float(0, 1, 0), "0 0 0 1 * Vector 0 1 0"); + + q1 = new(1, 0, 0, 0); + r = q1 * v1; + Assert.AreEqual(r, new Vector3Float(0, -1, 0), "1 0 0 0 * Vector 0 1 0"); + } + + [Test] + public void Equality() { + Quaternion q1 = new(0, 0, 0, 1); + Quaternion q2 = new(1, 0, 0, 0); + Assert.AreNotEqual(q1, q2, "0 0 0 1 == 1 0 0 0"); + + q2 = new(0, 0, 0, 1); + Assert.AreEqual(q1, q2, "0 0 0 1 == 1 0 0 0"); + } + + [Test, Ignore("ToDo")] + public void Inverse() { } + + [Test, Ignore("ToDo")] + public void LookRotation() { } + + [Test, Ignore("ToDo")] + public void FromToRotation() { } + + [Test, Ignore("ToDo")] + public void RotateTowards() { } + + [Test, Ignore("ToDo")] + public void AngleAxis() { } + + [Test, Ignore("ToDo")] + public void Angle() { } + + [Test, Ignore("ToDo")] + public void Slerp() { } + + [Test, Ignore("ToDo")] + public void SlerpUnclamped() { } + + [Test] + public void Euler() { + Vector3Float v1 = new(0, 0, 0); + Quaternion q; + + q = Quaternion.Euler(v1); + Assert.AreEqual(q, Quaternion.identity, "Euler Vector 0 0 0"); + + q = Quaternion.Euler(0, 0, 0); + Assert.AreEqual(q, Quaternion.identity, "Euler 0 0 0"); + + v1 = new(90, 90, -90); + q = Quaternion.Euler(v1); + Assert.AreEqual(q, new Quaternion(0, 0.707106709F, -0.707106709F, 0), "Euler Vector 90 90 -90"); + + q = Quaternion.Euler(90, 90, -90); + Assert.AreEqual(q, new Quaternion(0, 0.707106709F, -0.707106709F, 0), "Euler 90 90 -90"); + } + + [Test] + public void EulerToAngles() { + Vector3Float v; + Quaternion q; + Quaternion r; + + //v = new(0, 0, 0); + q = Quaternion.Euler(0, 0 , 0); + v = Quaternion.ToAngles(q); + r = Quaternion.Euler(v); + Assert.AreEqual(0, Quaternion.UnsignedAngle(q, r), 10e-2f, "0 0 0"); + + q = Quaternion.Euler(-45, -30, -15); + v = Quaternion.ToAngles(q); + r = Quaternion.Euler(v); + Assert.AreEqual(0, Quaternion.UnsignedAngle(q, r), 10e-2f, "-45, -30, -15"); + + // Gimball lock + // q = Quaternion.Euler(90, 90, -90); + // v = Quaternion.ToAngles(q); + // r = Quaternion.Euler(v); + // Assert.AreEqual(0, Quaternion.UnsignedAngle(q, r), 10e-2f, "0 0 0"); + + } + + [Test] + public void GetAngleAround() { + Vector3Float v1 = new(0, 1, 0); + Quaternion q1 = new(0, 0, 0, 1); + + float f = Quaternion.GetAngleAround(v1, q1); + Assert.AreEqual(f, 0, "GetAngleAround 0 1 0 , 0 0 0 1"); + + q1 = new(0, 0.707106709F, -0.707106709F, 0); + f = Quaternion.GetAngleAround(v1, q1); + Assert.AreEqual(f, 180, "GetAngleAround 0 1 0 , 0 0.7 -0.7 0"); + + v1 = new(0, 0, 0); + f = Quaternion.GetAngleAround(v1, q1); + Assert.IsTrue(float.IsNaN(f), "GetAngleAround 0 0 0 , 0 0.7 -0.7 0"); + } + + [Test] + public void GetRotationAround() { + Vector3Float v1 = new(0, 1, 0); + Quaternion q1 = new(0, 0, 0, 1); + + Quaternion q = Quaternion.GetRotationAround(v1, q1); + Assert.AreEqual(q, new Quaternion(0, 0, 0, 1), "GetRotationAround 0 1 0 , 0 0 0 1"); + + q1 = new(0, 0.707106709F, -0.707106709F, 0); + q = Quaternion.GetRotationAround(v1, q1); + Assert.AreEqual(q, new Quaternion(0, 1, 0, 0), "GetRotationAround 0 1 0 , 0 0.7 -0.7 0"); + + v1 = new(0, 0, 0); + q = Quaternion.GetRotationAround(v1, q1); + bool r = float.IsNaN(q.x) && float.IsNaN(q.y) && float.IsNaN(q.z) && float.IsNaN(q.w); + Assert.IsTrue(r, "GetRotationAround 0 0 0 , 0 0.7 -0.7 0"); + } + + [Test, Ignore("ToDo")] + public void GetSwingTwist() { } + + [Test, Ignore("ToDo")] + public void Dot() { } + + } +} +#endif \ No newline at end of file diff --git a/test/SphericalTest.cs b/test/SphericalTest.cs new file mode 100644 index 0000000..125cdb1 --- /dev/null +++ b/test/SphericalTest.cs @@ -0,0 +1,53 @@ +#if !UNITY_5_6_OR_NEWER +using System; +using NUnit.Framework; + +namespace LinearAlgebra.Test { + public class SphericalTest { + [SetUp] + public void Setup() { + } + + [Test] + public void FromVector3() { + Vector3Float v = new(0, 0, 1); + Spherical s = Spherical.FromVector3(v); + Assert.AreEqual(1.0f, s.distance, "s.distance 0 0 1"); + Assert.AreEqual(0.0f, s.direction.horizontal.inDegrees, "s.hor 0 0 1"); + Assert.AreEqual(0.0f, s.direction.vertical.inDegrees, 1.0E-05F, "s.vert 0 0 1"); + + v = new(0, 1, 0); + s = Spherical.FromVector3(v); + Assert.AreEqual(1.0f, s.distance, "s.distance 0 1 0"); + Assert.AreEqual(0.0f, s.direction.horizontal.inDegrees, "s.hor 0 1 0"); + Assert.AreEqual(90.0f, s.direction.vertical.inDegrees, "s.vert 0 1 0"); + + v = new(1, 0, 0); + s = Spherical.FromVector3(v); + Assert.AreEqual(1.0f, s.distance, "s.distance 1 0 0"); + Assert.AreEqual(90.0f, s.direction.horizontal.inDegrees, "s.hor 1 0 0"); + Assert.AreEqual(0.0f, s.direction.vertical.inDegrees, 1.0E-05F, "s.vert 1 0 0"); + } + + [Test] + public void Addition() { + Spherical v1 = Spherical.Degrees(1, 45, 0); + Spherical v2 = Spherical.zero; + Spherical r = Spherical.zero; + + r = v1 + v2; + Assert.AreEqual(v1.distance, r.distance, 1.0E-05F, "Addition(0,0,0)"); + + r = v1; + r += v2; + Assert.AreEqual(v1.distance, r.distance, 1.0E-05F, "Addition(0,0,0)"); + + v2 = Spherical.Degrees(1, 0, 90); + r = v1 + v2; + Assert.AreEqual(Math.Sqrt(2), r.distance, 1.0E-05F, "Addition(1 0 90)"); + Assert.AreEqual(45.0f, r.direction.horizontal.inDegrees, "Addition(1 0 90)"); + Assert.AreEqual(45.0f, r.direction.vertical.inDegrees, 1.0E-05F, "Addition(1 0 90)"); + } + } +} +#endif \ No newline at end of file diff --git a/test/SwingTwistTest.cs b/test/SwingTwistTest.cs new file mode 100644 index 0000000..5f05a96 --- /dev/null +++ b/test/SwingTwistTest.cs @@ -0,0 +1,131 @@ +#if !UNITY_5_6_OR_NEWER +using NUnit.Framework; + +namespace LinearAlgebra.Test { + + [TestFixture] + public class SwingTwistTest { + + [Test] + public void Degrees_CreatesSwingTwistWithDegreeAngles() { + SwingTwist st = SwingTwist.Degrees(45, 30, 15); + Assert.IsNotNull(st); + Assert.AreEqual(45, st.swing.horizontal.inDegrees, 0.01f); + Assert.AreEqual(30, st.swing.vertical.inDegrees, 0.01f); + Assert.AreEqual(15, st.twist.inDegrees, 0.01f); + } + + [Test] + public void Radians_CreatesSwingTwistWithRadianAngles() { + float pi = (float)System.Math.PI; + SwingTwist st = SwingTwist.Radians(pi / 4, pi / 6, pi / 12); + Assert.IsNotNull(st); + Assert.AreEqual(45, st.swing.horizontal.inDegrees, 0.01f); + Assert.AreEqual(30, st.swing.vertical.inDegrees, 0.01f); + Assert.AreEqual(15, st.twist.inDegrees, 0.01f); + } + + [Test] + public void Zero_CreatesZeroRotation() { + SwingTwist st = SwingTwist.zero; + Assert.AreEqual(0, st.swing.horizontal.inDegrees, 0.01f); + Assert.AreEqual(0, st.swing.vertical.inDegrees, 0.01f); + Assert.AreEqual(0, st.twist.inDegrees, 0.01f); + } + + [Test] + public void QuaternionTest() { + Quaternion q; + SwingTwist s; + Quaternion r; + + q = Quaternion.identity; + s = SwingTwist.FromQuaternion(q); + r = s.ToQuaternion(); + Assert.AreEqual(q, r); + + q = Quaternion.Euler(90, 0, 0); + s = SwingTwist.FromQuaternion(q); + Assert.AreEqual(0, s.swing.horizontal.inDegrees, 10e-2f); + Assert.AreEqual(90, s.swing.vertical.inDegrees, 10e-2f); + Assert.AreEqual(0, s.twist.inDegrees, 0.01f); + r = s.ToQuaternion(); + Assert.AreEqual(0, Quaternion.UnsignedAngle(q, r), 10e-2f); + + q = Quaternion.Euler(0, 90, 0); + s = SwingTwist.FromQuaternion(q); + Assert.AreEqual(90, s.swing.horizontal.inDegrees,10e-2f); + Assert.AreEqual(0, s.swing.vertical.inDegrees, 0.01f); + Assert.AreEqual(0, s.twist.inDegrees, 0.01f); + r = s.ToQuaternion(); + Assert.AreEqual(0, Quaternion.UnsignedAngle(q, r), 10e-2f); + + q = Quaternion.Euler(0, 0, 90); + s = SwingTwist.FromQuaternion(q); + Assert.AreEqual(0, s.swing.horizontal.inDegrees, 0.01f); + Assert.AreEqual(0, s.swing.vertical.inDegrees, 0.01f); + Assert.AreEqual(90, s.twist.inDegrees, 0.01f); + r = s.ToQuaternion(); + Assert.AreEqual(0, Quaternion.UnsignedAngle(q, r), 10e-2f); + + q = Quaternion.Euler(0, 180, 0); + s = SwingTwist.FromQuaternion(q); + Assert.AreEqual(-180, s.swing.horizontal.inDegrees, 0.01f); + Assert.AreEqual(0, s.swing.vertical.inDegrees, 0.01f); + Assert.AreEqual(0, s.twist.inDegrees, 0.01f); + r = s.ToQuaternion(); + Assert.AreEqual(0, Quaternion.UnsignedAngle(q, r), 10e-2f); + + q = Quaternion.Euler(0, 135, 0); + s = SwingTwist.FromQuaternion(q); + Assert.AreEqual(135, s.swing.horizontal.inDegrees, 0.01f); + Assert.AreEqual(0, s.swing.vertical.inDegrees, 0.01f); + Assert.AreEqual(0, s.twist.inDegrees, 0.01f); + r = s.ToQuaternion(); + Assert.AreEqual(0, Quaternion.UnsignedAngle(q, r), 10e-2f); + + q = Quaternion.Euler(60, 45, 30); + s = SwingTwist.FromQuaternion(q); + Assert.AreEqual(45, s.swing.horizontal.inDegrees, 0.01f); + Assert.AreEqual(60, s.swing.vertical.inDegrees, 0.01f); + Assert.AreEqual(30, s.twist.inDegrees, 0.01f); + // r = s.ToQuaternion(); + // Assert.AreEqual(0, Quaternion.UnsignedAngle(q, r), 10e-2f); + + // q = Quaternion.Euler(-45, -30, -15); + // s = SwingTwist.FromQuaternion(q); + // Assert.AreEqual(-30, s.swing.horizontal.inDegrees, 0.01f); + // Assert.AreEqual(-45, s.swing.vertical.inDegrees, 0.01f); + // Assert.AreEqual(-15, s.twist.inDegrees, 0.01f); + // r = s.ToQuaternion(); + // Assert.AreEqual(0, Quaternion.UnsignedAngle(q, r), 10e-2f); + + // q = Quaternion.Euler(180, 180, 180); + // s = SwingTwist.FromQuaternion(q); + // Assert.AreEqual(-180, s.swing.horizontal.inDegrees, 0.01f); + // Assert.AreEqual(-180, s.swing.vertical.inDegrees, 0.01f); + // Assert.AreEqual(-180, s.twist.inDegrees, 0.01f); + // r = s.ToQuaternion(); + // Assert.AreEqual(0, Quaternion.UnsignedAngle(q, r), 10e-2f); + + } + + [Test] + public void ToAngleAxis_ConvertsToSpherical() { + SwingTwist st = SwingTwist.Degrees(45, 30, 15); + Spherical s = st.ToAngleAxis(); + Assert.IsNotNull(s); + } + + [Test] + public void FromAngleAxis_ConvertsFromSpherical() { + Spherical s = new(90, Direction.Degrees(45, 0)); + SwingTwist st = SwingTwist.FromAngleAxis(s); + Assert.IsNotNull(st); + } + + } + +} + +#endif \ No newline at end of file diff --git a/test/Vector2FloatTest.cs b/test/Vector2FloatTest.cs new file mode 100644 index 0000000..867765a --- /dev/null +++ b/test/Vector2FloatTest.cs @@ -0,0 +1,364 @@ +#if !UNITY_5_6_OR_NEWER +using NUnit.Framework; + +namespace LinearAlgebra.Test { + using Vector2 = Vector2Float; + + public class Vector2FloatTest { + + [SetUp] + public void Setup() { + } + + [Test] + public void FromPolar() { + } + + [Test] + public void Equality() { + Vector2 v1 = new(4, 5); + Vector2 v2 = new(1, 2); + + Assert.IsFalse(v1 == v2, "4 5 == 1 2"); + Assert.IsTrue(v1 != v2, "4 5 != 1 2"); + + v2 = new(4, 5); + Assert.IsTrue(v1 == v2, "4 5 == 4 5"); + Assert.IsFalse(v1 != v2, "4 5 != 4 5"); + } + + [Test] + public void Magnitude() { + Vector2 v = new(1, 2); + float m = 0; + m = v.magnitude; + Assert.AreEqual(m, 2.236068F, "v.magnitude 1 2"); + + m = Vector2.MagnitudeOf(v); + Assert.AreEqual(m, 2.236068F, "MagnitudeOf 1 2"); + + v = new(-1, -2); + m = v.magnitude; + Assert.AreEqual(m, 2.236068F, "v.magnitude -1 -2"); + + v = new(0, 0); + m = v.magnitude; + Assert.AreEqual(m, 0, "v.magnitude 0 0"); + } + + [Test] + public void SqrMagnitude() { + Vector2 v = new(1, 2); + float m = 0; + + m = v.sqrMagnitude; + Assert.AreEqual(m, 5, "v.sqrMagnitude 1 2"); + + m = Vector2.SqrMagnitudeOf(v); + Assert.AreEqual(m, 5, "SqrMagnitudeOf 1 2"); + + v = new(-1, -2); + m = v.sqrMagnitude; + Assert.AreEqual(m, 5, "v.sqrMagnitude -1 -2"); + + v = new(0, 0); + m = v.sqrMagnitude; + Assert.AreEqual(m, 0, "v.sqrMagnitude 0 0"); + } + + [Test] + public void Distance() { + Vector2 v1 = new(4, 5); + Vector2 v2 = new(1, 2); + float f = 0; + + f = Vector2.Distance(v1, v2); + Assert.AreEqual(f, 4.24264002f, 1.0E-05F, "Distance(4 5, 1 2)"); + + v2 = new(-1, -2); + f = Vector2.Distance(v1, v2); + Assert.AreEqual(f, 8.602325F, "Distance(4 5, 1 2)"); + + v2 = new(0, 0); + f = Vector2.Distance(v1, v2); + Assert.AreEqual(f, 6.403124F, 1.0E-05F, "Distance(4 5, 1 2)"); + } + + [Test] + public void Normalize() { + Vector2 v = new(0, 3); + Vector2Float r; + + r = v.normalized; + Assert.AreEqual(0, r.horizontal, "normalized 0 3 H"); + Assert.AreEqual(1, r.vertical, "normalized 0 3 V"); + + r = Vector2.Normalize(v); + Assert.AreEqual(0, r.horizontal, "Normalize 0 3 H"); + Assert.AreEqual(1, r.vertical, "Normalize 0 3 V"); + + v = new(0, -3); + r = v.normalized; + Assert.AreEqual(0, r.horizontal, "normalized 0 -3 H"); + Assert.AreEqual(-1, r.vertical, "normalized 0 -3 V"); + + v = new(0, 0); + r = v.normalized; + Assert.AreEqual(0, r.horizontal, "normalized 0 0 H"); + Assert.AreEqual(0, r.vertical, "normalized 0 0 V"); + } + + [Test] + public void Negate() { + Vector2 v = new(4, 5); + Vector2 r; + + r = -v; + Assert.AreEqual(-4, r.horizontal, "- 4 5 H"); + Assert.AreEqual(-5, r.vertical, "- 4 5 V"); + + v = new(-4, -5); + r = -v; + Assert.AreEqual(4, r.horizontal, "- -4 -5 H"); + Assert.AreEqual(5, r.vertical, "- -4 -5 V"); + + v = new(0, 0); + r = -v; + Assert.AreEqual(0, r.horizontal, "- 0 0 H"); + Assert.AreEqual(0, r.vertical, "- 0 0 V"); + } + + [Test] + public void Subtract() { + Vector2 v1 = new(4, 5); + Vector2 v2 = new(1, 2); + Vector2 r = Vector2.zero; + + r = v1 - v2; + Assert.IsTrue(r == new Vector2(3, 3), "4 5 - 1 2"); + + v2 = new(-1, -2); + r = v1 - v2; + Assert.IsTrue(r == new Vector2(5, 7), "4 5 - -1 -2"); + + v2 = new(4, 5); + r = v1 - v2; + Assert.IsTrue(r == new Vector2(0, 0), "4 5 - 4 5"); + r = v1; + r -= v2; + Assert.AreEqual(r, new Vector2(0, 0), "4 5 - 4 5"); + + v2 = new(0, 0); + r = v1 - v2; + Assert.AreEqual(r, new Vector2(4, 5), "4 5 - 0 0"); + r -= v2; + Assert.AreEqual(r, new Vector2(4, 5), "4 5 - 0 0"); + } + + [Test] + public void Addition() { + Vector2 v1 = new(4, 5); + Vector2 v2 = new(1, 2); + Vector2 r = Vector2.zero; + + r = v1 + v2; + Assert.IsTrue(r == new Vector2(5, 7), "4 5 + 1 2"); + + v2 = new(-1, -2); + r = v1 + v2; + Assert.IsTrue(r == new Vector2(3, 3), "4 5 + -1 -2"); + r = v1; + r += v2; + Assert.AreEqual(r, new Vector2(3, 3), "4 5 + -1 -2"); + + v2 = new(0, 0); + r = v1 + v2; + Assert.AreEqual(r, new Vector2(4, 5), "4 5 + 0 0"); + r += v2; + Assert.AreEqual(r, new Vector2(4, 5), "4 5 + 0 0"); + } + + [Test] + public void Scale() { + Vector2 v1 = new(4, 5); + Vector2 v2 = new(1, 2); + Vector2 r; + + r = Vector2.Scale(v1, v2); + Assert.AreEqual(4, r.horizontal, "Scale 4 5 , 1 2 H"); + Assert.AreEqual(10, r.vertical, "Scale 4 5 , 1 2 V"); + + v2 = new(-1, -2); + r = Vector2.Scale(v1, v2); + Assert.AreEqual(-4, r.horizontal, "Scale 4 5 , -1 -2 H"); + Assert.AreEqual(-10, r.vertical, "Scale 4 5 , -1 -2 V"); + + v2 = new(0, 0); + r = Vector2.Scale(v1, v2); + Assert.AreEqual(0, r.horizontal, "Scale 4 5 , 0 0 H"); + Assert.AreEqual(0, r.vertical, "Scale 4 5 , 0 0 V"); + } + + [Test] + public void Multiply() { + Vector2 v1 = new(4, 5); + int f = 3; + Vector2 r; + + r = v1 * f; + Assert.AreEqual(12, r.horizontal, "4 5 * 3 H"); + Assert.AreEqual(15, r.vertical, "4 5 * 3 V"); + + r = f * v1; + Assert.AreEqual(12, r.horizontal, "3 * 4 5 H"); + Assert.AreEqual(15, r.vertical, "3 * 4 5 V"); + + f = -3; + r = v1 * f; + Assert.AreEqual(-12, r.horizontal, "4 5 * -3 H"); + Assert.AreEqual(-15, r.vertical, "4 5 * -3 V"); + + f = 0; + r = v1 * f; + Assert.AreEqual(0, r.horizontal, "4 5 * 0 H"); + Assert.AreEqual(0, r.vertical, "4 5 * 0 V"); + } + + [Test] + public void Divide() { + Vector2 v1 = new(4, 5); + float f = 2; + Vector2 r; + + r = v1 / f; + Assert.AreEqual(2, r.horizontal, "4 5 / 2 H"); + Assert.AreEqual(2.5, r.vertical, "4 5 / 2 V"); + + f = -2; + r = v1 / f; + Assert.AreEqual(-2, r.horizontal, "4 5 / -2 H"); + Assert.AreEqual(-2.5, r.vertical, "4 5 / -2 V"); + + f = 0; + r = v1 / f; + Assert.AreEqual(float.PositiveInfinity, r.horizontal, "4 5 / 0 H"); + Assert.AreEqual(float.PositiveInfinity, r.vertical, "4 5 / 0 V"); + } + + [Test] + public void Dot() { + Vector2 v1 = new(4, 5); + Vector2 v2 = new(1, 2); + float f; + + f = Vector2.Dot(v1, v2); + Assert.AreEqual(14, f, "Dot(4 5, 1 2)"); + + v2 = new(-1, -2); + f = Vector2.Dot(v1, v2); + Assert.AreEqual(-14, f, "Dot(4 5, -1 -2)"); + + v2 = new(0, 0); + f = Vector2.Dot(v1, v2); + Assert.AreEqual(0, f, "Dot(4 5, 0 0)"); + } + + [Test] + public void SignedAngle() { + Vector2 v1 = new(4, 5); + Vector2 v2 = new(1, 2); + float f; + + f = Vector2.SignedAngle(v1, v2); + Assert.AreEqual(-12.094758f, f); + + v2 = new(-1, -2); + f = Vector2.SignedAngle(v1, v2); + Assert.AreEqual(167.905228f, f); + + v2 = new(0, 0); + f = Vector2.SignedAngle(v1, v2); + Assert.AreEqual(0, f); + + v1 = new(0, 1); + v2 = new(1, 0); + f = Vector2.SignedAngle(v1, v2); + Assert.AreEqual(90, f); + + v1 = new(0, 1); + v2 = new(0, -1); + f = Vector2.SignedAngle(v1, v2); + Assert.AreEqual(180, f); + } + + [Test] + public void UnsignedAngle() { + Vector2 v1 = new(4, 5); + Vector2 v2 = new(1, 2); + float f; + + f = Vector2.UnsignedAngle(v1, v2); + Assert.AreEqual(12.094758f, f); + + v2 = new(-1, -2); + f = Vector2.UnsignedAngle(v1, v2); + Assert.AreEqual(167.905228f, f); + + v2 = new(0, 0); + f = Vector2.UnsignedAngle(v1, v2); + Assert.AreEqual(0, f); + + v1 = new(0, 1); + v2 = new(1, 0); + f = Vector2.UnsignedAngle(v1, v2); + Assert.AreEqual(90, f); + + v1 = new(0, 1); + v2 = new(0, -1); + f = Vector2.UnsignedAngle(v1, v2); + Assert.AreEqual(180, f); + } + + [Test] + public void Rotate() { + Vector2 v1 = new(1, 2); + Vector2 r; + + r = Vector2.Rotate(v1, AngleFloat.Degrees(0)); + Assert.AreEqual(0, Vector2.Distance(r, v1)); + + r = Vector2.Rotate(v1, AngleFloat.Degrees(180)); + Assert.AreEqual(0, Vector2.Distance(r, new Vector2(-1, -2)), 1.0e-06); + + r = Vector2.Rotate(v1, AngleFloat.Degrees(-90)); + Assert.AreEqual(0, Vector2.Distance(r, new Vector2(2, -1)), 1.0e-06); + + r = Vector2.Rotate(v1, AngleFloat.Degrees(270)); + Assert.AreEqual(0, Vector2.Distance(r, new Vector2(2, -1)), 1.0e-06); + } + + [Test] + public void Lerp() { + Vector2 v1 = new(4, 5); + Vector2 v2 = new(1, 2); + Vector2 r; + + r = Vector2.Lerp(v1, v2, 0); + Assert.AreEqual(0, Vector2.Distance(r, v1), 0); + + r = Vector2.Lerp(v1, v2, 1); + Assert.AreEqual(0, Vector2.Distance(r, v2), 0); + + r = Vector2.Lerp(v1, v2, 0.5f); + Assert.AreEqual(0, Vector2.Distance(r, new Vector2(2.5f, 3.5f)), 0); + + r = Vector2.Lerp(v1, v2, -1); + Assert.AreEqual(0, Vector2.Distance(r, new Vector2(7, 8)), 0); + + r = Vector2.Lerp(v1, v2, 2); + Assert.AreEqual(0, Vector2.Distance(r, new Vector2(-2, -1)), 0); + } + + } +} +#endif \ No newline at end of file diff --git a/test/Vector2IntTest.cs b/test/Vector2IntTest.cs new file mode 100644 index 0000000..3647ca0 --- /dev/null +++ b/test/Vector2IntTest.cs @@ -0,0 +1,270 @@ +#if !UNITY_5_6_OR_NEWER +using NUnit.Framework; + +namespace LinearAlgebra.Test { + using Vector2 = Vector2Int; + + public class Vector2IntTest { + + [SetUp] + public void Setup() { + } + + [Test] + public void FromPolar() { + } + + [Test] + public void Equality() { + Vector2 v1 = new(4, 5); + Vector2 v2 = new(1, 2); + + Assert.IsFalse(v1 == v2, "4 5 == 1 2"); + Assert.IsTrue(v1 != v2, "4 5 != 1 2"); + + v2 = new(4, 5); + Assert.IsTrue(v1 == v2, "4 5 == 4 5"); + Assert.IsFalse(v1 != v2, "4 5 != 4 5"); + } + + [Test] + public void Magnitude() { + Vector2 v = new(1, 2); + float m = 0; + m = v.magnitude; + Assert.AreEqual(m, 2.236068F, "v.magnitude 1 2"); + + m = Vector2.MagnitudeOf(v); + Assert.AreEqual(m, 2.236068F, "MagnitudeOf 1 2"); + + v = new(-1, -2); + m = v.magnitude; + Assert.AreEqual(m, 2.236068F, "v.magnitude -1 -2"); + + v = new(0, 0); + m = v.magnitude; + Assert.AreEqual(m, 0, "v.magnitude 0 0"); + } + + [Test] + public void SqrMagnitude() { + Vector2 v = new(1, 2); + float m = 0; + + m = v.sqrMagnitude; + Assert.AreEqual(m, 5, "v.sqrMagnitude 1 2"); + + m = Vector2.SqrMagnitudeOf(v); + Assert.AreEqual(m, 5, "SqrMagnitudeOf 1 2"); + + v = new(-1, -2); + m = v.sqrMagnitude; + Assert.AreEqual(m, 5, "v.sqrMagnitude -1 -2"); + + v = new(0, 0); + m = v.sqrMagnitude; + Assert.AreEqual(m, 0, "v.sqrMagnitude 0 0"); + } + + [Test] + public void Distance() { + Vector2 v1 = new(4, 5); + Vector2 v2 = new(1, 2); + float f = 0; + + f = Vector2.Distance(v1, v2); + Assert.AreEqual(f, 4.24264002f, 1.0E-05F, "Distance(4 5, 1 2)"); + + v2 = new(-1, -2); + f = Vector2.Distance(v1, v2); + Assert.AreEqual(f, 8.602325F, "Distance(4 5, 1 2)"); + + v2 = new(0, 0); + f = Vector2.Distance(v1, v2); + Assert.AreEqual(f, 6.403124F, 1.0E-05F, "Distance(4 5, 1 2)"); + } + + [Test] + public void Normalize() { + Vector2 v = new(0, 3); + Vector2Float r; + + r = v.normalized; + Assert.AreEqual(0, r.horizontal, "normalized 0 3 H"); + Assert.AreEqual(1, r.vertical, "normalized 0 3 V"); + + r = Vector2.Normalize(v); + Assert.AreEqual(0, r.horizontal, "Normalize 0 3 H"); + Assert.AreEqual(1, r.vertical, "Normalize 0 3 V"); + + v = new(0, -3); + r = v.normalized; + Assert.AreEqual(0, r.horizontal, "normalized 0 -3 H"); + Assert.AreEqual(-1, r.vertical, "normalized 0 -3 V"); + + v = new(0, 0); + r = v.normalized; + Assert.AreEqual(0, r.horizontal, "normalized 0 0 H"); + Assert.AreEqual(0, r.vertical, "normalized 0 0 V"); + } + + [Test] + public void Negate() { + Vector2 v = new(4, 5); + Vector2 r; + + r = -v; + Assert.AreEqual(-4, r.horizontal, "- 4 5 H"); + Assert.AreEqual(-5, r.vertical, "- 4 5 V"); + + v = new(-4, -5); + r = -v; + Assert.AreEqual(4, r.horizontal, "- -4 -5 H"); + Assert.AreEqual(5, r.vertical, "- -4 -5 V"); + + v = new(0, 0); + r = -v; + Assert.AreEqual(0, r.horizontal, "- 0 0 H"); + Assert.AreEqual(0, r.vertical, "- 0 0 V"); + } + + [Test] + public void Subtract() { + Vector2 v1 = new(4, 5); + Vector2 v2 = new(1, 2); + Vector2 r = Vector2.zero; + + r = v1 - v2; + Assert.IsTrue(r == new Vector2(3, 3), "4 5 - 1 2"); + + v2 = new(-1, -2); + r = v1 - v2; + Assert.IsTrue(r == new Vector2(5, 7), "4 5 - -1 -2"); + + v2 = new(4, 5); + r = v1 - v2; + Assert.IsTrue(r == new Vector2(0, 0), "4 5 - 4 5"); + r = v1; + r -= v2; + Assert.AreEqual(r, new Vector2(0, 0), "4 5 - 4 5"); + + v2 = new(0, 0); + r = v1 - v2; + Assert.AreEqual(r, new Vector2(4, 5), "4 5 - 0 0"); + r -= v2; + Assert.AreEqual(r, new Vector2(4, 5), "4 5 - 0 0"); + } + + [Test] + public void Addition() { + Vector2 v1 = new(4, 5); + Vector2 v2 = new(1, 2); + Vector2 r = Vector2.zero; + + r = v1 + v2; + Assert.IsTrue(r == new Vector2(5, 7), "4 5 + 1 2"); + + v2 = new(-1, -2); + r = v1 + v2; + Assert.IsTrue(r == new Vector2(3, 3), "4 5 + -1 -2"); + r = v1; + r += v2; + Assert.AreEqual(r, new Vector2(3, 3), "4 5 + -1 -2"); + + v2 = new(0, 0); + r = v1 + v2; + Assert.AreEqual(r, new Vector2(4, 5), "4 5 + 0 0"); + r += v2; + Assert.AreEqual(r, new Vector2(4, 5), "4 5 + 0 0"); + } + + [Test] + public void Scale() { + Vector2 v1 = new(4, 5); + Vector2 v2 = new(1, 2); + Vector2 r; + + r = Vector2.Scale(v1, v2); + Assert.AreEqual(4, r.horizontal, "Scale 4 5 , 1 2 H"); + Assert.AreEqual(10, r.vertical, "Scale 4 5 , 1 2 V"); + + v2 = new(-1, -2); + r = Vector2.Scale(v1, v2); + Assert.AreEqual(-4, r.horizontal, "Scale 4 5 , -1 -2 H"); + Assert.AreEqual(-10, r.vertical, "Scale 4 5 , -1 -2 V"); + + v2 = new(0, 0); + r = Vector2.Scale(v1, v2); + Assert.AreEqual(0, r.horizontal, "Scale 4 5 , 0 0 H"); + Assert.AreEqual(0, r.vertical, "Scale 4 5 , 0 0 V"); + } + + [Test] + public void Multiply() { + Vector2 v1 = new(4, 5); + int f = 3; + Vector2 r; + + r = v1 * f; + Assert.AreEqual(12, r.horizontal, "4 5 * 3 H"); + Assert.AreEqual(15, r.vertical, "4 5 * 3 V"); + + r = f * v1; + Assert.AreEqual(12, r.horizontal, "3 * 4 5 H"); + Assert.AreEqual(15, r.vertical, "3 * 4 5 V"); + + f = -3; + r = v1 * f; + Assert.AreEqual(-12, r.horizontal, "4 5 * -3 H"); + Assert.AreEqual(-15, r.vertical, "4 5 * -3 V"); + + f = 0; + r = v1 * f; + Assert.AreEqual(0, r.horizontal, "4 5 * 0 H"); + Assert.AreEqual(0, r.vertical, "4 5 * 0 V"); + } + + [Test] + public void Divide() { + Vector2 v1 = new(4, 5); + int f = 2; + Vector2 r; + + r = v1 / f; + Assert.AreEqual(2, r.horizontal, "4 5 / 2 H"); + Assert.AreEqual(2, r.vertical, "4 5 / 2 V"); + + f = -2; + r = v1 / f; + Assert.AreEqual(-2, r.horizontal, "4 5 / -2 H"); + Assert.AreEqual(-2, r.vertical, "4 5 / -2 V"); + + Assert.Throws(() => { + f = 0; + r = v1 / f; + Assert.AreEqual(float.PositiveInfinity, r.horizontal, "4 5 / 0 H"); + Assert.AreEqual(float.PositiveInfinity, r.vertical, "4 5 / 0 V"); + }); + } + + [Test] + public void Dot() { + Vector2 v1 = new(4, 5); + Vector2 v2 = new(1, 2); + int f; + + f = Vector2.Dot(v1, v2); + Assert.AreEqual(14, f, "Dot(4 5, 1 2)"); + + v2 = new(-1, -2); + f = Vector2.Dot(v1, v2); + Assert.AreEqual(-14, f, "Dot(4 5, -1 -2)"); + + v2 = new(0, 0); + f = Vector2.Dot(v1, v2); + Assert.AreEqual(0, f, "Dot(4 5, 0 0)"); + } + + } +} +#endif \ No newline at end of file diff --git a/test/Vector3FloatTest.cs b/test/Vector3FloatTest.cs new file mode 100644 index 0000000..fd3c2dc --- /dev/null +++ b/test/Vector3FloatTest.cs @@ -0,0 +1,581 @@ +#if !UNITY_5_6_OR_NEWER +using NUnit.Framework; + +namespace LinearAlgebra.Test { + using Vector3 = Vector3Float; + + public class Vector3FloatTest { + + [Test] + public void FromSpherical() { + Vector3 v = new(0, 0, 1); + Spherical s = Spherical.FromVector3(v); + Vector3 r = Vector3.FromSpherical(s); + + Assert.AreEqual(0, r.horizontal, "0 0 1"); + Assert.AreEqual(0, r.vertical, 1.0e-06, "0 0 1"); + Assert.AreEqual(1, r.depth, "0 0 1"); + + v = new(0, 1, 0); + s = Spherical.FromVector3(v); + r = Vector3.FromSpherical(s); + Assert.AreEqual(0, r.horizontal, "0 0 1"); + Assert.AreEqual(1, r.vertical, "0 0 1"); + Assert.AreEqual(0, r.depth, 1.0e-06, "0 0 1"); + + v = new(1, 0, 0); + s = Spherical.FromVector3(v); + r = Vector3.FromSpherical(s); + Assert.AreEqual(1, r.horizontal, "0 0 1"); + Assert.AreEqual(0, r.vertical, 1.0e-06, "0 0 1"); + Assert.AreEqual(0, r.depth, 1.0e-06, "0 0 1"); + } + + [Test] + public void Magnitude() { + Vector3 v = new(1, 2, 3); + float m = 0; + + m = v.magnitude; + Assert.AreEqual(3.7416575f, m, "magnitude 1 2 3"); + + m = Vector3.MagnitudeOf(v); + Assert.AreEqual(3.7416575f, m, "MagnitudeOf 1 2 3"); + + v = new(-1, -2, -3); + m = v.magnitude; + Assert.AreEqual(3.7416575f, m, "magnitude -1 -2 -3"); + + v = new(0, 0, 0); + m = v.magnitude; + Assert.AreEqual(0, m, "magnitude 0 0 0"); + + // Infinity tests are still missing + } + + [Test] + public void SqrMagnitude() { + Vector3 v = new(1, 2, 3); + float m = 0; + + m = v.sqrMagnitude; + Assert.AreEqual(14, m, "sqrMagnitude 1 2 3"); + + m = Vector3.SqrMagnitudeOf(v); + Assert.AreEqual(14, m, "SqrMagnitudeOf 1 2 3"); + + v = new(-1, -2, -3); + m = v.sqrMagnitude; + Assert.AreEqual(14, m, "sqrMagnitude -1 -2 -3"); + + v = new(0, 0, 0); + m = v.sqrMagnitude; + Assert.AreEqual(0, m, "sqrMagnitude 0 0 0"); + + // Infinity tests are still missing + } + + [Test] + public void Normalize() { + Vector3 v = new(0, 2, 0); + Vector3 r; + + r = v.normalized; + Assert.AreEqual(new Vector3(0, 1, 0), r, "normalized 0 2 0"); + + r = Vector3.Normalize(v); + Assert.AreEqual(new Vector3(0, 1, 0), r, "Normalize 0 2 0"); + + v = new(0, -2, 0); + r = v.normalized; + Assert.AreEqual(new Vector3(0, -1, 0), r, "normalized 0 -2 0"); + v = new(0, 0, 0); + r = v.normalized; + Assert.AreEqual(new Vector3(0, 0, 0), r, "normalized 0 0 0"); + + v = new(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); + r = v.normalized; + Assert.IsTrue(float.IsNaN(r.horizontal), "normalized infinity infinity infinity"); + Assert.IsTrue(float.IsNaN(r.vertical), "normalized infinity infinity infinity"); + Assert.IsTrue(float.IsNaN(r.depth), "normalized infinity infinity infinity"); + + v = new(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); + r = v.normalized; + Assert.IsTrue(float.IsNaN(r.horizontal), "normalized -infinity -infinity -infinity"); + Assert.IsTrue(float.IsNaN(r.vertical), "normalized -infinity -infinity -infinity"); + Assert.IsTrue(float.IsNaN(r.depth), "normalized -infinity -infinity -infinity"); + } + + [Test] + public void Negate() { + Vector3 v = new(4, 5, 6); + Vector3 r; + + r = -v; + Assert.AreEqual(-4, r.horizontal, "- 4 5 6 H"); + Assert.AreEqual(-5, r.vertical, "- 4 5 6 V"); + Assert.AreEqual(-6, r.depth, "- 4 5 6 D"); + + v = new(-4, -5, -6); + r = -v; + Assert.AreEqual(4, r.horizontal, "- -4 -5 -6 H"); + Assert.AreEqual(5, r.vertical, "- -4 -5 -6 V"); + Assert.AreEqual(6, r.depth, "- -4 -5 -6 D"); + + v = new(0, 0, 0); + r = -v; + Assert.AreEqual(new Vector3(0, 0, 0), r, "- 0 0 0"); + Assert.AreEqual(0, r.horizontal, "- 0 0 0 H"); + Assert.AreEqual(0, r.vertical, "- 0 0 0 V"); + Assert.AreEqual(0, r.depth, "- 0 0 0 D"); + + + v = new(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); + r = -v; + Assert.AreEqual(new Vector3(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity), r, "- inifinty infinity infinity"); + + v = new(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); + r = -v; + Assert.AreEqual(new Vector3(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity), r, "- -inifinty -infinity -infinity"); + } + + [Test] + public void Subtract() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + Vector3 r = Vector3.zero; + + r = v1 - v2; + Assert.IsTrue(r == new Vector3(3, 3, 3), "4 5 6 - 1 2 3"); + + v2 = new(-1, -2, -3); + r = v1 - v2; + Assert.IsTrue(r == new Vector3(5, 7, 9), "4 5 6 - -1 -2 -3"); + + v2 = new(4, 5, 6); + r = v1 - v2; + Assert.IsTrue(r == new Vector3(0, 0, 0), "4 5 6 - 4 5 6"); + r = v1; + r -= v2; + Assert.AreEqual(r, new Vector3(0, 0, 0), "4 5 6 - 4 5 6"); + + v2 = new(0, 0, 0); + r = v1 - v2; + Assert.AreEqual(r, new Vector3(4, 5, 6), "4 5 6 - 0 0 0"); + r -= v2; + Assert.AreEqual(r, new Vector3(4, 5, 6), "4 5 6 - 0 0 0"); + + // Infinity tests are still missing + } + + [Test] + public void Addition() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + Vector3 r = Vector3.zero; + + r = v1 + v2; + Assert.IsTrue(r == new Vector3(5, 7, 9), "4 5 6 + 1 2 3"); + + v2 = new(-1, -2, -3); + r = v1 + v2; + Assert.IsTrue(r == new Vector3(3, 3, 3), "4 5 6 + -1 -2 -3"); + r = v1; + r += v2; + Assert.AreEqual(r, new Vector3(3, 3, 3), "4 5 6 + -1 -2 -3"); + + v2 = new(0, 0, 0); + r = v1 + v2; + Assert.AreEqual(r, new Vector3(4, 5, 6), "4 5 6 + 0 0 0"); + r += v2; + Assert.AreEqual(r, new Vector3(4, 5, 6), "4 5 6 + 0 0 0"); + + // Infinity tests are still missing + } + + [Test] + public void Scale() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + Vector3 r; + + r = Vector3.Scale(v1, v2); + Assert.AreEqual(4, r.horizontal, "Scale 4 5 6 , 1 2 3 H"); + Assert.AreEqual(10, r.vertical, "Scale 4 5 6 , 1 2 3 V"); + Assert.AreEqual(18, r.depth, "Scale 4 5 6 , 1 2 3 D"); + + v2 = new(-1, -2, -3); + r = Vector3.Scale(v1, v2); + Assert.AreEqual(-4, r.horizontal, "Scale 4 5 6 , -1 -2 -3 H"); + Assert.AreEqual(-10, r.vertical, "Scale 4 5 6 , -1 -2 -3 V"); + Assert.AreEqual(-18, r.depth, "Scale 4 5 6 , -1 -2 -3 D"); + + v2 = new(0, 0, 0); + r = Vector3.Scale(v1, v2); + Assert.AreEqual(0, r.horizontal, "Scale 4 5 6 , 0 0 0 H"); + Assert.AreEqual(0, r.vertical, "Scale 4 5 6 , 0 0 0 V"); + Assert.AreEqual(0, r.depth, "Scale 4 5 6 , 0 0 0 D"); + + v2 = new(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); + r = Vector3.Scale(v1, v2); + Assert.AreEqual(float.PositiveInfinity, r.horizontal, "Scale 4 5 6 , inf inf inf H"); + Assert.AreEqual(float.PositiveInfinity, r.vertical, "Scale 4 5 6 , inf inf inf V"); + Assert.AreEqual(float.PositiveInfinity, r.depth, "Scale 4 5 6 , inf inf inf D"); + + v2 = new(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); + r = Vector3.Scale(v1, v2); + Assert.AreEqual(float.NegativeInfinity, r.horizontal, "Scale 4 5 6 , -inf -inf -inf H"); + Assert.AreEqual(float.NegativeInfinity, r.vertical, "Scale 4 5 6 , -inf -inf -inf V"); + Assert.AreEqual(float.NegativeInfinity, r.depth, "Scale 4 5 6 , -inf -inf -inf D"); + } + + [Test] + public void Multiply() { + Vector3 v1 = new(4, 5, 6); + float f = 3; + Vector3 r; + + r = v1 * f; + Assert.AreEqual(12, r.horizontal, "4 5 6 * 3 H"); + Assert.AreEqual(15, r.vertical, "4 5 6 * 3 V"); + Assert.AreEqual(18, r.depth, "4 5 6 * 3 D"); + + f = -3; + r = v1 * f; + Assert.AreEqual(-12, r.horizontal, "4 5 6 * -3 H"); + Assert.AreEqual(-15, r.vertical, "4 5 6 * -3 V"); + Assert.AreEqual(-18, r.depth, "4 5 6 * -3 D"); + + f = 0; + r = v1 * f; + Assert.AreEqual(0, r.horizontal, "4 5 6 * 0 H"); + Assert.AreEqual(0, r.vertical, "4 5 6 * 0 V"); + Assert.AreEqual(0, r.depth, "4 5 6 * 0 D"); + + f = float.PositiveInfinity; + r = v1 * f; + Assert.AreEqual(float.PositiveInfinity, r.horizontal, "4 5 6 * inf H"); + Assert.AreEqual(float.PositiveInfinity, r.vertical, "4 5 6 * inf V"); + Assert.AreEqual(float.PositiveInfinity, r.depth, "4 5 6 * inf D"); + + f = float.NegativeInfinity; + r = v1 * f; + Assert.AreEqual(float.NegativeInfinity, r.horizontal, "4 5 6 * -inf H"); + Assert.AreEqual(float.NegativeInfinity, r.vertical, "4 5 6 * -inf V"); + Assert.AreEqual(float.NegativeInfinity, r.depth, "4 5 6 * -inf D"); + } + + [Test] + public void Divide() { + Vector3 v1 = new(4, 5, 6); + float f = 2; + Vector3 r; + + r = v1 / f; + Assert.AreEqual(2, r.horizontal, "4 5 6 / 2 H"); + Assert.AreEqual(2.5, r.vertical, "4 5 6 / 2 V"); + Assert.AreEqual(3, r.depth, "4 5 6 / 2 D"); + + f = -2; + r = v1 / f; + Assert.AreEqual(-2, r.horizontal, "4 5 6 / -2 H"); + Assert.AreEqual(-2.5, r.vertical, "4 5 6 / -2 V"); + Assert.AreEqual(-3, r.depth, "4 5 6 / -2 D"); + + f = 0; + r = v1 / f; + Assert.AreEqual(float.PositiveInfinity, r.horizontal, "4 5 6 / 0 H"); + Assert.AreEqual(float.PositiveInfinity, r.vertical, "4 5 6 / 0 V"); + Assert.AreEqual(float.PositiveInfinity, r.depth, "4 5 6 / 0 D"); + + f = float.PositiveInfinity; + r = v1 / f; + Assert.AreEqual(0, r.horizontal, "4 5 6 / inf H"); + Assert.AreEqual(0, r.vertical, "4 5 6 / inf V"); + Assert.AreEqual(0, r.depth, "4 5 6 / inf D"); + + f = float.NegativeInfinity; + r = v1 / f; + Assert.AreEqual(0, r.horizontal, "4 5 6 / -inf H"); + Assert.AreEqual(0, r.vertical, "4 5 6 / -inf V"); + Assert.AreEqual(0, r.depth, "4 5 6 / -inf D"); + } + + [Test] + public void Dot() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + float f; + + f = Vector3.Dot(v1, v2); + Assert.AreEqual(32, f, "Dot(4 5 6, 1 2 3)"); + + v2 = new(-1, -2, -3); + f = Vector3.Dot(v1, v2); + Assert.AreEqual(-32, f, "Dot(4 5 6, -1 -2 -3)"); + + v2 = new(0, 0, 0); + f = Vector3.Dot(v1, v2); + Assert.AreEqual(0, f, "Dot(4 5 6, 0 0 0)"); + + v2 = new(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); + f = Vector3.Dot(v1, v2); + Assert.AreEqual(float.PositiveInfinity, f, "Dot(4 5 6, inf inf inf)"); + + v2 = new(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); + f = Vector3.Dot(v1, v2); + Assert.AreEqual(float.NegativeInfinity, f, "Dot(4 5 6, -inf -inf -inf)"); + } + + [Test] + public void Equality() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + bool r; + + r = v1 == v2; + Assert.IsFalse(r, "4 5 6 == 1 2 3"); + + v2 = new(4, 5, 6); + r = v1 == v2; + Assert.IsTrue(r, "4 5 6 == 4 5 6"); + + v2 = new(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); + r = v1 == v2; + Assert.IsFalse(r, "4 5 6 == inf inf inf"); + + v1 = new(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); + r = v1 == v2; + Assert.IsFalse(r, "-inf -inf -inf == inf inf inf"); + } + + [Test] + public void Distance() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + float f; + + f = Vector3.Distance(v1, v2); + Assert.AreEqual(5.19615221F, f, "Distance(4 5 6, 1 2 3)"); + + v2 = new(-1, -2, -3); + f = Vector3.Distance(v1, v2); + Assert.AreEqual(12.4498997F, f, "Distance(4 5 6, -1 -2 -3)"); + + v2 = new(0, 0, 0); + f = Vector3.Distance(v1, v2); + Assert.AreEqual(v1.magnitude, f, "Distance(4 5 6, 0 0 0)"); + + v2 = new(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); + f = Vector3.Distance(v1, v2); + Assert.AreEqual(float.PositiveInfinity, f, "Distance(4 5 6, inf inf inf)"); + + v2 = new(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); + f = Vector3.Distance(v1, v2); + Assert.AreEqual(float.PositiveInfinity, f, "Distance(4 5 6, -inf -inf -inf)"); + } + + [Test] + public void Cross() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + Vector3 r; + + r = Vector3.Cross(v1, v2); + Assert.AreEqual(3, r.horizontal, "Cross(4 5 6, 1 2 3) H"); + Assert.AreEqual(-6, r.vertical, "Cross(4 5 6, 1 2 3) V"); + Assert.AreEqual(3, r.depth, "Cross(4 5 6, 1 2 3) D"); + + v2 = new(-1, -2, -3); + r = Vector3.Cross(v1, v2); + Assert.AreEqual(-3, r.horizontal, "Cross(4 5 6, -1 -2 -3) H"); + Assert.AreEqual(6, r.vertical, "Cross(4 5 6, -1 -2 -3) V"); + Assert.AreEqual(-3, r.depth, "Cross(4 5 6, -1 -2 -3) D"); + + v2 = new(0, 0, 0); + r = Vector3.Cross(v1, v2); + Assert.AreEqual(0, r.horizontal, "Cross(4 5 6, 0 0 0) H"); + Assert.AreEqual(0, r.vertical, "Cross(4 5 6, 0 0 0) V"); + Assert.AreEqual(0, r.depth, "Cross(4 5 6, 0 0 0) D"); + + v2 = new(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); + r = Vector3.Cross(v1, v2); + Assert.IsTrue(float.IsNaN(r.horizontal), "Cross(4 5 6, inf inf inf) H"); + Assert.IsTrue(float.IsNaN(r.vertical), "Cross(4 5 6, inf inf inf) V"); + Assert.IsTrue(float.IsNaN(r.depth), "Cross(4 5 6, inf inf inf) D"); + + v2 = new(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); + r = Vector3.Cross(v1, v2); + Assert.IsTrue(float.IsNaN(r.horizontal), "Cross(4 5 6, -inf -inf -inf) H"); + Assert.IsTrue(float.IsNaN(r.vertical), "Cross(4 5 6, -inf -inf -inf) V"); + Assert.IsTrue(float.IsNaN(r.depth), "Cross(4 5 6, -inf -inf -inf) D"); + } + + [Test] + public void Project() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + Vector3 r; + + r = Vector3.Project(v1, v2); + Assert.AreEqual(2.28571439F, r.horizontal, "Project(4 5 6, 1 2 3) H"); + Assert.AreEqual(4.57142878F, r.vertical, "Project(4 5 6, 1 2 3) V"); + Assert.AreEqual(6.85714293F, r.depth, "Project(4 5 6, 1 2 3) D"); + + v2 = new(-1, -2, -3); + r = Vector3.Project(v1, v2); + Assert.AreEqual(2.28571439F, r.horizontal, "Project(4 5 6, -1 -2 -3) H"); + Assert.AreEqual(4.57142878F, r.vertical, "Project(4 5 6, -1 -2 -3) V"); + Assert.AreEqual(6.85714293F, r.depth, "Project(4 5 6, -1 -2 -3) D"); + + v2 = new(0, 0, 0); + r = Vector3.Project(v1, v2); + Assert.AreEqual(0, r.horizontal, "Project(4 5 6, 0 0 0) H"); + Assert.AreEqual(0, r.vertical, "Project(4 5 6, 0 0 0) V"); + Assert.AreEqual(0, r.depth, "Project(4 5 6, 0 0 0) D"); + + r = Vector3.Project(v2, v1); + Assert.AreEqual(0, r.horizontal, "Project(0 0 0, 4 5 6) H"); + Assert.AreEqual(0, r.vertical, "Project(0 0 0, 4 5 6) V"); + Assert.AreEqual(0, r.depth, "Project(0 0 0, 4 5 6) D"); + + v2 = new(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); + r = Vector3.Project(v1, v2); + Assert.IsTrue(float.IsNaN(r.horizontal), "Project(4 5 6, inf inf inf) H"); + Assert.IsTrue(float.IsNaN(r.vertical), "Project(4 5 6, inf inf inf) V"); + Assert.IsTrue(float.IsNaN(r.depth), "Project(4 5 6, inf inf inf) D"); + + v2 = new(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); + r = Vector3.Project(v1, v2); + Assert.IsTrue(float.IsNaN(r.horizontal), "Project(4 5 6, -inf -inf -inf) H"); + Assert.IsTrue(float.IsNaN(r.vertical), "Project(4 5 6, -inf -inf -inf) V"); + Assert.IsTrue(float.IsNaN(r.depth), "Project(4 5 6, -inf -inf -inf) D"); + } + + [Test] + public void ProjectOnPlane() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + Vector3 r; + + r = Vector3.ProjectOnPlane(v1, v2); + Assert.AreEqual(1.71428561F, r.horizontal, "ProjectOnPlane(4 5 6, 1 2 3) H"); + Assert.AreEqual(0.428571224F, r.vertical, "ProjectOnPlane(4 5 6, 1 2 3) V"); + Assert.AreEqual(-0.857142925F, r.depth, "ProjectOnPlane(4 5 6, 1 2 3) D"); + + v2 = new(-1, -2, -3); + r = Vector3.ProjectOnPlane(v1, v2); + Assert.AreEqual(1.71428561F, r.horizontal, "ProjectOnPlane(4 5 6, -1 -2 -3) H"); + Assert.AreEqual(0.428571224F, r.vertical, "ProjectOnPlane(4 5 6, -1 -2 -3) V"); + Assert.AreEqual(-0.857142925F, r.depth, "ProjectOnPlane(4 5 6, -1 -2 -3) D"); + + v2 = new(0, 0, 0); + r = Vector3.ProjectOnPlane(v1, v2); + Assert.AreEqual(4, r.horizontal, "ProjectOnPlane(4 5 6, 0 0 0) H"); + Assert.AreEqual(5, r.vertical, "ProjectOnPlane(4 5 6, 0 0 0) V"); + Assert.AreEqual(6, r.depth, "ProjectOnPlane(4 5 6, 0 0 0) D"); + + r = Vector3.ProjectOnPlane(v2, v1); + Assert.AreEqual(0, r.horizontal, "ProjectOnPlane(0 0 0, 4 5 6) H"); + Assert.AreEqual(0, r.vertical, "ProjectOnPlane(0 0 0, 4 5 6) V"); + Assert.AreEqual(0, r.depth, "ProjectOnPlane(0 0 0, 4 5 6) D"); + + v2 = new(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); + r = Vector3.ProjectOnPlane(v1, v2); + Assert.IsTrue(float.IsNaN(r.horizontal), "ProjectOnPlane(4 5 6, inf inf inf) H"); + Assert.IsTrue(float.IsNaN(r.vertical), "ProjectOnPlane(4 5 6, inf inf inf) V"); + Assert.IsTrue(float.IsNaN(r.depth), "ProjectOnPlane(4 5 6, inf inf inf) D"); + + v2 = new(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); + r = Vector3.ProjectOnPlane(v1, v2); + Assert.IsTrue(float.IsNaN(r.horizontal), "ProjectOnPlane(4 5 6, -inf -inf -inf) H"); + Assert.IsTrue(float.IsNaN(r.vertical), "ProjectOnPlane(4 5 6, -inf -inf -inf) V"); + Assert.IsTrue(float.IsNaN(r.depth), "ProjectOnPlane(4 5 6, -inf -inf -inf) D"); + } + + [Test] + public void UnsignedAngle() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + AngleFloat a; + + a = Vector3.UnsignedAngle(v1, v2); + Assert.AreEqual(12.9331379F, a.inDegrees, "Angle(4 5 6, 1 2 3)"); + + v2 = new(-1, -2, -3); + a = Vector3.UnsignedAngle(v1, v2); + Assert.AreEqual(167.066849F, a.inDegrees, "Angle(4 5 6, -1 -2 -3)"); + + v2 = new(0, 0, 0); + a = Vector3.UnsignedAngle(v1, v2); + Assert.AreEqual(0, a.inDegrees, "Angle(4 5 6, 0 0 0)"); + + v2 = new(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); + a = Vector3.UnsignedAngle(v1, v2); + Assert.IsTrue(float.IsNaN(a.inDegrees), "Angle(4 5 6, inf inf inf)"); + + v2 = new(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); + a = Vector3.UnsignedAngle(v1, v2); + Assert.IsTrue(float.IsNaN(a.inDegrees), "Angle(4 5 6, inf inf inf)"); + } + + [Test] + public void SignedAngle() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + Vector3 v3 = new(7, 8, -9); + AngleFloat a; + + a = Vector3.SignedAngle(v1, v2, v3); + Assert.AreEqual(-12.9331379F, a.inDegrees, "SignedAngle(4 5 6, 1 2 3, 7 8 -9)"); + + v2 = new(-1, -2, -3); + a = Vector3.SignedAngle(v1, v2, v3); + Assert.AreEqual(167.066849F, a.inDegrees, "SignedAngle(4 5 6, -1 -2 -3, 7 8 -9)"); + + v2 = new(0, 0, 0); + a = Vector3.SignedAngle(v1, v2, v3); + Assert.AreEqual(0, a.inDegrees, "SignedAngle(4 5 6, 0 0 0, 7 8 -9)"); + + v2 = new(1, 2, 3); + v3 = new(-7, -8, 9); + a = Vector3.SignedAngle(v1, v2, v3); + Assert.AreEqual(12.9331379F, a.inDegrees, "SignedAngle(4 5 6, 1 2 3, -7 -8 9)"); + + v3 = new(0, 0, 0); + a = Vector3.SignedAngle(v1, v2, v3); + Assert.AreEqual(0, a.inDegrees, "SignedAngle(4 5 6, 1 2 3, 0 0 0)"); + + v2 = new(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); + a = Vector3.SignedAngle(v1, v2, v3); + Assert.IsTrue(float.IsNaN(a.inDegrees), "SignedAngle(4 5 6, inf inf inf, 0 0 0)"); + + v2 = new(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); + a = Vector3.SignedAngle(v1, v2, v3); + Assert.IsTrue(float.IsNaN(a.inDegrees), "SignedAngle(4 5 6, -inf -inf -inf, 0 0 0)"); + } + + [Test] + public void Lerp() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + Vector3 r; + + r = Vector3.Lerp(v1, v2, 0); + Assert.AreEqual(0, Vector3.Distance(r, v1), 0); + + r = Vector3.Lerp(v1, v2, 1); + Assert.AreEqual(0, Vector3.Distance(r, v2), 0); + + r = Vector3.Lerp(v1, v2, 0.5f); + Assert.AreEqual(0, Vector3.Distance(r, new Vector3(2.5f, 3.5f, 4.5f)), 0); + + r = Vector3.Lerp(v1, v2, -1); + Assert.AreEqual(0, Vector3.Distance(r, new Vector3(7, 8, 9)), 0); + + r = Vector3.Lerp(v1, v2, 2); + Assert.AreEqual(0, Vector3.Distance(r, new Vector3(-2, -1, 0)), 0); + } + } +} +#endif \ No newline at end of file diff --git a/test/Vector3IntTest.cs b/test/Vector3IntTest.cs new file mode 100644 index 0000000..b718178 --- /dev/null +++ b/test/Vector3IntTest.cs @@ -0,0 +1,349 @@ +#if !UNITY_5_6_OR_NEWER +using NUnit.Framework; + +namespace LinearAlgebra.Test { + using Vector3 = Vector3Int; + + public class Vector3IntTest { + + [Test] + public void Equality() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + + Assert.IsFalse(v1 == v2, "4 5 6 == 1 2 3"); + Assert.IsTrue(v1 != v2, "4 5 6 != 1 2 3"); + + v2 = new(4, 5, 6); + Assert.IsTrue(v1 == v2, "4 5 6 == 4 5 6"); + Assert.IsFalse(v1 != v2, "4 5 6 != 4 5 6"); + } + + [Test] + public void Magnitude() { + Vector3 v = new(1, 2, 3); + float m = 0; + + m = v.magnitude; + Assert.AreEqual(3.7416575f, m, "magnitude 1 2 3"); + + m = Vector3.MagnitudeOf(v); + Assert.AreEqual(3.7416575f, m, "MagnitudeOf 1 2 3"); + + v = new(-1, -2, -3); + m = v.magnitude; + Assert.AreEqual(3.7416575f, m, "magnitude -1 -2 -3"); + + v = new(0, 0, 0); + m = v.magnitude; + Assert.AreEqual(0, m, "magnitude 0 0 0"); + + // Infinity tests are still missing + } + + [Test] + public void SqrMagnitude() { + Vector3 v = new(1, 2, 3); + float m = 0; + + m = v.sqrMagnitude; + Assert.AreEqual(14, m, "sqrMagnitude 1 2 3"); + + m = Vector3.SqrMagnitudeOf(v); + Assert.AreEqual(14, m, "SqrMagnitudeOf 1 2 3"); + + v = new(-1, -2, -3); + m = v.sqrMagnitude; + Assert.AreEqual(14, m, "sqrMagnitude -1 -2 -3"); + + v = new(0, 0, 0); + m = v.sqrMagnitude; + Assert.AreEqual(0, m, "sqrMagnitude 0 0 0"); + + // Infinity tests are still missing + } + + [Test] + public void Distance() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + float f; + + f = Vector3.Distance(v1, v2); + Assert.AreEqual(5.19615221F, f, "Distance(4 5 6, 1 2 3)"); + + v2 = new(-1, -2, -3); + f = Vector3.Distance(v1, v2); + Assert.AreEqual(12.4498997F, f, "Distance(4 5 6, -1 -2 -3)"); + + v2 = new(0, 0, 0); + f = Vector3.Distance(v1, v2); + Assert.AreEqual(v1.magnitude, f, "Distance(4 5 6, 0 0 0)"); + } + + [Test] + public void Normalize() { + Vector3 v = new(0, 2, 0); + Vector3Float r; + + r = v.normalized; + //Assert.AreEqual(new Vector3(0, 1, 0), r, "normalized 0 2 0"); + Assert.AreEqual(0, r.horizontal, "normalized 0 2 0"); + Assert.AreEqual(1, r.vertical, "normalized 0 2 0"); + Assert.AreEqual(0, r.depth, "normalized 0 2 0"); + + r = Vector3.Normalize(v); + Assert.AreEqual(new Vector3Float(0, 1, 0), r, "Normalize 0 2 0"); + + v = new(0, -2, 0); + r = v.normalized; + Assert.AreEqual(new Vector3Float(0, -1, 0), r, "normalized 0 -2 0"); + v = new(0, 0, 0); + r = v.normalized; + Assert.AreEqual(new Vector3Float(0, 0, 0), r, "normalized 0 0 0"); + } + + [Test] + public void Negate() { + Vector3 v = new(4, 5, 6); + Vector3 r; + + r = -v; + Assert.AreEqual(-4, r.horizontal, "- 4 5 6 H"); + Assert.AreEqual(-5, r.vertical, "- 4 5 6 V"); + Assert.AreEqual(-6, r.depth, "- 4 5 6 D"); + + v = new(-4, -5, -6); + r = -v; + Assert.AreEqual(4, r.horizontal, "- -4 -5 -6 H"); + Assert.AreEqual(5, r.vertical, "- -4 -5 -6 V"); + Assert.AreEqual(6, r.depth, "- -4 -5 -6 D"); + + v = new(0, 0, 0); + r = -v; + Assert.AreEqual(new Vector3(0, 0, 0), r, "- 0 0 0"); + Assert.AreEqual(0, r.horizontal, "- 0 0 0 H"); + Assert.AreEqual(0, r.vertical, "- 0 0 0 V"); + Assert.AreEqual(0, r.depth, "- 0 0 0 D"); + } + + [Test] + public void Subtract() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + Vector3 r = Vector3.zero; + + r = v1 - v2; + Assert.IsTrue(r == new Vector3(3, 3, 3), "4 5 6 - 1 2 3"); + + v2 = new(-1, -2, -3); + r = v1 - v2; + Assert.IsTrue(r == new Vector3(5, 7, 9), "4 5 6 - -1 -2 -3"); + + v2 = new(4, 5, 6); + r = v1 - v2; + Assert.IsTrue(r == new Vector3(0, 0, 0), "4 5 6 - 4 5 6"); + r = v1; + r -= v2; + Assert.AreEqual(r, new Vector3(0, 0, 0), "4 5 6 - 4 5 6"); + + v2 = new(0, 0, 0); + r = v1 - v2; + Assert.AreEqual(r, new Vector3(4, 5, 6), "4 5 6 - 0 0 0"); + r -= v2; + Assert.AreEqual(r, new Vector3(4, 5, 6), "4 5 6 - 0 0 0"); + + // Infinity tests are still missing + } + + [Test] + public void Addition() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + Vector3 r = Vector3.zero; + + r = v1 + v2; + Assert.IsTrue(r == new Vector3(5, 7, 9), "4 5 6 + 1 2 3"); + + v2 = new(-1, -2, -3); + r = v1 + v2; + Assert.IsTrue(r == new Vector3(3, 3, 3), "4 5 6 + -1 -2 -3"); + r = v1; + r += v2; + Assert.AreEqual(r, new Vector3(3, 3, 3), "4 5 6 + -1 -2 -3"); + + v2 = new(0, 0, 0); + r = v1 + v2; + Assert.AreEqual(r, new Vector3(4, 5, 6), "4 5 6 + 0 0 0"); + r += v2; + Assert.AreEqual(r, new Vector3(4, 5, 6), "4 5 6 + 0 0 0"); + + // Infinity tests are still missing + } + + [Test] + public void Scale() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + Vector3 r; + + r = Vector3.Scale(v1, v2); + Assert.AreEqual(4, r.horizontal, "Scale 4 5 6 , 1 2 3 H"); + Assert.AreEqual(10, r.vertical, "Scale 4 5 6 , 1 2 3 V"); + Assert.AreEqual(18, r.depth, "Scale 4 5 6 , 1 2 3 D"); + + v2 = new(-1, -2, -3); + r = Vector3.Scale(v1, v2); + Assert.AreEqual(-4, r.horizontal, "Scale 4 5 6 , -1 -2 -3 H"); + Assert.AreEqual(-10, r.vertical, "Scale 4 5 6 , -1 -2 -3 V"); + Assert.AreEqual(-18, r.depth, "Scale 4 5 6 , -1 -2 -3 D"); + + v2 = new(0, 0, 0); + r = Vector3.Scale(v1, v2); + Assert.AreEqual(0, r.horizontal, "Scale 4 5 6 , 0 0 0 H"); + Assert.AreEqual(0, r.vertical, "Scale 4 5 6 , 0 0 0 V"); + Assert.AreEqual(0, r.depth, "Scale 4 5 6 , 0 0 0 D"); + } + + [Test] + public void Multiply() { + Vector3 v1 = new(4, 5, 6); + int f = 3; + Vector3 r; + + r = v1 * f; + Assert.AreEqual(12, r.horizontal, "4 5 6 * 3 H"); + Assert.AreEqual(15, r.vertical, "4 5 6 * 3 V"); + Assert.AreEqual(18, r.depth, "4 5 6 * 3 D"); + + r = f * v1; + Assert.AreEqual(12, r.horizontal, "3 * 4 5 6 H"); + Assert.AreEqual(15, r.vertical, "3 * 4 5 6 V"); + Assert.AreEqual(18, r.depth, "3 * 4 5 6 D"); + + f = -3; + r = v1 * f; + Assert.AreEqual(-12, r.horizontal, "4 5 6 * -3 H"); + Assert.AreEqual(-15, r.vertical, "4 5 6 * -3 V"); + Assert.AreEqual(-18, r.depth, "4 5 6 * -3 D"); + + f = 0; + r = v1 * f; + Assert.AreEqual(0, r.horizontal, "4 5 6 * 0 H"); + Assert.AreEqual(0, r.vertical, "4 5 6 * 0 V"); + Assert.AreEqual(0, r.depth, "4 5 6 * 0 D"); + } + + [Test] + public void Divide() { + Vector3 v1 = new(4, 5, 6); + int f = 2; + Vector3 r; + + r = v1 / f; + Assert.AreEqual(2, r.horizontal, "4 5 6 / 2 H"); + Assert.AreEqual(2, r.vertical, "4 5 6 / 2 V"); + Assert.AreEqual(3, r.depth, "4 5 6 / 2 D"); + + f = -2; + r = v1 / f; + Assert.AreEqual(-2, r.horizontal, "4 5 6 / -2 H"); + Assert.AreEqual(-2, r.vertical, "4 5 6 / -2 V"); + Assert.AreEqual(-3, r.depth, "4 5 6 / -2 D"); + + Assert.Throws(() => { + f = 0; + r = v1 / f; + }); + } + + [Test] + public void Dot() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + float f; + + f = Vector3.Dot(v1, v2); + Assert.AreEqual(32, f, "Dot(4 5 6, 1 2 3)"); + + v2 = new(-1, -2, -3); + f = Vector3.Dot(v1, v2); + Assert.AreEqual(-32, f, "Dot(4 5 6, -1 -2 -3)"); + + v2 = new(0, 0, 0); + f = Vector3.Dot(v1, v2); + Assert.AreEqual(0, f, "Dot(4 5 6, 0 0 0)"); + } + + [Test] + public void Cross() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + Vector3 r; + + r = Vector3.Cross(v1, v2); + Assert.AreEqual(3, r.horizontal, "Cross(4 5 6, 1 2 3) H"); + Assert.AreEqual(-6, r.vertical, "Cross(4 5 6, 1 2 3) V"); + Assert.AreEqual(3, r.depth, "Cross(4 5 6, 1 2 3) D"); + + v2 = new(-1, -2, -3); + r = Vector3.Cross(v1, v2); + Assert.AreEqual(-3, r.horizontal, "Cross(4 5 6, -1 -2 -3) H"); + Assert.AreEqual(6, r.vertical, "Cross(4 5 6, -1 -2 -3) V"); + Assert.AreEqual(-3, r.depth, "Cross(4 5 6, -1 -2 -3) D"); + + v2 = new(0, 0, 0); + r = Vector3.Cross(v1, v2); + Assert.AreEqual(0, r.horizontal, "Cross(4 5 6, 0 0 0) H"); + Assert.AreEqual(0, r.vertical, "Cross(4 5 6, 0 0 0) V"); + Assert.AreEqual(0, r.depth, "Cross(4 5 6, 0 0 0) D"); + } + + [Test] + public void UnsignedAngle() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + AngleFloat a; + + a = Vector3.UnsignedAngle(v1, v2); + Assert.AreEqual(12.9331379F, a.inDegrees, "Angle(4 5 6, 1 2 3)"); + + v2 = new(-1, -2, -3); + a = Vector3.UnsignedAngle(v1, v2); + Assert.AreEqual(167.066849F, a.inDegrees, "Angle(4 5 6, -1 -2 -3)"); + + v2 = new(0, 0, 0); + a = Vector3.UnsignedAngle(v1, v2); + Assert.AreEqual(0, a.inDegrees, "Angle(4 5 6, 0 0 0)"); + } + + [Test] + public void SignedAngle() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + Vector3 v3 = new(7, 8, -9); + AngleFloat a; + + a = Vector3.SignedAngle(v1, v2, v3); + Assert.AreEqual(-12.9331379F, a.inDegrees, "SignedAngle(4 5 6, 1 2 3, 7 8 -9)"); + + v2 = new(-1, -2, -3); + a = Vector3.SignedAngle(v1, v2, v3); + Assert.AreEqual(167.066849F, a.inDegrees, "SignedAngle(4 5 6, -1 -2 -3, 7 8 -9)"); + + v2 = new(0, 0, 0); + a = Vector3.SignedAngle(v1, v2, v3); + Assert.AreEqual(0, a.inDegrees, "SignedAngle(4 5 6, 0 0 0, 7 8 -9)"); + + v2 = new(1, 2, 3); + v3 = new(-7, -8, 9); + a = Vector3.SignedAngle(v1, v2, v3); + Assert.AreEqual(12.9331379F, a.inDegrees, "SignedAngle(4 5 6, 1 2 3, -7 -8 9)"); + + v3 = new(0, 0, 0); + a = Vector3.SignedAngle(v1, v2, v3); + Assert.AreEqual(0, a.inDegrees, "SignedAngle(4 5 6, 1 2 3, 0 0 0)"); + } + } +} +#endif \ No newline at end of file From 91950a2d19737f0f04e9240edcf28593e5313dbc Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 5 Jan 2026 10:55:43 +0100 Subject: [PATCH 031/179] Add linearAlgebra subtree --- Assembly-CSharp.csproj | 46 ++++++++++++++--------------- Assets/NanoBrain/LinearAlgebra.meta | 8 +++++ NanoBrain-Unity.slnx | 2 +- 3 files changed, 32 insertions(+), 24 deletions(-) create mode 100644 Assets/NanoBrain/LinearAlgebra.meta diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index f174f82..2dfb31c 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -49,44 +49,44 @@ - + + + + + + - - - - - - - + + + + + - - - - - + + + - + - + + - - - - + - + + + - - - + + diff --git a/Assets/NanoBrain/LinearAlgebra.meta b/Assets/NanoBrain/LinearAlgebra.meta new file mode 100644 index 0000000..c54c1af --- /dev/null +++ b/Assets/NanoBrain/LinearAlgebra.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d98555a675e8e5e879de17db950b55fe +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/NanoBrain-Unity.slnx b/NanoBrain-Unity.slnx index 398dc64..90452ad 100644 --- a/NanoBrain-Unity.slnx +++ b/NanoBrain-Unity.slnx @@ -1,4 +1,4 @@  - + From a91bd6dfee5c3215a63ae219e56c8922e4957ca4 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 5 Jan 2026 11:02:02 +0100 Subject: [PATCH 032/179] Improve Unity compatibility --- .../NanoBrain/LinearAlgebra/src/Direction.cs | 39 +++++++---- .../NanoBrain/LinearAlgebra/src/SwingTwist.cs | 66 ++++++++++++------- 2 files changed, 70 insertions(+), 35 deletions(-) diff --git a/Assets/NanoBrain/LinearAlgebra/src/Direction.cs b/Assets/NanoBrain/LinearAlgebra/src/Direction.cs index ed82901..a962589 100644 --- a/Assets/NanoBrain/LinearAlgebra/src/Direction.cs +++ b/Assets/NanoBrain/LinearAlgebra/src/Direction.cs @@ -102,17 +102,7 @@ namespace LinearAlgebra { } } -#if !UNITY_5_3_OR_NEWER - /// - /// Convert the direction into a carthesian vector - /// - /// The carthesian vector corresponding to this direction. - public Vector3Float ToVector3Float() { - Quaternion q = Quaternion.Euler(90 - this.vertical.inDegrees, this.horizontal.inDegrees, 0); - Vector3Float v = q * Vector3Float.forward; - return v; - } -#else +#if UNITY_5_3_OR_NEWER /// /// Convert the direction into a carthesian vector /// @@ -122,7 +112,30 @@ namespace LinearAlgebra { UnityEngine.Vector3 v = q * UnityEngine.Vector3.forward; return v; } -#endif + + /// + /// Convert a carthesian vector into a direction + /// + /// The carthesian vector + /// The direction + /// Information about the length of the carthesian vector is not + /// included in this transformation + public static Direction FromVector3(UnityEngine.Vector3 v) { + AngleFloat horizontal = AngleFloat.Atan2(v.x, v.z); + AngleFloat vertical = AngleFloat.deg90 - AngleFloat.Acos(v.y); + Direction d = new(horizontal, vertical); + return d; + } +#else + /// + /// Convert the direction into a carthesian vector + /// + /// The carthesian vector corresponding to this direction. + public Vector3Float ToVector3() { + Quaternion q = Quaternion.Euler(90 - this.vertical.inDegrees, this.horizontal.inDegrees, 0); + Vector3Float v = q * Vector3Float.forward; + return v; + } /// /// Convert a carthesian vector into a direction @@ -137,6 +150,8 @@ namespace LinearAlgebra { Direction d = new(horizontal, vertical); return d; } +#endif + /// /// Tests the equality of two directions diff --git a/Assets/NanoBrain/LinearAlgebra/src/SwingTwist.cs b/Assets/NanoBrain/LinearAlgebra/src/SwingTwist.cs index 4437c4f..df6e048 100644 --- a/Assets/NanoBrain/LinearAlgebra/src/SwingTwist.cs +++ b/Assets/NanoBrain/LinearAlgebra/src/SwingTwist.cs @@ -1,6 +1,6 @@ -#if !UNITY_5_3_OR_NEWER -using UnityEngine; -#endif +// #if !UNITY_5_3_OR_NEWER +// using UnityEngine; +// #endif namespace LinearAlgebra { @@ -46,7 +46,45 @@ namespace LinearAlgebra { return s; } -#if !UNITY_5_3_OR_NEWER +#if UNITY_5_3_OR_NEWER + /// + /// A zero angle rotation + /// + public static readonly SwingTwist zero = Degrees(0, 0, 0); + + public Spherical ToAngleAxis() { + UnityEngine.Quaternion q = this.ToQuaternion(); + q.ToAngleAxis(out float angle, out UnityEngine.Vector3 axis); + Direction direction = Direction.FromVector3(axis); + + Spherical r = new(angle, direction); + return r; + } + + public static SwingTwist FromAngleAxis(Spherical r) { + UnityEngine.Vector3 vectorAxis = r.direction.ToVector3(); + UnityEngine.Quaternion q = UnityEngine.Quaternion.AngleAxis(r.distance, vectorAxis); + return FromQuaternion(q); + } + + /// + /// Convert a quaternion in a swing/twist rotation + /// + /// The quaternion to convert + /// The swing/twist rotation + public static SwingTwist FromQuaternion(UnityEngine.Quaternion q) { + UnityEngine.Vector3 angles = q.eulerAngles; + SwingTwist r = Degrees(angles.y, -angles.x, -angles.z); + return r; + } + + public UnityEngine.Quaternion ToQuaternion() { + UnityEngine.Quaternion q = UnityEngine.Quaternion.Euler(this.swing.vertical.inDegrees, + this.swing.horizontal.inDegrees, + this.twist.inDegrees); + return q; + } +#else /// /// A zero angle rotation /// @@ -92,25 +130,7 @@ namespace LinearAlgebra { return r; } #endif -#if UNITY_5_3_OR_NEWER - /// - /// Convert a quaternion in a swing/twist rotation - /// - /// The quaternion to convert - /// The swing/twist rotation - public static SwingTwist FromQuaternion(UnityEngine.Quaternion q) { - UnityEngine.Vector3 angles = q.eulerAngles; - SwingTwist r = Degrees(angles.y, -angles.x, -angles.z); - return r; - } - - public UnityEngine.Quaternion ToUnityQuaternion() { - UnityEngine.Quaternion q = UnityEngine.Quaternion.Euler(this.swing.vertical.inDegrees, - this.swing.horizontal.inDegrees, - this.twist.inDegrees); - return q; - } -#endif + } } \ No newline at end of file From 3611de5142b9392f4587a670c798fa2ed38432bd Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 5 Jan 2026 11:12:22 +0100 Subject: [PATCH 033/179] Fix roaming boid --- Assets/NanoBrain/LinearAlgebra/src/Angle.cs | 27 ++++++++++++--------- Assets/Scenes/Boids/Prefabs/Boid.prefab | 3 ++- Assets/Scenes/Boids/Scripts/Boid.cs | 2 +- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/Assets/NanoBrain/LinearAlgebra/src/Angle.cs b/Assets/NanoBrain/LinearAlgebra/src/Angle.cs index 694d1b7..d73d257 100644 --- a/Assets/NanoBrain/LinearAlgebra/src/Angle.cs +++ b/Assets/NanoBrain/LinearAlgebra/src/Angle.cs @@ -32,7 +32,6 @@ namespace LinearAlgebra { } return new AngleFloat(radians * Rad2Deg); - } public static AngleFloat Revolutions(float revolutions) { @@ -51,17 +50,11 @@ namespace LinearAlgebra { return new AngleFloat(revolutions * 360); } - public float inDegrees { - get { return this.value; } - } + public readonly float inDegrees => this.value; - public float inRadians { - get { return this.value * Deg2Rad; } - } - - public float inRevolutions { - get { return this.value / 360.0f; } - } + public readonly float inRadians => this.value * Deg2Rad; + + public readonly float inRevolutions => this.value / 360.0f; public static readonly AngleFloat zero = Degrees(0); public static readonly AngleFloat deg90 = Degrees(90); @@ -115,6 +108,18 @@ namespace LinearAlgebra { return a1.value != a2.value; } + public override readonly bool Equals(object obj) { + if (obj is AngleFloat other) { + return this == other; + } + return false; + } + + public override readonly int GetHashCode() { + return this.value.GetHashCode(); + } + + /// /// Tests if the first angle is greater than the second /// diff --git a/Assets/Scenes/Boids/Prefabs/Boid.prefab b/Assets/Scenes/Boids/Prefabs/Boid.prefab index 31be0f5..fc3c83c 100644 --- a/Assets/Scenes/Boids/Prefabs/Boid.prefab +++ b/Assets/Scenes/Boids/Prefabs/Boid.prefab @@ -89,6 +89,7 @@ MeshRenderer: m_SortingLayerID: 0 m_SortingLayer: 0 m_SortingOrder: 0 + m_MaskInteraction: 0 m_AdditionalVertexStreams: {fileID: 0} --- !u!136 &8702527963799169118 CapsuleCollider: @@ -176,4 +177,4 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 92f34a5e4027a1dc39efd8ce63cf6aba, type: 3} m_Name: m_EditorClassIdentifier: Assembly-CSharp::NanoBrainComponent - defaultBrain: {fileID: 11400000, guid: fc1a4800a8c531eb4855b436bc9084ae, type: 2} + defaultBrain: {fileID: 11400000, guid: af8d90b8b4b9dcad7837130c4143d91c, type: 2} diff --git a/Assets/Scenes/Boids/Scripts/Boid.cs b/Assets/Scenes/Boids/Scripts/Boid.cs index 43da333..87e8acd 100644 --- a/Assets/Scenes/Boids/Scripts/Boid.cs +++ b/Assets/Scenes/Boids/Scripts/Boid.cs @@ -43,7 +43,7 @@ public class Boid : MonoBehaviour { //Debug.DrawRay(this.transform.position, this.transform.TransformDirection(localPosition), Color.magenta); int thingId = neighbour.GetInstanceID(); - boidReceptor.ProcessStimulus(thingId, localPosition); + boidReceptor?.ProcessStimulus(thingId, localPosition); } } From d102fc7b806e29dae4fb8413bfad986a00dd36a7 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 5 Jan 2026 11:26:13 +0100 Subject: [PATCH 034/179] Fix Unity warnings --- .../LinearAlgebra/src/Vector2Float.cs | 36 +++++++++---------- .../NanoBrain/LinearAlgebra/src/Vector2Int.cs | 31 ++++++++++------ .../LinearAlgebra/src/Vector3Float.cs | 31 ++++++++-------- .../VisualEditor/Editor/NanoBrainEditor.cs | 2 +- 4 files changed, 52 insertions(+), 48 deletions(-) diff --git a/Assets/NanoBrain/LinearAlgebra/src/Vector2Float.cs b/Assets/NanoBrain/LinearAlgebra/src/Vector2Float.cs index e0418a8..ac1867c 100644 --- a/Assets/NanoBrain/LinearAlgebra/src/Vector2Float.cs +++ b/Assets/NanoBrain/LinearAlgebra/src/Vector2Float.cs @@ -324,27 +324,13 @@ namespace LinearAlgebra { public static Vector2Float Scale(Vector2Float v1, Vector2Float v2) { return new Vector2Float(v1.horizontal * v2.horizontal, v1.vertical * v2.vertical); } - - /* + /// /// Tests if the vector has equal values as the given vector /// /// The vector to compare to /// true if the vector values are equal - public bool Equals(Vector2Float v1) => horizontal == v1.horizontal && vertical == v1.vertical; - - /// - /// Tests if the vector is equal to the given object - /// - /// The object to compare to - /// false when the object is not a Vector2 or does not have equal values - public override bool Equals(object obj) { - if (!(obj is Vector2Float v)) - return false; - - return (horizontal == v.horizontal && vertical == v.vertical); - } - */ + //public readonly bool Equals(Vector2Float v1) => horizontal == v1.horizontal && vertical == v1.vertical; /// /// Tests if the two vectors have equal values @@ -372,15 +358,25 @@ namespace LinearAlgebra { return (v1.horizontal != v2.horizontal || v1.vertical != v2.vertical); } - /* + /// + /// Tests if the vector is equal to the given object + /// + /// The object to compare to + /// false when the object is not a Vector2 or does not have equal values + public override readonly bool Equals(object obj) { + if (obj is not Vector2Float v) + return false; + + return (horizontal == v.horizontal && vertical == v.vertical); + } + /// /// Get an hash code for the vector /// /// The hash code - public override int GetHashCode() { - return (horizontal, vertical).GetHashCode(); + public override readonly int GetHashCode() { + return HashCode.Combine(horizontal, vertical); } - */ /// /// Get the distance between two vectors diff --git a/Assets/NanoBrain/LinearAlgebra/src/Vector2Int.cs b/Assets/NanoBrain/LinearAlgebra/src/Vector2Int.cs index 0eca7dc..ed68e8b 100644 --- a/Assets/NanoBrain/LinearAlgebra/src/Vector2Int.cs +++ b/Assets/NanoBrain/LinearAlgebra/src/Vector2Int.cs @@ -60,17 +60,6 @@ namespace LinearAlgebra { /// true if the vector values are equal public readonly bool Equals(Vector2Int v) => this.horizontal == v.horizontal && vertical == v.vertical; - /// - /// Tests if the vector is equal to the given object - /// - /// The object to compare to - /// false when the object is not a Vector2 or does not have equal values - public override readonly bool Equals(object obj) { - if (obj is not Vector2Int v) - return false; - - return (this.horizontal == v.horizontal && this.vertical == v.vertical); - } */ /// @@ -98,6 +87,26 @@ namespace LinearAlgebra { return (v1.horizontal != v2.horizontal || v1.vertical != v2.vertical); } + /// + /// Tests if the vector is equal to the given object + /// + /// The object to compare to + /// false when the object is not a Vector2 or does not have equal values + public override readonly bool Equals(object obj) { + if (obj is not Vector2Int v) + return false; + + return (this.horizontal == v.horizontal && this.vertical == v.vertical); + } + + /// + /// Get an hash code for the vector + /// + /// The hash code + public override readonly int GetHashCode() { + return HashCode.Combine(horizontal, vertical); + } + public readonly float sqrMagnitude => this.horizontal * this.horizontal + this.vertical * this.vertical; public static float SqrMagnitudeOf(Vector2Int v) { diff --git a/Assets/NanoBrain/LinearAlgebra/src/Vector3Float.cs b/Assets/NanoBrain/LinearAlgebra/src/Vector3Float.cs index bff0936..d8208d3 100644 --- a/Assets/NanoBrain/LinearAlgebra/src/Vector3Float.cs +++ b/Assets/NanoBrain/LinearAlgebra/src/Vector3Float.cs @@ -250,30 +250,22 @@ namespace LinearAlgebra { public static Vector3Float operator *(Vector3Float v1, float d) { - Vector3Float v = new Vector3Float(v1.horizontal * d, v1.vertical * d, v1.depth * d); + Vector3Float v = new(v1.horizontal * d, v1.vertical * d, v1.depth * d); return v; } public static Vector3Float operator *(float d, Vector3Float v1) { - Vector3Float v = new Vector3Float(d * v1.horizontal, d * v1.vertical, d * v1.depth); + Vector3Float v = new(d * v1.horizontal, d * v1.vertical, d * v1.depth); return v; } public static Vector3Float operator /(Vector3Float v1, float d) { - Vector3Float v = new Vector3Float(v1.horizontal / d, v1.vertical / d, v1.depth / d); + Vector3Float v = new(v1.horizontal / d, v1.vertical / d, v1.depth / d); return v; } - /* - public bool Equals(Vector3Float v) => (horizontal == v.horizontal && vertical == v.vertical && depth == v.depth); - - public override bool Equals(object obj) { - if (!(obj is Vector3Float v)) - return false; - - return (horizontal == v.horizontal && vertical == v.vertical && depth == v.depth); - } - */ + + //public bool Equals(Vector3Float v) => (horizontal == v.horizontal && vertical == v.vertical && depth == v.depth); public static bool operator ==(Vector3Float v1, Vector3Float v2) { return (v1.horizontal == v2.horizontal && v1.vertical == v2.vertical && v1.depth == v2.depth); @@ -283,9 +275,16 @@ namespace LinearAlgebra { return (v1.horizontal != v2.horizontal || v1.vertical != v2.vertical || v1.depth != v2.depth); } - // public override int GetHashCode() { - // return (horizontal, vertical, depth).GetHashCode(); - // } + public override readonly bool Equals(object obj) { + if (obj is not Vector3Float v) + return false; + + return (horizontal == v.horizontal && vertical == v.vertical && depth == v.depth); + } + + public override readonly int GetHashCode() { + return HashCode.Combine(horizontal, vertical, depth); + } /// @brief The distance between two vectors /// @param v1 The first vector diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs index f1946f3..31938b1 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs @@ -501,7 +501,7 @@ public static class OpenAssetHandler { // Called when an asset is double-clicked or opened. [OnOpenAsset] public static bool OpenMyScriptableObject(int instanceID, int line) { - NanoBrainObj obj = EditorUtility.InstanceIDToObject(instanceID) as NanoBrainObj; + NanoBrainObj obj = EditorUtility.EntityIdToObject(instanceID) as NanoBrainObj; if (obj != null) { NanoBrainEditor.Open(obj); return true; // handled From a1d1f7ba24d900df6c90e40a7efbc9f0987eb4d1 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 5 Jan 2026 11:34:41 +0100 Subject: [PATCH 035/179] Vector3 conversion fixes --- .../NanoBrain/LinearAlgebra/src/Spherical.cs | 136 ++++++------------ 1 file changed, 46 insertions(+), 90 deletions(-) diff --git a/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs b/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs index de06d24..1c92faa 100644 --- a/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs +++ b/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs @@ -3,21 +3,18 @@ using System; using Vector3 = UnityEngine.Vector3; #endif -namespace LinearAlgebra -{ +namespace LinearAlgebra { /// /// A spherical vector /// /// This is a struct such that it is a value type and cannot be null - public struct Spherical - { + public struct Spherical { /// /// Create a spherical vector /// /// The distance in meters /// The direction of the vector - public Spherical(float distance, Direction direction) - { + public Spherical(float distance, Direction direction) { this.distance = distance; this.direction = direction; } @@ -29,15 +26,13 @@ namespace LinearAlgebra /// The horizontal angle in degrees /// The vertical angle in degrees /// - public static Spherical Degrees(float distance, float horizontal, float vertical) - { + public static Spherical Degrees(float distance, float horizontal, float vertical) { Direction direction = Direction.Degrees(horizontal, vertical); Spherical s = new(distance, direction); return s; } - public static Spherical Radians(float distance, float horizontal, float vertical) - { + public static Spherical Radians(float distance, float horizontal, float vertical) { Direction direction = Direction.Radians(horizontal, vertical); Spherical s = new(distance, direction); return s; @@ -62,79 +57,19 @@ namespace LinearAlgebra /// public readonly static Spherical forward = new(1, Direction.forward); - - // public static Spherical FromVector3Float(Vector3Float v) { - // float distance = v.magnitude; - // if (distance == 0.0f) - // return Spherical.zero; - // else { - // float verticalAngle = (float)((Angle.pi / 2 - Math.Acos(v.y / distance)) * Angle.Rad2Deg); - // float horizontalAngle = (float)Math.Atan2(v.x, v.z) * Angle.Rad2Deg; - // return Spherical.Degrees(distance, horizontalAngle, verticalAngle); - // } - // } - - public static Spherical FromVector3Float(Vector3Float v) - { - float distance = v.magnitude; - if (distance == 0.0f) - return Spherical.zero; - else - { - float verticalAngle = (float)(Math.PI / 2 - Math.Acos(v.vertical / distance)) * AngleFloat.Rad2Deg; - float horizontalAngle = (float)Math.Atan2(v.horizontal, v.depth) * AngleFloat.Rad2Deg; - return Degrees(distance, horizontalAngle, verticalAngle); - } - } - - // public Vector3Float ToVector3Float() { - // float verticalRad = (Angle.pi / 2) - this.direction.vertical * Angle.Deg2Rad; - // float horizontalRad = this.direction.horizontal * Angle.Deg2Rad; - // float cosVertical = (float)Math.Cos(verticalRad); - // float sinVertical = (float)Math.Sin(verticalRad); - // float cosHorizontal = (float)Math.Cos(horizontalRad); - // float sinHorizontal = (float)Math.Sin(horizontalRad); - - // float x = this.distance * sinVertical * sinHorizontal; - // float y = this.distance * cosVertical; - // float z = this.distance * sinVertical * cosHorizontal; - - // Vector3Float v = new(x, y, z); - // return v; - // } - - public Vector3Float ToVector3Float() - { - float verticalRad = (AngleFloat.deg90 - this.direction.vertical).inRadians; - float horizontalRad = this.direction.horizontal.inRadians; - float cosVertical = (float)Math.Cos(verticalRad); - float sinVertical = (float)Math.Sin(verticalRad); - float cosHorizontal = (float)Math.Cos(horizontalRad); - float sinHorizontal = (float)Math.Sin(horizontalRad); - - float x = this.distance * sinVertical * sinHorizontal; - float y = this.distance * cosVertical; - float z = this.distance * sinVertical * cosHorizontal; - - Vector3Float v = new(x, y, z); - return v; - } #if UNITY_5_3_OR_NEWER - public static Spherical FromVector3(Vector3 v) - { + public static Spherical FromVector3(Vector3 v) { float distance = v.magnitude; if (distance == 0.0f) return Spherical.zero; - else - { + else { float verticalAngle = (float)(Math.PI / 2 - Math.Acos(v.y / distance)) * AngleFloat.Rad2Deg; float horizontalAngle = (float)Math.Atan2(v.x, v.z) * AngleFloat.Rad2Deg; return Degrees(distance, horizontalAngle, verticalAngle); } } - public Vector3 ToVector3() - { + public readonly Vector3 ToVector3() { float verticalRad = (AngleFloat.deg90 - this.direction.vertical).inRadians; float horizontalRad = this.direction.horizontal.inRadians; float cosVertical = (float)Math.Cos(verticalRad); @@ -149,21 +84,42 @@ namespace LinearAlgebra Vector3 v = new(x, y, z); return v; } -#endif - - public float magnitude +#else + public static Spherical FromVector3(Vector3Float v) { - get + float distance = v.magnitude; + if (distance == 0.0f) + return Spherical.zero; + else { - return this.distance; + float verticalAngle = (float)(Math.PI / 2 - Math.Acos(v.vertical / distance)) * AngleFloat.Rad2Deg; + float horizontalAngle = (float)Math.Atan2(v.horizontal, v.depth) * AngleFloat.Rad2Deg; + return Degrees(distance, horizontalAngle, verticalAngle); } } - public Spherical normalized - { - get - { - Spherical r = new() - { + + public readonly Vector3Float ToVector3() { + float verticalRad = (AngleFloat.deg90 - this.direction.vertical).inRadians; + float horizontalRad = this.direction.horizontal.inRadians; + float cosVertical = (float)Math.Cos(verticalRad); + float sinVertical = (float)Math.Sin(verticalRad); + float cosHorizontal = (float)Math.Cos(horizontalRad); + float sinHorizontal = (float)Math.Sin(horizontalRad); + + float x = this.distance * sinVertical * sinHorizontal; + float y = this.distance * cosVertical; + float z = this.distance * sinVertical * cosHorizontal; + + Vector3Float v = new(x, y, z); + return v; + } +#endif + + public readonly float magnitude => this.distance; + + public Spherical normalized { + get { + Spherical r = new() { distance = 1, direction = this.direction }; @@ -171,13 +127,13 @@ namespace LinearAlgebra } } - public static Spherical operator +(Spherical s1, Spherical s2) - { + public static Spherical operator +(Spherical s1, Spherical s2) { // let's do it the easy way... - Vector3Float v1 = s1.ToVector3Float(); - Vector3Float v2 = s2.ToVector3Float(); - Vector3Float v = v1 + v2; - Spherical r = FromVector3Float(v); + // using vars to be compatible with both unity (Vector3) and native (Vector3Float) + var v1 = s1.ToVector3(); + var v2 = s2.ToVector3(); + var v = v1 + v2; + Spherical r = FromVector3(v); return r; } From c86b01ae571b223f666c4f5a14490e28036b4f0e Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 5 Jan 2026 13:04:53 +0100 Subject: [PATCH 036/179] Updating swarm weights --- Assembly-CSharp-Editor.csproj | 1 + .../Editor/NanoBrainComponent_Editor.cs | 10 ++++-- .../VisualEditor/Editor/NanoBrainInspector.cs | 2 ++ Assets/NanoBrain/VisualEditor/NanoBrainObj.cs | 2 +- Assets/Scenes/Boids/Boids.unity | 12 +++++-- Assets/Scenes/Boids/RoamingBrain.asset | 24 ++++++++++++-- Assets/Scenes/Boids/Scripts/Editor.meta | 8 +++++ .../Scripts/Editor/SwarmControl_Editor.cs | 32 +++++++++++++++++++ .../Editor/SwarmControl_Editor.cs.meta | 2 ++ 9 files changed, 83 insertions(+), 10 deletions(-) create mode 100644 Assets/Scenes/Boids/Scripts/Editor.meta create mode 100644 Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs create mode 100644 Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs.meta diff --git a/Assembly-CSharp-Editor.csproj b/Assembly-CSharp-Editor.csproj index 99bbb27..010371d 100644 --- a/Assembly-CSharp-Editor.csproj +++ b/Assembly-CSharp-Editor.csproj @@ -52,6 +52,7 @@ + diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs index 895092f..7fdec1b 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs @@ -8,15 +8,18 @@ public class NanoBrainComponent_Editor : Editor { protected static VisualElement mainContainer; protected static VisualElement inspectorContainer; + protected NanoBrainComponent component; private SerializedProperty brainProp; public void OnEnable() { + component = target as NanoBrainComponent; + if (Application.isPlaying == false) brainProp = serializedObject.FindProperty(nameof(NanoBrainComponent.defaultBrain)); } public override VisualElement CreateInspectorGUI() { - NanoBrainComponent component = target as NanoBrainComponent; + //NanoBrainComponent component = target as NanoBrainComponent; NanoBrainObj brain = Application.isPlaying ? component.brain : component.defaultBrain; if (Application.isPlaying == false) @@ -35,8 +38,9 @@ public class NanoBrainComponent_Editor : Editor { root.styleSheets.Add(Resources.Load("GraphStyles")); if (Application.isPlaying == false) { - PropertyField brainField = new(brainProp); - brainField.label = "Nano Brain"; + PropertyField brainField = new(brainProp) { + label = "Nano Brain" + }; root.Add(brainField); } diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs index 8db7231..705aa68 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs @@ -395,8 +395,10 @@ public class NanoBrainInspector : Editor { if (so.targetObject == null) return; so.Update(); + if (this.currentNucleus == null) return; + this.currentNucleus.name = EditorGUILayout.TextField(this.currentNucleus.name); if (this.currentNucleus is Perceptoid currentPerceptoid) currentPerceptoid.thingType = EditorGUILayout.IntField("Thing Type", currentPerceptoid.thingType); diff --git a/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs b/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs index 145e14d..096ff4b 100644 --- a/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs +++ b/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs @@ -70,7 +70,7 @@ public class NanoBrainObj : ScriptableObject, ISerializationCallbackReceiver { public void GarbageCollection() { HashSet visitedNuclei = new(); MarkNuclei(visitedNuclei, this.root); - Debug.Log($"Garbage collection found {visitedNuclei.Count} Nuclei"); + //Debug.Log($"Garbage collection found {visitedNuclei.Count} Nuclei"); this.nuclei.RemoveAll(nucleus => visitedNuclei.Contains(nucleus) == false); this.perceptei.RemoveAll(perceptoid => visitedNuclei.Contains(perceptoid) == false); } diff --git a/Assets/Scenes/Boids/Boids.unity b/Assets/Scenes/Boids/Boids.unity index 9df0ef9..955eb8d 100644 --- a/Assets/Scenes/Boids/Boids.unity +++ b/Assets/Scenes/Boids/Boids.unity @@ -221,6 +221,7 @@ MeshRenderer: m_SortingLayerID: 0 m_SortingLayer: 0 m_SortingOrder: 0 + m_MaskInteraction: 0 m_AdditionalVertexStreams: {fileID: 0} --- !u!33 &231291189 MeshFilter: @@ -332,6 +333,7 @@ MeshRenderer: m_SortingLayerID: 0 m_SortingLayer: 0 m_SortingOrder: 0 + m_MaskInteraction: 0 m_AdditionalVertexStreams: {fileID: 0} --- !u!33 &246180157 MeshFilter: @@ -375,7 +377,7 @@ MonoBehaviour: inertia: 0.8 alignmentForce: 2 cohesionForce: 2 - avoidanceForce: 1 + avoidanceForce: 100 separationDistance: 0.3 perceptionDistance: 2 boundaryForce: 5 @@ -515,6 +517,7 @@ MeshRenderer: m_SortingLayerID: 0 m_SortingLayer: 0 m_SortingOrder: 0 + m_MaskInteraction: 0 m_AdditionalVertexStreams: {fileID: 0} --- !u!33 &704151346 MeshFilter: @@ -550,14 +553,14 @@ Light: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 837238090} m_Enabled: 1 - serializedVersion: 11 + serializedVersion: 12 m_Type: 1 m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} m_Intensity: 1 m_Range: 10 m_SpotAngle: 30 m_InnerSpotAngle: 21.80208 - m_CookieSize: 10 + m_CookieSize2D: {x: 10, y: 10} m_Shadows: m_Type: 2 m_Resolution: -1 @@ -845,6 +848,7 @@ MeshRenderer: m_SortingLayerID: 0 m_SortingLayer: 0 m_SortingOrder: 0 + m_MaskInteraction: 0 m_AdditionalVertexStreams: {fileID: 0} --- !u!33 &1690670940 MeshFilter: @@ -956,6 +960,7 @@ MeshRenderer: m_SortingLayerID: 0 m_SortingLayer: 0 m_SortingOrder: 0 + m_MaskInteraction: 0 m_AdditionalVertexStreams: {fileID: 0} --- !u!33 &1738679981 MeshFilter: @@ -1104,6 +1109,7 @@ MeshRenderer: m_SortingLayerID: 0 m_SortingLayer: 0 m_SortingOrder: 0 + m_MaskInteraction: 0 m_AdditionalVertexStreams: {fileID: 0} --- !u!33 &1924016464 MeshFilter: diff --git a/Assets/Scenes/Boids/RoamingBrain.asset b/Assets/Scenes/Boids/RoamingBrain.asset index 2ca9ea7..0771c4d 100644 --- a/Assets/Scenes/Boids/RoamingBrain.asset +++ b/Assets/Scenes/Boids/RoamingBrain.asset @@ -21,7 +21,7 @@ MonoBehaviour: _name: Root synapses: - nucleusId: -112538112 - weight: 1 + weight: 10 curvePreset: 0 curve: serializedVersion: 2 @@ -80,11 +80,29 @@ MonoBehaviour: _curvePreset: 0 curve: serializedVersion: 2 - m_Curve: [] + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 m_PreInfinity: 2 m_PostInfinity: 2 m_RotationOrder: 4 - curveMax: 0 + curveMax: 1 average: 0 inverse: 0 exponent: 1 diff --git a/Assets/Scenes/Boids/Scripts/Editor.meta b/Assets/Scenes/Boids/Scripts/Editor.meta new file mode 100644 index 0000000..ef97f40 --- /dev/null +++ b/Assets/Scenes/Boids/Scripts/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2b86e8b28533d905899af9666a98e804 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs b/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs new file mode 100644 index 0000000..5feb192 --- /dev/null +++ b/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs @@ -0,0 +1,32 @@ +using UnityEditor; +using UnityEngine; + +[CustomEditor(typeof(SwarmControl))] +public class SwarmControl_Editor : Editor { + public override void OnInspectorGUI() { + EditorGUI.BeginChangeCheck(); + + DrawDefaultInspector(); + + if (EditorGUI.EndChangeCheck()) { + + SwarmControl swarmControl = (SwarmControl)target; + NanoBrainObj[] nanoBrains = FindObjectsByType(FindObjectsSortMode.None); + + foreach (NanoBrainObj brain in nanoBrains) { + UpdateWeight(brain, "Avoidance", swarmControl.avoidanceForce); + } + //} + Debug.Log("Updated weights"); + } + } + + protected void UpdateWeight(NanoBrainObj brain, string name, float weight) { + Nucleus root = brain.root; + foreach (Synapse synapse in root.synapses) { + if (synapse.nucleus.name == name) { + synapse.weight = weight; + } + } + } +} \ No newline at end of file diff --git a/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs.meta b/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs.meta new file mode 100644 index 0000000..51eae02 --- /dev/null +++ b/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: df2bd18155543a1a09fefea3252981e0 \ No newline at end of file From bb394358922671961a51362f1e174044e3bc2882 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 5 Jan 2026 14:39:08 +0100 Subject: [PATCH 037/179] Fix Direction.ToVector3 --- Assets/NanoBrain/LinearAlgebra/src/Angle.cs | 4 +++ .../NanoBrain/LinearAlgebra/src/Direction.cs | 36 +++++++++++++++---- Assets/NanoBrain/Neuroid.cs | 4 ++- Assets/Scenes/Boids/Boids.unity | 6 ++-- .../Scripts/Editor/SwarmControl_Editor.cs | 4 +-- 5 files changed, 40 insertions(+), 14 deletions(-) diff --git a/Assets/NanoBrain/LinearAlgebra/src/Angle.cs b/Assets/NanoBrain/LinearAlgebra/src/Angle.cs index d73d257..70f5b10 100644 --- a/Assets/NanoBrain/LinearAlgebra/src/Angle.cs +++ b/Assets/NanoBrain/LinearAlgebra/src/Angle.cs @@ -56,6 +56,10 @@ namespace LinearAlgebra { public readonly float inRevolutions => this.value / 360.0f; + public override string ToString() { + return $"{this.inDegrees} deg."; + } + public static readonly AngleFloat zero = Degrees(0); public static readonly AngleFloat deg90 = Degrees(90); public static readonly AngleFloat deg180 = Degrees(180); diff --git a/Assets/NanoBrain/LinearAlgebra/src/Direction.cs b/Assets/NanoBrain/LinearAlgebra/src/Direction.cs index a962589..dfc90bd 100644 --- a/Assets/NanoBrain/LinearAlgebra/src/Direction.cs +++ b/Assets/NanoBrain/LinearAlgebra/src/Direction.cs @@ -66,6 +66,10 @@ namespace LinearAlgebra { return d; } + public override readonly string ToString() { + return $"Direction(h: {this.horizontal}, v: {this.vertical})"; + } + /// /// A forward direction with zero for both angles /// @@ -107,10 +111,17 @@ namespace LinearAlgebra { /// Convert the direction into a carthesian vector /// /// The carthesian vector corresponding to this direction. - public UnityEngine.Vector3 ToVector3() { - UnityEngine.Quaternion q = UnityEngine.Quaternion.Euler(90 - this.vertical.inDegrees, this.horizontal.inDegrees, 0); - UnityEngine.Vector3 v = q * UnityEngine.Vector3.forward; - return v; + public readonly UnityEngine.Vector3 ToVector3() { + // Convert degrees to radians + float radH = this.horizontal.inRadians; + float radV = this.vertical.inRadians; + + // Calculate Vector + float x = MathF.Cos(radV) * MathF.Cos(radH); + float y = MathF.Sin(radV); + float z = MathF.Cos(radV) * MathF.Sin(radH); + + return new UnityEngine.Vector3(x, y, z); } /// @@ -132,9 +143,20 @@ namespace LinearAlgebra { /// /// The carthesian vector corresponding to this direction. public Vector3Float ToVector3() { - Quaternion q = Quaternion.Euler(90 - this.vertical.inDegrees, this.horizontal.inDegrees, 0); - Vector3Float v = q * Vector3Float.forward; - return v; + // Quaternion q = Quaternion.Euler(90 - this.vertical.inDegrees, this.horizontal.inDegrees, 0); + // Vector3Float v = q * Vector3Float.forward; + // return v; + // Convert degrees to radians + float radH = this.horizontal.inRadians; + float radV = this.vertical.inRadians; + + // Calculate Vector + float x = MathF.Cos(radV) * MathF.Cos(radH); + float y = MathF.Sin(radV); + float z = MathF.Cos(radV) * MathF.Sin(radH); + + return new Vector3Float(x, y, z); + } /// diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index 5468235..a7ddff9 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -83,7 +83,9 @@ public class Neuroid : Nucleus { Vector3 direction = synapseNucleus.outputValue.direction.ToVector3(); float weight = synapse.weight; - float magnitude = weight * curve.Evaluate(synapseNucleus.outputValue.magnitude); + float activatedValue = curve.Evaluate(synapseNucleus.outputValue.magnitude); + float magnitude = weight * activatedValue; + Debug.Log($"{this.name} {synapseNucleus.outputValue.direction} {synapseNucleus.outputValue.direction.horizontal}{synapseNucleus.outputValue.direction.vertical} {direction}"); result += direction * magnitude; } diff --git a/Assets/Scenes/Boids/Boids.unity b/Assets/Scenes/Boids/Boids.unity index 955eb8d..593d20e 100644 --- a/Assets/Scenes/Boids/Boids.unity +++ b/Assets/Scenes/Boids/Boids.unity @@ -374,10 +374,10 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: Assembly-CSharp::SwarmControl speed: 1 - inertia: 0.8 + inertia: 0.9 alignmentForce: 2 cohesionForce: 2 - avoidanceForce: 100 + avoidanceForce: 10 separationDistance: 0.3 perceptionDistance: 2 boundaryForce: 5 @@ -395,7 +395,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec888ca5333d45a438f9f417fa5ce135, type: 3} m_Name: m_EditorClassIdentifier: Assembly-CSharp::SwarmSpawn - count: 100 + count: 1 boidPrefab: {fileID: 8702527964058765413, guid: f9c706268554ce449a8773675b2864b8, type: 3} spawnAreaSize: {x: 0.5, y: 0.5, z: 0.5} minDelay: 0.05 diff --git a/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs b/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs index 5feb192..4f2fe37 100644 --- a/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs +++ b/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs @@ -9,14 +9,12 @@ public class SwarmControl_Editor : Editor { DrawDefaultInspector(); if (EditorGUI.EndChangeCheck()) { - SwarmControl swarmControl = (SwarmControl)target; NanoBrainObj[] nanoBrains = FindObjectsByType(FindObjectsSortMode.None); - + foreach (NanoBrainObj brain in nanoBrains) { UpdateWeight(brain, "Avoidance", swarmControl.avoidanceForce); } - //} Debug.Log("Updated weights"); } } From cb8c9dbb7cb340a2faca1177cd0b211c297d9e7c Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 5 Jan 2026 15:35:39 +0100 Subject: [PATCH 038/179] Better swarm control --- Assets/NanoBrain/Neuroid.cs | 2 +- Assets/NanoBrain/SensoryNeuroid.cs | 1 - Assets/Scenes/Boids/Boids.unity | 10 +++++----- Assets/Scenes/Boids/Prefabs/Boid.prefab | 2 +- .../Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs | 3 +++ Assets/Scenes/Boids/SwarmingBrain.asset | 6 +++--- 6 files changed, 13 insertions(+), 11 deletions(-) diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index a7ddff9..d7cd1ac 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -85,7 +85,7 @@ public class Neuroid : Nucleus { float weight = synapse.weight; float activatedValue = curve.Evaluate(synapseNucleus.outputValue.magnitude); float magnitude = weight * activatedValue; - Debug.Log($"{this.name} {synapseNucleus.outputValue.direction} {synapseNucleus.outputValue.direction.horizontal}{synapseNucleus.outputValue.direction.vertical} {direction}"); + //Debug.Log($"{this.name} {synapseNucleus.outputValue.direction} {synapseNucleus.outputValue.direction.horizontal}{synapseNucleus.outputValue.direction.vertical} {direction}"); result += direction * magnitude; } diff --git a/Assets/NanoBrain/SensoryNeuroid.cs b/Assets/NanoBrain/SensoryNeuroid.cs index d0948a7..aad0936 100644 --- a/Assets/NanoBrain/SensoryNeuroid.cs +++ b/Assets/NanoBrain/SensoryNeuroid.cs @@ -122,7 +122,6 @@ public class VelocityNeuroid : Neuroid { this.outputValue = Spherical.FromVector3(velocity); this.stale = 0; - //foreach (Neuroid receiver in receivers) foreach (Receiver receiver in receivers) { if (receiver.nucleus is Neuroid neuroid) neuroid.SetInput(this); diff --git a/Assets/Scenes/Boids/Boids.unity b/Assets/Scenes/Boids/Boids.unity index 593d20e..3931efd 100644 --- a/Assets/Scenes/Boids/Boids.unity +++ b/Assets/Scenes/Boids/Boids.unity @@ -374,10 +374,10 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: Assembly-CSharp::SwarmControl speed: 1 - inertia: 0.9 - alignmentForce: 2 - cohesionForce: 2 - avoidanceForce: 10 + inertia: 0.8 + alignmentForce: 9 + cohesionForce: 4 + avoidanceForce: 5 separationDistance: 0.3 perceptionDistance: 2 boundaryForce: 5 @@ -395,7 +395,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec888ca5333d45a438f9f417fa5ce135, type: 3} m_Name: m_EditorClassIdentifier: Assembly-CSharp::SwarmSpawn - count: 1 + count: 100 boidPrefab: {fileID: 8702527964058765413, guid: f9c706268554ce449a8773675b2864b8, type: 3} spawnAreaSize: {x: 0.5, y: 0.5, z: 0.5} minDelay: 0.05 diff --git a/Assets/Scenes/Boids/Prefabs/Boid.prefab b/Assets/Scenes/Boids/Prefabs/Boid.prefab index fc3c83c..49d299c 100644 --- a/Assets/Scenes/Boids/Prefabs/Boid.prefab +++ b/Assets/Scenes/Boids/Prefabs/Boid.prefab @@ -177,4 +177,4 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 92f34a5e4027a1dc39efd8ce63cf6aba, type: 3} m_Name: m_EditorClassIdentifier: Assembly-CSharp::NanoBrainComponent - defaultBrain: {fileID: 11400000, guid: af8d90b8b4b9dcad7837130c4143d91c, type: 2} + defaultBrain: {fileID: 11400000, guid: fc1a4800a8c531eb4855b436bc9084ae, type: 2} diff --git a/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs b/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs index 4f2fe37..45a42aa 100644 --- a/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs +++ b/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs @@ -14,6 +14,9 @@ public class SwarmControl_Editor : Editor { foreach (NanoBrainObj brain in nanoBrains) { UpdateWeight(brain, "Avoidance", swarmControl.avoidanceForce); + UpdateWeight(brain, "Cohesion", swarmControl.cohesionForce); + //UpdateWeight(brain, "Separation", swarmControl.separationDistance); + UpdateWeight(brain, "Alignment", swarmControl.alignmentForce); } Debug.Log("Updated weights"); } diff --git a/Assets/Scenes/Boids/SwarmingBrain.asset b/Assets/Scenes/Boids/SwarmingBrain.asset index 9213d2b..4293769 100644 --- a/Assets/Scenes/Boids/SwarmingBrain.asset +++ b/Assets/Scenes/Boids/SwarmingBrain.asset @@ -21,7 +21,7 @@ MonoBehaviour: _name: Root synapses: - nucleusId: -112538112 - weight: -5 + weight: 5 curvePreset: 0 curve: serializedVersion: 2 @@ -1280,10 +1280,10 @@ MonoBehaviour: inverse: 0 exponent: 1 - id: -112538112 - _name: Boundary Avoidance + _name: Avoidance synapses: - nucleusId: 407735232 - weight: 1 + weight: -1 curvePreset: 0 curve: serializedVersion: 2 From 61bdc36e84e16c2c58383019a6073273ece82fa4 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 5 Jan 2026 17:04:49 +0100 Subject: [PATCH 039/179] Using velocity receptor --- Assets/Scenes/Boids/Boids.unity | 5 +- Assets/Scenes/Boids/Materials/Red.mat | 84 +++++++++++++++++++ Assets/Scenes/Boids/Materials/Red.mat.meta | 8 ++ Assets/Scenes/Boids/Prefabs/Boid.prefab | 2 + Assets/Scenes/Boids/Scripts/Boid.cs | 25 +++++- .../Scripts/Editor/SwarmControl_Editor.cs | 2 +- Assets/Scenes/Boids/Scripts/SwarmControl.cs | 1 + 7 files changed, 123 insertions(+), 4 deletions(-) create mode 100644 Assets/Scenes/Boids/Materials/Red.mat create mode 100644 Assets/Scenes/Boids/Materials/Red.mat.meta diff --git a/Assets/Scenes/Boids/Boids.unity b/Assets/Scenes/Boids/Boids.unity index 3931efd..7024359 100644 --- a/Assets/Scenes/Boids/Boids.unity +++ b/Assets/Scenes/Boids/Boids.unity @@ -374,9 +374,10 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: Assembly-CSharp::SwarmControl speed: 1 - inertia: 0.8 - alignmentForce: 9 + inertia: 0.7 + alignmentForce: 0 cohesionForce: 4 + separationForce: -5 avoidanceForce: 5 separationDistance: 0.3 perceptionDistance: 2 diff --git a/Assets/Scenes/Boids/Materials/Red.mat b/Assets/Scenes/Boids/Materials/Red.mat new file mode 100644 index 0000000..eeeb395 --- /dev/null +++ b/Assets/Scenes/Boids/Materials/Red.mat @@ -0,0 +1,84 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Red + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 0, b: 0, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] + m_AllowLocking: 1 diff --git a/Assets/Scenes/Boids/Materials/Red.mat.meta b/Assets/Scenes/Boids/Materials/Red.mat.meta new file mode 100644 index 0000000..c0bf12a --- /dev/null +++ b/Assets/Scenes/Boids/Materials/Red.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2a7557e54580b6a8b976f12aa6cc761c +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/Boids/Prefabs/Boid.prefab b/Assets/Scenes/Boids/Prefabs/Boid.prefab index 49d299c..37277d0 100644 --- a/Assets/Scenes/Boids/Prefabs/Boid.prefab +++ b/Assets/Scenes/Boids/Prefabs/Boid.prefab @@ -165,6 +165,8 @@ MonoBehaviour: acceleration: {x: 0, y: 0, z: 0} nanoBrain: {fileID: 0} id: 0 + red: {fileID: 2100000, guid: 2a7557e54580b6a8b976f12aa6cc761c, type: 2} + gray: {fileID: 2100000, guid: a79ccc131cb43254cb8575d1cedb537e, type: 2} --- !u!114 &85370558829139006 MonoBehaviour: m_ObjectHideFlags: 0 diff --git a/Assets/Scenes/Boids/Scripts/Boid.cs b/Assets/Scenes/Boids/Scripts/Boid.cs index 87e8acd..844f5fe 100644 --- a/Assets/Scenes/Boids/Scripts/Boid.cs +++ b/Assets/Scenes/Boids/Scripts/Boid.cs @@ -5,6 +5,7 @@ using UnityEngine; public class Boid : MonoBehaviour { public static int BoundaryType = 1; public static int BoidType = 2; + public static int BoidVelocityType =3; public SwarmControl sc; public Vector3 velocity = Vector3.zero; @@ -15,15 +16,20 @@ public class Boid : MonoBehaviour { public NanoBrainComponent nanoBrain; public Receptor boundaryReceptor; public Receptor boidReceptor; + public Receptor boidVelocityReceptor; public int id; + public Material red; + public Material gray; + void Awake() { this.id = this.GetInstanceID(); nanoBrain = GetComponent(); boundaryReceptor = Perceptoid.GetReceptor(nanoBrain.brain, BoundaryType); boidReceptor = Perceptoid.GetReceptor(nanoBrain.brain, BoidType); + boidVelocityReceptor = Perceptoid.GetReceptor(nanoBrain.brain, BoidVelocityType); sc = FindFirstObjectByType(); @@ -39,11 +45,14 @@ public class Boid : MonoBehaviour { continue; Vector3 localPosition = this.transform.InverseTransformPoint(neighbour.transform.position); - localPosition = localPosition.normalized * (localPosition.magnitude - sc.separationDistance); + //localPosition = localPosition.normalized * (localPosition.magnitude - sc.separationDistance); //Debug.DrawRay(this.transform.position, this.transform.TransformDirection(localPosition), Color.magenta); + Vector3 localVelocity = this.transform.InverseTransformVector(neighbour.velocity); + int thingId = neighbour.GetInstanceID(); boidReceptor?.ProcessStimulus(thingId, localPosition); + boidVelocityReceptor?.ProcessStimulus(thingId, localVelocity); } } @@ -55,6 +64,7 @@ public class Boid : MonoBehaviour { boundaryReceptor.ProcessStimulus(777, desiredLocalSpace); } + Vector3 worldForce = this.transform.TransformDirection(nanoBrain.root.outputValue.ToVector3()); this.velocity = (1 - sc.inertia) * (worldForce * Time.deltaTime) + sc.inertia * velocity; @@ -72,6 +82,19 @@ public class Boid : MonoBehaviour { } nanoBrain.brain.UpdateNuclei(); + + Renderer renderer = GetComponentInChildren(); + results = Physics.OverlapSphere(this.transform.position, 0.1f); + if (results.Length > 1) { + // string s= this.name; + // foreach (Collider c in results) + // s += " " + c.transform.parent.gameObject.name; + // Debug.Log(s); + renderer.sharedMaterial = red; + } + else { + renderer.sharedMaterial = gray; + } } } diff --git a/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs b/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs index 45a42aa..4d51630 100644 --- a/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs +++ b/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs @@ -15,7 +15,7 @@ public class SwarmControl_Editor : Editor { foreach (NanoBrainObj brain in nanoBrains) { UpdateWeight(brain, "Avoidance", swarmControl.avoidanceForce); UpdateWeight(brain, "Cohesion", swarmControl.cohesionForce); - //UpdateWeight(brain, "Separation", swarmControl.separationDistance); + UpdateWeight(brain, "Separation", swarmControl.separationForce); UpdateWeight(brain, "Alignment", swarmControl.alignmentForce); } Debug.Log("Updated weights"); diff --git a/Assets/Scenes/Boids/Scripts/SwarmControl.cs b/Assets/Scenes/Boids/Scripts/SwarmControl.cs index c98a403..0326213 100644 --- a/Assets/Scenes/Boids/Scripts/SwarmControl.cs +++ b/Assets/Scenes/Boids/Scripts/SwarmControl.cs @@ -8,6 +8,7 @@ public class SwarmControl : MonoBehaviour public float inertia = 0.1f; public float alignmentForce = 0.0f; public float cohesionForce = 10.0f; + public float separationForce = 5.0f; public float avoidanceForce = 5.0f; public float separationDistance = 0.5f; // public float bodyForce = 20; From 11ecb905eeff028d297af6b1b8fb9d6e77a88763 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 5 Jan 2026 17:46:47 +0100 Subject: [PATCH 040/179] Cleanup --- Assets/NanoBrain/Editor/NanoBrain_Editor.cs | 16 +- Assets/NanoBrain/Editor/NeuroidWindow.cs | 6 +- .../VisualEditor/Editor/NanoBrainEditor.cs | 16 +- .../VisualEditor/Editor/NanoBrainInspector.cs | 6 +- Assets/Scenes/Boids/Boids.unity | 2 +- Assets/Scenes/Boids/Prefabs/Boid.prefab | 2 +- Assets/Scenes/Boids/Scripts/Boid.cs | 24 +- Assets/Scenes/Boids/SwarmingBrain.asset | 340 ++++++++++++++++-- 8 files changed, 352 insertions(+), 60 deletions(-) diff --git a/Assets/NanoBrain/Editor/NanoBrain_Editor.cs b/Assets/NanoBrain/Editor/NanoBrain_Editor.cs index b070c5e..eb59d54 100644 --- a/Assets/NanoBrain/Editor/NanoBrain_Editor.cs +++ b/Assets/NanoBrain/Editor/NanoBrain_Editor.cs @@ -158,7 +158,7 @@ public class NanoBrain_Editor : Editor { //int i = 0; float inputSpacing = 400f / layerNeuroid.synapses.Count; float inputMargin = 10 + inputSpacing / 2; - int minStale = 10000; + // int minStale = 10000; //foreach ((Nucleus nucleus, float weight) in layerNeuroid.synapses) { foreach (Synapse synapse in layerNeuroid.synapses) { Nucleus nucleus = synapse.nucleus; @@ -173,12 +173,12 @@ public class NanoBrain_Editor : Editor { Handles.DrawLine(parentPos, pos); } } - if (nucleus is Neuroid neuroid && neuroid.stale < minStale) - minStale = neuroid.stale; + // if (nucleus is Neuroid neuroid && neuroid.stale < minStale) + // minStale = neuroid.stale; } - if (layerNeuroid.synapses.Count > 0 && minStale > 2 && layerNeuroid.stale < 3) - Debug.LogWarning($"Strange {minStale} is big duing update"); + // if (layerNeuroid.synapses.Count > 0 && minStale > 2 && layerNeuroid.stale < 3) + // Debug.LogWarning($"Strange {minStale} is big duing update"); float size = 20; @@ -222,15 +222,13 @@ public class NanoBrain_Editor : Editor { tooltip = new( $"{sensoryNeuroid.name}" + $"\nThing {sensoryNeuroid.receptor.thingType}" + - $"\nValue: {neuroid.outputValue}" + - $"\nStale: {neuroid.stale}"); + $"\nValue: {neuroid.outputValue}"); } else { tooltip = new( $"{neuroid.name}" + $"\nsynapse count {neuroid.synapses.Count}" + - $"\nValue: {neuroid.outputValue}" + - $"\nStale: {neuroid.stale}"); + $"\nValue: {neuroid.outputValue}"); } Vector2 mousePosition = Event.current.mousePosition; diff --git a/Assets/NanoBrain/Editor/NeuroidWindow.cs b/Assets/NanoBrain/Editor/NeuroidWindow.cs index 133d99c..354dd4e 100644 --- a/Assets/NanoBrain/Editor/NeuroidWindow.cs +++ b/Assets/NanoBrain/Editor/NeuroidWindow.cs @@ -245,15 +245,13 @@ public class GraphEditorWindow : EditorWindow { tooltip = new( $"{sensoryNeuroid.name}" + $"\nThing {sensoryNeuroid.receptor.thingType}" + - $"\nValue: {neuroid.outputValue}" + - $"\nStale: {neuroid.stale}"); + $"\nValue: {neuroid.outputValue}"); } else { tooltip = new( $"{neuroid.name}" + $"\nsynapse count {neuroid.synapses.Count}" + - $"\nValue: {neuroid.outputValue}" + - $"\nStale: {neuroid.stale}"); + $"\nValue: {neuroid.outputValue}"); } Vector2 mousePosition = Event.current.mousePosition; diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs index 31938b1..d534b9e 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs @@ -235,7 +235,7 @@ public class GraphBoardView : VisualElement { //int i = 0; float inputSpacing = 400f / layerNucleus.synapses.Count; float inputMargin = 10 + inputSpacing / 2; - int minStale = 10000; + // int minStale = 10000; //foreach ((Nucleus nucleus, float weight) in layerNucleus.synapses) { foreach (Synapse synapse in layerNucleus.synapses) { Nucleus nucleus = synapse.nucleus; @@ -251,13 +251,13 @@ public class GraphBoardView : VisualElement { Handles.DrawLine(parentPos, pos); } } - if (nucleus is Neuroid neuroid && neuroid.stale < minStale) - minStale = neuroid.stale; + // if (nucleus is Neuroid neuroid && neuroid.stale < minStale) + // minStale = neuroid.stale; } } - if (layerNucleus.synapses.Count > 0 && minStale > 2 && layerNucleus.stale < 3) - Debug.LogWarning($"Strange {minStale} is big duing update"); + // if (layerNucleus.synapses.Count > 0 && minStale > 2 && layerNucleus.stale < 3) + // Debug.LogWarning($"Strange {minStale} is big duing update"); float size = 20; @@ -300,15 +300,13 @@ public class GraphBoardView : VisualElement { tooltip = new( $"{sensoryNeuroid.name}" + $"\nThing {sensoryNeuroid.receptor.thingType}" + - $"\nValue: {neuroid.outputValue}" + - $"\nStale: {neuroid.stale}"); + $"\nValue: {neuroid.outputValue}"); } else { tooltip = new( $"{neuroid.name}" + $"\nsynapse count {neuroid.synapses.Count}" + - $"\nValue: {neuroid.outputValue}" + - $"\nStale: {neuroid.stale}"); + $"\nValue: {neuroid.outputValue}"); } Vector2 mousePosition = Event.current.mousePosition; diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs index 705aa68..0a694e0 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs @@ -341,8 +341,7 @@ public class NanoBrainInspector : Editor { tooltip = new( $"{sensoryNeuroid.name}" + $"\nThing {sensoryNeuroid.receptor.thingType}" + - $"\nValue: {nucleus.outputValue}" + - $"\nStale: {nucleus.stale}"); + $"\nValue: {nucleus.outputValue}"); } else if (nucleus is Perceptoid perceptoid) { if (perceptoid.receptor != null) { @@ -363,8 +362,7 @@ public class NanoBrainInspector : Editor { tooltip = new( $"{nucleus.name}" + $"\nsynapse count {nucleus.synapses.Count}" + - $"\nValue: {nucleus.outputValue}" + - $"\nStale: {nucleus.stale}"); + $"\nValue: {nucleus.outputValue}"); } Vector2 mousePosition = Event.current.mousePosition; diff --git a/Assets/Scenes/Boids/Boids.unity b/Assets/Scenes/Boids/Boids.unity index 7024359..9c0eb11 100644 --- a/Assets/Scenes/Boids/Boids.unity +++ b/Assets/Scenes/Boids/Boids.unity @@ -375,7 +375,7 @@ MonoBehaviour: m_EditorClassIdentifier: Assembly-CSharp::SwarmControl speed: 1 inertia: 0.7 - alignmentForce: 0 + alignmentForce: 2 cohesionForce: 4 separationForce: -5 avoidanceForce: 5 diff --git a/Assets/Scenes/Boids/Prefabs/Boid.prefab b/Assets/Scenes/Boids/Prefabs/Boid.prefab index 37277d0..82bf014 100644 --- a/Assets/Scenes/Boids/Prefabs/Boid.prefab +++ b/Assets/Scenes/Boids/Prefabs/Boid.prefab @@ -179,4 +179,4 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 92f34a5e4027a1dc39efd8ce63cf6aba, type: 3} m_Name: m_EditorClassIdentifier: Assembly-CSharp::NanoBrainComponent - defaultBrain: {fileID: 11400000, guid: fc1a4800a8c531eb4855b436bc9084ae, type: 2} + defaultBrain: {fileID: 11400000, guid: af8d90b8b4b9dcad7837130c4143d91c, type: 2} diff --git a/Assets/Scenes/Boids/Scripts/Boid.cs b/Assets/Scenes/Boids/Scripts/Boid.cs index 844f5fe..ac78915 100644 --- a/Assets/Scenes/Boids/Scripts/Boid.cs +++ b/Assets/Scenes/Boids/Scripts/Boid.cs @@ -83,18 +83,18 @@ public class Boid : MonoBehaviour { nanoBrain.brain.UpdateNuclei(); - Renderer renderer = GetComponentInChildren(); - results = Physics.OverlapSphere(this.transform.position, 0.1f); - if (results.Length > 1) { - // string s= this.name; - // foreach (Collider c in results) - // s += " " + c.transform.parent.gameObject.name; - // Debug.Log(s); - renderer.sharedMaterial = red; - } - else { - renderer.sharedMaterial = gray; - } + // Renderer renderer = GetComponentInChildren(); + // results = Physics.OverlapSphere(this.transform.position, 0.1f); + // if (results.Length > 1) { + // // string s= this.name; + // // foreach (Collider c in results) + // // s += " " + c.transform.parent.gameObject.name; + // // Debug.Log(s); + // renderer.sharedMaterial = red; + // } + // else { + // renderer.sharedMaterial = gray; + // } } } diff --git a/Assets/Scenes/Boids/SwarmingBrain.asset b/Assets/Scenes/Boids/SwarmingBrain.asset index 4293769..d47131b 100644 --- a/Assets/Scenes/Boids/SwarmingBrain.asset +++ b/Assets/Scenes/Boids/SwarmingBrain.asset @@ -77,7 +77,7 @@ MonoBehaviour: m_RotationOrder: 4 curveMax: 10 - nucleusId: 1641120128 - weight: -10 + weight: -5 curvePreset: 3 curve: serializedVersion: 2 @@ -1239,7 +1239,7 @@ MonoBehaviour: m_RotationOrder: 4 curveMax: 1000 - nucleusId: -1857835930 - weight: 9 + weight: 2 curvePreset: 0 curve: serializedVersion: 2 @@ -1250,6 +1250,7 @@ MonoBehaviour: curveMax: 1 receivers: [] nucleusType: + isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -1295,6 +1296,7 @@ MonoBehaviour: receivers: - nucleusId: -1707533328 nucleusType: + isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -1390,6 +1392,7 @@ MonoBehaviour: receivers: - nucleusId: -1707533328 nucleusType: + isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -1485,6 +1488,7 @@ MonoBehaviour: receivers: - nucleusId: -1707533328 nucleusType: + isSleeping: 0 _curvePreset: 2 curve: serializedVersion: 2 @@ -1787,7 +1791,7 @@ MonoBehaviour: - id: -1857835930 _name: Alignment synapses: - - nucleusId: -176251552 + - nucleusId: 1921239042 weight: 1 curvePreset: 0 curve: @@ -1797,7 +1801,7 @@ MonoBehaviour: m_PostInfinity: 2 m_RotationOrder: 4 curveMax: 1 - - nucleusId: 1164040656 + - nucleusId: 1686464114 weight: 1 curvePreset: 0 curve: @@ -1807,7 +1811,7 @@ MonoBehaviour: m_PostInfinity: 2 m_RotationOrder: 4 curveMax: 1 - - nucleusId: -1679360144 + - nucleusId: -1926972526 weight: 1 curvePreset: 0 curve: @@ -1817,7 +1821,7 @@ MonoBehaviour: m_PostInfinity: 2 m_RotationOrder: 4 curveMax: 1 - - nucleusId: -1513426512 + - nucleusId: 483038322 weight: 1 curvePreset: 0 curve: @@ -1827,7 +1831,7 @@ MonoBehaviour: m_PostInfinity: 2 m_RotationOrder: 4 curveMax: 1 - - nucleusId: 1708725840 + - nucleusId: 890767934 weight: 1 curvePreset: 0 curve: @@ -1837,7 +1841,7 @@ MonoBehaviour: m_PostInfinity: 2 m_RotationOrder: 4 curveMax: 1 - - nucleusId: -1645785904 + - nucleusId: -324208238 weight: 1 curvePreset: 0 curve: @@ -1850,6 +1854,7 @@ MonoBehaviour: receivers: - nucleusId: -1707533328 nucleusType: + isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -1892,9 +1897,9 @@ MonoBehaviour: m_PostInfinity: 2 m_RotationOrder: 4 curveMax: 1 - receivers: - - nucleusId: -1857835930 + receivers: [] nucleusType: + isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -1937,9 +1942,9 @@ MonoBehaviour: m_PostInfinity: 2 m_RotationOrder: 4 curveMax: 1 - receivers: - - nucleusId: -1857835930 + receivers: [] nucleusType: + isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -1982,9 +1987,9 @@ MonoBehaviour: m_PostInfinity: 2 m_RotationOrder: 4 curveMax: 1 - receivers: - - nucleusId: -1857835930 + receivers: [] nucleusType: + isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -2027,9 +2032,9 @@ MonoBehaviour: m_PostInfinity: 2 m_RotationOrder: 4 curveMax: 1 - receivers: - - nucleusId: -1857835930 + receivers: [] nucleusType: + isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -2072,9 +2077,9 @@ MonoBehaviour: m_PostInfinity: 2 m_RotationOrder: 4 curveMax: 1 - receivers: - - nucleusId: -1857835930 + receivers: [] nucleusType: + isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -2117,9 +2122,9 @@ MonoBehaviour: m_PostInfinity: 2 m_RotationOrder: 4 curveMax: 1 - receivers: - - nucleusId: -1857835930 + receivers: [] nucleusType: + isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -2149,6 +2154,168 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 + - id: -1621097280 + _name: 'New Perceptoid: velocity' + synapses: + - nucleusId: 1921239042 + weight: 1 + curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + receivers: [] + nucleusType: + isSleeping: 0 + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + - id: -966090960 + _name: 'New Perceptoid: velocity' + synapses: + - nucleusId: 1686464114 + weight: 1 + curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + receivers: [] + nucleusType: + isSleeping: 0 + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + - id: 1426014432 + _name: 'New Perceptoid: velocity' + synapses: + - nucleusId: -1926972526 + weight: 1 + curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + receivers: [] + nucleusType: + isSleeping: 0 + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + - id: -610217840 + _name: 'New Perceptoid: velocity' + synapses: + - nucleusId: 483038322 + weight: 1 + curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + receivers: [] + nucleusType: + isSleeping: 0 + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + - id: -481628544 + _name: 'New Perceptoid: velocity' + synapses: + - nucleusId: 890767934 + weight: 1 + curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + receivers: [] + nucleusType: + isSleeping: 0 + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + - id: 1464656048 + _name: 'New Perceptoid: velocity' + synapses: + - nucleusId: -324208238 + weight: 1 + curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + receivers: [] + nucleusType: + isSleeping: 0 + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 perceptei: - id: 407735232 _name: Boundary @@ -2156,6 +2323,7 @@ MonoBehaviour: receivers: - nucleusId: -112538112 nucleusType: Perceptoid + isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -2177,6 +2345,7 @@ MonoBehaviour: - nucleusId: 1938577052 - nucleusId: 1641120128 nucleusType: Perceptoid + isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -2198,6 +2367,7 @@ MonoBehaviour: - nucleusId: 1938577052 - nucleusId: 1641120128 nucleusType: Perceptoid + isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -2219,6 +2389,7 @@ MonoBehaviour: - nucleusId: 1938577052 - nucleusId: 1641120128 nucleusType: Perceptoid + isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -2240,6 +2411,7 @@ MonoBehaviour: - nucleusId: 1938577052 - nucleusId: 1641120128 nucleusType: Perceptoid + isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -2261,6 +2433,7 @@ MonoBehaviour: - nucleusId: 1938577052 - nucleusId: 1641120128 nucleusType: Perceptoid + isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -2282,6 +2455,7 @@ MonoBehaviour: - nucleusId: 1938577052 - nucleusId: 1641120128 nucleusType: Perceptoid + isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -2295,4 +2469,130 @@ MonoBehaviour: exponent: 1 thingType: 2 thingId: 0 + - id: 1921239042 + _name: Boid1Velocity + synapses: [] + receivers: + - nucleusId: -1621097280 + - nucleusId: -1857835930 + nucleusType: Perceptoid + isSleeping: 0 + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + thingType: 3 + thingId: 0 + - id: 1686464114 + _name: Boid2Velocity + synapses: [] + receivers: + - nucleusId: -966090960 + - nucleusId: -1857835930 + nucleusType: Perceptoid + isSleeping: 0 + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + thingType: 3 + thingId: 0 + - id: -1926972526 + _name: Boid3Velocity + synapses: [] + receivers: + - nucleusId: 1426014432 + - nucleusId: -1857835930 + nucleusType: Perceptoid + isSleeping: 0 + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + thingType: 3 + thingId: 0 + - id: 483038322 + _name: Boid4Velocity + synapses: [] + receivers: + - nucleusId: -610217840 + - nucleusId: -1857835930 + nucleusType: Perceptoid + isSleeping: 0 + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + thingType: 3 + thingId: 0 + - id: 890767934 + _name: Boid5Velocity + synapses: [] + receivers: + - nucleusId: -481628544 + - nucleusId: -1857835930 + nucleusType: Perceptoid + isSleeping: 0 + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + thingType: 3 + thingId: 0 + - id: -324208238 + _name: Boid6Velocity + synapses: [] + receivers: + - nucleusId: 1464656048 + - nucleusId: -1857835930 + nucleusType: Perceptoid + isSleeping: 0 + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + thingType: 3 + thingId: 0 rootId: -1707533328 From 14a786246c8700f83ee22fcbb806138845831a0e Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 5 Jan 2026 17:55:09 +0100 Subject: [PATCH 041/179] Simplifying stale nuclei --- Assets/NanoBrain/Neuroid.cs | 3 +- Assets/NanoBrain/Nucleus.cs | 30 ++++++++++++++----- Assets/NanoBrain/Perceptoid.cs | 6 ++-- Assets/NanoBrain/SensoryNeuroid.cs | 6 ++-- Assets/NanoBrain/VisualEditor/NanoBrainObj.cs | 6 ++-- Assets/Scenes/Boids/Prefabs/Boid.prefab | 2 +- .../Scenes/Boids/Scripts/SwarmingNucleus.cs | 2 +- 7 files changed, 39 insertions(+), 16 deletions(-) diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index d7cd1ac..0bd9c90 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -93,7 +93,8 @@ public class Neuroid : Nucleus { result /= this.synapses.Count; this.outputValue = Spherical.FromVector3(result); - this.stale = 0; + //this.stale = 0; + this.Refresh(); foreach (Receiver receiver in this.receivers) { if (receiver.nucleus is Neuroid neuroid) diff --git a/Assets/NanoBrain/Nucleus.cs b/Assets/NanoBrain/Nucleus.cs index 9c195ca..b114911 100644 --- a/Assets/NanoBrain/Nucleus.cs +++ b/Assets/NanoBrain/Nucleus.cs @@ -64,10 +64,26 @@ public class Nucleus { public NanoBrainObj brain { get; set; } - public virtual Spherical outputValue { get; set; } + private Spherical _outputValue; + public Spherical outputValue //{ get; set; } + { + get { return _outputValue; } + set { + //Refresh(); + this.stale = 0; + _outputValue = value; + } + } [System.NonSerialized] - public int stale = 0; + private int stale = 0; + public bool isSleeping => this.stale > 2; + public void Refresh() { + //this.stale = 0; + } + public void IncreaseAge() { + this.stale++; + } [System.NonSerialized] public int layerIx; @@ -122,11 +138,11 @@ public class Nucleus { this.SetWeight(input, weight); } - public bool isSleeping { - get { - return this.stale > 2; - } - } + // public bool isSleeping { + // get { + // return this.stale > 2; + // } + // } public bool SynapseExists(Nucleus nucleus) { foreach (Synapse synapse in synapses) { diff --git a/Assets/NanoBrain/Perceptoid.cs b/Assets/NanoBrain/Perceptoid.cs index c2acb1f..75fd6e2 100644 --- a/Assets/NanoBrain/Perceptoid.cs +++ b/Assets/NanoBrain/Perceptoid.cs @@ -118,7 +118,8 @@ public class Perceptoid : Neuroid { foreach (Receiver receiver in this.receivers) if (receiver.nucleus is Neuroid neuroid) neuroid.SetInput(this); - this.stale = 0; + //this.stale = 0; + this.Refresh(); } public void UpdateState(int thingId, Spherical receptorValue) { @@ -142,7 +143,8 @@ public class Perceptoid : Neuroid { foreach (Receiver receiver in this.receivers) if (receiver.nucleus is Neuroid neuroid) neuroid.SetInput(this); - this.stale = 0; + //this.stale = 0; + this.Refresh(); } diff --git a/Assets/NanoBrain/SensoryNeuroid.cs b/Assets/NanoBrain/SensoryNeuroid.cs index aad0936..1c12129 100644 --- a/Assets/NanoBrain/SensoryNeuroid.cs +++ b/Assets/NanoBrain/SensoryNeuroid.cs @@ -87,7 +87,8 @@ public class SensoryNeuroid : Neuroid { foreach (Receiver receiver in this.receivers) if (receiver.nucleus is Neuroid neuroid) neuroid.SetInput(this); - this.stale = 0; + //this.stale = 0; + this.Refresh(); } } @@ -120,7 +121,8 @@ public class VelocityNeuroid : Neuroid { // No activation function... this.outputValue = Spherical.FromVector3(velocity); - this.stale = 0; + //this.stale = 0; + this.Refresh(); foreach (Receiver receiver in receivers) { if (receiver.nucleus is Neuroid neuroid) diff --git a/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs b/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs index 096ff4b..970a2ac 100644 --- a/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs +++ b/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs @@ -32,12 +32,14 @@ public class NanoBrainObj : ScriptableObject, ISerializationCallbackReceiver { public void UpdateNuclei() { foreach (Nucleus nucleus in nuclei) { - nucleus.stale++; + //nucleus.stale++; + nucleus.IncreaseAge(); if (nucleus.isSleeping) nucleus.outputValue = Spherical.zero; } foreach (Perceptoid perception in perceptei) { - perception.stale++; + //perception.stale++; + perception.IncreaseAge(); if (perception.isSleeping) perception.outputValue = Spherical.zero; } diff --git a/Assets/Scenes/Boids/Prefabs/Boid.prefab b/Assets/Scenes/Boids/Prefabs/Boid.prefab index 82bf014..37277d0 100644 --- a/Assets/Scenes/Boids/Prefabs/Boid.prefab +++ b/Assets/Scenes/Boids/Prefabs/Boid.prefab @@ -179,4 +179,4 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 92f34a5e4027a1dc39efd8ce63cf6aba, type: 3} m_Name: m_EditorClassIdentifier: Assembly-CSharp::NanoBrainComponent - defaultBrain: {fileID: 11400000, guid: af8d90b8b4b9dcad7837130c4143d91c, type: 2} + defaultBrain: {fileID: 11400000, guid: fc1a4800a8c531eb4855b436bc9084ae, type: 2} diff --git a/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs b/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs index bbe6200..a269b01 100644 --- a/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs +++ b/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs @@ -9,7 +9,7 @@ public class Swarming : Nucleus { public Neuroid output; - public override Spherical outputValue { get => output.outputValue; set => output.outputValue = value; } + //public override Spherical outputValue { get => output.outputValue; set => output.outputValue = value; } public Swarming(NanoBrainObj brain, Perception perception, SwarmControl sc) : base("Swarming Nucleus") { this.cohesion = new(brain, "Cohesion") { inverse = false }; From 21344950459c0fac09b733d57f1665bb0e9c9aad Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Tue, 6 Jan 2026 15:03:52 +0100 Subject: [PATCH 042/179] (A little) Performance improvements --- .editorconfig | 34 +- .../NanoBrain/LinearAlgebra/src/Direction.cs | 71 +- .../NanoBrain/LinearAlgebra/src/Spherical.cs | 25 + Assets/NanoBrain/Neuroid.cs | 17 +- Assets/NanoBrain/Nucleus.cs | 7 +- Assets/NanoBrain/Perception.cs | 60 +- Assets/NanoBrain/Perceptoid.cs | 80 +- Assets/NanoBrain/Receptor.cs | 75 +- Assets/NanoBrain/SensoryNeuroid.cs | 88 +- .../VisualEditor/Editor/NanoBrainInspector.cs | 5 +- Assets/NanoBrain/VisualEditor/NanoBrainObj.cs | 12 +- Assets/Scenes/Boids/Boids.unity | 2 +- Assets/Scenes/Boids/Scripts/Boid.cs | 6 +- Assets/Scenes/Boids/Scripts/RoamingNucleus.cs | 4 +- .../Scenes/Boids/Scripts/SwarmingNucleus.cs | 56 +- Assets/Scenes/Boids/SwarmingBrain.asset | 870 ++++++------------ 16 files changed, 589 insertions(+), 823 deletions(-) diff --git a/.editorconfig b/.editorconfig index 64e4e80..1ec7f97 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,23 +1,19 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file root = true +[*] +indent_style = space +indent_size = 4 +end_of_line = crlf +charset = utf-8 +trim_trailing_whitespace = false +insert_final_newline = false +max_line_length = 80 + [*.cs] -# Use tabs for indentation -indent_style = space # To use spaces, you could set this to 'space' -indent_size = 2 # Standard C# indent size - -# Alignment and Style Rules -csharp_indent_case_contents = true -csharp_new_line_after_open_brace = all csharp_new_line_before_open_brace = none -csharp_new_line_before_else = true -csharp_new_line_before_catch = true -csharp_new_line_before_finally = true -csharp_new_line_before_members_in_object_initializers = true -csharp_new_line_before_members_in_anonymous_types = true -csharp_new_line_between_query_expression_clauses = true - -# Limit the number of characters in a line -max_line_length = 100 # This setting does not enforce it; it's a guideline. - -[*.{cs,vb}] -dotnet_diagnostic.IDE1006.severity = none \ No newline at end of file +# Suppress warnings everywhere +dotnet_diagnostic.IDE1006.severity = none +dotnet_diagnostic.IDE0130.severity = none \ No newline at end of file diff --git a/Assets/NanoBrain/LinearAlgebra/src/Direction.cs b/Assets/NanoBrain/LinearAlgebra/src/Direction.cs index dfc90bd..95b8d6a 100644 --- a/Assets/NanoBrain/LinearAlgebra/src/Direction.cs +++ b/Assets/NanoBrain/LinearAlgebra/src/Direction.cs @@ -3,7 +3,8 @@ using System; using Vector3Float = UnityEngine.Vector3; #endif -namespace LinearAlgebra { +namespace LinearAlgebra +{ /// /// A direction in 3D space @@ -16,7 +17,8 @@ namespace LinearAlgebra { /// rotation has been applied. /// The angles are automatically normalized to stay within the abovenmentioned /// ranges. - public struct Direction { + public struct Direction + { /// @brief horizontal angle, range = (-180..180] degrees public AngleFloat horizontal; /// @brief vertical angle, range in degrees = (-90..90] degrees @@ -29,7 +31,8 @@ namespace LinearAlgebra { /// The vertical angle /// The direction will be normalized automatically /// to ensure the angles are within the allowed ranges - public Direction(AngleFloat horizontal, AngleFloat vertical) { + public Direction(AngleFloat horizontal, AngleFloat vertical) + { this.horizontal = horizontal; this.vertical = vertical; this.Normalize(); @@ -43,8 +46,10 @@ namespace LinearAlgebra { /// The direction /// The direction will be normalized automatically /// to ensure the angles are within the allowed ranges - public static Direction Degrees(float horizontal, float vertical) { - Direction d = new() { + public static Direction Degrees(float horizontal, float vertical) + { + Direction d = new() + { horizontal = AngleFloat.Degrees(horizontal), vertical = AngleFloat.Degrees(vertical) }; @@ -57,8 +62,10 @@ namespace LinearAlgebra { /// The horizontal angle in radians /// The vertical angle in radians /// The direction - public static Direction Radians(float horizontal, float vertical) { - Direction d = new() { + public static Direction Radians(float horizontal, float vertical) + { + Direction d = new() + { horizontal = AngleFloat.Radians(horizontal), vertical = AngleFloat.Radians(vertical) }; @@ -66,7 +73,8 @@ namespace LinearAlgebra { return d; } - public override readonly string ToString() { + public override readonly string ToString() + { return $"Direction(h: {this.horizontal}, v: {this.vertical})"; } @@ -99,8 +107,10 @@ namespace LinearAlgebra { /// public readonly static Direction right = Degrees(90, 0); - private void Normalize() { - if (this.vertical > AngleFloat.deg90 || this.vertical < -AngleFloat.deg90) { + private void Normalize() + { + if (this.vertical > AngleFloat.deg90 || this.vertical < -AngleFloat.deg90) + { this.horizontal += AngleFloat.deg180; this.vertical = AngleFloat.deg180 - this.vertical; } @@ -142,11 +152,12 @@ namespace LinearAlgebra { /// Convert the direction into a carthesian vector /// /// The carthesian vector corresponding to this direction. - public Vector3Float ToVector3() { + public Vector3Float ToVector3() + { // Quaternion q = Quaternion.Euler(90 - this.vertical.inDegrees, this.horizontal.inDegrees, 0); // Vector3Float v = q * Vector3Float.forward; // return v; - // Convert degrees to radians + // Convert degrees to radians float radH = this.horizontal.inRadians; float radV = this.vertical.inRadians; @@ -166,7 +177,8 @@ namespace LinearAlgebra { /// The direction /// Information about the length of the carthesian vector is not /// included in this transformation - public static Direction FromVector3(Vector3Float v) { + public static Direction FromVector3(Vector3Float v) + { AngleFloat horizontal = AngleFloat.Atan2(v.horizontal, v.depth); AngleFloat vertical = AngleFloat.deg90 - AngleFloat.Acos(v.vertical); Direction d = new(horizontal, vertical); @@ -181,7 +193,8 @@ namespace LinearAlgebra { /// /// /// True when the direction angles are equal, false otherwise. - public static bool operator ==(Direction d1, Direction d2) { + public static bool operator ==(Direction d1, Direction d2) + { bool horizontalEq = d1.horizontal == d2.horizontal; bool verticalEq = d1.vertical == d2.vertical; return horizontalEq && verticalEq; @@ -193,13 +206,15 @@ namespace LinearAlgebra { /// /// /// True when the direction angles are not equal, false otherwise. - public static bool operator !=(Direction d1, Direction d2) { + public static bool operator !=(Direction d1, Direction d2) + { bool horizontalNEq = d1.horizontal != d2.horizontal; bool verticalNEq = d1.vertical != d2.vertical; return horizontalNEq || verticalNEq; } - public override readonly bool Equals(object obj) { + public override readonly bool Equals(object obj) + { if (obj is not Direction d) return false; @@ -209,10 +224,32 @@ namespace LinearAlgebra { } - public override readonly int GetHashCode() { + public override readonly int GetHashCode() + { return HashCode.Combine(horizontal, vertical); } + public static AngleFloat UnsignedAngle(Direction d1, Direction d2) + { + // Convert angles from degrees to radians + float horizontal1Rad = d1.horizontal.inRadians; + float vertical1Rad = d1.vertical.inRadians; + + float horizontal2Rad = d2.horizontal.inRadians; + float vertical2Rad = d2.vertical.inRadians; + + // Calculate the cosine of the angle using the spherical law of cosines + float cosTheta = MathF.Sin(vertical1Rad) * MathF.Sin(vertical2Rad) + + MathF.Cos(vertical1Rad) * MathF.Cos(vertical2Rad) * + MathF.Cos(horizontal1Rad - horizontal2Rad); + + // Clip cosTheta to the valid range for acos + cosTheta = Float.Clamp(cosTheta, -1.0f, 1.0f); + + // Calculate the angle + AngleFloat angle = AngleFloat.Acos(cosTheta); + return angle; + } } } \ No newline at end of file diff --git a/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs b/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs index 1c92faa..e1e3ab6 100644 --- a/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs +++ b/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs @@ -137,5 +137,30 @@ namespace LinearAlgebra { return r; } + public static float Distance(Spherical v1, Spherical v2) { + // Convert degrees to radians + float thetaARadians = v1.direction.horizontal.inRadians; + float phiARadians = v1.direction.vertical.inRadians;// DegreesToRadians(phiA); + float thetaBRadians = v2.direction.horizontal.inRadians; // DegreesToRadians(thetaB); + float phiBRadians = v2.direction.vertical.inRadians; // DegreesToRadians(phiB); + + // Calculate sine and cosine values + float sinPhiA = MathF.Sin(phiARadians); + float cosPhiA = MathF.Cos(phiARadians); + float sinPhiB = MathF.Sin(phiBRadians); + float cosPhiB = MathF.Cos(phiBRadians); + + // Calculate the cosine of the difference in azimuthal angles + float cosThetaDifference = MathF.Cos(thetaARadians - thetaBRadians); + + // Apply the spherical law of cosines + float distance = MathF.Sqrt( + v1.distance * v1.distance + + v2.distance * v2.distance - + 2 * v1.distance * v2.distance * (sinPhiA * sinPhiB * cosThetaDifference + cosPhiA * cosPhiB) + ); + + return distance; + } } } \ No newline at end of file diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index 0bd9c90..287c23b 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -74,7 +74,7 @@ public class Neuroid : Nucleus { } public virtual void UpdateState() { - Vector3 result = Vector3.zero; + Vector3 resultVector = Vector3.zero; foreach (Synapse synapse in this.synapses) { Nucleus synapseNucleus = synapse.nucleus; if (synapseNucleus is Neuroid neuroid && neuroid.isSleeping) @@ -87,14 +87,21 @@ public class Neuroid : Nucleus { float magnitude = weight * activatedValue; //Debug.Log($"{this.name} {synapseNucleus.outputValue.direction} {synapseNucleus.outputValue.direction.horizontal}{synapseNucleus.outputValue.direction.vertical} {direction}"); - result += direction * magnitude; + resultVector += direction * magnitude; } if (average && this.synapses.Count > 0) - result /= this.synapses.Count; + resultVector /= this.synapses.Count; - this.outputValue = Spherical.FromVector3(result); + Spherical result = Spherical.FromVector3(resultVector); + float d = Spherical.Distance(result, this.outputValue); + if (d < 0.1f) { + //Debug.Log($"insignificant update: {d}"); + return; + } + + this.outputValue = result; //Spherical.FromVector3(resultVector); //this.stale = 0; - this.Refresh(); + //this.Refresh(); foreach (Receiver receiver in this.receivers) { if (receiver.nucleus is Neuroid neuroid) diff --git a/Assets/NanoBrain/Nucleus.cs b/Assets/NanoBrain/Nucleus.cs index b114911..7b49319 100644 --- a/Assets/NanoBrain/Nucleus.cs +++ b/Assets/NanoBrain/Nucleus.cs @@ -76,13 +76,12 @@ public class Nucleus { } [System.NonSerialized] - private int stale = 0; + private int stale = 1000; public bool isSleeping => this.stale > 2; - public void Refresh() { - //this.stale = 0; - } public void IncreaseAge() { this.stale++; + if (isSleeping) + _outputValue = Spherical.zero; } [System.NonSerialized] public int layerIx; diff --git a/Assets/NanoBrain/Perception.cs b/Assets/NanoBrain/Perception.cs index 46ca2ab..f98077d 100644 --- a/Assets/NanoBrain/Perception.cs +++ b/Assets/NanoBrain/Perception.cs @@ -29,32 +29,32 @@ public class Perception : Nucleus { return null; } - public void SendPositions(Nucleus receivingNeuroid, int thingType = 0, float weight = 1.0f) { - Receiver receiver = new() { - thingType = thingType, - neuroid = receivingNeuroid - }; - positionReceivers.Add(receiver); - foreach (SensoryNeuroid neuroid in sensoryNeuroids) { - if (neuroid != null) { - neuroid.AddReceiver(receivingNeuroid); - receivingNeuroid.SetWeight(neuroid, weight); - } - } - } - public void SendVelocities(Nucleus receivingNeuroid, int thingType = 0, float weight = 1.0f) { - Receiver receiver = new() { - thingType = thingType, - neuroid = receivingNeuroid - }; - velocityReceivers.Add(receiver); - foreach (SensoryNeuroid neuroid in sensoryNeuroids) { - if (neuroid != null && neuroid.velocityNeuroid != null) { - neuroid.velocityNeuroid.AddReceiver(receivingNeuroid); - receivingNeuroid.SetWeight(neuroid, weight); - } - } - } + // public void SendPositions(Nucleus receivingNeuroid, int thingType = 0, float weight = 1.0f) { + // Receiver receiver = new() { + // thingType = thingType, + // neuroid = receivingNeuroid + // }; + // positionReceivers.Add(receiver); + // foreach (SensoryNeuroid neuroid in sensoryNeuroids) { + // if (neuroid != null) { + // neuroid.AddReceiver(receivingNeuroid); + // receivingNeuroid.SetWeight(neuroid, weight); + // } + // } + // } + // public void SendVelocities(Nucleus receivingNeuroid, int thingType = 0, float weight = 1.0f) { + // Receiver receiver = new() { + // thingType = thingType, + // neuroid = receivingNeuroid + // }; + // velocityReceivers.Add(receiver); + // foreach (SensoryNeuroid neuroid in sensoryNeuroids) { + // if (neuroid != null && neuroid.velocityNeuroid != null) { + // neuroid.velocityNeuroid.AddReceiver(receivingNeuroid); + // receivingNeuroid.SetWeight(neuroid, weight); + // } + // } + // } public void ProcessStimulus(int thingId, int thingType, Vector3 localPosition, string name = "Sensing") { int availableIx = -1; @@ -97,10 +97,10 @@ public class Perception : Nucleus { receiver.neuroid.GetInputFrom(neuroid); } } - foreach (Receiver receiver in velocityReceivers) { - if (receiver.thingType == 0 || receiver.thingType == thingType) - receiver.neuroid.GetInputFrom(neuroid.velocityNeuroid); - } + // foreach (Receiver receiver in velocityReceivers) { + // if (receiver.thingType == 0 || receiver.thingType == thingType) + // receiver.neuroid.GetInputFrom(neuroid.velocityNeuroid); + // } //neuroid.receptor.position = localPosition; neuroid.receptor.ProcessStimulus(333, localPosition); diff --git a/Assets/NanoBrain/Perceptoid.cs b/Assets/NanoBrain/Perceptoid.cs index 75fd6e2..54e9a36 100644 --- a/Assets/NanoBrain/Perceptoid.cs +++ b/Assets/NanoBrain/Perceptoid.cs @@ -6,7 +6,7 @@ public class Perceptoid : Neuroid { // A neuroid which has no neurons as input // But receives value from a receptor public Receptor receptor; - public VelocityNeuroid velocityNeuroid; + //public VelocityNeuroid velocityNeuroid; #region Serialization @@ -16,12 +16,8 @@ public class Perceptoid : Neuroid { public override void Rebuild(NanoBrainObj brain) { base.Rebuild(brain); - //this.receptor = new Receptor(this); - this.receptor = Perceptoid.GetReceptor(brain, thingType); - if (this.receptor == null) - this.receptor = new Receptor(this); - else - this.receptor.perceptei.Add(this); + this.receptor = Receptor.GetReceptor(brain, thingType); + this.receptor.perceptei.Add(this); } public override void Deserialize(Nucleus nucleus) { @@ -52,18 +48,18 @@ public class Perceptoid : Neuroid { #endregion Serialization - public Perceptoid(NanoBrainObj brain, string name) : base(name) { - this.brain = brain; - if (this.brain != null) { - this.brain.perceptei.Add(this); - } - else - Debug.LogError("No neuroid network"); + // public Perceptoid(NanoBrainObj brain, string name) : base(name) { + // this.brain = brain; + // if (this.brain != null) { + // this.brain.perceptei.Add(this); + // } + // else + // Debug.LogError("No neuroid network"); - this.nucleusType = nameof(Perceptoid); - this.name = name; - this.receptor = new Receptor(this); - } + // this.nucleusType = nameof(Perceptoid); + // this.name = name; + // this.receptor = new Receptor(this); + // } public Perceptoid(NanoBrainObj brain, int thingType, string name = "sensor") : base(name) { this.brain = brain; @@ -76,26 +72,25 @@ public class Perceptoid : Neuroid { this.nucleusType = nameof(Perceptoid); this.name = name; this.thingType = thingType; - this.receptor = new Receptor(this) { - thingType = thingType - }; - this.velocityNeuroid = new(brain, name + ": velocity"); - // The velocity neuroid received position data from this - this.AddReceiver(velocityNeuroid); + this.receptor = Receptor.GetReceptor(brain, thingType); + this.receptor.perceptei.Add(this); + // this.velocityNeuroid = new(brain, name + ": velocity"); + // // The velocity neuroid received position data from this + // this.AddReceiver(velocityNeuroid); } public void Replace(int thingType, string name = "sensor") { this.name = name; - this.thingType = thingType; + //this.thingType = thingType; this.receptor.thingType = thingType; this.receptor.localPosition = Spherical.zero; this.outputValue = Spherical.zero; this.receivers = new(); - this.AddReceiver(velocityNeuroid); + // this.AddReceiver(velocityNeuroid); - this.velocityNeuroid.Replace(name + ": velocity"); + // this.velocityNeuroid.Replace(name + ": velocity"); } public override void UpdateState() { @@ -119,7 +114,7 @@ public class Perceptoid : Neuroid { if (receiver.nucleus is Neuroid neuroid) neuroid.SetInput(this); //this.stale = 0; - this.Refresh(); + //this.Refresh(); } public void UpdateState(int thingId, Spherical receptorValue) { @@ -139,18 +134,23 @@ public class Perceptoid : Neuroid { // if (average && this.synapses.Count > 0) // result /= this.synapses.Count + 1; + float d = Spherical.Distance(result, this.outputValue); + if (d < 0.1f) { + //Debug.Log($"insignificant update: {d}"); + return; + } this.outputValue = result; foreach (Receiver receiver in this.receivers) if (receiver.nucleus is Neuroid neuroid) neuroid.SetInput(this); //this.stale = 0; - this.Refresh(); + //this.Refresh(); } public static Perceptoid GetPerception(NanoBrainObj brain, int thingType = 0) { foreach (Nucleus nucleus in brain.nuclei) { - if (nucleus is Perceptoid perceptoid && (thingType == 0 || perceptoid.thingType == thingType)) + if (nucleus is Perceptoid perceptoid && (thingType == 0 || perceptoid.receptor.thingType == thingType)) return perceptoid; } return null; @@ -159,7 +159,7 @@ public class Perceptoid : Neuroid { public static void ProcessStimulus(NanoBrainObj brain, int thingType, Vector3 localPosition) { Perceptoid selectedPerceptoid = null; foreach (Perceptoid nucleus in brain.perceptei) { - if (nucleus is Perceptoid perceptoid && (thingType == 0 || perceptoid.thingType == thingType)) + if (nucleus is Perceptoid perceptoid && (thingType == 0 || perceptoid.receptor.thingType == thingType)) if (selectedPerceptoid == null) { selectedPerceptoid = perceptoid; if (perceptoid.isSleeping) { @@ -176,11 +176,15 @@ public class Perceptoid : Neuroid { //selectedPerceptoid.receptor.position = localPosition; selectedPerceptoid.receptor.ProcessStimulus(888, localPosition); } - public static Receptor GetReceptor(NanoBrainObj brain, int thingType) { - foreach (Perceptoid perceptoid in brain.perceptei) { - if (thingType == 0 || perceptoid.thingType == thingType) - return perceptoid.receptor; - } - return null; - } + + // public static Receptor GetReceptor(NanoBrainObj brain, int thingType) { + // foreach (Perceptoid perceptoid in brain.perceptei) { + // if (perceptoid.receptor != null) { + // if (thingType == 0 || perceptoid.receptor.thingType == thingType) + // return perceptoid.receptor; + // } + // } + // Receptor receptor = new(thingType); + // return receptor; + // } } diff --git a/Assets/NanoBrain/Receptor.cs b/Assets/NanoBrain/Receptor.cs index 5f64972..18b8089 100644 --- a/Assets/NanoBrain/Receptor.cs +++ b/Assets/NanoBrain/Receptor.cs @@ -1,47 +1,92 @@ using System.Collections.Generic; -using System.Linq; using UnityEngine; using LinearAlgebra; public class Receptor { - - + /// + /// The list of perceptoid which can process stimuli from this receptor + /// public List perceptei = new(); - public int thingId; - public int thingType; + //public int thingId; + private int _thingType = 0; + public int thingType { + get { return _thingType; } + set { + _thingType = value; + foreach (Perceptoid perceptoid in perceptei) { + perceptoid.thingType = _thingType; + } + } + } public Spherical localPosition; + public float distanceResolution = 0.1f; + public float directionResolution = 5; - public Receptor(Perceptoid perceptoid) { - this.perceptei.Add(perceptoid); + public Receptor(NanoBrainObj brain, int thingType) { + this.thingType = thingType; + //this.perceptei.Add(perceptoid); + brain.receptors.Add(this); } + public static Receptor GetReceptor(NanoBrainObj brain, int thingType) { + foreach (Receptor receptor in brain.receptors) { + if (thingType == 0 || receptor.thingType == thingType) + return receptor; + } + Receptor newReceptor = new(brain, thingType); + return newReceptor; + } - public virtual void ProcessStimulus(int thingId, Vector3 localPosition) { - this.thingId = thingId; - this.localPosition = Spherical.FromVector3(localPosition); + public virtual void ProcessStimulus(int thingId, Vector3 newLocalPositionVector) { + Spherical newLocalPosition = Spherical.FromVector3(newLocalPositionVector); + + Spherical previousLocalPosition = this.localPosition; + this.localPosition = newLocalPosition; Perceptoid selectedPerceptoid = null; foreach (Perceptoid perceptoid in this.perceptei) { - if (perceptoid.thingId == this.thingId) { + if (perceptoid.thingId == thingId) { + // We found an existing perceptoid for this thing selectedPerceptoid = perceptoid; + // Do not look any further + + // This does not do a lot.... + float deltaDistance = newLocalPosition.distance - previousLocalPosition.distance; + // See if the change is significant + AngleFloat deltaDirection = Direction.UnsignedAngle(newLocalPosition.direction, previousLocalPosition.direction); + if (deltaDistance < this.distanceResolution && deltaDirection.inDegrees < directionResolution) { + // The difference is not significant we don't process this data. + this.localPosition = previousLocalPosition; + return; + } break; } - else if (perceptoid.isSleeping) + else if (perceptoid.isSleeping) { + // A sleeping perceptoid is not active and can therefore always be reused selectedPerceptoid = perceptoid; + // Look further because we could find a existing perceptoid for this thing + } + else if (selectedPerceptoid == null) { + // If we haven't found a perceptoid yet, just start by taking the first selectedPerceptoid = perceptoid; } + else if (selectedPerceptoid.isSleeping == false) { - if (perceptoid.receptor.localPosition.magnitude < selectedPerceptoid.receptor.localPosition.magnitude) + // If no existing or sleeping perceptoid is found, we look for the perceptoid + // we the furthest (least interesting) stimulus + if (perceptoid.receptor.localPosition.magnitude < selectedPerceptoid.receptor.localPosition.magnitude) { + Debug.Log($"{selectedPerceptoid.name} {selectedPerceptoid.receptor.localPosition.magnitude} {perceptoid.receptor.localPosition.magnitude} "); selectedPerceptoid = perceptoid; + } } } if (selectedPerceptoid == null) { Debug.Log("No perceptoid selected, stimulus is ignored"); return; } - //Debug.Log($"Stimulus {thingId} {selectedPerceptoid.thingId}"); - selectedPerceptoid.UpdateState(this.thingId, this.localPosition); + // Debug.Log($"Stimulus {thingType} {thingId} {selectedPerceptoid.name}"); + selectedPerceptoid.UpdateState(thingId, this.localPosition); } } \ No newline at end of file diff --git a/Assets/NanoBrain/SensoryNeuroid.cs b/Assets/NanoBrain/SensoryNeuroid.cs index 1c12129..ffc4e4a 100644 --- a/Assets/NanoBrain/SensoryNeuroid.cs +++ b/Assets/NanoBrain/SensoryNeuroid.cs @@ -37,16 +37,16 @@ public class SensoryNeuroid : Neuroid { // A neuroid which has no neurons as input // But receives value from a receptor public Receptor receptor; - public VelocityNeuroid velocityNeuroid; + //public VelocityNeuroid velocityNeuroid; public SensoryNeuroid(NanoBrainObj brain, int thingId, string name = "sensor") : base(brain, name) { this.name = name + ": position"; // this.receptor = new Receptor(this) { // thingType = thingId // }; - this.velocityNeuroid = new(brain, name + ": velocity"); - // The velocity neuroid received position data from this - this.AddReceiver(velocityNeuroid); + // this.velocityNeuroid = new(brain, name + ": velocity"); + // // The velocity neuroid received position data from this + // this.AddReceiver(velocityNeuroid); } public void Replace(int thingId, string name = "sensor") { @@ -57,11 +57,11 @@ public class SensoryNeuroid : Neuroid { this.outputValue = Spherical.zero; this.receivers = new(); - this.AddReceiver(velocityNeuroid); + // this.AddReceiver(velocityNeuroid); - // this.velocityNeuroid.name = name + ": velocity"; - // this.velocityNeuroid.receivers = new(); - this.velocityNeuroid.Replace(name + ": velocity"); + // // this.velocityNeuroid.name = name + ": velocity"; + // // this.velocityNeuroid.receivers = new(); + // this.velocityNeuroid.Replace(name + ": velocity"); } public override void UpdateState() { @@ -88,49 +88,49 @@ public class SensoryNeuroid : Neuroid { if (receiver.nucleus is Neuroid neuroid) neuroid.SetInput(this); //this.stale = 0; - this.Refresh(); + //this.Refresh(); } } -public class VelocityNeuroid : Neuroid { - // Would be best if this was received through a synapse via a loop.... - private Vector3 lastPosition = Vector3.zero; - private float lastValueTime = 0; +// public class VelocityNeuroid : Neuroid { +// // Would be best if this was received through a synapse via a loop.... +// private Vector3 lastPosition = Vector3.zero; +// private float lastValueTime = 0; - public VelocityNeuroid(NanoBrainObj net, string name = "velocity") : base(net, name) { - } +// public VelocityNeuroid(NanoBrainObj net, string name = "velocity") : base(net, name) { +// } - public void Replace(string name = "velocity") { - this.name = name; - this.receivers = new(); - this.lastPosition = Vector3.zero; - this.lastValueTime = 0; - } +// public void Replace(string name = "velocity") { +// this.name = name; +// this.receivers = new(); +// this.lastPosition = Vector3.zero; +// this.lastValueTime = 0; +// } - public override void UpdateState() { - // Assuming only one synapse for now.... - //Vector3 currentPosition = this.synapses.First().Key.outputValue; - Spherical currentPosition = this.synapses.First().nucleus.outputValue; - Vector3 currentPositionV3 = currentPosition.ToVector3(); - float currentValueTime = Time.time; +// public override void UpdateState() { +// // Assuming only one synapse for now.... +// //Vector3 currentPosition = this.synapses.First().Key.outputValue; +// Spherical currentPosition = this.synapses.First().nucleus.outputValue; +// Vector3 currentPositionV3 = currentPosition.ToVector3(); +// float currentValueTime = Time.time; - if (lastValueTime != 0) { - float deltaTime = currentValueTime - lastValueTime; - Vector3 translation = currentPositionV3 - lastPosition; - Vector3 velocity = translation / deltaTime; +// if (lastValueTime != 0) { +// float deltaTime = currentValueTime - lastValueTime; +// Vector3 translation = currentPositionV3 - lastPosition; +// Vector3 velocity = translation / deltaTime; - // No activation function... - this.outputValue = Spherical.FromVector3(velocity); - //this.stale = 0; - this.Refresh(); +// // No activation function... +// this.outputValue = Spherical.FromVector3(velocity); +// //this.stale = 0; +// //this.Refresh(); - foreach (Receiver receiver in receivers) { - if (receiver.nucleus is Neuroid neuroid) - neuroid.SetInput(this); - } - } +// foreach (Receiver receiver in receivers) { +// if (receiver.nucleus is Neuroid neuroid) +// neuroid.SetInput(this); +// } +// } - this.lastValueTime = currentValueTime; - this.lastPosition = currentPositionV3; - } -} \ No newline at end of file +// this.lastValueTime = currentValueTime; +// this.lastPosition = currentPositionV3; +// } +// } \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs index 0a694e0..5f65741 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs @@ -398,8 +398,9 @@ public class NanoBrainInspector : Editor { return; this.currentNucleus.name = EditorGUILayout.TextField(this.currentNucleus.name); - if (this.currentNucleus is Perceptoid currentPerceptoid) - currentPerceptoid.thingType = EditorGUILayout.IntField("Thing Type", currentPerceptoid.thingType); + if (this.currentNucleus is Perceptoid currentPerceptoid) { + currentPerceptoid.receptor.thingType = EditorGUILayout.IntField("Thing Type", currentPerceptoid.receptor.thingType); + } else if (this.currentNucleus is Neuroid neuroid) { EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Activation Curve", GUILayout.Width(150)); diff --git a/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs b/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs index 970a2ac..1a52db1 100644 --- a/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs +++ b/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs @@ -12,6 +12,7 @@ public class NanoBrainObj : ScriptableObject, ISerializationCallbackReceiver { public List nuclei = new(); public List perceptei = new(); + public List receptors = new(); // This is probably always the first element in the nuclei list... [System.NonSerialized] @@ -34,14 +35,14 @@ public class NanoBrainObj : ScriptableObject, ISerializationCallbackReceiver { foreach (Nucleus nucleus in nuclei) { //nucleus.stale++; nucleus.IncreaseAge(); - if (nucleus.isSleeping) - nucleus.outputValue = Spherical.zero; + // if (nucleus.isSleeping) + // nucleus.outputValue = Spherical.zero; } foreach (Perceptoid perception in perceptei) { //perception.stale++; perception.IncreaseAge(); - if (perception.isSleeping) - perception.outputValue = Spherical.zero; + // if (perception.isSleeping) + // perception.outputValue = Spherical.zero; } } @@ -84,6 +85,9 @@ public class NanoBrainObj : ScriptableObject, ISerializationCallbackReceiver { if (nucleus.brain == null) nucleus.brain = this; + if (nucleus.name == "Boid1") + Debug.Log(" Found boiid1"); + visitedNuclei.Add(nucleus); if (nucleus.synapses != null) { HashSet visitedSynapses = new(); diff --git a/Assets/Scenes/Boids/Boids.unity b/Assets/Scenes/Boids/Boids.unity index 9c0eb11..a2bc83e 100644 --- a/Assets/Scenes/Boids/Boids.unity +++ b/Assets/Scenes/Boids/Boids.unity @@ -680,7 +680,7 @@ AudioListener: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1633626499} - m_Enabled: 1 + m_Enabled: 0 --- !u!20 &1633626501 Camera: m_ObjectHideFlags: 0 diff --git a/Assets/Scenes/Boids/Scripts/Boid.cs b/Assets/Scenes/Boids/Scripts/Boid.cs index ac78915..ef7846d 100644 --- a/Assets/Scenes/Boids/Scripts/Boid.cs +++ b/Assets/Scenes/Boids/Scripts/Boid.cs @@ -27,9 +27,9 @@ public class Boid : MonoBehaviour { this.id = this.GetInstanceID(); nanoBrain = GetComponent(); - boundaryReceptor = Perceptoid.GetReceptor(nanoBrain.brain, BoundaryType); - boidReceptor = Perceptoid.GetReceptor(nanoBrain.brain, BoidType); - boidVelocityReceptor = Perceptoid.GetReceptor(nanoBrain.brain, BoidVelocityType); + boundaryReceptor = Receptor.GetReceptor(nanoBrain.brain, BoundaryType); + boidReceptor = Receptor.GetReceptor(nanoBrain.brain, BoidType); + boidVelocityReceptor = Receptor.GetReceptor(nanoBrain.brain, BoidVelocityType); sc = FindFirstObjectByType(); diff --git a/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs b/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs index 513f05e..de86097 100644 --- a/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs +++ b/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs @@ -1,3 +1,4 @@ +/* public class Roaming : Nucleus { public Neuroid avoidance; @@ -14,4 +15,5 @@ public class Roaming : Nucleus { public override void AddReceiver(Nucleus receiver) { output.AddReceiver(receiver); } -} \ No newline at end of file +} +*/ \ No newline at end of file diff --git a/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs b/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs index a269b01..a5d715d 100644 --- a/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs +++ b/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs @@ -1,37 +1,37 @@ -using UnityEngine; -using LinearAlgebra; +// using UnityEngine; +// using LinearAlgebra; -public class Swarming : Nucleus { - public Neuroid cohesion; - public Neuroid alignment; - public Neuroid avoidance; - public Neuroid boundary; +// public class Swarming : Nucleus { +// public Neuroid cohesion; +// public Neuroid alignment; +// public Neuroid avoidance; +// public Neuroid boundary; - public Neuroid output; +// public Neuroid output; - //public override Spherical outputValue { get => output.outputValue; set => output.outputValue = value; } +// //public override Spherical outputValue { get => output.outputValue; set => output.outputValue = value; } - public Swarming(NanoBrainObj brain, Perception perception, SwarmControl sc) : base("Swarming Nucleus") { - this.cohesion = new(brain, "Cohesion") { inverse = false }; - perception.SendPositions(this.cohesion, Boid.BoidType); +// public Swarming(NanoBrainObj brain, Perception perception, SwarmControl sc) : base("Swarming Nucleus") { +// this.cohesion = new(brain, "Cohesion") { inverse = false }; +// perception.SendPositions(this.cohesion, Boid.BoidType); - this.alignment = new(brain, "Alignment") { average = true }; - perception.SendVelocities(this.alignment, Boid.BoidType); +// this.alignment = new(brain, "Alignment") { average = true }; +// perception.SendVelocities(this.alignment, Boid.BoidType); - this.avoidance = new(brain, "Avoidance") { inverse = true }; - perception.SendPositions(this.avoidance); +// this.avoidance = new(brain, "Avoidance") { inverse = true }; +// perception.SendPositions(this.avoidance); - this.boundary = new(brain, "Boundary"); - perception.SendPositions(this.boundary, Boid.BoundaryType); +// this.boundary = new(brain, "Boundary"); +// perception.SendPositions(this.boundary, Boid.BoundaryType); - this.output = new(brain, "Swarming"); - this.output.GetInputFrom(alignment, sc.alignmentForce); - this.output.GetInputFrom(cohesion, sc.cohesionForce); - this.output.GetInputFrom(avoidance, -sc.avoidanceForce); - this.output.GetInputFrom(boundary, -sc.avoidanceForce); - } +// this.output = new(brain, "Swarming"); +// this.output.GetInputFrom(alignment, sc.alignmentForce); +// this.output.GetInputFrom(cohesion, sc.cohesionForce); +// this.output.GetInputFrom(avoidance, -sc.avoidanceForce); +// this.output.GetInputFrom(boundary, -sc.avoidanceForce); +// } - public override void AddReceiver(Nucleus receiver) { - this.output.AddReceiver(receiver); - } -} \ No newline at end of file +// public override void AddReceiver(Nucleus receiver) { +// this.output.AddReceiver(receiver); +// } +// } \ No newline at end of file diff --git a/Assets/Scenes/Boids/SwarmingBrain.asset b/Assets/Scenes/Boids/SwarmingBrain.asset index d47131b..08a62b5 100644 --- a/Assets/Scenes/Boids/SwarmingBrain.asset +++ b/Assets/Scenes/Boids/SwarmingBrain.asset @@ -1250,7 +1250,6 @@ MonoBehaviour: curveMax: 1 receivers: [] nucleusType: - isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -1296,7 +1295,6 @@ MonoBehaviour: receivers: - nucleusId: -1707533328 nucleusType: - isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -1329,7 +1327,7 @@ MonoBehaviour: - id: 1938577052 _name: Cohesion synapses: - - nucleusId: 1302452224 + - nucleusId: -1659429232 weight: 1 curvePreset: 0 curve: @@ -1339,7 +1337,7 @@ MonoBehaviour: m_PostInfinity: 2 m_RotationOrder: 4 curveMax: 1 - - nucleusId: 10881140 + - nucleusId: 839544896 weight: 1 curvePreset: 0 curve: @@ -1349,7 +1347,7 @@ MonoBehaviour: m_PostInfinity: 2 m_RotationOrder: 4 curveMax: 1 - - nucleusId: 2020437392 + - nucleusId: -348340288 weight: 1 curvePreset: 0 curve: @@ -1359,7 +1357,7 @@ MonoBehaviour: m_PostInfinity: 2 m_RotationOrder: 4 curveMax: 1 - - nucleusId: -1530763258 + - nucleusId: -1095934288 weight: 1 curvePreset: 0 curve: @@ -1369,7 +1367,7 @@ MonoBehaviour: m_PostInfinity: 2 m_RotationOrder: 4 curveMax: 1 - - nucleusId: 1790226608 + - nucleusId: -1413006832 weight: 1 curvePreset: 0 curve: @@ -1379,7 +1377,7 @@ MonoBehaviour: m_PostInfinity: 2 m_RotationOrder: 4 curveMax: 1 - - nucleusId: 626548796 + - nucleusId: -61245040 weight: 1 curvePreset: 0 curve: @@ -1392,7 +1390,6 @@ MonoBehaviour: receivers: - nucleusId: -1707533328 nucleusType: - isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -1425,7 +1422,7 @@ MonoBehaviour: - id: 1641120128 _name: Separation synapses: - - nucleusId: 1302452224 + - nucleusId: -1659429232 weight: 1 curvePreset: 0 curve: @@ -1435,7 +1432,7 @@ MonoBehaviour: m_PostInfinity: 2 m_RotationOrder: 4 curveMax: 1 - - nucleusId: 10881140 + - nucleusId: 839544896 weight: 1 curvePreset: 0 curve: @@ -1445,7 +1442,7 @@ MonoBehaviour: m_PostInfinity: 2 m_RotationOrder: 4 curveMax: 1 - - nucleusId: 2020437392 + - nucleusId: -348340288 weight: 1 curvePreset: 0 curve: @@ -1455,7 +1452,7 @@ MonoBehaviour: m_PostInfinity: 2 m_RotationOrder: 4 curveMax: 1 - - nucleusId: -1530763258 + - nucleusId: -1095934288 weight: 1 curvePreset: 0 curve: @@ -1465,7 +1462,7 @@ MonoBehaviour: m_PostInfinity: 2 m_RotationOrder: 4 curveMax: 1 - - nucleusId: 1790226608 + - nucleusId: -1413006832 weight: 1 curvePreset: 0 curve: @@ -1475,7 +1472,7 @@ MonoBehaviour: m_PostInfinity: 2 m_RotationOrder: 4 curveMax: 1 - - nucleusId: 626548796 + - nucleusId: -61245040 weight: 1 curvePreset: 0 curve: @@ -1488,7 +1485,6 @@ MonoBehaviour: receivers: - nucleusId: -1707533328 nucleusType: - isSleeping: 0 _curvePreset: 2 curve: serializedVersion: 2 @@ -1791,7 +1787,7 @@ MonoBehaviour: - id: -1857835930 _name: Alignment synapses: - - nucleusId: 1921239042 + - nucleusId: -1659687600 weight: 1 curvePreset: 0 curve: @@ -1801,7 +1797,7 @@ MonoBehaviour: m_PostInfinity: 2 m_RotationOrder: 4 curveMax: 1 - - nucleusId: 1686464114 + - nucleusId: 1322333072 weight: 1 curvePreset: 0 curve: @@ -1811,7 +1807,7 @@ MonoBehaviour: m_PostInfinity: 2 m_RotationOrder: 4 curveMax: 1 - - nucleusId: -1926972526 + - nucleusId: -1563920864 weight: 1 curvePreset: 0 curve: @@ -1821,7 +1817,7 @@ MonoBehaviour: m_PostInfinity: 2 m_RotationOrder: 4 curveMax: 1 - - nucleusId: 483038322 + - nucleusId: 182328688 weight: 1 curvePreset: 0 curve: @@ -1831,7 +1827,7 @@ MonoBehaviour: m_PostInfinity: 2 m_RotationOrder: 4 curveMax: 1 - - nucleusId: 890767934 + - nucleusId: -1666561744 weight: 1 curvePreset: 0 curve: @@ -1841,7 +1837,7 @@ MonoBehaviour: m_PostInfinity: 2 m_RotationOrder: 4 curveMax: 1 - - nucleusId: -324208238 + - nucleusId: -1884196224 weight: 1 curvePreset: 0 curve: @@ -1854,7 +1850,6 @@ MonoBehaviour: receivers: - nucleusId: -1707533328 nucleusType: - isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -1884,438 +1879,6 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 - - id: 1164040656 - _name: Boid3 Velocity - synapses: - - nucleusId: 2020437392 - weight: 1 - curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - receivers: [] - nucleusType: - isSleeping: 0 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 1 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1 - value: 1 - inSlope: 1 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - - id: -176251552 - _name: Boid2 Velocity - synapses: - - nucleusId: 10881140 - weight: 1 - curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - receivers: [] - nucleusType: - isSleeping: 0 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 1 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1 - value: 1 - inSlope: 1 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - - id: -1679360144 - _name: Boid1 Velocity - synapses: - - nucleusId: 1302452224 - weight: 1 - curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - receivers: [] - nucleusType: - isSleeping: 0 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 1 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1 - value: 1 - inSlope: 1 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - - id: -1513426512 - _name: Boid4 Velocity - synapses: - - nucleusId: -1530763258 - weight: 1 - curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - receivers: [] - nucleusType: - isSleeping: 0 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 1 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1 - value: 1 - inSlope: 1 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - - id: 1708725840 - _name: Boid5 Velocity - synapses: - - nucleusId: 1790226608 - weight: 1 - curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - receivers: [] - nucleusType: - isSleeping: 0 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 1 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1 - value: 1 - inSlope: 1 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - - id: -1645785904 - _name: Boid6 Velocity - synapses: - - nucleusId: 626548796 - weight: 1 - curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - receivers: [] - nucleusType: - isSleeping: 0 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 1 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1 - value: 1 - inSlope: 1 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - - id: -1621097280 - _name: 'New Perceptoid: velocity' - synapses: - - nucleusId: 1921239042 - weight: 1 - curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - receivers: [] - nucleusType: - isSleeping: 0 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - - id: -966090960 - _name: 'New Perceptoid: velocity' - synapses: - - nucleusId: 1686464114 - weight: 1 - curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - receivers: [] - nucleusType: - isSleeping: 0 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - - id: 1426014432 - _name: 'New Perceptoid: velocity' - synapses: - - nucleusId: -1926972526 - weight: 1 - curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - receivers: [] - nucleusType: - isSleeping: 0 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - - id: -610217840 - _name: 'New Perceptoid: velocity' - synapses: - - nucleusId: 483038322 - weight: 1 - curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - receivers: [] - nucleusType: - isSleeping: 0 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - - id: -481628544 - _name: 'New Perceptoid: velocity' - synapses: - - nucleusId: 890767934 - weight: 1 - curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - receivers: [] - nucleusType: - isSleeping: 0 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - - id: 1464656048 - _name: 'New Perceptoid: velocity' - synapses: - - nucleusId: -324208238 - weight: 1 - curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - receivers: [] - nucleusType: - isSleeping: 0 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 perceptei: - id: 407735232 _name: Boundary @@ -2323,7 +1886,6 @@ MonoBehaviour: receivers: - nucleusId: -112538112 nucleusType: Perceptoid - isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -2337,146 +1899,11 @@ MonoBehaviour: exponent: 1 thingType: 1 thingId: 0 - - id: 2020437392 - _name: Boid3 - synapses: [] - receivers: - - nucleusId: 1164040656 - - nucleusId: 1938577052 - - nucleusId: 1641120128 - nucleusType: Perceptoid - isSleeping: 0 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - thingType: 2 - thingId: 0 - - id: 10881140 - _name: Boid2 - synapses: [] - receivers: - - nucleusId: -176251552 - - nucleusId: 1938577052 - - nucleusId: 1641120128 - nucleusType: Perceptoid - isSleeping: 0 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - thingType: 2 - thingId: 0 - - id: 1302452224 - _name: Boid1 - synapses: [] - receivers: - - nucleusId: -1679360144 - - nucleusId: 1938577052 - - nucleusId: 1641120128 - nucleusType: Perceptoid - isSleeping: 0 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - thingType: 2 - thingId: 0 - - id: -1530763258 - _name: Boid4 - synapses: [] - receivers: - - nucleusId: -1513426512 - - nucleusId: 1938577052 - - nucleusId: 1641120128 - nucleusType: Perceptoid - isSleeping: 0 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - thingType: 2 - thingId: 0 - - id: 1790226608 - _name: Boid5 - synapses: [] - receivers: - - nucleusId: 1708725840 - - nucleusId: 1938577052 - - nucleusId: 1641120128 - nucleusType: Perceptoid - isSleeping: 0 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - thingType: 2 - thingId: 0 - - id: 626548796 - _name: Boid6 - synapses: [] - receivers: - - nucleusId: -1645785904 - - nucleusId: 1938577052 - - nucleusId: 1641120128 - nucleusType: Perceptoid - isSleeping: 0 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - thingType: 2 - thingId: 0 - id: 1921239042 _name: Boid1Velocity synapses: [] - receivers: - - nucleusId: -1621097280 - - nucleusId: -1857835930 + receivers: [] nucleusType: Perceptoid - isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -2493,11 +1920,8 @@ MonoBehaviour: - id: 1686464114 _name: Boid2Velocity synapses: [] - receivers: - - nucleusId: -966090960 - - nucleusId: -1857835930 + receivers: [] nucleusType: Perceptoid - isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -2514,11 +1938,8 @@ MonoBehaviour: - id: -1926972526 _name: Boid3Velocity synapses: [] - receivers: - - nucleusId: 1426014432 - - nucleusId: -1857835930 + receivers: [] nucleusType: Perceptoid - isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -2535,11 +1956,8 @@ MonoBehaviour: - id: 483038322 _name: Boid4Velocity synapses: [] - receivers: - - nucleusId: -610217840 - - nucleusId: -1857835930 + receivers: [] nucleusType: Perceptoid - isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -2556,11 +1974,8 @@ MonoBehaviour: - id: 890767934 _name: Boid5Velocity synapses: [] - receivers: - - nucleusId: -481628544 - - nucleusId: -1857835930 + receivers: [] nucleusType: Perceptoid - isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -2577,11 +1992,8 @@ MonoBehaviour: - id: -324208238 _name: Boid6Velocity synapses: [] - receivers: - - nucleusId: 1464656048 - - nucleusId: -1857835930 + receivers: [] nucleusType: Perceptoid - isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -2595,4 +2007,238 @@ MonoBehaviour: exponent: 1 thingType: 3 thingId: 0 + - id: -1659429232 + _name: BoidA + synapses: [] + receivers: + - nucleusId: 1938577052 + - nucleusId: 1641120128 + nucleusType: Perceptoid + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + thingType: 0 + thingId: 0 + - id: 839544896 + _name: BoidB + synapses: [] + receivers: + - nucleusId: 1938577052 + - nucleusId: 1641120128 + nucleusType: Perceptoid + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + thingType: 0 + thingId: 0 + - id: -348340288 + _name: BoidC + synapses: [] + receivers: + - nucleusId: 1641120128 + - nucleusId: 1938577052 + nucleusType: Perceptoid + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + thingType: 0 + thingId: 0 + - id: -1095934288 + _name: BoidD + synapses: [] + receivers: + - nucleusId: 1938577052 + - nucleusId: 1641120128 + nucleusType: Perceptoid + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + thingType: 0 + thingId: 0 + - id: -1413006832 + _name: BoidE + synapses: [] + receivers: + - nucleusId: 1641120128 + - nucleusId: 1938577052 + nucleusType: Perceptoid + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + thingType: 0 + thingId: 0 + - id: -61245040 + _name: BoidF + synapses: [] + receivers: + - nucleusId: 1938577052 + - nucleusId: 1641120128 + nucleusType: Perceptoid + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + thingType: 0 + thingId: 0 + - id: -1659687600 + _name: BoidA Velocity + synapses: [] + receivers: + - nucleusId: -1857835930 + nucleusType: Perceptoid + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + thingType: 0 + thingId: 0 + - id: 1322333072 + _name: BoidB Velocity + synapses: [] + receivers: + - nucleusId: -1857835930 + nucleusType: Perceptoid + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + thingType: 0 + thingId: 0 + - id: -1563920864 + _name: BoidC Velocity + synapses: [] + receivers: + - nucleusId: -1857835930 + nucleusType: Perceptoid + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + thingType: 0 + thingId: 0 + - id: 182328688 + _name: BoidD Velocity + synapses: [] + receivers: + - nucleusId: -1857835930 + nucleusType: Perceptoid + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + thingType: 0 + thingId: 0 + - id: -1666561744 + _name: BoidE Velocity + synapses: [] + receivers: + - nucleusId: -1857835930 + nucleusType: Perceptoid + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + thingType: 0 + thingId: 0 + - id: -1884196224 + _name: BoidF Velocity + synapses: [] + receivers: + - nucleusId: -1857835930 + nucleusType: Perceptoid + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + thingType: 0 + thingId: 0 rootId: -1707533328 From a22e4b149a4a0d6b019800375447993544a4c134 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Tue, 6 Jan 2026 15:44:31 +0100 Subject: [PATCH 043/179] Cleanup --- Assembly-CSharp-Editor.csproj | 1 - Assembly-CSharp.csproj | 6 - Assets/NanoBrain/Editor/NanoBrain_Editor.cs | 272 ------------------ .../NanoBrain/Editor/NanoBrain_Editor.cs.meta | 2 - Assets/NanoBrain/Editor/NeuroidWindow.cs | 16 +- Assets/NanoBrain/NanoBrain.cs | 22 -- Assets/NanoBrain/NanoBrain.cs.meta | 2 - Assets/NanoBrain/Neuroid.cs | 4 +- Assets/NanoBrain/NeuroidBehaviour.cs | 14 - Assets/NanoBrain/NeuroidBehaviour.cs.meta | 2 - Assets/NanoBrain/Perception.cs | 110 ------- Assets/NanoBrain/Perception.cs.meta | 2 - Assets/NanoBrain/Perceptoid.cs | 92 +----- Assets/NanoBrain/Receptor.cs | 20 +- Assets/NanoBrain/SensoryNeuroid.cs | 136 --------- Assets/NanoBrain/SensoryNeuroid.cs.meta | 2 - .../VisualEditor/Editor/NanoBrainEditor.cs | 16 +- .../VisualEditor/Editor/NanoBrainInspector.cs | 51 ++-- .../NanoBrain/VisualEditor/NeuroidObject.cs | 0 .../VisualEditor/NeuroidObject.cs.meta | 2 - .../NanoBrain/VisualEditor/NucleusObject.cs | 28 -- .../VisualEditor/NucleusObject.cs.meta | 2 - 22 files changed, 54 insertions(+), 748 deletions(-) delete mode 100644 Assets/NanoBrain/Editor/NanoBrain_Editor.cs delete mode 100644 Assets/NanoBrain/Editor/NanoBrain_Editor.cs.meta delete mode 100644 Assets/NanoBrain/NanoBrain.cs delete mode 100644 Assets/NanoBrain/NanoBrain.cs.meta delete mode 100644 Assets/NanoBrain/NeuroidBehaviour.cs delete mode 100644 Assets/NanoBrain/NeuroidBehaviour.cs.meta delete mode 100644 Assets/NanoBrain/Perception.cs delete mode 100644 Assets/NanoBrain/Perception.cs.meta delete mode 100644 Assets/NanoBrain/SensoryNeuroid.cs delete mode 100644 Assets/NanoBrain/SensoryNeuroid.cs.meta delete mode 100644 Assets/NanoBrain/VisualEditor/NeuroidObject.cs delete mode 100644 Assets/NanoBrain/VisualEditor/NeuroidObject.cs.meta delete mode 100644 Assets/NanoBrain/VisualEditor/NucleusObject.cs delete mode 100644 Assets/NanoBrain/VisualEditor/NucleusObject.cs.meta diff --git a/Assembly-CSharp-Editor.csproj b/Assembly-CSharp-Editor.csproj index 010371d..369d5d7 100644 --- a/Assembly-CSharp-Editor.csproj +++ b/Assembly-CSharp-Editor.csproj @@ -51,7 +51,6 @@ - diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index 2dfb31c..7e83f6b 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -58,23 +58,19 @@ - - - - @@ -83,11 +79,9 @@ - - diff --git a/Assets/NanoBrain/Editor/NanoBrain_Editor.cs b/Assets/NanoBrain/Editor/NanoBrain_Editor.cs deleted file mode 100644 index eb59d54..0000000 --- a/Assets/NanoBrain/Editor/NanoBrain_Editor.cs +++ /dev/null @@ -1,272 +0,0 @@ -using System.Collections.Generic; -using UnityEngine; -using UnityEditor; - -[CustomEditor(typeof(NanoBrain))] -public class NanoBrain_Editor : Editor { - private Nucleus currentNucleus; - private List layers = new(); - private Dictionary neuroidPositions = new(); - - protected bool breakOnWake = false; - - #region Start - - private void OnEnable() { - // NanoBrain brain = target as NanoBrain; - // if (brain == null) - // return; - - // if (brain.rootNucleus == null) { - // brain.rootNucleus = CreateInstance(); - // EditorUtility.SetDirty(brain.rootNucleus); - // } - - SelectNeuron(); - } - - private void SelectNeuron() { - // GameObject selectedObject = ((NanoBrain)target).gameObject; - // if (!selectedObject.TryGetComponent(out Boid boid)) - // return; - - // Nucleus neuroid = boid.totalForce; - // this.currentNucleus = neuroid; - - // BuildLayers(); - // Debug.Log($"Layercount = {this.layers.Count}"); - } - - #endregion Start - - #region Update - - public override void OnInspectorGUI() { - if (this.currentNucleus == null) - return; - - breakOnWake = EditorGUILayout.Toggle("Break on wake", breakOnWake); - if (breakOnWake && currentNucleus is Neuroid currentNeuroid) { - if (!currentNeuroid.isSleeping) - Debug.Break(); - } - - DrawGraph(); - - EditorGUILayout.TextField("Name", currentNucleus.name); - EditorGUILayout.Vector3Field("Output Value", currentNucleus.outputValue.ToVector3()); - if (currentNucleus.synapses.Count > 0) { - EditorGUI.indentLevel++; - //foreach ((Nucleus nucleus, float weight) in currentNucleus.synapses) { - foreach (Synapse synapse in currentNucleus.synapses) { - Nucleus nucleus = synapse.nucleus; - float weight = synapse.weight; - - EditorGUI.BeginDisabledGroup(nucleus.isSleeping); - - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.Vector3Field(nucleus.name, nucleus.outputValue.ToVector3()); - EditorGUILayout.FloatField(weight, GUILayout.Width(50)); - EditorGUILayout.EndHorizontal(); - - EditorGUI.EndDisabledGroup(); - - } - EditorGUI.indentLevel--; - } - DrawDefaultInspector(); - } - - private void BuildLayers() { - // A temporary list to track what's been added to layers - this.layers = new(); - int layerIx = 0; - - Nucleus selectedNucleus = this.currentNucleus; - if (selectedNucleus == null) - return; - NeuroidLayer currentLayer = new() { ix = layerIx }; - - //foreach (Neuroid outputNeuroid in selectedNucleus.receivers) { - foreach (Receiver receiver in selectedNucleus.receivers) { - Nucleus outputNeuroid = receiver.nucleus; - if (outputNeuroid != null) { - AddToLayer(currentLayer, outputNeuroid); - // Debug.Log($"layer {layerIx} nucleus {outputNeuroid.name}"); - } - } - if (currentLayer.neuroids.Count > 0) { - this.layers.Add(currentLayer); - layerIx++; - currentLayer = new() { ix = layerIx }; - } - - AddToLayer(currentLayer, selectedNucleus); - this.layers.Add(currentLayer); - // Debug.Log($"layer {layerIx} nucleus {selectedNucleus.name}"); - - layerIx++; - currentLayer = new() { ix = layerIx }; - - //foreach (Nucleus input in selectedNucleus.synapses.Keys) { - foreach (Synapse synapse in selectedNucleus.synapses) { - Nucleus input = synapse.nucleus; - AddToLayer(currentLayer, input); - // Debug.Log($"layer {layerIx} nucleus {input.name}"); - } - if (currentLayer.neuroids.Count > 0) { - this.layers.Add(currentLayer); - } - } - - private void AddToLayer(NeuroidLayer layer, Nucleus nucleus) { - layer.neuroids.Add(nucleus); - nucleus.layerIx = layer.ix; - // Store its position - Vector2Int neuroidPosition = new(layer.ix, layer.neuroids.Count - 1); - neuroidPositions[nucleus] = neuroidPosition; - - } - - private void DrawGraph() { - if (currentNucleus == null) - return; - Rect outer = EditorGUILayout.GetControlRect(false, 420); - GUI.BeginGroup(outer); - foreach (NeuroidLayer layer in layers) - DrawLayer(layer); - GUI.EndGroup(); - } - - private void DrawLayer(NeuroidLayer layer) { - int nodeCount = layer.neuroids.Count; - float maxValue = 0; - foreach (Nucleus nucleus in layer.neuroids) { - if (nucleus is Neuroid neuroid) { - float value = neuroid.outputValue.magnitude; - if (value > maxValue) - maxValue = value; - } - } - float spacing = 400f / nodeCount; - float margin = 10 + spacing / 2; - foreach (Nucleus layerNucleus in layer.neuroids) { - if (layerNucleus is Neuroid layerNeuroid) { - Vector2Int layerNeuroidPos = this.neuroidPositions[layerNeuroid]; - Vector3 parentPos = new(100 + layerNeuroidPos.x * 100, margin + layerNeuroidPos.y * spacing, 0.1f); - - //int i = 0; - float inputSpacing = 400f / layerNeuroid.synapses.Count; - float inputMargin = 10 + inputSpacing / 2; - // int minStale = 10000; - //foreach ((Nucleus nucleus, float weight) in layerNeuroid.synapses) { - foreach (Synapse synapse in layerNeuroid.synapses) { - Nucleus nucleus = synapse.nucleus; - float weight = synapse.weight; - if (this.neuroidPositions.ContainsKey(nucleus)) { - Vector2Int inputNeuroidPos = this.neuroidPositions[nucleus]; - if (inputNeuroidPos.x == layerNeuroidPos.x + 1) { - Vector3 pos = new(100 + inputNeuroidPos.x * 100, inputMargin + inputNeuroidPos.y * inputSpacing, 0.0f); - - float brightness = weight / 10.0f; - Handles.color = new Color(brightness, brightness, brightness); - Handles.DrawLine(parentPos, pos); - } - } - // if (nucleus is Neuroid neuroid && neuroid.stale < minStale) - // minStale = neuroid.stale; - } - - // if (layerNeuroid.synapses.Count > 0 && minStale > 2 && layerNeuroid.stale < 3) - // Debug.LogWarning($"Strange {minStale} is big duing update"); - - - float size = 20; - if (layerNeuroid.isSleeping) - Handles.color = Color.darkRed; - else { - float brightness = layerNeuroid.outputValue.magnitude / maxValue; - Handles.color = new Color(brightness, brightness, brightness); - } - Handles.DrawSolidDisc(parentPos, Vector3.forward, size); - Vector3 labelPos = parentPos - Vector3.down * (size + 0.2f); // below disc along up axis - GUIStyle style = new GUIStyle(EditorStyles.label) { - alignment = TextAnchor.UpperCenter, - normal = { textColor = Color.white }, - fontStyle = FontStyle.Bold - }; - Handles.Label(labelPos, layerNeuroid.name, style); - - Rect neuronRect = new(parentPos.x - size, parentPos.y - size, size * 2, size * 2); - int id = GUIUtility.GetControlID(FocusType.Passive); - Event e = Event.current; - EventType et = e.GetTypeForControl(id); - if (e != null && neuronRect.Contains(e.mousePosition)) { - // Process Hover - HandleMouseHover(layerNeuroid, neuronRect); - // Process click - if (et == EventType.MouseDown && e.button == 0) { - // Consume the event so the scene doesn't also handle it - e.Use(); - HandleDiscClicked(layerNeuroid); - } - } - //i++; - } - } - } - - private void HandleMouseHover(Neuroid neuroid, Rect rect) { - GUIContent tooltip; - if (neuroid is SensoryNeuroid sensoryNeuroid) { - tooltip = new( - $"{sensoryNeuroid.name}" + - $"\nThing {sensoryNeuroid.receptor.thingType}" + - $"\nValue: {neuroid.outputValue}"); - } - else { - tooltip = new( - $"{neuroid.name}" + - $"\nsynapse count {neuroid.synapses.Count}" + - $"\nValue: {neuroid.outputValue}"); - } - - Vector2 mousePosition = Event.current.mousePosition; - - // Display tooltip with some offset - Vector2 tooltipSize = GUI.skin.box.CalcSize(tooltip); - Rect tooltipRect = new Rect(mousePosition.x + 10, mousePosition.y + 10, tooltipSize.x, tooltipSize.y); - - GUI.Box(tooltipRect, tooltip); - } - - private void HandleDiscClicked(Nucleus nucleus) { - this.currentNucleus = nucleus; - BuildLayers(); - } - - protected virtual void OnSceneGUI() { - NanoBrain brain = target as NanoBrain; - if (brain == null) - return; - - Vector3 position = brain.transform.position; - float radius = 1; - - - Handles.DrawWireDisc(position, Vector3.up, radius); // horizontal circle - Handles.DrawWireDisc(position, Vector3.right, radius); // X-plane - Handles.DrawWireDisc(position, Vector3.forward, radius); // Z-plane - - - // Debug.DrawRay(brain.transform.position, Vector3.forward, Color.magenta); - // Handles.color = Color.green; - // Handles.DrawLine(brain.transform.position, brain.transform.position + Vector3.up); - Handles.color = Color.yellow; - Vector3 worldForce = brain.transform.TransformDirection(this.currentNucleus.outputValue.ToVector3()); - //Debug.DrawRay(position, worldForce * 10, Color.yellow); - Handles.DrawLine(position, position + worldForce * 10); - } - - #endregion Update -} diff --git a/Assets/NanoBrain/Editor/NanoBrain_Editor.cs.meta b/Assets/NanoBrain/Editor/NanoBrain_Editor.cs.meta deleted file mode 100644 index ebb08bb..0000000 --- a/Assets/NanoBrain/Editor/NanoBrain_Editor.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 2299b68d073cc5c31915f591deb79ddc \ No newline at end of file diff --git a/Assets/NanoBrain/Editor/NeuroidWindow.cs b/Assets/NanoBrain/Editor/NeuroidWindow.cs index 354dd4e..72494b8 100644 --- a/Assets/NanoBrain/Editor/NeuroidWindow.cs +++ b/Assets/NanoBrain/Editor/NeuroidWindow.cs @@ -241,18 +241,18 @@ public class GraphEditorWindow : EditorWindow { private void HandleMouseHover(Neuroid neuroid, Rect rect) { GUIContent tooltip; - if (neuroid is SensoryNeuroid sensoryNeuroid) { - tooltip = new( - $"{sensoryNeuroid.name}" + - $"\nThing {sensoryNeuroid.receptor.thingType}" + - $"\nValue: {neuroid.outputValue}"); - } - else { + // if (neuroid is SensoryNeuroid sensoryNeuroid) { + // tooltip = new( + // $"{sensoryNeuroid.name}" + + // $"\nThing {sensoryNeuroid.receptor.thingType}" + + // $"\nValue: {neuroid.outputValue}"); + // } + // else { tooltip = new( $"{neuroid.name}" + $"\nsynapse count {neuroid.synapses.Count}" + $"\nValue: {neuroid.outputValue}"); - } + // } Vector2 mousePosition = Event.current.mousePosition; diff --git a/Assets/NanoBrain/NanoBrain.cs b/Assets/NanoBrain/NanoBrain.cs deleted file mode 100644 index 9fca89a..0000000 --- a/Assets/NanoBrain/NanoBrain.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Collections.Generic; -using UnityEngine; - -public class NanoBrain : MonoBehaviour { - -// public NucleusObj rootNucleus; - - // public List neuroids = new(); - - // public Neuroid AddNeuron(string name) { - // Neuroid neuroid = new(this, name); - // return neuroid; - // } - - // public void UpdateNeurons() { - // foreach (Neuroid neuroid in neuroids) { - // neuroid.stale++; - // if (neuroid.isSleeping) - // neuroid.outputValue = Vector3.zero; - // } - // } -} diff --git a/Assets/NanoBrain/NanoBrain.cs.meta b/Assets/NanoBrain/NanoBrain.cs.meta deleted file mode 100644 index 078dc8f..0000000 --- a/Assets/NanoBrain/NanoBrain.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 74e1478743ac3bc078cbe8501c287e98 \ No newline at end of file diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index 287c23b..6e192ec 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -99,9 +99,7 @@ public class Neuroid : Nucleus { return; } - this.outputValue = result; //Spherical.FromVector3(resultVector); - //this.stale = 0; - //this.Refresh(); + this.outputValue = result; foreach (Receiver receiver in this.receivers) { if (receiver.nucleus is Neuroid neuroid) diff --git a/Assets/NanoBrain/NeuroidBehaviour.cs b/Assets/NanoBrain/NeuroidBehaviour.cs deleted file mode 100644 index 411f2a8..0000000 --- a/Assets/NanoBrain/NeuroidBehaviour.cs +++ /dev/null @@ -1,14 +0,0 @@ -using UnityEngine; - -public class NeuroidBehaviour : MonoBehaviour -{ - public Neuroid neuroid; - public GameObject thing; - - public void Start() { - Debug.Log("Neuroid start"); - } - public void Update() { - Debug.Log("Neuroid update"); - } -} diff --git a/Assets/NanoBrain/NeuroidBehaviour.cs.meta b/Assets/NanoBrain/NeuroidBehaviour.cs.meta deleted file mode 100644 index a6a62af..0000000 --- a/Assets/NanoBrain/NeuroidBehaviour.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: dded3a10fb4fd894383b44483dd47382 \ No newline at end of file diff --git a/Assets/NanoBrain/Perception.cs b/Assets/NanoBrain/Perception.cs deleted file mode 100644 index f98077d..0000000 --- a/Assets/NanoBrain/Perception.cs +++ /dev/null @@ -1,110 +0,0 @@ -using System.Collections.Generic; -using UnityEngine; - -[System.Serializable] -public class Perception : Nucleus { - public SensoryNeuroid[] sensoryNeuroids = new SensoryNeuroid[7]; - - [System.Serializable] - public class Receiver { - public int thingType = 0; - public Nucleus neuroid; - } - - //public HashSet positionReceivers { get; protected set; } - public List positionReceivers; - //public HashSet velocityReceivers { get; protected set; } - public List velocityReceivers; - - public Perception(NanoBrainObj brain) : base("Perception") { - this.positionReceivers = new(); - this.velocityReceivers = new(); - } - - public Perceptoid GetPerception(int thingType = 0) { - foreach (Nucleus nucleus in this.brain.nuclei) { - if (nucleus is Perceptoid perceptoid && (thingType == 0 || perceptoid.receptor.thingType == thingType)) - return perceptoid; - } - return null; - } - - // public void SendPositions(Nucleus receivingNeuroid, int thingType = 0, float weight = 1.0f) { - // Receiver receiver = new() { - // thingType = thingType, - // neuroid = receivingNeuroid - // }; - // positionReceivers.Add(receiver); - // foreach (SensoryNeuroid neuroid in sensoryNeuroids) { - // if (neuroid != null) { - // neuroid.AddReceiver(receivingNeuroid); - // receivingNeuroid.SetWeight(neuroid, weight); - // } - // } - // } - // public void SendVelocities(Nucleus receivingNeuroid, int thingType = 0, float weight = 1.0f) { - // Receiver receiver = new() { - // thingType = thingType, - // neuroid = receivingNeuroid - // }; - // velocityReceivers.Add(receiver); - // foreach (SensoryNeuroid neuroid in sensoryNeuroids) { - // if (neuroid != null && neuroid.velocityNeuroid != null) { - // neuroid.velocityNeuroid.AddReceiver(receivingNeuroid); - // receivingNeuroid.SetWeight(neuroid, weight); - // } - // } - // } - - public void ProcessStimulus(int thingId, int thingType, Vector3 localPosition, string name = "Sensing") { - int availableIx = -1; - int leastInterestingIx = -1; - for (int i = 0; i < sensoryNeuroids.Length; i++) { - if (sensoryNeuroids[i] == null) - availableIx = i; - else if (sensoryNeuroids[i].receptor.thingType == thingId) { - //sensoryNeuroids[i].receptor.position = localPosition; - sensoryNeuroids[i].receptor.ProcessStimulus(999, localPosition); - return; - } - if (availableIx == -1) { - if (sensoryNeuroids[i].isSleeping) - leastInterestingIx = i; - else if (sensoryNeuroids[i] != null) { - if (leastInterestingIx == -1 || sensoryNeuroids[leastInterestingIx].receptor.localPosition.magnitude > sensoryNeuroids[i].receptor.localPosition.magnitude) - leastInterestingIx = i; - } - } - } - if (availableIx == -1) - availableIx = leastInterestingIx; - - if (availableIx != -1) { - SensoryNeuroid neuroid; - if (sensoryNeuroids[availableIx] != null) { - Debug.Log($"replace receptor for {thingId} at {availableIx}"); - neuroid = sensoryNeuroids[availableIx]; - neuroid.Replace(thingId, name); - } - else { - Debug.Log($"new receptor for {thingId} at {availableIx}"); - neuroid = new(brain, thingId, name); - sensoryNeuroids[availableIx] = neuroid; - } - foreach (Receiver receiver in positionReceivers) { - if (receiver.thingType == 0 || receiver.thingType == thingType) { - Debug.Log("Add position receiver"); - receiver.neuroid.GetInputFrom(neuroid); - } - } - // foreach (Receiver receiver in velocityReceivers) { - // if (receiver.thingType == 0 || receiver.thingType == thingType) - // receiver.neuroid.GetInputFrom(neuroid.velocityNeuroid); - // } - - //neuroid.receptor.position = localPosition; - neuroid.receptor.ProcessStimulus(333, localPosition); - } - } - -} \ No newline at end of file diff --git a/Assets/NanoBrain/Perception.cs.meta b/Assets/NanoBrain/Perception.cs.meta deleted file mode 100644 index adfa3db..0000000 --- a/Assets/NanoBrain/Perception.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 37d94d399d30e6eb996236adabad87ee \ No newline at end of file diff --git a/Assets/NanoBrain/Perceptoid.cs b/Assets/NanoBrain/Perceptoid.cs index 54e9a36..d46f9dc 100644 --- a/Assets/NanoBrain/Perceptoid.cs +++ b/Assets/NanoBrain/Perceptoid.cs @@ -48,19 +48,6 @@ public class Perceptoid : Neuroid { #endregion Serialization - // public Perceptoid(NanoBrainObj brain, string name) : base(name) { - // this.brain = brain; - // if (this.brain != null) { - // this.brain.perceptei.Add(this); - // } - // else - // Debug.LogError("No neuroid network"); - - // this.nucleusType = nameof(Perceptoid); - // this.name = name; - // this.receptor = new Receptor(this); - // } - public Perceptoid(NanoBrainObj brain, int thingType, string name = "sensor") : base(name) { this.brain = brain; if (this.brain != null) { @@ -74,65 +61,22 @@ public class Perceptoid : Neuroid { this.thingType = thingType; this.receptor = Receptor.GetReceptor(brain, thingType); this.receptor.perceptei.Add(this); - // this.velocityNeuroid = new(brain, name + ": velocity"); - // // The velocity neuroid received position data from this - // this.AddReceiver(velocityNeuroid); } public void Replace(int thingType, string name = "sensor") { this.name = name; - //this.thingType = thingType; + this.thingType = thingType; this.receptor.thingType = thingType; this.receptor.localPosition = Spherical.zero; this.outputValue = Spherical.zero; this.receivers = new(); - // this.AddReceiver(velocityNeuroid); - - // this.velocityNeuroid.Replace(name + ": velocity"); - } - - public override void UpdateState() { - Vector3 result = receptor.localPosition.ToVector3(); - foreach (Synapse synapse in this.synapses) { - Nucleus nucleus = synapse.nucleus; - float weight = synapse.weight; - Vector3 direction = nucleus.outputValue.normalized.ToVector3(); - float magnitude = nucleus.outputValue.magnitude; - - magnitude = weight * Mathf.Pow(magnitude, exponent); - if (inverse) - magnitude = 1 / magnitude; - result += direction * magnitude; - } - if (average && this.synapses.Count > 0) - result /= this.synapses.Count + 1; - - this.outputValue = Spherical.FromVector3(result); - foreach (Receiver receiver in this.receivers) - if (receiver.nucleus is Neuroid neuroid) - neuroid.SetInput(this); - //this.stale = 0; - //this.Refresh(); } public void UpdateState(int thingId, Spherical receptorValue) { this.thingId = thingId; Spherical result = receptorValue; - // foreach (Synapse synapse in this.synapses) { - // Nucleus nucleus = synapse.nucleus; - // float weight = synapse.weight; - // Vector3 direction = nucleus.outputValue.normalized; - // float magnitude = nucleus.outputValue.magnitude; - - // magnitude = weight * Mathf.Pow(magnitude, exponent); - // if (inverse) - // magnitude = 1 / magnitude; - // result += direction * magnitude; - // } - // if (average && this.synapses.Count > 0) - // result /= this.synapses.Count + 1; float d = Spherical.Distance(result, this.outputValue); if (d < 0.1f) { @@ -143,8 +87,6 @@ public class Perceptoid : Neuroid { foreach (Receiver receiver in this.receivers) if (receiver.nucleus is Neuroid neuroid) neuroid.SetInput(this); - //this.stale = 0; - //this.Refresh(); } @@ -155,36 +97,4 @@ public class Perceptoid : Neuroid { } return null; } - - public static void ProcessStimulus(NanoBrainObj brain, int thingType, Vector3 localPosition) { - Perceptoid selectedPerceptoid = null; - foreach (Perceptoid nucleus in brain.perceptei) { - if (nucleus is Perceptoid perceptoid && (thingType == 0 || perceptoid.receptor.thingType == thingType)) - if (selectedPerceptoid == null) { - selectedPerceptoid = perceptoid; - if (perceptoid.isSleeping) { - break; - } - } - else if (perceptoid.receptor.localPosition.magnitude < selectedPerceptoid.receptor.localPosition.magnitude) - selectedPerceptoid = perceptoid; - } - if (selectedPerceptoid == null) { - Debug.Log("No perceptoid selected, stimulus is ignored"); - return; - } - //selectedPerceptoid.receptor.position = localPosition; - selectedPerceptoid.receptor.ProcessStimulus(888, localPosition); - } - - // public static Receptor GetReceptor(NanoBrainObj brain, int thingType) { - // foreach (Perceptoid perceptoid in brain.perceptei) { - // if (perceptoid.receptor != null) { - // if (thingType == 0 || perceptoid.receptor.thingType == thingType) - // return perceptoid.receptor; - // } - // } - // Receptor receptor = new(thingType); - // return receptor; - // } } diff --git a/Assets/NanoBrain/Receptor.cs b/Assets/NanoBrain/Receptor.cs index 18b8089..45f3697 100644 --- a/Assets/NanoBrain/Receptor.cs +++ b/Assets/NanoBrain/Receptor.cs @@ -8,7 +8,6 @@ public class Receptor { /// public List perceptei = new(); - //public int thingId; private int _thingType = 0; public int thingType { get { return _thingType; } @@ -51,15 +50,16 @@ public class Receptor { selectedPerceptoid = perceptoid; // Do not look any further - // This does not do a lot.... - float deltaDistance = newLocalPosition.distance - previousLocalPosition.distance; - // See if the change is significant - AngleFloat deltaDirection = Direction.UnsignedAngle(newLocalPosition.direction, previousLocalPosition.direction); - if (deltaDistance < this.distanceResolution && deltaDirection.inDegrees < directionResolution) { - // The difference is not significant we don't process this data. - this.localPosition = previousLocalPosition; - return; - } + // // This does not do a lot.... + // float deltaDistance = newLocalPosition.distance - previousLocalPosition.distance; + // // See if the change is significant + // AngleFloat deltaDirection = Direction.UnsignedAngle(newLocalPosition.direction, previousLocalPosition.direction); + // if (deltaDistance < this.distanceResolution && deltaDirection.inDegrees < directionResolution) { + // // The difference is not significant we don't process this data. + // this.localPosition = previousLocalPosition; + // return; + // } + // This is now also handled by the UpdateState Spherical.Distance break; } else if (perceptoid.isSleeping) { diff --git a/Assets/NanoBrain/SensoryNeuroid.cs b/Assets/NanoBrain/SensoryNeuroid.cs deleted file mode 100644 index ffc4e4a..0000000 --- a/Assets/NanoBrain/SensoryNeuroid.cs +++ /dev/null @@ -1,136 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using LinearAlgebra; - -// public class Receptor { - -// public Neuroid neuroid; -// public List perceptoids; - -// public int thingId; -// public int thingType; -// public Vector3 localPosition; - -// /// -// /// Local position of the thing -// /// -// public virtual Vector3 position { -// get { -// return this.localPosition; -// } -// set { -// this.localPosition = value; -// neuroid.UpdateState(); -// } -// } - -// public virtual void ProcessStimulus(int thingId, Vector3 localPosition) { -// this.thingId = thingId; -// this.localPosition = localPosition; -// neuroid.UpdateState(); - -// } -// } - -public class SensoryNeuroid : Neuroid { - // A neuroid which has no neurons as input - // But receives value from a receptor - public Receptor receptor; - //public VelocityNeuroid velocityNeuroid; - - public SensoryNeuroid(NanoBrainObj brain, int thingId, string name = "sensor") : base(brain, name) { - this.name = name + ": position"; - // this.receptor = new Receptor(this) { - // thingType = thingId - // }; - // this.velocityNeuroid = new(brain, name + ": velocity"); - // // The velocity neuroid received position data from this - // this.AddReceiver(velocityNeuroid); - } - - public void Replace(int thingId, string name = "sensor") { - this.name = name + ": position"; - - this.receptor.thingType = thingId; - this.receptor.localPosition = Spherical.zero; - - this.outputValue = Spherical.zero; - this.receivers = new(); - // this.AddReceiver(velocityNeuroid); - - // // this.velocityNeuroid.name = name + ": velocity"; - // // this.velocityNeuroid.receivers = new(); - // this.velocityNeuroid.Replace(name + ": velocity"); - } - - public override void UpdateState() { - Vector3 result = receptor.localPosition.ToVector3(); - //foreach ((Nucleus nucleus, float weight) in this.synapses) { - foreach (Synapse synapse in this.synapses) { - Nucleus nucleus = synapse.nucleus; - float weight = synapse.weight; - Vector3 outputV3 = nucleus.outputValue.ToVector3(); - Vector3 direction = outputV3.normalized; - float magnitude = outputV3.magnitude; - - magnitude = weight * Mathf.Pow(magnitude, exponent); - if (inverse) - magnitude = 1 / magnitude; - result += direction * magnitude; - } - if (average && this.synapses.Count > 0) - result /= this.synapses.Count + 1; - - this.outputValue = Spherical.FromVector3(result); - //foreach (Neuroid neuroid in this.receivers) - foreach (Receiver receiver in this.receivers) - if (receiver.nucleus is Neuroid neuroid) - neuroid.SetInput(this); - //this.stale = 0; - //this.Refresh(); - } -} - -// public class VelocityNeuroid : Neuroid { -// // Would be best if this was received through a synapse via a loop.... -// private Vector3 lastPosition = Vector3.zero; -// private float lastValueTime = 0; - -// public VelocityNeuroid(NanoBrainObj net, string name = "velocity") : base(net, name) { -// } - -// public void Replace(string name = "velocity") { -// this.name = name; -// this.receivers = new(); -// this.lastPosition = Vector3.zero; -// this.lastValueTime = 0; -// } - -// public override void UpdateState() { -// // Assuming only one synapse for now.... -// //Vector3 currentPosition = this.synapses.First().Key.outputValue; -// Spherical currentPosition = this.synapses.First().nucleus.outputValue; -// Vector3 currentPositionV3 = currentPosition.ToVector3(); -// float currentValueTime = Time.time; - -// if (lastValueTime != 0) { -// float deltaTime = currentValueTime - lastValueTime; -// Vector3 translation = currentPositionV3 - lastPosition; -// Vector3 velocity = translation / deltaTime; - -// // No activation function... -// this.outputValue = Spherical.FromVector3(velocity); -// //this.stale = 0; -// //this.Refresh(); - -// foreach (Receiver receiver in receivers) { -// if (receiver.nucleus is Neuroid neuroid) -// neuroid.SetInput(this); -// } -// } - -// this.lastValueTime = currentValueTime; -// this.lastPosition = currentPositionV3; -// } -// } \ No newline at end of file diff --git a/Assets/NanoBrain/SensoryNeuroid.cs.meta b/Assets/NanoBrain/SensoryNeuroid.cs.meta deleted file mode 100644 index 40e2ec3..0000000 --- a/Assets/NanoBrain/SensoryNeuroid.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 9e34db6b23aa12477a2f98b9eb0cbbe2 \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs index d534b9e..81ffac3 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs @@ -296,18 +296,18 @@ public class GraphBoardView : VisualElement { private void HandleMouseHover(Nucleus neuroid, Rect rect) { GUIContent tooltip; - if (neuroid is SensoryNeuroid sensoryNeuroid) { - tooltip = new( - $"{sensoryNeuroid.name}" + - $"\nThing {sensoryNeuroid.receptor.thingType}" + - $"\nValue: {neuroid.outputValue}"); - } - else { + // if (neuroid is SensoryNeuroid sensoryNeuroid) { + // tooltip = new( + // $"{sensoryNeuroid.name}" + + // $"\nThing {sensoryNeuroid.receptor.thingType}" + + // $"\nValue: {neuroid.outputValue}"); + // } + // else { tooltip = new( $"{neuroid.name}" + $"\nsynapse count {neuroid.synapses.Count}" + $"\nValue: {neuroid.outputValue}"); - } + // } Vector2 mousePosition = Event.current.mousePosition; diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs index 5f65741..9ab8a35 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs @@ -337,13 +337,14 @@ public class NanoBrainInspector : Editor { private void HandleMouseHover(Nucleus nucleus, Rect rect) { GUIContent tooltip; - if (nucleus is SensoryNeuroid sensoryNeuroid) { - tooltip = new( - $"{sensoryNeuroid.name}" + - $"\nThing {sensoryNeuroid.receptor.thingType}" + - $"\nValue: {nucleus.outputValue}"); - } - else if (nucleus is Perceptoid perceptoid) { + // if (nucleus is SensoryNeuroid sensoryNeuroid) { + // tooltip = new( + // $"{sensoryNeuroid.name}" + + // $"\nThing {sensoryNeuroid.receptor.thingType}" + + // $"\nValue: {nucleus.outputValue}"); + // } + //else + if (nucleus is Perceptoid perceptoid) { if (perceptoid.receptor != null) { tooltip = new( $"{perceptoid.name}" + @@ -396,7 +397,7 @@ public class NanoBrainInspector : Editor { if (this.currentNucleus == null) return; - + this.currentNucleus.name = EditorGUILayout.TextField(this.currentNucleus.name); if (this.currentNucleus is Perceptoid currentPerceptoid) { currentPerceptoid.receptor.thingType = EditorGUILayout.IntField("Thing Type", currentPerceptoid.receptor.thingType); @@ -572,29 +573,29 @@ public class NanoBrainInspector : Editor { } } - protected virtual void OnSceneGUI() { - NanoBrain brain = target as NanoBrain; - if (brain == null) - return; + // protected virtual void OnSceneGUI() { + // NanoBrain brain = target as NanoBrain; + // if (brain == null) + // return; - Vector3 position = brain.transform.position; - float radius = 1; + // Vector3 position = brain.transform.position; + // float radius = 1; - Handles.DrawWireDisc(position, Vector3.up, radius); // horizontal circle - Handles.DrawWireDisc(position, Vector3.right, radius); // X-plane - Handles.DrawWireDisc(position, Vector3.forward, radius); // Z-plane + // Handles.DrawWireDisc(position, Vector3.up, radius); // horizontal circle + // Handles.DrawWireDisc(position, Vector3.right, radius); // X-plane + // Handles.DrawWireDisc(position, Vector3.forward, radius); // Z-plane - // Debug.DrawRay(brain.transform.position, Vector3.forward, Color.magenta); - // Handles.color = Color.green; - // Handles.DrawLine(brain.transform.position, brain.transform.position + Vector3.up); + // // Debug.DrawRay(brain.transform.position, Vector3.forward, Color.magenta); + // // Handles.color = Color.green; + // // Handles.DrawLine(brain.transform.position, brain.transform.position + Vector3.up); - // Handles.color = Color.yellow; - // Vector3 worldForce = brain.transform.TransformDirection(this.currentNucleus.outputValue); - // //Debug.DrawRay(position, worldForce * 10, Color.yellow); - // Handles.DrawLine(position, position + worldForce * 10); - } + // // Handles.color = Color.yellow; + // // Vector3 worldForce = brain.transform.TransformDirection(this.currentNucleus.outputValue); + // // //Debug.DrawRay(position, worldForce * 10, Color.yellow); + // // Handles.DrawLine(position, position + worldForce * 10); + // } #endregion Update } diff --git a/Assets/NanoBrain/VisualEditor/NeuroidObject.cs b/Assets/NanoBrain/VisualEditor/NeuroidObject.cs deleted file mode 100644 index e69de29..0000000 diff --git a/Assets/NanoBrain/VisualEditor/NeuroidObject.cs.meta b/Assets/NanoBrain/VisualEditor/NeuroidObject.cs.meta deleted file mode 100644 index 8d0614f..0000000 --- a/Assets/NanoBrain/VisualEditor/NeuroidObject.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: d14e756f390f41a1c9923a0015329389 \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/NucleusObject.cs b/Assets/NanoBrain/VisualEditor/NucleusObject.cs deleted file mode 100644 index 989f603..0000000 --- a/Assets/NanoBrain/VisualEditor/NucleusObject.cs +++ /dev/null @@ -1,28 +0,0 @@ -// using System.Collections.Generic; -// using UnityEngine; - -// public class NucleusObj : ScriptableObject { -// public virtual string objName { get; set; } - -// public readonly Dictionary synapses = new(); -// public HashSet receivers = new(); -// public virtual Vector3 outputValue { get; set; } - -// public int stale = 0; - -// public NucleusObj(string name) { -// this.objName = name; -// } - -// public virtual void AddReceiver(NucleusObj receiver) { -// this.receivers.Add(receiver); -// receiver.synapses[this] = 1.0f; -// } - -// public bool isSleeping { -// get { -// return this.stale > 2; -// } -// } - -// } \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/NucleusObject.cs.meta b/Assets/NanoBrain/VisualEditor/NucleusObject.cs.meta deleted file mode 100644 index e867330..0000000 --- a/Assets/NanoBrain/VisualEditor/NucleusObject.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: ca2a41cdae50b5005b5cf10cebb28de6 \ No newline at end of file From 1e1e5b134492a240b7d838a0f541d7f856f2575a Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Tue, 6 Jan 2026 15:48:51 +0100 Subject: [PATCH 044/179] Further cleanup --- Assembly-CSharp.csproj | 2 - Assets/NanoBrain/Nucleus.cs | 19 ++-------- Assets/Scenes/Boids/Scripts/RoamingNucleus.cs | 19 ---------- .../Boids/Scripts/RoamingNucleus.cs.meta | 2 - .../Scenes/Boids/Scripts/SwarmingNucleus.cs | 37 ------------------- .../Boids/Scripts/SwarmingNucleus.cs.meta | 2 - 6 files changed, 4 insertions(+), 77 deletions(-) delete mode 100644 Assets/Scenes/Boids/Scripts/RoamingNucleus.cs delete mode 100644 Assets/Scenes/Boids/Scripts/RoamingNucleus.cs.meta delete mode 100644 Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs delete mode 100644 Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs.meta diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index 7e83f6b..6091706 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -70,10 +70,8 @@ - - diff --git a/Assets/NanoBrain/Nucleus.cs b/Assets/NanoBrain/Nucleus.cs index 7b49319..dcf1b5b 100644 --- a/Assets/NanoBrain/Nucleus.cs +++ b/Assets/NanoBrain/Nucleus.cs @@ -69,17 +69,19 @@ public class Nucleus { { get { return _outputValue; } set { - //Refresh(); this.stale = 0; + this.isSleeping = false; _outputValue = value; } } [System.NonSerialized] private int stale = 1000; - public bool isSleeping => this.stale > 2; + + public bool isSleeping = false; public void IncreaseAge() { this.stale++; + this.isSleeping = this.stale > 2; if (isSleeping) _outputValue = Spherical.zero; } @@ -89,13 +91,6 @@ public class Nucleus { #endregion Runtime state public Nucleus(string name) { - // this.brain = brain; - // if (this.brain != null) { - // this.brain.nuclei.Add(this); - // } - // else - // Debug.LogError("No neuroid network"); - this._name = name; this.id = this.GetHashCode(); } @@ -137,12 +132,6 @@ public class Nucleus { this.SetWeight(input, weight); } - // public bool isSleeping { - // get { - // return this.stale > 2; - // } - // } - public bool SynapseExists(Nucleus nucleus) { foreach (Synapse synapse in synapses) { if (synapse.nucleus == nucleus) diff --git a/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs b/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs deleted file mode 100644 index de86097..0000000 --- a/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs +++ /dev/null @@ -1,19 +0,0 @@ -/* -public class Roaming : Nucleus { - public Neuroid avoidance; - - public Neuroid output; - - public Roaming(NanoBrainObj brain, Perception perception, SwarmControl sc) : base("Roaming nucleus") { - avoidance = new(brain, "Avoidance") { inverse = true }; - perception.SendPositions(avoidance, Boid.BoundaryType); - - this.output = new(brain, "Roaming"); - output.GetInputFrom(avoidance, -sc.avoidanceForce); - } - - public override void AddReceiver(Nucleus receiver) { - output.AddReceiver(receiver); - } -} -*/ \ No newline at end of file diff --git a/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs.meta b/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs.meta deleted file mode 100644 index 27a0198..0000000 --- a/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 2c0f5292293252943b1d45dbd1d14515 \ No newline at end of file diff --git a/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs b/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs deleted file mode 100644 index a5d715d..0000000 --- a/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs +++ /dev/null @@ -1,37 +0,0 @@ -// using UnityEngine; -// using LinearAlgebra; - -// public class Swarming : Nucleus { -// public Neuroid cohesion; -// public Neuroid alignment; -// public Neuroid avoidance; -// public Neuroid boundary; - -// public Neuroid output; - -// //public override Spherical outputValue { get => output.outputValue; set => output.outputValue = value; } - -// public Swarming(NanoBrainObj brain, Perception perception, SwarmControl sc) : base("Swarming Nucleus") { -// this.cohesion = new(brain, "Cohesion") { inverse = false }; -// perception.SendPositions(this.cohesion, Boid.BoidType); - -// this.alignment = new(brain, "Alignment") { average = true }; -// perception.SendVelocities(this.alignment, Boid.BoidType); - -// this.avoidance = new(brain, "Avoidance") { inverse = true }; -// perception.SendPositions(this.avoidance); - -// this.boundary = new(brain, "Boundary"); -// perception.SendPositions(this.boundary, Boid.BoundaryType); - -// this.output = new(brain, "Swarming"); -// this.output.GetInputFrom(alignment, sc.alignmentForce); -// this.output.GetInputFrom(cohesion, sc.cohesionForce); -// this.output.GetInputFrom(avoidance, -sc.avoidanceForce); -// this.output.GetInputFrom(boundary, -sc.avoidanceForce); -// } - -// public override void AddReceiver(Nucleus receiver) { -// this.output.AddReceiver(receiver); -// } -// } \ No newline at end of file diff --git a/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs.meta b/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs.meta deleted file mode 100644 index f303111..0000000 --- a/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 14b1bfd5a5b0784e098fc5e47b1720a1 \ No newline at end of file From d026996ce2bb2bd3a394085ae596fa57c63a1b41 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Tue, 6 Jan 2026 17:18:31 +0100 Subject: [PATCH 045/179] Prepare for spherical average --- .../NanoBrain/LinearAlgebra/src/Spherical.cs | 47 +++++++++++++++++++ Assets/NanoBrain/Neuroid.cs | 28 ++++++----- Assets/NanoBrain/Nucleus.cs | 14 ++++++ Assets/NanoBrain/Perceptoid.cs | 16 ++----- Assets/NanoBrain/Receptor.cs | 3 +- 5 files changed, 83 insertions(+), 25 deletions(-) diff --git a/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs b/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs index e1e3ab6..db829dc 100644 --- a/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs +++ b/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; + #if UNITY_5_3_OR_NEWER using Vector3 = UnityEngine.Vector3; #endif @@ -137,6 +139,19 @@ namespace LinearAlgebra { return r; } + public static Spherical operator *(Spherical v, float d) { + Spherical r = new(v.distance * d, v.direction); + return r; + } + + public static bool operator ==(Spherical v1, Spherical v2) { + return (v1.distance == v2.distance && v1.direction == v2.direction); + } + + public static bool operator !=(Spherical v1, Spherical v2) { + return (v1.distance != v2.distance || v1.direction != v2.direction); + } + public static float Distance(Spherical v1, Spherical v2) { // Convert degrees to radians float thetaARadians = v1.direction.horizontal.inRadians; @@ -162,5 +177,37 @@ namespace LinearAlgebra { return distance; } + + public static Spherical Average(List vectors) { + float sumSinPhiCosTheta = 0.0f; + float sumSinPhiSinTheta = 0.0f; + float sumCosPhi = 0.0f; + + int n = vectors.Count; + + // Step 1: Accumulate sine and cosine components + foreach(Spherical v in vectors) { + float sinHorizontal = AngleFloat.Sin(v.direction.horizontal); + sumSinPhiCosTheta += v.distance * sinHorizontal * AngleFloat.Cos(v.direction.vertical); + sumSinPhiSinTheta += v.distance * sinHorizontal * AngleFloat.Sin(v.direction.vertical); + sumCosPhi += v.distance * AngleFloat.Cos(v.direction.horizontal); + } + + // Step 2: Calculate average components + float avgSinPhiCosTheta = sumSinPhiCosTheta / n; + float avgSinPhiSinTheta = sumSinPhiSinTheta / n; + float avgCosPhi = sumCosPhi / n; + + // Step 3: Calculate the magnitude of the average vector + float rAvg = MathF.Sqrt(avgSinPhiCosTheta * avgSinPhiCosTheta + + avgSinPhiSinTheta * avgSinPhiSinTheta + + avgCosPhi * avgCosPhi); + + // Step 4: Calculate average angles + AngleFloat horizontalAvg = AngleFloat.Acos(avgCosPhi / rAvg); // Handle rAvg != 0 case + AngleFloat verticalAvg = AngleFloat.Atan2(avgSinPhiSinTheta, avgSinPhiCosTheta); + + return new Spherical(rAvg, new Direction(horizontalAvg, verticalAvg)); + } } } \ No newline at end of file diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index 6e192ec..301ce03 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using UnityEngine; using LinearAlgebra; @@ -73,7 +74,7 @@ public class Neuroid : Nucleus { UpdateState(); } - public virtual void UpdateState() { + public override void UpdateState() { Vector3 resultVector = Vector3.zero; foreach (Synapse synapse in this.synapses) { Nucleus synapseNucleus = synapse.nucleus; @@ -93,18 +94,23 @@ public class Neuroid : Nucleus { resultVector /= this.synapses.Count; Spherical result = Spherical.FromVector3(resultVector); - float d = Spherical.Distance(result, this.outputValue); - if (d < 0.1f) { - //Debug.Log($"insignificant update: {d}"); - return; - } - this.outputValue = result; + // List vectors = new(); + // foreach (Synapse synapse in this.synapses) { + // if (synapse.nucleus.isSleeping) + // continue; + + // vectors.Add(synapse.nucleus.outputValue); + // } + // Spherical result2 = Spherical.Average(vectors); + // if (average == false) + // result2 *= vectors.Count; - foreach (Receiver receiver in this.receivers) { - if (receiver.nucleus is Neuroid neuroid) - neuroid.SetInput(this); - } + // if (result2 != result) + // Debug.Log($"update error {result2} != {result}"); + + UpdateResult(result); + } } diff --git a/Assets/NanoBrain/Nucleus.cs b/Assets/NanoBrain/Nucleus.cs index dcf1b5b..94e2e64 100644 --- a/Assets/NanoBrain/Nucleus.cs +++ b/Assets/NanoBrain/Nucleus.cs @@ -151,6 +151,20 @@ public class Nucleus { synapses.Add(newSynapse); } + public virtual void UpdateState() { } + + public void UpdateResult(Spherical result) { + float d = Spherical.Distance(result, this.outputValue); + if (d < 0.1f) { + //Debug.Log($"insignificant update: {d}"); + return; + } + + this.outputValue = result; + foreach (Receiver receiver in this.receivers) + receiver.nucleus.UpdateState(); + + } } [System.Serializable] diff --git a/Assets/NanoBrain/Perceptoid.cs b/Assets/NanoBrain/Perceptoid.cs index d46f9dc..4f5b5a9 100644 --- a/Assets/NanoBrain/Perceptoid.cs +++ b/Assets/NanoBrain/Perceptoid.cs @@ -74,19 +74,9 @@ public class Perceptoid : Neuroid { this.receivers = new(); } - public void UpdateState(int thingId, Spherical receptorValue) { - this.thingId = thingId; - Spherical result = receptorValue; - - float d = Spherical.Distance(result, this.outputValue); - if (d < 0.1f) { - //Debug.Log($"insignificant update: {d}"); - return; - } - this.outputValue = result; - foreach (Receiver receiver in this.receivers) - if (receiver.nucleus is Neuroid neuroid) - neuroid.SetInput(this); + public override void UpdateState() { + Spherical result = this.receptor.localPosition; + UpdateResult(result); } diff --git a/Assets/NanoBrain/Receptor.cs b/Assets/NanoBrain/Receptor.cs index 45f3697..47e215f 100644 --- a/Assets/NanoBrain/Receptor.cs +++ b/Assets/NanoBrain/Receptor.cs @@ -87,6 +87,7 @@ public class Receptor { return; } // Debug.Log($"Stimulus {thingType} {thingId} {selectedPerceptoid.name}"); - selectedPerceptoid.UpdateState(thingId, this.localPosition); + selectedPerceptoid.thingId = thingId; + selectedPerceptoid.UpdateState(); } } \ No newline at end of file From 28c1fac3f8ebdbeca4b3f522fb95a59f2e1dfa5a Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 7 Jan 2026 09:53:16 +0100 Subject: [PATCH 046/179] Updated swarming brain --- Assets/Scenes/Boids/SwarmingBrain.asset | 150 +++++------------------- 1 file changed, 30 insertions(+), 120 deletions(-) diff --git a/Assets/Scenes/Boids/SwarmingBrain.asset b/Assets/Scenes/Boids/SwarmingBrain.asset index 08a62b5..5989f27 100644 --- a/Assets/Scenes/Boids/SwarmingBrain.asset +++ b/Assets/Scenes/Boids/SwarmingBrain.asset @@ -1250,6 +1250,7 @@ MonoBehaviour: curveMax: 1 receivers: [] nucleusType: + isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -1295,6 +1296,7 @@ MonoBehaviour: receivers: - nucleusId: -1707533328 nucleusType: + isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -1390,6 +1392,7 @@ MonoBehaviour: receivers: - nucleusId: -1707533328 nucleusType: + isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -1485,6 +1488,7 @@ MonoBehaviour: receivers: - nucleusId: -1707533328 nucleusType: + isSleeping: 0 _curvePreset: 2 curve: serializedVersion: 2 @@ -1850,6 +1854,7 @@ MonoBehaviour: receivers: - nucleusId: -1707533328 nucleusType: + isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -1886,6 +1891,7 @@ MonoBehaviour: receivers: - nucleusId: -112538112 nucleusType: Perceptoid + isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -1899,114 +1905,6 @@ MonoBehaviour: exponent: 1 thingType: 1 thingId: 0 - - id: 1921239042 - _name: Boid1Velocity - synapses: [] - receivers: [] - nucleusType: Perceptoid - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - thingType: 3 - thingId: 0 - - id: 1686464114 - _name: Boid2Velocity - synapses: [] - receivers: [] - nucleusType: Perceptoid - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - thingType: 3 - thingId: 0 - - id: -1926972526 - _name: Boid3Velocity - synapses: [] - receivers: [] - nucleusType: Perceptoid - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - thingType: 3 - thingId: 0 - - id: 483038322 - _name: Boid4Velocity - synapses: [] - receivers: [] - nucleusType: Perceptoid - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - thingType: 3 - thingId: 0 - - id: 890767934 - _name: Boid5Velocity - synapses: [] - receivers: [] - nucleusType: Perceptoid - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - thingType: 3 - thingId: 0 - - id: -324208238 - _name: Boid6Velocity - synapses: [] - receivers: [] - nucleusType: Perceptoid - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - thingType: 3 - thingId: 0 - id: -1659429232 _name: BoidA synapses: [] @@ -2014,6 +1912,7 @@ MonoBehaviour: - nucleusId: 1938577052 - nucleusId: 1641120128 nucleusType: Perceptoid + isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -2025,7 +1924,7 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 - thingType: 0 + thingType: 2 thingId: 0 - id: 839544896 _name: BoidB @@ -2034,6 +1933,7 @@ MonoBehaviour: - nucleusId: 1938577052 - nucleusId: 1641120128 nucleusType: Perceptoid + isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -2045,7 +1945,7 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 - thingType: 0 + thingType: 2 thingId: 0 - id: -348340288 _name: BoidC @@ -2054,6 +1954,7 @@ MonoBehaviour: - nucleusId: 1641120128 - nucleusId: 1938577052 nucleusType: Perceptoid + isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -2065,7 +1966,7 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 - thingType: 0 + thingType: 2 thingId: 0 - id: -1095934288 _name: BoidD @@ -2074,6 +1975,7 @@ MonoBehaviour: - nucleusId: 1938577052 - nucleusId: 1641120128 nucleusType: Perceptoid + isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -2085,7 +1987,7 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 - thingType: 0 + thingType: 2 thingId: 0 - id: -1413006832 _name: BoidE @@ -2094,6 +1996,7 @@ MonoBehaviour: - nucleusId: 1641120128 - nucleusId: 1938577052 nucleusType: Perceptoid + isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -2105,7 +2008,7 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 - thingType: 0 + thingType: 2 thingId: 0 - id: -61245040 _name: BoidF @@ -2114,6 +2017,7 @@ MonoBehaviour: - nucleusId: 1938577052 - nucleusId: 1641120128 nucleusType: Perceptoid + isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -2125,7 +2029,7 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 - thingType: 0 + thingType: 2 thingId: 0 - id: -1659687600 _name: BoidA Velocity @@ -2133,6 +2037,7 @@ MonoBehaviour: receivers: - nucleusId: -1857835930 nucleusType: Perceptoid + isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -2144,7 +2049,7 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 - thingType: 0 + thingType: 3 thingId: 0 - id: 1322333072 _name: BoidB Velocity @@ -2152,6 +2057,7 @@ MonoBehaviour: receivers: - nucleusId: -1857835930 nucleusType: Perceptoid + isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -2163,7 +2069,7 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 - thingType: 0 + thingType: 3 thingId: 0 - id: -1563920864 _name: BoidC Velocity @@ -2171,6 +2077,7 @@ MonoBehaviour: receivers: - nucleusId: -1857835930 nucleusType: Perceptoid + isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -2182,7 +2089,7 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 - thingType: 0 + thingType: 3 thingId: 0 - id: 182328688 _name: BoidD Velocity @@ -2190,6 +2097,7 @@ MonoBehaviour: receivers: - nucleusId: -1857835930 nucleusType: Perceptoid + isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -2201,7 +2109,7 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 - thingType: 0 + thingType: 3 thingId: 0 - id: -1666561744 _name: BoidE Velocity @@ -2209,6 +2117,7 @@ MonoBehaviour: receivers: - nucleusId: -1857835930 nucleusType: Perceptoid + isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -2220,7 +2129,7 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 - thingType: 0 + thingType: 3 thingId: 0 - id: -1884196224 _name: BoidF Velocity @@ -2228,6 +2137,7 @@ MonoBehaviour: receivers: - nucleusId: -1857835930 nucleusType: Perceptoid + isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -2239,6 +2149,6 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 - thingType: 0 + thingType: 3 thingId: 0 rootId: -1707533328 From 841d923fed686700610a85aeab6289e44239aa6c Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 7 Jan 2026 11:33:48 +0100 Subject: [PATCH 047/179] Squashed 'Assets/NanoBrain/LinearAlgebra/' changes from 15c08f2..672f8bf 672f8bf Spherical Average a278b7d Fix/Improve ToVector3 09d34d1 Prepare for spherical average b19e504 (A little) Performance improvements 2b0433f Fix normalizing direction 3e115cc Fix Direction.ToVector3 0eeedd2 Vector3 conversion fixes 3024562 Fix Unity warnings aa23d57 Fix roaming boid cdfe039 Improve Unity compatibility git-subtree-dir: Assets/NanoBrain/LinearAlgebra git-subtree-split: 672f8bfca1b1e0bc312df41142fa3c4447ce6dba --- src/Angle.cs | 27 ++- src/Direction.cs | 83 ++++++++-- src/Quaternion.cs | 26 --- src/Spherical.cs | 376 +++++++++++++++++++++++++++++++----------- src/SwingTwist.cs | 66 +++++--- src/Vector2Float.cs | 36 ++-- src/Vector2Int.cs | 31 ++-- src/Vector3Float.cs | 31 ++-- test/AngleTest.cs | 4 + test/DirectionTest.cs | 25 +++ test/SphericalTest.cs | 186 +++++++++++++++++++++ 11 files changed, 682 insertions(+), 209 deletions(-) diff --git a/src/Angle.cs b/src/Angle.cs index 694d1b7..70f5b10 100644 --- a/src/Angle.cs +++ b/src/Angle.cs @@ -32,7 +32,6 @@ namespace LinearAlgebra { } return new AngleFloat(radians * Rad2Deg); - } public static AngleFloat Revolutions(float revolutions) { @@ -51,16 +50,14 @@ namespace LinearAlgebra { return new AngleFloat(revolutions * 360); } - public float inDegrees { - get { return this.value; } - } + public readonly float inDegrees => this.value; - public float inRadians { - get { return this.value * Deg2Rad; } - } + public readonly float inRadians => this.value * Deg2Rad; + + public readonly float inRevolutions => this.value / 360.0f; - public float inRevolutions { - get { return this.value / 360.0f; } + public override string ToString() { + return $"{this.inDegrees} deg."; } public static readonly AngleFloat zero = Degrees(0); @@ -115,6 +112,18 @@ namespace LinearAlgebra { return a1.value != a2.value; } + public override readonly bool Equals(object obj) { + if (obj is AngleFloat other) { + return this == other; + } + return false; + } + + public override readonly int GetHashCode() { + return this.value.GetHashCode(); + } + + /// /// Tests if the first angle is greater than the second /// diff --git a/src/Direction.cs b/src/Direction.cs index ed82901..9293503 100644 --- a/src/Direction.cs +++ b/src/Direction.cs @@ -66,6 +66,10 @@ namespace LinearAlgebra { return d; } + public override readonly string ToString() { + return $"Direction(h: {this.horizontal}, v: {this.vertical})"; + } + /// /// A forward direction with zero for both angles /// @@ -98,31 +102,64 @@ namespace LinearAlgebra { private void Normalize() { if (this.vertical > AngleFloat.deg90 || this.vertical < -AngleFloat.deg90) { this.horizontal += AngleFloat.deg180; - this.vertical = AngleFloat.deg180 - this.vertical; + this.vertical = AngleFloat.Degrees(180 - this.vertical.inDegrees); } } -#if !UNITY_5_3_OR_NEWER +#if UNITY_5_3_OR_NEWER /// /// Convert the direction into a carthesian vector /// /// The carthesian vector corresponding to this direction. - public Vector3Float ToVector3Float() { - Quaternion q = Quaternion.Euler(90 - this.vertical.inDegrees, this.horizontal.inDegrees, 0); - Vector3Float v = q * Vector3Float.forward; - return v; + public readonly UnityEngine.Vector3 ToVector3() { + // Convert degrees to radians + float radH = this.horizontal.inRadians; + float radV = this.vertical.inRadians; + + // Calculate Vector + float cosV = MathF.Cos(radV); + float x = cosV * MathF.Cos(radH); + float y = MathF.Sin(radV); + float z = cosV * MathF.Sin(radH); + + return new UnityEngine.Vector3(x, y, z); } -#else + + /// + /// Convert a carthesian vector into a direction + /// + /// The carthesian vector + /// The direction + /// Information about the length of the carthesian vector is not + /// included in this transformation + public static Direction FromVector3(UnityEngine.Vector3 v) { + AngleFloat horizontal = AngleFloat.Atan2(v.x, v.z); + AngleFloat vertical = AngleFloat.deg90 - AngleFloat.Acos(v.y); + Direction d = new(horizontal, vertical); + return d; + } +#else /// /// Convert the direction into a carthesian vector /// /// The carthesian vector corresponding to this direction. - public UnityEngine.Vector3 ToVector3() { - UnityEngine.Quaternion q = UnityEngine.Quaternion.Euler(90 - this.vertical.inDegrees, this.horizontal.inDegrees, 0); - UnityEngine.Vector3 v = q * UnityEngine.Vector3.forward; - return v; + public readonly Vector3Float ToVector3() { + // Quaternion q = Quaternion.Euler(90 - this.vertical.inDegrees, this.horizontal.inDegrees, 0); + // Vector3Float v = q * Vector3Float.forward; + // return v; + + float radH = this.horizontal.inRadians; + float radV = this.vertical.inRadians; + + float cosV = MathF.Cos(radV); + float sinV = MathF.Sin(radV); + + float horizontal = cosV * MathF.Sin(radH); + float vertical = sinV; + float depth = cosV * MathF.Cos(radH); + + return new Vector3Float(horizontal, vertical, depth); } -#endif /// /// Convert a carthesian vector into a direction @@ -137,6 +174,8 @@ namespace LinearAlgebra { Direction d = new(horizontal, vertical); return d; } +#endif + /// /// Tests the equality of two directions @@ -176,6 +215,26 @@ namespace LinearAlgebra { return HashCode.Combine(horizontal, vertical); } + public static AngleFloat UnsignedAngle(Direction d1, Direction d2) { + // Convert angles from degrees to radians + float horizontal1Rad = d1.horizontal.inRadians; + float vertical1Rad = d1.vertical.inRadians; + + float horizontal2Rad = d2.horizontal.inRadians; + float vertical2Rad = d2.vertical.inRadians; + + // Calculate the cosine of the angle using the spherical law of cosines + float cosTheta = MathF.Sin(vertical1Rad) * MathF.Sin(vertical2Rad) + + MathF.Cos(vertical1Rad) * MathF.Cos(vertical2Rad) * + MathF.Cos(horizontal1Rad - horizontal2Rad); + + // Clip cosTheta to the valid range for acos + cosTheta = Float.Clamp(cosTheta, -1.0f, 1.0f); + + // Calculate the angle + AngleFloat angle = AngleFloat.Acos(cosTheta); + return angle; + } } } \ No newline at end of file diff --git a/src/Quaternion.cs b/src/Quaternion.cs index 670c0a4..7936843 100644 --- a/src/Quaternion.cs +++ b/src/Quaternion.cs @@ -180,11 +180,7 @@ namespace LinearAlgebra { /// The resulting quaternion /// Rotation are appied in the order Z, X, Y. public static Quaternion Euler(Vector3Float angles) { - // return Quaternion.FromEulerRad(angles * AngleFloat.Deg2Rad); - // } - // private static Quaternion FromEulerRad(Vector3Float euler) { Vector3Float euler = angles * AngleFloat.Deg2Rad; - // euler.x = pitch, euler.y = yaw, euler.z = roll (radians) float cx = MathF.Cos(euler.horizontal * 0.5f); float sx = MathF.Sin(euler.horizontal * 0.5f); float cy = MathF.Cos(euler.vertical * 0.5f); @@ -199,28 +195,6 @@ namespace LinearAlgebra { q.y = sy * cx * cz - cy * sx * sz; q.z = cy * cx * sz - sy * sx * cz; return q; - // float yaw = euler.horizontal; - // float pitch = euler.vertical; - // float roll = euler.depth; - // float rollOver2 = roll * 0.5f; - // float sinRollOver2 = MathF.Sin(rollOver2); - // float cosRollOver2 = MathF.Cos(rollOver2); - // float pitchOver2 = pitch * 0.5f; - // float sinPitchOver2 = MathF.Sin(pitchOver2); - // float cosPitchOver2 = MathF.Cos(pitchOver2); - // float yawOver2 = yaw * 0.5f; - // float sinYawOver2 = MathF.Sin(yawOver2); - // float cosYawOver2 = MathF.Cos(yawOver2); - // Quaternion result; - // result.w = cosYawOver2 * cosPitchOver2 * cosRollOver2 + - // sinYawOver2 * sinPitchOver2 * sinRollOver2; - // result.x = sinYawOver2 * cosPitchOver2 * cosRollOver2 + - // cosYawOver2 * sinPitchOver2 * sinRollOver2; - // result.y = cosYawOver2 * sinPitchOver2 * cosRollOver2 - - // sinYawOver2 * cosPitchOver2 * sinRollOver2; - // result.z = cosYawOver2 * cosPitchOver2 * sinRollOver2 - - // sinYawOver2 * sinPitchOver2 * cosRollOver2; - // return result; } /// diff --git a/src/Spherical.cs b/src/Spherical.cs index de06d24..3a76085 100644 --- a/src/Spherical.cs +++ b/src/Spherical.cs @@ -1,23 +1,22 @@ using System; +using System.Collections.Generic; + #if UNITY_5_3_OR_NEWER using Vector3 = UnityEngine.Vector3; #endif -namespace LinearAlgebra -{ +namespace LinearAlgebra { /// /// A spherical vector /// /// This is a struct such that it is a value type and cannot be null - public struct Spherical - { + public struct Spherical { /// /// Create a spherical vector /// /// The distance in meters /// The direction of the vector - public Spherical(float distance, Direction direction) - { + public Spherical(float distance, Direction direction) { this.distance = distance; this.direction = direction; } @@ -29,15 +28,13 @@ namespace LinearAlgebra /// The horizontal angle in degrees /// The vertical angle in degrees /// - public static Spherical Degrees(float distance, float horizontal, float vertical) - { + public static Spherical Degrees(float distance, float horizontal, float vertical) { Direction direction = Direction.Degrees(horizontal, vertical); Spherical s = new(distance, direction); return s; } - public static Spherical Radians(float distance, float horizontal, float vertical) - { + public static Spherical Radians(float distance, float horizontal, float vertical) { Direction direction = Direction.Radians(horizontal, vertical); Spherical s = new(distance, direction); return s; @@ -62,79 +59,19 @@ namespace LinearAlgebra /// public readonly static Spherical forward = new(1, Direction.forward); - - // public static Spherical FromVector3Float(Vector3Float v) { - // float distance = v.magnitude; - // if (distance == 0.0f) - // return Spherical.zero; - // else { - // float verticalAngle = (float)((Angle.pi / 2 - Math.Acos(v.y / distance)) * Angle.Rad2Deg); - // float horizontalAngle = (float)Math.Atan2(v.x, v.z) * Angle.Rad2Deg; - // return Spherical.Degrees(distance, horizontalAngle, verticalAngle); - // } - // } - - public static Spherical FromVector3Float(Vector3Float v) - { - float distance = v.magnitude; - if (distance == 0.0f) - return Spherical.zero; - else - { - float verticalAngle = (float)(Math.PI / 2 - Math.Acos(v.vertical / distance)) * AngleFloat.Rad2Deg; - float horizontalAngle = (float)Math.Atan2(v.horizontal, v.depth) * AngleFloat.Rad2Deg; - return Degrees(distance, horizontalAngle, verticalAngle); - } - } - - // public Vector3Float ToVector3Float() { - // float verticalRad = (Angle.pi / 2) - this.direction.vertical * Angle.Deg2Rad; - // float horizontalRad = this.direction.horizontal * Angle.Deg2Rad; - // float cosVertical = (float)Math.Cos(verticalRad); - // float sinVertical = (float)Math.Sin(verticalRad); - // float cosHorizontal = (float)Math.Cos(horizontalRad); - // float sinHorizontal = (float)Math.Sin(horizontalRad); - - // float x = this.distance * sinVertical * sinHorizontal; - // float y = this.distance * cosVertical; - // float z = this.distance * sinVertical * cosHorizontal; - - // Vector3Float v = new(x, y, z); - // return v; - // } - - public Vector3Float ToVector3Float() - { - float verticalRad = (AngleFloat.deg90 - this.direction.vertical).inRadians; - float horizontalRad = this.direction.horizontal.inRadians; - float cosVertical = (float)Math.Cos(verticalRad); - float sinVertical = (float)Math.Sin(verticalRad); - float cosHorizontal = (float)Math.Cos(horizontalRad); - float sinHorizontal = (float)Math.Sin(horizontalRad); - - float x = this.distance * sinVertical * sinHorizontal; - float y = this.distance * cosVertical; - float z = this.distance * sinVertical * cosHorizontal; - - Vector3Float v = new(x, y, z); - return v; - } #if UNITY_5_3_OR_NEWER - public static Spherical FromVector3(Vector3 v) - { + public static Spherical FromVector3(Vector3 v) { float distance = v.magnitude; if (distance == 0.0f) return Spherical.zero; - else - { + else { float verticalAngle = (float)(Math.PI / 2 - Math.Acos(v.y / distance)) * AngleFloat.Rad2Deg; float horizontalAngle = (float)Math.Atan2(v.x, v.z) * AngleFloat.Rad2Deg; return Degrees(distance, horizontalAngle, verticalAngle); } } - public Vector3 ToVector3() - { + public readonly Vector3 ToVector3() { float verticalRad = (AngleFloat.deg90 - this.direction.vertical).inRadians; float horizontalRad = this.direction.horizontal.inRadians; float cosVertical = (float)Math.Cos(verticalRad); @@ -149,21 +86,40 @@ namespace LinearAlgebra Vector3 v = new(x, y, z); return v; } -#endif - - public float magnitude - { - get - { - return this.distance; +#else + public static Spherical FromVector3(Vector3Float v) { + float distance = v.magnitude; + if (distance == 0.0f) + return Spherical.zero; + else { + float verticalAngle = (float)(Math.PI / 2 - Math.Acos(v.vertical / distance)) * AngleFloat.Rad2Deg; + float horizontalAngle = (float)Math.Atan2(v.horizontal, v.depth) * AngleFloat.Rad2Deg; + return Degrees(distance, horizontalAngle, verticalAngle); } } - public Spherical normalized - { - get - { - Spherical r = new() - { + + public readonly Vector3Float ToVector3() { + float verticalRad = (AngleFloat.deg90 - this.direction.vertical).inRadians; + float horizontalRad = this.direction.horizontal.inRadians; + float cosVertical = (float)Math.Cos(verticalRad); + float sinVertical = (float)Math.Sin(verticalRad); + float cosHorizontal = (float)Math.Cos(horizontalRad); + float sinHorizontal = (float)Math.Sin(horizontalRad); + + float x = this.distance * sinVertical * sinHorizontal; + float y = this.distance * cosVertical; + float z = this.distance * sinVertical * cosHorizontal; + + Vector3Float v = new(x, y, z); + return v; + } +#endif + + public readonly float magnitude => this.distance; + + public Spherical normalized { + get { + Spherical r = new() { distance = 1, direction = this.direction }; @@ -171,15 +127,251 @@ namespace LinearAlgebra } } - public static Spherical operator +(Spherical s1, Spherical s2) - { + public static Spherical operator +(Spherical s1, Spherical s2) { // let's do it the easy way... - Vector3Float v1 = s1.ToVector3Float(); - Vector3Float v2 = s2.ToVector3Float(); - Vector3Float v = v1 + v2; - Spherical r = FromVector3Float(v); + // using vars to be compatible with both unity (Vector3) and native (Vector3Float) + var v1 = s1.ToVector3(); + var v2 = s2.ToVector3(); + var v = v1 + v2; + Spherical r = FromVector3(v); return r; } + public static Spherical operator *(Spherical v, float d) { + Spherical r = new(v.distance * d, v.direction); + return r; + } + + public static bool operator ==(Spherical v1, Spherical v2) { + return (v1.distance == v2.distance && v1.direction == v2.direction); + } + + public static bool operator !=(Spherical v1, Spherical v2) { + return (v1.distance != v2.distance || v1.direction != v2.direction); + } + + public static float Distance(Spherical v1, Spherical v2) { + // Convert degrees to radians + float thetaARadians = v1.direction.horizontal.inRadians; + float phiARadians = v1.direction.vertical.inRadians;// DegreesToRadians(phiA); + float thetaBRadians = v2.direction.horizontal.inRadians; // DegreesToRadians(thetaB); + float phiBRadians = v2.direction.vertical.inRadians; // DegreesToRadians(phiB); + + // Calculate sine and cosine values + float sinPhiA = MathF.Sin(phiARadians); + float cosPhiA = MathF.Cos(phiARadians); + float sinPhiB = MathF.Sin(phiBRadians); + float cosPhiB = MathF.Cos(phiBRadians); + + // Calculate the cosine of the difference in azimuthal angles + float cosThetaDifference = MathF.Cos(thetaARadians - thetaBRadians); + + // Apply the spherical law of cosines + float distance = MathF.Sqrt( + v1.distance * v1.distance + + v2.distance * v2.distance - + 2 * v1.distance * v2.distance * (sinPhiA * sinPhiB * cosThetaDifference + cosPhiA * cosPhiB) + ); + + return distance; + } + + public static Spherical Average(Spherical v1, Spherical v2) { + const float EPS = 1e-6f; + + // Angles in radians + float a1 = v1.direction.horizontal.inRadians; + float a2 = v2.direction.horizontal.inRadians; + float e1 = v1.direction.vertical.inRadians; + float e2 = v2.direction.vertical.inRadians; + + // Fast path: exactly same direction (allowing wrap for azimuth) -> preserve exact angles + bool sameAz = MathF.Abs(MathF.IEEERemainder(a1 - a2, MathF.PI * 2f)) < EPS; + bool sameEl = MathF.Abs(e1 - e2) < EPS; + if (sameAz && sameEl) { + // Distances may differ; average distance but keep exact angles from v1 + float rAvgExact = 0.5f * (v1.distance + v2.distance); + return new Spherical(rAvgExact, v1.direction); + } + + // Horizontal unit-circle sum + float cx = MathF.Cos(a1) + MathF.Cos(a2); + float cy = MathF.Sin(a1) + MathF.Sin(a2); + + // Vertical as z = sin(el) + float z1 = MathF.Sin(e1); + float z2 = MathF.Sin(e2); + float cz = z1 + z2; + + // Magnitude of summed unit-direction vectors + float sumX = cx; + float sumY = cy; + float sumZ = cz; + float magSum = MathF.Sqrt(sumX * sumX + sumY * sumY + sumZ * sumZ); + + // If the two direction unit-vectors cancel (or nearly), return zero distance. + if (magSum < EPS) { + return Spherical.Radians(0f, 0f, 0f); + } + + // Normalized averaged direction components + float ux = sumX / magSum; + float uy = sumY / magSum; + float uz = sumZ / magSum; + + // Compute averaged angles from normalized vector + float azAvgRad = MathF.Atan2(uy, ux); + float elAvgRad = MathF.Asin(Float.Clamp(uz, -1f, 1f)); + + // Average distance (arithmetic mean) + float rAvg = 0.5f * (v1.distance + v2.distance); + + return Spherical.Radians(rAvg, azAvgRad, elAvgRad); + } + + public static Spherical Average(List vectors) { + // float sumSinPhiCosTheta = 0.0f; + // float sumSinPhiSinTheta = 0.0f; + // float sumCosPhi = 0.0f; + + // int n = vectors.Count; + + // // Step 1: Accumulate sine and cosine components + // foreach(Spherical v in vectors) { + // float sinHorizontal = AngleFloat.Sin(v.direction.horizontal); + // sumSinPhiCosTheta += v.distance * sinHorizontal * AngleFloat.Cos(v.direction.vertical); + // sumSinPhiSinTheta += v.distance * sinHorizontal * AngleFloat.Sin(v.direction.vertical); + // sumCosPhi += v.distance * AngleFloat.Cos(v.direction.horizontal); + // } + + // // Step 2: Calculate average components + // float avgSinPhiCosTheta = sumSinPhiCosTheta / n; + // float avgSinPhiSinTheta = sumSinPhiSinTheta / n; + // float avgCosPhi = sumCosPhi / n; + + // // Step 3: Calculate the magnitude of the average vector + // float rAvg = MathF.Sqrt(avgSinPhiCosTheta * avgSinPhiCosTheta + + // avgSinPhiSinTheta * avgSinPhiSinTheta + + // avgCosPhi * avgCosPhi); + + // // Step 4: Calculate average angles + // AngleFloat horizontalAvg = AngleFloat.Acos(avgCosPhi / rAvg); // Handle rAvg != 0 case + // AngleFloat verticalAvg = AngleFloat.Atan2(avgSinPhiSinTheta, avgSinPhiCosTheta); + + // return new Spherical(rAvg, new Direction(horizontalAvg, verticalAvg)); + + if (vectors == null || vectors.Count == 0) + throw new ArgumentException("vectors must contain at least one element", nameof(vectors)); + + float sumX = 0f, sumY = 0f, sumZ = 0f; + int n = vectors.Count; + + foreach (var v in vectors) { + // AngleFloat -> radians; assume AngleFloat provides Radians property + float theta = v.direction.horizontal.inRadians; // azimuth + float phi = v.direction.vertical.inRadians; // elevation + + float cosPhi = MathF.Cos(phi); + float sinPhi = MathF.Sin(phi); + float cosTheta = MathF.Cos(theta); + float sinTheta = MathF.Sin(theta); + + float x = v.distance * cosPhi * cosTheta; + float y = v.distance * cosPhi * sinTheta; + float z = v.distance * sinPhi; + + sumX += x; + sumY += y; + sumZ += z; + } + + float avgX = sumX / n; + float avgY = sumY / n; + float avgZ = sumZ / n; + + float rAvg = MathF.Sqrt(avgX * avgX + avgY * avgY + avgZ * avgZ); + + if (rAvg == 0f) { + return new Spherical(0f, new Direction(AngleFloat.Radians(0f), AngleFloat.Radians(0f))); + } + + // elevation = asin(z / r) + AngleFloat verticalAvg = AngleFloat.Asin(avgZ / rAvg); // -90..90 + // azimuth = atan2(y, x) -> -pi..pi + AngleFloat horizontalAvg = AngleFloat.Atan2(avgY, avgX); // -180..180 + + return new Spherical(rAvg, new Direction(horizontalAvg, verticalAvg)); + } + + +/* + public static Spherical Average(IEnumerable vectors) { + const float EPS = 1e-6f; + if (vectors == null) throw new ArgumentNullException(nameof(vectors)); + + float sumRx = 0f, sumRy = 0f, sumRz = 0f; + float sumDistances = 0f; + int count = 0; + + bool firstSet = false; + float firstAz = 0f, firstEl = 0f; + bool allSameDirection = true; + + foreach (var v in vectors) { + float az = v.direction.horizontal.inRadians; // horizontal (azimuth) + float el = v.direction.vertical.inRadians; // vertical (elevation) + + if (!firstSet) { + firstSet = true; + firstAz = az; + firstEl = el; + } + else { + if (MathF.Abs(MathF.IEEERemainder(az - firstAz, MathF.PI * 2f)) >= EPS || + MathF.Abs(el - firstEl) >= EPS) { + allSameDirection = false; + } + } + + float cosEl = MathF.Cos(el); + float ux = cosEl * MathF.Cos(az); // x + float uy = cosEl * MathF.Sin(az); // y + float uz = MathF.Sin(el); // z + + sumRx += v.distance * ux; + sumRy += v.distance * uy; + sumRz += v.distance * uz; + + sumDistances += v.distance; + count++; + } + + if (count == 0) throw new ArgumentException("Sequence contains no elements", nameof(vectors)); + + // All directions equal -> preserve exact angles, average distance + if (allSameDirection) { + float rAvg = sumDistances / count; + return new Spherical(rAvg, Direction.Radians(firstAz, firstEl)); + } + + // Total vector sum V + float Vx = sumRx; + float Vy = sumRy; + float Vz = sumRz; + float Vmag = MathF.Sqrt(Vx * Vx + Vy * Vy + Vz * Vz); + + if (Vmag < EPS) { + // Directions cancel out -> zero distance, angles arbitrary + return Spherical.Radians(0f, 0f, 0f); + } + + float azAvg = MathF.Atan2(Vy, Vx); + float elAvg = MathF.Asin(Float.Clamp(Vz / Vmag, -1f, 1f)); + float rAvgFinal = Vmag / count; + + return Spherical.Radians(rAvgFinal, azAvg, elAvg); + } +*/ + } } \ No newline at end of file diff --git a/src/SwingTwist.cs b/src/SwingTwist.cs index 4437c4f..df6e048 100644 --- a/src/SwingTwist.cs +++ b/src/SwingTwist.cs @@ -1,6 +1,6 @@ -#if !UNITY_5_3_OR_NEWER -using UnityEngine; -#endif +// #if !UNITY_5_3_OR_NEWER +// using UnityEngine; +// #endif namespace LinearAlgebra { @@ -46,7 +46,45 @@ namespace LinearAlgebra { return s; } -#if !UNITY_5_3_OR_NEWER +#if UNITY_5_3_OR_NEWER + /// + /// A zero angle rotation + /// + public static readonly SwingTwist zero = Degrees(0, 0, 0); + + public Spherical ToAngleAxis() { + UnityEngine.Quaternion q = this.ToQuaternion(); + q.ToAngleAxis(out float angle, out UnityEngine.Vector3 axis); + Direction direction = Direction.FromVector3(axis); + + Spherical r = new(angle, direction); + return r; + } + + public static SwingTwist FromAngleAxis(Spherical r) { + UnityEngine.Vector3 vectorAxis = r.direction.ToVector3(); + UnityEngine.Quaternion q = UnityEngine.Quaternion.AngleAxis(r.distance, vectorAxis); + return FromQuaternion(q); + } + + /// + /// Convert a quaternion in a swing/twist rotation + /// + /// The quaternion to convert + /// The swing/twist rotation + public static SwingTwist FromQuaternion(UnityEngine.Quaternion q) { + UnityEngine.Vector3 angles = q.eulerAngles; + SwingTwist r = Degrees(angles.y, -angles.x, -angles.z); + return r; + } + + public UnityEngine.Quaternion ToQuaternion() { + UnityEngine.Quaternion q = UnityEngine.Quaternion.Euler(this.swing.vertical.inDegrees, + this.swing.horizontal.inDegrees, + this.twist.inDegrees); + return q; + } +#else /// /// A zero angle rotation /// @@ -92,25 +130,7 @@ namespace LinearAlgebra { return r; } #endif -#if UNITY_5_3_OR_NEWER - /// - /// Convert a quaternion in a swing/twist rotation - /// - /// The quaternion to convert - /// The swing/twist rotation - public static SwingTwist FromQuaternion(UnityEngine.Quaternion q) { - UnityEngine.Vector3 angles = q.eulerAngles; - SwingTwist r = Degrees(angles.y, -angles.x, -angles.z); - return r; - } - - public UnityEngine.Quaternion ToUnityQuaternion() { - UnityEngine.Quaternion q = UnityEngine.Quaternion.Euler(this.swing.vertical.inDegrees, - this.swing.horizontal.inDegrees, - this.twist.inDegrees); - return q; - } -#endif + } } \ No newline at end of file diff --git a/src/Vector2Float.cs b/src/Vector2Float.cs index e0418a8..ac1867c 100644 --- a/src/Vector2Float.cs +++ b/src/Vector2Float.cs @@ -324,27 +324,13 @@ namespace LinearAlgebra { public static Vector2Float Scale(Vector2Float v1, Vector2Float v2) { return new Vector2Float(v1.horizontal * v2.horizontal, v1.vertical * v2.vertical); } - - /* + /// /// Tests if the vector has equal values as the given vector /// /// The vector to compare to /// true if the vector values are equal - public bool Equals(Vector2Float v1) => horizontal == v1.horizontal && vertical == v1.vertical; - - /// - /// Tests if the vector is equal to the given object - /// - /// The object to compare to - /// false when the object is not a Vector2 or does not have equal values - public override bool Equals(object obj) { - if (!(obj is Vector2Float v)) - return false; - - return (horizontal == v.horizontal && vertical == v.vertical); - } - */ + //public readonly bool Equals(Vector2Float v1) => horizontal == v1.horizontal && vertical == v1.vertical; /// /// Tests if the two vectors have equal values @@ -372,15 +358,25 @@ namespace LinearAlgebra { return (v1.horizontal != v2.horizontal || v1.vertical != v2.vertical); } - /* + /// + /// Tests if the vector is equal to the given object + /// + /// The object to compare to + /// false when the object is not a Vector2 or does not have equal values + public override readonly bool Equals(object obj) { + if (obj is not Vector2Float v) + return false; + + return (horizontal == v.horizontal && vertical == v.vertical); + } + /// /// Get an hash code for the vector /// /// The hash code - public override int GetHashCode() { - return (horizontal, vertical).GetHashCode(); + public override readonly int GetHashCode() { + return HashCode.Combine(horizontal, vertical); } - */ /// /// Get the distance between two vectors diff --git a/src/Vector2Int.cs b/src/Vector2Int.cs index 0eca7dc..ed68e8b 100644 --- a/src/Vector2Int.cs +++ b/src/Vector2Int.cs @@ -60,17 +60,6 @@ namespace LinearAlgebra { /// true if the vector values are equal public readonly bool Equals(Vector2Int v) => this.horizontal == v.horizontal && vertical == v.vertical; - /// - /// Tests if the vector is equal to the given object - /// - /// The object to compare to - /// false when the object is not a Vector2 or does not have equal values - public override readonly bool Equals(object obj) { - if (obj is not Vector2Int v) - return false; - - return (this.horizontal == v.horizontal && this.vertical == v.vertical); - } */ /// @@ -98,6 +87,26 @@ namespace LinearAlgebra { return (v1.horizontal != v2.horizontal || v1.vertical != v2.vertical); } + /// + /// Tests if the vector is equal to the given object + /// + /// The object to compare to + /// false when the object is not a Vector2 or does not have equal values + public override readonly bool Equals(object obj) { + if (obj is not Vector2Int v) + return false; + + return (this.horizontal == v.horizontal && this.vertical == v.vertical); + } + + /// + /// Get an hash code for the vector + /// + /// The hash code + public override readonly int GetHashCode() { + return HashCode.Combine(horizontal, vertical); + } + public readonly float sqrMagnitude => this.horizontal * this.horizontal + this.vertical * this.vertical; public static float SqrMagnitudeOf(Vector2Int v) { diff --git a/src/Vector3Float.cs b/src/Vector3Float.cs index bff0936..d8208d3 100644 --- a/src/Vector3Float.cs +++ b/src/Vector3Float.cs @@ -250,30 +250,22 @@ namespace LinearAlgebra { public static Vector3Float operator *(Vector3Float v1, float d) { - Vector3Float v = new Vector3Float(v1.horizontal * d, v1.vertical * d, v1.depth * d); + Vector3Float v = new(v1.horizontal * d, v1.vertical * d, v1.depth * d); return v; } public static Vector3Float operator *(float d, Vector3Float v1) { - Vector3Float v = new Vector3Float(d * v1.horizontal, d * v1.vertical, d * v1.depth); + Vector3Float v = new(d * v1.horizontal, d * v1.vertical, d * v1.depth); return v; } public static Vector3Float operator /(Vector3Float v1, float d) { - Vector3Float v = new Vector3Float(v1.horizontal / d, v1.vertical / d, v1.depth / d); + Vector3Float v = new(v1.horizontal / d, v1.vertical / d, v1.depth / d); return v; } - /* - public bool Equals(Vector3Float v) => (horizontal == v.horizontal && vertical == v.vertical && depth == v.depth); - - public override bool Equals(object obj) { - if (!(obj is Vector3Float v)) - return false; - - return (horizontal == v.horizontal && vertical == v.vertical && depth == v.depth); - } - */ + + //public bool Equals(Vector3Float v) => (horizontal == v.horizontal && vertical == v.vertical && depth == v.depth); public static bool operator ==(Vector3Float v1, Vector3Float v2) { return (v1.horizontal == v2.horizontal && v1.vertical == v2.vertical && v1.depth == v2.depth); @@ -283,9 +275,16 @@ namespace LinearAlgebra { return (v1.horizontal != v2.horizontal || v1.vertical != v2.vertical || v1.depth != v2.depth); } - // public override int GetHashCode() { - // return (horizontal, vertical, depth).GetHashCode(); - // } + public override readonly bool Equals(object obj) { + if (obj is not Vector3Float v) + return false; + + return (horizontal == v.horizontal && vertical == v.vertical && depth == v.depth); + } + + public override readonly int GetHashCode() { + return HashCode.Combine(horizontal, vertical, depth); + } /// @brief The distance between two vectors /// @param v1 The first vector diff --git a/test/AngleTest.cs b/test/AngleTest.cs index 787130d..8362d82 100644 --- a/test/AngleTest.cs +++ b/test/AngleTest.cs @@ -24,6 +24,10 @@ namespace LinearAlgebra.Test { a = AngleFloat.Degrees(angle); Assert.AreEqual(-90, a.inDegrees); + angle = -270.0f; + a = AngleFloat.Degrees(angle); + Assert.AreEqual(90, a.inDegrees); + // Radians angle = 0.0f; a = AngleFloat.Radians(angle); diff --git a/test/DirectionTest.cs b/test/DirectionTest.cs index 146c9df..8fe3b93 100644 --- a/test/DirectionTest.cs +++ b/test/DirectionTest.cs @@ -33,6 +33,13 @@ namespace LinearAlgebra.Test { Assert.AreEqual(30, d.vertical.inDegrees, 0.0001f); } + [Test] + public void DegreesNormalize1() { + Direction d = Direction.Degrees(112, 91); + Assert.AreEqual(-68, d.horizontal.inDegrees, 0.0001f); + Assert.AreEqual(89, d.vertical.inDegrees, 0.0001f); + } + [Test] public void RadiansEquivalentToDegreesConversion() { Direction d1 = Direction.Radians((float)Math.PI / 3, (float)Math.PI / 4); @@ -68,6 +75,15 @@ namespace LinearAlgebra.Test { Assert.AreEqual(0, v.depth, 0.0001f); } + [Test] + public void ToVector3Left() { + Direction d = Direction.left; + Vector3Float v = d.ToVector3(); + Assert.AreEqual(-1, v.horizontal, 0.0001f); + Assert.AreEqual(0, v.vertical, 0.0001f); + Assert.AreEqual(0, v.depth, 0.0001f); + } + [Test] public void FromVector3Forward() { Vector3Float v = new(0, 0, 1); @@ -85,6 +101,15 @@ namespace LinearAlgebra.Test { Assert.AreEqual(d1.vertical.inDegrees, d2.vertical.inDegrees, 0.0001f); } + [Test] + public void ToVector3AndBack2() { + Direction d1 = Direction.Degrees(135, 85); + Vector3Float v = d1.ToVector3(); + Direction d2 = Direction.FromVector3(v); + Assert.AreEqual(d1.horizontal.inDegrees, d2.horizontal.inDegrees, 0.0001f); + Assert.AreEqual(d1.vertical.inDegrees, d2.vertical.inDegrees, 0.0001f); + } + [Test] public void Compare() { Direction d1 = Direction.Degrees(45, 135); diff --git a/test/SphericalTest.cs b/test/SphericalTest.cs index 125cdb1..d7553dd 100644 --- a/test/SphericalTest.cs +++ b/test/SphericalTest.cs @@ -1,5 +1,6 @@ #if !UNITY_5_6_OR_NEWER using System; +using System.Collections.Generic; using NUnit.Framework; namespace LinearAlgebra.Test { @@ -48,6 +49,191 @@ namespace LinearAlgebra.Test { Assert.AreEqual(45.0f, r.direction.horizontal.inDegrees, "Addition(1 0 90)"); Assert.AreEqual(45.0f, r.direction.vertical.inDegrees, 1.0E-05F, "Addition(1 0 90)"); } + + [Test] + public void Average2_IdenticalVectors() { + Direction dir = Direction.Radians(MathF.PI / 4f, MathF.PI / 6f); + Spherical v = new(2.5f, dir); + + Spherical avg = Spherical.Average(v, v); + + Assert.AreEqual(2.5f, avg.distance, 1e-5f); + Assert.AreEqual(dir.horizontal, avg.direction.horizontal); + Assert.AreEqual(dir.vertical, avg.direction.vertical); + } + + [Test] + public void Average2_OppositeUnitVectors() { + // Two opposite vectors: same distance, horizontal opposite (pi apart), same vertical + Spherical v1 = Spherical.Radians(1f, 0f, 0f); + Spherical v2 = Spherical.Radians(1f, MathF.PI, 0f); + Spherical avg = Spherical.Average(v1, v2); + + Assert.AreEqual(0f, avg.distance, 1e-4f); + // When distance is zero, angles may be undefined; allow any angle but ensure near-zero magnitude + } + + [Test] + public void Average2_WeightedByDistance() { + // Two vectors same direction but different distances -> weighted average distance + Direction dir = Direction.Radians(MathF.PI / 3f, MathF.PI / 4f); + Spherical a = new(1f, dir); + Spherical b = new(3f, dir); + Spherical avg = Spherical.Average(a, b); + + // average distance should be (1+3)/2 = 2 + Assert.AreEqual(2f, avg.distance, 1e-5f); + Assert.AreEqual(dir.horizontal.inRadians, avg.direction.horizontal.inRadians, 1e-5f); + Assert.AreEqual(dir.vertical.inRadians, avg.direction.vertical.inRadians, 1e-5f); + } + + [Test] + public void Average2_OppositeButNotExact_NotZero() { + // Nearly opposite but not exact; expect a valid averaged direction and averaged distance + Direction d1 = Direction.Radians(0f, 0f); + Direction d2 = Direction.Radians(MathF.PI - 1e-3f, 0.0f); // slight offset + Spherical v1 = new(2.0f, d1); + Spherical v2 = new(4.0f, d2); + + Spherical avg = Spherical.Average(v1, v2); + + // Distance is arithmetic mean + Assert.AreEqual(3.0f, avg.distance, 1e-5f); + + // Averaged azimuth should be near +pi/2 or -pi/2? we can check it's not NaN and unit-vector properties hold + float ux = MathF.Cos(avg.direction.horizontal.inRadians) * MathF.Cos(avg.direction.vertical.inRadians); + float uy = MathF.Sin(avg.direction.horizontal.inRadians) * MathF.Cos(avg.direction.vertical.inRadians); + float uz = MathF.Sin(avg.direction.vertical.inRadians); + float mag = MathF.Sqrt(ux * ux + uy * uy + uz * uz); + Assert.IsTrue(mag > 0.999f && mag < 1.001f); + + } + + [Test] + public void Average2_BasicAverageDirectionAndDistance() { + // Two different directions not cancelling: expect vector-average result + Direction d1 = Direction.Radians(MathF.PI / 6f, MathF.PI / 12f); // 30°, 15° + Direction d2 = Direction.Radians(MathF.PI / 3f, MathF.PI / 18f); // 60°, 10° + Spherical v1 = new(2.0f, d1); + Spherical v2 = new(4.0f, d2); + + Spherical avg = Spherical.Average(v1, v2); + + // Distance is arithmetic mean + Assert.AreEqual(3.0f, avg.distance, 1e-5f); + + // Check averaged unit-vector equals normalized sum of unit vectors computed here + float a1 = d1.horizontal.inRadians; + float a2 = d2.horizontal.inRadians; + float e1 = d1.vertical.inRadians; + float e2 = d2.vertical.inRadians; + + float cx = MathF.Cos(a1) + MathF.Cos(a2); + float cy = MathF.Sin(a1) + MathF.Sin(a2); + float z1 = MathF.Sin(e1); + float z2 = MathF.Sin(e2); + float cz = z1 + z2; + float mag = MathF.Sqrt(cx * cx + cy * cy + cz * cz); + Assert.IsTrue(mag > 1e-6f); + + float ux = cx / mag; + float uy = cy / mag; + float uz = cz / mag; + + // Reconstruct direction from avg result + float uxAvg = MathF.Cos(avg.direction.horizontal.inRadians) * MathF.Cos(avg.direction.vertical.inRadians); + float uyAvg = MathF.Sin(avg.direction.horizontal.inRadians) * MathF.Cos(avg.direction.vertical.inRadians); + float uzAvg = MathF.Sin(avg.direction.vertical.inRadians); + + Assert.AreEqual(ux, uxAvg, 1e-4f); + Assert.AreEqual(uy, uyAvg, 1e-4f); + Assert.AreEqual(uz, uzAvg, 1e-4f); + } + + [Test] + public void Average_IdenticalVectors() { + var dir = Direction.Radians(MathF.PI / 4f, MathF.PI / 6f); + var v = new Spherical(2.5f, dir); + var list = new List { v, v, v }; + + var avg = Spherical.Average(list); + + Assert.AreEqual(2.5f, avg.distance, 1e-5f); + Assert.AreEqual(dir.horizontal, avg.direction.horizontal); + Assert.AreEqual(dir.vertical, avg.direction.vertical); + } + + [Test] + public void Average_SingleElement() { + Spherical s = Spherical.Radians(1.234f, 0.3f, -0.7f); + Spherical avg = Spherical.Average([s]); + + Assert.AreEqual(s.distance, avg.distance, 1e-5f); + Assert.AreEqual(s.direction.horizontal.inRadians, avg.direction.horizontal.inRadians, 1e-5f); + Assert.AreEqual(s.direction.vertical.inRadians, avg.direction.vertical.inRadians, 1e-5f); + } + + [Test] + public void Average_OppositeUnitVectors() { + // Two opposite vectors: same distance, horizontal opposite (pi apart), same vertical + Spherical v1 = Spherical.Radians(1f, 0f, 0f); + Spherical v2 = Spherical.Radians(1f, MathF.PI, 0f); + Spherical avg = Spherical.Average([v1, v2]); + + Assert.AreEqual(0f, avg.distance, 1e-4f); + // When distance is zero, angles may be undefined; allow any angle but ensure near-zero magnitude + } + + [Test] + public void Average_WeightedByDistance() { + // Two vectors same direction but different distances -> weighted average distance + Direction dir = Direction.Radians(MathF.PI / 3f, MathF.PI / 4f); + Spherical a = new(1f, dir); + Spherical b = new(3f, dir); + Spherical avg = Spherical.Average([a, b]); + + // average distance should be (1+3)/2 = 2 + Assert.AreEqual(2f, avg.distance, 1e-5f); + Assert.AreEqual(dir.horizontal.inRadians, avg.direction.horizontal.inRadians, 1e-5f); + Assert.AreEqual(dir.vertical.inRadians, avg.direction.vertical.inRadians, 1e-5f); + } + + [Test] + public void Average_AxisSymmetricAroundVertical() { + // Four vectors around azimuth 0, pi/2, pi, 3pi/2 at same elevation (vertical) angle phi + float phi = MathF.PI / 6f; // elevation from horizontal plane + var dirs = new List { + new(1f, Direction.Radians(0f, phi)), + new(1f, Direction.Radians(MathF.PI/2, phi)), + new(1f, Direction.Radians(MathF.PI, phi)), + new(1f, Direction.Radians(3*MathF.PI/2, phi)) + }; + + Spherical avg = Spherical.Average(dirs); + + // rAvg should equal r * sin(elevation) = sin(phi) + Assert.AreEqual(MathF.Sin(phi), avg.distance, 1e-4f); + // vertical angle undefined when horizontal xy components cancel; allow any angle but ensure r matches + } + + [Test] + public void Average_AxisSymmetricAroundVertical2() { + // Four vectors around azimuth 0, pi/2, pi, 3pi/2 at same polar angle from vertical (alpha) + float alpha = MathF.PI / 6f; // polar angle from vertical + float elevation = MathF.PI / 2f - alpha; // convert polar-from-vertical to elevation + var dirs = new List { + new(1f, Direction.Radians(0f, elevation)), + new(1f, Direction.Radians(MathF.PI/2, elevation)), + new(1f, Direction.Radians(MathF.PI, elevation)), + new(1f, Direction.Radians(3*MathF.PI/2, elevation)) + }; + + Spherical avg = Spherical.Average(dirs); + + // rAvg should equal r * sin(elevation) which equals cos(alpha) + Assert.AreEqual(MathF.Cos(alpha), avg.distance, 1e-4f); + } + } } #endif \ No newline at end of file From ccf0b16136ee6997a847561735dda571bdafdade Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 7 Jan 2026 12:21:12 +0100 Subject: [PATCH 048/179] Fixed Spherical.ToVector3 --- .../NanoBrain/LinearAlgebra/src/Spherical.cs | 59 +++++++++++-------- Assets/NanoBrain/Neuroid.cs | 32 ++++++---- 2 files changed, 54 insertions(+), 37 deletions(-) diff --git a/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs b/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs index 3a76085..0b7c8b4 100644 --- a/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs +++ b/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs @@ -72,18 +72,22 @@ namespace LinearAlgebra { } public readonly Vector3 ToVector3() { - float verticalRad = (AngleFloat.deg90 - this.direction.vertical).inRadians; - float horizontalRad = this.direction.horizontal.inRadians; - float cosVertical = (float)Math.Cos(verticalRad); - float sinVertical = (float)Math.Sin(verticalRad); - float cosHorizontal = (float)Math.Cos(horizontalRad); - float sinHorizontal = (float)Math.Sin(horizontalRad); + // float verticalRad = (AngleFloat.deg90 - this.direction.vertical).inRadians; + // float horizontalRad = this.direction.horizontal.inRadians; + // float cosVertical = (float)Math.Cos(verticalRad); + // float sinVertical = (float)Math.Sin(verticalRad); + // float cosHorizontal = (float)Math.Cos(horizontalRad); + // float sinHorizontal = (float)Math.Sin(horizontalRad); - float x = this.distance * sinVertical * sinHorizontal; - float y = this.distance * cosVertical; - float z = this.distance * sinVertical * cosHorizontal; + // float x = this.distance * sinVertical * sinHorizontal; + // float y = this.distance * cosVertical; + // float z = this.distance * sinVertical * cosHorizontal; - Vector3 v = new(x, y, z); + // Vector3 v = new(x, y, z); + // return v; + + Vector3 v = this.direction.ToVector3(); + v *= this.distance; return v; } #else @@ -99,22 +103,29 @@ namespace LinearAlgebra { } public readonly Vector3Float ToVector3() { - float verticalRad = (AngleFloat.deg90 - this.direction.vertical).inRadians; - float horizontalRad = this.direction.horizontal.inRadians; - float cosVertical = (float)Math.Cos(verticalRad); - float sinVertical = (float)Math.Sin(verticalRad); - float cosHorizontal = (float)Math.Cos(horizontalRad); - float sinHorizontal = (float)Math.Sin(horizontalRad); + // float verticalRad = (AngleFloat.deg90 - this.direction.vertical).inRadians; + // float horizontalRad = this.direction.horizontal.inRadians; + // float cosVertical = (float)Math.Cos(verticalRad); + // float sinVertical = (float)Math.Sin(verticalRad); + // float cosHorizontal = (float)Math.Cos(horizontalRad); + // float sinHorizontal = (float)Math.Sin(horizontalRad); - float x = this.distance * sinVertical * sinHorizontal; - float y = this.distance * cosVertical; - float z = this.distance * sinVertical * cosHorizontal; + // float x = this.distance * sinVertical * sinHorizontal; + // float y = this.distance * cosVertical; + // float z = this.distance * sinVertical * cosHorizontal; - Vector3Float v = new(x, y, z); + // Vector3Float v = new(x, y, z); + Vector3Float v = this.direction.ToVector3(); + v *= this.distance; return v; } #endif + public override readonly string ToString() { + return $"Spherical(h: {this.direction.horizontal}, v: {this.direction.vertical}, distance: {this.distance})"; + } + + public readonly float magnitude => this.distance; public Spherical normalized { @@ -228,7 +239,7 @@ namespace LinearAlgebra { return Spherical.Radians(rAvg, azAvgRad, elAvgRad); } - + /* public static Spherical Average(List vectors) { // float sumSinPhiCosTheta = 0.0f; // float sumSinPhiSinTheta = 0.0f; @@ -302,9 +313,9 @@ namespace LinearAlgebra { return new Spherical(rAvg, new Direction(horizontalAvg, verticalAvg)); } - + */ + -/* public static Spherical Average(IEnumerable vectors) { const float EPS = 1e-6f; if (vectors == null) throw new ArgumentNullException(nameof(vectors)); @@ -371,7 +382,7 @@ namespace LinearAlgebra { return Spherical.Radians(rAvgFinal, azAvg, elAvg); } -*/ + } } \ No newline at end of file diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index 301ce03..e0ba72f 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -87,27 +87,33 @@ public class Neuroid : Nucleus { float activatedValue = curve.Evaluate(synapseNucleus.outputValue.magnitude); float magnitude = weight * activatedValue; //Debug.Log($"{this.name} {synapseNucleus.outputValue.direction} {synapseNucleus.outputValue.direction.horizontal}{synapseNucleus.outputValue.direction.vertical} {direction}"); - - resultVector += direction * magnitude; + Vector3 a = direction * magnitude; + //Debug.Log($"A {direction} {magnitude} {a}"); + resultVector += a; } if (average && this.synapses.Count > 0) resultVector /= this.synapses.Count; Spherical result = Spherical.FromVector3(resultVector); - // List vectors = new(); - // foreach (Synapse synapse in this.synapses) { - // if (synapse.nucleus.isSleeping) - // continue; + List vectors = new(); + foreach (Synapse synapse in this.synapses) { + if (synapse.nucleus.isSleeping) + continue; - // vectors.Add(synapse.nucleus.outputValue); - // } - // Spherical result2 = Spherical.Average(vectors); - // if (average == false) - // result2 *= vectors.Count; + float weight = synapse.weight; + float activatedValue = curve.Evaluate(synapse.nucleus.outputValue.magnitude); + float magnitude = weight * activatedValue; + Spherical vector = new(magnitude, synapse.nucleus.outputValue.direction); + //Debug.Log($"B {synapse.nucleus.outputValue.direction.ToVector3()} {magnitude} {vector.ToVector3()}"); + vectors.Add(vector); //synapse.nucleus.outputValue); + } + Spherical result2 = Spherical.Average(vectors); + if (average == false) + result2 *= vectors.Count; - // if (result2 != result) - // Debug.Log($"update error {result2} != {result}"); + if (result2 != result) + Debug.Log($"update error {result2} != {result}"); UpdateResult(result); From 19318796daa357ba758ce5e487f7b8db6e7d42a2 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 7 Jan 2026 14:30:54 +0100 Subject: [PATCH 049/179] Fix direction To Unity Vector3 --- .../NanoBrain/LinearAlgebra/src/Direction.cs | 8 ++- .../NanoBrain/LinearAlgebra/src/Spherical.cs | 16 +++-- Assets/NanoBrain/Neuroid.cs | 70 +++++++++++++++---- 3 files changed, 69 insertions(+), 25 deletions(-) diff --git a/Assets/NanoBrain/LinearAlgebra/src/Direction.cs b/Assets/NanoBrain/LinearAlgebra/src/Direction.cs index 7047da6..a1ff8f3 100644 --- a/Assets/NanoBrain/LinearAlgebra/src/Direction.cs +++ b/Assets/NanoBrain/LinearAlgebra/src/Direction.cs @@ -127,9 +127,11 @@ namespace LinearAlgebra // Calculate Vector float cosV = MathF.Cos(radV); - float x = cosV * MathF.Cos(radH); - float y = MathF.Sin(radV); - float z = cosV * MathF.Sin(radH); + float sinV = MathF.Sin(radV); + + float x = cosV * MathF.Sin(radH); + float y = sinV; + float z = cosV * MathF.Cos(radH); return new UnityEngine.Vector3(x, y, z); } diff --git a/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs b/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs index 0b7c8b4..996232c 100644 --- a/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs +++ b/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs @@ -62,13 +62,15 @@ namespace LinearAlgebra { #if UNITY_5_3_OR_NEWER public static Spherical FromVector3(Vector3 v) { float distance = v.magnitude; - if (distance == 0.0f) - return Spherical.zero; - else { - float verticalAngle = (float)(Math.PI / 2 - Math.Acos(v.y / distance)) * AngleFloat.Rad2Deg; - float horizontalAngle = (float)Math.Atan2(v.x, v.z) * AngleFloat.Rad2Deg; - return Degrees(distance, horizontalAngle, verticalAngle); - } + // if (distance == 0.0f) + // return Spherical.zero; + // else { + // float verticalAngle = (float)(Math.PI / 2 - Math.Acos(v.y / distance)) * AngleFloat.Rad2Deg; + // float horizontalAngle = (float)Math.Atan2(v.x, v.z) * AngleFloat.Rad2Deg; + // return Degrees(distance, horizontalAngle, verticalAngle); + // } + Direction direction = Direction.FromVector3(v.normalized); + return new Spherical(distance, direction); } public readonly Vector3 ToVector3() { diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index e0ba72f..71e48e7 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -75,7 +75,26 @@ public class Neuroid : Nucleus { } public override void UpdateState() { - Vector3 resultVector = Vector3.zero; + // Vector3 resultVector = Vector3.zero; + // foreach (Synapse synapse in this.synapses) { + // Nucleus synapseNucleus = synapse.nucleus; + // if (synapseNucleus is Neuroid neuroid && neuroid.isSleeping) + // continue; + + // Vector3 direction = synapseNucleus.outputValue.direction.ToVector3(); + + // float weight = synapse.weight; + // float activatedValue = curve.Evaluate(synapseNucleus.outputValue.magnitude); + // float magnitude = weight * activatedValue; + // //Debug.Log($"{this.name} {synapseNucleus.outputValue.direction} {synapseNucleus.outputValue.direction.horizontal}{synapseNucleus.outputValue.direction.vertical} {direction}"); + // Vector3 a = direction * magnitude; + // //Debug.Log($"A {direction} {magnitude} {a}"); + // resultVector += a; + // } + // if (average && this.synapses.Count > 0) + // resultVector /= this.synapses.Count; + /* + List v3s = new(); foreach (Synapse synapse in this.synapses) { Nucleus synapseNucleus = synapse.nucleus; if (synapseNucleus is Neuroid neuroid && neuroid.isSleeping) @@ -89,34 +108,55 @@ public class Neuroid : Nucleus { //Debug.Log($"{this.name} {synapseNucleus.outputValue.direction} {synapseNucleus.outputValue.direction.horizontal}{synapseNucleus.outputValue.direction.vertical} {direction}"); Vector3 a = direction * magnitude; //Debug.Log($"A {direction} {magnitude} {a}"); - resultVector += a; + v3s.Add(a); } - if (average && this.synapses.Count > 0) - resultVector /= this.synapses.Count; + Vector3 sum = Vector3.zero; // Start with a zero vector - Spherical result = Spherical.FromVector3(resultVector); + // Sum all vectors + foreach (Vector3 vector in v3s) + sum += vector; - List vectors = new(); + // Calculate average + Vector3 averagevs = sum / v3s.Count; + Vector3 result1 = averagevs * v3s.Count; + // if (average && this.synapses.Count > 0) + // resultVector /= this.synapses.Count; + + Spherical result = Spherical.FromVector3(result1); + */ + List sVectors = new(); + List cVectors = new(); foreach (Synapse synapse in this.synapses) { if (synapse.nucleus.isSleeping) continue; - + float weight = synapse.weight; float activatedValue = curve.Evaluate(synapse.nucleus.outputValue.magnitude); float magnitude = weight * activatedValue; - Spherical vector = new(magnitude, synapse.nucleus.outputValue.direction); + Spherical sVector = new(magnitude, synapse.nucleus.outputValue.direction); //Debug.Log($"B {synapse.nucleus.outputValue.direction.ToVector3()} {magnitude} {vector.ToVector3()}"); - vectors.Add(vector); //synapse.nucleus.outputValue); + sVectors.Add(sVector); //synapse.nucleus.outputValue); + + Vector3 direction = synapse.nucleus.outputValue.direction.ToVector3(); + Vector3 cVector = direction * magnitude; + cVectors.Add(cVector); } - Spherical result2 = Spherical.Average(vectors); + Vector3 cResult = Vector3.zero; + foreach (Vector3 vector in cVectors) + cResult += vector; + + Spherical sResult = Spherical.Average(sVectors); if (average == false) - result2 *= vectors.Count; + sResult *= sVectors.Count; - if (result2 != result) - Debug.Log($"update error {result2} != {result}"); + if (sResult != Spherical.FromVector3(cResult)) + Debug.Log($"spherical different {sResult} != {Spherical.FromVector3(cResult)}"); + //if (sResult.ToVector3() != cResult) + Debug.Log($"vector different {sResult.ToVector3()} != {cResult}"); + + + UpdateResult(Spherical.FromVector3(cResult)); - UpdateResult(result); - } } From 1855aa0705deb54be7886fd6572bf186365559a6 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 7 Jan 2026 14:33:10 +0100 Subject: [PATCH 050/179] Squashed 'Assets/NanoBrain/LinearAlgebra/' changes from 672f8bf..a0bbb5b a0bbb5b Improve unit tests f3044db Add more ToString e64eaa2 Fix direction To Unity Vector3 3bcd212 Fixed Spherical.ToVector3 a232385 Merge commit '841d923fed686700610a85aeab6289e44239aa6c' git-subtree-dir: Assets/NanoBrain/LinearAlgebra git-subtree-split: a0bbb5b5dd2e938be6d8a516bb69eb1130c4a51d --- src/Angle.cs | 2 +- src/Direction.cs | 50 +++++++++++++++++++---------- src/Spherical.cs | 75 +++++++++++++++++++++++++------------------ src/Vector3Float.cs | 4 +++ test/DirectionTest.cs | 2 +- test/SphericalTest.cs | 24 ++++++++++++++ 6 files changed, 107 insertions(+), 50 deletions(-) diff --git a/src/Angle.cs b/src/Angle.cs index 70f5b10..7d2fd6b 100644 --- a/src/Angle.cs +++ b/src/Angle.cs @@ -57,7 +57,7 @@ namespace LinearAlgebra { public readonly float inRevolutions => this.value / 360.0f; public override string ToString() { - return $"{this.inDegrees} deg."; + return $"{this.inDegrees}\u00B0"; } public static readonly AngleFloat zero = Degrees(0); diff --git a/src/Direction.cs b/src/Direction.cs index 9293503..a1ff8f3 100644 --- a/src/Direction.cs +++ b/src/Direction.cs @@ -3,7 +3,8 @@ using System; using Vector3Float = UnityEngine.Vector3; #endif -namespace LinearAlgebra { +namespace LinearAlgebra +{ /// /// A direction in 3D space @@ -16,7 +17,8 @@ namespace LinearAlgebra { /// rotation has been applied. /// The angles are automatically normalized to stay within the abovenmentioned /// ranges. - public struct Direction { + public struct Direction + { /// @brief horizontal angle, range = (-180..180] degrees public AngleFloat horizontal; /// @brief vertical angle, range in degrees = (-90..90] degrees @@ -29,7 +31,8 @@ namespace LinearAlgebra { /// The vertical angle /// The direction will be normalized automatically /// to ensure the angles are within the allowed ranges - public Direction(AngleFloat horizontal, AngleFloat vertical) { + public Direction(AngleFloat horizontal, AngleFloat vertical) + { this.horizontal = horizontal; this.vertical = vertical; this.Normalize(); @@ -43,8 +46,10 @@ namespace LinearAlgebra { /// The direction /// The direction will be normalized automatically /// to ensure the angles are within the allowed ranges - public static Direction Degrees(float horizontal, float vertical) { - Direction d = new() { + public static Direction Degrees(float horizontal, float vertical) + { + Direction d = new() + { horizontal = AngleFloat.Degrees(horizontal), vertical = AngleFloat.Degrees(vertical) }; @@ -57,8 +62,10 @@ namespace LinearAlgebra { /// The horizontal angle in radians /// The vertical angle in radians /// The direction - public static Direction Radians(float horizontal, float vertical) { - Direction d = new() { + public static Direction Radians(float horizontal, float vertical) + { + Direction d = new() + { horizontal = AngleFloat.Radians(horizontal), vertical = AngleFloat.Radians(vertical) }; @@ -99,8 +106,10 @@ namespace LinearAlgebra { /// public readonly static Direction right = Degrees(90, 0); - private void Normalize() { - if (this.vertical > AngleFloat.deg90 || this.vertical < -AngleFloat.deg90) { + private void Normalize() + { + if (this.vertical > AngleFloat.deg90 || this.vertical < -AngleFloat.deg90) + { this.horizontal += AngleFloat.deg180; this.vertical = AngleFloat.Degrees(180 - this.vertical.inDegrees); } @@ -118,9 +127,11 @@ namespace LinearAlgebra { // Calculate Vector float cosV = MathF.Cos(radV); - float x = cosV * MathF.Cos(radH); - float y = MathF.Sin(radV); - float z = cosV * MathF.Sin(radH); + float sinV = MathF.Sin(radV); + + float x = cosV * MathF.Sin(radH); + float y = sinV; + float z = cosV * MathF.Cos(radH); return new UnityEngine.Vector3(x, y, z); } @@ -168,7 +179,8 @@ namespace LinearAlgebra { /// The direction /// Information about the length of the carthesian vector is not /// included in this transformation - public static Direction FromVector3(Vector3Float v) { + public static Direction FromVector3(Vector3Float v) + { AngleFloat horizontal = AngleFloat.Atan2(v.horizontal, v.depth); AngleFloat vertical = AngleFloat.deg90 - AngleFloat.Acos(v.vertical); Direction d = new(horizontal, vertical); @@ -183,7 +195,8 @@ namespace LinearAlgebra { /// /// /// True when the direction angles are equal, false otherwise. - public static bool operator ==(Direction d1, Direction d2) { + public static bool operator ==(Direction d1, Direction d2) + { bool horizontalEq = d1.horizontal == d2.horizontal; bool verticalEq = d1.vertical == d2.vertical; return horizontalEq && verticalEq; @@ -195,13 +208,15 @@ namespace LinearAlgebra { /// /// /// True when the direction angles are not equal, false otherwise. - public static bool operator !=(Direction d1, Direction d2) { + public static bool operator !=(Direction d1, Direction d2) + { bool horizontalNEq = d1.horizontal != d2.horizontal; bool verticalNEq = d1.vertical != d2.vertical; return horizontalNEq || verticalNEq; } - public override readonly bool Equals(object obj) { + public override readonly bool Equals(object obj) + { if (obj is not Direction d) return false; @@ -211,7 +226,8 @@ namespace LinearAlgebra { } - public override readonly int GetHashCode() { + public override readonly int GetHashCode() + { return HashCode.Combine(horizontal, vertical); } diff --git a/src/Spherical.cs b/src/Spherical.cs index 3a76085..2f3f801 100644 --- a/src/Spherical.cs +++ b/src/Spherical.cs @@ -62,28 +62,34 @@ namespace LinearAlgebra { #if UNITY_5_3_OR_NEWER public static Spherical FromVector3(Vector3 v) { float distance = v.magnitude; - if (distance == 0.0f) - return Spherical.zero; - else { - float verticalAngle = (float)(Math.PI / 2 - Math.Acos(v.y / distance)) * AngleFloat.Rad2Deg; - float horizontalAngle = (float)Math.Atan2(v.x, v.z) * AngleFloat.Rad2Deg; - return Degrees(distance, horizontalAngle, verticalAngle); - } + // if (distance == 0.0f) + // return Spherical.zero; + // else { + // float verticalAngle = (float)(Math.PI / 2 - Math.Acos(v.y / distance)) * AngleFloat.Rad2Deg; + // float horizontalAngle = (float)Math.Atan2(v.x, v.z) * AngleFloat.Rad2Deg; + // return Degrees(distance, horizontalAngle, verticalAngle); + // } + Direction direction = Direction.FromVector3(v.normalized); + return new Spherical(distance, direction); } public readonly Vector3 ToVector3() { - float verticalRad = (AngleFloat.deg90 - this.direction.vertical).inRadians; - float horizontalRad = this.direction.horizontal.inRadians; - float cosVertical = (float)Math.Cos(verticalRad); - float sinVertical = (float)Math.Sin(verticalRad); - float cosHorizontal = (float)Math.Cos(horizontalRad); - float sinHorizontal = (float)Math.Sin(horizontalRad); + // float verticalRad = (AngleFloat.deg90 - this.direction.vertical).inRadians; + // float horizontalRad = this.direction.horizontal.inRadians; + // float cosVertical = (float)Math.Cos(verticalRad); + // float sinVertical = (float)Math.Sin(verticalRad); + // float cosHorizontal = (float)Math.Cos(horizontalRad); + // float sinHorizontal = (float)Math.Sin(horizontalRad); - float x = this.distance * sinVertical * sinHorizontal; - float y = this.distance * cosVertical; - float z = this.distance * sinVertical * cosHorizontal; + // float x = this.distance * sinVertical * sinHorizontal; + // float y = this.distance * cosVertical; + // float z = this.distance * sinVertical * cosHorizontal; - Vector3 v = new(x, y, z); + // Vector3 v = new(x, y, z); + // return v; + + Vector3 v = this.direction.ToVector3(); + v *= this.distance; return v; } #else @@ -99,22 +105,29 @@ namespace LinearAlgebra { } public readonly Vector3Float ToVector3() { - float verticalRad = (AngleFloat.deg90 - this.direction.vertical).inRadians; - float horizontalRad = this.direction.horizontal.inRadians; - float cosVertical = (float)Math.Cos(verticalRad); - float sinVertical = (float)Math.Sin(verticalRad); - float cosHorizontal = (float)Math.Cos(horizontalRad); - float sinHorizontal = (float)Math.Sin(horizontalRad); + // float verticalRad = (AngleFloat.deg90 - this.direction.vertical).inRadians; + // float horizontalRad = this.direction.horizontal.inRadians; + // float cosVertical = (float)Math.Cos(verticalRad); + // float sinVertical = (float)Math.Sin(verticalRad); + // float cosHorizontal = (float)Math.Cos(horizontalRad); + // float sinHorizontal = (float)Math.Sin(horizontalRad); - float x = this.distance * sinVertical * sinHorizontal; - float y = this.distance * cosVertical; - float z = this.distance * sinVertical * cosHorizontal; + // float x = this.distance * sinVertical * sinHorizontal; + // float y = this.distance * cosVertical; + // float z = this.distance * sinVertical * cosHorizontal; - Vector3Float v = new(x, y, z); + // Vector3Float v = new(x, y, z); + Vector3Float v = this.direction.ToVector3(); + v *= this.distance; return v; } #endif + public override readonly string ToString() { + return $"Spherical({this.distance}, h: {this.direction.horizontal}, v: {this.direction.vertical})"; + } + + public readonly float magnitude => this.distance; public Spherical normalized { @@ -228,7 +241,7 @@ namespace LinearAlgebra { return Spherical.Radians(rAvg, azAvgRad, elAvgRad); } - + /* public static Spherical Average(List vectors) { // float sumSinPhiCosTheta = 0.0f; // float sumSinPhiSinTheta = 0.0f; @@ -302,9 +315,9 @@ namespace LinearAlgebra { return new Spherical(rAvg, new Direction(horizontalAvg, verticalAvg)); } - + */ + -/* public static Spherical Average(IEnumerable vectors) { const float EPS = 1e-6f; if (vectors == null) throw new ArgumentNullException(nameof(vectors)); @@ -371,7 +384,7 @@ namespace LinearAlgebra { return Spherical.Radians(rAvgFinal, azAvg, elAvg); } -*/ + } } \ No newline at end of file diff --git a/src/Vector3Float.cs b/src/Vector3Float.cs index d8208d3..bcf8626 100644 --- a/src/Vector3Float.cs +++ b/src/Vector3Float.cs @@ -119,6 +119,10 @@ namespace LinearAlgebra { return new Vector3Float(horizontal, vertical, depth); } + public override string ToString() { + return $"({this.horizontal}, {this.vertical}, {this.depth})"; + } + /// /// A vector with zero for all axis /// diff --git a/test/DirectionTest.cs b/test/DirectionTest.cs index 8fe3b93..0eb9882 100644 --- a/test/DirectionTest.cs +++ b/test/DirectionTest.cs @@ -103,7 +103,7 @@ namespace LinearAlgebra.Test { [Test] public void ToVector3AndBack2() { - Direction d1 = Direction.Degrees(135, 85); + Direction d1 = Direction.Degrees(-135, 85); Vector3Float v = d1.ToVector3(); Direction d2 = Direction.FromVector3(v); Assert.AreEqual(d1.horizontal.inDegrees, d2.horizontal.inDegrees, 0.0001f); diff --git a/test/SphericalTest.cs b/test/SphericalTest.cs index d7553dd..48db8d9 100644 --- a/test/SphericalTest.cs +++ b/test/SphericalTest.cs @@ -234,6 +234,30 @@ namespace LinearAlgebra.Test { Assert.AreEqual(MathF.Cos(alpha), avg.distance, 1e-4f); } + [Test] + public void Average_CompareWithVector3() { + // Four vectors around azimuth 0, pi/2, pi, 3pi/2 at same polar angle from vertical (alpha) + float alpha = MathF.PI / 6f; // polar angle from vertical + float elevation = MathF.PI / 2f - alpha; // convert polar-from-vertical to elevation + List dirs = new List { + new(1f, Direction.Radians(0f, elevation)), + new(2f, Direction.Radians(MathF.PI/2, elevation+1)), + new(3f, Direction.Radians(MathF.PI, elevation+2)), + new(4f, Direction.Radians(3*MathF.PI/2, elevation+3)) + }; + + Spherical avg = Spherical.Average(dirs); + + Vector3Float r = Vector3Float.zero; + foreach (Spherical dir in dirs) { + r += dir.ToVector3(); + } + r = r / 4; + Spherical avg2 = Spherical.FromVector3(r); + + Assert.AreEqual(avg, avg2); + } + } } #endif \ No newline at end of file From 6341d827e9ff64bba0afc9c6087136c92527e96f Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 7 Jan 2026 14:51:15 +0100 Subject: [PATCH 051/179] Spherical UpdateState (finally) --- .../NanoBrain/LinearAlgebra/src/Direction.cs | 5 ++ .../NanoBrain/LinearAlgebra/src/Spherical.cs | 12 +++- Assets/NanoBrain/Neuroid.cs | 69 +------------------ 3 files changed, 16 insertions(+), 70 deletions(-) diff --git a/Assets/NanoBrain/LinearAlgebra/src/Direction.cs b/Assets/NanoBrain/LinearAlgebra/src/Direction.cs index a1ff8f3..fd25b98 100644 --- a/Assets/NanoBrain/LinearAlgebra/src/Direction.cs +++ b/Assets/NanoBrain/LinearAlgebra/src/Direction.cs @@ -188,6 +188,11 @@ namespace LinearAlgebra } #endif + public static Direction operator -(Direction d) { + AngleFloat horizontal = d.horizontal + AngleFloat.deg180; + AngleFloat vertical = -d.vertical; + return new Direction(horizontal, vertical); + } /// /// Tests the equality of two directions diff --git a/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs b/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs index 2f3f801..2d6b6ed 100644 --- a/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs +++ b/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs @@ -17,8 +17,14 @@ namespace LinearAlgebra { /// The distance in meters /// The direction of the vector public Spherical(float distance, Direction direction) { - this.distance = distance; - this.direction = direction; + if (distance > 0) { + this.distance = distance; + this.direction = direction; + } + else { + this.distance = -distance; + this.direction = -direction; + } } /// @@ -315,7 +321,7 @@ namespace LinearAlgebra { return new Spherical(rAvg, new Direction(horizontalAvg, verticalAvg)); } - */ + */ public static Spherical Average(IEnumerable vectors) { diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index 71e48e7..7196a11 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -75,57 +75,7 @@ public class Neuroid : Nucleus { } public override void UpdateState() { - // Vector3 resultVector = Vector3.zero; - // foreach (Synapse synapse in this.synapses) { - // Nucleus synapseNucleus = synapse.nucleus; - // if (synapseNucleus is Neuroid neuroid && neuroid.isSleeping) - // continue; - - // Vector3 direction = synapseNucleus.outputValue.direction.ToVector3(); - - // float weight = synapse.weight; - // float activatedValue = curve.Evaluate(synapseNucleus.outputValue.magnitude); - // float magnitude = weight * activatedValue; - // //Debug.Log($"{this.name} {synapseNucleus.outputValue.direction} {synapseNucleus.outputValue.direction.horizontal}{synapseNucleus.outputValue.direction.vertical} {direction}"); - // Vector3 a = direction * magnitude; - // //Debug.Log($"A {direction} {magnitude} {a}"); - // resultVector += a; - // } - // if (average && this.synapses.Count > 0) - // resultVector /= this.synapses.Count; - /* - List v3s = new(); - foreach (Synapse synapse in this.synapses) { - Nucleus synapseNucleus = synapse.nucleus; - if (synapseNucleus is Neuroid neuroid && neuroid.isSleeping) - continue; - - Vector3 direction = synapseNucleus.outputValue.direction.ToVector3(); - - float weight = synapse.weight; - float activatedValue = curve.Evaluate(synapseNucleus.outputValue.magnitude); - float magnitude = weight * activatedValue; - //Debug.Log($"{this.name} {synapseNucleus.outputValue.direction} {synapseNucleus.outputValue.direction.horizontal}{synapseNucleus.outputValue.direction.vertical} {direction}"); - Vector3 a = direction * magnitude; - //Debug.Log($"A {direction} {magnitude} {a}"); - v3s.Add(a); - } - Vector3 sum = Vector3.zero; // Start with a zero vector - - // Sum all vectors - foreach (Vector3 vector in v3s) - sum += vector; - - // Calculate average - Vector3 averagevs = sum / v3s.Count; - Vector3 result1 = averagevs * v3s.Count; - // if (average && this.synapses.Count > 0) - // resultVector /= this.synapses.Count; - - Spherical result = Spherical.FromVector3(result1); - */ List sVectors = new(); - List cVectors = new(); foreach (Synapse synapse in this.synapses) { if (synapse.nucleus.isSleeping) continue; @@ -134,29 +84,14 @@ public class Neuroid : Nucleus { float activatedValue = curve.Evaluate(synapse.nucleus.outputValue.magnitude); float magnitude = weight * activatedValue; Spherical sVector = new(magnitude, synapse.nucleus.outputValue.direction); - //Debug.Log($"B {synapse.nucleus.outputValue.direction.ToVector3()} {magnitude} {vector.ToVector3()}"); - sVectors.Add(sVector); //synapse.nucleus.outputValue); - - Vector3 direction = synapse.nucleus.outputValue.direction.ToVector3(); - Vector3 cVector = direction * magnitude; - cVectors.Add(cVector); + sVectors.Add(sVector); } - Vector3 cResult = Vector3.zero; - foreach (Vector3 vector in cVectors) - cResult += vector; Spherical sResult = Spherical.Average(sVectors); if (average == false) sResult *= sVectors.Count; - if (sResult != Spherical.FromVector3(cResult)) - Debug.Log($"spherical different {sResult} != {Spherical.FromVector3(cResult)}"); - //if (sResult.ToVector3() != cResult) - Debug.Log($"vector different {sResult.ToVector3()} != {cResult}"); - - - UpdateResult(Spherical.FromVector3(cResult)); - + UpdateResult(sResult); } } From 5dbb5654a147af70e81fdd008d93e9cf0034173d Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 7 Jan 2026 15:30:05 +0100 Subject: [PATCH 052/179] Performance tweaking --- .../NanoBrain/LinearAlgebra/src/Spherical.cs | 195 +++--------------- .../LinearAlgebra/test/SphericalTest.cs | 20 +- Assets/NanoBrain/Neuroid.cs | 22 +- Assets/NanoBrain/Nucleus.cs | 10 +- ProjectSettings/ProjectSettings.asset | 11 +- 5 files changed, 74 insertions(+), 184 deletions(-) diff --git a/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs b/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs index 2d6b6ed..aee6a64 100644 --- a/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs +++ b/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs @@ -68,32 +68,11 @@ namespace LinearAlgebra { #if UNITY_5_3_OR_NEWER public static Spherical FromVector3(Vector3 v) { float distance = v.magnitude; - // if (distance == 0.0f) - // return Spherical.zero; - // else { - // float verticalAngle = (float)(Math.PI / 2 - Math.Acos(v.y / distance)) * AngleFloat.Rad2Deg; - // float horizontalAngle = (float)Math.Atan2(v.x, v.z) * AngleFloat.Rad2Deg; - // return Degrees(distance, horizontalAngle, verticalAngle); - // } - Direction direction = Direction.FromVector3(v.normalized); + Direction direction = Direction.FromVector3(v / distance); return new Spherical(distance, direction); } public readonly Vector3 ToVector3() { - // float verticalRad = (AngleFloat.deg90 - this.direction.vertical).inRadians; - // float horizontalRad = this.direction.horizontal.inRadians; - // float cosVertical = (float)Math.Cos(verticalRad); - // float sinVertical = (float)Math.Sin(verticalRad); - // float cosHorizontal = (float)Math.Cos(horizontalRad); - // float sinHorizontal = (float)Math.Sin(horizontalRad); - - // float x = this.distance * sinVertical * sinHorizontal; - // float y = this.distance * cosVertical; - // float z = this.distance * sinVertical * cosHorizontal; - - // Vector3 v = new(x, y, z); - // return v; - Vector3 v = this.direction.ToVector3(); v *= this.distance; return v; @@ -247,150 +226,44 @@ namespace LinearAlgebra { return Spherical.Radians(rAvg, azAvgRad, elAvgRad); } - /* - public static Spherical Average(List vectors) { - // float sumSinPhiCosTheta = 0.0f; - // float sumSinPhiSinTheta = 0.0f; - // float sumCosPhi = 0.0f; - // int n = vectors.Count; + public static Spherical Sum(List vectors) { + if (vectors == null || vectors.Count == 0) + throw new ArgumentException("vectors must contain at least one element", nameof(vectors)); - // // Step 1: Accumulate sine and cosine components - // foreach(Spherical v in vectors) { - // float sinHorizontal = AngleFloat.Sin(v.direction.horizontal); - // sumSinPhiCosTheta += v.distance * sinHorizontal * AngleFloat.Cos(v.direction.vertical); - // sumSinPhiSinTheta += v.distance * sinHorizontal * AngleFloat.Sin(v.direction.vertical); - // sumCosPhi += v.distance * AngleFloat.Cos(v.direction.horizontal); - // } +#if UNITY_5_3_OR_NEWER + Vector3 sum = Vector3.zero; +#else + Vector3Float sum = Vector3Float.zero; +#endif + foreach (Spherical v in vectors) + sum += v.ToVector3(); - // // Step 2: Calculate average components - // float avgSinPhiCosTheta = sumSinPhiCosTheta / n; - // float avgSinPhiSinTheta = sumSinPhiSinTheta / n; - // float avgCosPhi = sumCosPhi / n; - - // // Step 3: Calculate the magnitude of the average vector - // float rAvg = MathF.Sqrt(avgSinPhiCosTheta * avgSinPhiCosTheta + - // avgSinPhiSinTheta * avgSinPhiSinTheta + - // avgCosPhi * avgCosPhi); - - // // Step 4: Calculate average angles - // AngleFloat horizontalAvg = AngleFloat.Acos(avgCosPhi / rAvg); // Handle rAvg != 0 case - // AngleFloat verticalAvg = AngleFloat.Atan2(avgSinPhiSinTheta, avgSinPhiCosTheta); - - // return new Spherical(rAvg, new Direction(horizontalAvg, verticalAvg)); - - if (vectors == null || vectors.Count == 0) - throw new ArgumentException("vectors must contain at least one element", nameof(vectors)); - - float sumX = 0f, sumY = 0f, sumZ = 0f; - int n = vectors.Count; - - foreach (var v in vectors) { - // AngleFloat -> radians; assume AngleFloat provides Radians property - float theta = v.direction.horizontal.inRadians; // azimuth - float phi = v.direction.vertical.inRadians; // elevation - - float cosPhi = MathF.Cos(phi); - float sinPhi = MathF.Sin(phi); - float cosTheta = MathF.Cos(theta); - float sinTheta = MathF.Sin(theta); - - float x = v.distance * cosPhi * cosTheta; - float y = v.distance * cosPhi * sinTheta; - float z = v.distance * sinPhi; - - sumX += x; - sumY += y; - sumZ += z; - } - - float avgX = sumX / n; - float avgY = sumY / n; - float avgZ = sumZ / n; - - float rAvg = MathF.Sqrt(avgX * avgX + avgY * avgY + avgZ * avgZ); - - if (rAvg == 0f) { - return new Spherical(0f, new Direction(AngleFloat.Radians(0f), AngleFloat.Radians(0f))); - } - - // elevation = asin(z / r) - AngleFloat verticalAvg = AngleFloat.Asin(avgZ / rAvg); // -90..90 - // azimuth = atan2(y, x) -> -pi..pi - AngleFloat horizontalAvg = AngleFloat.Atan2(avgY, avgX); // -180..180 - - return new Spherical(rAvg, new Direction(horizontalAvg, verticalAvg)); - } - */ - - - public static Spherical Average(IEnumerable vectors) { - const float EPS = 1e-6f; - if (vectors == null) throw new ArgumentNullException(nameof(vectors)); - - float sumRx = 0f, sumRy = 0f, sumRz = 0f; - float sumDistances = 0f; - int count = 0; - - bool firstSet = false; - float firstAz = 0f, firstEl = 0f; - bool allSameDirection = true; - - foreach (var v in vectors) { - float az = v.direction.horizontal.inRadians; // horizontal (azimuth) - float el = v.direction.vertical.inRadians; // vertical (elevation) - - if (!firstSet) { - firstSet = true; - firstAz = az; - firstEl = el; - } - else { - if (MathF.Abs(MathF.IEEERemainder(az - firstAz, MathF.PI * 2f)) >= EPS || - MathF.Abs(el - firstEl) >= EPS) { - allSameDirection = false; - } - } - - float cosEl = MathF.Cos(el); - float ux = cosEl * MathF.Cos(az); // x - float uy = cosEl * MathF.Sin(az); // y - float uz = MathF.Sin(el); // z - - sumRx += v.distance * ux; - sumRy += v.distance * uy; - sumRz += v.distance * uz; - - sumDistances += v.distance; - count++; - } - - if (count == 0) throw new ArgumentException("Sequence contains no elements", nameof(vectors)); - - // All directions equal -> preserve exact angles, average distance - if (allSameDirection) { - float rAvg = sumDistances / count; - return new Spherical(rAvg, Direction.Radians(firstAz, firstEl)); - } - - // Total vector sum V - float Vx = sumRx; - float Vy = sumRy; - float Vz = sumRz; - float Vmag = MathF.Sqrt(Vx * Vx + Vy * Vy + Vz * Vz); - - if (Vmag < EPS) { - // Directions cancel out -> zero distance, angles arbitrary - return Spherical.Radians(0f, 0f, 0f); - } - - float azAvg = MathF.Atan2(Vy, Vx); - float elAvg = MathF.Asin(Float.Clamp(Vz / Vmag, -1f, 1f)); - float rAvgFinal = Vmag / count; - - return Spherical.Radians(rAvgFinal, azAvg, elAvg); + return FromVector3(sum); } + public static Spherical Average(List vectors) { + if (vectors == null || vectors.Count == 0) + throw new ArgumentException("vectors must contain at least one element", nameof(vectors)); + +#if UNITY_5_3_OR_NEWER + Vector3 sum = Vector3.zero; +#else + Vector3Float sum = Vector3Float.zero; +#endif + int n = 0; + foreach (Spherical v in vectors) { + sum += v.ToVector3(); + n++; + } + var avg = sum / n; + + // if (avg.sqrMagnitude == 0f) + // return new Spherical(0f, new Direction(AngleFloat.Radians(0f), AngleFloat.Radians(0f))); + // else + return FromVector3(avg); + } + } } \ No newline at end of file diff --git a/Assets/NanoBrain/LinearAlgebra/test/SphericalTest.cs b/Assets/NanoBrain/LinearAlgebra/test/SphericalTest.cs index 48db8d9..b28b9d9 100644 --- a/Assets/NanoBrain/LinearAlgebra/test/SphericalTest.cs +++ b/Assets/NanoBrain/LinearAlgebra/test/SphericalTest.cs @@ -1,4 +1,4 @@ -#if !UNITY_5_6_OR_NEWER +//#if !UNITY_5_6_OR_NEWER using System; using System.Collections.Generic; using NUnit.Framework; @@ -11,7 +11,11 @@ namespace LinearAlgebra.Test { [Test] public void FromVector3() { +#if UNITY_5_6_OR_NEWER + UnityEngine.Vector3 v = new(0, 0, 1); +#else Vector3Float v = new(0, 0, 1); +#endif Spherical s = Spherical.FromVector3(v); Assert.AreEqual(1.0f, s.distance, "s.distance 0 0 1"); Assert.AreEqual(0.0f, s.direction.horizontal.inDegrees, "s.hor 0 0 1"); @@ -46,7 +50,7 @@ namespace LinearAlgebra.Test { v2 = Spherical.Degrees(1, 0, 90); r = v1 + v2; Assert.AreEqual(Math.Sqrt(2), r.distance, 1.0E-05F, "Addition(1 0 90)"); - Assert.AreEqual(45.0f, r.direction.horizontal.inDegrees, "Addition(1 0 90)"); + Assert.AreEqual(45.0f, r.direction.horizontal.inDegrees, 1e-5f, "Addition(1 0 90)"); Assert.AreEqual(45.0f, r.direction.vertical.inDegrees, 1.0E-05F, "Addition(1 0 90)"); } @@ -166,7 +170,7 @@ namespace LinearAlgebra.Test { [Test] public void Average_SingleElement() { Spherical s = Spherical.Radians(1.234f, 0.3f, -0.7f); - Spherical avg = Spherical.Average([s]); + Spherical avg = Spherical.Average(new List { s }); Assert.AreEqual(s.distance, avg.distance, 1e-5f); Assert.AreEqual(s.direction.horizontal.inRadians, avg.direction.horizontal.inRadians, 1e-5f); @@ -178,7 +182,7 @@ namespace LinearAlgebra.Test { // Two opposite vectors: same distance, horizontal opposite (pi apart), same vertical Spherical v1 = Spherical.Radians(1f, 0f, 0f); Spherical v2 = Spherical.Radians(1f, MathF.PI, 0f); - Spherical avg = Spherical.Average([v1, v2]); + Spherical avg = Spherical.Average(new List { v1, v2 }); Assert.AreEqual(0f, avg.distance, 1e-4f); // When distance is zero, angles may be undefined; allow any angle but ensure near-zero magnitude @@ -190,7 +194,7 @@ namespace LinearAlgebra.Test { Direction dir = Direction.Radians(MathF.PI / 3f, MathF.PI / 4f); Spherical a = new(1f, dir); Spherical b = new(3f, dir); - Spherical avg = Spherical.Average([a, b]); + Spherical avg = Spherical.Average(new List { a, b }); // average distance should be (1+3)/2 = 2 Assert.AreEqual(2f, avg.distance, 1e-5f); @@ -248,7 +252,11 @@ namespace LinearAlgebra.Test { Spherical avg = Spherical.Average(dirs); +#if UNITY_5_3_OR_NEWER + UnityEngine.Vector3 r = UnityEngine.Vector3.zero; +#else Vector3Float r = Vector3Float.zero; +#endif foreach (Spherical dir in dirs) { r += dir.ToVector3(); } @@ -260,4 +268,4 @@ namespace LinearAlgebra.Test { } } -#endif \ No newline at end of file +//#endif \ No newline at end of file diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index 7196a11..e1f382a 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -75,23 +75,29 @@ public class Neuroid : Nucleus { } public override void UpdateState() { - List sVectors = new(); + Vector3 sum = Vector3.zero; + int n = 0; foreach (Synapse synapse in this.synapses) { if (synapse.nucleus.isSleeping) continue; + Spherical outputValue = synapse.nucleus.outputValue; float weight = synapse.weight; - float activatedValue = curve.Evaluate(synapse.nucleus.outputValue.magnitude); + float activatedValue = curve.Evaluate(outputValue.magnitude); float magnitude = weight * activatedValue; - Spherical sVector = new(magnitude, synapse.nucleus.outputValue.direction); - sVectors.Add(sVector); + Spherical sVector = new(magnitude, outputValue.direction); + + sum += sVector.ToVector3(); + n++; } - Spherical sResult = Spherical.Average(sVectors); - if (average == false) - sResult *= sVectors.Count; + Spherical result; + if (average) + result = Spherical.FromVector3(sum / n); + else + result = Spherical.FromVector3(sum); - UpdateResult(sResult); + UpdateResult(result); } } diff --git a/Assets/NanoBrain/Nucleus.cs b/Assets/NanoBrain/Nucleus.cs index 94e2e64..d29bdc3 100644 --- a/Assets/NanoBrain/Nucleus.cs +++ b/Assets/NanoBrain/Nucleus.cs @@ -154,11 +154,11 @@ public class Nucleus { public virtual void UpdateState() { } public void UpdateResult(Spherical result) { - float d = Spherical.Distance(result, this.outputValue); - if (d < 0.1f) { - //Debug.Log($"insignificant update: {d}"); - return; - } + // float d = Spherical.Distance(result, this.outputValue); + // if (d < 0.1f) { + // //Debug.Log($"insignificant update: {d}"); + // return; + // } this.outputValue = result; foreach (Receiver receiver in this.receivers) diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset index eb3e21f..a47eafd 100644 --- a/ProjectSettings/ProjectSettings.asset +++ b/ProjectSettings/ProjectSettings.asset @@ -176,9 +176,10 @@ PlayerSettings: tvOS: 0 overrideDefaultApplicationIdentifier: 1 AndroidBundleVersionCode: 1 - AndroidMinSdkVersion: 23 + AndroidMinSdkVersion: 25 AndroidTargetSdkVersion: 0 AndroidPreferredInstallLocation: 1 + AndroidPreferredDataLocation: 1 aotOptions: stripEngineCode: 1 iPhoneStrippingLevel: 0 @@ -193,11 +194,11 @@ PlayerSettings: VertexChannelCompressionMask: 4054 iPhoneSdkVersion: 988 iOSSimulatorArchitecture: 0 - iOSTargetOSVersionString: 13.0 + iOSTargetOSVersionString: 15.0 tvOSSdkVersion: 0 tvOSSimulatorArchitecture: 0 tvOSRequireExtendedGameController: 0 - tvOSTargetOSVersionString: 13.0 + tvOSTargetOSVersionString: 15.0 VisionOSSdkVersion: 0 VisionOSTargetOSVersionString: 1.0 uIPrerenderedIcon: 0 @@ -267,6 +268,7 @@ PlayerSettings: useCustomGradleSettingsTemplate: 0 useCustomProguardFile: 0 AndroidTargetArchitectures: 2 + AndroidAllowedArchitectures: -1 AndroidSplashScreenScale: 0 androidSplashScreen: {fileID: 0} AndroidKeystoreName: @@ -569,7 +571,7 @@ PlayerSettings: locationUsageDescription: microphoneUsageDescription: bluetoothUsageDescription: - macOSTargetOSVersion: 11.0 + macOSTargetOSVersion: 12.0 switchNMETAOverride: switchNetLibKey: switchSocketMemoryPoolSize: 6144 @@ -937,3 +939,4 @@ PlayerSettings: androidVulkanAllowFilterList: [] androidVulkanDeviceFilterListAsset: {fileID: 0} d3d12DeviceFilterListAsset: {fileID: 0} + allowedHttpConnections: 3 From cd74c312dc8575ade3a69c60908a1b99bdc64ab9 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 7 Jan 2026 16:43:38 +0100 Subject: [PATCH 053/179] neuroid value as Vector3 --- Assets/NanoBrain/Neuroid.cs | 15 +++++++++------ Assets/NanoBrain/Nucleus.cs | 8 ++++---- Assets/NanoBrain/Perceptoid.cs | 6 +++--- Assets/NanoBrain/Receptor.cs | 8 ++++---- .../VisualEditor/Editor/NanoBrainEditor.cs | 4 ++-- .../VisualEditor/Editor/NanoBrainInspector.cs | 2 +- Assets/Scenes/Boids/Scripts/Boid.cs | 17 ++++++++--------- 7 files changed, 31 insertions(+), 29 deletions(-) diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index e1f382a..ed9f88a 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -81,21 +81,24 @@ public class Neuroid : Nucleus { if (synapse.nucleus.isSleeping) continue; - Spherical outputValue = synapse.nucleus.outputValue; + Vector3 outputValue = synapse.nucleus.outputValue; float weight = synapse.weight; float activatedValue = curve.Evaluate(outputValue.magnitude); float magnitude = weight * activatedValue; - Spherical sVector = new(magnitude, outputValue.direction); + //Spherical sVector = new(magnitude, outputValue.direction); - sum += sVector.ToVector3(); + sum += magnitude * outputValue.normalized;//sVector.ToVector3(); n++; } - Spherical result; + //Spherical result; + Vector3 result; if (average) - result = Spherical.FromVector3(sum / n); + //result = Spherical.FromVector3(sum / n); + result = sum / n; else - result = Spherical.FromVector3(sum); + //result = Spherical.FromVector3(sum); + result = sum; UpdateResult(result); } diff --git a/Assets/NanoBrain/Nucleus.cs b/Assets/NanoBrain/Nucleus.cs index d29bdc3..dbdb6ab 100644 --- a/Assets/NanoBrain/Nucleus.cs +++ b/Assets/NanoBrain/Nucleus.cs @@ -64,8 +64,8 @@ public class Nucleus { public NanoBrainObj brain { get; set; } - private Spherical _outputValue; - public Spherical outputValue //{ get; set; } + private Vector3 _outputValue; + public Vector3 outputValue //{ get; set; } { get { return _outputValue; } set { @@ -83,7 +83,7 @@ public class Nucleus { this.stale++; this.isSleeping = this.stale > 2; if (isSleeping) - _outputValue = Spherical.zero; + _outputValue = Vector3.zero; } [System.NonSerialized] public int layerIx; @@ -153,7 +153,7 @@ public class Nucleus { public virtual void UpdateState() { } - public void UpdateResult(Spherical result) { + public void UpdateResult(Vector3 result) { // float d = Spherical.Distance(result, this.outputValue); // if (d < 0.1f) { // //Debug.Log($"insignificant update: {d}"); diff --git a/Assets/NanoBrain/Perceptoid.cs b/Assets/NanoBrain/Perceptoid.cs index 4f5b5a9..0d4970f 100644 --- a/Assets/NanoBrain/Perceptoid.cs +++ b/Assets/NanoBrain/Perceptoid.cs @@ -68,14 +68,14 @@ public class Perceptoid : Neuroid { this.thingType = thingType; this.receptor.thingType = thingType; - this.receptor.localPosition = Spherical.zero; + this.receptor.localPosition = Vector3.zero; - this.outputValue = Spherical.zero; + this.outputValue = Vector3.zero; this.receivers = new(); } public override void UpdateState() { - Spherical result = this.receptor.localPosition; + Vector3 result = this.receptor.localPosition; UpdateResult(result); } diff --git a/Assets/NanoBrain/Receptor.cs b/Assets/NanoBrain/Receptor.cs index 47e215f..050993b 100644 --- a/Assets/NanoBrain/Receptor.cs +++ b/Assets/NanoBrain/Receptor.cs @@ -18,7 +18,7 @@ public class Receptor { } } } - public Spherical localPosition; + public Vector3 localPosition; public float distanceResolution = 0.1f; public float directionResolution = 5; @@ -38,10 +38,10 @@ public class Receptor { } public virtual void ProcessStimulus(int thingId, Vector3 newLocalPositionVector) { - Spherical newLocalPosition = Spherical.FromVector3(newLocalPositionVector); + //Spherical newLocalPosition = Spherical.FromVector3(newLocalPositionVector); - Spherical previousLocalPosition = this.localPosition; - this.localPosition = newLocalPosition; + Vector3 previousLocalPosition = this.localPosition; + this.localPosition = newLocalPositionVector; Perceptoid selectedPerceptoid = null; foreach (Perceptoid perceptoid in this.perceptei) { diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs index 81ffac3..86d346d 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs @@ -339,7 +339,7 @@ public class GraphBoardView : VisualElement { currentNucleus.name = EditorGUILayout.TextField(currentNucleus.name); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Output Value", GUILayout.Width(100)); - EditorGUILayout.Vector3Field(GUIContent.none, currentNucleus.outputValue.ToVector3()); + EditorGUILayout.Vector3Field(GUIContent.none, currentNucleus.outputValue); EditorGUILayout.EndHorizontal(); if (currentNucleus.synapses.Count > 0) { EditorGUILayout.LabelField("Synapses"); @@ -358,7 +358,7 @@ public class GraphBoardView : VisualElement { // currentNucleus.synapses[nucleus] = EditorGUILayout.FloatField(weight, GUILayout.Width(40)); synapse.weight = EditorGUILayout.FloatField(synapse.weight, GUILayout.Width(40)); EditorGUI.indentLevel++; - EditorGUILayout.Vector3Field(GUIContent.none, synapse.nucleus.outputValue.ToVector3(), GUILayout.Width(180)); + EditorGUILayout.Vector3Field(GUIContent.none, synapse.nucleus.outputValue, GUILayout.Width(180)); EditorGUILayout.EndHorizontal(); EditorGUI.EndDisabledGroup(); diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs index 9ab8a35..fce8b3e 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs @@ -457,7 +457,7 @@ public class NanoBrainInspector : Editor { DisconnectNucleus(this.currentNucleus); if (this.gameObject != null) { - Vector3 worldVector = this.gameObject.transform.TransformVector(this.currentNucleus.outputValue.ToVector3()); + Vector3 worldVector = this.gameObject.transform.TransformVector(this.currentNucleus.outputValue); Debug.DrawRay(this.gameObject.transform.position, worldVector, Color.yellow); } }); diff --git a/Assets/Scenes/Boids/Scripts/Boid.cs b/Assets/Scenes/Boids/Scripts/Boid.cs index ef7846d..260a788 100644 --- a/Assets/Scenes/Boids/Scripts/Boid.cs +++ b/Assets/Scenes/Boids/Scripts/Boid.cs @@ -44,15 +44,15 @@ public class Boid : MonoBehaviour { if (neighbour == null || neighbour == this) continue; - Vector3 localPosition = this.transform.InverseTransformPoint(neighbour.transform.position); - //localPosition = localPosition.normalized * (localPosition.magnitude - sc.separationDistance); - //Debug.DrawRay(this.transform.position, this.transform.TransformDirection(localPosition), Color.magenta); + int thingId = neighbour.GetInstanceID(); + + Vector3 localPosition = this.transform.InverseTransformPoint(neighbour.transform.position); + if (localPosition.sqrMagnitude > 0) + boidReceptor?.ProcessStimulus(thingId, localPosition); Vector3 localVelocity = this.transform.InverseTransformVector(neighbour.velocity); - - int thingId = neighbour.GetInstanceID(); - boidReceptor?.ProcessStimulus(thingId, localPosition); - boidVelocityReceptor?.ProcessStimulus(thingId, localVelocity); + if (localVelocity.sqrMagnitude > 0) + boidVelocityReceptor?.ProcessStimulus(thingId, localVelocity); } } @@ -64,8 +64,7 @@ public class Boid : MonoBehaviour { boundaryReceptor.ProcessStimulus(777, desiredLocalSpace); } - - Vector3 worldForce = this.transform.TransformDirection(nanoBrain.root.outputValue.ToVector3()); + Vector3 worldForce = this.transform.TransformDirection(nanoBrain.root.outputValue); this.velocity = (1 - sc.inertia) * (worldForce * Time.deltaTime) + sc.inertia * velocity; if (this.velocity.magnitude > 0) From b9b942760b38922d11478019a84699f1ba4e8002 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 7 Jan 2026 17:16:35 +0100 Subject: [PATCH 054/179] pre: activation function to synapse neuron --- Assets/NanoBrain/Neuroid.cs | 21 +++++---------------- Assets/NanoBrain/Nucleus.cs | 4 ++-- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index ed9f88a..014533d 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -75,30 +75,19 @@ public class Neuroid : Nucleus { } public override void UpdateState() { - Vector3 sum = Vector3.zero; + Vector3 result = Vector3.zero; int n = 0; foreach (Synapse synapse in this.synapses) { - if (synapse.nucleus.isSleeping) - continue; - Vector3 outputValue = synapse.nucleus.outputValue; - float weight = synapse.weight; + // As this is the activation function, it should be evaluated in the synapse.nucleus... float activatedValue = curve.Evaluate(outputValue.magnitude); - float magnitude = weight * activatedValue; - //Spherical sVector = new(magnitude, outputValue.direction); + float magnitude = synapse.weight * activatedValue; - sum += magnitude * outputValue.normalized;//sVector.ToVector3(); + result += magnitude * outputValue.normalized; n++; } - - //Spherical result; - Vector3 result; if (average) - //result = Spherical.FromVector3(sum / n); - result = sum / n; - else - //result = Spherical.FromVector3(sum); - result = sum; + result /= n; UpdateResult(result); } diff --git a/Assets/NanoBrain/Nucleus.cs b/Assets/NanoBrain/Nucleus.cs index dbdb6ab..802ffcf 100644 --- a/Assets/NanoBrain/Nucleus.cs +++ b/Assets/NanoBrain/Nucleus.cs @@ -65,7 +65,7 @@ public class Nucleus { public NanoBrainObj brain { get; set; } private Vector3 _outputValue; - public Vector3 outputValue //{ get; set; } + public Vector3 outputValue { get { return _outputValue; } set { @@ -154,7 +154,7 @@ public class Nucleus { public virtual void UpdateState() { } public void UpdateResult(Vector3 result) { - // float d = Spherical.Distance(result, this.outputValue); + // float d = Vector3.Distance(result, this.outputValue); // if (d < 0.1f) { // //Debug.Log($"insignificant update: {d}"); // return; From 600ecd54069c27c45fdee733f584be5d943f72ab Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 8 Jan 2026 14:09:31 +0100 Subject: [PATCH 055/179] Moved activation function to after weight application --- Assets/NanoBrain/Neuroid.cs | 34 +- Assets/NanoBrain/Nucleus.cs | 64 +- Assets/NanoBrain/Perceptoid.cs | 6 +- Assets/NanoBrain/Receptor.cs | 17 +- .../Editor/NanoBrainComponent_Editor.cs | 2 +- .../VisualEditor/Editor/NanoBrainEditor.cs | 14 +- .../VisualEditor/Editor/NanoBrainInspector.cs | 8 +- .../VisualEditor/NanoBrainComponent.cs | 6 +- Assets/NanoBrain/VisualEditor/NanoBrainObj.cs | 4 +- Assets/Scenes/Boids/Boids.unity | 6 +- .../Scripts/Editor/SwarmControl_Editor.cs | 6 +- Assets/Scenes/Boids/SwarmingBrain.asset | 1363 +---------------- mono_crash.mem.19211.1.blob | Bin 10000001 -> 0 bytes 13 files changed, 94 insertions(+), 1436 deletions(-) delete mode 100644 mono_crash.mem.19211.1.blob diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index 014533d..8f8401e 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -48,7 +48,7 @@ public class Neuroid : Nucleus { public float exponent = 1.0f; - public Neuroid(NanoBrainObj brain, string name) : base(name) { + public Neuroid(NanoBrain brain, string name) : base(name) { this.brain = brain; if (this.brain != null) { this.brain.nuclei.Add(this); @@ -75,20 +75,40 @@ public class Neuroid : Nucleus { } public override void UpdateState() { - Vector3 result = Vector3.zero; + Vector3 sum = Vector3.zero; int n = 0; + + //Applying the weight factgors foreach (Synapse synapse in this.synapses) { Vector3 outputValue = synapse.nucleus.outputValue; - // As this is the activation function, it should be evaluated in the synapse.nucleus... - float activatedValue = curve.Evaluate(outputValue.magnitude); - float magnitude = synapse.weight * activatedValue; + float magnitude = synapse.weight * outputValue.magnitude; - result += magnitude * outputValue.normalized; + sum += magnitude * outputValue.normalized; n++; } if (average) - result /= n; + sum /= n; + // Activation function + Vector3 result; + switch (this.curvePreset) { + case CurvePresets.Linear: + result = sum; + break; + case CurvePresets.Sqrt: + result = sum.normalized * System.MathF.Sqrt(sum.magnitude); + break; + case CurvePresets.Power: + result = sum.normalized * System.MathF.Pow(sum.magnitude, 2); + break; + case CurvePresets.Reciprocal: + result = sum.normalized * (1 / sum.magnitude); + break; + default: + float activatedValue = this.curve.Evaluate(sum.magnitude); + result = sum.normalized * activatedValue; + break; + } UpdateResult(result); } diff --git a/Assets/NanoBrain/Nucleus.cs b/Assets/NanoBrain/Nucleus.cs index 802ffcf..7141d09 100644 --- a/Assets/NanoBrain/Nucleus.cs +++ b/Assets/NanoBrain/Nucleus.cs @@ -26,7 +26,7 @@ public class Nucleus { [SerializeField] protected string nucleusType; - public virtual void Rebuild(NanoBrainObj brain) { + public virtual void Rebuild(NanoBrain brain) { if (this.synapses != null) { foreach (Synapse synapse in synapses) synapse.Rebuild(brain); @@ -43,7 +43,7 @@ public class Nucleus { } } - public static Nucleus RebuildType(NanoBrainObj brain, Nucleus nucleus) { + public static Nucleus RebuildType(NanoBrain brain, Nucleus nucleus) { if (string.IsNullOrEmpty(nucleus.nucleusType) == false) { Type nucleusType = Type.GetType(nucleus.nucleusType); if (nucleusType != null) { @@ -62,7 +62,7 @@ public class Nucleus { #region Runtime state (not serialized) - public NanoBrainObj brain { get; set; } + public NanoBrain brain { get; set; } private Vector3 _outputValue; public Vector3 outputValue @@ -154,11 +154,11 @@ public class Nucleus { public virtual void UpdateState() { } public void UpdateResult(Vector3 result) { - // float d = Vector3.Distance(result, this.outputValue); - // if (d < 0.1f) { - // //Debug.Log($"insignificant update: {d}"); - // return; - // } + float d = Vector3.Distance(result, this.outputValue); + if (d < 0.5f) { + //Debug.Log($"insignificant update: {d}"); + return; + } this.outputValue = result; foreach (Receiver receiver in this.receivers) @@ -181,8 +181,8 @@ public class Synapse { Reciprocal, Custom } - public CurvePresets curvePreset; - public AnimationCurve curve; + // public CurvePresets curvePreset; + // public AnimationCurve curve; public float curveMax = 1.0f; public Synapse(Nucleus nucleus, float weight) { @@ -191,7 +191,7 @@ public class Synapse { this.weight = weight; } - public void Rebuild(NanoBrainObj brain) { + public void Rebuild(NanoBrain brain) { if (brain == null) { return; } @@ -211,30 +211,30 @@ public class Synapse { Debug.LogError($"Synapse deserialization error: could not find nucleus with id {this.nucleusId}"); } - public AnimationCurve GenerateCurve() { - switch (this.curvePreset) { - case CurvePresets.Linear: - this.curveMax = this.weight; - return Presets.Linear(this.weight); - case CurvePresets.Power: - this.curveMax = this.weight; - return Presets.Power(2.0f, this.weight); - case CurvePresets.Sqrt: - this.curveMax = this.weight; - return Presets.Power(0.5f, this.weight); - case CurvePresets.Reciprocal: - this.curveMax = 1 / 0.01f * this.weight; - return Presets.Reciprocal(this.weight); - default: - this.curveMax = weight; - return AnimationCurve.Constant(0, 1, weight); - } - } + // public AnimationCurve GenerateCurve() { + // switch (this.curvePreset) { + // case CurvePresets.Linear: + // this.curveMax = this.weight; + // return Presets.Linear(this.weight); + // case CurvePresets.Power: + // this.curveMax = this.weight; + // return Presets.Power(2.0f, this.weight); + // case CurvePresets.Sqrt: + // this.curveMax = this.weight; + // return Presets.Power(0.5f, this.weight); + // case CurvePresets.Reciprocal: + // this.curveMax = 1 / 0.01f * this.weight; + // return Presets.Reciprocal(this.weight); + // default: + // this.curveMax = weight; + // return AnimationCurve.Constant(0, 1, weight); + // } + // } public static class Presets { private const int samples = 32; public static AnimationCurve Linear(float weight) { - return AnimationCurve.Linear(0f, 0f, 1f, weight); + return AnimationCurve.Linear(0f, 0f, 1000f, weight * 1000); } public static AnimationCurve Power(float exponent, float weight) { // build keyframes @@ -287,7 +287,7 @@ public class Receiver { this.nucleusId = nucleus.id; } - public bool Rebuild(NanoBrainObj brain) { + public bool Rebuild(NanoBrain brain) { if (brain == null) { return false; } diff --git a/Assets/NanoBrain/Perceptoid.cs b/Assets/NanoBrain/Perceptoid.cs index 0d4970f..f46d049 100644 --- a/Assets/NanoBrain/Perceptoid.cs +++ b/Assets/NanoBrain/Perceptoid.cs @@ -14,7 +14,7 @@ public class Perceptoid : Neuroid { public int thingType; public int thingId; - public override void Rebuild(NanoBrainObj brain) { + public override void Rebuild(NanoBrain brain) { base.Rebuild(brain); this.receptor = Receptor.GetReceptor(brain, thingType); this.receptor.perceptei.Add(this); @@ -48,7 +48,7 @@ public class Perceptoid : Neuroid { #endregion Serialization - public Perceptoid(NanoBrainObj brain, int thingType, string name = "sensor") : base(name) { + public Perceptoid(NanoBrain brain, int thingType, string name = "sensor") : base(name) { this.brain = brain; if (this.brain != null) { this.brain.perceptei.Add(this); @@ -80,7 +80,7 @@ public class Perceptoid : Neuroid { } - public static Perceptoid GetPerception(NanoBrainObj brain, int thingType = 0) { + public static Perceptoid GetPerception(NanoBrain brain, int thingType = 0) { foreach (Nucleus nucleus in brain.nuclei) { if (nucleus is Perceptoid perceptoid && (thingType == 0 || perceptoid.receptor.thingType == thingType)) return perceptoid; diff --git a/Assets/NanoBrain/Receptor.cs b/Assets/NanoBrain/Receptor.cs index 050993b..3b1300e 100644 --- a/Assets/NanoBrain/Receptor.cs +++ b/Assets/NanoBrain/Receptor.cs @@ -22,13 +22,13 @@ public class Receptor { public float distanceResolution = 0.1f; public float directionResolution = 5; - public Receptor(NanoBrainObj brain, int thingType) { + public Receptor(NanoBrain brain, int thingType) { this.thingType = thingType; //this.perceptei.Add(perceptoid); brain.receptors.Add(this); } - public static Receptor GetReceptor(NanoBrainObj brain, int thingType) { + public static Receptor GetReceptor(NanoBrain brain, int thingType) { foreach (Receptor receptor in brain.receptors) { if (thingType == 0 || receptor.thingType == thingType) return receptor; @@ -38,9 +38,6 @@ public class Receptor { } public virtual void ProcessStimulus(int thingId, Vector3 newLocalPositionVector) { - //Spherical newLocalPosition = Spherical.FromVector3(newLocalPositionVector); - - Vector3 previousLocalPosition = this.localPosition; this.localPosition = newLocalPositionVector; Perceptoid selectedPerceptoid = null; @@ -50,16 +47,6 @@ public class Receptor { selectedPerceptoid = perceptoid; // Do not look any further - // // This does not do a lot.... - // float deltaDistance = newLocalPosition.distance - previousLocalPosition.distance; - // // See if the change is significant - // AngleFloat deltaDirection = Direction.UnsignedAngle(newLocalPosition.direction, previousLocalPosition.direction); - // if (deltaDistance < this.distanceResolution && deltaDirection.inDegrees < directionResolution) { - // // The difference is not significant we don't process this data. - // this.localPosition = previousLocalPosition; - // return; - // } - // This is now also handled by the UpdateState Spherical.Distance break; } else if (perceptoid.isSleeping) { diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs index 7fdec1b..ae876a8 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs @@ -20,7 +20,7 @@ public class NanoBrainComponent_Editor : Editor { public override VisualElement CreateInspectorGUI() { //NanoBrainComponent component = target as NanoBrainComponent; - NanoBrainObj brain = Application.isPlaying ? component.brain : component.defaultBrain; + NanoBrain brain = Application.isPlaying ? component.brain : component.defaultBrain; if (Application.isPlaying == false) serializedObject.Update(); diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs index 86d346d..656920e 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs @@ -11,7 +11,7 @@ public class NucleusLayer { } public class NanoBrainEditor : EditorWindow { - public NanoBrainObj brain; + public NanoBrain brain; public static VisualElement inspectorContainer; @@ -20,7 +20,7 @@ public class NanoBrainEditor : EditorWindow { GetWindow("NanoBrain Editor"); } - public static void Open(NanoBrainObj asset) { + public static void Open(NanoBrain asset) { NanoBrainEditor editor = GetWindow("NanoBrain Editor"); editor.brain = asset; editor.Show(); @@ -69,7 +69,7 @@ public class NanoBrainEditor : EditorWindow { } public class GraphBoardView : VisualElement { - NanoBrainObj brain; + NanoBrain brain; SerializedObject serializedBrain; Nucleus currentNucleus; private List layers = new(); @@ -99,7 +99,7 @@ public class GraphBoardView : VisualElement { RegisterCallback(OnMouseUp); } - public void SetGraph(NanoBrainObj brain, Nucleus nucleus) { + public void SetGraph(NanoBrain brain, Nucleus nucleus) { this.brain = brain; this.serializedBrain = new SerializedObject(brain); this.currentNucleus = nucleus; @@ -473,9 +473,9 @@ public class GraphNodeWrapper : ScriptableObject { public string title; public Vector2 position; Nucleus node; - NanoBrainObj graph; // needed to write back and mark dirty + NanoBrain graph; // needed to write back and mark dirty - public GraphNodeWrapper Init(Nucleus node, NanoBrainObj graphAsset) { + public GraphNodeWrapper Init(Nucleus node, NanoBrain graphAsset) { this.node = node; this.graph = graphAsset; this.title = " A " + node.name; @@ -499,7 +499,7 @@ public static class OpenAssetHandler { // Called when an asset is double-clicked or opened. [OnOpenAsset] public static bool OpenMyScriptableObject(int instanceID, int line) { - NanoBrainObj obj = EditorUtility.EntityIdToObject(instanceID) as NanoBrainObj; + NanoBrain obj = EditorUtility.EntityIdToObject(instanceID) as NanoBrain; if (obj != null) { NanoBrainEditor.Open(obj); return true; // handled diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs index fce8b3e..3dd33ae 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs @@ -5,7 +5,7 @@ using UnityEditor; using UnityEngine; using UnityEngine.UIElements; -[CustomEditor(typeof(NanoBrainObj))] +[CustomEditor(typeof(NanoBrain))] public class NanoBrainInspector : Editor { protected static VisualElement mainContainer; protected static VisualElement inspectorContainer; @@ -15,7 +15,7 @@ public class NanoBrainInspector : Editor { #region Start public override VisualElement CreateInspectorGUI() { - NanoBrainObj brain = target as NanoBrainObj; + NanoBrain brain = target as NanoBrain; serializedObject.Update(); @@ -72,7 +72,7 @@ public class NanoBrainInspector : Editor { } public class GraphView : VisualElement { - NanoBrainObj brain; + NanoBrain brain; SerializedObject serializedBrain; Nucleus currentNucleus; GameObject gameObject; @@ -103,7 +103,7 @@ public class NanoBrainInspector : Editor { RegisterCallback(OnMouseUp); } - public void SetGraph(GameObject gameObject, NanoBrainObj brain, Nucleus nucleus, VisualElement inspectorContainer) { + public void SetGraph(GameObject gameObject, NanoBrain brain, Nucleus nucleus, VisualElement inspectorContainer) { this.gameObject = gameObject; this.brain = brain; if (Application.isPlaying == false) diff --git a/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs b/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs index 79a25d2..96126b5 100644 --- a/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs +++ b/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs @@ -1,15 +1,15 @@ using UnityEngine; public class NanoBrainComponent : MonoBehaviour { - public NanoBrainObj defaultBrain; - private NanoBrainObj brainInstance; + public NanoBrain defaultBrain; + private NanoBrain brainInstance; public Nucleus root { get { return brainInstance.root; } } - public NanoBrainObj brain { + public NanoBrain brain { get { if (brainInstance == null && defaultBrain != null) { brainInstance = Instantiate(defaultBrain); diff --git a/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs b/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs index 1a52db1..e260806 100644 --- a/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs +++ b/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs @@ -3,7 +3,7 @@ using UnityEngine; using LinearAlgebra; [CreateAssetMenu(menuName = "Passer/NanoBrain")] -public class NanoBrainObj : ScriptableObject, ISerializationCallbackReceiver { +public class NanoBrain : ScriptableObject, ISerializationCallbackReceiver { public string title; public int count; @@ -21,7 +21,7 @@ public class NanoBrainObj : ScriptableObject, ISerializationCallbackReceiver { // public Perception perception; - public NanoBrainObj() { + public NanoBrain() { this.root = new Neuroid(this, "Root"); // this.perception = new Perception(this); } diff --git a/Assets/Scenes/Boids/Boids.unity b/Assets/Scenes/Boids/Boids.unity index a2bc83e..18718af 100644 --- a/Assets/Scenes/Boids/Boids.unity +++ b/Assets/Scenes/Boids/Boids.unity @@ -375,10 +375,10 @@ MonoBehaviour: m_EditorClassIdentifier: Assembly-CSharp::SwarmControl speed: 1 inertia: 0.7 - alignmentForce: 2 - cohesionForce: 4 + alignmentForce: 0.5 + cohesionForce: 2.2 separationForce: -5 - avoidanceForce: 5 + avoidanceForce: 1 separationDistance: 0.3 perceptionDistance: 2 boundaryForce: 5 diff --git a/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs b/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs index 4d51630..ae3f693 100644 --- a/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs +++ b/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs @@ -10,9 +10,9 @@ public class SwarmControl_Editor : Editor { if (EditorGUI.EndChangeCheck()) { SwarmControl swarmControl = (SwarmControl)target; - NanoBrainObj[] nanoBrains = FindObjectsByType(FindObjectsSortMode.None); + NanoBrain[] nanoBrains = FindObjectsByType(FindObjectsSortMode.None); - foreach (NanoBrainObj brain in nanoBrains) { + foreach (NanoBrain brain in nanoBrains) { UpdateWeight(brain, "Avoidance", swarmControl.avoidanceForce); UpdateWeight(brain, "Cohesion", swarmControl.cohesionForce); UpdateWeight(brain, "Separation", swarmControl.separationForce); @@ -22,7 +22,7 @@ public class SwarmControl_Editor : Editor { } } - protected void UpdateWeight(NanoBrainObj brain, string name, float weight) { + protected void UpdateWeight(NanoBrain brain, string name, float weight) { Nucleus root = brain.root; foreach (Synapse synapse in root.synapses) { if (synapse.nucleus.name == name) { diff --git a/Assets/Scenes/Boids/SwarmingBrain.asset b/Assets/Scenes/Boids/SwarmingBrain.asset index 5989f27..fa44b3f 100644 --- a/Assets/Scenes/Boids/SwarmingBrain.asset +++ b/Assets/Scenes/Boids/SwarmingBrain.asset @@ -21,1232 +21,16 @@ MonoBehaviour: _name: Root synapses: - nucleusId: -112538112 - weight: 5 - curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: -10 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1 - value: -10 - inSlope: -10 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 + weight: 1 curveMax: -10 - nucleusId: 1938577052 - weight: 4 - curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 10 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1 - value: 10 - inSlope: 10 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 + weight: 2.1 curveMax: 10 - nucleusId: 1641120128 weight: -5 - curvePreset: 3 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0.001 - value: 10000 - inSlope: 0 - outSlope: -1127886.4 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.008866142 - value: 1127.8864 - inSlope: -1127886.4 - outSlope: -67407.8 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.016732283 - value: 597.6471 - inSlope: -67407.8 - outSlope: -24296.154 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.024598425 - value: 406.5301 - inSlope: -24296.154 - outSlope: -12522.27 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.032464568 - value: 308.02814 - inSlope: -12522.27 - outSlope: -7637.5586 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.040330708 - value: 247.95003 - inSlope: -7637.5586 - outSlope: -5144.5273 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.04819685 - value: 207.48245 - inSlope: -5144.5273 - outSlope: -3700.881 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.056062993 - value: 178.37079 - inSlope: -3700.881 - outSlope: -2790.134 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.06392913 - value: 156.4232 - inSlope: -2790.134 - outSlope: -2178.739 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.07179528 - value: 139.28493 - inSlope: -2178.739 - outSlope: -1748.4618 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.079661414 - value: 125.53129 - inSlope: -1748.4618 - outSlope: -1434.1919 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.087527566 - value: 114.24972 - inSlope: -1434.1919 - outSlope: -1197.6652 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.0953937 - value: 104.82872 - inSlope: -1197.6652 - outSlope: -1015.1933 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.10325985 - value: 96.84306 - inSlope: -1015.1933 - outSlope: -871.471 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.11112598 - value: 89.98795 - inSlope: -871.471 - outSlope: -756.2516 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.11899213 - value: 84.03917 - inSlope: -756.2516 - outSlope: -662.46454 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.12685826 - value: 78.82813 - inSlope: -662.46454 - outSlope: -585.10645 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.13472441 - value: 74.2256 - inSlope: -585.10645 - outSlope: -520.55066 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.14259055 - value: 70.130875 - inSlope: -520.55066 - outSlope: -466.11972 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.1504567 - value: 66.46431 - inSlope: -466.11972 - outSlope: -419.80298 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.15832284 - value: 63.16208 - inSlope: -419.80298 - outSlope: -380.06146 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.16618897 - value: 60.172466 - inSlope: -380.06146 - outSlope: -345.70953 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.17405513 - value: 57.45306 - inSlope: -345.70953 - outSlope: -315.81256 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.18192126 - value: 54.968838 - inSlope: -315.81256 - outSlope: -289.6338 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.1897874 - value: 52.690536 - inSlope: -289.6338 - outSlope: -266.5802 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.19765353 - value: 50.593582 - inSlope: -266.5802 - outSlope: -246.17393 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.20551969 - value: 48.65714 - inSlope: -246.17393 - outSlope: -228.02412 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.21338584 - value: 46.86347 - inSlope: -228.02412 - outSlope: -211.81067 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.22125196 - value: 45.19734 - inSlope: -211.81067 - outSlope: -197.26657 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.22911811 - value: 43.64561 - inSlope: -197.26657 - outSlope: -184.17094 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.23698425 - value: 42.196896 - inSlope: -184.17094 - outSlope: -172.33716 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.2448504 - value: 40.841267 - inSlope: -172.33716 - outSlope: -161.60907 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.25271654 - value: 39.570026 - inSlope: -161.60907 - outSlope: -151.85233 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.2605827 - value: 38.375534 - inSlope: -151.85233 - outSlope: -142.95256 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.2684488 - value: 37.251053 - inSlope: -142.95256 - outSlope: -134.81406 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.27631494 - value: 36.190586 - inSlope: -134.81406 - outSlope: -127.35017 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.28418112 - value: 35.188828 - inSlope: -127.35017 - outSlope: -120.49053 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.29204726 - value: 34.24103 - inSlope: -120.49053 - outSlope: -114.16967 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.2999134 - value: 33.342957 - inSlope: -114.16967 - outSlope: -108.333694 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.30777952 - value: 32.49079 - inSlope: -108.333694 - outSlope: -102.93456 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.31564566 - value: 31.681093 - inSlope: -102.93456 - outSlope: -97.92865 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.3235118 - value: 30.910772 - inSlope: -97.92865 - outSlope: -93.27943 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.33137795 - value: 30.177023 - inSlope: -93.27943 - outSlope: -88.95375 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.33924407 - value: 29.477303 - inSlope: -88.95375 - outSlope: -84.921936 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.34711024 - value: 28.809292 - inSlope: -84.921936 - outSlope: -81.15831 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.3549764 - value: 28.170889 - inSlope: -81.15831 - outSlope: -77.639496 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.36284253 - value: 27.560165 - inSlope: -77.639496 - outSlope: -74.3445 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.37070867 - value: 26.97536 - inSlope: -74.3445 - outSlope: -71.25514 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.3785748 - value: 26.41486 - inSlope: -71.25514 - outSlope: -68.35413 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.38644093 - value: 25.877176 - inSlope: -68.35413 - outSlope: -65.627014 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.39430708 - value: 25.360945 - inSlope: -65.627014 - outSlope: -63.05968 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.40217322 - value: 24.864908 - inSlope: -63.05968 - outSlope: -60.64027 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4100394 - value: 24.387901 - inSlope: -60.64027 - outSlope: -58.35757 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4179055 - value: 23.928854 - inSlope: -58.35757 - outSlope: -56.20101 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.42577165 - value: 23.486769 - inSlope: -56.20101 - outSlope: -54.162277 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4336378 - value: 23.06072 - inSlope: -54.162277 - outSlope: -52.23217 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.44150394 - value: 22.649855 - inSlope: -52.23217 - outSlope: -50.40366 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4493701 - value: 22.253372 - inSlope: -50.40366 - outSlope: -48.669174 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4572362 - value: 21.870535 - inSlope: -48.669174 - outSlope: -47.023064 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.46510234 - value: 21.500645 - inSlope: -47.023064 - outSlope: -45.458923 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.47296852 - value: 21.143057 - inSlope: -45.458923 - outSlope: -43.971752 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.48083466 - value: 20.797169 - inSlope: -43.971752 - outSlope: -42.555935 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4887008 - value: 20.462418 - inSlope: -42.555935 - outSlope: -41.207684 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.49656692 - value: 20.138273 - inSlope: -41.207684 - outSlope: -39.92274 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5044331 - value: 19.824234 - inSlope: -39.92274 - outSlope: -38.696503 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5122992 - value: 19.519844 - inSlope: -38.696503 - outSlope: -37.526264 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5201653 - value: 19.224657 - inSlope: -37.526264 - outSlope: -36.408207 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.52803147 - value: 18.938265 - inSlope: -36.408207 - outSlope: -35.339375 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5358976 - value: 18.66028 - inSlope: -35.339375 - outSlope: -34.316856 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.54376376 - value: 18.390339 - inSlope: -34.316856 - outSlope: -33.338223 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5516299 - value: 18.128096 - inSlope: -33.338223 - outSlope: -32.40057 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.55949605 - value: 17.873228 - inSlope: -32.40057 - outSlope: -31.502443 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.56736225 - value: 17.625423 - inSlope: -31.502443 - outSlope: -30.640682 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5752284 - value: 17.3844 - inSlope: -30.640682 - outSlope: -29.814081 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.58309454 - value: 17.149878 - inSlope: -29.814081 - outSlope: -29.020437 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5909606 - value: 16.9216 - inSlope: -29.020437 - outSlope: -28.257874 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.59882677 - value: 16.69932 - inSlope: -28.257874 - outSlope: -27.525112 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6066929 - value: 16.482803 - inSlope: -27.525112 - outSlope: -26.820477 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.61455905 - value: 16.27183 - inSlope: -26.820477 - outSlope: -26.142757 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6224252 - value: 16.066187 - inSlope: -26.142757 - outSlope: -25.490013 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.63029134 - value: 15.865679 - inSlope: -25.490013 - outSlope: -24.861637 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6381575 - value: 15.670114 - inSlope: -24.861637 - outSlope: -24.256296 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.64602363 - value: 15.47931 - inSlope: -24.256296 - outSlope: -23.672657 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6538898 - value: 15.2930975 - inSlope: -23.672657 - outSlope: -23.109926 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.66175586 - value: 15.111313 - inSlope: -23.109926 - outSlope: -22.566847 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.669622 - value: 14.933799 - inSlope: -22.566847 - outSlope: -22.042978 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.67748815 - value: 14.760406 - inSlope: -22.042978 - outSlope: -21.53681 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6853543 - value: 14.590994 - inSlope: -21.53681 - outSlope: -21.048183 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6932205 - value: 14.425425 - inSlope: -21.048183 - outSlope: -20.575758 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.70108664 - value: 14.263573 - inSlope: -20.575758 - outSlope: -20.119299 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7089528 - value: 14.105311 - inSlope: -20.119299 - outSlope: -19.67763 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7168189 - value: 13.950524 - inSlope: -19.67763 - outSlope: -19.250507 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7246851 - value: 13.799097 - inSlope: -19.250507 - outSlope: -18.836966 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7325512 - value: 13.650923 - inSlope: -18.836966 - outSlope: -18.436777 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7404173 - value: 13.5058975 - inSlope: -18.436777 - outSlope: -18.049162 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.74828345 - value: 13.36392 - inSlope: -18.049162 - outSlope: -17.673689 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7561496 - value: 13.224896 - inSlope: -17.673689 - outSlope: -17.309732 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.76401573 - value: 13.088736 - inSlope: -17.309732 - outSlope: -16.95693 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7718819 - value: 12.95535 - inSlope: -16.95693 - outSlope: -16.614798 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.779748 - value: 12.824656 - inSlope: -16.614798 - outSlope: -16.282848 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.78761417 - value: 12.696572 - inSlope: -16.282848 - outSlope: -15.960961 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7954803 - value: 12.571021 - inSlope: -15.960961 - outSlope: -15.648289 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.80334646 - value: 12.447929 - inSlope: -15.648289 - outSlope: -15.344826 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.81121254 - value: 12.327226 - inSlope: -15.344826 - outSlope: -15.050109 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.81907874 - value: 12.208838 - inSlope: -15.050109 - outSlope: -14.763738 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8269449 - value: 12.092705 - inSlope: -14.763738 - outSlope: -14.485619 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.83481103 - value: 11.978759 - inSlope: -14.485619 - outSlope: -14.215137 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8426772 - value: 11.8669405 - inSlope: -14.215137 - outSlope: -13.952171 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8505433 - value: 11.757191 - inSlope: -13.952171 - outSlope: -13.696481 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.85840946 - value: 11.649452 - inSlope: -13.696481 - outSlope: -13.447701 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8662756 - value: 11.543671 - inSlope: -13.447701 - outSlope: -13.20571 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.87414175 - value: 11.439793 - inSlope: -13.20571 - outSlope: -12.970266 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8820079 - value: 11.337767 - inSlope: -12.970266 - outSlope: -12.74086 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.889874 - value: 11.237546 - inSlope: -12.74086 - outSlope: -12.517565 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8977401 - value: 11.139081 - inSlope: -12.517565 - outSlope: -12.300185 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.90560627 - value: 11.042326 - inSlope: -12.300185 - outSlope: -12.088262 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9134724 - value: 10.947238 - inSlope: -12.088262 - outSlope: -11.881914 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.92133856 - value: 10.853773 - inSlope: -11.881914 - outSlope: -11.680659 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9292047 - value: 10.761891 - inSlope: -11.680659 - outSlope: -11.484618 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.93707085 - value: 10.671552 - inSlope: -11.484618 - outSlope: -11.293341 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.94493705 - value: 10.582716 - inSlope: -11.293341 - outSlope: -11.106962 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9528032 - value: 10.495347 - inSlope: -11.106962 - outSlope: -10.925105 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.96066934 - value: 10.409409 - inSlope: -10.925105 - outSlope: -10.747573 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9685354 - value: 10.324867 - inSlope: -10.747573 - outSlope: -10.574365 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.97640157 - value: 10.241688 - inSlope: -10.574365 - outSlope: -10.405358 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9842677 - value: 10.159838 - inSlope: -10.405358 - outSlope: -10.240476 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.99213386 - value: 10.079285 - inSlope: -10.240476 - outSlope: -10.079229 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1 - value: 10 - inSlope: -10.079229 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 curveMax: 1000 - nucleusId: -1857835930 - weight: 2 - curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 + weight: 0.5 curveMax: 1 receivers: [] nucleusType: @@ -1265,8 +49,8 @@ MonoBehaviour: inWeight: 0 outWeight: 0 - serializedVersion: 3 - time: 1 - value: 1 + time: 1000 + value: 1000 inSlope: 1 outSlope: 0 tangentMode: 0 @@ -1285,13 +69,6 @@ MonoBehaviour: synapses: - nucleusId: 407735232 weight: -1 - curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 curveMax: 0 receivers: - nucleusId: -1707533328 @@ -1311,8 +88,8 @@ MonoBehaviour: inWeight: 0 outWeight: 0 - serializedVersion: 3 - time: 1 - value: 1 + time: 1000 + value: 1000 inSlope: 1 outSlope: 0 tangentMode: 0 @@ -1331,63 +108,21 @@ MonoBehaviour: synapses: - nucleusId: -1659429232 weight: 1 - curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 curveMax: 1 - nucleusId: 839544896 weight: 1 - curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 curveMax: 1 - nucleusId: -348340288 weight: 1 - curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 curveMax: 1 - nucleusId: -1095934288 weight: 1 - curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 curveMax: 1 - nucleusId: -1413006832 weight: 1 - curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 curveMax: 1 - nucleusId: -61245040 weight: 1 - curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 curveMax: 1 receivers: - nucleusId: -1707533328 @@ -1427,63 +162,21 @@ MonoBehaviour: synapses: - nucleusId: -1659429232 weight: 1 - curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 curveMax: 1 - nucleusId: 839544896 weight: 1 - curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 curveMax: 1 - nucleusId: -348340288 weight: 1 - curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 curveMax: 1 - nucleusId: -1095934288 weight: 1 - curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 curveMax: 1 - nucleusId: -1413006832 weight: 1 - curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 curveMax: 1 - nucleusId: -61245040 weight: 1 - curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 curveMax: 1 receivers: - nucleusId: -1707533328 @@ -1793,63 +486,21 @@ MonoBehaviour: synapses: - nucleusId: -1659687600 weight: 1 - curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 curveMax: 1 - nucleusId: 1322333072 weight: 1 - curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 curveMax: 1 - nucleusId: -1563920864 weight: 1 - curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 curveMax: 1 - nucleusId: 182328688 weight: 1 - curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 curveMax: 1 - nucleusId: -1666561744 weight: 1 - curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 curveMax: 1 - nucleusId: -1884196224 weight: 1 - curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 curveMax: 1 receivers: - nucleusId: -1707533328 diff --git a/mono_crash.mem.19211.1.blob b/mono_crash.mem.19211.1.blob deleted file mode 100644 index b4452d03786c823d7f5bf4b096959cbe169e45b1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10000001 zcmeFtfdBvi0Dz$VsTV1P3IhfV7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjm>oJ0000000P=rrgaii; z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=0qxKM2><{9fS~`c+Y#sl4Hz(Bz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM a7%*VKfB^#r3>YwAz<>b*1`HT5up0=UX#fEL From 5206469764c3b19e9c00f5930bdd4e664f11672d Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 8 Jan 2026 17:41:43 +0100 Subject: [PATCH 056/179] Improved network --- Assembly-CSharp.csproj | 3 +- Assets/NanoBrain/Neuroid.cs | 10 +- Assets/NanoBrain/Nucleus.cs | 10 +- Assets/NanoBrain/PercepteiArray.cs | 22 + Assets/NanoBrain/PercepteiArray.cs.meta | 2 + Assets/NanoBrain/Perceptoid.cs | 33 +- Assets/NanoBrain/Receptor.cs | 4 +- .../VisualEditor/Editor/NanoBrainEditor.cs | 6 +- .../VisualEditor/Editor/NanoBrainInspector.cs | 183 +- .../{NanoBrainObj.cs => NanoBrain.cs} | 34 +- ...NanoBrainObj.cs.meta => NanoBrain.cs.meta} | 0 .../VisualEditor/NanoBrainComponent.cs | 22 +- Assets/Scenes/Boids/Boids.unity | 5 +- Assets/Scenes/Boids/Scripts/Boid.cs | 9 +- .../Scripts/Editor/SwarmControl_Editor.cs | 24 +- Assets/Scenes/Boids/Scripts/SwarmControl.cs | 2 +- Assets/Scenes/Boids/SwarmingBrain.asset | 7357 ++++++++++++++++- 17 files changed, 7248 insertions(+), 478 deletions(-) create mode 100644 Assets/NanoBrain/PercepteiArray.cs create mode 100644 Assets/NanoBrain/PercepteiArray.cs.meta rename Assets/NanoBrain/VisualEditor/{NanoBrainObj.cs => NanoBrain.cs} (73%) rename Assets/NanoBrain/VisualEditor/{NanoBrainObj.cs.meta => NanoBrain.cs.meta} (100%) diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index 6091706..49d2ce0 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -53,8 +53,8 @@ - + @@ -62,6 +62,7 @@ + diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index 8f8401e..0f9894a 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; using UnityEngine; -using LinearAlgebra; [System.Serializable] public class Neuroid : Nucleus { @@ -80,11 +78,9 @@ public class Neuroid : Nucleus { //Applying the weight factgors foreach (Synapse synapse in this.synapses) { - Vector3 outputValue = synapse.nucleus.outputValue; - float magnitude = synapse.weight * outputValue.magnitude; - - sum += magnitude * outputValue.normalized; - n++; + sum += synapse.weight * synapse.nucleus.outputValue; + if (synapse.nucleus.outputValue.sqrMagnitude != 0) + n++; } if (average) sum /= n; diff --git a/Assets/NanoBrain/Nucleus.cs b/Assets/NanoBrain/Nucleus.cs index 7141d09..62e4481 100644 --- a/Assets/NanoBrain/Nucleus.cs +++ b/Assets/NanoBrain/Nucleus.cs @@ -154,11 +154,11 @@ public class Nucleus { public virtual void UpdateState() { } public void UpdateResult(Vector3 result) { - float d = Vector3.Distance(result, this.outputValue); - if (d < 0.5f) { - //Debug.Log($"insignificant update: {d}"); - return; - } + // float d = Vector3.Distance(result, this.outputValue); + // if (d < 0.5f) { + // //Debug.Log($"insignificant update: {d}"); + // return; + // } this.outputValue = result; foreach (Receiver receiver in this.receivers) diff --git a/Assets/NanoBrain/PercepteiArray.cs b/Assets/NanoBrain/PercepteiArray.cs new file mode 100644 index 0000000..cf4b5e2 --- /dev/null +++ b/Assets/NanoBrain/PercepteiArray.cs @@ -0,0 +1,22 @@ +public class PercepteiArray { + public ArrayPerceptoid[] perceptei; + public string name; + + public PercepteiArray(NanoBrain brain, int thingType, string baseName, uint count) { + this.name = baseName; + this.perceptei = new ArrayPerceptoid[count]; + for (uint i = 0; i < count; i++) { + this.perceptei[i] = new ArrayPerceptoid(brain, thingType, $"{baseName}[{i}]") { + array = this + }; + } + } +} + +public class ArrayPerceptoid : Perceptoid { + public PercepteiArray array; + + public ArrayPerceptoid(NanoBrain brain, int thingType, string name = "sensor") : base(brain, thingType, name) { + } + +} \ No newline at end of file diff --git a/Assets/NanoBrain/PercepteiArray.cs.meta b/Assets/NanoBrain/PercepteiArray.cs.meta new file mode 100644 index 0000000..61e26b7 --- /dev/null +++ b/Assets/NanoBrain/PercepteiArray.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f8cac60bd79854595a8571c042f77998 \ No newline at end of file diff --git a/Assets/NanoBrain/Perceptoid.cs b/Assets/NanoBrain/Perceptoid.cs index f46d049..62f0b11 100644 --- a/Assets/NanoBrain/Perceptoid.cs +++ b/Assets/NanoBrain/Perceptoid.cs @@ -6,7 +6,7 @@ public class Perceptoid : Neuroid { // A neuroid which has no neurons as input // But receives value from a receptor public Receptor receptor; - //public VelocityNeuroid velocityNeuroid; + public string baseName; #region Serialization @@ -58,21 +58,22 @@ public class Perceptoid : Neuroid { this.nucleusType = nameof(Perceptoid); this.name = name; + this.baseName = name; this.thingType = thingType; this.receptor = Receptor.GetReceptor(brain, thingType); this.receptor.perceptei.Add(this); } - public void Replace(int thingType, string name = "sensor") { - this.name = name; + // public void Replace(int thingType, string name = "sensor") { + // this.name = name; - this.thingType = thingType; - this.receptor.thingType = thingType; - this.receptor.localPosition = Vector3.zero; + // this.thingType = thingType; + // this.receptor.thingType = thingType; + // this.receptor.localPosition = Vector3.zero; - this.outputValue = Vector3.zero; - this.receivers = new(); - } + // this.outputValue = Vector3.zero; + // this.receivers = new(); + // } public override void UpdateState() { Vector3 result = this.receptor.localPosition; @@ -80,11 +81,11 @@ public class Perceptoid : Neuroid { } - public static Perceptoid GetPerception(NanoBrain brain, int thingType = 0) { - foreach (Nucleus nucleus in brain.nuclei) { - if (nucleus is Perceptoid perceptoid && (thingType == 0 || perceptoid.receptor.thingType == thingType)) - return perceptoid; - } - return null; - } + // public static Perceptoid GetPerception(NanoBrain brain, int thingType = 0) { + // foreach (Nucleus nucleus in brain.nuclei) { + // if (nucleus is Perceptoid perceptoid && (thingType == 0 || perceptoid.receptor.thingType == thingType)) + // return perceptoid; + // } + // return null; + // } } diff --git a/Assets/NanoBrain/Receptor.cs b/Assets/NanoBrain/Receptor.cs index 3b1300e..3e63760 100644 --- a/Assets/NanoBrain/Receptor.cs +++ b/Assets/NanoBrain/Receptor.cs @@ -37,7 +37,7 @@ public class Receptor { return newReceptor; } - public virtual void ProcessStimulus(int thingId, Vector3 newLocalPositionVector) { + public virtual void ProcessStimulus(int thingId, Vector3 newLocalPositionVector, string thingName = null) { this.localPosition = newLocalPositionVector; Perceptoid selectedPerceptoid = null; @@ -75,6 +75,8 @@ public class Receptor { } // Debug.Log($"Stimulus {thingType} {thingId} {selectedPerceptoid.name}"); selectedPerceptoid.thingId = thingId; + if (thingName != null) + selectedPerceptoid.name = selectedPerceptoid.baseName + " " + thingName; selectedPerceptoid.UpdateState(); } } \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs index 656920e..230bfa1 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs @@ -1,3 +1,4 @@ +/* using UnityEditor; using UnityEngine; using UnityEngine.UIElements; @@ -406,7 +407,7 @@ public class GraphBoardView : VisualElement { // } } -/* + public class NodeView : VisualElement { Nucleus data; GraphBoardView board; @@ -466,7 +467,7 @@ public class NodeView : VisualElement { //dragging = false; } } -*/ + public class GraphNodeWrapper : ScriptableObject { // expose fields that map to GraphNode @@ -507,3 +508,4 @@ public static class OpenAssetHandler { return false; // let Unity open normally } } +*/ \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs index 3dd33ae..e8f7daf 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs @@ -181,22 +181,6 @@ public class NanoBrainInspector : Editor { } - // basic pan/zoom handling - // void OnWheel(WheelEvent e) { - // if (e.ctrlKey) { - // float delta = -e.delta.y * 0.001f; - // zoom = Mathf.Clamp(zoom + delta, 0.25f, 2f); - // content.transform.rotation = Quaternion.identity; // keep transform accessible - // content.transform.scale = new Vector3(zoom, zoom, 1); - // e.StopPropagation(); - // } - // else { - // pan += e.delta; - // content.style.left = pan.x; - // content.style.top = pan.y; - // } - // } - void OnMouseDown(MouseDownEvent e) { if (e.button == 2) { draggingCanvas = true; lastMouse = e.mousePosition; e.StopPropagation(); } } @@ -220,8 +204,6 @@ public class NanoBrainInspector : Editor { Handles.BeginGUI(); DrawGraph(); - // foreach (NeuroidLayer layer in layers) - // DrawLayer(layer); Handles.EndGUI(); } @@ -291,15 +273,24 @@ public class NanoBrainInspector : Editor { float margin = 10 + spacing / 2; int row = 0; - foreach (Synapse receiver in nucleus.synapses) { - Nucleus receiverNucleus = receiver.nucleus; - + List drawnArrays = new(); + foreach (Synapse synapse in nucleus.synapses) { Vector3 pos = new(250, margin + row * spacing, 0.0f); Handles.color = Color.white; Handles.DrawLine(parentPos, pos); + if (synapse.nucleus is ArrayPerceptoid perceptoid) { + if (drawnArrays.Contains(perceptoid.array)) + // We already drawn this array + continue; - DrawNucleus(receiverNucleus, pos, maxValue, size); - row++; + drawnArrays.Add(perceptoid.array); + DrawArray(perceptoid.array, pos, size); + } + else { + + DrawNucleus(synapse.nucleus, pos, maxValue, size); + row++; + } } } @@ -312,7 +303,7 @@ public class NanoBrainInspector : Editor { } Handles.DrawSolidDisc(position, Vector3.forward, size); Vector3 labelPos = position - Vector3.down * (size + 0.2f); // below disc along up axis - GUIStyle style = new GUIStyle(EditorStyles.label) { + GUIStyle style = new(EditorStyles.label) { alignment = TextAnchor.UpperCenter, normal = { textColor = Color.white }, fontStyle = FontStyle.Bold @@ -335,15 +326,28 @@ public class NanoBrainInspector : Editor { } } + private void DrawArray(PercepteiArray array, Vector3 position, float size) { + Vector3 offset = new(size/4, size/4, 0); + Handles.color = Color.darkGray; + Handles.DrawSolidDisc(position + offset * 2, Vector3.forward, size); + Handles.color = Color.lightGray; + Handles.DrawSolidDisc(position + offset, Vector3.forward, size); + Handles.color = Color.white; + Handles.DrawSolidDisc(position, Vector3.forward, size); + + Vector3 labelPos = position - Vector3.down * (size + 0.2f); // below disc along up axis + GUIStyle style = new GUIStyle(EditorStyles.label) { + alignment = TextAnchor.UpperCenter, + normal = { textColor = Color.white }, + fontStyle = FontStyle.Bold + }; + Handles.Label(labelPos, array.name, style); + + // To do: add HandleClick (see above) to expand the array + } + private void HandleMouseHover(Nucleus nucleus, Rect rect) { GUIContent tooltip; - // if (nucleus is SensoryNeuroid sensoryNeuroid) { - // tooltip = new( - // $"{sensoryNeuroid.name}" + - // $"\nThing {sensoryNeuroid.receptor.thingType}" + - // $"\nValue: {nucleus.outputValue}"); - // } - //else if (nucleus is Perceptoid perceptoid) { if (perceptoid.receptor != null) { tooltip = new( @@ -419,42 +423,43 @@ public class NanoBrainInspector : Editor { EditorGUILayout.LabelField(" "); if (this.currentNucleus.synapses.Count > 0) { - foreach (Synapse synapse in this.currentNucleus.synapses) { + Synapse[] synapses = this.currentNucleus.synapses.ToArray(); + foreach (Synapse synapse in synapses) { if (synapse.nucleus != null) { EditorGUILayout.Space(); EditorGUI.BeginDisabledGroup(synapse.nucleus.isSleeping); if (Application.isPlaying) EditorGUILayout.FloatField(synapse.nucleus.name, synapse.nucleus.outputValue.magnitude * synapse.weight); - else + else { + EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField(synapse.nucleus.name); + if (GUILayout.Button("Disconnect")) + synapse.nucleus.RemoveReceiver(this.currentNucleus); + EditorGUILayout.EndHorizontal(); + } EditorGUI.indentLevel++; - // EditorGUI.BeginChangeCheck(); synapse.weight = EditorGUILayout.FloatField("Weight", synapse.weight); - - // synapse.curvePreset = (Synapse.CurvePresets)EditorGUILayout.EnumPopup("Preset", synapse.curvePreset); - // if (EditorGUI.EndChangeCheck()) { - // synapse.curve = synapse.GenerateCurve(); - // } - // if (synapse.curveMax > 0) - // EditorGUILayout.CurveField("Curve", synapse.curve, Color.cyan, new Rect(0, 0, 1, synapse.curveMax)); - // else - // EditorGUILayout.CurveField("Curve", synapse.curve, Color.cyan, new Rect(0, synapse.curveMax, 1, -synapse.curveMax)); EditorGUI.indentLevel--; EditorGUI.EndDisabledGroup(); } } - //EditorGUI.indentLevel--; } - if (GUILayout.Button("Add Neuron")) + + EditorGUILayout.Space(); + + ConnectNucleus(this.currentNucleus); + if (GUILayout.Button("Add Input Neuron")) AddInputNeuron(this.currentNucleus); - if (GUILayout.Button("Add Perceptoid")) + if (GUILayout.Button("Add Input Perceptoid")) AddPerceptoid(this.currentNucleus); + + EditorGUILayout.Space(); + if (GUILayout.Button("Delete this neuron")) DeleteNeuron(this.currentNucleus); - ConnectNucleus(this.currentNucleus); - DisconnectNucleus(this.currentNucleus); + //DisconnectNucleus(this.currentNucleus); if (this.gameObject != null) { Vector3 worldVector = this.gameObject.transform.TransformVector(this.currentNucleus.outputValue); @@ -498,9 +503,9 @@ public class NanoBrainInspector : Editor { if (this.currentNucleus.brain == null) return; - //string[] names = this.currentNucleus.brain.perceptei.Select(i => i.name).ToArray(); - IEnumerable perceptei = this.currentNucleus.brain.perceptei.Select(i => i.name); - IEnumerable nuclei = this.currentNucleus.brain.nuclei.Select(i => i.name); + IEnumerable synapseNuclei = this.currentNucleus.synapses.Select(synapse => synapse.nucleus.name); + IEnumerable perceptei = this.currentNucleus.brain.perceptei.Select(i => i.name).Except(synapseNuclei); + IEnumerable nuclei = this.currentNucleus.brain.nuclei.Select(i => i.name).Except(synapseNuclei); string[] names = perceptei.Concat(nuclei).ToArray(); int selectedIndex = -1; selectedIndex = EditorGUILayout.Popup("Connect to", selectedIndex, names); @@ -527,32 +532,6 @@ public class NanoBrainInspector : Editor { synapse.nucleus.RemoveReceiver(this.currentNucleus); } } - - // private Vector3 NodePosition(Nucleus nucleus, int layerNodeCount = 1) { - // if (this.neuroidPositions.ContainsKey(nucleus)) { - // Vector2Int nucleusPos = this.neuroidPositions[nucleus]; - // return NodePosition(nucleusPos, layerNodeCount); - // } - // else { - // return Vector3.zero; - // } - // } - // private Vector3 NodePosition(Vector2Int location, int layerNodeCount = 1) { - // float spacing = 400f / layerNodeCount; - // float margin = 10 + spacing / 2; - // float size = 20; - // Vector3 parentPos = new(100 + location.x * 100 - size, margin + location.y * spacing - size, 0.1f); - // return parentPos; - // } - - - // public void CreateEdge(string fromId, string toId) { - // if (fromId == toId) return; - // Undo.RecordObject(graph, "Create Edge"); - // graph.edges.Add(new GraphEdge { fromNodeId = fromId, toNodeId = toId }); - // EditorUtility.SetDirty(graph); - // Rebuild(); - // } } #endregion Start @@ -573,29 +552,31 @@ public class NanoBrainInspector : Editor { } } - // protected virtual void OnSceneGUI() { - // NanoBrain brain = target as NanoBrain; - // if (brain == null) - // return; - - // Vector3 position = brain.transform.position; - // float radius = 1; - - - // Handles.DrawWireDisc(position, Vector3.up, radius); // horizontal circle - // Handles.DrawWireDisc(position, Vector3.right, radius); // X-plane - // Handles.DrawWireDisc(position, Vector3.forward, radius); // Z-plane - - - // // Debug.DrawRay(brain.transform.position, Vector3.forward, Color.magenta); - // // Handles.color = Color.green; - // // Handles.DrawLine(brain.transform.position, brain.transform.position + Vector3.up); - - // // Handles.color = Color.yellow; - // // Vector3 worldForce = brain.transform.TransformDirection(this.currentNucleus.outputValue); - // // //Debug.DrawRay(position, worldForce * 10, Color.yellow); - // // Handles.DrawLine(position, position + worldForce * 10); - // } - #endregion Update } + +public class GraphNodeWrapper : ScriptableObject { + // expose fields that map to GraphNode + public string title; + public Vector2 position; + Nucleus node; + NanoBrain graph; // needed to write back and mark dirty + + public GraphNodeWrapper Init(Nucleus node, NanoBrain graphAsset) { + this.node = node; + this.graph = graphAsset; + this.title = " A " + node.name; + //position = node.position; + return this; + } + void OnValidate() { + if (node != null) { + node.name = title; + //node.position = position; +#if UNITY_EDITOR + if (graph != null) + UnityEditor.EditorUtility.SetDirty(graph); +#endif + } + } +} \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs b/Assets/NanoBrain/VisualEditor/NanoBrain.cs similarity index 73% rename from Assets/NanoBrain/VisualEditor/NanoBrainObj.cs rename to Assets/NanoBrain/VisualEditor/NanoBrain.cs index e260806..93e5c00 100644 --- a/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs +++ b/Assets/NanoBrain/VisualEditor/NanoBrain.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using UnityEngine; -using LinearAlgebra; [CreateAssetMenu(menuName = "Passer/NanoBrain")] public class NanoBrain : ScriptableObject, ISerializationCallbackReceiver { @@ -19,11 +18,8 @@ public class NanoBrain : ScriptableObject, ISerializationCallbackReceiver { public Nucleus root; public int rootId; - // public Perception perception; - public NanoBrain() { this.root = new Neuroid(this, "Root"); - // this.perception = new Perception(this); } public Neuroid AddNeuron(string name) { @@ -32,18 +28,10 @@ public class NanoBrain : ScriptableObject, ISerializationCallbackReceiver { } public void UpdateNuclei() { - foreach (Nucleus nucleus in nuclei) { - //nucleus.stale++; - nucleus.IncreaseAge(); - // if (nucleus.isSleeping) - // nucleus.outputValue = Spherical.zero; - } - foreach (Perceptoid perception in perceptei) { - //perception.stale++; - perception.IncreaseAge(); - // if (perception.isSleeping) - // perception.outputValue = Spherical.zero; - } + foreach (Nucleus nucleus in nuclei) + nucleus.IncreaseAge(); + foreach (Perceptoid perception in perceptei) + perception.IncreaseAge(); } public void OnBeforeSerialize() { @@ -57,14 +45,8 @@ public class NanoBrain : ScriptableObject, ISerializationCallbackReceiver { nucleus.Rebuild(this); } - // List rebuildNuclei = new(); - // foreach (Nucleus nucleus in this.nuclei.ToArray()) { - // rebuildNuclei.Add(Nucleus.RebuildType(this, nucleus)); - // } - // this.nuclei = rebuildNuclei; - foreach (Perceptoid perceptoid in this.perceptei.ToArray()) { - perceptoid.Rebuild(this); - } + foreach (Perceptoid perceptoid in this.perceptei.ToArray()) + perceptoid.Rebuild(this); } catch (System.Exception) { } this.GarbageCollection(); @@ -85,9 +67,6 @@ public class NanoBrain : ScriptableObject, ISerializationCallbackReceiver { if (nucleus.brain == null) nucleus.brain = this; - if (nucleus.name == "Boid1") - Debug.Log(" Found boiid1"); - visitedNuclei.Add(nucleus); if (nucleus.synapses != null) { HashSet visitedSynapses = new(); @@ -105,7 +84,6 @@ public class NanoBrain : ScriptableObject, ISerializationCallbackReceiver { if (receiver != null && receiver.nucleus != null) { visitedReceivers.Add(receiver); visitedNuclei.Add(receiver.nucleus); - //MarkNuclei(visitedNuclei, receiver.nucleus); } } nucleus.receivers.RemoveAll(receiver => visitedReceivers.Contains(receiver) == false); diff --git a/Assets/NanoBrain/VisualEditor/NanoBrainObj.cs.meta b/Assets/NanoBrain/VisualEditor/NanoBrain.cs.meta similarity index 100% rename from Assets/NanoBrain/VisualEditor/NanoBrainObj.cs.meta rename to Assets/NanoBrain/VisualEditor/NanoBrain.cs.meta diff --git a/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs b/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs index 96126b5..bdeda86 100644 --- a/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs +++ b/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs @@ -4,18 +4,30 @@ public class NanoBrainComponent : MonoBehaviour { public NanoBrain defaultBrain; private NanoBrain brainInstance; - public Nucleus root { - get { - return brainInstance.root; - } - } + public Nucleus root => brainInstance.root; public NanoBrain brain { get { if (brainInstance == null && defaultBrain != null) { brainInstance = Instantiate(defaultBrain); brainInstance.name = defaultBrain.name + " (Instance)"; + + SwarmControl sc = FindFirstObjectByType(); + UpdateWeight(brainInstance, "Avoidance", sc.avoidanceForce); + UpdateWeight(brainInstance, "Cohesion", sc.cohesionForce); + UpdateWeight(brainInstance, "Separation", sc.separationForce); + UpdateWeight(brainInstance, "Alignment", sc.alignmentForce); } return brainInstance; } } + + public static void UpdateWeight(NanoBrain brain, string name, float weight) { + Nucleus root = brain.root; + foreach (Synapse synapse in root.synapses) { + if (synapse.nucleus.name == name) { + synapse.weight = weight; + } + } + } + } \ No newline at end of file diff --git a/Assets/Scenes/Boids/Boids.unity b/Assets/Scenes/Boids/Boids.unity index 18718af..de7d29d 100644 --- a/Assets/Scenes/Boids/Boids.unity +++ b/Assets/Scenes/Boids/Boids.unity @@ -376,12 +376,11 @@ MonoBehaviour: speed: 1 inertia: 0.7 alignmentForce: 0.5 - cohesionForce: 2.2 - separationForce: -5 + cohesionForce: 0.1 + separationForce: -0.1 avoidanceForce: 1 separationDistance: 0.3 perceptionDistance: 2 - boundaryForce: 5 spaceSize: {x: 10, y: 10, z: 10} boundaryWidth: {x: 1, y: 1, z: 1} --- !u!114 &301943979 diff --git a/Assets/Scenes/Boids/Scripts/Boid.cs b/Assets/Scenes/Boids/Scripts/Boid.cs index 260a788..7b16c88 100644 --- a/Assets/Scenes/Boids/Scripts/Boid.cs +++ b/Assets/Scenes/Boids/Scripts/Boid.cs @@ -46,9 +46,14 @@ public class Boid : MonoBehaviour { int thingId = neighbour.GetInstanceID(); - Vector3 localPosition = this.transform.InverseTransformPoint(neighbour.transform.position); + Vector3 localPosition = this.transform.InverseTransformPoint(neighbour.transform.position); + float d = localPosition.magnitude; + if (d <= sc.separationDistance) + localPosition = localPosition.normalized * 0.01f; + else + localPosition = localPosition.normalized * (localPosition.magnitude - sc.separationDistance); if (localPosition.sqrMagnitude > 0) - boidReceptor?.ProcessStimulus(thingId, localPosition); + boidReceptor?.ProcessStimulus(thingId, localPosition, neighbour.name); Vector3 localVelocity = this.transform.InverseTransformVector(neighbour.velocity); if (localVelocity.sqrMagnitude > 0) diff --git a/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs b/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs index ae3f693..5adbcb7 100644 --- a/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs +++ b/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs @@ -13,21 +13,21 @@ public class SwarmControl_Editor : Editor { NanoBrain[] nanoBrains = FindObjectsByType(FindObjectsSortMode.None); foreach (NanoBrain brain in nanoBrains) { - UpdateWeight(brain, "Avoidance", swarmControl.avoidanceForce); - UpdateWeight(brain, "Cohesion", swarmControl.cohesionForce); - UpdateWeight(brain, "Separation", swarmControl.separationForce); - UpdateWeight(brain, "Alignment", swarmControl.alignmentForce); + NanoBrainComponent.UpdateWeight(brain, "Avoidance", swarmControl.avoidanceForce); + NanoBrainComponent.UpdateWeight(brain, "Cohesion", swarmControl.cohesionForce); + NanoBrainComponent.UpdateWeight(brain, "Separation", swarmControl.separationForce); + NanoBrainComponent.UpdateWeight(brain, "Alignment", swarmControl.alignmentForce); } Debug.Log("Updated weights"); } } - protected void UpdateWeight(NanoBrain brain, string name, float weight) { - Nucleus root = brain.root; - foreach (Synapse synapse in root.synapses) { - if (synapse.nucleus.name == name) { - synapse.weight = weight; - } - } - } + // protected void UpdateWeight(NanoBrain brain, string name, float weight) { + // Nucleus root = brain.root; + // foreach (Synapse synapse in root.synapses) { + // if (synapse.nucleus.name == name) { + // synapse.weight = weight; + // } + // } + // } } \ No newline at end of file diff --git a/Assets/Scenes/Boids/Scripts/SwarmControl.cs b/Assets/Scenes/Boids/Scripts/SwarmControl.cs index 0326213..80d1b15 100644 --- a/Assets/Scenes/Boids/Scripts/SwarmControl.cs +++ b/Assets/Scenes/Boids/Scripts/SwarmControl.cs @@ -14,7 +14,7 @@ public class SwarmControl : MonoBehaviour // public float bodyForce = 20; public float perceptionDistance = 1.0f; - public float boundaryForce = 2.0f; + //public float boundaryForce = 2.0f; public Vector3 spaceSize = new (10, 10, 10); public Vector3 boundaryWidth = Vector3.one * 1.0f; } diff --git a/Assets/Scenes/Boids/SwarmingBrain.asset b/Assets/Scenes/Boids/SwarmingBrain.asset index fa44b3f..c78bca5 100644 --- a/Assets/Scenes/Boids/SwarmingBrain.asset +++ b/Assets/Scenes/Boids/SwarmingBrain.asset @@ -24,7 +24,7 @@ MonoBehaviour: weight: 1 curveMax: -10 - nucleusId: 1938577052 - weight: 2.1 + weight: 2.2 curveMax: 10 - nucleusId: 1641120128 weight: -5 @@ -160,319 +160,49 @@ MonoBehaviour: - id: 1641120128 _name: Separation synapses: - - nucleusId: -1659429232 + - nucleusId: 1710403072 weight: 1 curveMax: 1 - - nucleusId: 839544896 + - nucleusId: -916054576 weight: 1 curveMax: 1 - - nucleusId: -348340288 + - nucleusId: -1391520368 weight: 1 curveMax: 1 - - nucleusId: -1095934288 + - nucleusId: 763145504 weight: 1 curveMax: 1 - - nucleusId: -1413006832 + - nucleusId: 1469392160 weight: 1 curveMax: 1 - - nucleusId: -61245040 + - nucleusId: -1828317248 weight: 1 curveMax: 1 receivers: - nucleusId: -1707533328 nucleusType: isSleeping: 0 - _curvePreset: 2 + _curvePreset: 0 curve: serializedVersion: 2 m_Curve: - serializedVersion: 3 time: 0 value: 0 - inSlope: 5.5677648 - outSlope: 5.5677648 - tangentMode: 35 + inSlope: 0 + outSlope: 1 + tangentMode: 0 weightedMode: 0 inWeight: 0 - outWeight: 0.33333334 + outWeight: 0 - serializedVersion: 3 - time: 0.032258064 - value: 0.1796053 - inSlope: 3.937004 - outSlope: 3.937004 - tangentMode: 35 + time: 1000 + value: 1000 + inSlope: 1 + outSlope: 0 + tangentMode: 0 weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.06451613 - value: 0.25400025 - inSlope: 2.037943 - outSlope: 2.037943 - tangentMode: 35 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.09677419 - value: 0.3110855 - inSlope: 1.6307607 - outSlope: 1.6307607 - tangentMode: 35 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.12903225 - value: 0.3592106 - inSlope: 1.4031246 - outSlope: 1.4031246 - tangentMode: 35 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.16129032 - value: 0.40160966 - inSlope: 1.2513264 - outSlope: 1.2513264 - tangentMode: 35 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.19354838 - value: 0.43994135 - inSlope: 1.1405103 - outSlope: 1.1405103 - tangentMode: 35 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.22580644 - value: 0.47519097 - inSlope: 1.0549169 - outSlope: 1.0549169 - tangentMode: 35 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.2580645 - value: 0.5080005 - inSlope: 0.98618674 - outSlope: 0.98618674 - tangentMode: 35 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.29032257 - value: 0.5388159 - inSlope: 0.92940044 - outSlope: 0.92940044 - tangentMode: 35 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.32258064 - value: 0.5679618 - inSlope: 0.88144594 - outSlope: 0.88144594 - tangentMode: 35 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.3548387 - value: 0.5956834 - inSlope: 0.84024215 - outSlope: 0.84024215 - tangentMode: 35 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.38709676 - value: 0.622171 - inSlope: 0.8043368 - outSlope: 0.8043368 - tangentMode: 35 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.41935483 - value: 0.6475761 - inSlope: 0.77268314 - outSlope: 0.77268314 - tangentMode: 35 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.4516129 - value: 0.6720215 - inSlope: 0.74449944 - outSlope: 0.74449944 - tangentMode: 35 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.48387095 - value: 0.6956083 - inSlope: 0.71919554 - outSlope: 0.71919554 - tangentMode: 35 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.516129 - value: 0.7184212 - inSlope: 0.69631094 - outSlope: 0.69631094 - tangentMode: 35 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.5483871 - value: 0.7405316 - inSlope: 0.6754826 - outSlope: 0.6754826 - tangentMode: 35 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.58064514 - value: 0.76200074 - inSlope: 0.65642124 - outSlope: 0.65642124 - tangentMode: 35 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.61290324 - value: 0.7828814 - inSlope: 0.638888 - outSlope: 0.638888 - tangentMode: 35 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.6451613 - value: 0.8032193 - inSlope: 0.6226897 - outSlope: 0.6226897 - tangentMode: 35 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.67741936 - value: 0.8230549 - inSlope: 0.6076648 - outSlope: 0.6076648 - tangentMode: 35 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.7096774 - value: 0.8424235 - inSlope: 0.59367925 - outSlope: 0.59367925 - tangentMode: 35 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.7419355 - value: 0.8613568 - inSlope: 0.58061755 - outSlope: 0.58061755 - tangentMode: 35 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.7741935 - value: 0.8798827 - inSlope: 0.56838083 - outSlope: 0.56838083 - tangentMode: 35 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.8064516 - value: 0.8980265 - inSlope: 0.55688787 - outSlope: 0.55688787 - tangentMode: 35 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.83870965 - value: 0.91581094 - inSlope: 0.54606473 - outSlope: 0.54606473 - tangentMode: 35 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.87096775 - value: 0.9332565 - inSlope: 0.5358504 - outSlope: 0.5358504 - tangentMode: 35 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.9032258 - value: 0.95038193 - inSlope: 0.5261885 - outSlope: 0.5261885 - tangentMode: 35 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.9354839 - value: 0.96720415 - inSlope: 0.5170302 - outSlope: 0.5170302 - tangentMode: 35 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 0.9677419 - value: 0.9837387 - inSlope: 0.5083356 - outSlope: 0.5083356 - tangentMode: 35 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 1 - value: 1 - inSlope: 0.5040992 - outSlope: 0.5040992 - tangentMode: 35 - weightedMode: 0 - inWeight: 0.33333334 + inWeight: 0 outWeight: 0 m_PreInfinity: 2 m_PostInfinity: 2 @@ -535,6 +265,7035 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 + - id: 1710403072 + _name: Inverse Boid A + synapses: + - nucleusId: -1659429232 + weight: 1 + curveMax: 1 + receivers: + - nucleusId: 1641120128 + nucleusType: + isSleeping: 0 + _curvePreset: 3 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.001 + value: 999.99994 + inSlope: 0 + outSlope: -112788.63 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.008866142 + value: 112.788635 + inSlope: -112788.63 + outSlope: -6740.78 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.016732283 + value: 59.76471 + inSlope: -6740.78 + outSlope: -2429.6155 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.024598425 + value: 40.653008 + inSlope: -2429.6155 + outSlope: -1252.2269 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.032464568 + value: 30.802813 + inSlope: -1252.2269 + outSlope: -763.7558 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.040330708 + value: 24.795002 + inSlope: -763.7558 + outSlope: -514.45264 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.04819685 + value: 20.748245 + inSlope: -514.45264 + outSlope: -370.0882 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.056062993 + value: 17.837078 + inSlope: -370.0882 + outSlope: -279.01324 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.06392913 + value: 15.642321 + inSlope: -279.01324 + outSlope: -217.87398 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.07179528 + value: 13.928493 + inSlope: -217.87398 + outSlope: -174.8461 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.079661414 + value: 12.553129 + inSlope: -174.8461 + outSlope: -143.41913 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.087527566 + value: 11.424973 + inSlope: -143.41913 + outSlope: -119.76661 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.0953937 + value: 10.482872 + inSlope: -119.76661 + outSlope: -101.519356 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.10325985 + value: 9.684306 + inSlope: -101.519356 + outSlope: -87.14706 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.11112598 + value: 8.9987955 + inSlope: -87.14706 + outSlope: -75.62513 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.11899213 + value: 8.403917 + inSlope: -75.62513 + outSlope: -66.24654 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.12685826 + value: 7.882813 + inSlope: -66.24654 + outSlope: -58.510654 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.13472441 + value: 7.4225597 + inSlope: -58.510654 + outSlope: -52.055042 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.14259055 + value: 7.0130873 + inSlope: -52.055042 + outSlope: -46.612007 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.1504567 + value: 6.6464305 + inSlope: -46.612007 + outSlope: -41.98024 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.15832284 + value: 6.316208 + inSlope: -41.98024 + outSlope: -38.006134 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.16618897 + value: 6.0172467 + inSlope: -38.006134 + outSlope: -34.570965 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.17405513 + value: 5.745306 + inSlope: -34.570965 + outSlope: -31.581244 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.18192126 + value: 5.496884 + inSlope: -31.581244 + outSlope: -28.963417 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.1897874 + value: 5.2690535 + inSlope: -28.963417 + outSlope: -26.658009 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.19765353 + value: 5.059358 + inSlope: -26.658009 + outSlope: -24.617418 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.20551969 + value: 4.8657136 + inSlope: -24.617418 + outSlope: -22.802412 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.21338584 + value: 4.6863465 + inSlope: -22.802412 + outSlope: -21.181019 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.22125196 + value: 4.519734 + inSlope: -21.181019 + outSlope: -19.72667 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.22911811 + value: 4.364561 + inSlope: -19.72667 + outSlope: -18.417059 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.23698425 + value: 4.21969 + inSlope: -18.417059 + outSlope: -17.233776 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2448504 + value: 4.0841265 + inSlope: -17.233776 + outSlope: -16.160883 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.25271654 + value: 3.9570026 + inSlope: -16.160883 + outSlope: -15.185221 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2605827 + value: 3.8375535 + inSlope: -15.185221 + outSlope: -14.295299 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2684488 + value: 3.725105 + inSlope: -14.295299 + outSlope: -13.481375 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.27631494 + value: 3.6190586 + inSlope: -13.481375 + outSlope: -12.735047 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.28418112 + value: 3.5188825 + inSlope: -12.735047 + outSlope: -12.04901 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.29204726 + value: 3.4241033 + inSlope: -12.04901 + outSlope: -11.416967 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2999134 + value: 3.3342957 + inSlope: -11.416967 + outSlope: -10.8334 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.30777952 + value: 3.249079 + inSlope: -10.8334 + outSlope: -10.293426 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.31564566 + value: 3.1681094 + inSlope: -10.293426 + outSlope: -9.792865 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.3235118 + value: 3.0910773 + inSlope: -9.792865 + outSlope: -9.327949 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.33137795 + value: 3.0177023 + inSlope: -9.327949 + outSlope: -8.895375 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.33924407 + value: 2.9477303 + inSlope: -8.895375 + outSlope: -8.492224 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.34711024 + value: 2.880929 + inSlope: -8.492224 + outSlope: -8.115812 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.3549764 + value: 2.8170888 + inSlope: -8.115812 + outSlope: -7.76395 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.36284253 + value: 2.7560165 + inSlope: -7.76395 + outSlope: -7.434456 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.37070867 + value: 2.697536 + inSlope: -7.434456 + outSlope: -7.1255083 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.3785748 + value: 2.641486 + inSlope: -7.1255083 + outSlope: -6.8354197 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.38644093 + value: 2.5877175 + inSlope: -6.8354197 + outSlope: -6.562695 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.39430708 + value: 2.5360944 + inSlope: -6.562695 + outSlope: -6.305974 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.40217322 + value: 2.4864907 + inSlope: -6.305974 + outSlope: -6.064021 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4100394 + value: 2.43879 + inSlope: -6.064021 + outSlope: -5.835745 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4179055 + value: 2.3928854 + inSlope: -5.835745 + outSlope: -5.6201315 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.42577165 + value: 2.3486767 + inSlope: -5.6201315 + outSlope: -5.4162097 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4336378 + value: 2.306072 + inSlope: -5.4162097 + outSlope: -5.223229 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.44150394 + value: 2.2649853 + inSlope: -5.223229 + outSlope: -5.040342 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4493701 + value: 2.2253373 + inSlope: -5.040342 + outSlope: -4.8669295 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4572362 + value: 2.1870534 + inSlope: -4.8669295 + outSlope: -4.7023005 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.46510234 + value: 2.1500645 + inSlope: -4.7023005 + outSlope: -4.5458865 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.47296852 + value: 2.1143057 + inSlope: -4.5458865 + outSlope: -4.3971753 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.48083466 + value: 2.079717 + inSlope: -4.3971753 + outSlope: -4.2555995 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4887008 + value: 2.0462418 + inSlope: -4.2555995 + outSlope: -4.1207685 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.49656692 + value: 2.0138273 + inSlope: -4.1207685 + outSlope: -3.9922712 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5044331 + value: 1.9824234 + inSlope: -3.9922712 + outSlope: -3.8696532 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5122992 + value: 1.9519844 + inSlope: -3.8696532 + outSlope: -3.7526293 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5201653 + value: 1.9224657 + inSlope: -3.7526293 + outSlope: -3.6408176 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.52803147 + value: 1.8938265 + inSlope: -3.6408176 + outSlope: -3.5339315 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5358976 + value: 1.8660281 + inSlope: -3.5339315 + outSlope: -3.4316826 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.54376376 + value: 1.839034 + inSlope: -3.4316826 + outSlope: -3.3338284 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5516299 + value: 1.8128096 + inSlope: -3.3338284 + outSlope: -3.240066 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.55949605 + value: 1.7873228 + inSlope: -3.240066 + outSlope: -3.1502352 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.56736225 + value: 1.7625424 + inSlope: -3.1502352 + outSlope: -3.0640743 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5752284 + value: 1.7384399 + inSlope: -3.0640743 + outSlope: -2.9814053 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.58309454 + value: 1.7149878 + inSlope: -2.9814053 + outSlope: -2.9020314 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5909606 + value: 1.6921601 + inSlope: -2.9020314 + outSlope: -2.8257964 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.59882677 + value: 1.669932 + inSlope: -2.8257964 + outSlope: -2.7525082 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6066929 + value: 1.6482804 + inSlope: -2.7525082 + outSlope: -2.6820538 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.61455905 + value: 1.627183 + inSlope: -2.6820538 + outSlope: -2.6142666 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6224252 + value: 1.6066188 + inSlope: -2.6142666 + outSlope: -2.5490105 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.63029134 + value: 1.5865679 + inSlope: -2.5490105 + outSlope: -2.4861636 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6381575 + value: 1.5670114 + inSlope: -2.4861636 + outSlope: -2.4256358 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.64602363 + value: 1.547931 + inSlope: -2.4256358 + outSlope: -2.3672597 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6538898 + value: 1.5293097 + inSlope: -2.3672597 + outSlope: -2.3109925 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.66175586 + value: 1.5111313 + inSlope: -2.3109925 + outSlope: -2.2566907 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.669622 + value: 1.4933798 + inSlope: -2.2566907 + outSlope: -2.2042859 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.67748815 + value: 1.4760406 + inSlope: -2.2042859 + outSlope: -2.1536992 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6853543 + value: 1.4590993 + inSlope: -2.1536992 + outSlope: -2.1048093 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6932205 + value: 1.4425424 + inSlope: -2.1048093 + outSlope: -2.0575728 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.70108664 + value: 1.4263573 + inSlope: -2.0575728 + outSlope: -2.011927 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7089528 + value: 1.4105312 + inSlope: -2.011927 + outSlope: -1.9677659 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7168189 + value: 1.3950524 + inSlope: -1.9677659 + outSlope: -1.9250447 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7246851 + value: 1.3799098 + inSlope: -1.9250447 + outSlope: -1.8837026 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7325512 + value: 1.3650923 + inSlope: -1.8837026 + outSlope: -1.8436778 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7404173 + value: 1.3505898 + inSlope: -1.8436778 + outSlope: -1.8049132 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.74828345 + value: 1.336392 + inSlope: -1.8049132 + outSlope: -1.7673749 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7561496 + value: 1.3224896 + inSlope: -1.7673749 + outSlope: -1.7309732 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.76401573 + value: 1.3088735 + inSlope: -1.7309732 + outSlope: -1.695693 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7718819 + value: 1.295535 + inSlope: -1.695693 + outSlope: -1.6614736 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.779748 + value: 1.2824656 + inSlope: -1.6614736 + outSlope: -1.6282848 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.78761417 + value: 1.2696573 + inSlope: -1.6282848 + outSlope: -1.5960962 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7954803 + value: 1.2571021 + inSlope: -1.5960962 + outSlope: -1.564832 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.80334646 + value: 1.2447929 + inSlope: -1.564832 + outSlope: -1.5344887 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.81121254 + value: 1.2327225 + inSlope: -1.5344887 + outSlope: -1.5050048 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.81907874 + value: 1.2208838 + inSlope: -1.5050048 + outSlope: -1.4763738 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8269449 + value: 1.2092705 + inSlope: -1.4763738 + outSlope: -1.4485649 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.83481103 + value: 1.1978759 + inSlope: -1.4485649 + outSlope: -1.4215137 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8426772 + value: 1.186694 + inSlope: -1.4215137 + outSlope: -1.3952202 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8505433 + value: 1.175719 + inSlope: -1.3952202 + outSlope: -1.369639 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.85840946 + value: 1.1649452 + inSlope: -1.369639 + outSlope: -1.3447852 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8662756 + value: 1.154367 + inSlope: -1.3447852 + outSlope: -1.320568 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.87414175 + value: 1.1439792 + inSlope: -1.320568 + outSlope: -1.2970176 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8820079 + value: 1.1337767 + inSlope: -1.2970176 + outSlope: -1.2740829 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.889874 + value: 1.1237546 + inSlope: -1.2740829 + outSlope: -1.2517655 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8977401 + value: 1.113908 + inSlope: -1.2517655 + outSlope: -1.2300034 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.90560627 + value: 1.1042327 + inSlope: -1.2300034 + outSlope: -1.2088321 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9134724 + value: 1.0947238 + inSlope: -1.2088321 + outSlope: -1.1881914 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.92133856 + value: 1.0853773 + inSlope: -1.1881914 + outSlope: -1.1680659 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9292047 + value: 1.0761892 + inSlope: -1.1680659 + outSlope: -1.1484709 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.93707085 + value: 1.0671551 + inSlope: -1.1484709 + outSlope: -1.1293371 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.94493705 + value: 1.0582715 + inSlope: -1.1293371 + outSlope: -1.1106901 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9528032 + value: 1.0495347 + inSlope: -1.1106901 + outSlope: -1.0925045 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.96066934 + value: 1.0409409 + inSlope: -1.0925045 + outSlope: -1.0747513 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9685354 + value: 1.0324868 + inSlope: -1.0747513 + outSlope: -1.0574516 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.97640157 + value: 1.0241687 + inSlope: -1.0574516 + outSlope: -1.0405389 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9842677 + value: 1.0159837 + inSlope: -1.0405389 + outSlope: -1.0240355 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.99213386 + value: 1.0079285 + inSlope: -1.0240355 + outSlope: -1.0079259 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: -1.0079259 + outSlope: 0 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 100 + average: 0 + inverse: 0 + exponent: 1 + - id: -916054576 + _name: Inverse Boid B + synapses: + - nucleusId: 839544896 + weight: 1 + curveMax: 1 + receivers: + - nucleusId: 1641120128 + nucleusType: + isSleeping: 0 + _curvePreset: 3 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.001 + value: 999.99994 + inSlope: 0 + outSlope: -112788.63 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.008866142 + value: 112.788635 + inSlope: -112788.63 + outSlope: -6740.78 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.016732283 + value: 59.76471 + inSlope: -6740.78 + outSlope: -2429.6155 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.024598425 + value: 40.653008 + inSlope: -2429.6155 + outSlope: -1252.2269 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.032464568 + value: 30.802813 + inSlope: -1252.2269 + outSlope: -763.7558 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.040330708 + value: 24.795002 + inSlope: -763.7558 + outSlope: -514.45264 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.04819685 + value: 20.748245 + inSlope: -514.45264 + outSlope: -370.0882 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.056062993 + value: 17.837078 + inSlope: -370.0882 + outSlope: -279.01324 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.06392913 + value: 15.642321 + inSlope: -279.01324 + outSlope: -217.87398 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.07179528 + value: 13.928493 + inSlope: -217.87398 + outSlope: -174.8461 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.079661414 + value: 12.553129 + inSlope: -174.8461 + outSlope: -143.41913 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.087527566 + value: 11.424973 + inSlope: -143.41913 + outSlope: -119.76661 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.0953937 + value: 10.482872 + inSlope: -119.76661 + outSlope: -101.519356 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.10325985 + value: 9.684306 + inSlope: -101.519356 + outSlope: -87.14706 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.11112598 + value: 8.9987955 + inSlope: -87.14706 + outSlope: -75.62513 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.11899213 + value: 8.403917 + inSlope: -75.62513 + outSlope: -66.24654 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.12685826 + value: 7.882813 + inSlope: -66.24654 + outSlope: -58.510654 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.13472441 + value: 7.4225597 + inSlope: -58.510654 + outSlope: -52.055042 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.14259055 + value: 7.0130873 + inSlope: -52.055042 + outSlope: -46.612007 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.1504567 + value: 6.6464305 + inSlope: -46.612007 + outSlope: -41.98024 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.15832284 + value: 6.316208 + inSlope: -41.98024 + outSlope: -38.006134 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.16618897 + value: 6.0172467 + inSlope: -38.006134 + outSlope: -34.570965 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.17405513 + value: 5.745306 + inSlope: -34.570965 + outSlope: -31.581244 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.18192126 + value: 5.496884 + inSlope: -31.581244 + outSlope: -28.963417 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.1897874 + value: 5.2690535 + inSlope: -28.963417 + outSlope: -26.658009 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.19765353 + value: 5.059358 + inSlope: -26.658009 + outSlope: -24.617418 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.20551969 + value: 4.8657136 + inSlope: -24.617418 + outSlope: -22.802412 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.21338584 + value: 4.6863465 + inSlope: -22.802412 + outSlope: -21.181019 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.22125196 + value: 4.519734 + inSlope: -21.181019 + outSlope: -19.72667 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.22911811 + value: 4.364561 + inSlope: -19.72667 + outSlope: -18.417059 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.23698425 + value: 4.21969 + inSlope: -18.417059 + outSlope: -17.233776 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2448504 + value: 4.0841265 + inSlope: -17.233776 + outSlope: -16.160883 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.25271654 + value: 3.9570026 + inSlope: -16.160883 + outSlope: -15.185221 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2605827 + value: 3.8375535 + inSlope: -15.185221 + outSlope: -14.295299 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2684488 + value: 3.725105 + inSlope: -14.295299 + outSlope: -13.481375 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.27631494 + value: 3.6190586 + inSlope: -13.481375 + outSlope: -12.735047 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.28418112 + value: 3.5188825 + inSlope: -12.735047 + outSlope: -12.04901 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.29204726 + value: 3.4241033 + inSlope: -12.04901 + outSlope: -11.416967 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2999134 + value: 3.3342957 + inSlope: -11.416967 + outSlope: -10.8334 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.30777952 + value: 3.249079 + inSlope: -10.8334 + outSlope: -10.293426 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.31564566 + value: 3.1681094 + inSlope: -10.293426 + outSlope: -9.792865 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.3235118 + value: 3.0910773 + inSlope: -9.792865 + outSlope: -9.327949 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.33137795 + value: 3.0177023 + inSlope: -9.327949 + outSlope: -8.895375 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.33924407 + value: 2.9477303 + inSlope: -8.895375 + outSlope: -8.492224 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.34711024 + value: 2.880929 + inSlope: -8.492224 + outSlope: -8.115812 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.3549764 + value: 2.8170888 + inSlope: -8.115812 + outSlope: -7.76395 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.36284253 + value: 2.7560165 + inSlope: -7.76395 + outSlope: -7.434456 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.37070867 + value: 2.697536 + inSlope: -7.434456 + outSlope: -7.1255083 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.3785748 + value: 2.641486 + inSlope: -7.1255083 + outSlope: -6.8354197 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.38644093 + value: 2.5877175 + inSlope: -6.8354197 + outSlope: -6.562695 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.39430708 + value: 2.5360944 + inSlope: -6.562695 + outSlope: -6.305974 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.40217322 + value: 2.4864907 + inSlope: -6.305974 + outSlope: -6.064021 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4100394 + value: 2.43879 + inSlope: -6.064021 + outSlope: -5.835745 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4179055 + value: 2.3928854 + inSlope: -5.835745 + outSlope: -5.6201315 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.42577165 + value: 2.3486767 + inSlope: -5.6201315 + outSlope: -5.4162097 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4336378 + value: 2.306072 + inSlope: -5.4162097 + outSlope: -5.223229 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.44150394 + value: 2.2649853 + inSlope: -5.223229 + outSlope: -5.040342 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4493701 + value: 2.2253373 + inSlope: -5.040342 + outSlope: -4.8669295 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4572362 + value: 2.1870534 + inSlope: -4.8669295 + outSlope: -4.7023005 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.46510234 + value: 2.1500645 + inSlope: -4.7023005 + outSlope: -4.5458865 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.47296852 + value: 2.1143057 + inSlope: -4.5458865 + outSlope: -4.3971753 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.48083466 + value: 2.079717 + inSlope: -4.3971753 + outSlope: -4.2555995 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4887008 + value: 2.0462418 + inSlope: -4.2555995 + outSlope: -4.1207685 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.49656692 + value: 2.0138273 + inSlope: -4.1207685 + outSlope: -3.9922712 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5044331 + value: 1.9824234 + inSlope: -3.9922712 + outSlope: -3.8696532 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5122992 + value: 1.9519844 + inSlope: -3.8696532 + outSlope: -3.7526293 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5201653 + value: 1.9224657 + inSlope: -3.7526293 + outSlope: -3.6408176 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.52803147 + value: 1.8938265 + inSlope: -3.6408176 + outSlope: -3.5339315 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5358976 + value: 1.8660281 + inSlope: -3.5339315 + outSlope: -3.4316826 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.54376376 + value: 1.839034 + inSlope: -3.4316826 + outSlope: -3.3338284 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5516299 + value: 1.8128096 + inSlope: -3.3338284 + outSlope: -3.240066 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.55949605 + value: 1.7873228 + inSlope: -3.240066 + outSlope: -3.1502352 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.56736225 + value: 1.7625424 + inSlope: -3.1502352 + outSlope: -3.0640743 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5752284 + value: 1.7384399 + inSlope: -3.0640743 + outSlope: -2.9814053 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.58309454 + value: 1.7149878 + inSlope: -2.9814053 + outSlope: -2.9020314 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5909606 + value: 1.6921601 + inSlope: -2.9020314 + outSlope: -2.8257964 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.59882677 + value: 1.669932 + inSlope: -2.8257964 + outSlope: -2.7525082 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6066929 + value: 1.6482804 + inSlope: -2.7525082 + outSlope: -2.6820538 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.61455905 + value: 1.627183 + inSlope: -2.6820538 + outSlope: -2.6142666 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6224252 + value: 1.6066188 + inSlope: -2.6142666 + outSlope: -2.5490105 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.63029134 + value: 1.5865679 + inSlope: -2.5490105 + outSlope: -2.4861636 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6381575 + value: 1.5670114 + inSlope: -2.4861636 + outSlope: -2.4256358 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.64602363 + value: 1.547931 + inSlope: -2.4256358 + outSlope: -2.3672597 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6538898 + value: 1.5293097 + inSlope: -2.3672597 + outSlope: -2.3109925 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.66175586 + value: 1.5111313 + inSlope: -2.3109925 + outSlope: -2.2566907 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.669622 + value: 1.4933798 + inSlope: -2.2566907 + outSlope: -2.2042859 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.67748815 + value: 1.4760406 + inSlope: -2.2042859 + outSlope: -2.1536992 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6853543 + value: 1.4590993 + inSlope: -2.1536992 + outSlope: -2.1048093 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6932205 + value: 1.4425424 + inSlope: -2.1048093 + outSlope: -2.0575728 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.70108664 + value: 1.4263573 + inSlope: -2.0575728 + outSlope: -2.011927 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7089528 + value: 1.4105312 + inSlope: -2.011927 + outSlope: -1.9677659 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7168189 + value: 1.3950524 + inSlope: -1.9677659 + outSlope: -1.9250447 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7246851 + value: 1.3799098 + inSlope: -1.9250447 + outSlope: -1.8837026 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7325512 + value: 1.3650923 + inSlope: -1.8837026 + outSlope: -1.8436778 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7404173 + value: 1.3505898 + inSlope: -1.8436778 + outSlope: -1.8049132 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.74828345 + value: 1.336392 + inSlope: -1.8049132 + outSlope: -1.7673749 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7561496 + value: 1.3224896 + inSlope: -1.7673749 + outSlope: -1.7309732 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.76401573 + value: 1.3088735 + inSlope: -1.7309732 + outSlope: -1.695693 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7718819 + value: 1.295535 + inSlope: -1.695693 + outSlope: -1.6614736 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.779748 + value: 1.2824656 + inSlope: -1.6614736 + outSlope: -1.6282848 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.78761417 + value: 1.2696573 + inSlope: -1.6282848 + outSlope: -1.5960962 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7954803 + value: 1.2571021 + inSlope: -1.5960962 + outSlope: -1.564832 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.80334646 + value: 1.2447929 + inSlope: -1.564832 + outSlope: -1.5344887 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.81121254 + value: 1.2327225 + inSlope: -1.5344887 + outSlope: -1.5050048 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.81907874 + value: 1.2208838 + inSlope: -1.5050048 + outSlope: -1.4763738 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8269449 + value: 1.2092705 + inSlope: -1.4763738 + outSlope: -1.4485649 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.83481103 + value: 1.1978759 + inSlope: -1.4485649 + outSlope: -1.4215137 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8426772 + value: 1.186694 + inSlope: -1.4215137 + outSlope: -1.3952202 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8505433 + value: 1.175719 + inSlope: -1.3952202 + outSlope: -1.369639 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.85840946 + value: 1.1649452 + inSlope: -1.369639 + outSlope: -1.3447852 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8662756 + value: 1.154367 + inSlope: -1.3447852 + outSlope: -1.320568 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.87414175 + value: 1.1439792 + inSlope: -1.320568 + outSlope: -1.2970176 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8820079 + value: 1.1337767 + inSlope: -1.2970176 + outSlope: -1.2740829 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.889874 + value: 1.1237546 + inSlope: -1.2740829 + outSlope: -1.2517655 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8977401 + value: 1.113908 + inSlope: -1.2517655 + outSlope: -1.2300034 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.90560627 + value: 1.1042327 + inSlope: -1.2300034 + outSlope: -1.2088321 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9134724 + value: 1.0947238 + inSlope: -1.2088321 + outSlope: -1.1881914 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.92133856 + value: 1.0853773 + inSlope: -1.1881914 + outSlope: -1.1680659 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9292047 + value: 1.0761892 + inSlope: -1.1680659 + outSlope: -1.1484709 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.93707085 + value: 1.0671551 + inSlope: -1.1484709 + outSlope: -1.1293371 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.94493705 + value: 1.0582715 + inSlope: -1.1293371 + outSlope: -1.1106901 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9528032 + value: 1.0495347 + inSlope: -1.1106901 + outSlope: -1.0925045 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.96066934 + value: 1.0409409 + inSlope: -1.0925045 + outSlope: -1.0747513 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9685354 + value: 1.0324868 + inSlope: -1.0747513 + outSlope: -1.0574516 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.97640157 + value: 1.0241687 + inSlope: -1.0574516 + outSlope: -1.0405389 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9842677 + value: 1.0159837 + inSlope: -1.0405389 + outSlope: -1.0240355 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.99213386 + value: 1.0079285 + inSlope: -1.0240355 + outSlope: -1.0079259 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: -1.0079259 + outSlope: 0 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 100 + average: 0 + inverse: 0 + exponent: 1 + - id: -1391520368 + _name: Inverse Boid C + synapses: + - nucleusId: -348340288 + weight: 1 + curveMax: 1 + receivers: + - nucleusId: 1641120128 + nucleusType: + isSleeping: 0 + _curvePreset: 3 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.001 + value: 999.99994 + inSlope: 0 + outSlope: -112788.63 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.008866142 + value: 112.788635 + inSlope: -112788.63 + outSlope: -6740.78 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.016732283 + value: 59.76471 + inSlope: -6740.78 + outSlope: -2429.6155 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.024598425 + value: 40.653008 + inSlope: -2429.6155 + outSlope: -1252.2269 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.032464568 + value: 30.802813 + inSlope: -1252.2269 + outSlope: -763.7558 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.040330708 + value: 24.795002 + inSlope: -763.7558 + outSlope: -514.45264 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.04819685 + value: 20.748245 + inSlope: -514.45264 + outSlope: -370.0882 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.056062993 + value: 17.837078 + inSlope: -370.0882 + outSlope: -279.01324 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.06392913 + value: 15.642321 + inSlope: -279.01324 + outSlope: -217.87398 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.07179528 + value: 13.928493 + inSlope: -217.87398 + outSlope: -174.8461 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.079661414 + value: 12.553129 + inSlope: -174.8461 + outSlope: -143.41913 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.087527566 + value: 11.424973 + inSlope: -143.41913 + outSlope: -119.76661 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.0953937 + value: 10.482872 + inSlope: -119.76661 + outSlope: -101.519356 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.10325985 + value: 9.684306 + inSlope: -101.519356 + outSlope: -87.14706 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.11112598 + value: 8.9987955 + inSlope: -87.14706 + outSlope: -75.62513 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.11899213 + value: 8.403917 + inSlope: -75.62513 + outSlope: -66.24654 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.12685826 + value: 7.882813 + inSlope: -66.24654 + outSlope: -58.510654 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.13472441 + value: 7.4225597 + inSlope: -58.510654 + outSlope: -52.055042 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.14259055 + value: 7.0130873 + inSlope: -52.055042 + outSlope: -46.612007 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.1504567 + value: 6.6464305 + inSlope: -46.612007 + outSlope: -41.98024 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.15832284 + value: 6.316208 + inSlope: -41.98024 + outSlope: -38.006134 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.16618897 + value: 6.0172467 + inSlope: -38.006134 + outSlope: -34.570965 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.17405513 + value: 5.745306 + inSlope: -34.570965 + outSlope: -31.581244 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.18192126 + value: 5.496884 + inSlope: -31.581244 + outSlope: -28.963417 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.1897874 + value: 5.2690535 + inSlope: -28.963417 + outSlope: -26.658009 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.19765353 + value: 5.059358 + inSlope: -26.658009 + outSlope: -24.617418 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.20551969 + value: 4.8657136 + inSlope: -24.617418 + outSlope: -22.802412 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.21338584 + value: 4.6863465 + inSlope: -22.802412 + outSlope: -21.181019 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.22125196 + value: 4.519734 + inSlope: -21.181019 + outSlope: -19.72667 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.22911811 + value: 4.364561 + inSlope: -19.72667 + outSlope: -18.417059 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.23698425 + value: 4.21969 + inSlope: -18.417059 + outSlope: -17.233776 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2448504 + value: 4.0841265 + inSlope: -17.233776 + outSlope: -16.160883 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.25271654 + value: 3.9570026 + inSlope: -16.160883 + outSlope: -15.185221 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2605827 + value: 3.8375535 + inSlope: -15.185221 + outSlope: -14.295299 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2684488 + value: 3.725105 + inSlope: -14.295299 + outSlope: -13.481375 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.27631494 + value: 3.6190586 + inSlope: -13.481375 + outSlope: -12.735047 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.28418112 + value: 3.5188825 + inSlope: -12.735047 + outSlope: -12.04901 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.29204726 + value: 3.4241033 + inSlope: -12.04901 + outSlope: -11.416967 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2999134 + value: 3.3342957 + inSlope: -11.416967 + outSlope: -10.8334 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.30777952 + value: 3.249079 + inSlope: -10.8334 + outSlope: -10.293426 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.31564566 + value: 3.1681094 + inSlope: -10.293426 + outSlope: -9.792865 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.3235118 + value: 3.0910773 + inSlope: -9.792865 + outSlope: -9.327949 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.33137795 + value: 3.0177023 + inSlope: -9.327949 + outSlope: -8.895375 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.33924407 + value: 2.9477303 + inSlope: -8.895375 + outSlope: -8.492224 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.34711024 + value: 2.880929 + inSlope: -8.492224 + outSlope: -8.115812 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.3549764 + value: 2.8170888 + inSlope: -8.115812 + outSlope: -7.76395 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.36284253 + value: 2.7560165 + inSlope: -7.76395 + outSlope: -7.434456 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.37070867 + value: 2.697536 + inSlope: -7.434456 + outSlope: -7.1255083 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.3785748 + value: 2.641486 + inSlope: -7.1255083 + outSlope: -6.8354197 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.38644093 + value: 2.5877175 + inSlope: -6.8354197 + outSlope: -6.562695 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.39430708 + value: 2.5360944 + inSlope: -6.562695 + outSlope: -6.305974 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.40217322 + value: 2.4864907 + inSlope: -6.305974 + outSlope: -6.064021 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4100394 + value: 2.43879 + inSlope: -6.064021 + outSlope: -5.835745 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4179055 + value: 2.3928854 + inSlope: -5.835745 + outSlope: -5.6201315 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.42577165 + value: 2.3486767 + inSlope: -5.6201315 + outSlope: -5.4162097 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4336378 + value: 2.306072 + inSlope: -5.4162097 + outSlope: -5.223229 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.44150394 + value: 2.2649853 + inSlope: -5.223229 + outSlope: -5.040342 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4493701 + value: 2.2253373 + inSlope: -5.040342 + outSlope: -4.8669295 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4572362 + value: 2.1870534 + inSlope: -4.8669295 + outSlope: -4.7023005 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.46510234 + value: 2.1500645 + inSlope: -4.7023005 + outSlope: -4.5458865 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.47296852 + value: 2.1143057 + inSlope: -4.5458865 + outSlope: -4.3971753 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.48083466 + value: 2.079717 + inSlope: -4.3971753 + outSlope: -4.2555995 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4887008 + value: 2.0462418 + inSlope: -4.2555995 + outSlope: -4.1207685 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.49656692 + value: 2.0138273 + inSlope: -4.1207685 + outSlope: -3.9922712 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5044331 + value: 1.9824234 + inSlope: -3.9922712 + outSlope: -3.8696532 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5122992 + value: 1.9519844 + inSlope: -3.8696532 + outSlope: -3.7526293 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5201653 + value: 1.9224657 + inSlope: -3.7526293 + outSlope: -3.6408176 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.52803147 + value: 1.8938265 + inSlope: -3.6408176 + outSlope: -3.5339315 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5358976 + value: 1.8660281 + inSlope: -3.5339315 + outSlope: -3.4316826 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.54376376 + value: 1.839034 + inSlope: -3.4316826 + outSlope: -3.3338284 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5516299 + value: 1.8128096 + inSlope: -3.3338284 + outSlope: -3.240066 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.55949605 + value: 1.7873228 + inSlope: -3.240066 + outSlope: -3.1502352 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.56736225 + value: 1.7625424 + inSlope: -3.1502352 + outSlope: -3.0640743 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5752284 + value: 1.7384399 + inSlope: -3.0640743 + outSlope: -2.9814053 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.58309454 + value: 1.7149878 + inSlope: -2.9814053 + outSlope: -2.9020314 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5909606 + value: 1.6921601 + inSlope: -2.9020314 + outSlope: -2.8257964 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.59882677 + value: 1.669932 + inSlope: -2.8257964 + outSlope: -2.7525082 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6066929 + value: 1.6482804 + inSlope: -2.7525082 + outSlope: -2.6820538 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.61455905 + value: 1.627183 + inSlope: -2.6820538 + outSlope: -2.6142666 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6224252 + value: 1.6066188 + inSlope: -2.6142666 + outSlope: -2.5490105 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.63029134 + value: 1.5865679 + inSlope: -2.5490105 + outSlope: -2.4861636 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6381575 + value: 1.5670114 + inSlope: -2.4861636 + outSlope: -2.4256358 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.64602363 + value: 1.547931 + inSlope: -2.4256358 + outSlope: -2.3672597 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6538898 + value: 1.5293097 + inSlope: -2.3672597 + outSlope: -2.3109925 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.66175586 + value: 1.5111313 + inSlope: -2.3109925 + outSlope: -2.2566907 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.669622 + value: 1.4933798 + inSlope: -2.2566907 + outSlope: -2.2042859 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.67748815 + value: 1.4760406 + inSlope: -2.2042859 + outSlope: -2.1536992 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6853543 + value: 1.4590993 + inSlope: -2.1536992 + outSlope: -2.1048093 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6932205 + value: 1.4425424 + inSlope: -2.1048093 + outSlope: -2.0575728 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.70108664 + value: 1.4263573 + inSlope: -2.0575728 + outSlope: -2.011927 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7089528 + value: 1.4105312 + inSlope: -2.011927 + outSlope: -1.9677659 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7168189 + value: 1.3950524 + inSlope: -1.9677659 + outSlope: -1.9250447 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7246851 + value: 1.3799098 + inSlope: -1.9250447 + outSlope: -1.8837026 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7325512 + value: 1.3650923 + inSlope: -1.8837026 + outSlope: -1.8436778 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7404173 + value: 1.3505898 + inSlope: -1.8436778 + outSlope: -1.8049132 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.74828345 + value: 1.336392 + inSlope: -1.8049132 + outSlope: -1.7673749 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7561496 + value: 1.3224896 + inSlope: -1.7673749 + outSlope: -1.7309732 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.76401573 + value: 1.3088735 + inSlope: -1.7309732 + outSlope: -1.695693 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7718819 + value: 1.295535 + inSlope: -1.695693 + outSlope: -1.6614736 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.779748 + value: 1.2824656 + inSlope: -1.6614736 + outSlope: -1.6282848 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.78761417 + value: 1.2696573 + inSlope: -1.6282848 + outSlope: -1.5960962 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7954803 + value: 1.2571021 + inSlope: -1.5960962 + outSlope: -1.564832 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.80334646 + value: 1.2447929 + inSlope: -1.564832 + outSlope: -1.5344887 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.81121254 + value: 1.2327225 + inSlope: -1.5344887 + outSlope: -1.5050048 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.81907874 + value: 1.2208838 + inSlope: -1.5050048 + outSlope: -1.4763738 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8269449 + value: 1.2092705 + inSlope: -1.4763738 + outSlope: -1.4485649 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.83481103 + value: 1.1978759 + inSlope: -1.4485649 + outSlope: -1.4215137 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8426772 + value: 1.186694 + inSlope: -1.4215137 + outSlope: -1.3952202 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8505433 + value: 1.175719 + inSlope: -1.3952202 + outSlope: -1.369639 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.85840946 + value: 1.1649452 + inSlope: -1.369639 + outSlope: -1.3447852 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8662756 + value: 1.154367 + inSlope: -1.3447852 + outSlope: -1.320568 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.87414175 + value: 1.1439792 + inSlope: -1.320568 + outSlope: -1.2970176 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8820079 + value: 1.1337767 + inSlope: -1.2970176 + outSlope: -1.2740829 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.889874 + value: 1.1237546 + inSlope: -1.2740829 + outSlope: -1.2517655 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8977401 + value: 1.113908 + inSlope: -1.2517655 + outSlope: -1.2300034 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.90560627 + value: 1.1042327 + inSlope: -1.2300034 + outSlope: -1.2088321 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9134724 + value: 1.0947238 + inSlope: -1.2088321 + outSlope: -1.1881914 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.92133856 + value: 1.0853773 + inSlope: -1.1881914 + outSlope: -1.1680659 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9292047 + value: 1.0761892 + inSlope: -1.1680659 + outSlope: -1.1484709 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.93707085 + value: 1.0671551 + inSlope: -1.1484709 + outSlope: -1.1293371 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.94493705 + value: 1.0582715 + inSlope: -1.1293371 + outSlope: -1.1106901 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9528032 + value: 1.0495347 + inSlope: -1.1106901 + outSlope: -1.0925045 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.96066934 + value: 1.0409409 + inSlope: -1.0925045 + outSlope: -1.0747513 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9685354 + value: 1.0324868 + inSlope: -1.0747513 + outSlope: -1.0574516 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.97640157 + value: 1.0241687 + inSlope: -1.0574516 + outSlope: -1.0405389 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9842677 + value: 1.0159837 + inSlope: -1.0405389 + outSlope: -1.0240355 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.99213386 + value: 1.0079285 + inSlope: -1.0240355 + outSlope: -1.0079259 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: -1.0079259 + outSlope: 0 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 100 + average: 0 + inverse: 0 + exponent: 1 + - id: 763145504 + _name: Inverse Boid D + synapses: [] + receivers: + - nucleusId: 1641120128 + nucleusType: + isSleeping: 0 + _curvePreset: 3 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.001 + value: 999.99994 + inSlope: 0 + outSlope: -112788.63 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.008866142 + value: 112.788635 + inSlope: -112788.63 + outSlope: -6740.78 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.016732283 + value: 59.76471 + inSlope: -6740.78 + outSlope: -2429.6155 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.024598425 + value: 40.653008 + inSlope: -2429.6155 + outSlope: -1252.2269 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.032464568 + value: 30.802813 + inSlope: -1252.2269 + outSlope: -763.7558 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.040330708 + value: 24.795002 + inSlope: -763.7558 + outSlope: -514.45264 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.04819685 + value: 20.748245 + inSlope: -514.45264 + outSlope: -370.0882 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.056062993 + value: 17.837078 + inSlope: -370.0882 + outSlope: -279.01324 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.06392913 + value: 15.642321 + inSlope: -279.01324 + outSlope: -217.87398 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.07179528 + value: 13.928493 + inSlope: -217.87398 + outSlope: -174.8461 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.079661414 + value: 12.553129 + inSlope: -174.8461 + outSlope: -143.41913 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.087527566 + value: 11.424973 + inSlope: -143.41913 + outSlope: -119.76661 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.0953937 + value: 10.482872 + inSlope: -119.76661 + outSlope: -101.519356 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.10325985 + value: 9.684306 + inSlope: -101.519356 + outSlope: -87.14706 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.11112598 + value: 8.9987955 + inSlope: -87.14706 + outSlope: -75.62513 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.11899213 + value: 8.403917 + inSlope: -75.62513 + outSlope: -66.24654 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.12685826 + value: 7.882813 + inSlope: -66.24654 + outSlope: -58.510654 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.13472441 + value: 7.4225597 + inSlope: -58.510654 + outSlope: -52.055042 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.14259055 + value: 7.0130873 + inSlope: -52.055042 + outSlope: -46.612007 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.1504567 + value: 6.6464305 + inSlope: -46.612007 + outSlope: -41.98024 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.15832284 + value: 6.316208 + inSlope: -41.98024 + outSlope: -38.006134 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.16618897 + value: 6.0172467 + inSlope: -38.006134 + outSlope: -34.570965 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.17405513 + value: 5.745306 + inSlope: -34.570965 + outSlope: -31.581244 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.18192126 + value: 5.496884 + inSlope: -31.581244 + outSlope: -28.963417 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.1897874 + value: 5.2690535 + inSlope: -28.963417 + outSlope: -26.658009 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.19765353 + value: 5.059358 + inSlope: -26.658009 + outSlope: -24.617418 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.20551969 + value: 4.8657136 + inSlope: -24.617418 + outSlope: -22.802412 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.21338584 + value: 4.6863465 + inSlope: -22.802412 + outSlope: -21.181019 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.22125196 + value: 4.519734 + inSlope: -21.181019 + outSlope: -19.72667 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.22911811 + value: 4.364561 + inSlope: -19.72667 + outSlope: -18.417059 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.23698425 + value: 4.21969 + inSlope: -18.417059 + outSlope: -17.233776 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2448504 + value: 4.0841265 + inSlope: -17.233776 + outSlope: -16.160883 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.25271654 + value: 3.9570026 + inSlope: -16.160883 + outSlope: -15.185221 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2605827 + value: 3.8375535 + inSlope: -15.185221 + outSlope: -14.295299 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2684488 + value: 3.725105 + inSlope: -14.295299 + outSlope: -13.481375 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.27631494 + value: 3.6190586 + inSlope: -13.481375 + outSlope: -12.735047 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.28418112 + value: 3.5188825 + inSlope: -12.735047 + outSlope: -12.04901 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.29204726 + value: 3.4241033 + inSlope: -12.04901 + outSlope: -11.416967 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2999134 + value: 3.3342957 + inSlope: -11.416967 + outSlope: -10.8334 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.30777952 + value: 3.249079 + inSlope: -10.8334 + outSlope: -10.293426 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.31564566 + value: 3.1681094 + inSlope: -10.293426 + outSlope: -9.792865 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.3235118 + value: 3.0910773 + inSlope: -9.792865 + outSlope: -9.327949 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.33137795 + value: 3.0177023 + inSlope: -9.327949 + outSlope: -8.895375 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.33924407 + value: 2.9477303 + inSlope: -8.895375 + outSlope: -8.492224 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.34711024 + value: 2.880929 + inSlope: -8.492224 + outSlope: -8.115812 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.3549764 + value: 2.8170888 + inSlope: -8.115812 + outSlope: -7.76395 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.36284253 + value: 2.7560165 + inSlope: -7.76395 + outSlope: -7.434456 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.37070867 + value: 2.697536 + inSlope: -7.434456 + outSlope: -7.1255083 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.3785748 + value: 2.641486 + inSlope: -7.1255083 + outSlope: -6.8354197 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.38644093 + value: 2.5877175 + inSlope: -6.8354197 + outSlope: -6.562695 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.39430708 + value: 2.5360944 + inSlope: -6.562695 + outSlope: -6.305974 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.40217322 + value: 2.4864907 + inSlope: -6.305974 + outSlope: -6.064021 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4100394 + value: 2.43879 + inSlope: -6.064021 + outSlope: -5.835745 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4179055 + value: 2.3928854 + inSlope: -5.835745 + outSlope: -5.6201315 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.42577165 + value: 2.3486767 + inSlope: -5.6201315 + outSlope: -5.4162097 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4336378 + value: 2.306072 + inSlope: -5.4162097 + outSlope: -5.223229 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.44150394 + value: 2.2649853 + inSlope: -5.223229 + outSlope: -5.040342 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4493701 + value: 2.2253373 + inSlope: -5.040342 + outSlope: -4.8669295 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4572362 + value: 2.1870534 + inSlope: -4.8669295 + outSlope: -4.7023005 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.46510234 + value: 2.1500645 + inSlope: -4.7023005 + outSlope: -4.5458865 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.47296852 + value: 2.1143057 + inSlope: -4.5458865 + outSlope: -4.3971753 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.48083466 + value: 2.079717 + inSlope: -4.3971753 + outSlope: -4.2555995 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4887008 + value: 2.0462418 + inSlope: -4.2555995 + outSlope: -4.1207685 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.49656692 + value: 2.0138273 + inSlope: -4.1207685 + outSlope: -3.9922712 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5044331 + value: 1.9824234 + inSlope: -3.9922712 + outSlope: -3.8696532 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5122992 + value: 1.9519844 + inSlope: -3.8696532 + outSlope: -3.7526293 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5201653 + value: 1.9224657 + inSlope: -3.7526293 + outSlope: -3.6408176 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.52803147 + value: 1.8938265 + inSlope: -3.6408176 + outSlope: -3.5339315 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5358976 + value: 1.8660281 + inSlope: -3.5339315 + outSlope: -3.4316826 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.54376376 + value: 1.839034 + inSlope: -3.4316826 + outSlope: -3.3338284 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5516299 + value: 1.8128096 + inSlope: -3.3338284 + outSlope: -3.240066 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.55949605 + value: 1.7873228 + inSlope: -3.240066 + outSlope: -3.1502352 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.56736225 + value: 1.7625424 + inSlope: -3.1502352 + outSlope: -3.0640743 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5752284 + value: 1.7384399 + inSlope: -3.0640743 + outSlope: -2.9814053 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.58309454 + value: 1.7149878 + inSlope: -2.9814053 + outSlope: -2.9020314 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5909606 + value: 1.6921601 + inSlope: -2.9020314 + outSlope: -2.8257964 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.59882677 + value: 1.669932 + inSlope: -2.8257964 + outSlope: -2.7525082 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6066929 + value: 1.6482804 + inSlope: -2.7525082 + outSlope: -2.6820538 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.61455905 + value: 1.627183 + inSlope: -2.6820538 + outSlope: -2.6142666 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6224252 + value: 1.6066188 + inSlope: -2.6142666 + outSlope: -2.5490105 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.63029134 + value: 1.5865679 + inSlope: -2.5490105 + outSlope: -2.4861636 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6381575 + value: 1.5670114 + inSlope: -2.4861636 + outSlope: -2.4256358 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.64602363 + value: 1.547931 + inSlope: -2.4256358 + outSlope: -2.3672597 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6538898 + value: 1.5293097 + inSlope: -2.3672597 + outSlope: -2.3109925 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.66175586 + value: 1.5111313 + inSlope: -2.3109925 + outSlope: -2.2566907 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.669622 + value: 1.4933798 + inSlope: -2.2566907 + outSlope: -2.2042859 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.67748815 + value: 1.4760406 + inSlope: -2.2042859 + outSlope: -2.1536992 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6853543 + value: 1.4590993 + inSlope: -2.1536992 + outSlope: -2.1048093 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6932205 + value: 1.4425424 + inSlope: -2.1048093 + outSlope: -2.0575728 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.70108664 + value: 1.4263573 + inSlope: -2.0575728 + outSlope: -2.011927 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7089528 + value: 1.4105312 + inSlope: -2.011927 + outSlope: -1.9677659 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7168189 + value: 1.3950524 + inSlope: -1.9677659 + outSlope: -1.9250447 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7246851 + value: 1.3799098 + inSlope: -1.9250447 + outSlope: -1.8837026 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7325512 + value: 1.3650923 + inSlope: -1.8837026 + outSlope: -1.8436778 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7404173 + value: 1.3505898 + inSlope: -1.8436778 + outSlope: -1.8049132 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.74828345 + value: 1.336392 + inSlope: -1.8049132 + outSlope: -1.7673749 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7561496 + value: 1.3224896 + inSlope: -1.7673749 + outSlope: -1.7309732 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.76401573 + value: 1.3088735 + inSlope: -1.7309732 + outSlope: -1.695693 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7718819 + value: 1.295535 + inSlope: -1.695693 + outSlope: -1.6614736 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.779748 + value: 1.2824656 + inSlope: -1.6614736 + outSlope: -1.6282848 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.78761417 + value: 1.2696573 + inSlope: -1.6282848 + outSlope: -1.5960962 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7954803 + value: 1.2571021 + inSlope: -1.5960962 + outSlope: -1.564832 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.80334646 + value: 1.2447929 + inSlope: -1.564832 + outSlope: -1.5344887 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.81121254 + value: 1.2327225 + inSlope: -1.5344887 + outSlope: -1.5050048 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.81907874 + value: 1.2208838 + inSlope: -1.5050048 + outSlope: -1.4763738 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8269449 + value: 1.2092705 + inSlope: -1.4763738 + outSlope: -1.4485649 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.83481103 + value: 1.1978759 + inSlope: -1.4485649 + outSlope: -1.4215137 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8426772 + value: 1.186694 + inSlope: -1.4215137 + outSlope: -1.3952202 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8505433 + value: 1.175719 + inSlope: -1.3952202 + outSlope: -1.369639 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.85840946 + value: 1.1649452 + inSlope: -1.369639 + outSlope: -1.3447852 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8662756 + value: 1.154367 + inSlope: -1.3447852 + outSlope: -1.320568 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.87414175 + value: 1.1439792 + inSlope: -1.320568 + outSlope: -1.2970176 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8820079 + value: 1.1337767 + inSlope: -1.2970176 + outSlope: -1.2740829 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.889874 + value: 1.1237546 + inSlope: -1.2740829 + outSlope: -1.2517655 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8977401 + value: 1.113908 + inSlope: -1.2517655 + outSlope: -1.2300034 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.90560627 + value: 1.1042327 + inSlope: -1.2300034 + outSlope: -1.2088321 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9134724 + value: 1.0947238 + inSlope: -1.2088321 + outSlope: -1.1881914 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.92133856 + value: 1.0853773 + inSlope: -1.1881914 + outSlope: -1.1680659 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9292047 + value: 1.0761892 + inSlope: -1.1680659 + outSlope: -1.1484709 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.93707085 + value: 1.0671551 + inSlope: -1.1484709 + outSlope: -1.1293371 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.94493705 + value: 1.0582715 + inSlope: -1.1293371 + outSlope: -1.1106901 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9528032 + value: 1.0495347 + inSlope: -1.1106901 + outSlope: -1.0925045 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.96066934 + value: 1.0409409 + inSlope: -1.0925045 + outSlope: -1.0747513 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9685354 + value: 1.0324868 + inSlope: -1.0747513 + outSlope: -1.0574516 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.97640157 + value: 1.0241687 + inSlope: -1.0574516 + outSlope: -1.0405389 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9842677 + value: 1.0159837 + inSlope: -1.0405389 + outSlope: -1.0240355 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.99213386 + value: 1.0079285 + inSlope: -1.0240355 + outSlope: -1.0079259 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: -1.0079259 + outSlope: 0 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 100 + average: 0 + inverse: 0 + exponent: 1 + - id: 1469392160 + _name: Inverse Boid E + synapses: [] + receivers: + - nucleusId: 1641120128 + nucleusType: + isSleeping: 0 + _curvePreset: 3 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.001 + value: 999.99994 + inSlope: 0 + outSlope: -112788.63 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.008866142 + value: 112.788635 + inSlope: -112788.63 + outSlope: -6740.78 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.016732283 + value: 59.76471 + inSlope: -6740.78 + outSlope: -2429.6155 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.024598425 + value: 40.653008 + inSlope: -2429.6155 + outSlope: -1252.2269 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.032464568 + value: 30.802813 + inSlope: -1252.2269 + outSlope: -763.7558 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.040330708 + value: 24.795002 + inSlope: -763.7558 + outSlope: -514.45264 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.04819685 + value: 20.748245 + inSlope: -514.45264 + outSlope: -370.0882 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.056062993 + value: 17.837078 + inSlope: -370.0882 + outSlope: -279.01324 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.06392913 + value: 15.642321 + inSlope: -279.01324 + outSlope: -217.87398 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.07179528 + value: 13.928493 + inSlope: -217.87398 + outSlope: -174.8461 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.079661414 + value: 12.553129 + inSlope: -174.8461 + outSlope: -143.41913 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.087527566 + value: 11.424973 + inSlope: -143.41913 + outSlope: -119.76661 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.0953937 + value: 10.482872 + inSlope: -119.76661 + outSlope: -101.519356 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.10325985 + value: 9.684306 + inSlope: -101.519356 + outSlope: -87.14706 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.11112598 + value: 8.9987955 + inSlope: -87.14706 + outSlope: -75.62513 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.11899213 + value: 8.403917 + inSlope: -75.62513 + outSlope: -66.24654 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.12685826 + value: 7.882813 + inSlope: -66.24654 + outSlope: -58.510654 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.13472441 + value: 7.4225597 + inSlope: -58.510654 + outSlope: -52.055042 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.14259055 + value: 7.0130873 + inSlope: -52.055042 + outSlope: -46.612007 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.1504567 + value: 6.6464305 + inSlope: -46.612007 + outSlope: -41.98024 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.15832284 + value: 6.316208 + inSlope: -41.98024 + outSlope: -38.006134 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.16618897 + value: 6.0172467 + inSlope: -38.006134 + outSlope: -34.570965 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.17405513 + value: 5.745306 + inSlope: -34.570965 + outSlope: -31.581244 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.18192126 + value: 5.496884 + inSlope: -31.581244 + outSlope: -28.963417 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.1897874 + value: 5.2690535 + inSlope: -28.963417 + outSlope: -26.658009 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.19765353 + value: 5.059358 + inSlope: -26.658009 + outSlope: -24.617418 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.20551969 + value: 4.8657136 + inSlope: -24.617418 + outSlope: -22.802412 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.21338584 + value: 4.6863465 + inSlope: -22.802412 + outSlope: -21.181019 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.22125196 + value: 4.519734 + inSlope: -21.181019 + outSlope: -19.72667 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.22911811 + value: 4.364561 + inSlope: -19.72667 + outSlope: -18.417059 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.23698425 + value: 4.21969 + inSlope: -18.417059 + outSlope: -17.233776 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2448504 + value: 4.0841265 + inSlope: -17.233776 + outSlope: -16.160883 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.25271654 + value: 3.9570026 + inSlope: -16.160883 + outSlope: -15.185221 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2605827 + value: 3.8375535 + inSlope: -15.185221 + outSlope: -14.295299 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2684488 + value: 3.725105 + inSlope: -14.295299 + outSlope: -13.481375 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.27631494 + value: 3.6190586 + inSlope: -13.481375 + outSlope: -12.735047 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.28418112 + value: 3.5188825 + inSlope: -12.735047 + outSlope: -12.04901 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.29204726 + value: 3.4241033 + inSlope: -12.04901 + outSlope: -11.416967 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2999134 + value: 3.3342957 + inSlope: -11.416967 + outSlope: -10.8334 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.30777952 + value: 3.249079 + inSlope: -10.8334 + outSlope: -10.293426 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.31564566 + value: 3.1681094 + inSlope: -10.293426 + outSlope: -9.792865 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.3235118 + value: 3.0910773 + inSlope: -9.792865 + outSlope: -9.327949 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.33137795 + value: 3.0177023 + inSlope: -9.327949 + outSlope: -8.895375 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.33924407 + value: 2.9477303 + inSlope: -8.895375 + outSlope: -8.492224 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.34711024 + value: 2.880929 + inSlope: -8.492224 + outSlope: -8.115812 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.3549764 + value: 2.8170888 + inSlope: -8.115812 + outSlope: -7.76395 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.36284253 + value: 2.7560165 + inSlope: -7.76395 + outSlope: -7.434456 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.37070867 + value: 2.697536 + inSlope: -7.434456 + outSlope: -7.1255083 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.3785748 + value: 2.641486 + inSlope: -7.1255083 + outSlope: -6.8354197 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.38644093 + value: 2.5877175 + inSlope: -6.8354197 + outSlope: -6.562695 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.39430708 + value: 2.5360944 + inSlope: -6.562695 + outSlope: -6.305974 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.40217322 + value: 2.4864907 + inSlope: -6.305974 + outSlope: -6.064021 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4100394 + value: 2.43879 + inSlope: -6.064021 + outSlope: -5.835745 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4179055 + value: 2.3928854 + inSlope: -5.835745 + outSlope: -5.6201315 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.42577165 + value: 2.3486767 + inSlope: -5.6201315 + outSlope: -5.4162097 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4336378 + value: 2.306072 + inSlope: -5.4162097 + outSlope: -5.223229 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.44150394 + value: 2.2649853 + inSlope: -5.223229 + outSlope: -5.040342 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4493701 + value: 2.2253373 + inSlope: -5.040342 + outSlope: -4.8669295 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4572362 + value: 2.1870534 + inSlope: -4.8669295 + outSlope: -4.7023005 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.46510234 + value: 2.1500645 + inSlope: -4.7023005 + outSlope: -4.5458865 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.47296852 + value: 2.1143057 + inSlope: -4.5458865 + outSlope: -4.3971753 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.48083466 + value: 2.079717 + inSlope: -4.3971753 + outSlope: -4.2555995 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4887008 + value: 2.0462418 + inSlope: -4.2555995 + outSlope: -4.1207685 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.49656692 + value: 2.0138273 + inSlope: -4.1207685 + outSlope: -3.9922712 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5044331 + value: 1.9824234 + inSlope: -3.9922712 + outSlope: -3.8696532 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5122992 + value: 1.9519844 + inSlope: -3.8696532 + outSlope: -3.7526293 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5201653 + value: 1.9224657 + inSlope: -3.7526293 + outSlope: -3.6408176 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.52803147 + value: 1.8938265 + inSlope: -3.6408176 + outSlope: -3.5339315 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5358976 + value: 1.8660281 + inSlope: -3.5339315 + outSlope: -3.4316826 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.54376376 + value: 1.839034 + inSlope: -3.4316826 + outSlope: -3.3338284 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5516299 + value: 1.8128096 + inSlope: -3.3338284 + outSlope: -3.240066 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.55949605 + value: 1.7873228 + inSlope: -3.240066 + outSlope: -3.1502352 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.56736225 + value: 1.7625424 + inSlope: -3.1502352 + outSlope: -3.0640743 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5752284 + value: 1.7384399 + inSlope: -3.0640743 + outSlope: -2.9814053 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.58309454 + value: 1.7149878 + inSlope: -2.9814053 + outSlope: -2.9020314 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5909606 + value: 1.6921601 + inSlope: -2.9020314 + outSlope: -2.8257964 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.59882677 + value: 1.669932 + inSlope: -2.8257964 + outSlope: -2.7525082 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6066929 + value: 1.6482804 + inSlope: -2.7525082 + outSlope: -2.6820538 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.61455905 + value: 1.627183 + inSlope: -2.6820538 + outSlope: -2.6142666 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6224252 + value: 1.6066188 + inSlope: -2.6142666 + outSlope: -2.5490105 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.63029134 + value: 1.5865679 + inSlope: -2.5490105 + outSlope: -2.4861636 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6381575 + value: 1.5670114 + inSlope: -2.4861636 + outSlope: -2.4256358 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.64602363 + value: 1.547931 + inSlope: -2.4256358 + outSlope: -2.3672597 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6538898 + value: 1.5293097 + inSlope: -2.3672597 + outSlope: -2.3109925 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.66175586 + value: 1.5111313 + inSlope: -2.3109925 + outSlope: -2.2566907 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.669622 + value: 1.4933798 + inSlope: -2.2566907 + outSlope: -2.2042859 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.67748815 + value: 1.4760406 + inSlope: -2.2042859 + outSlope: -2.1536992 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6853543 + value: 1.4590993 + inSlope: -2.1536992 + outSlope: -2.1048093 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6932205 + value: 1.4425424 + inSlope: -2.1048093 + outSlope: -2.0575728 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.70108664 + value: 1.4263573 + inSlope: -2.0575728 + outSlope: -2.011927 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7089528 + value: 1.4105312 + inSlope: -2.011927 + outSlope: -1.9677659 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7168189 + value: 1.3950524 + inSlope: -1.9677659 + outSlope: -1.9250447 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7246851 + value: 1.3799098 + inSlope: -1.9250447 + outSlope: -1.8837026 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7325512 + value: 1.3650923 + inSlope: -1.8837026 + outSlope: -1.8436778 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7404173 + value: 1.3505898 + inSlope: -1.8436778 + outSlope: -1.8049132 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.74828345 + value: 1.336392 + inSlope: -1.8049132 + outSlope: -1.7673749 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7561496 + value: 1.3224896 + inSlope: -1.7673749 + outSlope: -1.7309732 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.76401573 + value: 1.3088735 + inSlope: -1.7309732 + outSlope: -1.695693 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7718819 + value: 1.295535 + inSlope: -1.695693 + outSlope: -1.6614736 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.779748 + value: 1.2824656 + inSlope: -1.6614736 + outSlope: -1.6282848 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.78761417 + value: 1.2696573 + inSlope: -1.6282848 + outSlope: -1.5960962 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7954803 + value: 1.2571021 + inSlope: -1.5960962 + outSlope: -1.564832 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.80334646 + value: 1.2447929 + inSlope: -1.564832 + outSlope: -1.5344887 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.81121254 + value: 1.2327225 + inSlope: -1.5344887 + outSlope: -1.5050048 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.81907874 + value: 1.2208838 + inSlope: -1.5050048 + outSlope: -1.4763738 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8269449 + value: 1.2092705 + inSlope: -1.4763738 + outSlope: -1.4485649 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.83481103 + value: 1.1978759 + inSlope: -1.4485649 + outSlope: -1.4215137 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8426772 + value: 1.186694 + inSlope: -1.4215137 + outSlope: -1.3952202 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8505433 + value: 1.175719 + inSlope: -1.3952202 + outSlope: -1.369639 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.85840946 + value: 1.1649452 + inSlope: -1.369639 + outSlope: -1.3447852 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8662756 + value: 1.154367 + inSlope: -1.3447852 + outSlope: -1.320568 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.87414175 + value: 1.1439792 + inSlope: -1.320568 + outSlope: -1.2970176 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8820079 + value: 1.1337767 + inSlope: -1.2970176 + outSlope: -1.2740829 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.889874 + value: 1.1237546 + inSlope: -1.2740829 + outSlope: -1.2517655 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8977401 + value: 1.113908 + inSlope: -1.2517655 + outSlope: -1.2300034 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.90560627 + value: 1.1042327 + inSlope: -1.2300034 + outSlope: -1.2088321 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9134724 + value: 1.0947238 + inSlope: -1.2088321 + outSlope: -1.1881914 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.92133856 + value: 1.0853773 + inSlope: -1.1881914 + outSlope: -1.1680659 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9292047 + value: 1.0761892 + inSlope: -1.1680659 + outSlope: -1.1484709 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.93707085 + value: 1.0671551 + inSlope: -1.1484709 + outSlope: -1.1293371 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.94493705 + value: 1.0582715 + inSlope: -1.1293371 + outSlope: -1.1106901 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9528032 + value: 1.0495347 + inSlope: -1.1106901 + outSlope: -1.0925045 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.96066934 + value: 1.0409409 + inSlope: -1.0925045 + outSlope: -1.0747513 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9685354 + value: 1.0324868 + inSlope: -1.0747513 + outSlope: -1.0574516 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.97640157 + value: 1.0241687 + inSlope: -1.0574516 + outSlope: -1.0405389 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9842677 + value: 1.0159837 + inSlope: -1.0405389 + outSlope: -1.0240355 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.99213386 + value: 1.0079285 + inSlope: -1.0240355 + outSlope: -1.0079259 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: -1.0079259 + outSlope: 0 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 100 + average: 0 + inverse: 0 + exponent: 1 + - id: -1828317248 + _name: Inverse Bodi F + synapses: [] + receivers: + - nucleusId: 1641120128 + nucleusType: + isSleeping: 0 + _curvePreset: 3 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.001 + value: 999.99994 + inSlope: 0 + outSlope: -112788.63 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.008866142 + value: 112.788635 + inSlope: -112788.63 + outSlope: -6740.78 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.016732283 + value: 59.76471 + inSlope: -6740.78 + outSlope: -2429.6155 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.024598425 + value: 40.653008 + inSlope: -2429.6155 + outSlope: -1252.2269 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.032464568 + value: 30.802813 + inSlope: -1252.2269 + outSlope: -763.7558 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.040330708 + value: 24.795002 + inSlope: -763.7558 + outSlope: -514.45264 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.04819685 + value: 20.748245 + inSlope: -514.45264 + outSlope: -370.0882 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.056062993 + value: 17.837078 + inSlope: -370.0882 + outSlope: -279.01324 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.06392913 + value: 15.642321 + inSlope: -279.01324 + outSlope: -217.87398 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.07179528 + value: 13.928493 + inSlope: -217.87398 + outSlope: -174.8461 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.079661414 + value: 12.553129 + inSlope: -174.8461 + outSlope: -143.41913 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.087527566 + value: 11.424973 + inSlope: -143.41913 + outSlope: -119.76661 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.0953937 + value: 10.482872 + inSlope: -119.76661 + outSlope: -101.519356 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.10325985 + value: 9.684306 + inSlope: -101.519356 + outSlope: -87.14706 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.11112598 + value: 8.9987955 + inSlope: -87.14706 + outSlope: -75.62513 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.11899213 + value: 8.403917 + inSlope: -75.62513 + outSlope: -66.24654 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.12685826 + value: 7.882813 + inSlope: -66.24654 + outSlope: -58.510654 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.13472441 + value: 7.4225597 + inSlope: -58.510654 + outSlope: -52.055042 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.14259055 + value: 7.0130873 + inSlope: -52.055042 + outSlope: -46.612007 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.1504567 + value: 6.6464305 + inSlope: -46.612007 + outSlope: -41.98024 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.15832284 + value: 6.316208 + inSlope: -41.98024 + outSlope: -38.006134 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.16618897 + value: 6.0172467 + inSlope: -38.006134 + outSlope: -34.570965 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.17405513 + value: 5.745306 + inSlope: -34.570965 + outSlope: -31.581244 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.18192126 + value: 5.496884 + inSlope: -31.581244 + outSlope: -28.963417 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.1897874 + value: 5.2690535 + inSlope: -28.963417 + outSlope: -26.658009 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.19765353 + value: 5.059358 + inSlope: -26.658009 + outSlope: -24.617418 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.20551969 + value: 4.8657136 + inSlope: -24.617418 + outSlope: -22.802412 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.21338584 + value: 4.6863465 + inSlope: -22.802412 + outSlope: -21.181019 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.22125196 + value: 4.519734 + inSlope: -21.181019 + outSlope: -19.72667 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.22911811 + value: 4.364561 + inSlope: -19.72667 + outSlope: -18.417059 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.23698425 + value: 4.21969 + inSlope: -18.417059 + outSlope: -17.233776 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2448504 + value: 4.0841265 + inSlope: -17.233776 + outSlope: -16.160883 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.25271654 + value: 3.9570026 + inSlope: -16.160883 + outSlope: -15.185221 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2605827 + value: 3.8375535 + inSlope: -15.185221 + outSlope: -14.295299 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2684488 + value: 3.725105 + inSlope: -14.295299 + outSlope: -13.481375 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.27631494 + value: 3.6190586 + inSlope: -13.481375 + outSlope: -12.735047 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.28418112 + value: 3.5188825 + inSlope: -12.735047 + outSlope: -12.04901 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.29204726 + value: 3.4241033 + inSlope: -12.04901 + outSlope: -11.416967 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2999134 + value: 3.3342957 + inSlope: -11.416967 + outSlope: -10.8334 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.30777952 + value: 3.249079 + inSlope: -10.8334 + outSlope: -10.293426 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.31564566 + value: 3.1681094 + inSlope: -10.293426 + outSlope: -9.792865 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.3235118 + value: 3.0910773 + inSlope: -9.792865 + outSlope: -9.327949 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.33137795 + value: 3.0177023 + inSlope: -9.327949 + outSlope: -8.895375 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.33924407 + value: 2.9477303 + inSlope: -8.895375 + outSlope: -8.492224 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.34711024 + value: 2.880929 + inSlope: -8.492224 + outSlope: -8.115812 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.3549764 + value: 2.8170888 + inSlope: -8.115812 + outSlope: -7.76395 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.36284253 + value: 2.7560165 + inSlope: -7.76395 + outSlope: -7.434456 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.37070867 + value: 2.697536 + inSlope: -7.434456 + outSlope: -7.1255083 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.3785748 + value: 2.641486 + inSlope: -7.1255083 + outSlope: -6.8354197 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.38644093 + value: 2.5877175 + inSlope: -6.8354197 + outSlope: -6.562695 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.39430708 + value: 2.5360944 + inSlope: -6.562695 + outSlope: -6.305974 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.40217322 + value: 2.4864907 + inSlope: -6.305974 + outSlope: -6.064021 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4100394 + value: 2.43879 + inSlope: -6.064021 + outSlope: -5.835745 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4179055 + value: 2.3928854 + inSlope: -5.835745 + outSlope: -5.6201315 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.42577165 + value: 2.3486767 + inSlope: -5.6201315 + outSlope: -5.4162097 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4336378 + value: 2.306072 + inSlope: -5.4162097 + outSlope: -5.223229 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.44150394 + value: 2.2649853 + inSlope: -5.223229 + outSlope: -5.040342 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4493701 + value: 2.2253373 + inSlope: -5.040342 + outSlope: -4.8669295 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4572362 + value: 2.1870534 + inSlope: -4.8669295 + outSlope: -4.7023005 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.46510234 + value: 2.1500645 + inSlope: -4.7023005 + outSlope: -4.5458865 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.47296852 + value: 2.1143057 + inSlope: -4.5458865 + outSlope: -4.3971753 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.48083466 + value: 2.079717 + inSlope: -4.3971753 + outSlope: -4.2555995 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4887008 + value: 2.0462418 + inSlope: -4.2555995 + outSlope: -4.1207685 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.49656692 + value: 2.0138273 + inSlope: -4.1207685 + outSlope: -3.9922712 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5044331 + value: 1.9824234 + inSlope: -3.9922712 + outSlope: -3.8696532 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5122992 + value: 1.9519844 + inSlope: -3.8696532 + outSlope: -3.7526293 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5201653 + value: 1.9224657 + inSlope: -3.7526293 + outSlope: -3.6408176 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.52803147 + value: 1.8938265 + inSlope: -3.6408176 + outSlope: -3.5339315 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5358976 + value: 1.8660281 + inSlope: -3.5339315 + outSlope: -3.4316826 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.54376376 + value: 1.839034 + inSlope: -3.4316826 + outSlope: -3.3338284 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5516299 + value: 1.8128096 + inSlope: -3.3338284 + outSlope: -3.240066 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.55949605 + value: 1.7873228 + inSlope: -3.240066 + outSlope: -3.1502352 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.56736225 + value: 1.7625424 + inSlope: -3.1502352 + outSlope: -3.0640743 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5752284 + value: 1.7384399 + inSlope: -3.0640743 + outSlope: -2.9814053 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.58309454 + value: 1.7149878 + inSlope: -2.9814053 + outSlope: -2.9020314 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5909606 + value: 1.6921601 + inSlope: -2.9020314 + outSlope: -2.8257964 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.59882677 + value: 1.669932 + inSlope: -2.8257964 + outSlope: -2.7525082 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6066929 + value: 1.6482804 + inSlope: -2.7525082 + outSlope: -2.6820538 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.61455905 + value: 1.627183 + inSlope: -2.6820538 + outSlope: -2.6142666 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6224252 + value: 1.6066188 + inSlope: -2.6142666 + outSlope: -2.5490105 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.63029134 + value: 1.5865679 + inSlope: -2.5490105 + outSlope: -2.4861636 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6381575 + value: 1.5670114 + inSlope: -2.4861636 + outSlope: -2.4256358 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.64602363 + value: 1.547931 + inSlope: -2.4256358 + outSlope: -2.3672597 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6538898 + value: 1.5293097 + inSlope: -2.3672597 + outSlope: -2.3109925 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.66175586 + value: 1.5111313 + inSlope: -2.3109925 + outSlope: -2.2566907 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.669622 + value: 1.4933798 + inSlope: -2.2566907 + outSlope: -2.2042859 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.67748815 + value: 1.4760406 + inSlope: -2.2042859 + outSlope: -2.1536992 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6853543 + value: 1.4590993 + inSlope: -2.1536992 + outSlope: -2.1048093 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6932205 + value: 1.4425424 + inSlope: -2.1048093 + outSlope: -2.0575728 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.70108664 + value: 1.4263573 + inSlope: -2.0575728 + outSlope: -2.011927 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7089528 + value: 1.4105312 + inSlope: -2.011927 + outSlope: -1.9677659 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7168189 + value: 1.3950524 + inSlope: -1.9677659 + outSlope: -1.9250447 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7246851 + value: 1.3799098 + inSlope: -1.9250447 + outSlope: -1.8837026 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7325512 + value: 1.3650923 + inSlope: -1.8837026 + outSlope: -1.8436778 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7404173 + value: 1.3505898 + inSlope: -1.8436778 + outSlope: -1.8049132 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.74828345 + value: 1.336392 + inSlope: -1.8049132 + outSlope: -1.7673749 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7561496 + value: 1.3224896 + inSlope: -1.7673749 + outSlope: -1.7309732 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.76401573 + value: 1.3088735 + inSlope: -1.7309732 + outSlope: -1.695693 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7718819 + value: 1.295535 + inSlope: -1.695693 + outSlope: -1.6614736 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.779748 + value: 1.2824656 + inSlope: -1.6614736 + outSlope: -1.6282848 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.78761417 + value: 1.2696573 + inSlope: -1.6282848 + outSlope: -1.5960962 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7954803 + value: 1.2571021 + inSlope: -1.5960962 + outSlope: -1.564832 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.80334646 + value: 1.2447929 + inSlope: -1.564832 + outSlope: -1.5344887 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.81121254 + value: 1.2327225 + inSlope: -1.5344887 + outSlope: -1.5050048 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.81907874 + value: 1.2208838 + inSlope: -1.5050048 + outSlope: -1.4763738 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8269449 + value: 1.2092705 + inSlope: -1.4763738 + outSlope: -1.4485649 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.83481103 + value: 1.1978759 + inSlope: -1.4485649 + outSlope: -1.4215137 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8426772 + value: 1.186694 + inSlope: -1.4215137 + outSlope: -1.3952202 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8505433 + value: 1.175719 + inSlope: -1.3952202 + outSlope: -1.369639 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.85840946 + value: 1.1649452 + inSlope: -1.369639 + outSlope: -1.3447852 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8662756 + value: 1.154367 + inSlope: -1.3447852 + outSlope: -1.320568 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.87414175 + value: 1.1439792 + inSlope: -1.320568 + outSlope: -1.2970176 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8820079 + value: 1.1337767 + inSlope: -1.2970176 + outSlope: -1.2740829 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.889874 + value: 1.1237546 + inSlope: -1.2740829 + outSlope: -1.2517655 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8977401 + value: 1.113908 + inSlope: -1.2517655 + outSlope: -1.2300034 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.90560627 + value: 1.1042327 + inSlope: -1.2300034 + outSlope: -1.2088321 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9134724 + value: 1.0947238 + inSlope: -1.2088321 + outSlope: -1.1881914 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.92133856 + value: 1.0853773 + inSlope: -1.1881914 + outSlope: -1.1680659 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9292047 + value: 1.0761892 + inSlope: -1.1680659 + outSlope: -1.1484709 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.93707085 + value: 1.0671551 + inSlope: -1.1484709 + outSlope: -1.1293371 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.94493705 + value: 1.0582715 + inSlope: -1.1293371 + outSlope: -1.1106901 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9528032 + value: 1.0495347 + inSlope: -1.1106901 + outSlope: -1.0925045 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.96066934 + value: 1.0409409 + inSlope: -1.0925045 + outSlope: -1.0747513 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9685354 + value: 1.0324868 + inSlope: -1.0747513 + outSlope: -1.0574516 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.97640157 + value: 1.0241687 + inSlope: -1.0574516 + outSlope: -1.0405389 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9842677 + value: 1.0159837 + inSlope: -1.0405389 + outSlope: -1.0240355 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.99213386 + value: 1.0079285 + inSlope: -1.0240355 + outSlope: -1.0079259 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: -1.0079259 + outSlope: 0 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 100 + average: 0 + inverse: 0 + exponent: 1 perceptei: - id: 407735232 _name: Boundary @@ -554,6 +7313,7 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 + baseName: thingType: 1 thingId: 0 - id: -1659429232 @@ -561,7 +7321,7 @@ MonoBehaviour: synapses: [] receivers: - nucleusId: 1938577052 - - nucleusId: 1641120128 + - nucleusId: 1710403072 nucleusType: Perceptoid isSleeping: 0 _curvePreset: 0 @@ -575,6 +7335,7 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 + baseName: thingType: 2 thingId: 0 - id: 839544896 @@ -582,7 +7343,7 @@ MonoBehaviour: synapses: [] receivers: - nucleusId: 1938577052 - - nucleusId: 1641120128 + - nucleusId: -916054576 nucleusType: Perceptoid isSleeping: 0 _curvePreset: 0 @@ -596,14 +7357,15 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 + baseName: thingType: 2 thingId: 0 - id: -348340288 _name: BoidC synapses: [] receivers: - - nucleusId: 1641120128 - nucleusId: 1938577052 + - nucleusId: -1391520368 nucleusType: Perceptoid isSleeping: 0 _curvePreset: 0 @@ -617,6 +7379,7 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 + baseName: thingType: 2 thingId: 0 - id: -1095934288 @@ -624,7 +7387,6 @@ MonoBehaviour: synapses: [] receivers: - nucleusId: 1938577052 - - nucleusId: 1641120128 nucleusType: Perceptoid isSleeping: 0 _curvePreset: 0 @@ -638,13 +7400,13 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 + baseName: thingType: 2 thingId: 0 - id: -1413006832 _name: BoidE synapses: [] receivers: - - nucleusId: 1641120128 - nucleusId: 1938577052 nucleusType: Perceptoid isSleeping: 0 @@ -659,6 +7421,7 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 + baseName: thingType: 2 thingId: 0 - id: -61245040 @@ -666,7 +7429,6 @@ MonoBehaviour: synapses: [] receivers: - nucleusId: 1938577052 - - nucleusId: 1641120128 nucleusType: Perceptoid isSleeping: 0 _curvePreset: 0 @@ -680,6 +7442,7 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 + baseName: thingType: 2 thingId: 0 - id: -1659687600 @@ -700,6 +7463,7 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 + baseName: thingType: 3 thingId: 0 - id: 1322333072 @@ -720,6 +7484,7 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 + baseName: thingType: 3 thingId: 0 - id: -1563920864 @@ -740,6 +7505,7 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 + baseName: thingType: 3 thingId: 0 - id: 182328688 @@ -760,6 +7526,7 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 + baseName: thingType: 3 thingId: 0 - id: -1666561744 @@ -780,6 +7547,7 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 + baseName: thingType: 3 thingId: 0 - id: -1884196224 @@ -800,6 +7568,7 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 + baseName: thingType: 3 thingId: 0 rootId: -1707533328 From de7503bb4a216e60594b44c40e1da66a81e096c8 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Fri, 9 Jan 2026 10:08:06 +0100 Subject: [PATCH 057/179] Add perception array UI --- Assets/NanoBrain/PercepteiArray.cs | 67 +++++++++++--- Assets/NanoBrain/Perceptoid.cs | 45 ++++++---- .../VisualEditor/Editor/NanoBrainInspector.cs | 89 +++++++++++++------ Assets/Scenes/Boids/Boids.unity | 2 +- Assets/Scenes/Boids/SwarmingBrain.asset | 26 ++++-- 5 files changed, 161 insertions(+), 68 deletions(-) diff --git a/Assets/NanoBrain/PercepteiArray.cs b/Assets/NanoBrain/PercepteiArray.cs index cf4b5e2..a46f2d0 100644 --- a/Assets/NanoBrain/PercepteiArray.cs +++ b/Assets/NanoBrain/PercepteiArray.cs @@ -1,22 +1,61 @@ +using UnityEngine; + +[System.Serializable] public class PercepteiArray { - public ArrayPerceptoid[] perceptei; + [SerializeReference] + public Perceptoid[] perceptei; public string name; - public PercepteiArray(NanoBrain brain, int thingType, string baseName, uint count) { - this.name = baseName; - this.perceptei = new ArrayPerceptoid[count]; - for (uint i = 0; i < count; i++) { - this.perceptei[i] = new ArrayPerceptoid(brain, thingType, $"{baseName}[{i}]") { - array = this - }; - } + // public PercepteiArray(NanoBrain brain, int thingType, string baseName, uint count) { + // this.name = baseName; + // this.perceptei = new Perceptoid[count]; + // for (uint i = 0; i < count; i++) { + // this.perceptei[i] = new Perceptoid(brain, thingType, $"{baseName}[{i}]") { + // array = this + // }; + // } + // } + public PercepteiArray(Perceptoid perceptoid) { + this.name = perceptoid.baseName; + this.perceptei = new Perceptoid[1]; + this.perceptei[0] = perceptoid; + } + + public void AddPerceptoid() { + if (this.perceptei.Length == 0) { + Debug.LogError("Empty perceptoid array, cannot add"); + return; + } + int newLength = this.perceptei.Length + 1; + Perceptoid[] newPerceptei = new Perceptoid[newLength]; + + for (int i = 0; i < this.perceptei.Length; i++) + newPerceptei[i] = this.perceptei[i]; + newPerceptei[newLength - 1] = new Perceptoid(this); + + this.perceptei = newPerceptei; + } + + public void RemovePerceptoid() { + int newLength = this.perceptei.Length - 1; + if (newLength == 0) { + Debug.LogWarning("Perceptoid array cannot be empty"); + return; + } + Perceptoid[] newPerceptei = new Perceptoid[newLength]; + for (int i = 0; i < newLength; i++) + newPerceptei[i++] = this.perceptei[i]; + // Delete the last perception + Nucleus.Delete(this.perceptei[newLength]); + + this.perceptei = newPerceptei; } } -public class ArrayPerceptoid : Perceptoid { - public PercepteiArray array; +// public class ArrayPerceptoid : Perceptoid { +// public PercepteiArray array; - public ArrayPerceptoid(NanoBrain brain, int thingType, string name = "sensor") : base(brain, thingType, name) { - } +// public ArrayPerceptoid(NanoBrain brain, int thingType, string name = "sensor") : base(brain, thingType, name) { +// } -} \ No newline at end of file +// } \ No newline at end of file diff --git a/Assets/NanoBrain/Perceptoid.cs b/Assets/NanoBrain/Perceptoid.cs index 62f0b11..3f1d0b1 100644 --- a/Assets/NanoBrain/Perceptoid.cs +++ b/Assets/NanoBrain/Perceptoid.cs @@ -1,5 +1,4 @@ using UnityEngine; -using LinearAlgebra; [System.Serializable] public class Perceptoid : Neuroid { @@ -8,16 +7,24 @@ public class Perceptoid : Neuroid { public Receptor receptor; public string baseName; + public int thingId; + + //[SerializeField] + // Needs serialization!!!! + [SerializeReference] + public PercepteiArray array; + #region Serialization [SerializeField] public int thingType; - public int thingId; public override void Rebuild(NanoBrain brain) { base.Rebuild(brain); this.receptor = Receptor.GetReceptor(brain, thingType); this.receptor.perceptei.Add(this); + if (string.IsNullOrEmpty(this.baseName)) + this.baseName = this.name; } public override void Deserialize(Nucleus nucleus) { @@ -62,30 +69,30 @@ public class Perceptoid : Neuroid { this.thingType = thingType; this.receptor = Receptor.GetReceptor(brain, thingType); this.receptor.perceptei.Add(this); + this.array = new PercepteiArray(this); } - // public void Replace(int thingType, string name = "sensor") { - // this.name = name; + public Perceptoid(PercepteiArray array) : base(array.name) { + this.array = array; + Perceptoid source = array.perceptei[0]; + this.brain = source.brain; + if (this.brain != null) { + this.brain.perceptei.Add(this); + } + else + Debug.LogError("No neuroid network"); - // this.thingType = thingType; - // this.receptor.thingType = thingType; - // this.receptor.localPosition = Vector3.zero; - - // this.outputValue = Vector3.zero; - // this.receivers = new(); - // } + this.nucleusType = nameof(Perceptoid); + this.name = source.baseName; + this.baseName = source.baseName; + this.thingType = source.thingType; + this.receptor = Receptor.GetReceptor(this.brain, this.thingType); + this.receptor.perceptei.Add(this); + } public override void UpdateState() { Vector3 result = this.receptor.localPosition; UpdateResult(result); } - - // public static Perceptoid GetPerception(NanoBrain brain, int thingType = 0) { - // foreach (Nucleus nucleus in brain.nuclei) { - // if (nucleus is Perceptoid perceptoid && (thingType == 0 || perceptoid.receptor.thingType == thingType)) - // return perceptoid; - // } - // return null; - // } } diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs index e8f7daf..cb39199 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs @@ -278,19 +278,19 @@ public class NanoBrainInspector : Editor { Vector3 pos = new(250, margin + row * spacing, 0.0f); Handles.color = Color.white; Handles.DrawLine(parentPos, pos); - if (synapse.nucleus is ArrayPerceptoid perceptoid) { - if (drawnArrays.Contains(perceptoid.array)) - // We already drawn this array - continue; + // if (synapse.nucleus is Perceptoid perceptoid && perceptoid.array != null) { + // // if (drawnArrays.Contains(perceptoid.array)) + // // // We already drawn this array + // // continue; - drawnArrays.Add(perceptoid.array); - DrawArray(perceptoid.array, pos, size); - } - else { + // drawnArrays.Add(perceptoid.array); + // DrawArray(perceptoid.array, pos, size); + // } + // else { - DrawNucleus(synapse.nucleus, pos, maxValue, size); - row++; - } + DrawNucleus(synapse.nucleus, pos, maxValue, size); + row++; + // } } } @@ -298,16 +298,35 @@ public class NanoBrainInspector : Editor { if (nucleus.isSleeping) Handles.color = Color.darkRed; else { - float brightness = nucleus.outputValue.magnitude / maxValue; - Handles.color = new Color(brightness, brightness, brightness); + if (Application.isPlaying) { + float brightness = nucleus.outputValue.magnitude / maxValue; + Handles.color = new Color(brightness, brightness, brightness, 1f); + } + else + Handles.color = Color.black; } Handles.DrawSolidDisc(position, Vector3.forward, size); - Vector3 labelPos = position - Vector3.down * (size + 0.2f); // below disc along up axis + + Handles.color = Color.white; + // Position the label in front of the disc + Vector3 labelPosition = position + (Vector3.forward * 0.1f); + GUIStyle style = new(EditorStyles.label) { - alignment = TextAnchor.UpperCenter, + alignment = TextAnchor.MiddleCenter, normal = { textColor = Color.white }, - fontStyle = FontStyle.Bold + fontStyle = FontStyle.Bold, }; + if (nucleus is Perceptoid perceptoid) { + if (perceptoid.array == null || perceptoid.array.perceptei == null || perceptoid.array.perceptei.Length == 0) + perceptoid.array = new PercepteiArray(perceptoid); + + if (perceptoid.array.perceptei.Length > 1) { + Handles.Label(labelPosition, perceptoid.array.perceptei.Length.ToString(), style); + } + } + + style.alignment = TextAnchor.UpperCenter; + Vector3 labelPos = position - Vector3.down * (size + 0.2f); // below disc along up axis Handles.Label(labelPos, nucleus.name, style); Rect neuronRect = new(position.x - size, position.y - size, size * 2, size * 2); @@ -326,21 +345,18 @@ public class NanoBrainInspector : Editor { } } - private void DrawArray(PercepteiArray array, Vector3 position, float size) { - Vector3 offset = new(size/4, size/4, 0); - Handles.color = Color.darkGray; - Handles.DrawSolidDisc(position + offset * 2, Vector3.forward, size); - Handles.color = Color.lightGray; - Handles.DrawSolidDisc(position + offset, Vector3.forward, size); - Handles.color = Color.white; + private void DrawArray(PercepteiArray array, Vector3 position, float size) { + Vector3 offset = new(size / 4, size / 4, 0); + Handles.color = Color.black; Handles.DrawSolidDisc(position, Vector3.forward, size); - Vector3 labelPos = position - Vector3.down * (size + 0.2f); // below disc along up axis - GUIStyle style = new GUIStyle(EditorStyles.label) { + GUIStyle style = new(EditorStyles.label) { alignment = TextAnchor.UpperCenter, normal = { textColor = Color.white }, fontStyle = FontStyle.Bold }; + Handles.Label(position, array.perceptei.Length.ToString(), style); + Vector3 labelPos = position - Vector3.down * (size + 0.2f); // below disc along up axis Handles.Label(labelPos, array.name, style); // To do: add HandleClick (see above) to expand the array @@ -403,8 +419,18 @@ public class NanoBrainInspector : Editor { return; this.currentNucleus.name = EditorGUILayout.TextField(this.currentNucleus.name); - if (this.currentNucleus is Perceptoid currentPerceptoid) { - currentPerceptoid.receptor.thingType = EditorGUILayout.IntField("Thing Type", currentPerceptoid.receptor.thingType); + if (this.currentNucleus is Perceptoid perceptoid) { + perceptoid.receptor.thingType = EditorGUILayout.IntField("Thing Type", perceptoid.receptor.thingType); + + if (perceptoid.array == null || perceptoid.array.perceptei == null || perceptoid.array.perceptei.Length == 0) + perceptoid.array = new PercepteiArray(perceptoid); + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.IntField("Array size", perceptoid.array.perceptei.Length); + if (GUILayout.Button("Add")) + perceptoid.array.AddPerceptoid(); + if (GUILayout.Button("Del")) + perceptoid.array.RemovePerceptoid(); + EditorGUILayout.EndHorizontal(); } else if (this.currentNucleus is Neuroid neuroid) { EditorGUILayout.BeginHorizontal(); @@ -427,12 +453,21 @@ public class NanoBrainInspector : Editor { foreach (Synapse synapse in synapses) { if (synapse.nucleus != null) { EditorGUILayout.Space(); + EditorGUI.BeginDisabledGroup(synapse.nucleus.isSleeping); if (Application.isPlaying) EditorGUILayout.FloatField(synapse.nucleus.name, synapse.nucleus.outputValue.magnitude * synapse.weight); else { EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField(synapse.nucleus.name); + // if (synapse.nucleus is Perceptoid perceptoid) { + // if (perceptoid.array == null || perceptoid.array.perceptei == null || perceptoid.array.perceptei.Length == 0) { + // perceptoid.array = new PercepteiArray(perceptoid); + // } + // EditorGUILayout.IntField(perceptoid.array.perceptei.Length); + // if (GUILayout.Button("Add")) + // perceptoid.array.AddPerceptoid(); + // } if (GUILayout.Button("Disconnect")) synapse.nucleus.RemoveReceiver(this.currentNucleus); EditorGUILayout.EndHorizontal(); diff --git a/Assets/Scenes/Boids/Boids.unity b/Assets/Scenes/Boids/Boids.unity index de7d29d..2c0ccaf 100644 --- a/Assets/Scenes/Boids/Boids.unity +++ b/Assets/Scenes/Boids/Boids.unity @@ -375,7 +375,7 @@ MonoBehaviour: m_EditorClassIdentifier: Assembly-CSharp::SwarmControl speed: 1 inertia: 0.7 - alignmentForce: 0.5 + alignmentForce: 0.4 cohesionForce: 0.1 separationForce: -0.1 avoidanceForce: 1 diff --git a/Assets/Scenes/Boids/SwarmingBrain.asset b/Assets/Scenes/Boids/SwarmingBrain.asset index c78bca5..92d4f4b 100644 --- a/Assets/Scenes/Boids/SwarmingBrain.asset +++ b/Assets/Scenes/Boids/SwarmingBrain.asset @@ -142,8 +142,8 @@ MonoBehaviour: inWeight: 0 outWeight: 0 - serializedVersion: 3 - time: 1 - value: 1 + time: 1000 + value: 1000 inSlope: 1 outSlope: 0 tangentMode: 0 @@ -250,8 +250,8 @@ MonoBehaviour: inWeight: 0 outWeight: 0 - serializedVersion: 3 - time: 1 - value: 1 + time: 1000 + value: 1000 inSlope: 1 outSlope: 0 tangentMode: 0 @@ -3786,7 +3786,10 @@ MonoBehaviour: exponent: 1 - id: 763145504 _name: Inverse Boid D - synapses: [] + synapses: + - nucleusId: -1095934288 + weight: 1 + curveMax: 1 receivers: - nucleusId: 1641120128 nucleusType: @@ -4956,7 +4959,10 @@ MonoBehaviour: exponent: 1 - id: 1469392160 _name: Inverse Boid E - synapses: [] + synapses: + - nucleusId: -1413006832 + weight: 1 + curveMax: 1 receivers: - nucleusId: 1641120128 nucleusType: @@ -6126,7 +6132,10 @@ MonoBehaviour: exponent: 1 - id: -1828317248 _name: Inverse Bodi F - synapses: [] + synapses: + - nucleusId: -61245040 + weight: 1 + curveMax: 1 receivers: - nucleusId: 1641120128 nucleusType: @@ -7387,6 +7396,7 @@ MonoBehaviour: synapses: [] receivers: - nucleusId: 1938577052 + - nucleusId: 763145504 nucleusType: Perceptoid isSleeping: 0 _curvePreset: 0 @@ -7408,6 +7418,7 @@ MonoBehaviour: synapses: [] receivers: - nucleusId: 1938577052 + - nucleusId: 1469392160 nucleusType: Perceptoid isSleeping: 0 _curvePreset: 0 @@ -7429,6 +7440,7 @@ MonoBehaviour: synapses: [] receivers: - nucleusId: 1938577052 + - nucleusId: -1828317248 nucleusType: Perceptoid isSleeping: 0 _curvePreset: 0 From f8dc4dc5d3a3e919f43fa4b0cbaa04244b47eef3 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Fri, 9 Jan 2026 10:56:16 +0100 Subject: [PATCH 058/179] Add identity cluster --- Assets/Scenes/Boids/Identity.asset | 59 +++++++++++++++++++++++++ Assets/Scenes/Boids/Identity.asset.meta | 8 ++++ 2 files changed, 67 insertions(+) create mode 100644 Assets/Scenes/Boids/Identity.asset create mode 100644 Assets/Scenes/Boids/Identity.asset.meta diff --git a/Assets/Scenes/Boids/Identity.asset b/Assets/Scenes/Boids/Identity.asset new file mode 100644 index 0000000..94f63d4 --- /dev/null +++ b/Assets/Scenes/Boids/Identity.asset @@ -0,0 +1,59 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 36081359186edfec998d891a1feeb17b, type: 3} + m_Name: Identity + m_EditorClassIdentifier: Assembly-CSharp::NanoBrain + title: + count: 0 + color: {r: 1, g: 1, b: 1, a: 1} + texture: {fileID: 0} + nuclei: + - id: 1707104464 + _name: Root + synapses: [] + receivers: [] + nucleusType: + isSleeping: 0 + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1000 + value: 1000 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + perceptei: [] + rootId: 1707104464 + references: + version: 2 + RefIds: [] diff --git a/Assets/Scenes/Boids/Identity.asset.meta b/Assets/Scenes/Boids/Identity.asset.meta new file mode 100644 index 0000000..9797408 --- /dev/null +++ b/Assets/Scenes/Boids/Identity.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5040f18b0515ba23eb0782d6f6794054 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: From 1b5a86ce55447f52abd19506ca41e9f35966a42c Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Fri, 9 Jan 2026 12:06:49 +0100 Subject: [PATCH 059/179] Improve UI style --- .../VisualEditor/Editor/NanoBrainInspector.cs | 1228 ++++++++--------- .../VisualEditor/Resources/GraphStyles.uss | 27 +- ProjectSettings/GraphicsSettings.asset | 4 +- 3 files changed, 625 insertions(+), 634 deletions(-) diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs index cb39199..8cd7114 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs @@ -1,617 +1,613 @@ -using System.Collections.Generic; -using System.Linq; -using UnityEditor; - -using UnityEngine; -using UnityEngine.UIElements; - -[CustomEditor(typeof(NanoBrain))] -public class NanoBrainInspector : Editor { - protected static VisualElement mainContainer; - protected static VisualElement inspectorContainer; - - protected bool breakOnWake = false; - - #region Start - - public override VisualElement CreateInspectorGUI() { - NanoBrain brain = target as NanoBrain; - - serializedObject.Update(); - - VisualElement root = new(); - root.style.flexDirection = FlexDirection.Column; // side-by-side layout - root.style.flexGrow = 1; - root.style.minHeight = 600; - root.style.paddingLeft = 0; - root.style.paddingRight = 0; - root.style.paddingTop = 0; - root.style.paddingBottom = 0; - - root.styleSheets.Add(Resources.Load("GraphStyles")); - - mainContainer = new() { - name = "main", - style = { - flexDirection = FlexDirection.Row, - flexGrow = 1, - minHeight = 500, - } - }; - GraphView board; - board = new GraphView(); - board.style.flexGrow = 1; - - inspectorContainer = new VisualElement { - name = "inspector", - style = { - width = 400, - } - }; - - mainContainer.Add(board); - mainContainer.Add(inspectorContainer); - root.Add(mainContainer); - - // Run once for initial state (use resolved style width if available) - float initialWidth = root.layout.width > 0 ? root.layout.width : root.contentRect.width; - UpdateLayout(initialWidth); - - // React to size changes of root (or parent if appropriate) - root.RegisterCallback(evt => { - UpdateLayout(evt.newRect.width); - }); - - if (brain != null) - board.SetGraph(null, brain, brain.root, inspectorContainer); - else - Debug.LogWarning(" No brain!"); - - serializedObject.ApplyModifiedProperties(); - return root; - } - - public class GraphView : VisualElement { - NanoBrain brain; - SerializedObject serializedBrain; - Nucleus currentNucleus; - GameObject gameObject; - private List layers = new(); - private readonly Dictionary neuroidPositions = new(); - - Vector2 pan = Vector2.zero; - //float zoom = 1f; - bool draggingCanvas = false; - Vector2 lastMouse; - GraphNodeWrapper currentWrapper; - - public GraphView() { - name = "content"; - style.flexGrow = 1; - - IMGUIContainer imguiContainer = new(OnIMGUI); - imguiContainer.style.position = Position.Absolute; - imguiContainer.style.left = 0; imguiContainer.style.top = 0; - imguiContainer.style.right = 0; imguiContainer.style.bottom = 0; - imguiContainer.pickingMode = PickingMode.Position; - imguiContainer.focusable = true; - Add(imguiContainer); - - //RegisterCallback(OnWheel); - RegisterCallback(OnMouseDown); - RegisterCallback(OnMouseMove); - RegisterCallback(OnMouseUp); - } - - public void SetGraph(GameObject gameObject, NanoBrain brain, Nucleus nucleus, VisualElement inspectorContainer) { - this.gameObject = gameObject; - this.brain = brain; - if (Application.isPlaying == false) - this.serializedBrain = new SerializedObject(brain); - this.currentNucleus = nucleus; - Rebuild(inspectorContainer); - } - - void Rebuild(VisualElement inspectorContainer) { - BuildLayers(); - - if (this.currentNucleus == null) { - inspectorContainer.Clear(); - return; - } - - if (currentWrapper != null) - DestroyImmediate(currentWrapper); - currentWrapper = CreateInstance().Init(this.currentNucleus, brain); - DrawInspector(inspectorContainer); - } - - private void BuildLayers() { - // A temporary list to track what's been added to layers - this.layers = new(); - int layerIx = 0; - - Nucleus selectedNucleus = this.currentNucleus; - if (selectedNucleus == null) - return; - NeuroidLayer currentLayer = new() { ix = layerIx }; - - if (selectedNucleus.receivers != null) { - foreach (Receiver receiver in selectedNucleus.receivers) { - Nucleus outputNeuroid = receiver.nucleus; - if (outputNeuroid != null) { - AddToLayer(currentLayer, outputNeuroid); - // Debug.Log($"layer {layerIx} nucleus {outputNeuroid.name}"); - } - } - } - if (currentLayer.neuroids.Count > 0) { - this.layers.Add(currentLayer); - layerIx++; - currentLayer = new() { ix = layerIx }; - } - - AddToLayer(currentLayer, selectedNucleus); - this.layers.Add(currentLayer); - // Debug.Log($"layer {layerIx} nucleus {selectedNucleus.name}"); - - layerIx++; - currentLayer = new() { ix = layerIx }; - - if (selectedNucleus.synapses != null) { - foreach (Synapse synapse in selectedNucleus.synapses) { - Nucleus input = synapse.nucleus; - AddToLayer(currentLayer, input); - // Debug.Log($"layer {layerIx} nucleus {input.name}"); - } - } - if (currentLayer.neuroids.Count > 0) { - this.layers.Add(currentLayer); - } - } - - private void AddToLayer(NeuroidLayer layer, Nucleus nucleus) { - if (nucleus == null) - return; - layer.neuroids.Add(nucleus); - nucleus.layerIx = layer.ix; - // Store its position - Vector2Int neuroidPosition = new(layer.ix, layer.neuroids.Count - 1); - neuroidPositions[nucleus] = neuroidPosition; - - } - - void OnMouseDown(MouseDownEvent e) { - if (e.button == 2) { draggingCanvas = true; lastMouse = e.mousePosition; e.StopPropagation(); } - } - void OnMouseMove(MouseMoveEvent e) { - if (draggingCanvas) { - var delta = e.mousePosition - lastMouse; - pan += delta; - //content.style.left = pan.x; - //content.style.top = pan.y; - lastMouse = e.mousePosition; - } - } - void OnMouseUp(MouseUpEvent e) { if (e.button == 2) draggingCanvas = false; } - - void OnIMGUI() { - if (currentNucleus == null) - return; - - if (Application.isPlaying == false) - serializedBrain.Update(); - - Handles.BeginGUI(); - DrawGraph(); - Handles.EndGUI(); - - } - - private void DrawGraph() { - float size = 20; - Vector3 position = new(150, 210, 0); - - DrawReceivers(this.currentNucleus, position, size); - DrawSynapses(this.currentNucleus, position, size); - - // Draw selected Nucleus - Handles.color = Color.white; - Handles.DrawSolidDisc(position, Vector3.forward, size + 2); - DrawNucleus(this.currentNucleus, position, this.currentNucleus.outputValue.magnitude, 20); - } - - private void DrawReceivers(Nucleus nucleus, Vector3 parentPos, float size) { - int nodeCount = nucleus.receivers.Count; - - // Determine the maximum value in this layer - // This is used to 'scale' the output value colors of the nuclei - float maxValue = 0; - foreach (Receiver receiver in nucleus.receivers) { - if (receiver.nucleus is Neuroid neuroid) { - float value = neuroid.outputValue.magnitude; - if (value > maxValue) - maxValue = value; - } - } - - // Determine the spacing of the nuclei in the layer - float spacing = 400f / nodeCount; - float margin = 10 + spacing / 2; - - int row = 0; - foreach (Receiver receiver in nucleus.receivers) { - Nucleus receiverNucleus = receiver.nucleus; - if (receiverNucleus == null) - continue; - - Vector3 pos = new(50, margin + row * spacing, 0.0f); - Handles.color = Color.white; - Handles.DrawLine(parentPos, pos); - - DrawNucleus(receiverNucleus, pos, maxValue, size); - row++; - } - } - - private void DrawSynapses(Nucleus nucleus, Vector3 parentPos, float size) { - int nodeCount = nucleus.synapses.Count; - - // Determine the maximum value in this layer - // This is used to 'scale' the output value colors of the nuclei - float maxValue = 0; - foreach (Synapse receiver in nucleus.synapses) { - if (receiver.nucleus is Neuroid neuroid) { - float value = neuroid.outputValue.magnitude; - if (value > maxValue) - maxValue = value; - } - } - - // Determine the spacing of the nuclei in the layer - float spacing = 400f / nodeCount; - float margin = 10 + spacing / 2; - - int row = 0; - List drawnArrays = new(); - foreach (Synapse synapse in nucleus.synapses) { - Vector3 pos = new(250, margin + row * spacing, 0.0f); - Handles.color = Color.white; - Handles.DrawLine(parentPos, pos); - // if (synapse.nucleus is Perceptoid perceptoid && perceptoid.array != null) { - // // if (drawnArrays.Contains(perceptoid.array)) - // // // We already drawn this array - // // continue; - - // drawnArrays.Add(perceptoid.array); - // DrawArray(perceptoid.array, pos, size); - // } - // else { - - DrawNucleus(synapse.nucleus, pos, maxValue, size); - row++; - // } - } - } - - private void DrawNucleus(Nucleus nucleus, Vector3 position, float maxValue, float size) { - if (nucleus.isSleeping) - Handles.color = Color.darkRed; - else { - if (Application.isPlaying) { - float brightness = nucleus.outputValue.magnitude / maxValue; - Handles.color = new Color(brightness, brightness, brightness, 1f); - } - else - Handles.color = Color.black; - } - Handles.DrawSolidDisc(position, Vector3.forward, size); - - Handles.color = Color.white; - // Position the label in front of the disc - Vector3 labelPosition = position + (Vector3.forward * 0.1f); - - GUIStyle style = new(EditorStyles.label) { - alignment = TextAnchor.MiddleCenter, - normal = { textColor = Color.white }, - fontStyle = FontStyle.Bold, - }; - if (nucleus is Perceptoid perceptoid) { - if (perceptoid.array == null || perceptoid.array.perceptei == null || perceptoid.array.perceptei.Length == 0) - perceptoid.array = new PercepteiArray(perceptoid); - - if (perceptoid.array.perceptei.Length > 1) { - Handles.Label(labelPosition, perceptoid.array.perceptei.Length.ToString(), style); - } - } - - style.alignment = TextAnchor.UpperCenter; - Vector3 labelPos = position - Vector3.down * (size + 0.2f); // below disc along up axis - Handles.Label(labelPos, nucleus.name, style); - - Rect neuronRect = new(position.x - size, position.y - size, size * 2, size * 2); - int id = GUIUtility.GetControlID(FocusType.Passive); - Event e = Event.current; - EventType et = e.GetTypeForControl(id); - if (e != null && neuronRect.Contains(e.mousePosition)) { - // Process Hover - HandleMouseHover(nucleus, neuronRect); - // Process click - if (e.type == EventType.MouseDown && e.button == 0) { - // Consume the event so the scene doesn't also handle it - e.Use(); - HandleClicked(nucleus); - } - } - } - - private void DrawArray(PercepteiArray array, Vector3 position, float size) { - Vector3 offset = new(size / 4, size / 4, 0); - Handles.color = Color.black; - Handles.DrawSolidDisc(position, Vector3.forward, size); - - GUIStyle style = new(EditorStyles.label) { - alignment = TextAnchor.UpperCenter, - normal = { textColor = Color.white }, - fontStyle = FontStyle.Bold - }; - Handles.Label(position, array.perceptei.Length.ToString(), style); - Vector3 labelPos = position - Vector3.down * (size + 0.2f); // below disc along up axis - Handles.Label(labelPos, array.name, style); - - // To do: add HandleClick (see above) to expand the array - } - - private void HandleMouseHover(Nucleus nucleus, Rect rect) { - GUIContent tooltip; - if (nucleus is Perceptoid perceptoid) { - if (perceptoid.receptor != null) { - tooltip = new( - $"{perceptoid.name}" + - $"\nType {perceptoid.receptor.thingType}" + - $" Thing {perceptoid.thingId}" + - $"\nValue: {nucleus.outputValue}"); - } - else { - tooltip = new( - $"{perceptoid.name}" + - $"\nThing {perceptoid.thingId}" + - $"\nValue: {nucleus.outputValue}"); - } - } - else { - tooltip = new( - $"{nucleus.name}" + - $"\nsynapse count {nucleus.synapses.Count}" + - $"\nValue: {nucleus.outputValue}"); - } - - Vector2 mousePosition = Event.current.mousePosition; - - // Display tooltip with some offset - Vector2 tooltipSize = GUI.skin.box.CalcSize(tooltip); - Rect tooltipRect = new Rect(mousePosition.x + 10, mousePosition.y + 10, tooltipSize.x, tooltipSize.y); - - GUI.Box(tooltipRect, tooltip); - } - - private void HandleClicked(Nucleus nucleus) { - this.currentNucleus = nucleus; - BuildLayers(); - } - - void DrawInspector(VisualElement inspectorContainer) { - if (inspectorContainer == null) - return; - - inspectorContainer.Clear(); - if (this.currentNucleus == null) - return; - - // create a SerializedObject wrapper so Unity inspector controls work (and Undo) - SerializedObject so = new(currentWrapper); - IMGUIContainer container = new(() => { - if (so.targetObject == null) - return; - so.Update(); - - if (this.currentNucleus == null) - return; - - this.currentNucleus.name = EditorGUILayout.TextField(this.currentNucleus.name); - if (this.currentNucleus is Perceptoid perceptoid) { - perceptoid.receptor.thingType = EditorGUILayout.IntField("Thing Type", perceptoid.receptor.thingType); - - if (perceptoid.array == null || perceptoid.array.perceptei == null || perceptoid.array.perceptei.Length == 0) - perceptoid.array = new PercepteiArray(perceptoid); - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.IntField("Array size", perceptoid.array.perceptei.Length); - if (GUILayout.Button("Add")) - perceptoid.array.AddPerceptoid(); - if (GUILayout.Button("Del")) - perceptoid.array.RemovePerceptoid(); - EditorGUILayout.EndHorizontal(); - } - else if (this.currentNucleus is Neuroid neuroid) { - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.LabelField("Activation Curve", GUILayout.Width(150)); - if (neuroid.curveMax > 0) - EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, 0, 1, neuroid.curveMax)); - else - EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, neuroid.curveMax, 1, -neuroid.curveMax)); - neuroid.curvePreset = (Neuroid.CurvePresets)EditorGUILayout.EnumPopup(neuroid.curvePreset, GUILayout.Width(100)); - EditorGUILayout.EndHorizontal(); - } - - if (Application.isPlaying) - EditorGUILayout.FloatField("Output", this.currentNucleus.outputValue.magnitude); - else - EditorGUILayout.LabelField(" "); - - if (this.currentNucleus.synapses.Count > 0) { - Synapse[] synapses = this.currentNucleus.synapses.ToArray(); - foreach (Synapse synapse in synapses) { - if (synapse.nucleus != null) { - EditorGUILayout.Space(); - - EditorGUI.BeginDisabledGroup(synapse.nucleus.isSleeping); - if (Application.isPlaying) - EditorGUILayout.FloatField(synapse.nucleus.name, synapse.nucleus.outputValue.magnitude * synapse.weight); - else { - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.LabelField(synapse.nucleus.name); - // if (synapse.nucleus is Perceptoid perceptoid) { - // if (perceptoid.array == null || perceptoid.array.perceptei == null || perceptoid.array.perceptei.Length == 0) { - // perceptoid.array = new PercepteiArray(perceptoid); - // } - // EditorGUILayout.IntField(perceptoid.array.perceptei.Length); - // if (GUILayout.Button("Add")) - // perceptoid.array.AddPerceptoid(); - // } - if (GUILayout.Button("Disconnect")) - synapse.nucleus.RemoveReceiver(this.currentNucleus); - EditorGUILayout.EndHorizontal(); - } - - EditorGUI.indentLevel++; - synapse.weight = EditorGUILayout.FloatField("Weight", synapse.weight); - EditorGUI.indentLevel--; - EditorGUI.EndDisabledGroup(); - } - } - } - - EditorGUILayout.Space(); - - ConnectNucleus(this.currentNucleus); - if (GUILayout.Button("Add Input Neuron")) - AddInputNeuron(this.currentNucleus); - if (GUILayout.Button("Add Input Perceptoid")) - AddPerceptoid(this.currentNucleus); - - EditorGUILayout.Space(); - - if (GUILayout.Button("Delete this neuron")) - DeleteNeuron(this.currentNucleus); - - //DisconnectNucleus(this.currentNucleus); - - if (this.gameObject != null) { - Vector3 worldVector = this.gameObject.transform.TransformVector(this.currentNucleus.outputValue); - Debug.DrawRay(this.gameObject.transform.position, worldVector, Color.yellow); - } - }); - - inspectorContainer.Add(container); - } - - protected virtual void AddInputNeuron(Nucleus nucleus) { - Neuroid newNeuroid = new(this.brain, "New neuron"); - newNeuroid.AddReceiver(nucleus); - this.currentNucleus = newNeuroid; - BuildLayers(); - } - - protected virtual void DeleteNeuron(Nucleus nucleus) { - if (nucleus == null) - return; - if (nucleus.brain != null) - this.currentNucleus = nucleus.brain.root; - foreach (Receiver receiver in nucleus.receivers) { - if (receiver.nucleus != null) { - this.currentNucleus = receiver.nucleus; - break; - } - } - Nucleus.Delete(nucleus); - BuildLayers(); - } - - protected virtual void AddPerceptoid(Nucleus nucleus) { - Perceptoid newPerceptoid = new(this.brain, 0, "New Perceptoid"); - newPerceptoid.AddReceiver(nucleus); - this.currentNucleus = newPerceptoid; - BuildLayers(); - } - - protected virtual void ConnectNucleus(Nucleus nucleus) { - if (this.currentNucleus.brain == null) - return; - - IEnumerable synapseNuclei = this.currentNucleus.synapses.Select(synapse => synapse.nucleus.name); - IEnumerable perceptei = this.currentNucleus.brain.perceptei.Select(i => i.name).Except(synapseNuclei); - IEnumerable nuclei = this.currentNucleus.brain.nuclei.Select(i => i.name).Except(synapseNuclei); - string[] names = perceptei.Concat(nuclei).ToArray(); - int selectedIndex = -1; - selectedIndex = EditorGUILayout.Popup("Connect to", selectedIndex, names); - if (selectedIndex >= 0) { - if (selectedIndex < perceptei.Count()) { - Nucleus n = this.currentNucleus.brain.perceptei[selectedIndex]; - n.AddReceiver(this.currentNucleus); - } - else { - Nucleus n = this.currentNucleus.brain.nuclei[selectedIndex - perceptei.Count()]; - n.AddReceiver(this.currentNucleus); - } - } - } - - protected virtual void DisconnectNucleus(Nucleus nucleus) { - if (this.currentNucleus.brain == null) - return; - string[] names = this.currentNucleus.synapses.Select(synapse => synapse.nucleus.name).ToArray(); - int selectedIndex = -1; - selectedIndex = EditorGUILayout.Popup("Disconnect from", selectedIndex, names); - if (selectedIndex >= 0 && selectedIndex < this.currentNucleus.brain.perceptei.Count) { - Synapse synapse = this.currentNucleus.synapses[selectedIndex]; - synapse.nucleus.RemoveReceiver(this.currentNucleus); - } - } - } - - #endregion Start - - #region Update - - private void UpdateLayout(float containerWidth) { - if (containerWidth > 700f) { - mainContainer.style.flexDirection = FlexDirection.Row; - inspectorContainer.style.width = 400; // fixed sidebar width - inspectorContainer.style.flexGrow = 0; - } - else { - mainContainer.style.flexDirection = FlexDirection.Column; - inspectorContainer.style.width = Length.Percent(100); // full width below - inspectorContainer.style.flexDirection = FlexDirection.Column; - inspectorContainer.style.flexGrow = 1; // can set 0 or keep as needed - } - } - - #endregion Update -} - -public class GraphNodeWrapper : ScriptableObject { - // expose fields that map to GraphNode - public string title; - public Vector2 position; - Nucleus node; - NanoBrain graph; // needed to write back and mark dirty - - public GraphNodeWrapper Init(Nucleus node, NanoBrain graphAsset) { - this.node = node; - this.graph = graphAsset; - this.title = " A " + node.name; - //position = node.position; - return this; - } - void OnValidate() { - if (node != null) { - node.name = title; - //node.position = position; -#if UNITY_EDITOR - if (graph != null) - UnityEditor.EditorUtility.SetDirty(graph); -#endif - } - } +using System.Collections.Generic; +using System.Linq; +using UnityEditor; + +using UnityEngine; +using UnityEngine.UIElements; + +[CustomEditor(typeof(NanoBrain))] +public class NanoBrainInspector : Editor { + protected static VisualElement mainContainer; + protected static VisualElement inspectorContainer; + + protected bool breakOnWake = false; + + #region Start + + public override VisualElement CreateInspectorGUI() { + NanoBrain brain = target as NanoBrain; + + serializedObject.Update(); + + VisualElement root = new(); + //root.style.flexDirection = FlexDirection.Row; // side-by-side layout + //root.style.flexGrow = 1; + //root.style.minHeight = 600; + root.style.paddingLeft = 0; + root.style.paddingRight = 0; + root.style.paddingTop = 0; + root.style.paddingBottom = 0; + + root.styleSheets.Add(Resources.Load("GraphStyles")); + + mainContainer = new() { + // name = "main", + style = { + // flexDirection = FlexDirection.Row, + // flexGrow = 1, + height = 450, + } + }; + GraphView graph = new(); + graph.style.flexGrow = 1; + + inspectorContainer = new VisualElement { + // name = "inspector" + }; + + mainContainer.Add(graph); + mainContainer.Add(inspectorContainer); + root.Add(mainContainer); + + // Run once for initial state (use resolved style width if available) + float initialWidth = root.layout.width > 0 ? root.layout.width : root.contentRect.width; + UpdateLayout(initialWidth); + + // React to size changes of root (or parent if appropriate) + root.RegisterCallback(evt => { + UpdateLayout(evt.newRect.width); + }); + + if (brain != null) + graph.SetGraph(null, brain, brain.root, inspectorContainer); + else + Debug.LogWarning(" No brain!"); + + serializedObject.ApplyModifiedProperties(); + return root; + } + + public class GraphView : VisualElement { + NanoBrain brain; + SerializedObject serializedBrain; + Nucleus currentNucleus; + GameObject gameObject; + private List layers = new(); + private readonly Dictionary neuroidPositions = new(); + + Vector2 pan = Vector2.zero; + //float zoom = 1f; + bool draggingCanvas = false; + Vector2 lastMouse; + GraphNodeWrapper currentWrapper; + + public GraphView() { + name = "content"; + style.flexGrow = 1; + + IMGUIContainer imguiContainer = new(OnIMGUI); + imguiContainer.style.position = Position.Absolute; + imguiContainer.style.left = 0; imguiContainer.style.top = 0; + imguiContainer.style.right = 0; imguiContainer.style.bottom = 0; + imguiContainer.pickingMode = PickingMode.Position; + imguiContainer.focusable = true; + Add(imguiContainer); + + //RegisterCallback(OnWheel); + RegisterCallback(OnMouseDown); + RegisterCallback(OnMouseMove); + RegisterCallback(OnMouseUp); + } + + public void SetGraph(GameObject gameObject, NanoBrain brain, Nucleus nucleus, VisualElement inspectorContainer) { + this.gameObject = gameObject; + this.brain = brain; + if (Application.isPlaying == false) + this.serializedBrain = new SerializedObject(brain); + this.currentNucleus = nucleus; + Rebuild(inspectorContainer); + } + + void Rebuild(VisualElement inspectorContainer) { + BuildLayers(); + + if (this.currentNucleus == null) { + inspectorContainer.Clear(); + return; + } + + if (currentWrapper != null) + DestroyImmediate(currentWrapper); + currentWrapper = CreateInstance().Init(this.currentNucleus, brain); + DrawInspector(inspectorContainer); + } + + private void BuildLayers() { + // A temporary list to track what's been added to layers + this.layers = new(); + int layerIx = 0; + + Nucleus selectedNucleus = this.currentNucleus; + if (selectedNucleus == null) + return; + NeuroidLayer currentLayer = new() { ix = layerIx }; + + if (selectedNucleus.receivers != null) { + foreach (Receiver receiver in selectedNucleus.receivers) { + Nucleus outputNeuroid = receiver.nucleus; + if (outputNeuroid != null) { + AddToLayer(currentLayer, outputNeuroid); + // Debug.Log($"layer {layerIx} nucleus {outputNeuroid.name}"); + } + } + } + if (currentLayer.neuroids.Count > 0) { + this.layers.Add(currentLayer); + layerIx++; + currentLayer = new() { ix = layerIx }; + } + + AddToLayer(currentLayer, selectedNucleus); + this.layers.Add(currentLayer); + // Debug.Log($"layer {layerIx} nucleus {selectedNucleus.name}"); + + layerIx++; + currentLayer = new() { ix = layerIx }; + + if (selectedNucleus.synapses != null) { + foreach (Synapse synapse in selectedNucleus.synapses) { + Nucleus input = synapse.nucleus; + AddToLayer(currentLayer, input); + // Debug.Log($"layer {layerIx} nucleus {input.name}"); + } + } + if (currentLayer.neuroids.Count > 0) { + this.layers.Add(currentLayer); + } + } + + private void AddToLayer(NeuroidLayer layer, Nucleus nucleus) { + if (nucleus == null) + return; + layer.neuroids.Add(nucleus); + nucleus.layerIx = layer.ix; + // Store its position + Vector2Int neuroidPosition = new(layer.ix, layer.neuroids.Count - 1); + neuroidPositions[nucleus] = neuroidPosition; + + } + + void OnMouseDown(MouseDownEvent e) { + if (e.button == 2) { draggingCanvas = true; lastMouse = e.mousePosition; e.StopPropagation(); } + } + void OnMouseMove(MouseMoveEvent e) { + if (draggingCanvas) { + var delta = e.mousePosition - lastMouse; + pan += delta; + //content.style.left = pan.x; + //content.style.top = pan.y; + lastMouse = e.mousePosition; + } + } + void OnMouseUp(MouseUpEvent e) { if (e.button == 2) draggingCanvas = false; } + + void OnIMGUI() { + if (currentNucleus == null) + return; + + if (Application.isPlaying == false) + serializedBrain.Update(); + + Handles.BeginGUI(); + DrawGraph(); + Handles.EndGUI(); + + } + + private void DrawGraph() { + float size = 20; + Vector3 position = new(150, 210, 0); + + DrawReceivers(this.currentNucleus, position, size); + DrawSynapses(this.currentNucleus, position, size); + + // Draw selected Nucleus + Handles.color = Color.white; + Handles.DrawSolidDisc(position, Vector3.forward, size + 2); + DrawNucleus(this.currentNucleus, position, this.currentNucleus.outputValue.magnitude, 20); + } + + private void DrawReceivers(Nucleus nucleus, Vector3 parentPos, float size) { + int nodeCount = nucleus.receivers.Count; + + // Determine the maximum value in this layer + // This is used to 'scale' the output value colors of the nuclei + float maxValue = 0; + foreach (Receiver receiver in nucleus.receivers) { + if (receiver.nucleus is Neuroid neuroid) { + float value = neuroid.outputValue.magnitude; + if (value > maxValue) + maxValue = value; + } + } + + // Determine the spacing of the nuclei in the layer + float spacing = 400f / nodeCount; + float margin = 10 + spacing / 2; + + int row = 0; + foreach (Receiver receiver in nucleus.receivers) { + Nucleus receiverNucleus = receiver.nucleus; + if (receiverNucleus == null) + continue; + + Vector3 pos = new(50, margin + row * spacing, 0.0f); + Handles.color = Color.white; + Handles.DrawLine(parentPos, pos); + + DrawNucleus(receiverNucleus, pos, maxValue, size); + row++; + } + } + + private void DrawSynapses(Nucleus nucleus, Vector3 parentPos, float size) { + int nodeCount = nucleus.synapses.Count; + + // Determine the maximum value in this layer + // This is used to 'scale' the output value colors of the nuclei + float maxValue = 0; + foreach (Synapse receiver in nucleus.synapses) { + if (receiver.nucleus is Neuroid neuroid) { + float value = neuroid.outputValue.magnitude; + if (value > maxValue) + maxValue = value; + } + } + + // Determine the spacing of the nuclei in the layer + float spacing = 400f / nodeCount; + float margin = 10 + spacing / 2; + + int row = 0; + List drawnArrays = new(); + foreach (Synapse synapse in nucleus.synapses) { + Vector3 pos = new(250, margin + row * spacing, 0.0f); + Handles.color = Color.white; + Handles.DrawLine(parentPos, pos); + // if (synapse.nucleus is Perceptoid perceptoid && perceptoid.array != null) { + // // if (drawnArrays.Contains(perceptoid.array)) + // // // We already drawn this array + // // continue; + + // drawnArrays.Add(perceptoid.array); + // DrawArray(perceptoid.array, pos, size); + // } + // else { + + DrawNucleus(synapse.nucleus, pos, maxValue, size); + row++; + // } + } + } + + private void DrawNucleus(Nucleus nucleus, Vector3 position, float maxValue, float size) { + if (nucleus.isSleeping) + Handles.color = Color.darkRed; + else { + if (Application.isPlaying) { + float brightness = nucleus.outputValue.magnitude / maxValue; + Handles.color = new Color(brightness, brightness, brightness, 1f); + } + else + Handles.color = Color.black; + } + Handles.DrawSolidDisc(position, Vector3.forward, size); + + Handles.color = Color.white; + // Position the label in front of the disc + Vector3 labelPosition = position + (Vector3.forward * 0.1f); + + GUIStyle style = new(EditorStyles.label) { + alignment = TextAnchor.MiddleCenter, + normal = { textColor = Color.white }, + fontStyle = FontStyle.Bold, + }; + if (nucleus is Perceptoid perceptoid) { + if (perceptoid.array == null || perceptoid.array.perceptei == null || perceptoid.array.perceptei.Length == 0) + perceptoid.array = new PercepteiArray(perceptoid); + + if (perceptoid.array.perceptei.Length > 1) { + Handles.Label(labelPosition, perceptoid.array.perceptei.Length.ToString(), style); + } + } + + style.alignment = TextAnchor.UpperCenter; + Vector3 labelPos = position - Vector3.down * (size + 0.2f); // below disc along up axis + Handles.Label(labelPos, nucleus.name, style); + + Rect neuronRect = new(position.x - size, position.y - size, size * 2, size * 2); + int id = GUIUtility.GetControlID(FocusType.Passive); + Event e = Event.current; + EventType et = e.GetTypeForControl(id); + if (e != null && neuronRect.Contains(e.mousePosition)) { + // Process Hover + HandleMouseHover(nucleus, neuronRect); + // Process click + if (e.type == EventType.MouseDown && e.button == 0) { + // Consume the event so the scene doesn't also handle it + e.Use(); + HandleClicked(nucleus); + } + } + } + + private void DrawArray(PercepteiArray array, Vector3 position, float size) { + Vector3 offset = new(size / 4, size / 4, 0); + Handles.color = Color.black; + Handles.DrawSolidDisc(position, Vector3.forward, size); + + GUIStyle style = new(EditorStyles.label) { + alignment = TextAnchor.UpperCenter, + normal = { textColor = Color.white }, + fontStyle = FontStyle.Bold + }; + Handles.Label(position, array.perceptei.Length.ToString(), style); + Vector3 labelPos = position - Vector3.down * (size + 0.2f); // below disc along up axis + Handles.Label(labelPos, array.name, style); + + // To do: add HandleClick (see above) to expand the array + } + + private void HandleMouseHover(Nucleus nucleus, Rect rect) { + GUIContent tooltip; + if (nucleus is Perceptoid perceptoid) { + if (perceptoid.receptor != null) { + tooltip = new( + $"{perceptoid.name}" + + $"\nType {perceptoid.receptor.thingType}" + + $" Thing {perceptoid.thingId}" + + $"\nValue: {nucleus.outputValue}"); + } + else { + tooltip = new( + $"{perceptoid.name}" + + $"\nThing {perceptoid.thingId}" + + $"\nValue: {nucleus.outputValue}"); + } + } + else { + tooltip = new( + $"{nucleus.name}" + + $"\nsynapse count {nucleus.synapses.Count}" + + $"\nValue: {nucleus.outputValue}"); + } + + Vector2 mousePosition = Event.current.mousePosition; + + // Display tooltip with some offset + Vector2 tooltipSize = GUI.skin.box.CalcSize(tooltip); + Rect tooltipRect = new Rect(mousePosition.x + 10, mousePosition.y + 10, tooltipSize.x, tooltipSize.y); + + GUI.Box(tooltipRect, tooltip); + } + + private void HandleClicked(Nucleus nucleus) { + this.currentNucleus = nucleus; + BuildLayers(); + } + + void DrawInspector(VisualElement inspectorContainer) { + if (inspectorContainer == null) + return; + + inspectorContainer.Clear(); + if (this.currentNucleus == null) + return; + + // create a SerializedObject wrapper so Unity inspector controls work (and Undo) + SerializedObject so = new(currentWrapper); + IMGUIContainer container = new(() => { + if (so.targetObject == null) + return; + so.Update(); + + if (this.currentNucleus == null) + return; + + this.currentNucleus.name = EditorGUILayout.TextField(this.currentNucleus.name); + if (this.currentNucleus is Perceptoid perceptoid) { + perceptoid.receptor.thingType = EditorGUILayout.IntField("Thing Type", perceptoid.receptor.thingType); + + if (perceptoid.array == null || perceptoid.array.perceptei == null || perceptoid.array.perceptei.Length == 0) + perceptoid.array = new PercepteiArray(perceptoid); + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.IntField("Array size", perceptoid.array.perceptei.Length); + if (GUILayout.Button("Add")) + perceptoid.array.AddPerceptoid(); + if (GUILayout.Button("Del")) + perceptoid.array.RemovePerceptoid(); + EditorGUILayout.EndHorizontal(); + } + else if (this.currentNucleus is Neuroid neuroid) { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Activation Curve", GUILayout.Width(150)); + if (neuroid.curveMax > 0) + EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, 0, 1, neuroid.curveMax)); + else + EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, neuroid.curveMax, 1, -neuroid.curveMax)); + neuroid.curvePreset = (Neuroid.CurvePresets)EditorGUILayout.EnumPopup(neuroid.curvePreset, GUILayout.Width(100)); + EditorGUILayout.EndHorizontal(); + } + + if (Application.isPlaying) + EditorGUILayout.FloatField("Output", this.currentNucleus.outputValue.magnitude); + else + EditorGUILayout.LabelField(" "); + + if (this.currentNucleus.synapses.Count > 0) { + Synapse[] synapses = this.currentNucleus.synapses.ToArray(); + foreach (Synapse synapse in synapses) { + if (synapse.nucleus != null) { + EditorGUILayout.Space(); + + EditorGUI.BeginDisabledGroup(synapse.nucleus.isSleeping); + if (Application.isPlaying) + EditorGUILayout.FloatField(synapse.nucleus.name, synapse.nucleus.outputValue.magnitude * synapse.weight); + else { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField(synapse.nucleus.name); + // if (synapse.nucleus is Perceptoid perceptoid) { + // if (perceptoid.array == null || perceptoid.array.perceptei == null || perceptoid.array.perceptei.Length == 0) { + // perceptoid.array = new PercepteiArray(perceptoid); + // } + // EditorGUILayout.IntField(perceptoid.array.perceptei.Length); + // if (GUILayout.Button("Add")) + // perceptoid.array.AddPerceptoid(); + // } + if (GUILayout.Button("Disconnect")) + synapse.nucleus.RemoveReceiver(this.currentNucleus); + EditorGUILayout.EndHorizontal(); + } + + EditorGUI.indentLevel++; + synapse.weight = EditorGUILayout.FloatField("Weight", synapse.weight); + EditorGUI.indentLevel--; + EditorGUI.EndDisabledGroup(); + } + } + } + + EditorGUILayout.Space(); + + ConnectNucleus(this.currentNucleus); + if (GUILayout.Button("Add Input Neuron")) + AddInputNeuron(this.currentNucleus); + if (GUILayout.Button("Add Input Perceptoid")) + AddPerceptoid(this.currentNucleus); + + EditorGUILayout.Space(); + + if (GUILayout.Button("Delete this neuron")) + DeleteNeuron(this.currentNucleus); + + //DisconnectNucleus(this.currentNucleus); + + if (this.gameObject != null) { + Vector3 worldVector = this.gameObject.transform.TransformVector(this.currentNucleus.outputValue); + Debug.DrawRay(this.gameObject.transform.position, worldVector, Color.yellow); + } + }); + + inspectorContainer.Add(container); + } + + protected virtual void AddInputNeuron(Nucleus nucleus) { + Neuroid newNeuroid = new(this.brain, "New neuron"); + newNeuroid.AddReceiver(nucleus); + this.currentNucleus = newNeuroid; + BuildLayers(); + } + + protected virtual void DeleteNeuron(Nucleus nucleus) { + if (nucleus == null) + return; + if (nucleus.brain != null) + this.currentNucleus = nucleus.brain.root; + foreach (Receiver receiver in nucleus.receivers) { + if (receiver.nucleus != null) { + this.currentNucleus = receiver.nucleus; + break; + } + } + Nucleus.Delete(nucleus); + BuildLayers(); + } + + protected virtual void AddPerceptoid(Nucleus nucleus) { + Perceptoid newPerceptoid = new(this.brain, 0, "New Perceptoid"); + newPerceptoid.AddReceiver(nucleus); + this.currentNucleus = newPerceptoid; + BuildLayers(); + } + + protected virtual void ConnectNucleus(Nucleus nucleus) { + if (this.currentNucleus.brain == null) + return; + + IEnumerable synapseNuclei = this.currentNucleus.synapses.Select(synapse => synapse.nucleus.name); + IEnumerable perceptei = this.currentNucleus.brain.perceptei.Select(i => i.name).Except(synapseNuclei); + IEnumerable nuclei = this.currentNucleus.brain.nuclei.Select(i => i.name).Except(synapseNuclei); + string[] names = perceptei.Concat(nuclei).ToArray(); + int selectedIndex = -1; + selectedIndex = EditorGUILayout.Popup("Connect to", selectedIndex, names); + if (selectedIndex >= 0) { + if (selectedIndex < perceptei.Count()) { + Nucleus n = this.currentNucleus.brain.perceptei[selectedIndex]; + n.AddReceiver(this.currentNucleus); + } + else { + Nucleus n = this.currentNucleus.brain.nuclei[selectedIndex - perceptei.Count()]; + n.AddReceiver(this.currentNucleus); + } + } + } + + protected virtual void DisconnectNucleus(Nucleus nucleus) { + if (this.currentNucleus.brain == null) + return; + string[] names = this.currentNucleus.synapses.Select(synapse => synapse.nucleus.name).ToArray(); + int selectedIndex = -1; + selectedIndex = EditorGUILayout.Popup("Disconnect from", selectedIndex, names); + if (selectedIndex >= 0 && selectedIndex < this.currentNucleus.brain.perceptei.Count) { + Synapse synapse = this.currentNucleus.synapses[selectedIndex]; + synapse.nucleus.RemoveReceiver(this.currentNucleus); + } + } + } + + #endregion Start + + #region Update + + private void UpdateLayout(float containerWidth) { + if (containerWidth > 600f) { + mainContainer.style.flexDirection = FlexDirection.Row; + inspectorContainer.style.width = 300; // fixed sidebar width + inspectorContainer.style.flexGrow = 0; + } + else { + mainContainer.style.flexDirection = FlexDirection.Column; + inspectorContainer.style.width = Length.Percent(100); // full width below + inspectorContainer.style.flexDirection = FlexDirection.Column; + inspectorContainer.style.flexGrow = 1; // can set 0 or keep as needed + } + } + + #endregion Update +} + +public class GraphNodeWrapper : ScriptableObject { + // expose fields that map to GraphNode + public string title; + public Vector2 position; + Nucleus node; + NanoBrain graph; // needed to write back and mark dirty + + public GraphNodeWrapper Init(Nucleus node, NanoBrain graphAsset) { + this.node = node; + this.graph = graphAsset; + this.title = " A " + node.name; + //position = node.position; + return this; + } + void OnValidate() { + if (node != null) { + node.name = title; + //node.position = position; +#if UNITY_EDITOR + if (graph != null) + UnityEditor.EditorUtility.SetDirty(graph); +#endif + } + } } \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/Resources/GraphStyles.uss b/Assets/NanoBrain/VisualEditor/Resources/GraphStyles.uss index d059194..79bafe8 100644 --- a/Assets/NanoBrain/VisualEditor/Resources/GraphStyles.uss +++ b/Assets/NanoBrain/VisualEditor/Resources/GraphStyles.uss @@ -1,15 +1,12 @@ -#main { - -} -#content { - background-color: #2b2b2b, - position: absolute; -} -#inspector { - border-left-width: 1px; - border-left-color: #000; - border-left_style: solid; - padding: 3px; -} -.node { background-color: #222; border-radius:4px; padding:6px; } -#title { unity-font-style: bold; color: white; } +#content { + background-color: #2b2b2b; +} +#inspector { + border-left-width: 1px; + border-left-color: #000; + padding: 3px; +} +#title { + -unity-font-style: bold; + color: white; + } diff --git a/ProjectSettings/GraphicsSettings.asset b/ProjectSettings/GraphicsSettings.asset index abe4fcd..02f1134 100644 --- a/ProjectSettings/GraphicsSettings.asset +++ b/ProjectSettings/GraphicsSettings.asset @@ -58,9 +58,7 @@ GraphicsSettings: m_FogKeepExp2: 1 m_AlbedoSwatchInfos: [] m_RenderPipelineGlobalSettingsMap: - UnityEngine.Rendering.Universal.UniversalRenderPipeline: {fileID: 11400000, guid: 2acc6984d25d4a508a6d7042927d3083, type: 2} - m_ShaderBuildSettings: - keywordDeclarationOverrides: [] + UnityEngine.Rendering.Universal.UniversalRenderPipeline: {fileID: 11400000, guid: 370d27fa5af5291e18529fa336759ac9, type: 2} m_LightsUseLinearIntensity: 1 m_LightsUseColorTemperature: 1 m_LogWhenShaderIsCompiled: 0 From c64ccb246c9b68f2e50bba6cf9d4b9ad0243d3f9 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Fri, 9 Jan 2026 17:08:11 +0100 Subject: [PATCH 060/179] Added Cluster & INucleus --- Assembly-CSharp-Editor.csproj | 2 + Assembly-CSharp.csproj | 2 + Assets/NanoBrain/Cluster.cs | 85 +++ Assets/NanoBrain/Cluster.cs.meta | 2 + Assets/NanoBrain/Editor/NeuroidWindow.cs | 602 ++++++++--------- Assets/NanoBrain/INucleus.cs | 32 + Assets/NanoBrain/INucleus.cs.meta | 2 + Assets/NanoBrain/Neuroid.cs | 224 +++---- Assets/NanoBrain/Nucleus.cs | 608 ++++++++--------- Assets/NanoBrain/Perceptoid.cs | 201 +++--- Assets/NanoBrain/Receptor.cs | 162 ++--- .../VisualEditor/Editor/BrainPickerWindow.cs | 72 ++ .../Editor/BrainPickerWindow.cs.meta | 2 + .../VisualEditor/Editor/ClusterInspector.cs | 633 ++++++++++++++++++ .../Editor/ClusterInspector.cs.meta | 2 + .../Editor/NanoBrainComponent_Editor.cs | 204 +++--- .../VisualEditor/Editor/NanoBrainInspector.cs | 102 +-- Assets/NanoBrain/VisualEditor/NanoBrain.cs | 185 ++--- .../VisualEditor/NanoBrainComponent.cs | 64 +- Assets/Scenes/Boids/New Cluster 1.asset | 20 + ...ty.asset.meta => New Cluster 1.asset.meta} | 2 +- Assets/Scenes/Boids/New Cluster.asset | 15 + Assets/Scenes/Boids/New Cluster.asset.meta | 8 + .../{Identity.asset => New Nano Brain.asset} | 6 +- Assets/Scenes/Boids/New Nano Brain.asset.meta | 8 + 25 files changed, 2082 insertions(+), 1163 deletions(-) create mode 100644 Assets/NanoBrain/Cluster.cs create mode 100644 Assets/NanoBrain/Cluster.cs.meta create mode 100644 Assets/NanoBrain/INucleus.cs create mode 100644 Assets/NanoBrain/INucleus.cs.meta create mode 100644 Assets/NanoBrain/VisualEditor/Editor/BrainPickerWindow.cs create mode 100644 Assets/NanoBrain/VisualEditor/Editor/BrainPickerWindow.cs.meta create mode 100644 Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs create mode 100644 Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs.meta create mode 100644 Assets/Scenes/Boids/New Cluster 1.asset rename Assets/Scenes/Boids/{Identity.asset.meta => New Cluster 1.asset.meta} (79%) create mode 100644 Assets/Scenes/Boids/New Cluster.asset create mode 100644 Assets/Scenes/Boids/New Cluster.asset.meta rename Assets/Scenes/Boids/{Identity.asset => New Nano Brain.asset} (94%) create mode 100644 Assets/Scenes/Boids/New Nano Brain.asset.meta diff --git a/Assembly-CSharp-Editor.csproj b/Assembly-CSharp-Editor.csproj index 369d5d7..94f9e7e 100644 --- a/Assembly-CSharp-Editor.csproj +++ b/Assembly-CSharp-Editor.csproj @@ -51,8 +51,10 @@ + + diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index 49d2ce0..b49e8b7 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -71,12 +71,14 @@ + + diff --git a/Assets/NanoBrain/Cluster.cs b/Assets/NanoBrain/Cluster.cs new file mode 100644 index 0000000..991c44e --- /dev/null +++ b/Assets/NanoBrain/Cluster.cs @@ -0,0 +1,85 @@ +using System.Collections.Generic; +using UnityEngine; + +[CreateAssetMenu(menuName = "Passer/Cluster")] +public class Cluster : ScriptableObject, INucleus { + + private string _name; + public string name { + get { return _name; } + set { _name = value; } + } + + public Cluster cluster => this; + + public List nuclei = new(); + + public Nucleus output => this.nuclei[0]; + + private readonly List _synapses = new(); // = inputs, compare receptors in NanoBrain + public List synapses => _synapses; + + private void OnEnable() { + nuclei ??= new List(); + if (nuclei.Count == 0) + new Neuroid(this, "Output"); // Every cluster should have at least 1 neuroid + } + + public void AddReceiver(INucleus receiver) { + output.AddReceiver(receiver); + } + + public void RemoveReceiver(INucleus receiver) { + output.RemoveReceiver(receiver); + } + public List receivers { + get => output.receivers; + } + + public void GarbageCollection() { + HashSet visitedNuclei = new(); + MarkNuclei(visitedNuclei, this.output); + //Debug.Log($"Garbage collection found {visitedNuclei.Count} Nuclei"); + this.nuclei.RemoveAll(nucleus => visitedNuclei.Contains(nucleus) == false); + //this.perceptei.RemoveAll(perceptoid => visitedNuclei.Contains(perceptoid) == false); + } + + public void MarkNuclei(HashSet visitedNuclei, INucleus nucleus) { + if (nucleus is null) + return; + + visitedNuclei.Add(nucleus); + if (nucleus.synapses != null) { + HashSet visitedSynapses = new(); + foreach (Synapse synapse in nucleus.synapses) { + if (synapse != null && synapse.nucleus != null) { + visitedSynapses.Add(synapse); + MarkNuclei(visitedNuclei, synapse.nucleus); + } + } + nucleus.synapses.RemoveAll(synapse => visitedSynapses.Contains(synapse) == false); + } + if (nucleus.receivers != null) { + HashSet visitedReceivers = new(); + foreach (Receiver receiver in nucleus.receivers) { + if (receiver != null && receiver.nucleus != null) { + visitedReceivers.Add(receiver); + visitedNuclei.Add(receiver.nucleus); + } + } + nucleus.receivers.RemoveAll(receiver => visitedReceivers.Contains(receiver) == false); + } + } + + #region Dynamics + + public Vector3 outputValue => this.output.outputValue; + public bool isSleeping => this.outputValue.sqrMagnitude == 0; + + public void UpdateState() { + // Don't know if this is right + this.output.UpdateState(); + } + + #endregion Dynamics +} \ No newline at end of file diff --git a/Assets/NanoBrain/Cluster.cs.meta b/Assets/NanoBrain/Cluster.cs.meta new file mode 100644 index 0000000..ee35e0b --- /dev/null +++ b/Assets/NanoBrain/Cluster.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 60a957541c24c57e78018c202ebb1d9b \ No newline at end of file diff --git a/Assets/NanoBrain/Editor/NeuroidWindow.cs b/Assets/NanoBrain/Editor/NeuroidWindow.cs index 72494b8..187df35 100644 --- a/Assets/NanoBrain/Editor/NeuroidWindow.cs +++ b/Assets/NanoBrain/Editor/NeuroidWindow.cs @@ -1,300 +1,302 @@ -using UnityEditor; -using UnityEngine; -using System.Linq; -using System.Collections.Generic; - -public class NeuroidLayer { - public int ix = 0; - public List neuroids = new(); -} - -public class GraphEditorWindow : EditorWindow { - private Nucleus currentNucleus; - private List allNeuroids; - private Dictionary neuroidPositions = new(); - - private List layers = new(); - - private void OnEnable() { - EditorApplication.update += EditorUpdate; - Selection.selectionChanged += OnSelectionChange; - SelectNeuron(); - } - - private void AddToLayer(NeuroidLayer layer, Nucleus nucleus) { - layer.neuroids.Add(nucleus); - nucleus.layerIx = layer.ix; - // Store its position - Vector2Int neuroidPosition = new(layer.ix, layer.neuroids.Count - 1); - neuroidPositions[nucleus] = neuroidPosition; - - } - - private void BuildLayers() { - // A temporary list to track what's been added to layers - this.layers = new(); - int layerIx = 0; - - Nucleus selectedNucleus = this.currentNucleus; - if (selectedNucleus == null) - return; - NeuroidLayer currentLayer = new() { ix = layerIx }; - - //foreach (Nucleus outputNeuroid in selectedNucleus.receivers) { - foreach (Receiver receiver in selectedNucleus.receivers) { - Nucleus outputNeuroid = receiver.nucleus; - if (outputNeuroid != null) { - AddToLayer(currentLayer, outputNeuroid); - Debug.Log($"layer {layerIx} nucleus {outputNeuroid.name}"); - } - } - if (currentLayer.neuroids.Count > 0) { - this.layers.Add(currentLayer); - layerIx++; - currentLayer = new() { ix = layerIx }; - } - - AddToLayer(currentLayer, selectedNucleus); - this.layers.Add(currentLayer); - Debug.Log($"layer {layerIx} nucleus {selectedNucleus.name}"); - - layerIx++; - currentLayer = new() { ix = layerIx }; - - int six = 0; - // foreach (Synapse synapse in selectedNucleus.synapses.Values) { - // Debug.Log($"Synapse {six}"); - // Nucleus input = synapse.neuroid; - //foreach ((Nucleus input, Synapse synapse) in selectedNucleus.synapses) { - //foreach ((Nucleus input, float weight) in selectedNucleus.synapses) { - foreach (Synapse synapse in selectedNucleus.synapses) { - Nucleus input = synapse.nucleus; - if (input != null) { - AddToLayer(currentLayer, input); - Debug.Log($"layer {layerIx} nucleus {input.name}"); - } - six++; - } - if (currentLayer.neuroids.Count > 0) { - this.layers.Add(currentLayer); - } - } - - private void BuildLayers_old(List neuroids) { - if (neuroids == null) - return; - - // A temporary list to track what's been added to layers - this.layers = new(); - HashSet neuronVisited = new(); - int layerIx = 0; - - // While there are unvisited neuroid - while (neuroids.Any(neuroid => !neuronVisited.Contains(neuroid))) { - // Create the next layer - NeuroidLayer currentLayer = new() { ix = layerIx }; - int neuroidIx = 0; - - foreach (Neuroid neuroid in neuroids) { - // Skip neurons we already processed - if (neuronVisited.Contains(neuroid)) - continue; - - // if (neuroid.IsStale()) { - // Debug.Log($"neuron {neuroid.name} is stale {neuroid.stale}"); - // neuronVisited.Add(neuroid); - // continue; - // } - - // If the output neuroid is visited - // Note: this does not yet work for multiple outputs yet (see the use of First()) - // if (neuroid.receivers.Count == 0 // make sure the root neuroids are processed directly - // || (neuronVisited.Contains(neuroid.receivers.First()) && neuroid.receivers.First().layerIx == layerIx - 1)) { - if (neuroid.receivers.Count == 0 // make sure the root neuroids are processed directly - || (neuronVisited.Contains(neuroid.receivers.First().nucleus) && neuroid.receivers.First().nucleus.layerIx == layerIx - 1)) { - // Add it to the next layer - currentLayer.neuroids.Add(neuroid); - neuroid.layerIx = layerIx; - // Register it as visited - neuronVisited.Add(neuroid); - // Store its position - Vector2Int neuroidPosition = new(layerIx, neuroidIx); - neuroidPositions[neuroid] = neuroidPosition; - neuroidIx++; - Debug.Log($"Layer {layerIx} neuron {neuroidIx} name {neuroid.name}"); - } - } - - if (currentLayer.neuroids.Count > 0) { - this.layers.Add(currentLayer); - layerIx++; - } - } - } - - private void OnDisable() { - EditorApplication.update -= EditorUpdate; - Selection.selectionChanged -= OnSelectionChange; - } - - private void OnSelectionChange() { - SelectNeuron(); - Repaint(); - } - - private void EditorUpdate() { - if (EditorApplication.isPlaying) - Repaint(); - } - - private void OnGUI() { - GUILayout.Label("Graph Visualizer", EditorStyles.boldLabel); - - DrawGraph(); - } - - private void DrawGraph() { - if (currentNucleus == null) - return; - - foreach (NeuroidLayer layer in layers) - DrawLayer(layer); - } - - private void DrawLayer(NeuroidLayer layer) { - int column = layer.ix * 100; - int nodeCount = layer.neuroids.Count; - float maxValue = 0; - foreach (Nucleus nucleus in layer.neuroids) { - if (nucleus is Neuroid neuroid) { - float value = neuroid.outputValue.magnitude; - if (value > maxValue) - maxValue = value; - } - } - float spacing = 400f / nodeCount; - float margin = 100 + spacing / 2; - foreach (Nucleus layerNucleus in layer.neuroids) { - if (layerNucleus is Neuroid layerNeuroid) { - Vector2Int layerNeuroidPos = this.neuroidPositions[layerNeuroid]; - Vector3 parentPos = new(100 + layerNeuroidPos.x * 100, margin + layerNeuroidPos.y * spacing, 0.1f); - - int i = 0; - float inputSpacing = 400f / layerNeuroid.synapses.Count; - float inputMargin = 100 + inputSpacing / 2; - // foreach (Synapse synapse in layerNeuroid.synapses.Values) { - // if (synapse.neuroid != null) { - // if (this.neuroidPositions.ContainsKey(synapse.neuroid)) { - - // Vector2Int inputNeuroidPos = this.neuroidPositions[synapse.neuroid]; - //foreach ((Nucleus neuroid, Synapse synapse) in layerNeuroid.synapses) { - //foreach ((Nucleus neuroid, float weight) in layerNeuroid.synapses) { - foreach (Synapse synapse in layerNeuroid.synapses) { - Nucleus neuroid = synapse.nucleus; - float weight = synapse.weight; - if (neuroid != null) { - if (this.neuroidPositions.ContainsKey(neuroid)) { - Vector2Int inputNeuroidPos = this.neuroidPositions[neuroid]; - if (inputNeuroidPos.x == layerNeuroidPos.x + 1) { - Vector3 pos = new(100 + inputNeuroidPos.x * 100, inputMargin + inputNeuroidPos.y * inputSpacing, 0.0f); - - //float brightness = synapse.weight / 10.0f; - float brightness = weight / 10.0f; - Handles.color = new Color(brightness, brightness, brightness); - Handles.DrawLine(parentPos, pos); - } - } - } - } - - float size = 20; - if (layerNeuroid.isSleeping) - Handles.color = Color.black; - else { - float brightness = layerNeuroid.outputValue.magnitude / maxValue; - Handles.color = new Color(brightness, brightness, brightness); - } - Handles.DrawSolidDisc(parentPos, Vector3.forward, size); - Vector3 labelPos = parentPos - Vector3.down * (size + 0.2f); // below disc along up axis - GUIStyle style = new GUIStyle(EditorStyles.label) { - alignment = TextAnchor.UpperCenter, - normal = { textColor = Color.white }, - fontStyle = FontStyle.Bold - }; - Handles.Label(labelPos, layerNeuroid.name, style); - - Rect neuronRect = new(parentPos.x - size, parentPos.y - size, size * 2, size * 2); - Event e = Event.current; - if (e != null && neuronRect.Contains(e.mousePosition)) { - HandleMouseHover(layerNeuroid, neuronRect); - // Process click - if (e.type == EventType.MouseDown && e.button == 0) { - // Consume the event so the scene doesn't also handle it - e.Use(); - HandleDiscClicked(layerNeuroid); - } - } - i++; - } - } - } - - private void HandleMouseHover(Neuroid neuroid, Rect rect) { - GUIContent tooltip; - // if (neuroid is SensoryNeuroid sensoryNeuroid) { - // tooltip = new( - // $"{sensoryNeuroid.name}" + - // $"\nThing {sensoryNeuroid.receptor.thingType}" + - // $"\nValue: {neuroid.outputValue}"); - // } - // else { - tooltip = new( - $"{neuroid.name}" + - $"\nsynapse count {neuroid.synapses.Count}" + - $"\nValue: {neuroid.outputValue}"); - // } - - Vector2 mousePosition = Event.current.mousePosition; - - // Display tooltip with some offset - Vector2 tooltipSize = GUI.skin.box.CalcSize(tooltip); - Rect tooltipRect = new Rect(mousePosition.x + 10, mousePosition.y + 10, tooltipSize.x, tooltipSize.y); - - GUI.Box(tooltipRect, tooltip); - } - - private void HandleDiscClicked(Nucleus nucleus) { - this.currentNucleus = nucleus; - BuildLayers(); - } - - // Update node colors based on selected GameObjects - private void SelectNeuron() { - GameObject[] selectedObjects = Selection.gameObjects; - if (selectedObjects.Length == 0) - return; - - GameObject selectedObject = selectedObjects[0]; - Boid boid = selectedObject.GetComponent(); - if (boid == null) - return; - - // Nucleus neuroid = boid.behaviour; - // this.currentNucleus = neuroid; - // if (neuroid == null) - // this.allNeuroids = new(); - // else - // this.allNeuroids = neuroid.brain.neuroids; - - - // Debug.Log($"Neuroncount = {this.allNeuroids.Count}"); - // BuildLayers(); - // Debug.Log($"Layercount = {this.layers.Count}"); - - } - - [MenuItem("Window/Neuroid Visualizer")] - public static void ShowWindow() { - GetWindow("Neuroid Visualizer"); - } -} +/* +using UnityEditor; +using UnityEngine; +using System.Linq; +using System.Collections.Generic; + +public class NeuroidLayer { + public int ix = 0; + public List neuroids = new(); +} + +public class GraphEditorWindow : EditorWindow { + private Nucleus currentNucleus; + private List allNeuroids; + private Dictionary neuroidPositions = new(); + + private List layers = new(); + + private void OnEnable() { + EditorApplication.update += EditorUpdate; + Selection.selectionChanged += OnSelectionChange; + SelectNeuron(); + } + + private void AddToLayer(NeuroidLayer layer, Nucleus nucleus) { + layer.neuroids.Add(nucleus); + nucleus.layerIx = layer.ix; + // Store its position + Vector2Int neuroidPosition = new(layer.ix, layer.neuroids.Count - 1); + neuroidPositions[nucleus] = neuroidPosition; + + } + + private void BuildLayers() { + // A temporary list to track what's been added to layers + this.layers = new(); + int layerIx = 0; + + Nucleus selectedNucleus = this.currentNucleus; + if (selectedNucleus == null) + return; + NeuroidLayer currentLayer = new() { ix = layerIx }; + + //foreach (Nucleus outputNeuroid in selectedNucleus.receivers) { + foreach (Receiver receiver in selectedNucleus.receivers) { + Nucleus outputNeuroid = receiver.nucleus; + if (outputNeuroid != null) { + AddToLayer(currentLayer, outputNeuroid); + Debug.Log($"layer {layerIx} nucleus {outputNeuroid.name}"); + } + } + if (currentLayer.neuroids.Count > 0) { + this.layers.Add(currentLayer); + layerIx++; + currentLayer = new() { ix = layerIx }; + } + + AddToLayer(currentLayer, selectedNucleus); + this.layers.Add(currentLayer); + Debug.Log($"layer {layerIx} nucleus {selectedNucleus.name}"); + + layerIx++; + currentLayer = new() { ix = layerIx }; + + int six = 0; + // foreach (Synapse synapse in selectedNucleus.synapses.Values) { + // Debug.Log($"Synapse {six}"); + // Nucleus input = synapse.neuroid; + //foreach ((Nucleus input, Synapse synapse) in selectedNucleus.synapses) { + //foreach ((Nucleus input, float weight) in selectedNucleus.synapses) { + foreach (Synapse synapse in selectedNucleus.synapses) { + Nucleus input = synapse.nucleus; + if (input != null) { + AddToLayer(currentLayer, input); + Debug.Log($"layer {layerIx} nucleus {input.name}"); + } + six++; + } + if (currentLayer.neuroids.Count > 0) { + this.layers.Add(currentLayer); + } + } + + private void BuildLayers_old(List neuroids) { + if (neuroids == null) + return; + + // A temporary list to track what's been added to layers + this.layers = new(); + HashSet neuronVisited = new(); + int layerIx = 0; + + // While there are unvisited neuroid + while (neuroids.Any(neuroid => !neuronVisited.Contains(neuroid))) { + // Create the next layer + NeuroidLayer currentLayer = new() { ix = layerIx }; + int neuroidIx = 0; + + foreach (Neuroid neuroid in neuroids) { + // Skip neurons we already processed + if (neuronVisited.Contains(neuroid)) + continue; + + // if (neuroid.IsStale()) { + // Debug.Log($"neuron {neuroid.name} is stale {neuroid.stale}"); + // neuronVisited.Add(neuroid); + // continue; + // } + + // If the output neuroid is visited + // Note: this does not yet work for multiple outputs yet (see the use of First()) + // if (neuroid.receivers.Count == 0 // make sure the root neuroids are processed directly + // || (neuronVisited.Contains(neuroid.receivers.First()) && neuroid.receivers.First().layerIx == layerIx - 1)) { + if (neuroid.receivers.Count == 0 // make sure the root neuroids are processed directly + || (neuronVisited.Contains(neuroid.receivers.First().nucleus) && neuroid.receivers.First().nucleus.layerIx == layerIx - 1)) { + // Add it to the next layer + currentLayer.neuroids.Add(neuroid); + neuroid.layerIx = layerIx; + // Register it as visited + neuronVisited.Add(neuroid); + // Store its position + Vector2Int neuroidPosition = new(layerIx, neuroidIx); + neuroidPositions[neuroid] = neuroidPosition; + neuroidIx++; + Debug.Log($"Layer {layerIx} neuron {neuroidIx} name {neuroid.name}"); + } + } + + if (currentLayer.neuroids.Count > 0) { + this.layers.Add(currentLayer); + layerIx++; + } + } + } + + private void OnDisable() { + EditorApplication.update -= EditorUpdate; + Selection.selectionChanged -= OnSelectionChange; + } + + private void OnSelectionChange() { + SelectNeuron(); + Repaint(); + } + + private void EditorUpdate() { + if (EditorApplication.isPlaying) + Repaint(); + } + + private void OnGUI() { + GUILayout.Label("Graph Visualizer", EditorStyles.boldLabel); + + DrawGraph(); + } + + private void DrawGraph() { + if (currentNucleus == null) + return; + + foreach (NeuroidLayer layer in layers) + DrawLayer(layer); + } + + private void DrawLayer(NeuroidLayer layer) { + int column = layer.ix * 100; + int nodeCount = layer.neuroids.Count; + float maxValue = 0; + foreach (Nucleus nucleus in layer.neuroids) { + if (nucleus is Neuroid neuroid) { + float value = neuroid.outputValue.magnitude; + if (value > maxValue) + maxValue = value; + } + } + float spacing = 400f / nodeCount; + float margin = 100 + spacing / 2; + foreach (Nucleus layerNucleus in layer.neuroids) { + if (layerNucleus is Neuroid layerNeuroid) { + Vector2Int layerNeuroidPos = this.neuroidPositions[layerNeuroid]; + Vector3 parentPos = new(100 + layerNeuroidPos.x * 100, margin + layerNeuroidPos.y * spacing, 0.1f); + + int i = 0; + float inputSpacing = 400f / layerNeuroid.synapses.Count; + float inputMargin = 100 + inputSpacing / 2; + // foreach (Synapse synapse in layerNeuroid.synapses.Values) { + // if (synapse.neuroid != null) { + // if (this.neuroidPositions.ContainsKey(synapse.neuroid)) { + + // Vector2Int inputNeuroidPos = this.neuroidPositions[synapse.neuroid]; + //foreach ((Nucleus neuroid, Synapse synapse) in layerNeuroid.synapses) { + //foreach ((Nucleus neuroid, float weight) in layerNeuroid.synapses) { + foreach (Synapse synapse in layerNeuroid.synapses) { + Nucleus neuroid = synapse.nucleus; + float weight = synapse.weight; + if (neuroid != null) { + if (this.neuroidPositions.ContainsKey(neuroid)) { + Vector2Int inputNeuroidPos = this.neuroidPositions[neuroid]; + if (inputNeuroidPos.x == layerNeuroidPos.x + 1) { + Vector3 pos = new(100 + inputNeuroidPos.x * 100, inputMargin + inputNeuroidPos.y * inputSpacing, 0.0f); + + //float brightness = synapse.weight / 10.0f; + float brightness = weight / 10.0f; + Handles.color = new Color(brightness, brightness, brightness); + Handles.DrawLine(parentPos, pos); + } + } + } + } + + float size = 20; + if (layerNeuroid.isSleeping) + Handles.color = Color.black; + else { + float brightness = layerNeuroid.outputValue.magnitude / maxValue; + Handles.color = new Color(brightness, brightness, brightness); + } + Handles.DrawSolidDisc(parentPos, Vector3.forward, size); + Vector3 labelPos = parentPos - Vector3.down * (size + 0.2f); // below disc along up axis + GUIStyle style = new GUIStyle(EditorStyles.label) { + alignment = TextAnchor.UpperCenter, + normal = { textColor = Color.white }, + fontStyle = FontStyle.Bold + }; + Handles.Label(labelPos, layerNeuroid.name, style); + + Rect neuronRect = new(parentPos.x - size, parentPos.y - size, size * 2, size * 2); + Event e = Event.current; + if (e != null && neuronRect.Contains(e.mousePosition)) { + HandleMouseHover(layerNeuroid, neuronRect); + // Process click + if (e.type == EventType.MouseDown && e.button == 0) { + // Consume the event so the scene doesn't also handle it + e.Use(); + HandleDiscClicked(layerNeuroid); + } + } + i++; + } + } + } + + private void HandleMouseHover(Neuroid neuroid, Rect rect) { + GUIContent tooltip; + // if (neuroid is SensoryNeuroid sensoryNeuroid) { + // tooltip = new( + // $"{sensoryNeuroid.name}" + + // $"\nThing {sensoryNeuroid.receptor.thingType}" + + // $"\nValue: {neuroid.outputValue}"); + // } + // else { + tooltip = new( + $"{neuroid.name}" + + $"\nsynapse count {neuroid.synapses.Count}" + + $"\nValue: {neuroid.outputValue}"); + // } + + Vector2 mousePosition = Event.current.mousePosition; + + // Display tooltip with some offset + Vector2 tooltipSize = GUI.skin.box.CalcSize(tooltip); + Rect tooltipRect = new Rect(mousePosition.x + 10, mousePosition.y + 10, tooltipSize.x, tooltipSize.y); + + GUI.Box(tooltipRect, tooltip); + } + + private void HandleDiscClicked(Nucleus nucleus) { + this.currentNucleus = nucleus; + BuildLayers(); + } + + // Update node colors based on selected GameObjects + private void SelectNeuron() { + GameObject[] selectedObjects = Selection.gameObjects; + if (selectedObjects.Length == 0) + return; + + GameObject selectedObject = selectedObjects[0]; + Boid boid = selectedObject.GetComponent(); + if (boid == null) + return; + + // Nucleus neuroid = boid.behaviour; + // this.currentNucleus = neuroid; + // if (neuroid == null) + // this.allNeuroids = new(); + // else + // this.allNeuroids = neuroid.brain.neuroids; + + + // Debug.Log($"Neuroncount = {this.allNeuroids.Count}"); + // BuildLayers(); + // Debug.Log($"Layercount = {this.layers.Count}"); + + } + + [MenuItem("Window/Neuroid Visualizer")] + public static void ShowWindow() { + GetWindow("Neuroid Visualizer"); + } +} +*/ \ No newline at end of file diff --git a/Assets/NanoBrain/INucleus.cs b/Assets/NanoBrain/INucleus.cs new file mode 100644 index 0000000..757f8ef --- /dev/null +++ b/Assets/NanoBrain/INucleus.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using UnityEngine; + +public interface INucleus { + + #region static struct + + public string name { get; set; } + + // Cluster + public Cluster cluster { get; } + + // Receivers + public List receivers { get; } + public void AddReceiver(INucleus receiver); + public void RemoveReceiver(INucleus receiverNucleus); + + // Senders + public List synapses { get; } + + #endregion static struct + + #region dynamic state + + public bool isSleeping { get; } + + public Vector3 outputValue { get; } + + public void UpdateState(); + + #endregion dynamic state +} \ No newline at end of file diff --git a/Assets/NanoBrain/INucleus.cs.meta b/Assets/NanoBrain/INucleus.cs.meta new file mode 100644 index 0000000..aed95bb --- /dev/null +++ b/Assets/NanoBrain/INucleus.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 6a8a0e8965cea660abff254cab8a4723 \ No newline at end of file diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index 0f9894a..cd534e0 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -1,112 +1,112 @@ -using UnityEngine; - -[System.Serializable] -public class Neuroid : Nucleus { - public enum CurvePresets { - Linear, - Power, - Sqrt, - Reciprocal, - Custom - } - [SerializeField] - private CurvePresets _curvePreset; - public CurvePresets curvePreset { - get { return _curvePreset; } - set { - _curvePreset = value; - this.curve = GenerateCurve(); - } - } - public AnimationCurve curve; - public float curveMax = 1.0f; - - public AnimationCurve GenerateCurve() { - switch (this.curvePreset) { - case CurvePresets.Linear: - this.curveMax = 1; - return Synapse.Presets.Linear(1); - case CurvePresets.Power: - this.curveMax = 1; - return Synapse.Presets.Power(2.0f, 1); - case CurvePresets.Sqrt: - this.curveMax = 1; - return Synapse.Presets.Power(0.5f, 1); - case CurvePresets.Reciprocal: - this.curveMax = 1 / 0.01f * 1; - return Synapse.Presets.Reciprocal(1); - default: - this.curveMax = 1; - return this.curve; - } - } - - public bool average = false; - public bool inverse = false; - public float exponent = 1.0f; - - - public Neuroid(NanoBrain brain, string name) : base(name) { - this.brain = brain; - if (this.brain != null) { - this.brain.nuclei.Add(this); - } - else - Debug.LogError("No neuroid network"); - } - - public Neuroid(string name) : base(name) { } - - public void SetWeight(Neuroid input, float weight) { - this.SetWeight((Nucleus)input, weight); - } - - public void SetInput(Neuroid input) { - if (this.SynapseExists(input) == false) - this.SetWeight(input, 1.0f); - UpdateState(); - } - - public void SetInput(Neuroid input, float weight) { - this.SetWeight(input, weight); - UpdateState(); - } - - public override void UpdateState() { - Vector3 sum = Vector3.zero; - int n = 0; - - //Applying the weight factgors - foreach (Synapse synapse in this.synapses) { - sum += synapse.weight * synapse.nucleus.outputValue; - if (synapse.nucleus.outputValue.sqrMagnitude != 0) - n++; - } - if (average) - sum /= n; - - // Activation function - Vector3 result; - switch (this.curvePreset) { - case CurvePresets.Linear: - result = sum; - break; - case CurvePresets.Sqrt: - result = sum.normalized * System.MathF.Sqrt(sum.magnitude); - break; - case CurvePresets.Power: - result = sum.normalized * System.MathF.Pow(sum.magnitude, 2); - break; - case CurvePresets.Reciprocal: - result = sum.normalized * (1 / sum.magnitude); - break; - default: - float activatedValue = this.curve.Evaluate(sum.magnitude); - result = sum.normalized * activatedValue; - break; - } - UpdateResult(result); - } - -} - +using UnityEngine; + +[System.Serializable] +public class Neuroid : Nucleus { + public enum CurvePresets { + Linear, + Power, + Sqrt, + Reciprocal, + Custom + } + [SerializeField] + private CurvePresets _curvePreset; + public CurvePresets curvePreset { + get { return _curvePreset; } + set { + _curvePreset = value; + this.curve = GenerateCurve(); + } + } + public AnimationCurve curve; + public float curveMax = 1.0f; + + public AnimationCurve GenerateCurve() { + switch (this.curvePreset) { + case CurvePresets.Linear: + this.curveMax = 1; + return Synapse.Presets.Linear(1); + case CurvePresets.Power: + this.curveMax = 1; + return Synapse.Presets.Power(2.0f, 1); + case CurvePresets.Sqrt: + this.curveMax = 1; + return Synapse.Presets.Power(0.5f, 1); + case CurvePresets.Reciprocal: + this.curveMax = 1 / 0.01f * 1; + return Synapse.Presets.Reciprocal(1); + default: + this.curveMax = 1; + return this.curve; + } + } + + public bool average = false; + public bool inverse = false; + public float exponent = 1.0f; + + + public Neuroid(Cluster brain, string name) : base(name) { + this.cluster = brain; + if (this.cluster != null) { + this.cluster.nuclei.Add(this); + } + else + Debug.LogError("No neuroid network"); + } + + public Neuroid(string name) : base(name) { } + + public void SetWeight(Neuroid input, float weight) { + this.SetWeight((Nucleus)input, weight); + } + + public void SetInput(Neuroid input) { + if (this.SynapseExists(input) == false) + this.SetWeight(input, 1.0f); + UpdateState(); + } + + public void SetInput(Neuroid input, float weight) { + this.SetWeight(input, weight); + UpdateState(); + } + + public override void UpdateState() { + Vector3 sum = Vector3.zero; + int n = 0; + + //Applying the weight factgors + foreach (Synapse synapse in this.synapses) { + sum += synapse.weight * synapse.nucleus.outputValue; + if (synapse.nucleus.outputValue.sqrMagnitude != 0) + n++; + } + if (average) + sum /= n; + + // Activation function + Vector3 result; + switch (this.curvePreset) { + case CurvePresets.Linear: + result = sum; + break; + case CurvePresets.Sqrt: + result = sum.normalized * System.MathF.Sqrt(sum.magnitude); + break; + case CurvePresets.Power: + result = sum.normalized * System.MathF.Pow(sum.magnitude, 2); + break; + case CurvePresets.Reciprocal: + result = sum.normalized * (1 / sum.magnitude); + break; + default: + float activatedValue = this.curve.Evaluate(sum.magnitude); + result = sum.normalized * activatedValue; + break; + } + UpdateResult(result); + } + +} + diff --git a/Assets/NanoBrain/Nucleus.cs b/Assets/NanoBrain/Nucleus.cs index 62e4481..79c05cb 100644 --- a/Assets/NanoBrain/Nucleus.cs +++ b/Assets/NanoBrain/Nucleus.cs @@ -1,304 +1,306 @@ -using System; -using System.Collections.Generic; -using UnityEngine; -using UnityEditor; -using LinearAlgebra; - -[System.Serializable] -public class Nucleus { - - public int id; // hash code - - [SerializeField] - protected string _name; - public virtual string name { - get => _name; - set => _name = value; - } - - [SerializeField] - public List synapses = new(); - [SerializeField] - public List receivers = new(); - - #region Serialization - - [SerializeField] - protected string nucleusType; - - public virtual void Rebuild(NanoBrain brain) { - if (this.synapses != null) { - foreach (Synapse synapse in synapses) - synapse.Rebuild(brain); - } - if (this.receivers == null) - this.receivers = new(); - else { - foreach (Receiver receiver in receivers.ToArray()) { - if (receiver.Rebuild(brain) == false) { - Debug.Log("Rebuilding failed, removing receiver."); - receivers.Remove(receiver); - } - } - } - } - - public static Nucleus RebuildType(NanoBrain brain, Nucleus nucleus) { - if (string.IsNullOrEmpty(nucleus.nucleusType) == false) { - Type nucleusType = Type.GetType(nucleus.nucleusType); - if (nucleusType != null) { - object[] args = new object[] { brain, nucleus.name }; - Nucleus rebuiltNucleus = (Nucleus)Activator.CreateInstance(nucleusType, args); - rebuiltNucleus.Deserialize(nucleus); - return rebuiltNucleus; - } - } - return nucleus; - } - - public virtual void Deserialize(Nucleus nucleus) { } - - #endregion Serialization - - #region Runtime state (not serialized) - - public NanoBrain brain { get; set; } - - private Vector3 _outputValue; - public Vector3 outputValue - { - get { return _outputValue; } - set { - this.stale = 0; - this.isSleeping = false; - _outputValue = value; - } - } - - [System.NonSerialized] - private int stale = 1000; - - public bool isSleeping = false; - public void IncreaseAge() { - this.stale++; - this.isSleeping = this.stale > 2; - if (isSleeping) - _outputValue = Vector3.zero; - } - [System.NonSerialized] - public int layerIx; - - #endregion Runtime state - - public Nucleus(string name) { - this._name = name; - this.id = this.GetHashCode(); - } - - public virtual void AddReceiver(Nucleus receiver) { - this.receivers.Add(new Receiver(receiver)); - receiver.SetWeight(this, 1.0f); - } - - public void RemoveReceiver(Nucleus receiverNucleus) { - this.receivers.RemoveAll(receiver => receiver.nucleus == receiverNucleus); - receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); - } - - public static void Delete(Nucleus nucleus) { - foreach (Synapse synapse in nucleus.synapses) { - if (synapse.nucleus.receivers.Count > 1) { - // there is another nucleus feeding into this input nucleus - synapse.nucleus.receivers.RemoveAll(r => r.nucleus == nucleus); - } - else { - // No other links, delete it. - Nucleus.Delete(synapse.nucleus); - } - } - foreach (Receiver receiver in nucleus.receivers) { - if (receiver.nucleus != null && receiver.nucleus.synapses != null) - receiver.nucleus.synapses.RemoveAll(s => s.nucleus == nucleus); - } - - if (nucleus.brain != null) { - nucleus.brain.nuclei.RemoveAll(n => n == nucleus); - nucleus.brain.GarbageCollection(); - } - } - - public void GetInputFrom(Nucleus input, float weight = 1.0f) { - input.AddReceiver(this); - this.SetWeight(input, weight); - } - - public bool SynapseExists(Nucleus nucleus) { - foreach (Synapse synapse in synapses) { - if (synapse.nucleus == nucleus) - return true; - } - return false; - } - - public void SetWeight(Nucleus nucleus, float weight) { - foreach (Synapse synapse in synapses) { - if (synapse.nucleus == nucleus) { - synapse.weight = weight; - return; - } - } - Synapse newSynapse = new(nucleus, weight); - synapses.Add(newSynapse); - } - - public virtual void UpdateState() { } - - public void UpdateResult(Vector3 result) { - // float d = Vector3.Distance(result, this.outputValue); - // if (d < 0.5f) { - // //Debug.Log($"insignificant update: {d}"); - // return; - // } - - this.outputValue = result; - foreach (Receiver receiver in this.receivers) - receiver.nucleus.UpdateState(); - - } -} - -[System.Serializable] -public class Synapse { - [System.NonSerialized] - public Nucleus nucleus; - public int nucleusId; - public float weight; - - public enum CurvePresets { - Linear, - Power, - Sqrt, - Reciprocal, - Custom - } - // public CurvePresets curvePreset; - // public AnimationCurve curve; - public float curveMax = 1.0f; - - public Synapse(Nucleus nucleus, float weight) { - this.nucleus = nucleus; - this.nucleusId = nucleus.id; - this.weight = weight; - } - - public void Rebuild(NanoBrain brain) { - if (brain == null) { - return; - } - - foreach (Nucleus nucleus in brain.nuclei) { - if (nucleus.id == this.nucleusId) { - this.nucleus = nucleus; - return; - } - } - foreach (Perceptoid perceptoid in brain.perceptei) { - if (perceptoid.id == this.nucleusId) { - this.nucleus = perceptoid; - return; - } - } - Debug.LogError($"Synapse deserialization error: could not find nucleus with id {this.nucleusId}"); - } - - // public AnimationCurve GenerateCurve() { - // switch (this.curvePreset) { - // case CurvePresets.Linear: - // this.curveMax = this.weight; - // return Presets.Linear(this.weight); - // case CurvePresets.Power: - // this.curveMax = this.weight; - // return Presets.Power(2.0f, this.weight); - // case CurvePresets.Sqrt: - // this.curveMax = this.weight; - // return Presets.Power(0.5f, this.weight); - // case CurvePresets.Reciprocal: - // this.curveMax = 1 / 0.01f * this.weight; - // return Presets.Reciprocal(this.weight); - // default: - // this.curveMax = weight; - // return AnimationCurve.Constant(0, 1, weight); - // } - // } - - public static class Presets { - private const int samples = 32; - public static AnimationCurve Linear(float weight) { - return AnimationCurve.Linear(0f, 0f, 1000f, weight * 1000); - } - public static AnimationCurve Power(float exponent, float weight) { - // build keyframes - Keyframe[] keys = new Keyframe[samples]; - for (int i = 0; i < samples; i++) { - float t = i / (float)(samples - 1); - float v = Mathf.Pow(t, exponent) * weight; - keys[i] = new Keyframe(t, v); - } - - AnimationCurve curve = new(keys); - - // set tangent modes for each key to Auto (smooth). Use Linear if you prefer straight segments. - for (int i = 0; i < curve.length; i++) { - AnimationUtility.SetKeyLeftTangentMode(curve, i, AnimationUtility.TangentMode.Auto); - AnimationUtility.SetKeyRightTangentMode(curve, i, AnimationUtility.TangentMode.Auto); - } - - return curve; - } - public static AnimationCurve Reciprocal(float weight) { - int samples = 128; - float xMin = 0.001f; - float xMax = 1; - var keys = new Keyframe[samples]; - for (int i = 0; i < samples; i++) { - float t = i / (float)(samples - 1); - float x = Mathf.Lerp(xMin, xMax, t); - float y = 1f / x * weight; - keys[i] = new Keyframe(x, y); - } - var curve = new AnimationCurve(keys); - for (int i = 0; i < curve.length; i++) { - AnimationUtility.SetKeyLeftTangentMode(curve, i, AnimationUtility.TangentMode.Linear); - AnimationUtility.SetKeyRightTangentMode(curve, i, AnimationUtility.TangentMode.Linear); - } - return curve; - } - } -} - -[System.Serializable] -public class Receiver { - [System.NonSerialized] - public Nucleus nucleus; - public int nucleusId; - - public Receiver(Nucleus nucleus) { - this.nucleus = nucleus; - this.nucleusId = nucleus.id; - } - - public bool Rebuild(NanoBrain brain) { - if (brain == null) { - return false; - } - - foreach (Nucleus nucleus in brain.nuclei) { - if (nucleus.id == this.nucleusId) { - this.nucleus = nucleus; - return true; - } - } - Debug.LogWarning($"Receiver deserialization error: could not find nucleus with id {this.nucleusId}"); - return false; - } +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; + +[Serializable] +public class Nucleus : INucleus { + + public int id; // hash code + + [SerializeField] + protected string _name; + public virtual string name { + get => _name; + set => _name = value; + } + + [SerializeField] + private List _synapses = new(); + public List synapses => _synapses; + + [SerializeField] + private List _receivers = new(); + public List receivers => _receivers; + + #region Serialization + + [SerializeField] + protected string nucleusType; + + public virtual void Rebuild(NanoBrain brain) { + if (this.synapses != null) { + foreach (Synapse synapse in synapses) + synapse.Rebuild(brain); + } + foreach (Receiver receiver in receivers.ToArray()) { + if (receiver.Rebuild(brain) == false) { + Debug.Log("Rebuilding failed, removing receiver."); + receivers.Remove(receiver); + } + } + } + + public static Nucleus RebuildType(NanoBrain brain, Nucleus nucleus) { + if (string.IsNullOrEmpty(nucleus.nucleusType) == false) { + Type nucleusType = Type.GetType(nucleus.nucleusType); + if (nucleusType != null) { + object[] args = new object[] { brain, nucleus.name }; + Nucleus rebuiltNucleus = (Nucleus)Activator.CreateInstance(nucleusType, args); + rebuiltNucleus.Deserialize(nucleus); + return rebuiltNucleus; + } + } + return nucleus; + } + + public virtual void Deserialize(Nucleus nucleus) { } + + #endregion Serialization + + #region Runtime state (not serialized) + + public Cluster cluster { get; set; } + + private Vector3 _outputValue; + public Vector3 outputValue + { + get { return _outputValue; } + set { + this.stale = 0; + this._isSleeping = false; + _outputValue = value; + } + } + + [System.NonSerialized] + private int stale = 1000; + + private bool _isSleeping = false; + public bool isSleeping => _isSleeping; + + public void IncreaseAge() { + this.stale++; + this._isSleeping = this.stale > 2; + if (isSleeping) + _outputValue = Vector3.zero; + } + [System.NonSerialized] + public int layerIx; + + #endregion Runtime state + + public Nucleus(string name) { + this._name = name; + this.id = this.GetHashCode(); + } + + public virtual void AddReceiver(INucleus receiver) { + this.receivers.Add(new Receiver(receiver)); + //receiver.SetWeight(this, 1.0f); + } + + public void RemoveReceiver(INucleus receiverNucleus) { + this.receivers.RemoveAll(receiver => receiver.nucleus == receiverNucleus); + receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); + } + + public static void Delete(INucleus nucleus) { + foreach (Synapse synapse in nucleus.synapses) { + if (synapse.nucleus.receivers.Count > 1) { + // there is another nucleus feeding into this input nucleus + synapse.nucleus.receivers.RemoveAll(r => r.nucleus == nucleus); + } + else { + // No other links, delete it. + Nucleus.Delete(synapse.nucleus); + } + } + foreach (Receiver receiver in nucleus.receivers) { + if (receiver.nucleus != null && receiver.nucleus.synapses != null) + receiver.nucleus.synapses.RemoveAll(s => s.nucleus == nucleus); + } + + if (nucleus.cluster != null) { + nucleus.cluster.nuclei.RemoveAll(n => n == nucleus); + nucleus.cluster.GarbageCollection(); + } + } + + public void GetInputFrom(Nucleus input, float weight = 1.0f) { + input.AddReceiver(this); + this.SetWeight(input, weight); + } + + public bool SynapseExists(Nucleus nucleus) { + foreach (Synapse synapse in synapses) { + if (synapse.nucleus == nucleus) + return true; + } + return false; + } + + public void SetWeight(Nucleus nucleus, float weight) { + foreach (Synapse synapse in synapses) { + if (synapse.nucleus == nucleus) { + synapse.weight = weight; + return; + } + } + Synapse newSynapse = new(nucleus, weight); + synapses.Add(newSynapse); + } + + public virtual void UpdateState() { } + + public void UpdateResult(Vector3 result) { + // float d = Vector3.Distance(result, this.outputValue); + // if (d < 0.5f) { + // //Debug.Log($"insignificant update: {d}"); + // return; + // } + + this.outputValue = result; + foreach (Receiver receiver in this.receivers) + receiver.nucleus.UpdateState(); + + } +} + +[System.Serializable] +public class Synapse { + [System.NonSerialized] + public INucleus nucleus; + public NanoBrain cluster; + public int nucleusId; + public float weight; + + public enum CurvePresets { + Linear, + Power, + Sqrt, + Reciprocal, + Custom + } + // public CurvePresets curvePreset; + // public AnimationCurve curve; + public float curveMax = 1.0f; + + public Synapse(Nucleus nucleus, float weight) { + this.nucleus = nucleus; + this.nucleusId = nucleus.id; + this.weight = weight; + } + + public void Rebuild(NanoBrain brain) { + if (brain == null) { + return; + } + + foreach (Nucleus nucleus in brain.nuclei) { + if (nucleus.id == this.nucleusId) { + this.nucleus = nucleus; + return; + } + } + foreach (Perceptoid perceptoid in brain.perceptei) { + if (perceptoid.id == this.nucleusId) { + this.nucleus = perceptoid; + return; + } + } + Debug.LogError($"Synapse deserialization error: could not find nucleus with id {this.nucleusId}"); + } + + // public AnimationCurve GenerateCurve() { + // switch (this.curvePreset) { + // case CurvePresets.Linear: + // this.curveMax = this.weight; + // return Presets.Linear(this.weight); + // case CurvePresets.Power: + // this.curveMax = this.weight; + // return Presets.Power(2.0f, this.weight); + // case CurvePresets.Sqrt: + // this.curveMax = this.weight; + // return Presets.Power(0.5f, this.weight); + // case CurvePresets.Reciprocal: + // this.curveMax = 1 / 0.01f * this.weight; + // return Presets.Reciprocal(this.weight); + // default: + // this.curveMax = weight; + // return AnimationCurve.Constant(0, 1, weight); + // } + // } + + public static class Presets { + private const int samples = 32; + public static AnimationCurve Linear(float weight) { + return AnimationCurve.Linear(0f, 0f, 1000f, weight * 1000); + } + public static AnimationCurve Power(float exponent, float weight) { + // build keyframes + Keyframe[] keys = new Keyframe[samples]; + for (int i = 0; i < samples; i++) { + float t = i / (float)(samples - 1); + float v = Mathf.Pow(t, exponent) * weight; + keys[i] = new Keyframe(t, v); + } + + AnimationCurve curve = new(keys); + + // set tangent modes for each key to Auto (smooth). Use Linear if you prefer straight segments. + for (int i = 0; i < curve.length; i++) { + AnimationUtility.SetKeyLeftTangentMode(curve, i, AnimationUtility.TangentMode.Auto); + AnimationUtility.SetKeyRightTangentMode(curve, i, AnimationUtility.TangentMode.Auto); + } + + return curve; + } + public static AnimationCurve Reciprocal(float weight) { + int samples = 128; + float xMin = 0.001f; + float xMax = 1; + var keys = new Keyframe[samples]; + for (int i = 0; i < samples; i++) { + float t = i / (float)(samples - 1); + float x = Mathf.Lerp(xMin, xMax, t); + float y = 1f / x * weight; + keys[i] = new Keyframe(x, y); + } + var curve = new AnimationCurve(keys); + for (int i = 0; i < curve.length; i++) { + AnimationUtility.SetKeyLeftTangentMode(curve, i, AnimationUtility.TangentMode.Linear); + AnimationUtility.SetKeyRightTangentMode(curve, i, AnimationUtility.TangentMode.Linear); + } + return curve; + } + } +} + +[Serializable] +public class Receiver { + [NonSerialized] + public INucleus nucleus; + //public int nucleusId; + + public Receiver(INucleus nucleus) { + this.nucleus = nucleus; + //this.nucleusId = nucleus.id; + } + + public bool Rebuild(NanoBrain brain) { + if (brain == null) { + return false; + } + + // Use SerializedReference instead? + // foreach (Nucleus nucleus in brain.nuclei) { + // if (nucleus.id == this.nucleusId) { + // this.nucleus = nucleus; + // return true; + // } + // } + //Debug.LogWarning($"Receiver deserialization error: could not find nucleus with id {this.nucleusId}"); + return false; + } } \ No newline at end of file diff --git a/Assets/NanoBrain/Perceptoid.cs b/Assets/NanoBrain/Perceptoid.cs index 3f1d0b1..85f0bc1 100644 --- a/Assets/NanoBrain/Perceptoid.cs +++ b/Assets/NanoBrain/Perceptoid.cs @@ -1,98 +1,103 @@ -using UnityEngine; - -[System.Serializable] -public class Perceptoid : Neuroid { - // A neuroid which has no neurons as input - // But receives value from a receptor - public Receptor receptor; - public string baseName; - - public int thingId; - - //[SerializeField] - // Needs serialization!!!! - [SerializeReference] - public PercepteiArray array; - - #region Serialization - - [SerializeField] - public int thingType; - - public override void Rebuild(NanoBrain brain) { - base.Rebuild(brain); - this.receptor = Receptor.GetReceptor(brain, thingType); - this.receptor.perceptei.Add(this); - if (string.IsNullOrEmpty(this.baseName)) - this.baseName = this.name; - } - - public override void Deserialize(Nucleus nucleus) { - base.Deserialize(nucleus); - - if (nucleus is Perceptoid perceptoid) - this.receptor.thingType = perceptoid.thingType; - - // Point all receivers to this perceptoid instead of the default nucleus - foreach (Receiver receiver in nucleus.receivers) { - foreach (Synapse synapse in receiver.nucleus.synapses) { - if (synapse.nucleus == nucleus) - synapse.nucleus = this; - } - } - // Point all synapses to this perceptoid instead of the default nucleus - foreach (Synapse synapse in nucleus.synapses) { - foreach (Receiver receiver in synapse.nucleus.receivers) { - if (receiver.nucleus == nucleus) - receiver.nucleus = this; - } - } - // Copy all the synapses - this.synapses = nucleus.synapses; - // Copy all receivers - this.receivers = nucleus.receivers; - } - - #endregion Serialization - - public Perceptoid(NanoBrain brain, int thingType, string name = "sensor") : base(name) { - this.brain = brain; - if (this.brain != null) { - this.brain.perceptei.Add(this); - } - else - Debug.LogError("No neuroid network"); - - this.nucleusType = nameof(Perceptoid); - this.name = name; - this.baseName = name; - this.thingType = thingType; - this.receptor = Receptor.GetReceptor(brain, thingType); - this.receptor.perceptei.Add(this); - this.array = new PercepteiArray(this); - } - - public Perceptoid(PercepteiArray array) : base(array.name) { - this.array = array; - Perceptoid source = array.perceptei[0]; - this.brain = source.brain; - if (this.brain != null) { - this.brain.perceptei.Add(this); - } - else - Debug.LogError("No neuroid network"); - - this.nucleusType = nameof(Perceptoid); - this.name = source.baseName; - this.baseName = source.baseName; - this.thingType = source.thingType; - this.receptor = Receptor.GetReceptor(this.brain, this.thingType); - this.receptor.perceptei.Add(this); - } - - public override void UpdateState() { - Vector3 result = this.receptor.localPosition; - UpdateResult(result); - } - -} +using UnityEngine; + +[System.Serializable] +public class Perceptoid : Neuroid { + // A neuroid which has no neurons as input + // But receives value from a receptor + + public NanoBrain brain; + public Receptor receptor; + public string baseName; + + public int thingId; + + //[SerializeField] + // Needs serialization!!!! + [SerializeReference] + public PercepteiArray array; + + #region Serialization + + [SerializeField] + public int thingType; + + public override void Rebuild(NanoBrain brain) { + base.Rebuild(brain); + this.receptor = Receptor.GetReceptor(brain, thingType); + this.receptor.perceptei.Add(this); + if (string.IsNullOrEmpty(this.baseName)) + this.baseName = this.name; + } + + public override void Deserialize(Nucleus nucleus) { + base.Deserialize(nucleus); + + if (nucleus is Perceptoid perceptoid) + this.receptor.thingType = perceptoid.thingType; + + // Point all receivers to this perceptoid instead of the default nucleus + foreach (Receiver receiver in nucleus.receivers) { + foreach (Synapse synapse in receiver.nucleus.synapses) { + if (synapse.nucleus == nucleus) + synapse.nucleus = this; + } + } + // Point all synapses to this perceptoid instead of the default nucleus + foreach (Synapse synapse in nucleus.synapses) { + foreach (Receiver receiver in synapse.nucleus.receivers) { + if (receiver.nucleus == nucleus) + receiver.nucleus = this; + } + } + // Copying disabled for now + // // Copy all the synapses + // this.synapses = nucleus.synapses; + // // Copy all receivers + // this.receivers = nucleus.receivers; + } + + #endregion Serialization + + public Perceptoid(NanoBrain brain, int thingType, string name = "sensor") : base(name) { + this.brain = brain; + this.cluster = brain.cluster; + if (this.cluster != null) { + brain.perceptei.Add(this); + } + else + Debug.LogError("No neuroid network"); + + this.nucleusType = nameof(Perceptoid); + this.name = name; + this.baseName = name; + this.thingType = thingType; + this.receptor = Receptor.GetReceptor(brain, thingType); + this.receptor.perceptei.Add(this); + this.array = new PercepteiArray(this); + } + + public Perceptoid(PercepteiArray array) : base(array.name) { + this.array = array; + Perceptoid source = array.perceptei[0]; + this.brain = source.brain; + this.cluster = source.cluster; + if (this.brain != null) { + this.brain.perceptei.Add(this); + } + else + Debug.LogError("No neuroid network"); + + this.nucleusType = nameof(Perceptoid); + this.name = source.baseName; + this.baseName = source.baseName; + this.thingType = source.thingType; + this.receptor = Receptor.GetReceptor(this.brain, this.thingType); + this.receptor.perceptei.Add(this); + } + + public override void UpdateState() { + Vector3 result = this.receptor.localPosition; + UpdateResult(result); + } + +} diff --git a/Assets/NanoBrain/Receptor.cs b/Assets/NanoBrain/Receptor.cs index 3e63760..ed8ba96 100644 --- a/Assets/NanoBrain/Receptor.cs +++ b/Assets/NanoBrain/Receptor.cs @@ -1,82 +1,82 @@ -using System.Collections.Generic; -using UnityEngine; -using LinearAlgebra; - -public class Receptor { - /// - /// The list of perceptoid which can process stimuli from this receptor - /// - public List perceptei = new(); - - private int _thingType = 0; - public int thingType { - get { return _thingType; } - set { - _thingType = value; - foreach (Perceptoid perceptoid in perceptei) { - perceptoid.thingType = _thingType; - } - } - } - public Vector3 localPosition; - public float distanceResolution = 0.1f; - public float directionResolution = 5; - - public Receptor(NanoBrain brain, int thingType) { - this.thingType = thingType; - //this.perceptei.Add(perceptoid); - brain.receptors.Add(this); - } - - public static Receptor GetReceptor(NanoBrain brain, int thingType) { - foreach (Receptor receptor in brain.receptors) { - if (thingType == 0 || receptor.thingType == thingType) - return receptor; - } - Receptor newReceptor = new(brain, thingType); - return newReceptor; - } - - public virtual void ProcessStimulus(int thingId, Vector3 newLocalPositionVector, string thingName = null) { - this.localPosition = newLocalPositionVector; - - Perceptoid selectedPerceptoid = null; - foreach (Perceptoid perceptoid in this.perceptei) { - if (perceptoid.thingId == thingId) { - // We found an existing perceptoid for this thing - selectedPerceptoid = perceptoid; - // Do not look any further - - break; - } - else if (perceptoid.isSleeping) { - // A sleeping perceptoid is not active and can therefore always be reused - selectedPerceptoid = perceptoid; - // Look further because we could find a existing perceptoid for this thing - } - - else if (selectedPerceptoid == null) { - // If we haven't found a perceptoid yet, just start by taking the first - selectedPerceptoid = perceptoid; - } - - else if (selectedPerceptoid.isSleeping == false) { - // If no existing or sleeping perceptoid is found, we look for the perceptoid - // we the furthest (least interesting) stimulus - if (perceptoid.receptor.localPosition.magnitude < selectedPerceptoid.receptor.localPosition.magnitude) { - Debug.Log($"{selectedPerceptoid.name} {selectedPerceptoid.receptor.localPosition.magnitude} {perceptoid.receptor.localPosition.magnitude} "); - selectedPerceptoid = perceptoid; - } - } - } - if (selectedPerceptoid == null) { - Debug.Log("No perceptoid selected, stimulus is ignored"); - return; - } - // Debug.Log($"Stimulus {thingType} {thingId} {selectedPerceptoid.name}"); - selectedPerceptoid.thingId = thingId; - if (thingName != null) - selectedPerceptoid.name = selectedPerceptoid.baseName + " " + thingName; - selectedPerceptoid.UpdateState(); - } +using System.Collections.Generic; +using UnityEngine; +using LinearAlgebra; + +public class Receptor { + /// + /// The list of perceptoid which can process stimuli from this receptor + /// + public List perceptei = new(); + + private int _thingType = 0; + public int thingType { + get { return _thingType; } + set { + _thingType = value; + foreach (Perceptoid perceptoid in perceptei) { + perceptoid.thingType = _thingType; + } + } + } + public Vector3 localPosition; + public float distanceResolution = 0.1f; + public float directionResolution = 5; + + public Receptor(NanoBrain brain, int thingType) { + this.thingType = thingType; + //this.perceptei.Add(perceptoid); + brain.receptors.Add(this); + } + + public static Receptor GetReceptor(NanoBrain brain, int thingType) { + foreach (Receptor receptor in brain.receptors) { + if (thingType == 0 || receptor.thingType == thingType) + return receptor; + } + Receptor newReceptor = new(brain, thingType); + return newReceptor; + } + + public virtual void ProcessStimulus(int thingId, Vector3 newLocalPositionVector, string thingName = null) { + this.localPosition = newLocalPositionVector; + + Perceptoid selectedPerceptoid = null; + foreach (Perceptoid perceptoid in this.perceptei) { + if (perceptoid.thingId == thingId) { + // We found an existing perceptoid for this thing + selectedPerceptoid = perceptoid; + // Do not look any further + + break; + } + else if (perceptoid.isSleeping) { + // A sleeping perceptoid is not active and can therefore always be reused + selectedPerceptoid = perceptoid; + // Look further because we could find a existing perceptoid for this thing + } + + else if (selectedPerceptoid == null) { + // If we haven't found a perceptoid yet, just start by taking the first + selectedPerceptoid = perceptoid; + } + + else if (selectedPerceptoid.isSleeping == false) { + // If no existing or sleeping perceptoid is found, we look for the perceptoid + // we the furthest (least interesting) stimulus + if (perceptoid.receptor.localPosition.magnitude < selectedPerceptoid.receptor.localPosition.magnitude) { + Debug.Log($"{selectedPerceptoid.name} {selectedPerceptoid.receptor.localPosition.magnitude} {perceptoid.receptor.localPosition.magnitude} "); + selectedPerceptoid = perceptoid; + } + } + } + if (selectedPerceptoid == null) { + Debug.Log("No perceptoid selected, stimulus is ignored"); + return; + } + // Debug.Log($"Stimulus {thingType} {thingId} {selectedPerceptoid.name}"); + selectedPerceptoid.thingId = thingId; + if (thingName != null) + selectedPerceptoid.name = selectedPerceptoid.baseName + " " + thingName; + selectedPerceptoid.UpdateState(); + } } \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/Editor/BrainPickerWindow.cs b/Assets/NanoBrain/VisualEditor/Editor/BrainPickerWindow.cs new file mode 100644 index 0000000..d80c282 --- /dev/null +++ b/Assets/NanoBrain/VisualEditor/Editor/BrainPickerWindow.cs @@ -0,0 +1,72 @@ +using UnityEditor; +using UnityEngine; +using System; +using System.Linq; + +public class BrainPickerWindow : EditorWindow +{ + private Vector2 scroll; + private NanoBrain[] items = new NanoBrain[0]; + private Action onPicked; + private string search = ""; + + public static void ShowPicker(Action onPicked, string title = "Select NanoBrain") + { + var w = CreateInstance(); + w.titleContent = new GUIContent(title); + w.minSize = new Vector2(360, 320); + w.onPicked = onPicked; + w.RefreshList(); + w.ShowModalUtility(); // modal dialog + } + + private void OnEnable() => RefreshList(); + + private void RefreshList() + { + var guids = AssetDatabase.FindAssets("t:NanoBrain"); + items = guids + .Select(g => AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(g))) + .Where(b => b != null) + .OrderBy(b => b.name) + .ToArray(); + } + + private void OnGUI() + { + EditorGUILayout.Space(); + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Choose NanoBrain:", EditorStyles.boldLabel); + if (GUILayout.Button("Refresh", GUILayout.Width(80))) RefreshList(); + GUILayout.FlexibleSpace(); + EditorGUILayout.EndHorizontal(); + + EditorGUILayout.Space(); + search = EditorGUILayout.TextField(search); + + EditorGUILayout.Space(); + scroll = EditorGUILayout.BeginScrollView(scroll); + foreach (var it in items) + { + if (!string.IsNullOrEmpty(search) && it.name.IndexOf(search, StringComparison.OrdinalIgnoreCase) < 0) + continue; + + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField(EditorGUIUtility.ObjectContent(it, typeof(NanoBrain)), GUILayout.Height(20)); + if (GUILayout.Button("Select", GUILayout.Width(70))) + { + onPicked?.Invoke(it); + Close(); + return; + } + EditorGUILayout.EndHorizontal(); + } + EditorGUILayout.EndScrollView(); + + EditorGUILayout.Space(); + EditorGUILayout.BeginHorizontal(); + if (GUILayout.Button("Cancel")) { onPicked?.Invoke(null); Close(); } + GUILayout.FlexibleSpace(); + EditorGUILayout.EndHorizontal(); + } +} diff --git a/Assets/NanoBrain/VisualEditor/Editor/BrainPickerWindow.cs.meta b/Assets/NanoBrain/VisualEditor/Editor/BrainPickerWindow.cs.meta new file mode 100644 index 0000000..b2de114 --- /dev/null +++ b/Assets/NanoBrain/VisualEditor/Editor/BrainPickerWindow.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 9197e2d322d23b5798ab4aef729815b0 \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs new file mode 100644 index 0000000..e078ad1 --- /dev/null +++ b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs @@ -0,0 +1,633 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEditor; + +using UnityEngine; +using UnityEngine.UIElements; + +[CustomEditor(typeof(Cluster))] +public class ClusterInspector : Editor { + protected static VisualElement mainContainer; + protected static VisualElement inspectorContainer; + + protected bool breakOnWake = false; + + #region Start + + public override VisualElement CreateInspectorGUI() { + Cluster cluster = target as Cluster; + + serializedObject.Update(); + + VisualElement root = new(); + //root.style.flexDirection = FlexDirection.Row; // side-by-side layout + //root.style.flexGrow = 1; + //root.style.minHeight = 600; + root.style.paddingLeft = 0; + root.style.paddingRight = 0; + root.style.paddingTop = 0; + root.style.paddingBottom = 0; + + root.styleSheets.Add(Resources.Load("GraphStyles")); + + mainContainer = new() { + // name = "main", + style = { + // flexDirection = FlexDirection.Row, + // flexGrow = 1, + height = 450, + } + }; + GraphView graph = new(); + graph.style.flexGrow = 1; + + inspectorContainer = new VisualElement { + // name = "inspector" + }; + + mainContainer.Add(graph); + mainContainer.Add(inspectorContainer); + root.Add(mainContainer); + + // Run once for initial state (use resolved style width if available) + float initialWidth = root.layout.width > 0 ? root.layout.width : root.contentRect.width; + UpdateLayout(initialWidth); + + // React to size changes of root (or parent if appropriate) + root.RegisterCallback(evt => { + UpdateLayout(evt.newRect.width); + }); + + if (cluster != null) + graph.SetGraph(null, cluster, cluster.output, inspectorContainer); + else + Debug.LogWarning(" No brain!"); + + serializedObject.ApplyModifiedProperties(); + return root; + } + + public class GraphView : VisualElement { + Cluster brain; + SerializedObject serializedBrain; + INucleus currentNucleus; + GameObject gameObject; + private List layers = new(); + private readonly Dictionary neuroidPositions = new(); + + Vector2 pan = Vector2.zero; + //float zoom = 1f; + bool draggingCanvas = false; + Vector2 lastMouse; + ClusterWrapper currentWrapper; + + public GraphView() { + name = "content"; + style.flexGrow = 1; + + IMGUIContainer imguiContainer = new(OnIMGUI); + imguiContainer.style.position = Position.Absolute; + imguiContainer.style.left = 0; imguiContainer.style.top = 0; + imguiContainer.style.right = 0; imguiContainer.style.bottom = 0; + imguiContainer.pickingMode = PickingMode.Position; + imguiContainer.focusable = true; + Add(imguiContainer); + + //RegisterCallback(OnWheel); + RegisterCallback(OnMouseDown); + RegisterCallback(OnMouseMove); + RegisterCallback(OnMouseUp); + } + + public void SetGraph(GameObject gameObject, Cluster brain, Nucleus nucleus, VisualElement inspectorContainer) { + this.gameObject = gameObject; + this.brain = brain; + if (Application.isPlaying == false) + this.serializedBrain = new SerializedObject(brain); + this.currentNucleus = nucleus; + Rebuild(inspectorContainer); + } + + void Rebuild(VisualElement inspectorContainer) { + BuildLayers(); + + if (this.currentNucleus == null) { + inspectorContainer.Clear(); + return; + } + + if (currentWrapper != null) + DestroyImmediate(currentWrapper); + currentWrapper = CreateInstance().Init(this.currentNucleus, brain); + DrawInspector(inspectorContainer); + } + + private void BuildLayers() { + // A temporary list to track what's been added to layers + this.layers = new(); + int layerIx = 0; + + INucleus selectedNucleus = this.currentNucleus; + if (selectedNucleus == null) + return; + NeuroidLayer currentLayer = new() { ix = layerIx }; + + if (selectedNucleus.receivers != null) { + foreach (Receiver receiver in selectedNucleus.receivers) { + INucleus outputNeuroid = receiver.nucleus; + if (outputNeuroid != null) { + AddToLayer(currentLayer, outputNeuroid); + // Debug.Log($"layer {layerIx} nucleus {outputNeuroid.name}"); + } + } + } + if (currentLayer.neuroids.Count > 0) { + this.layers.Add(currentLayer); + layerIx++; + currentLayer = new() { ix = layerIx }; + } + + AddToLayer(currentLayer, selectedNucleus); + this.layers.Add(currentLayer); + // Debug.Log($"layer {layerIx} nucleus {selectedNucleus.name}"); + + layerIx++; + currentLayer = new() { ix = layerIx }; + + if (selectedNucleus.synapses != null) { + foreach (Synapse synapse in selectedNucleus.synapses) { + INucleus input = synapse.nucleus; + AddToLayer(currentLayer, input); + // Debug.Log($"layer {layerIx} nucleus {input.name}"); + } + } + if (currentLayer.neuroids.Count > 0) { + this.layers.Add(currentLayer); + } + } + + private void AddToLayer(NeuroidLayer layer, INucleus nucleus) { + if (nucleus == null) + return; + layer.neuroids.Add(nucleus); + //nucleus.layerIx = layer.ix; + // Store its position + Vector2Int neuroidPosition = new(layer.ix, layer.neuroids.Count - 1); + neuroidPositions[nucleus] = neuroidPosition; + + } + + void OnMouseDown(MouseDownEvent e) { + if (e.button == 2) { draggingCanvas = true; lastMouse = e.mousePosition; e.StopPropagation(); } + } + void OnMouseMove(MouseMoveEvent e) { + if (draggingCanvas) { + var delta = e.mousePosition - lastMouse; + pan += delta; + //content.style.left = pan.x; + //content.style.top = pan.y; + lastMouse = e.mousePosition; + } + } + void OnMouseUp(MouseUpEvent e) { if (e.button == 2) draggingCanvas = false; } + + void OnIMGUI() { + if (currentNucleus == null) + return; + + if (Application.isPlaying == false) + serializedBrain.Update(); + + Handles.BeginGUI(); + DrawGraph(); + Handles.EndGUI(); + + } + + private void DrawGraph() { + float size = 20; + Vector3 position = new(150, 210, 0); + + DrawReceivers(this.currentNucleus, position, size); + DrawSynapses(this.currentNucleus, position, size); + + // Draw selected Nucleus + Handles.color = Color.white; + Handles.DrawSolidDisc(position, Vector3.forward, size + 2); + DrawNucleus(this.currentNucleus, position, this.currentNucleus.outputValue.magnitude, 20); + } + + private void DrawReceivers(INucleus nucleus, Vector3 parentPos, float size) { + int nodeCount = nucleus.receivers.Count; + + // Determine the maximum value in this layer + // This is used to 'scale' the output value colors of the nuclei + float maxValue = 0; + foreach (Receiver receiver in nucleus.receivers) { + if (receiver.nucleus is Neuroid neuroid) { + float value = neuroid.outputValue.magnitude; + if (value > maxValue) + maxValue = value; + } + } + + // Determine the spacing of the nuclei in the layer + float spacing = 400f / nodeCount; + float margin = 10 + spacing / 2; + + int row = 0; + foreach (Receiver receiver in nucleus.receivers) { + INucleus receiverNucleus = receiver.nucleus; + if (receiverNucleus == null) + continue; + + Vector3 pos = new(50, margin + row * spacing, 0.0f); + Handles.color = Color.white; + Handles.DrawLine(parentPos, pos); + + DrawNucleus(receiverNucleus, pos, maxValue, size); + row++; + } + } + + private void DrawSynapses(INucleus nucleus, Vector3 parentPos, float size) { + int nodeCount = nucleus.synapses.Count; + + // Determine the maximum value in this layer + // This is used to 'scale' the output value colors of the nuclei + float maxValue = 0; + foreach (Synapse receiver in nucleus.synapses) { + if (receiver.nucleus is Neuroid neuroid) { + float value = neuroid.outputValue.magnitude; + if (value > maxValue) + maxValue = value; + } + } + + // Determine the spacing of the nuclei in the layer + float spacing = 400f / nodeCount; + float margin = 10 + spacing / 2; + + int row = 0; + List drawnArrays = new(); + foreach (Synapse synapse in nucleus.synapses) { + Vector3 pos = new(250, margin + row * spacing, 0.0f); + Handles.color = Color.white; + Handles.DrawLine(parentPos, pos); + // if (synapse.nucleus is Perceptoid perceptoid && perceptoid.array != null) { + // // if (drawnArrays.Contains(perceptoid.array)) + // // // We already drawn this array + // // continue; + + // drawnArrays.Add(perceptoid.array); + // DrawArray(perceptoid.array, pos, size); + // } + // else { + + DrawNucleus(synapse.nucleus, pos, maxValue, size); + row++; + // } + } + } + + private void DrawNucleus(INucleus nucleus, Vector3 position, float maxValue, float size) { + if (nucleus.isSleeping) + Handles.color = Color.darkRed; + else { + if (Application.isPlaying) { + float brightness = nucleus.outputValue.magnitude / maxValue; + Handles.color = new Color(brightness, brightness, brightness, 1f); + } + else + Handles.color = Color.black; + } + Handles.DrawSolidDisc(position, Vector3.forward, size); + + Handles.color = Color.white; + // Position the label in front of the disc + Vector3 labelPosition = position + (Vector3.forward * 0.1f); + + GUIStyle style = new(EditorStyles.label) { + alignment = TextAnchor.MiddleCenter, + normal = { textColor = Color.white }, + fontStyle = FontStyle.Bold, + }; + if (nucleus is Perceptoid perceptoid) { + if (perceptoid.array == null || perceptoid.array.perceptei == null || perceptoid.array.perceptei.Length == 0) + perceptoid.array = new PercepteiArray(perceptoid); + + if (perceptoid.array.perceptei.Length > 1) { + Handles.Label(labelPosition, perceptoid.array.perceptei.Length.ToString(), style); + } + } + + style.alignment = TextAnchor.UpperCenter; + Vector3 labelPos = position - Vector3.down * (size + 0.2f); // below disc along up axis + Handles.Label(labelPos, nucleus.name, style); + + Rect neuronRect = new(position.x - size, position.y - size, size * 2, size * 2); + int id = GUIUtility.GetControlID(FocusType.Passive); + Event e = Event.current; + EventType et = e.GetTypeForControl(id); + if (e != null && neuronRect.Contains(e.mousePosition)) { + // Process Hover + HandleMouseHover(nucleus, neuronRect); + // Process click + if (e.type == EventType.MouseDown && e.button == 0) { + // Consume the event so the scene doesn't also handle it + e.Use(); + HandleClicked(nucleus); + } + } + } + + private void DrawArray(PercepteiArray array, Vector3 position, float size) { + Vector3 offset = new(size / 4, size / 4, 0); + Handles.color = Color.black; + Handles.DrawSolidDisc(position, Vector3.forward, size); + + GUIStyle style = new(EditorStyles.label) { + alignment = TextAnchor.UpperCenter, + normal = { textColor = Color.white }, + fontStyle = FontStyle.Bold + }; + Handles.Label(position, array.perceptei.Length.ToString(), style); + Vector3 labelPos = position - Vector3.down * (size + 0.2f); // below disc along up axis + Handles.Label(labelPos, array.name, style); + + // To do: add HandleClick (see above) to expand the array + } + + private void HandleMouseHover(INucleus nucleus, Rect rect) { + GUIContent tooltip; + if (nucleus is Perceptoid perceptoid) { + if (perceptoid.receptor != null) { + tooltip = new( + $"{perceptoid.name}" + + $"\nType {perceptoid.receptor.thingType}" + + $" Thing {perceptoid.thingId}" + + $"\nValue: {nucleus.outputValue}"); + } + else { + tooltip = new( + $"{perceptoid.name}" + + $"\nThing {perceptoid.thingId}" + + $"\nValue: {nucleus.outputValue}"); + } + } + else { + tooltip = new( + $"{nucleus.name}" + + $"\nsynapse count {nucleus.synapses.Count}" + + $"\nValue: {nucleus.outputValue}"); + } + + Vector2 mousePosition = Event.current.mousePosition; + + // Display tooltip with some offset + Vector2 tooltipSize = GUI.skin.box.CalcSize(tooltip); + Rect tooltipRect = new Rect(mousePosition.x + 10, mousePosition.y + 10, tooltipSize.x, tooltipSize.y); + + GUI.Box(tooltipRect, tooltip); + } + + private void HandleClicked(INucleus nucleus) { + this.currentNucleus = nucleus; + BuildLayers(); + } + + void DrawInspector(VisualElement inspectorContainer) { + if (inspectorContainer == null) + return; + + inspectorContainer.Clear(); + if (this.currentNucleus == null) + return; + + // create a SerializedObject wrapper so Unity inspector controls work (and Undo) + SerializedObject so = new(currentWrapper); + IMGUIContainer container = new(() => { + if (so.targetObject == null) + return; + so.Update(); + + if (this.currentNucleus == null) + return; + + this.currentNucleus.name = EditorGUILayout.TextField(this.currentNucleus.name); + if (this.currentNucleus is Perceptoid perceptoid) { + perceptoid.receptor.thingType = EditorGUILayout.IntField("Thing Type", perceptoid.receptor.thingType); + + if (perceptoid.array == null || perceptoid.array.perceptei == null || perceptoid.array.perceptei.Length == 0) + perceptoid.array = new PercepteiArray(perceptoid); + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.IntField("Array size", perceptoid.array.perceptei.Length); + if (GUILayout.Button("Add")) + perceptoid.array.AddPerceptoid(); + if (GUILayout.Button("Del")) + perceptoid.array.RemovePerceptoid(); + EditorGUILayout.EndHorizontal(); + } + else if (this.currentNucleus is Neuroid neuroid) { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Activation Curve", GUILayout.Width(150)); + if (neuroid.curveMax > 0) + EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, 0, 1, neuroid.curveMax)); + else + EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, neuroid.curveMax, 1, -neuroid.curveMax)); + neuroid.curvePreset = (Neuroid.CurvePresets)EditorGUILayout.EnumPopup(neuroid.curvePreset, GUILayout.Width(100)); + EditorGUILayout.EndHorizontal(); + } + + if (Application.isPlaying) + EditorGUILayout.FloatField("Output", this.currentNucleus.outputValue.magnitude); + else + EditorGUILayout.LabelField(" "); + + if (this.currentNucleus.synapses.Count > 0) { + Synapse[] synapses = this.currentNucleus.synapses.ToArray(); + foreach (Synapse synapse in synapses) { + if (synapse.nucleus != null) { + EditorGUILayout.Space(); + + EditorGUI.BeginDisabledGroup(synapse.nucleus.isSleeping); + if (Application.isPlaying) + EditorGUILayout.FloatField(synapse.nucleus.name, synapse.nucleus.outputValue.magnitude * synapse.weight); + else { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField(synapse.nucleus.name); + // if (synapse.nucleus is Perceptoid perceptoid) { + // if (perceptoid.array == null || perceptoid.array.perceptei == null || perceptoid.array.perceptei.Length == 0) { + // perceptoid.array = new PercepteiArray(perceptoid); + // } + // EditorGUILayout.IntField(perceptoid.array.perceptei.Length); + // if (GUILayout.Button("Add")) + // perceptoid.array.AddPerceptoid(); + // } + if (GUILayout.Button("Disconnect")) + synapse.nucleus.RemoveReceiver(this.currentNucleus); + EditorGUILayout.EndHorizontal(); + } + + EditorGUI.indentLevel++; + synapse.weight = EditorGUILayout.FloatField("Weight", synapse.weight); + EditorGUI.indentLevel--; + EditorGUI.EndDisabledGroup(); + } + } + } + + EditorGUILayout.Space(); + + ConnectNucleus(this.currentNucleus); + if (GUILayout.Button("Add Input Neuron")) + AddInputNeuron(this.currentNucleus); + // if (GUILayout.Button("Add Input Perceptoid")) + // AddPerceptoid(this.currentNucleus); + if (GUILayout.Button("Add Input Cluster")) + AddCluster(this.currentNucleus); + + EditorGUILayout.Space(); + + if (GUILayout.Button("Delete this neuron")) + DeleteNeuron(this.currentNucleus); + + //DisconnectNucleus(this.currentNucleus); + + if (this.gameObject != null) { + Vector3 worldVector = this.gameObject.transform.TransformVector(this.currentNucleus.outputValue); + Debug.DrawRay(this.gameObject.transform.position, worldVector, Color.yellow); + } + }); + + inspectorContainer.Add(container); + } + + protected virtual void AddInputNeuron(INucleus nucleus) { + Neuroid newNeuroid = new(this.brain.cluster, "New neuron"); + newNeuroid.AddReceiver(nucleus); + this.currentNucleus = newNeuroid; + BuildLayers(); + } + + protected virtual void DeleteNeuron(INucleus nucleus) { + if (nucleus == null) + return; + if (nucleus.cluster != null) + this.currentNucleus = nucleus.cluster.output; + foreach (Receiver receiver in nucleus.receivers) { + if (receiver.nucleus != null) { + this.currentNucleus = receiver.nucleus; + break; + } + } + Nucleus.Delete(nucleus); + BuildLayers(); + } + + // protected virtual void AddPerceptoid(INucleus nucleus) { + // Perceptoid newPerceptoid = new(this.brain, 0, "New Perceptoid"); + // newPerceptoid.AddReceiver(nucleus); + // this.currentNucleus = newPerceptoid; + // BuildLayers(); + // } + + protected virtual void AddCluster(INucleus nucleus) { + BrainPickerWindow.ShowPicker(brain => OnClusterPicked(nucleus, brain), "Select Cluster"); + } + + private void OnClusterPicked(INucleus nucleus, NanoBrain brain) { + NanoBrain brainInstance = Instantiate(brain); + brainInstance.AddReceiver(nucleus); + } + + protected virtual void ConnectNucleus(INucleus nucleus) { + if (this.currentNucleus.cluster == null) + return; + + IEnumerable synapseNuclei = this.currentNucleus.synapses.Select(synapse => synapse.nucleus.name); + //IEnumerable perceptei = this.currentNucleus.brain.perceptei.Select(i => i.name).Except(synapseNuclei); + IEnumerable nuclei = this.currentNucleus.cluster.nuclei.Select(i => i.name).Except(synapseNuclei); + //string[] names = perceptei.Concat(nuclei).ToArray(); + string[] names = nuclei.ToArray(); + int selectedIndex = -1; + selectedIndex = EditorGUILayout.Popup("Connect to", selectedIndex, names); + if (selectedIndex >= 0) { + // if (selectedIndex < perceptei.Count()) { + // Nucleus n = this.currentNucleus.brain.perceptei[selectedIndex]; + // n.AddReceiver(this.currentNucleus); + // } + // else { + // Nucleus n = this.currentNucleus.brain.nuclei[selectedIndex - perceptei.Count()]; + // n.AddReceiver(this.currentNucleus); + // } + Nucleus n = this.currentNucleus.cluster.nuclei[selectedIndex]; + n.AddReceiver(this.currentNucleus); + } + } + + protected virtual void DisconnectNucleus(Nucleus nucleus) { + if (this.currentNucleus.cluster == null) + return; + string[] names = this.currentNucleus.synapses.Select(synapse => synapse.nucleus.name).ToArray(); + int selectedIndex = -1; + selectedIndex = EditorGUILayout.Popup("Disconnect from", selectedIndex, names); + //if (selectedIndex >= 0 && selectedIndex < this.currentNucleus.brain.perceptei.Count) { + if (selectedIndex >= 0 && selectedIndex < this.currentNucleus.cluster.nuclei.Count) { + Synapse synapse = this.currentNucleus.synapses[selectedIndex]; + synapse.nucleus.RemoveReceiver(this.currentNucleus); + } + } + } + + #endregion Start + + #region Update + + private void UpdateLayout(float containerWidth) { + if (containerWidth > 600f) { + mainContainer.style.flexDirection = FlexDirection.Row; + inspectorContainer.style.width = 300; // fixed sidebar width + inspectorContainer.style.flexGrow = 0; + } + else { + mainContainer.style.flexDirection = FlexDirection.Column; + inspectorContainer.style.width = Length.Percent(100); // full width below + inspectorContainer.style.flexDirection = FlexDirection.Column; + inspectorContainer.style.flexGrow = 1; // can set 0 or keep as needed + } + } + + #endregion Update +} + +public class NeuroidLayer { + public int ix = 0; + public List neuroids = new(); +} + +public class ClusterWrapper : ScriptableObject { + // expose fields that map to GraphNode + //public string title; + public Vector2 position; + INucleus node; + Cluster graph; // needed to write back and mark dirty + + public ClusterWrapper Init(INucleus node, Cluster graphAsset) { + this.node = node; + this.graph = graphAsset; + //this.title = " A " + node.name; + //position = node.position; + return this; + } + void OnValidate() { + if (node != null) { + //node.name = title; + //node.position = position; +#if UNITY_EDITOR + if (graph != null) + UnityEditor.EditorUtility.SetDirty(graph); +#endif + } + } +} \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs.meta b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs.meta new file mode 100644 index 0000000..a1a18f5 --- /dev/null +++ b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 1fc1fb7db9f7ad54a87d31313e7f457d \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs index ae876a8..749b3d5 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs @@ -1,103 +1,103 @@ -using UnityEditor; -using UnityEditor.UIElements; -using UnityEngine; -using UnityEngine.UIElements; - -[CustomEditor(typeof(NanoBrainComponent))] -public class NanoBrainComponent_Editor : Editor { - protected static VisualElement mainContainer; - protected static VisualElement inspectorContainer; - - protected NanoBrainComponent component; - private SerializedProperty brainProp; - - public void OnEnable() { - component = target as NanoBrainComponent; - - if (Application.isPlaying == false) - brainProp = serializedObject.FindProperty(nameof(NanoBrainComponent.defaultBrain)); - } - - public override VisualElement CreateInspectorGUI() { - //NanoBrainComponent component = target as NanoBrainComponent; - NanoBrain brain = Application.isPlaying ? component.brain : component.defaultBrain; - - if (Application.isPlaying == false) - serializedObject.Update(); - - - VisualElement root = new(); - root.style.flexDirection = FlexDirection.Column; // side-by-side layout - root.style.flexGrow = 1; - root.style.minHeight = 600; - root.style.paddingLeft = 0; - root.style.paddingRight = 0; - root.style.paddingTop = 0; - root.style.paddingBottom = 0; - - root.styleSheets.Add(Resources.Load("GraphStyles")); - - if (Application.isPlaying == false) { - PropertyField brainField = new(brainProp) { - label = "Nano Brain" - }; - root.Add(brainField); - } - - mainContainer = new() { - name = "main", - style = { - flexDirection = FlexDirection.Row, - flexGrow = 1, - minHeight = 500, - } - }; - NanoBrainInspector.GraphView board; - board = new NanoBrainInspector.GraphView(); - board.style.flexGrow = 1; - - inspectorContainer = new VisualElement { - name = "inspector", - style = { - width = 400, - } - }; - - mainContainer.Add(board); - mainContainer.Add(inspectorContainer); - root.Add(mainContainer); - - // Run once for initial state (use resolved style width if available) - float initialWidth = root.layout.width > 0 ? root.layout.width : root.contentRect.width; - UpdateLayout(initialWidth); - - // React to size changes of root (or parent if appropriate) - root.RegisterCallback(evt => { - UpdateLayout(evt.newRect.width); - }); - - if (brain != null) - board.SetGraph(component.gameObject, brain, brain.root, inspectorContainer); - // else - // Debug.LogWarning(" No brain!"); - - if (Application.isPlaying == false) - serializedObject.ApplyModifiedProperties(); - return root; - } - - private void UpdateLayout(float containerWidth) { - if (containerWidth > 800f) { - mainContainer.style.flexDirection = FlexDirection.Row; - inspectorContainer.style.width = 400; // fixed sidebar width - inspectorContainer.style.flexGrow = 0; - } - else { - mainContainer.style.flexDirection = FlexDirection.Column; - inspectorContainer.style.width = Length.Percent(100); // full width below - inspectorContainer.style.flexDirection = FlexDirection.Column; - inspectorContainer.style.flexGrow = 1; // can set 0 or keep as needed - } - } - +using UnityEditor; +using UnityEditor.UIElements; +using UnityEngine; +using UnityEngine.UIElements; + +[CustomEditor(typeof(NanoBrainComponent))] +public class NanoBrainComponent_Editor : Editor { + protected static VisualElement mainContainer; + protected static VisualElement inspectorContainer; + + protected NanoBrainComponent component; + private SerializedProperty brainProp; + + public void OnEnable() { + component = target as NanoBrainComponent; + + if (Application.isPlaying == false) + brainProp = serializedObject.FindProperty(nameof(NanoBrainComponent.defaultBrain)); + } + + public override VisualElement CreateInspectorGUI() { + //NanoBrainComponent component = target as NanoBrainComponent; + NanoBrain brain = Application.isPlaying ? component.brain : component.defaultBrain; + + if (Application.isPlaying == false) + serializedObject.Update(); + + + VisualElement root = new(); + root.style.flexDirection = FlexDirection.Column; // side-by-side layout + root.style.flexGrow = 1; + root.style.minHeight = 600; + root.style.paddingLeft = 0; + root.style.paddingRight = 0; + root.style.paddingTop = 0; + root.style.paddingBottom = 0; + + root.styleSheets.Add(Resources.Load("GraphStyles")); + + if (Application.isPlaying == false) { + PropertyField brainField = new(brainProp) { + label = "Nano Brain" + }; + root.Add(brainField); + } + + mainContainer = new() { + name = "main", + style = { + flexDirection = FlexDirection.Row, + flexGrow = 1, + minHeight = 500, + } + }; + NanoBrainInspector.GraphView board; + board = new NanoBrainInspector.GraphView(); + board.style.flexGrow = 1; + + inspectorContainer = new VisualElement { + name = "inspector", + style = { + width = 400, + } + }; + + mainContainer.Add(board); + mainContainer.Add(inspectorContainer); + root.Add(mainContainer); + + // Run once for initial state (use resolved style width if available) + float initialWidth = root.layout.width > 0 ? root.layout.width : root.contentRect.width; + UpdateLayout(initialWidth); + + // React to size changes of root (or parent if appropriate) + root.RegisterCallback(evt => { + UpdateLayout(evt.newRect.width); + }); + + if (brain != null) + board.SetGraph(component.gameObject, brain, brain.output, inspectorContainer); + // else + // Debug.LogWarning(" No brain!"); + + if (Application.isPlaying == false) + serializedObject.ApplyModifiedProperties(); + return root; + } + + private void UpdateLayout(float containerWidth) { + if (containerWidth > 800f) { + mainContainer.style.flexDirection = FlexDirection.Row; + inspectorContainer.style.width = 400; // fixed sidebar width + inspectorContainer.style.flexGrow = 0; + } + else { + mainContainer.style.flexDirection = FlexDirection.Column; + inspectorContainer.style.width = Length.Percent(100); // full width below + inspectorContainer.style.flexDirection = FlexDirection.Column; + inspectorContainer.style.flexGrow = 1; // can set 0 or keep as needed + } + } + } \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs index 8cd7114..7290c03 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs @@ -59,7 +59,7 @@ public class NanoBrainInspector : Editor { }); if (brain != null) - graph.SetGraph(null, brain, brain.root, inspectorContainer); + graph.SetGraph(null, brain, brain.output, inspectorContainer); else Debug.LogWarning(" No brain!"); @@ -70,10 +70,10 @@ public class NanoBrainInspector : Editor { public class GraphView : VisualElement { NanoBrain brain; SerializedObject serializedBrain; - Nucleus currentNucleus; + INucleus currentNucleus; GameObject gameObject; private List layers = new(); - private readonly Dictionary neuroidPositions = new(); + private readonly Dictionary neuroidPositions = new(); Vector2 pan = Vector2.zero; //float zoom = 1f; @@ -127,14 +127,14 @@ public class NanoBrainInspector : Editor { this.layers = new(); int layerIx = 0; - Nucleus selectedNucleus = this.currentNucleus; + INucleus selectedNucleus = this.currentNucleus; if (selectedNucleus == null) return; NeuroidLayer currentLayer = new() { ix = layerIx }; if (selectedNucleus.receivers != null) { foreach (Receiver receiver in selectedNucleus.receivers) { - Nucleus outputNeuroid = receiver.nucleus; + INucleus outputNeuroid = receiver.nucleus; if (outputNeuroid != null) { AddToLayer(currentLayer, outputNeuroid); // Debug.Log($"layer {layerIx} nucleus {outputNeuroid.name}"); @@ -156,7 +156,7 @@ public class NanoBrainInspector : Editor { if (selectedNucleus.synapses != null) { foreach (Synapse synapse in selectedNucleus.synapses) { - Nucleus input = synapse.nucleus; + INucleus input = synapse.nucleus; AddToLayer(currentLayer, input); // Debug.Log($"layer {layerIx} nucleus {input.name}"); } @@ -166,11 +166,11 @@ public class NanoBrainInspector : Editor { } } - private void AddToLayer(NeuroidLayer layer, Nucleus nucleus) { + private void AddToLayer(NeuroidLayer layer, INucleus nucleus) { if (nucleus == null) return; layer.neuroids.Add(nucleus); - nucleus.layerIx = layer.ix; + //nucleus.layerIx = layer.ix; // Store its position Vector2Int neuroidPosition = new(layer.ix, layer.neuroids.Count - 1); neuroidPositions[nucleus] = neuroidPosition; @@ -217,7 +217,7 @@ public class NanoBrainInspector : Editor { DrawNucleus(this.currentNucleus, position, this.currentNucleus.outputValue.magnitude, 20); } - private void DrawReceivers(Nucleus nucleus, Vector3 parentPos, float size) { + private void DrawReceivers(INucleus nucleus, Vector3 parentPos, float size) { int nodeCount = nucleus.receivers.Count; // Determine the maximum value in this layer @@ -237,7 +237,7 @@ public class NanoBrainInspector : Editor { int row = 0; foreach (Receiver receiver in nucleus.receivers) { - Nucleus receiverNucleus = receiver.nucleus; + INucleus receiverNucleus = receiver.nucleus; if (receiverNucleus == null) continue; @@ -250,7 +250,7 @@ public class NanoBrainInspector : Editor { } } - private void DrawSynapses(Nucleus nucleus, Vector3 parentPos, float size) { + private void DrawSynapses(INucleus nucleus, Vector3 parentPos, float size) { int nodeCount = nucleus.synapses.Count; // Determine the maximum value in this layer @@ -290,7 +290,7 @@ public class NanoBrainInspector : Editor { } } - private void DrawNucleus(Nucleus nucleus, Vector3 position, float maxValue, float size) { + private void DrawNucleus(INucleus nucleus, Vector3 position, float maxValue, float size) { if (nucleus.isSleeping) Handles.color = Color.darkRed; else { @@ -358,7 +358,7 @@ public class NanoBrainInspector : Editor { // To do: add HandleClick (see above) to expand the array } - private void HandleMouseHover(Nucleus nucleus, Rect rect) { + private void HandleMouseHover(INucleus nucleus, Rect rect) { GUIContent tooltip; if (nucleus is Perceptoid perceptoid) { if (perceptoid.receptor != null) { @@ -391,7 +391,7 @@ public class NanoBrainInspector : Editor { GUI.Box(tooltipRect, tooltip); } - private void HandleClicked(Nucleus nucleus) { + private void HandleClicked(INucleus nucleus) { this.currentNucleus = nucleus; BuildLayers(); } @@ -484,6 +484,8 @@ public class NanoBrainInspector : Editor { AddInputNeuron(this.currentNucleus); if (GUILayout.Button("Add Input Perceptoid")) AddPerceptoid(this.currentNucleus); + if (GUILayout.Button("Add Input Cluster")) + AddCluster(this.currentNucleus); EditorGUILayout.Space(); @@ -501,18 +503,18 @@ public class NanoBrainInspector : Editor { inspectorContainer.Add(container); } - protected virtual void AddInputNeuron(Nucleus nucleus) { - Neuroid newNeuroid = new(this.brain, "New neuron"); + protected virtual void AddInputNeuron(INucleus nucleus) { + Neuroid newNeuroid = new(this.brain.cluster, "New neuron"); newNeuroid.AddReceiver(nucleus); this.currentNucleus = newNeuroid; BuildLayers(); } - protected virtual void DeleteNeuron(Nucleus nucleus) { + protected virtual void DeleteNeuron(INucleus nucleus) { if (nucleus == null) return; - if (nucleus.brain != null) - this.currentNucleus = nucleus.brain.root; + if (nucleus.cluster != null) + this.currentNucleus = nucleus.cluster.output; foreach (Receiver receiver in nucleus.receivers) { if (receiver.nucleus != null) { this.currentNucleus = receiver.nucleus; @@ -523,42 +525,55 @@ public class NanoBrainInspector : Editor { BuildLayers(); } - protected virtual void AddPerceptoid(Nucleus nucleus) { + protected virtual void AddPerceptoid(INucleus nucleus) { Perceptoid newPerceptoid = new(this.brain, 0, "New Perceptoid"); newPerceptoid.AddReceiver(nucleus); this.currentNucleus = newPerceptoid; BuildLayers(); } - protected virtual void ConnectNucleus(Nucleus nucleus) { - if (this.currentNucleus.brain == null) + protected virtual void AddCluster(INucleus nucleus) { + BrainPickerWindow.ShowPicker(brain => OnClusterPicked(nucleus, brain), "Select Cluster"); + } + + private void OnClusterPicked(INucleus nucleus, NanoBrain brain) { + NanoBrain brainInstance = Instantiate(brain); + brainInstance.AddReceiver(nucleus); + } + + protected virtual void ConnectNucleus(INucleus nucleus) { + if (this.currentNucleus.cluster == null) return; IEnumerable synapseNuclei = this.currentNucleus.synapses.Select(synapse => synapse.nucleus.name); - IEnumerable perceptei = this.currentNucleus.brain.perceptei.Select(i => i.name).Except(synapseNuclei); - IEnumerable nuclei = this.currentNucleus.brain.nuclei.Select(i => i.name).Except(synapseNuclei); - string[] names = perceptei.Concat(nuclei).ToArray(); + //IEnumerable perceptei = this.currentNucleus.brain.perceptei.Select(i => i.name).Except(synapseNuclei); + IEnumerable nuclei = this.currentNucleus.cluster.nuclei.Select(i => i.name).Except(synapseNuclei); + //string[] names = perceptei.Concat(nuclei).ToArray(); + string[] names = nuclei.ToArray(); int selectedIndex = -1; selectedIndex = EditorGUILayout.Popup("Connect to", selectedIndex, names); if (selectedIndex >= 0) { - if (selectedIndex < perceptei.Count()) { - Nucleus n = this.currentNucleus.brain.perceptei[selectedIndex]; + // if (selectedIndex < perceptei.Count()) { + // Nucleus n = this.currentNucleus.brain.perceptei[selectedIndex]; + // n.AddReceiver(this.currentNucleus); + // } + // else { + // Nucleus n = this.currentNucleus.brain.nuclei[selectedIndex - perceptei.Count()]; + // n.AddReceiver(this.currentNucleus); + // } + Nucleus n = this.currentNucleus.cluster.nuclei[selectedIndex]; n.AddReceiver(this.currentNucleus); - } - else { - Nucleus n = this.currentNucleus.brain.nuclei[selectedIndex - perceptei.Count()]; - n.AddReceiver(this.currentNucleus); - } } } protected virtual void DisconnectNucleus(Nucleus nucleus) { - if (this.currentNucleus.brain == null) + if (this.currentNucleus.cluster == null) return; string[] names = this.currentNucleus.synapses.Select(synapse => synapse.nucleus.name).ToArray(); int selectedIndex = -1; selectedIndex = EditorGUILayout.Popup("Disconnect from", selectedIndex, names); - if (selectedIndex >= 0 && selectedIndex < this.currentNucleus.brain.perceptei.Count) { + //if (selectedIndex >= 0 && selectedIndex < this.currentNucleus.brain.perceptei.Count) { + if (selectedIndex >= 0 && selectedIndex < this.currentNucleus.cluster.nuclei.Count) { Synapse synapse = this.currentNucleus.synapses[selectedIndex]; synapse.nucleus.RemoveReceiver(this.currentNucleus); } @@ -586,23 +601,30 @@ public class NanoBrainInspector : Editor { #endregion Update } +/* +public class NeuroidLayer { + public int ix = 0; + public List neuroids = new(); +} +*/ + public class GraphNodeWrapper : ScriptableObject { // expose fields that map to GraphNode - public string title; + //public string title; public Vector2 position; - Nucleus node; + INucleus node; NanoBrain graph; // needed to write back and mark dirty - public GraphNodeWrapper Init(Nucleus node, NanoBrain graphAsset) { + public GraphNodeWrapper Init(INucleus node, NanoBrain graphAsset) { this.node = node; this.graph = graphAsset; - this.title = " A " + node.name; + //this.title = " A " + node.name; //position = node.position; return this; } void OnValidate() { if (node != null) { - node.name = title; + //node.name = title; //node.position = position; #if UNITY_EDITOR if (graph != null) @@ -610,4 +632,4 @@ public class GraphNodeWrapper : ScriptableObject { #endif } } -} \ No newline at end of file +} diff --git a/Assets/NanoBrain/VisualEditor/NanoBrain.cs b/Assets/NanoBrain/VisualEditor/NanoBrain.cs index 93e5c00..c581ec6 100644 --- a/Assets/NanoBrain/VisualEditor/NanoBrain.cs +++ b/Assets/NanoBrain/VisualEditor/NanoBrain.cs @@ -1,92 +1,95 @@ -using System.Collections.Generic; -using UnityEngine; - -[CreateAssetMenu(menuName = "Passer/NanoBrain")] -public class NanoBrain : ScriptableObject, ISerializationCallbackReceiver { - - public string title; - public int count; - public Color color = Color.white; - public Texture2D texture; - - public List nuclei = new(); - public List perceptei = new(); - public List receptors = new(); - - // This is probably always the first element in the nuclei list... - [System.NonSerialized] - public Nucleus root; - public int rootId; - - public NanoBrain() { - this.root = new Neuroid(this, "Root"); - } - - public Neuroid AddNeuron(string name) { - Neuroid neuroid = new(this, name); - return neuroid; - } - - public void UpdateNuclei() { - foreach (Nucleus nucleus in nuclei) - nucleus.IncreaseAge(); - foreach (Perceptoid perception in perceptei) - perception.IncreaseAge(); - } - - public void OnBeforeSerialize() { - this.rootId = root.id; - } - public void OnAfterDeserialize() { - try { - foreach (Nucleus nucleus in this.nuclei.ToArray()) { - if (this.rootId == nucleus.id) - this.root = nucleus; - nucleus.Rebuild(this); - } - - foreach (Perceptoid perceptoid in this.perceptei.ToArray()) - perceptoid.Rebuild(this); - } - catch (System.Exception) { } - this.GarbageCollection(); - } - - public void GarbageCollection() { - HashSet visitedNuclei = new(); - MarkNuclei(visitedNuclei, this.root); - //Debug.Log($"Garbage collection found {visitedNuclei.Count} Nuclei"); - this.nuclei.RemoveAll(nucleus => visitedNuclei.Contains(nucleus) == false); - this.perceptei.RemoveAll(perceptoid => visitedNuclei.Contains(perceptoid) == false); - } - - public void MarkNuclei(HashSet visitedNuclei, Nucleus nucleus) { - if (nucleus is null) - return; - - if (nucleus.brain == null) - nucleus.brain = this; - - visitedNuclei.Add(nucleus); - if (nucleus.synapses != null) { - HashSet visitedSynapses = new(); - foreach (Synapse synapse in nucleus.synapses) { - if (synapse != null && synapse.nucleus != null) { - visitedSynapses.Add(synapse); - MarkNuclei(visitedNuclei, synapse.nucleus); - } - } - nucleus.synapses.RemoveAll(synapse => visitedSynapses.Contains(synapse) == false); - } - if (nucleus.receivers != null) { - HashSet visitedReceivers = new(); - foreach (Receiver receiver in nucleus.receivers) { - if (receiver != null && receiver.nucleus != null) { - visitedReceivers.Add(receiver); - visitedNuclei.Add(receiver.nucleus); - } - } - nucleus.receivers.RemoveAll(receiver => visitedReceivers.Contains(receiver) == false); - } - } +using System.Collections.Generic; +using UnityEngine; + +[CreateAssetMenu(menuName = "Passer/NanoBrain")] +public class NanoBrain : ScriptableObject, ISerializationCallbackReceiver { + public List nuclei = new(); + public List perceptei = new(); + public List receptors = new(); + + public Cluster cluster; + + // This is probably always the first element in the nuclei list... + [System.NonSerialized] + public Nucleus output; + public int rootId; + + public NanoBrain() { + this.output = new Neuroid(this.cluster, "Root"); + this.cluster = new(); + } + + public void AddReceiver(INucleus receiver) { + output.AddReceiver(receiver); + } + + public Neuroid AddNeuron(string name) { + Neuroid neuroid = new(this.cluster, name); + return neuroid; + } + + public void UpdateNuclei() { + foreach (Nucleus nucleus in nuclei) + nucleus.IncreaseAge(); + foreach (Perceptoid perception in perceptei) + perception.IncreaseAge(); + } + + public void OnBeforeSerialize() { + this.rootId = output.id; + } + public void OnAfterDeserialize() { + try { + foreach (Nucleus nucleus in this.nuclei.ToArray()) { + if (this.rootId == nucleus.id) + this.output = nucleus; + nucleus.Rebuild(this); + } + + foreach (Perceptoid perceptoid in this.perceptei.ToArray()) + perceptoid.Rebuild(this); + } + catch (System.Exception) { } + this.cluster.GarbageCollection(); + } + +/* + public void GarbageCollection() { + HashSet visitedNuclei = new(); + MarkNuclei(visitedNuclei, this.output); + //Debug.Log($"Garbage collection found {visitedNuclei.Count} Nuclei"); + this.nuclei.RemoveAll(nucleus => visitedNuclei.Contains(nucleus) == false); + this.perceptei.RemoveAll(perceptoid => visitedNuclei.Contains(perceptoid) == false); + } + + public void MarkNuclei(HashSet visitedNuclei, INucleus nucleus) { + if (nucleus is null) + return; + + if (nucleus.brain == null) + nucleus.brain = this; + + visitedNuclei.Add(nucleus); + if (nucleus.synapses != null) { + HashSet visitedSynapses = new(); + foreach (Synapse synapse in nucleus.synapses) { + if (synapse != null && synapse.nucleus != null) { + visitedSynapses.Add(synapse); + MarkNuclei(visitedNuclei, synapse.nucleus); + } + } + nucleus.synapses.RemoveAll(synapse => visitedSynapses.Contains(synapse) == false); + } + if (nucleus.receivers != null) { + HashSet visitedReceivers = new(); + foreach (Receiver receiver in nucleus.receivers) { + if (receiver != null && receiver.nucleus != null) { + visitedReceivers.Add(receiver); + visitedNuclei.Add(receiver.nucleus); + } + } + nucleus.receivers.RemoveAll(receiver => visitedReceivers.Contains(receiver) == false); + } + } + */ } \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs b/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs index bdeda86..5be46f1 100644 --- a/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs +++ b/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs @@ -1,33 +1,33 @@ -using UnityEngine; - -public class NanoBrainComponent : MonoBehaviour { - public NanoBrain defaultBrain; - private NanoBrain brainInstance; - - public Nucleus root => brainInstance.root; - public NanoBrain brain { - get { - if (brainInstance == null && defaultBrain != null) { - brainInstance = Instantiate(defaultBrain); - brainInstance.name = defaultBrain.name + " (Instance)"; - - SwarmControl sc = FindFirstObjectByType(); - UpdateWeight(brainInstance, "Avoidance", sc.avoidanceForce); - UpdateWeight(brainInstance, "Cohesion", sc.cohesionForce); - UpdateWeight(brainInstance, "Separation", sc.separationForce); - UpdateWeight(brainInstance, "Alignment", sc.alignmentForce); - } - return brainInstance; - } - } - - public static void UpdateWeight(NanoBrain brain, string name, float weight) { - Nucleus root = brain.root; - foreach (Synapse synapse in root.synapses) { - if (synapse.nucleus.name == name) { - synapse.weight = weight; - } - } - } - +using UnityEngine; + +public class NanoBrainComponent : MonoBehaviour { + public NanoBrain defaultBrain; + private NanoBrain brainInstance; + + public Nucleus root => brainInstance.output; + public NanoBrain brain { + get { + if (brainInstance == null && defaultBrain != null) { + brainInstance = Instantiate(defaultBrain); + brainInstance.name = defaultBrain.name + " (Instance)"; + + SwarmControl sc = FindFirstObjectByType(); + UpdateWeight(brainInstance, "Avoidance", sc.avoidanceForce); + UpdateWeight(brainInstance, "Cohesion", sc.cohesionForce); + UpdateWeight(brainInstance, "Separation", sc.separationForce); + UpdateWeight(brainInstance, "Alignment", sc.alignmentForce); + } + return brainInstance; + } + } + + public static void UpdateWeight(NanoBrain brain, string name, float weight) { + Nucleus root = brain.output; + foreach (Synapse synapse in root.synapses) { + if (synapse.nucleus.name == name) { + synapse.weight = weight; + } + } + } + } \ No newline at end of file diff --git a/Assets/Scenes/Boids/New Cluster 1.asset b/Assets/Scenes/Boids/New Cluster 1.asset new file mode 100644 index 0000000..c46baec --- /dev/null +++ b/Assets/Scenes/Boids/New Cluster 1.asset @@ -0,0 +1,20 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3} + m_Name: New Cluster 1 + m_EditorClassIdentifier: Assembly-CSharp::Cluster + nuclei: + - id: 949579472 + _name: Output + _synapses: [] + _receivers: [] + nucleusType: diff --git a/Assets/Scenes/Boids/Identity.asset.meta b/Assets/Scenes/Boids/New Cluster 1.asset.meta similarity index 79% rename from Assets/Scenes/Boids/Identity.asset.meta rename to Assets/Scenes/Boids/New Cluster 1.asset.meta index 9797408..fcb368b 100644 --- a/Assets/Scenes/Boids/Identity.asset.meta +++ b/Assets/Scenes/Boids/New Cluster 1.asset.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 5040f18b0515ba23eb0782d6f6794054 +guid: ad89de17be687dbc18a57252cadda0f3 NativeFormatImporter: externalObjects: {} mainObjectFileID: 11400000 diff --git a/Assets/Scenes/Boids/New Cluster.asset b/Assets/Scenes/Boids/New Cluster.asset new file mode 100644 index 0000000..fe0b8a4 --- /dev/null +++ b/Assets/Scenes/Boids/New Cluster.asset @@ -0,0 +1,15 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3} + m_Name: New Cluster + m_EditorClassIdentifier: Assembly-CSharp::Cluster + nuclei: [] diff --git a/Assets/Scenes/Boids/New Cluster.asset.meta b/Assets/Scenes/Boids/New Cluster.asset.meta new file mode 100644 index 0000000..575238a --- /dev/null +++ b/Assets/Scenes/Boids/New Cluster.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: eddc759ede59e66cd936ad6ae2c55c46 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/Boids/Identity.asset b/Assets/Scenes/Boids/New Nano Brain.asset similarity index 94% rename from Assets/Scenes/Boids/Identity.asset rename to Assets/Scenes/Boids/New Nano Brain.asset index 94f63d4..5251743 100644 --- a/Assets/Scenes/Boids/Identity.asset +++ b/Assets/Scenes/Boids/New Nano Brain.asset @@ -10,14 +10,14 @@ MonoBehaviour: m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 36081359186edfec998d891a1feeb17b, type: 3} - m_Name: Identity + m_Name: New Nano Brain m_EditorClassIdentifier: Assembly-CSharp::NanoBrain title: count: 0 color: {r: 1, g: 1, b: 1, a: 1} texture: {fileID: 0} nuclei: - - id: 1707104464 + - id: 2025140912 _name: Root synapses: [] receivers: [] @@ -53,7 +53,7 @@ MonoBehaviour: inverse: 0 exponent: 1 perceptei: [] - rootId: 1707104464 + rootId: 2025140912 references: version: 2 RefIds: [] diff --git a/Assets/Scenes/Boids/New Nano Brain.asset.meta b/Assets/Scenes/Boids/New Nano Brain.asset.meta new file mode 100644 index 0000000..cc404a1 --- /dev/null +++ b/Assets/Scenes/Boids/New Nano Brain.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fab876d6bf7dc9b10a56541a7eeccdd2 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: From beb88f82148eaca6c06eac5476fb6527d5a4f7a3 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 12 Jan 2026 09:56:49 +0100 Subject: [PATCH 061/179] WIP cluster redesign --- Assets/NanoBrain/Cluster.cs | 22 +- Assets/NanoBrain/INucleus.cs | 1 + .../NanoBrain/LinearAlgebra/src/Spherical.cs | 10 + Assets/NanoBrain/Nucleus.cs | 21 +- .../VisualEditor/Editor/ClusterInspector.cs | 23 +- Assets/NanoBrain/VisualEditor/NanoBrain.cs | 89 +-- Assets/Scenes/Boids/New Cluster 1.asset | 20 - Assets/Scenes/Boids/New Cluster 1.asset.meta | 8 - Assets/Scenes/Boids/New Cluster.asset | 7 +- Assets/Scenes/Boids/New Nano Brain.asset | 59 -- Assets/Scenes/Boids/New Nano Brain.asset.meta | 8 - Assets/Scenes/Boids/SwarmingBrain.asset | 523 ++++++++++-------- 12 files changed, 410 insertions(+), 381 deletions(-) delete mode 100644 Assets/Scenes/Boids/New Cluster 1.asset delete mode 100644 Assets/Scenes/Boids/New Cluster 1.asset.meta delete mode 100644 Assets/Scenes/Boids/New Nano Brain.asset delete mode 100644 Assets/Scenes/Boids/New Nano Brain.asset.meta diff --git a/Assets/NanoBrain/Cluster.cs b/Assets/NanoBrain/Cluster.cs index 991c44e..5b349e1 100644 --- a/Assets/NanoBrain/Cluster.cs +++ b/Assets/NanoBrain/Cluster.cs @@ -4,11 +4,11 @@ using UnityEngine; [CreateAssetMenu(menuName = "Passer/Cluster")] public class Cluster : ScriptableObject, INucleus { - private string _name; - public string name { - get { return _name; } - set { _name = value; } - } + // private string _name; + // public new string name { + // get { return _name; } + // set { _name = value; } + // } public Cluster cluster => this; @@ -16,10 +16,14 @@ public class Cluster : ScriptableObject, INucleus { public Nucleus output => this.nuclei[0]; + [SerializeField] private readonly List _synapses = new(); // = inputs, compare receptors in NanoBrain public List synapses => _synapses; - private void OnEnable() { + // Call this function to ensure that there is at least one nucleus + // This is an invariant and should be ensured before the nucleus is used + // because output requires it. + public void EnsureInitialization() { nuclei ??= new List(); if (nuclei.Count == 0) new Neuroid(this, "Output"); // Every cluster should have at least 1 neuroid @@ -36,6 +40,11 @@ public class Cluster : ScriptableObject, INucleus { get => output.receivers; } + public void AddSynapse(INucleus sender) { + Synapse synapse = new (sender, 1.0f); + synapses.Add(synapse); + } + public void GarbageCollection() { HashSet visitedNuclei = new(); MarkNuclei(visitedNuclei, this.output); @@ -79,6 +88,7 @@ public class Cluster : ScriptableObject, INucleus { public void UpdateState() { // Don't know if this is right this.output.UpdateState(); + // it is not, I should take inputs from the synapses and route them to the right internal nuclei } #endregion Dynamics diff --git a/Assets/NanoBrain/INucleus.cs b/Assets/NanoBrain/INucleus.cs index 757f8ef..46d424a 100644 --- a/Assets/NanoBrain/INucleus.cs +++ b/Assets/NanoBrain/INucleus.cs @@ -17,6 +17,7 @@ public interface INucleus { // Senders public List synapses { get; } + public void AddSynapse(INucleus sender); #endregion static struct diff --git a/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs b/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs index aee6a64..318839d 100644 --- a/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs +++ b/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs @@ -148,6 +148,16 @@ namespace LinearAlgebra { return (v1.distance != v2.distance || v1.direction != v2.direction); } + public override readonly bool Equals(object o) { + if (o is Spherical s) + return this == s; + return false; + } + + public override readonly int GetHashCode() { + return HashCode.Combine(this.distance, this.direction); + } + public static float Distance(Spherical v1, Spherical v2) { // Convert degrees to radians float thetaARadians = v1.direction.horizontal.inRadians; diff --git a/Assets/NanoBrain/Nucleus.cs b/Assets/NanoBrain/Nucleus.cs index 79c05cb..601c462 100644 --- a/Assets/NanoBrain/Nucleus.cs +++ b/Assets/NanoBrain/Nucleus.cs @@ -95,9 +95,10 @@ public class Nucleus : INucleus { this.id = this.GetHashCode(); } - public virtual void AddReceiver(INucleus receiver) { - this.receivers.Add(new Receiver(receiver)); - //receiver.SetWeight(this, 1.0f); + public virtual void AddReceiver(INucleus receivingNucleus) { + this.receivers.Add(new Receiver(receivingNucleus)); + //receivingNucleus.SetWeight(this, 1.0f); + receivingNucleus.AddSynapse(this); } public void RemoveReceiver(INucleus receiverNucleus) { @@ -140,6 +141,10 @@ public class Nucleus : INucleus { return false; } + public void AddSynapse(INucleus sendingNucleus) { + Synapse synapse = new(sendingNucleus, 1.0f); + this.synapses.Add(synapse); + } public void SetWeight(Nucleus nucleus, float weight) { foreach (Synapse synapse in synapses) { if (synapse.nucleus == nucleus) { @@ -167,11 +172,11 @@ public class Nucleus : INucleus { } } -[System.Serializable] +[Serializable] public class Synapse { - [System.NonSerialized] + [NonSerialized] public INucleus nucleus; - public NanoBrain cluster; + public Cluster cluster; public int nucleusId; public float weight; @@ -186,9 +191,9 @@ public class Synapse { // public AnimationCurve curve; public float curveMax = 1.0f; - public Synapse(Nucleus nucleus, float weight) { + public Synapse(INucleus nucleus, float weight) { this.nucleus = nucleus; - this.nucleusId = nucleus.id; + //this.nucleusId = nucleus.id; this.weight = weight; } diff --git a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs index e078ad1..bd681fa 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs @@ -58,8 +58,10 @@ public class ClusterInspector : Editor { UpdateLayout(evt.newRect.width); }); - if (cluster != null) + if (cluster != null) { + cluster.EnsureInitialization(); graph.SetGraph(null, cluster, cluster.output, inspectorContainer); + } else Debug.LogWarning(" No brain!"); @@ -68,7 +70,7 @@ public class ClusterInspector : Editor { } public class GraphView : VisualElement { - Cluster brain; + Cluster cluster; SerializedObject serializedBrain; INucleus currentNucleus; GameObject gameObject; @@ -101,7 +103,7 @@ public class ClusterInspector : Editor { public void SetGraph(GameObject gameObject, Cluster brain, Nucleus nucleus, VisualElement inspectorContainer) { this.gameObject = gameObject; - this.brain = brain; + this.cluster = brain; if (Application.isPlaying == false) this.serializedBrain = new SerializedObject(brain); this.currentNucleus = nucleus; @@ -118,7 +120,7 @@ public class ClusterInspector : Editor { if (currentWrapper != null) DestroyImmediate(currentWrapper); - currentWrapper = CreateInstance().Init(this.currentNucleus, brain); + currentWrapper = CreateInstance().Init(this.currentNucleus, cluster); DrawInspector(inspectorContainer); } @@ -479,7 +481,7 @@ public class ClusterInspector : Editor { EditorGUILayout.Space(); - ConnectNucleus(this.currentNucleus); + ConnectNucleus(cluster, this.currentNucleus); if (GUILayout.Button("Add Input Neuron")) AddInputNeuron(this.currentNucleus); // if (GUILayout.Button("Add Input Perceptoid")) @@ -504,7 +506,7 @@ public class ClusterInspector : Editor { } protected virtual void AddInputNeuron(INucleus nucleus) { - Neuroid newNeuroid = new(this.brain.cluster, "New neuron"); + Neuroid newNeuroid = new(this.cluster.cluster, "New neuron"); newNeuroid.AddReceiver(nucleus); this.currentNucleus = newNeuroid; BuildLayers(); @@ -541,13 +543,14 @@ public class ClusterInspector : Editor { brainInstance.AddReceiver(nucleus); } - protected virtual void ConnectNucleus(INucleus nucleus) { - if (this.currentNucleus.cluster == null) + // Connect to another nucleus in the same cluster + protected virtual void ConnectNucleus(Cluster cluster, INucleus nucleus) { + if (cluster == null) return; IEnumerable synapseNuclei = this.currentNucleus.synapses.Select(synapse => synapse.nucleus.name); //IEnumerable perceptei = this.currentNucleus.brain.perceptei.Select(i => i.name).Except(synapseNuclei); - IEnumerable nuclei = this.currentNucleus.cluster.nuclei.Select(i => i.name).Except(synapseNuclei); + IEnumerable nuclei = cluster.nuclei.Select(i => i.name).Except(synapseNuclei); //string[] names = perceptei.Concat(nuclei).ToArray(); string[] names = nuclei.ToArray(); int selectedIndex = -1; @@ -561,7 +564,7 @@ public class ClusterInspector : Editor { // Nucleus n = this.currentNucleus.brain.nuclei[selectedIndex - perceptei.Count()]; // n.AddReceiver(this.currentNucleus); // } - Nucleus n = this.currentNucleus.cluster.nuclei[selectedIndex]; + Nucleus n = cluster.nuclei[selectedIndex]; n.AddReceiver(this.currentNucleus); } } diff --git a/Assets/NanoBrain/VisualEditor/NanoBrain.cs b/Assets/NanoBrain/VisualEditor/NanoBrain.cs index c581ec6..8ac0896 100644 --- a/Assets/NanoBrain/VisualEditor/NanoBrain.cs +++ b/Assets/NanoBrain/VisualEditor/NanoBrain.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using UnityEngine; @@ -7,7 +8,6 @@ public class NanoBrain : ScriptableObject, ISerializationCallbackReceiver { public List perceptei = new(); public List receptors = new(); - public Cluster cluster; // This is probably always the first element in the nuclei list... [System.NonSerialized] @@ -15,9 +15,11 @@ public class NanoBrain : ScriptableObject, ISerializationCallbackReceiver { public int rootId; public NanoBrain() { - this.output = new Neuroid(this.cluster, "Root"); - this.cluster = new(); - } + // this.cluster = new(); + // this.output = new Neuroid(this.cluster, "Root"); + } + + public Cluster cluster; public void AddReceiver(INucleus receiver) { output.AddReceiver(receiver); @@ -30,9 +32,9 @@ public class NanoBrain : ScriptableObject, ISerializationCallbackReceiver { public void UpdateNuclei() { foreach (Nucleus nucleus in nuclei) - nucleus.IncreaseAge(); + nucleus.IncreaseAge(); foreach (Perceptoid perception in perceptei) - perception.IncreaseAge(); + perception.IncreaseAge(); } public void OnBeforeSerialize() { @@ -47,49 +49,50 @@ public class NanoBrain : ScriptableObject, ISerializationCallbackReceiver { } foreach (Perceptoid perceptoid in this.perceptei.ToArray()) - perceptoid.Rebuild(this); + perceptoid.Rebuild(this); } catch (System.Exception) { } - this.cluster.GarbageCollection(); + if (this.cluster != null) + this.cluster.GarbageCollection(); } -/* - public void GarbageCollection() { - HashSet visitedNuclei = new(); - MarkNuclei(visitedNuclei, this.output); - //Debug.Log($"Garbage collection found {visitedNuclei.Count} Nuclei"); - this.nuclei.RemoveAll(nucleus => visitedNuclei.Contains(nucleus) == false); - this.perceptei.RemoveAll(perceptoid => visitedNuclei.Contains(perceptoid) == false); - } - - public void MarkNuclei(HashSet visitedNuclei, INucleus nucleus) { - if (nucleus is null) - return; - - if (nucleus.brain == null) - nucleus.brain = this; - - visitedNuclei.Add(nucleus); - if (nucleus.synapses != null) { - HashSet visitedSynapses = new(); - foreach (Synapse synapse in nucleus.synapses) { - if (synapse != null && synapse.nucleus != null) { - visitedSynapses.Add(synapse); - MarkNuclei(visitedNuclei, synapse.nucleus); - } - } - nucleus.synapses.RemoveAll(synapse => visitedSynapses.Contains(synapse) == false); + /* + public void GarbageCollection() { + HashSet visitedNuclei = new(); + MarkNuclei(visitedNuclei, this.output); + //Debug.Log($"Garbage collection found {visitedNuclei.Count} Nuclei"); + this.nuclei.RemoveAll(nucleus => visitedNuclei.Contains(nucleus) == false); + this.perceptei.RemoveAll(perceptoid => visitedNuclei.Contains(perceptoid) == false); } - if (nucleus.receivers != null) { - HashSet visitedReceivers = new(); - foreach (Receiver receiver in nucleus.receivers) { - if (receiver != null && receiver.nucleus != null) { - visitedReceivers.Add(receiver); - visitedNuclei.Add(receiver.nucleus); + + public void MarkNuclei(HashSet visitedNuclei, INucleus nucleus) { + if (nucleus is null) + return; + + if (nucleus.brain == null) + nucleus.brain = this; + + visitedNuclei.Add(nucleus); + if (nucleus.synapses != null) { + HashSet visitedSynapses = new(); + foreach (Synapse synapse in nucleus.synapses) { + if (synapse != null && synapse.nucleus != null) { + visitedSynapses.Add(synapse); + MarkNuclei(visitedNuclei, synapse.nucleus); + } } + nucleus.synapses.RemoveAll(synapse => visitedSynapses.Contains(synapse) == false); + } + if (nucleus.receivers != null) { + HashSet visitedReceivers = new(); + foreach (Receiver receiver in nucleus.receivers) { + if (receiver != null && receiver.nucleus != null) { + visitedReceivers.Add(receiver); + visitedNuclei.Add(receiver.nucleus); + } + } + nucleus.receivers.RemoveAll(receiver => visitedReceivers.Contains(receiver) == false); } - nucleus.receivers.RemoveAll(receiver => visitedReceivers.Contains(receiver) == false); } - } - */ + */ } \ No newline at end of file diff --git a/Assets/Scenes/Boids/New Cluster 1.asset b/Assets/Scenes/Boids/New Cluster 1.asset deleted file mode 100644 index c46baec..0000000 --- a/Assets/Scenes/Boids/New Cluster 1.asset +++ /dev/null @@ -1,20 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3} - m_Name: New Cluster 1 - m_EditorClassIdentifier: Assembly-CSharp::Cluster - nuclei: - - id: 949579472 - _name: Output - _synapses: [] - _receivers: [] - nucleusType: diff --git a/Assets/Scenes/Boids/New Cluster 1.asset.meta b/Assets/Scenes/Boids/New Cluster 1.asset.meta deleted file mode 100644 index fcb368b..0000000 --- a/Assets/Scenes/Boids/New Cluster 1.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: ad89de17be687dbc18a57252cadda0f3 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Scenes/Boids/New Cluster.asset b/Assets/Scenes/Boids/New Cluster.asset index fe0b8a4..4f690b1 100644 --- a/Assets/Scenes/Boids/New Cluster.asset +++ b/Assets/Scenes/Boids/New Cluster.asset @@ -12,4 +12,9 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3} m_Name: New Cluster m_EditorClassIdentifier: Assembly-CSharp::Cluster - nuclei: [] + nuclei: + - id: 764290112 + _name: Output + _synapses: [] + _receivers: [] + nucleusType: diff --git a/Assets/Scenes/Boids/New Nano Brain.asset b/Assets/Scenes/Boids/New Nano Brain.asset deleted file mode 100644 index 5251743..0000000 --- a/Assets/Scenes/Boids/New Nano Brain.asset +++ /dev/null @@ -1,59 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 36081359186edfec998d891a1feeb17b, type: 3} - m_Name: New Nano Brain - m_EditorClassIdentifier: Assembly-CSharp::NanoBrain - title: - count: 0 - color: {r: 1, g: 1, b: 1, a: 1} - texture: {fileID: 0} - nuclei: - - id: 2025140912 - _name: Root - synapses: [] - receivers: [] - nucleusType: - isSleeping: 0 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 1 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1000 - value: 1000 - inSlope: 1 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - perceptei: [] - rootId: 2025140912 - references: - version: 2 - RefIds: [] diff --git a/Assets/Scenes/Boids/New Nano Brain.asset.meta b/Assets/Scenes/Boids/New Nano Brain.asset.meta deleted file mode 100644 index cc404a1..0000000 --- a/Assets/Scenes/Boids/New Nano Brain.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: fab876d6bf7dc9b10a56541a7eeccdd2 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Scenes/Boids/SwarmingBrain.asset b/Assets/Scenes/Boids/SwarmingBrain.asset index 92d4f4b..ffe8dd0 100644 --- a/Assets/Scenes/Boids/SwarmingBrain.asset +++ b/Assets/Scenes/Boids/SwarmingBrain.asset @@ -12,29 +12,12 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 36081359186edfec998d891a1feeb17b, type: 3} m_Name: SwarmingBrain m_EditorClassIdentifier: Assembly-CSharp::NanoBrainObj - title: - count: 0 - color: {r: 1, g: 1, b: 1, a: 1} - texture: {fileID: 0} nuclei: - id: -1707533328 _name: Root - synapses: - - nucleusId: -112538112 - weight: 1 - curveMax: -10 - - nucleusId: 1938577052 - weight: 2.2 - curveMax: 10 - - nucleusId: 1641120128 - weight: -5 - curveMax: 1000 - - nucleusId: -1857835930 - weight: 0.5 - curveMax: 1 - receivers: [] + _synapses: [] + _receivers: [] nucleusType: - isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -66,14 +49,9 @@ MonoBehaviour: exponent: 1 - id: -112538112 _name: Avoidance - synapses: - - nucleusId: 407735232 - weight: -1 - curveMax: 0 - receivers: - - nucleusId: -1707533328 + _synapses: [] + _receivers: [] nucleusType: - isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -105,29 +83,9 @@ MonoBehaviour: exponent: 1 - id: 1938577052 _name: Cohesion - synapses: - - nucleusId: -1659429232 - weight: 1 - curveMax: 1 - - nucleusId: 839544896 - weight: 1 - curveMax: 1 - - nucleusId: -348340288 - weight: 1 - curveMax: 1 - - nucleusId: -1095934288 - weight: 1 - curveMax: 1 - - nucleusId: -1413006832 - weight: 1 - curveMax: 1 - - nucleusId: -61245040 - weight: 1 - curveMax: 1 - receivers: - - nucleusId: -1707533328 + _synapses: [] + _receivers: [] nucleusType: - isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -159,29 +117,9 @@ MonoBehaviour: exponent: 1 - id: 1641120128 _name: Separation - synapses: - - nucleusId: 1710403072 - weight: 1 - curveMax: 1 - - nucleusId: -916054576 - weight: 1 - curveMax: 1 - - nucleusId: -1391520368 - weight: 1 - curveMax: 1 - - nucleusId: 763145504 - weight: 1 - curveMax: 1 - - nucleusId: 1469392160 - weight: 1 - curveMax: 1 - - nucleusId: -1828317248 - weight: 1 - curveMax: 1 - receivers: - - nucleusId: -1707533328 + _synapses: [] + _receivers: [] nucleusType: - isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -213,29 +151,9 @@ MonoBehaviour: exponent: 1 - id: -1857835930 _name: Alignment - synapses: - - nucleusId: -1659687600 - weight: 1 - curveMax: 1 - - nucleusId: 1322333072 - weight: 1 - curveMax: 1 - - nucleusId: -1563920864 - weight: 1 - curveMax: 1 - - nucleusId: 182328688 - weight: 1 - curveMax: 1 - - nucleusId: -1666561744 - weight: 1 - curveMax: 1 - - nucleusId: -1884196224 - weight: 1 - curveMax: 1 - receivers: - - nucleusId: -1707533328 + _synapses: [] + _receivers: [] nucleusType: - isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -267,14 +185,9 @@ MonoBehaviour: exponent: 1 - id: 1710403072 _name: Inverse Boid A - synapses: - - nucleusId: -1659429232 - weight: 1 - curveMax: 1 - receivers: - - nucleusId: 1641120128 + _synapses: [] + _receivers: [] nucleusType: - isSleeping: 0 _curvePreset: 3 curve: serializedVersion: 2 @@ -1440,14 +1353,9 @@ MonoBehaviour: exponent: 1 - id: -916054576 _name: Inverse Boid B - synapses: - - nucleusId: 839544896 - weight: 1 - curveMax: 1 - receivers: - - nucleusId: 1641120128 + _synapses: [] + _receivers: [] nucleusType: - isSleeping: 0 _curvePreset: 3 curve: serializedVersion: 2 @@ -2613,14 +2521,9 @@ MonoBehaviour: exponent: 1 - id: -1391520368 _name: Inverse Boid C - synapses: - - nucleusId: -348340288 - weight: 1 - curveMax: 1 - receivers: - - nucleusId: 1641120128 + _synapses: [] + _receivers: [] nucleusType: - isSleeping: 0 _curvePreset: 3 curve: serializedVersion: 2 @@ -3786,14 +3689,9 @@ MonoBehaviour: exponent: 1 - id: 763145504 _name: Inverse Boid D - synapses: - - nucleusId: -1095934288 - weight: 1 - curveMax: 1 - receivers: - - nucleusId: 1641120128 + _synapses: [] + _receivers: [] nucleusType: - isSleeping: 0 _curvePreset: 3 curve: serializedVersion: 2 @@ -4959,14 +4857,9 @@ MonoBehaviour: exponent: 1 - id: 1469392160 _name: Inverse Boid E - synapses: - - nucleusId: -1413006832 - weight: 1 - curveMax: 1 - receivers: - - nucleusId: 1641120128 + _synapses: [] + _receivers: [] nucleusType: - isSleeping: 0 _curvePreset: 3 curve: serializedVersion: 2 @@ -6132,14 +6025,9 @@ MonoBehaviour: exponent: 1 - id: -1828317248 _name: Inverse Bodi F - synapses: - - nucleusId: -61245040 - weight: 1 - curveMax: 1 - receivers: - - nucleusId: 1641120128 + _synapses: [] + _receivers: [] nucleusType: - isSleeping: 0 _curvePreset: 3 curve: serializedVersion: 2 @@ -7306,11 +7194,9 @@ MonoBehaviour: perceptei: - id: 407735232 _name: Boundary - synapses: [] - receivers: - - nucleusId: -112538112 + _synapses: [] + _receivers: [] nucleusType: Perceptoid - isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -7322,17 +7208,17 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 - baseName: - thingType: 1 + brain: {fileID: 0} + baseName: Boundary thingId: 0 + array: + rid: -2 + thingType: 1 - id: -1659429232 _name: BoidA - synapses: [] - receivers: - - nucleusId: 1938577052 - - nucleusId: 1710403072 + _synapses: [] + _receivers: [] nucleusType: Perceptoid - isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -7344,17 +7230,17 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 - baseName: - thingType: 2 + brain: {fileID: 0} + baseName: BoidA thingId: 0 + array: + rid: 2243600969536897085 + thingType: 2 - id: 839544896 _name: BoidB - synapses: [] - receivers: - - nucleusId: 1938577052 - - nucleusId: -916054576 + _synapses: [] + _receivers: [] nucleusType: Perceptoid - isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -7366,17 +7252,17 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 - baseName: - thingType: 2 + brain: {fileID: 0} + baseName: BoidB thingId: 0 + array: + rid: 2243600969536897086 + thingType: 2 - id: -348340288 _name: BoidC - synapses: [] - receivers: - - nucleusId: 1938577052 - - nucleusId: -1391520368 + _synapses: [] + _receivers: [] nucleusType: Perceptoid - isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -7388,17 +7274,17 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 - baseName: - thingType: 2 + brain: {fileID: 0} + baseName: BoidC thingId: 0 + array: + rid: 2243600969536897087 + thingType: 2 - id: -1095934288 _name: BoidD - synapses: [] - receivers: - - nucleusId: 1938577052 - - nucleusId: 763145504 + _synapses: [] + _receivers: [] nucleusType: Perceptoid - isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -7410,17 +7296,17 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 - baseName: - thingType: 2 + brain: {fileID: 0} + baseName: BoidD thingId: 0 + array: + rid: 2243600969536897088 + thingType: 2 - id: -1413006832 _name: BoidE - synapses: [] - receivers: - - nucleusId: 1938577052 - - nucleusId: 1469392160 + _synapses: [] + _receivers: [] nucleusType: Perceptoid - isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -7432,17 +7318,17 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 - baseName: - thingType: 2 + brain: {fileID: 0} + baseName: BoidE thingId: 0 + array: + rid: 2243600969536897089 + thingType: 2 - id: -61245040 _name: BoidF - synapses: [] - receivers: - - nucleusId: 1938577052 - - nucleusId: -1828317248 + _synapses: [] + _receivers: [] nucleusType: Perceptoid - isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -7454,16 +7340,17 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 - baseName: - thingType: 2 + brain: {fileID: 0} + baseName: BoidF thingId: 0 + array: + rid: 2243600969536897090 + thingType: 2 - id: -1659687600 _name: BoidA Velocity - synapses: [] - receivers: - - nucleusId: -1857835930 + _synapses: [] + _receivers: [] nucleusType: Perceptoid - isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -7475,16 +7362,17 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 - baseName: - thingType: 3 + brain: {fileID: 0} + baseName: BoidA Velocity thingId: 0 + array: + rid: -2 + thingType: 3 - id: 1322333072 _name: BoidB Velocity - synapses: [] - receivers: - - nucleusId: -1857835930 + _synapses: [] + _receivers: [] nucleusType: Perceptoid - isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -7496,16 +7384,17 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 - baseName: - thingType: 3 + brain: {fileID: 0} + baseName: BoidB Velocity thingId: 0 + array: + rid: -2 + thingType: 3 - id: -1563920864 _name: BoidC Velocity - synapses: [] - receivers: - - nucleusId: -1857835930 + _synapses: [] + _receivers: [] nucleusType: Perceptoid - isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -7517,16 +7406,17 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 - baseName: - thingType: 3 + brain: {fileID: 0} + baseName: BoidC Velocity thingId: 0 + array: + rid: -2 + thingType: 3 - id: 182328688 _name: BoidD Velocity - synapses: [] - receivers: - - nucleusId: -1857835930 + _synapses: [] + _receivers: [] nucleusType: Perceptoid - isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -7538,16 +7428,17 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 - baseName: - thingType: 3 + brain: {fileID: 0} + baseName: BoidD Velocity thingId: 0 + array: + rid: -2 + thingType: 3 - id: -1666561744 _name: BoidE Velocity - synapses: [] - receivers: - - nucleusId: -1857835930 + _synapses: [] + _receivers: [] nucleusType: Perceptoid - isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -7559,16 +7450,17 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 - baseName: - thingType: 3 + brain: {fileID: 0} + baseName: BoidE Velocity thingId: 0 + array: + rid: -2 + thingType: 3 - id: -1884196224 _name: BoidF Velocity - synapses: [] - receivers: - - nucleusId: -1857835930 + _synapses: [] + _receivers: [] nucleusType: Perceptoid - isSleeping: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -7580,7 +7472,202 @@ MonoBehaviour: average: 0 inverse: 0 exponent: 1 - baseName: - thingType: 3 + brain: {fileID: 0} + baseName: BoidF Velocity thingId: 0 + array: + rid: -2 + thingType: 3 + cluster: {fileID: 0} rootId: -1707533328 + references: + version: 2 + RefIds: + - rid: -2 + type: {class: , ns: , asm: } + - rid: 2243600969536897085 + type: {class: PercepteiArray, ns: , asm: Assembly-CSharp} + data: + perceptei: + - rid: 2243600969536897091 + name: BoidA + - rid: 2243600969536897086 + type: {class: PercepteiArray, ns: , asm: Assembly-CSharp} + data: + perceptei: + - rid: 2243600969536897092 + name: BoidB + - rid: 2243600969536897087 + type: {class: PercepteiArray, ns: , asm: Assembly-CSharp} + data: + perceptei: + - rid: 2243600969536897093 + name: BoidC + - rid: 2243600969536897088 + type: {class: PercepteiArray, ns: , asm: Assembly-CSharp} + data: + perceptei: + - rid: 2243600969536897094 + name: BoidD + - rid: 2243600969536897089 + type: {class: PercepteiArray, ns: , asm: Assembly-CSharp} + data: + perceptei: + - rid: 2243600969536897095 + name: BoidE + - rid: 2243600969536897090 + type: {class: PercepteiArray, ns: , asm: Assembly-CSharp} + data: + perceptei: + - rid: 2243600969536897096 + name: BoidF + - rid: 2243600969536897091 + type: {class: Perceptoid, ns: , asm: Assembly-CSharp} + data: + id: -1659429232 + _name: BoidA + _synapses: [] + _receivers: [] + nucleusType: Perceptoid + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + brain: {fileID: 0} + baseName: BoidA + thingId: 0 + array: + rid: 2243600969536897085 + thingType: 2 + - rid: 2243600969536897092 + type: {class: Perceptoid, ns: , asm: Assembly-CSharp} + data: + id: 839544896 + _name: BoidB + _synapses: [] + _receivers: [] + nucleusType: Perceptoid + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + brain: {fileID: 0} + baseName: BoidB + thingId: 0 + array: + rid: 2243600969536897086 + thingType: 2 + - rid: 2243600969536897093 + type: {class: Perceptoid, ns: , asm: Assembly-CSharp} + data: + id: -348340288 + _name: BoidC + _synapses: [] + _receivers: [] + nucleusType: Perceptoid + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + brain: {fileID: 0} + baseName: BoidC + thingId: 0 + array: + rid: 2243600969536897087 + thingType: 2 + - rid: 2243600969536897094 + type: {class: Perceptoid, ns: , asm: Assembly-CSharp} + data: + id: -1095934288 + _name: BoidD + _synapses: [] + _receivers: [] + nucleusType: Perceptoid + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + brain: {fileID: 0} + baseName: BoidD + thingId: 0 + array: + rid: 2243600969536897088 + thingType: 2 + - rid: 2243600969536897095 + type: {class: Perceptoid, ns: , asm: Assembly-CSharp} + data: + id: -1413006832 + _name: BoidE + _synapses: [] + _receivers: [] + nucleusType: Perceptoid + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + brain: {fileID: 0} + baseName: BoidE + thingId: 0 + array: + rid: 2243600969536897089 + thingType: 2 + - rid: 2243600969536897096 + type: {class: Perceptoid, ns: , asm: Assembly-CSharp} + data: + id: -61245040 + _name: BoidF + _synapses: [] + _receivers: [] + nucleusType: Perceptoid + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + brain: {fileID: 0} + baseName: BoidF + thingId: 0 + array: + rid: 2243600969536897090 + thingType: 2 From 90350b625b8602b2b095fb7a4187d7da15cdd095 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 12 Jan 2026 12:30:08 +0100 Subject: [PATCH 062/179] It works again (without nucleus array) --- Assembly-CSharp.csproj | 1 + Assets/NanoBrain/Cluster.cs | 55 ++-- Assets/NanoBrain/INucleus.cs | 36 ++- Assets/NanoBrain/Neuroid.cs | 41 --- Assets/NanoBrain/Nucleus.cs | 251 +++++++----------- Assets/NanoBrain/Perceptoid.cs | 16 +- Assets/NanoBrain/Receptor.cs | 141 +++++++--- Assets/NanoBrain/Synapse.cs | 115 ++++++++ Assets/NanoBrain/Synapse.cs.meta | 2 + .../VisualEditor/Editor/ClusterInspector.cs | 55 ++-- .../Editor/NanoBrainComponent_Editor.cs | 6 +- .../VisualEditor/Editor/NanoBrainInspector.cs | 47 ++-- Assets/NanoBrain/VisualEditor/NanoBrain.cs | 6 +- .../VisualEditor/NanoBrainComponent.cs | 12 +- Assets/Scenes/Boids/New Cluster.asset | 20 -- Assets/Scenes/Boids/NewSwarm.asset | 100 +++++++ ...Cluster.asset.meta => NewSwarm.asset.meta} | 0 Assets/Scenes/Boids/Prefabs/Boid.prefab | 2 +- Assets/Scenes/Boids/Scripts/Boid.cs | 213 +++++++-------- .../Scripts/Editor/SwarmControl_Editor.cs | 64 ++--- Assets/Scenes/Boids/SwarmingBrain.asset | 2 +- 21 files changed, 693 insertions(+), 492 deletions(-) create mode 100644 Assets/NanoBrain/Synapse.cs create mode 100644 Assets/NanoBrain/Synapse.cs.meta delete mode 100644 Assets/Scenes/Boids/New Cluster.asset create mode 100644 Assets/Scenes/Boids/NewSwarm.asset rename Assets/Scenes/Boids/{New Cluster.asset.meta => NewSwarm.asset.meta} (100%) diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index b49e8b7..d59c742 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -79,6 +79,7 @@ + diff --git a/Assets/NanoBrain/Cluster.cs b/Assets/NanoBrain/Cluster.cs index 5b349e1..2216d32 100644 --- a/Assets/NanoBrain/Cluster.cs +++ b/Assets/NanoBrain/Cluster.cs @@ -3,28 +3,30 @@ using UnityEngine; [CreateAssetMenu(menuName = "Passer/Cluster")] public class Cluster : ScriptableObject, INucleus { - - // private string _name; - // public new string name { - // get { return _name; } - // set { _name = value; } - // } - + public Cluster cluster => this; - public List nuclei = new(); + [SerializeReference] + public List nuclei = new(); - public Nucleus output => this.nuclei[0]; + public INucleus output => this.nuclei[0]; - [SerializeField] - private readonly List _synapses = new(); // = inputs, compare receptors in NanoBrain + //private readonly List _inputs = new(); + public List inputs { // = compare receptors in NanoBrain + // for now all nuclei are inputs + get { return this.nuclei; } + } + + // The synapses of all inputs + private readonly List _synapses = new(); public List synapses => _synapses; + // Call this function to ensure that there is at least one nucleus // This is an invariant and should be ensured before the nucleus is used // because output requires it. public void EnsureInitialization() { - nuclei ??= new List(); + nuclei ??= new List(); if (nuclei.Count == 0) new Neuroid(this, "Output"); // Every cluster should have at least 1 neuroid } @@ -36,12 +38,12 @@ public class Cluster : ScriptableObject, INucleus { public void RemoveReceiver(INucleus receiver) { output.RemoveReceiver(receiver); } - public List receivers { + public List receivers { get => output.receivers; } - public void AddSynapse(INucleus sender) { - Synapse synapse = new (sender, 1.0f); + public void AddSynapse(IReceptor sender) { + Synapse synapse = new(sender, 1.0f); synapses.Add(synapse); } @@ -63,17 +65,18 @@ public class Cluster : ScriptableObject, INucleus { foreach (Synapse synapse in nucleus.synapses) { if (synapse != null && synapse.nucleus != null) { visitedSynapses.Add(synapse); - MarkNuclei(visitedNuclei, synapse.nucleus); + if (synapse.nucleus is INucleus synapse_nucleus) + MarkNuclei(visitedNuclei, synapse_nucleus); } } nucleus.synapses.RemoveAll(synapse => visitedSynapses.Contains(synapse) == false); } if (nucleus.receivers != null) { - HashSet visitedReceivers = new(); - foreach (Receiver receiver in nucleus.receivers) { - if (receiver != null && receiver.nucleus != null) { + HashSet visitedReceivers = new(); + foreach (INucleus receiver in nucleus.receivers) { + if (receiver != null && receiver != null) { visitedReceivers.Add(receiver); - visitedNuclei.Add(receiver.nucleus); + visitedNuclei.Add(receiver); } } nucleus.receivers.RemoveAll(receiver => visitedReceivers.Contains(receiver) == false); @@ -91,5 +94,17 @@ public class Cluster : ScriptableObject, INucleus { // it is not, I should take inputs from the synapses and route them to the right internal nuclei } + public void UpdateNuclei() { + foreach (INucleus nucleus in nuclei) + nucleus.IncreaseAge(); + + } + + public void IncreaseAge() { + foreach (INucleus nucleus in nuclei) + nucleus.IncreaseAge(); + } + // ha ha ha + #endregion Dynamics } \ No newline at end of file diff --git a/Assets/NanoBrain/INucleus.cs b/Assets/NanoBrain/INucleus.cs index 46d424a..45c0acd 100644 --- a/Assets/NanoBrain/INucleus.cs +++ b/Assets/NanoBrain/INucleus.cs @@ -1,33 +1,45 @@ using System.Collections.Generic; using UnityEngine; -public interface INucleus { +public interface INucleus : IReceptor { #region static struct - public string name { get; set; } - // Cluster public Cluster cluster { get; } - // Receivers - public List receivers { get; } - public void AddReceiver(INucleus receiver); - public void RemoveReceiver(INucleus receiverNucleus); - // Senders public List synapses { get; } - public void AddSynapse(INucleus sender); + public void AddSynapse(IReceptor sender); #endregion static struct #region dynamic state - public bool isSleeping { get; } + public void UpdateState(); + + public void IncreaseAge(); + + #endregion dynamic state +} + +public interface IReceptor { + #region static + + public string name { get; set; } + + // Receivers + public List receivers { get; } + public void AddReceiver(INucleus receiver); + public void RemoveReceiver(INucleus receiverNucleus); + + #endregion static + + #region dynamic public Vector3 outputValue { get; } - public void UpdateState(); + public bool isSleeping { get; } - #endregion dynamic state + #endregion dynamic } \ No newline at end of file diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index cd534e0..9e56de1 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -2,49 +2,8 @@ using UnityEngine; [System.Serializable] public class Neuroid : Nucleus { - public enum CurvePresets { - Linear, - Power, - Sqrt, - Reciprocal, - Custom - } - [SerializeField] - private CurvePresets _curvePreset; - public CurvePresets curvePreset { - get { return _curvePreset; } - set { - _curvePreset = value; - this.curve = GenerateCurve(); - } - } - public AnimationCurve curve; - public float curveMax = 1.0f; - - public AnimationCurve GenerateCurve() { - switch (this.curvePreset) { - case CurvePresets.Linear: - this.curveMax = 1; - return Synapse.Presets.Linear(1); - case CurvePresets.Power: - this.curveMax = 1; - return Synapse.Presets.Power(2.0f, 1); - case CurvePresets.Sqrt: - this.curveMax = 1; - return Synapse.Presets.Power(0.5f, 1); - case CurvePresets.Reciprocal: - this.curveMax = 1 / 0.01f * 1; - return Synapse.Presets.Reciprocal(1); - default: - this.curveMax = 1; - return this.curve; - } - } public bool average = false; - public bool inverse = false; - public float exponent = 1.0f; - public Neuroid(Cluster brain, string name) : base(name) { this.cluster = brain; diff --git a/Assets/NanoBrain/Nucleus.cs b/Assets/NanoBrain/Nucleus.cs index 601c462..41ac085 100644 --- a/Assets/NanoBrain/Nucleus.cs +++ b/Assets/NanoBrain/Nucleus.cs @@ -19,26 +19,65 @@ public class Nucleus : INucleus { private List _synapses = new(); public List synapses => _synapses; - [SerializeField] - private List _receivers = new(); - public List receivers => _receivers; + [SerializeReference] + private List _receivers = new(); + public List receivers => _receivers; #region Serialization [SerializeField] protected string nucleusType; + public enum CurvePresets { + Linear, + Power, + Sqrt, + Reciprocal, + Custom + } + [SerializeField] + private CurvePresets _curvePreset; + public CurvePresets curvePreset { + get { return _curvePreset; } + set { + _curvePreset = value; + this.curve = GenerateCurve(); + } + } + public AnimationCurve curve; + public float curveMax = 1.0f; + + public AnimationCurve GenerateCurve() { + switch (this.curvePreset) { + case CurvePresets.Linear: + this.curveMax = 1; + return Synapse.Presets.Linear(1); + case CurvePresets.Power: + this.curveMax = 1; + return Synapse.Presets.Power(2.0f, 1); + case CurvePresets.Sqrt: + this.curveMax = 1; + return Synapse.Presets.Power(0.5f, 1); + case CurvePresets.Reciprocal: + this.curveMax = 1 / 0.01f * 1; + return Synapse.Presets.Reciprocal(1); + default: + this.curveMax = 1; + return this.curve; + } + } + public virtual void Rebuild(NanoBrain brain) { if (this.synapses != null) { foreach (Synapse synapse in synapses) synapse.Rebuild(brain); } - foreach (Receiver receiver in receivers.ToArray()) { - if (receiver.Rebuild(brain) == false) { - Debug.Log("Rebuilding failed, removing receiver."); - receivers.Remove(receiver); - } - } + // foreach (INucleus receiver in receivers.ToArray()) { + // if (receiver.Rebuild(brain) == false) { + // Debug.Log("Rebuilding failed, removing receiver."); + // receivers.Remove(receiver); + // } + // } } public static Nucleus RebuildType(NanoBrain brain, Nucleus nucleus) { @@ -63,8 +102,7 @@ public class Nucleus : INucleus { public Cluster cluster { get; set; } private Vector3 _outputValue; - public Vector3 outputValue - { + public Vector3 outputValue { get { return _outputValue; } set { this.stale = 0; @@ -96,30 +134,33 @@ public class Nucleus : INucleus { } public virtual void AddReceiver(INucleus receivingNucleus) { - this.receivers.Add(new Receiver(receivingNucleus)); + // this.receivers.Add(new Receiver(receivingNucleus)); + this.receivers.Add(receivingNucleus); //receivingNucleus.SetWeight(this, 1.0f); receivingNucleus.AddSynapse(this); } public void RemoveReceiver(INucleus receiverNucleus) { - this.receivers.RemoveAll(receiver => receiver.nucleus == receiverNucleus); + this.receivers.RemoveAll(receiver => receiver == receiverNucleus); receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); } public static void Delete(INucleus nucleus) { foreach (Synapse synapse in nucleus.synapses) { - if (synapse.nucleus.receivers.Count > 1) { - // there is another nucleus feeding into this input nucleus - synapse.nucleus.receivers.RemoveAll(r => r.nucleus == nucleus); - } - else { - // No other links, delete it. - Nucleus.Delete(synapse.nucleus); + if (synapse.nucleus is Nucleus synapse_nucleus) { + if (synapse_nucleus.receivers.Count > 1) { + // there is another nucleus feeding into this input nucleus + synapse_nucleus.receivers.RemoveAll(r => r == nucleus); + } + else { + // No other links, delete it. + Nucleus.Delete(synapse_nucleus); + } } } - foreach (Receiver receiver in nucleus.receivers) { - if (receiver.nucleus != null && receiver.nucleus.synapses != null) - receiver.nucleus.synapses.RemoveAll(s => s.nucleus == nucleus); + foreach (INucleus receiver in nucleus.receivers) { + if (receiver != null && receiver.synapses != null) + receiver.synapses.RemoveAll(s => s.nucleus == nucleus); } if (nucleus.cluster != null) { @@ -141,7 +182,7 @@ public class Nucleus : INucleus { return false; } - public void AddSynapse(INucleus sendingNucleus) { + public void AddSynapse(IReceptor sendingNucleus) { Synapse synapse = new(sendingNucleus, 1.0f); this.synapses.Add(synapse); } @@ -166,146 +207,36 @@ public class Nucleus : INucleus { // } this.outputValue = result; - foreach (Receiver receiver in this.receivers) - receiver.nucleus.UpdateState(); + foreach (INucleus receiver in this.receivers) + receiver.UpdateState(); } } -[Serializable] -public class Synapse { - [NonSerialized] - public INucleus nucleus; - public Cluster cluster; - public int nucleusId; - public float weight; +// [Serializable] +// public class Receiver { +// [NonSerialized] +// public INucleus nucleus; +// //public int nucleusId; - public enum CurvePresets { - Linear, - Power, - Sqrt, - Reciprocal, - Custom - } - // public CurvePresets curvePreset; - // public AnimationCurve curve; - public float curveMax = 1.0f; +// public Receiver(INucleus nucleus) { +// this.nucleus = nucleus; +// //this.nucleusId = nucleus.id; +// } - public Synapse(INucleus nucleus, float weight) { - this.nucleus = nucleus; - //this.nucleusId = nucleus.id; - this.weight = weight; - } +// public bool Rebuild(NanoBrain brain) { +// if (brain == null) { +// return false; +// } - public void Rebuild(NanoBrain brain) { - if (brain == null) { - return; - } - - foreach (Nucleus nucleus in brain.nuclei) { - if (nucleus.id == this.nucleusId) { - this.nucleus = nucleus; - return; - } - } - foreach (Perceptoid perceptoid in brain.perceptei) { - if (perceptoid.id == this.nucleusId) { - this.nucleus = perceptoid; - return; - } - } - Debug.LogError($"Synapse deserialization error: could not find nucleus with id {this.nucleusId}"); - } - - // public AnimationCurve GenerateCurve() { - // switch (this.curvePreset) { - // case CurvePresets.Linear: - // this.curveMax = this.weight; - // return Presets.Linear(this.weight); - // case CurvePresets.Power: - // this.curveMax = this.weight; - // return Presets.Power(2.0f, this.weight); - // case CurvePresets.Sqrt: - // this.curveMax = this.weight; - // return Presets.Power(0.5f, this.weight); - // case CurvePresets.Reciprocal: - // this.curveMax = 1 / 0.01f * this.weight; - // return Presets.Reciprocal(this.weight); - // default: - // this.curveMax = weight; - // return AnimationCurve.Constant(0, 1, weight); - // } - // } - - public static class Presets { - private const int samples = 32; - public static AnimationCurve Linear(float weight) { - return AnimationCurve.Linear(0f, 0f, 1000f, weight * 1000); - } - public static AnimationCurve Power(float exponent, float weight) { - // build keyframes - Keyframe[] keys = new Keyframe[samples]; - for (int i = 0; i < samples; i++) { - float t = i / (float)(samples - 1); - float v = Mathf.Pow(t, exponent) * weight; - keys[i] = new Keyframe(t, v); - } - - AnimationCurve curve = new(keys); - - // set tangent modes for each key to Auto (smooth). Use Linear if you prefer straight segments. - for (int i = 0; i < curve.length; i++) { - AnimationUtility.SetKeyLeftTangentMode(curve, i, AnimationUtility.TangentMode.Auto); - AnimationUtility.SetKeyRightTangentMode(curve, i, AnimationUtility.TangentMode.Auto); - } - - return curve; - } - public static AnimationCurve Reciprocal(float weight) { - int samples = 128; - float xMin = 0.001f; - float xMax = 1; - var keys = new Keyframe[samples]; - for (int i = 0; i < samples; i++) { - float t = i / (float)(samples - 1); - float x = Mathf.Lerp(xMin, xMax, t); - float y = 1f / x * weight; - keys[i] = new Keyframe(x, y); - } - var curve = new AnimationCurve(keys); - for (int i = 0; i < curve.length; i++) { - AnimationUtility.SetKeyLeftTangentMode(curve, i, AnimationUtility.TangentMode.Linear); - AnimationUtility.SetKeyRightTangentMode(curve, i, AnimationUtility.TangentMode.Linear); - } - return curve; - } - } -} - -[Serializable] -public class Receiver { - [NonSerialized] - public INucleus nucleus; - //public int nucleusId; - - public Receiver(INucleus nucleus) { - this.nucleus = nucleus; - //this.nucleusId = nucleus.id; - } - - public bool Rebuild(NanoBrain brain) { - if (brain == null) { - return false; - } - - // Use SerializedReference instead? - // foreach (Nucleus nucleus in brain.nuclei) { - // if (nucleus.id == this.nucleusId) { - // this.nucleus = nucleus; - // return true; - // } - // } - //Debug.LogWarning($"Receiver deserialization error: could not find nucleus with id {this.nucleusId}"); - return false; - } -} \ No newline at end of file +// // Use SerializedReference instead? +// // foreach (Nucleus nucleus in brain.nuclei) { +// // if (nucleus.id == this.nucleusId) { +// // this.nucleus = nucleus; +// // return true; +// // } +// // } +// //Debug.LogWarning($"Receiver deserialization error: could not find nucleus with id {this.nucleusId}"); +// return false; +// } +// } \ No newline at end of file diff --git a/Assets/NanoBrain/Perceptoid.cs b/Assets/NanoBrain/Perceptoid.cs index 85f0bc1..b30847e 100644 --- a/Assets/NanoBrain/Perceptoid.cs +++ b/Assets/NanoBrain/Perceptoid.cs @@ -36,19 +36,19 @@ public class Perceptoid : Neuroid { this.receptor.thingType = perceptoid.thingType; // Point all receivers to this perceptoid instead of the default nucleus - foreach (Receiver receiver in nucleus.receivers) { - foreach (Synapse synapse in receiver.nucleus.synapses) { + foreach (INucleus receiver in nucleus.receivers) { + foreach (Synapse synapse in receiver.synapses) { if (synapse.nucleus == nucleus) synapse.nucleus = this; } } // Point all synapses to this perceptoid instead of the default nucleus - foreach (Synapse synapse in nucleus.synapses) { - foreach (Receiver receiver in synapse.nucleus.receivers) { - if (receiver.nucleus == nucleus) - receiver.nucleus = this; - } - } + // foreach (Synapse synapse in nucleus.synapses) { + // foreach (INucleus r in synapse.nucleus.receivers) { + // if (r == nucleus) + // this.receiver = this; + // } + // } // Copying disabled for now // // Copy all the synapses // this.synapses = nucleus.synapses; diff --git a/Assets/NanoBrain/Receptor.cs b/Assets/NanoBrain/Receptor.cs index ed8ba96..dcd3c28 100644 --- a/Assets/NanoBrain/Receptor.cs +++ b/Assets/NanoBrain/Receptor.cs @@ -2,7 +2,36 @@ using System.Collections.Generic; using UnityEngine; using LinearAlgebra; -public class Receptor { +public class Receptor : IReceptor { + [SerializeField] + protected string _name; + public virtual string name { + get => _name; + set => _name = value; + } + + public Cluster cluster; + //public INucleus nucleus; + + //[SerializeField] + [SerializeReference] + private List _receivers = new(); + public List receivers => _receivers; + + public virtual void AddReceiver(INucleus receivingNucleus) { + //this.receivers.Add(new Receiver(receivingNucleus)); + this.receivers.Add(receivingNucleus); + //receivingNucleus.SetWeight(this, 1.0f); + receivingNucleus.AddSynapse(this); + } + + public void RemoveReceiver(INucleus receiverNucleus) { + this.receivers.RemoveAll(receiver => receiver == receiverNucleus); + receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); + } + + public bool isSleeping => false; + /// /// The list of perceptoid which can process stimuli from this receptor /// @@ -22,12 +51,26 @@ public class Receptor { public float distanceResolution = 0.1f; public float directionResolution = 5; + public Vector3 outputValue { + get { return localPosition; } + set { + localPosition = value; + } + } + + public Receptor(NanoBrain brain, int thingType) { this.thingType = thingType; //this.perceptei.Add(perceptoid); brain.receptors.Add(this); } + public Receptor(Cluster cluster, INucleus nucleus) { + this.cluster = cluster; + //nucleus.AddSynapse(this); + this.AddReceiver(nucleus); + } + public static Receptor GetReceptor(NanoBrain brain, int thingType) { foreach (Receptor receptor in brain.receptors) { if (thingType == 0 || receptor.thingType == thingType) @@ -37,46 +80,68 @@ public class Receptor { return newReceptor; } + public static Receptor CreateReceptor(Cluster cluster, string nucleusName) { + if (cluster == null) + return null; + + foreach (INucleus nucleus in cluster.inputs) { + if (nucleus != null && nucleus.name == nucleusName) { + Receptor receptor = new(cluster, nucleus); + return receptor; + } + } + return null; + } + public virtual void ProcessStimulus(int thingId, Vector3 newLocalPositionVector, string thingName = null) { this.localPosition = newLocalPositionVector; - Perceptoid selectedPerceptoid = null; - foreach (Perceptoid perceptoid in this.perceptei) { - if (perceptoid.thingId == thingId) { - // We found an existing perceptoid for this thing - selectedPerceptoid = perceptoid; - // Do not look any further - - break; - } - else if (perceptoid.isSleeping) { - // A sleeping perceptoid is not active and can therefore always be reused - selectedPerceptoid = perceptoid; - // Look further because we could find a existing perceptoid for this thing - } - - else if (selectedPerceptoid == null) { - // If we haven't found a perceptoid yet, just start by taking the first - selectedPerceptoid = perceptoid; - } - - else if (selectedPerceptoid.isSleeping == false) { - // If no existing or sleeping perceptoid is found, we look for the perceptoid - // we the furthest (least interesting) stimulus - if (perceptoid.receptor.localPosition.magnitude < selectedPerceptoid.receptor.localPosition.magnitude) { - Debug.Log($"{selectedPerceptoid.name} {selectedPerceptoid.receptor.localPosition.magnitude} {perceptoid.receptor.localPosition.magnitude} "); - selectedPerceptoid = perceptoid; - } - } + INucleus selectedReceiver = null; + foreach (INucleus receiver in this.receivers) { + selectedReceiver = receiver; } - if (selectedPerceptoid == null) { - Debug.Log("No perceptoid selected, stimulus is ignored"); - return; - } - // Debug.Log($"Stimulus {thingType} {thingId} {selectedPerceptoid.name}"); - selectedPerceptoid.thingId = thingId; - if (thingName != null) - selectedPerceptoid.name = selectedPerceptoid.baseName + " " + thingName; - selectedPerceptoid.UpdateState(); + // selectedReceiver.thingId = thingId; + // if (thingName != null) + // selectedReceiver.nucleus.name = selectedReceiver.nucleus.baseName + " " + thingName; + selectedReceiver.UpdateState(); + + // Perceptoid selectedPerceptoid = null; + // foreach (Perceptoid perceptoid in this.perceptei) { + // if (perceptoid.thingId == thingId) { + // // We found an existing perceptoid for this thing + // selectedPerceptoid = perceptoid; + // // Do not look any further + + // break; + // } + // else if (perceptoid.isSleeping) { + // // A sleeping perceptoid is not active and can therefore always be reused + // selectedPerceptoid = perceptoid; + // // Look further because we could find a existing perceptoid for this thing + // } + + // else if (selectedPerceptoid == null) { + // // If we haven't found a perceptoid yet, just start by taking the first + // selectedPerceptoid = perceptoid; + // } + + // else if (selectedPerceptoid.isSleeping == false) { + // // If no existing or sleeping perceptoid is found, we look for the perceptoid + // // we the furthest (least interesting) stimulus + // if (perceptoid.receptor.localPosition.magnitude < selectedPerceptoid.receptor.localPosition.magnitude) { + // Debug.Log($"{selectedPerceptoid.name} {selectedPerceptoid.receptor.localPosition.magnitude} {perceptoid.receptor.localPosition.magnitude} "); + // selectedPerceptoid = perceptoid; + // } + // } + // } + // if (selectedPerceptoid == null) { + // Debug.Log("No perceptoid selected, stimulus is ignored"); + // return; + // } + // // Debug.Log($"Stimulus {thingType} {thingId} {selectedPerceptoid.name}"); + // selectedPerceptoid.thingId = thingId; + // if (thingName != null) + // selectedPerceptoid.name = selectedPerceptoid.baseName + " " + thingName; + // selectedPerceptoid.UpdateState(); } } \ No newline at end of file diff --git a/Assets/NanoBrain/Synapse.cs b/Assets/NanoBrain/Synapse.cs new file mode 100644 index 0000000..7bcdfde --- /dev/null +++ b/Assets/NanoBrain/Synapse.cs @@ -0,0 +1,115 @@ +using System; +using UnityEngine; +using UnityEditor; + +[Serializable] +public class Synapse { + //[NonSerialized] + [SerializeReference] + public IReceptor nucleus; + [SerializeReference] + public Cluster cluster; + //public int nucleusId; + public float weight; + + public enum CurvePresets { + Linear, + Power, + Sqrt, + Reciprocal, + Custom + } + // public CurvePresets curvePreset; + // public AnimationCurve curve; + public float curveMax = 1.0f; + + public Synapse(IReceptor nucleus, float weight) { + this.nucleus = nucleus; + //this.nucleusId = nucleus.id; + this.weight = weight; + } + + public void Rebuild(NanoBrain brain) { + // if (brain == null) { + // return; + // } + + // foreach (Nucleus nucleus in brain.nuclei) { + // if (nucleus.id == this.nucleusId) { + // this.nucleus = nucleus; + // return; + // } + // } + // foreach (Perceptoid perceptoid in brain.perceptei) { + // if (perceptoid.id == this.nucleusId) { + // this.nucleus = perceptoid; + // return; + // } + // } + // Debug.LogError($"Synapse deserialization error: could not find nucleus with id {this.nucleusId}"); + } + + // public AnimationCurve GenerateCurve() { + // switch (this.curvePreset) { + // case CurvePresets.Linear: + // this.curveMax = this.weight; + // return Presets.Linear(this.weight); + // case CurvePresets.Power: + // this.curveMax = this.weight; + // return Presets.Power(2.0f, this.weight); + // case CurvePresets.Sqrt: + // this.curveMax = this.weight; + // return Presets.Power(0.5f, this.weight); + // case CurvePresets.Reciprocal: + // this.curveMax = 1 / 0.01f * this.weight; + // return Presets.Reciprocal(this.weight); + // default: + // this.curveMax = weight; + // return AnimationCurve.Constant(0, 1, weight); + // } + // } + + public static class Presets { + private const int samples = 32; + public static AnimationCurve Linear(float weight) { + return AnimationCurve.Linear(0f, 0f, 1000f, weight * 1000); + } + public static AnimationCurve Power(float exponent, float weight) { + // build keyframes + Keyframe[] keys = new Keyframe[samples]; + for (int i = 0; i < samples; i++) { + float t = i / (float)(samples - 1); + float v = Mathf.Pow(t, exponent) * weight; + keys[i] = new Keyframe(t, v); + } + + AnimationCurve curve = new(keys); + + // set tangent modes for each key to Auto (smooth). Use Linear if you prefer straight segments. + for (int i = 0; i < curve.length; i++) { + AnimationUtility.SetKeyLeftTangentMode(curve, i, AnimationUtility.TangentMode.Auto); + AnimationUtility.SetKeyRightTangentMode(curve, i, AnimationUtility.TangentMode.Auto); + } + + return curve; + } + public static AnimationCurve Reciprocal(float weight) { + int samples = 128; + float xMin = 0.001f; + float xMax = 1; + var keys = new Keyframe[samples]; + for (int i = 0; i < samples; i++) { + float t = i / (float)(samples - 1); + float x = Mathf.Lerp(xMin, xMax, t); + float y = 1f / x * weight; + keys[i] = new Keyframe(x, y); + } + var curve = new AnimationCurve(keys); + for (int i = 0; i < curve.length; i++) { + AnimationUtility.SetKeyLeftTangentMode(curve, i, AnimationUtility.TangentMode.Linear); + AnimationUtility.SetKeyRightTangentMode(curve, i, AnimationUtility.TangentMode.Linear); + } + return curve; + } + } +} \ No newline at end of file diff --git a/Assets/NanoBrain/Synapse.cs.meta b/Assets/NanoBrain/Synapse.cs.meta new file mode 100644 index 0000000..e62612c --- /dev/null +++ b/Assets/NanoBrain/Synapse.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 334a58eafccd60cbdb32f719e9e861c6 \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs index bd681fa..b3a443b 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs @@ -75,7 +75,7 @@ public class ClusterInspector : Editor { INucleus currentNucleus; GameObject gameObject; private List layers = new(); - private readonly Dictionary neuroidPositions = new(); + private readonly Dictionary neuroidPositions = new(); Vector2 pan = Vector2.zero; //float zoom = 1f; @@ -101,7 +101,7 @@ public class ClusterInspector : Editor { RegisterCallback(OnMouseUp); } - public void SetGraph(GameObject gameObject, Cluster brain, Nucleus nucleus, VisualElement inspectorContainer) { + public void SetGraph(GameObject gameObject, Cluster brain, INucleus nucleus, VisualElement inspectorContainer) { this.gameObject = gameObject; this.cluster = brain; if (Application.isPlaying == false) @@ -135,8 +135,8 @@ public class ClusterInspector : Editor { NeuroidLayer currentLayer = new() { ix = layerIx }; if (selectedNucleus.receivers != null) { - foreach (Receiver receiver in selectedNucleus.receivers) { - INucleus outputNeuroid = receiver.nucleus; + foreach (INucleus receiver in selectedNucleus.receivers) { + INucleus outputNeuroid = receiver; if (outputNeuroid != null) { AddToLayer(currentLayer, outputNeuroid); // Debug.Log($"layer {layerIx} nucleus {outputNeuroid.name}"); @@ -158,7 +158,7 @@ public class ClusterInspector : Editor { if (selectedNucleus.synapses != null) { foreach (Synapse synapse in selectedNucleus.synapses) { - INucleus input = synapse.nucleus; + IReceptor input = synapse.nucleus; AddToLayer(currentLayer, input); // Debug.Log($"layer {layerIx} nucleus {input.name}"); } @@ -168,7 +168,7 @@ public class ClusterInspector : Editor { } } - private void AddToLayer(NeuroidLayer layer, INucleus nucleus) { + private void AddToLayer(NeuroidLayer layer, IReceptor nucleus) { if (nucleus == null) return; layer.neuroids.Add(nucleus); @@ -225,8 +225,8 @@ public class ClusterInspector : Editor { // Determine the maximum value in this layer // This is used to 'scale' the output value colors of the nuclei float maxValue = 0; - foreach (Receiver receiver in nucleus.receivers) { - if (receiver.nucleus is Neuroid neuroid) { + foreach (INucleus receiver in nucleus.receivers) { + if (receiver is Neuroid neuroid) { float value = neuroid.outputValue.magnitude; if (value > maxValue) maxValue = value; @@ -238,8 +238,8 @@ public class ClusterInspector : Editor { float margin = 10 + spacing / 2; int row = 0; - foreach (Receiver receiver in nucleus.receivers) { - INucleus receiverNucleus = receiver.nucleus; + foreach (INucleus receiver in nucleus.receivers) { + INucleus receiverNucleus = receiver; if (receiverNucleus == null) continue; @@ -286,13 +286,14 @@ public class ClusterInspector : Editor { // } // else { - DrawNucleus(synapse.nucleus, pos, maxValue, size); + if (synapse.nucleus != null) + DrawNucleus(synapse.nucleus, pos, maxValue, size); row++; // } } } - private void DrawNucleus(INucleus nucleus, Vector3 position, float maxValue, float size) { + private void DrawNucleus(IReceptor nucleus, Vector3 position, float maxValue, float size) { if (nucleus.isSleeping) Handles.color = Color.darkRed; else { @@ -360,7 +361,7 @@ public class ClusterInspector : Editor { // To do: add HandleClick (see above) to expand the array } - private void HandleMouseHover(INucleus nucleus, Rect rect) { + private void HandleMouseHover(IReceptor nucleus, Rect rect) { GUIContent tooltip; if (nucleus is Perceptoid perceptoid) { if (perceptoid.receptor != null) { @@ -377,10 +378,14 @@ public class ClusterInspector : Editor { $"\nValue: {nucleus.outputValue}"); } } - else { + else if (nucleus is INucleus n) { + tooltip = new( + $"{nucleus.name}" + + $"\nsynapse count {n.synapses.Count}" + + $"\nValue: {nucleus.outputValue}"); + } else { tooltip = new( $"{nucleus.name}" + - $"\nsynapse count {nucleus.synapses.Count}" + $"\nValue: {nucleus.outputValue}"); } @@ -393,9 +398,11 @@ public class ClusterInspector : Editor { GUI.Box(tooltipRect, tooltip); } - private void HandleClicked(INucleus nucleus) { - this.currentNucleus = nucleus; + private void HandleClicked(IReceptor nucleus) { + if (nucleus is INucleus n) { + this.currentNucleus = n; BuildLayers(); + } } void DrawInspector(VisualElement inspectorContainer) { @@ -430,7 +437,7 @@ public class ClusterInspector : Editor { perceptoid.array.RemovePerceptoid(); EditorGUILayout.EndHorizontal(); } - else if (this.currentNucleus is Neuroid neuroid) { + else if (this.currentNucleus is Nucleus neuroid) { EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Activation Curve", GUILayout.Width(150)); if (neuroid.curveMax > 0) @@ -517,9 +524,9 @@ public class ClusterInspector : Editor { return; if (nucleus.cluster != null) this.currentNucleus = nucleus.cluster.output; - foreach (Receiver receiver in nucleus.receivers) { - if (receiver.nucleus != null) { - this.currentNucleus = receiver.nucleus; + foreach (INucleus receiver in nucleus.receivers) { + if (receiver != null) { + this.currentNucleus = receiver; break; } } @@ -548,7 +555,7 @@ public class ClusterInspector : Editor { if (cluster == null) return; - IEnumerable synapseNuclei = this.currentNucleus.synapses.Select(synapse => synapse.nucleus.name); + IEnumerable synapseNuclei = this.currentNucleus.synapses.Select(synapse => synapse.nucleus != null ? synapse.nucleus.name: ""); //IEnumerable perceptei = this.currentNucleus.brain.perceptei.Select(i => i.name).Except(synapseNuclei); IEnumerable nuclei = cluster.nuclei.Select(i => i.name).Except(synapseNuclei); //string[] names = perceptei.Concat(nuclei).ToArray(); @@ -564,7 +571,7 @@ public class ClusterInspector : Editor { // Nucleus n = this.currentNucleus.brain.nuclei[selectedIndex - perceptei.Count()]; // n.AddReceiver(this.currentNucleus); // } - Nucleus n = cluster.nuclei[selectedIndex]; + INucleus n = cluster.nuclei[selectedIndex]; n.AddReceiver(this.currentNucleus); } } @@ -606,7 +613,7 @@ public class ClusterInspector : Editor { public class NeuroidLayer { public int ix = 0; - public List neuroids = new(); + public List neuroids = new(); } public class ClusterWrapper : ScriptableObject { diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs index 749b3d5..6da496b 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs @@ -20,7 +20,7 @@ public class NanoBrainComponent_Editor : Editor { public override VisualElement CreateInspectorGUI() { //NanoBrainComponent component = target as NanoBrainComponent; - NanoBrain brain = Application.isPlaying ? component.brain : component.defaultBrain; + Cluster brain = Application.isPlaying ? component.brain : component.defaultBrain; if (Application.isPlaying == false) serializedObject.Update(); @@ -52,8 +52,8 @@ public class NanoBrainComponent_Editor : Editor { minHeight = 500, } }; - NanoBrainInspector.GraphView board; - board = new NanoBrainInspector.GraphView(); + ClusterInspector.GraphView board; + board = new ClusterInspector.GraphView(); board.style.flexGrow = 1; inspectorContainer = new VisualElement { diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs index 7290c03..c8cc316 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs @@ -73,7 +73,7 @@ public class NanoBrainInspector : Editor { INucleus currentNucleus; GameObject gameObject; private List layers = new(); - private readonly Dictionary neuroidPositions = new(); + private readonly Dictionary neuroidPositions = new(); Vector2 pan = Vector2.zero; //float zoom = 1f; @@ -133,8 +133,8 @@ public class NanoBrainInspector : Editor { NeuroidLayer currentLayer = new() { ix = layerIx }; if (selectedNucleus.receivers != null) { - foreach (Receiver receiver in selectedNucleus.receivers) { - INucleus outputNeuroid = receiver.nucleus; + foreach (INucleus receiver in selectedNucleus.receivers) { + INucleus outputNeuroid = receiver; if (outputNeuroid != null) { AddToLayer(currentLayer, outputNeuroid); // Debug.Log($"layer {layerIx} nucleus {outputNeuroid.name}"); @@ -156,7 +156,7 @@ public class NanoBrainInspector : Editor { if (selectedNucleus.synapses != null) { foreach (Synapse synapse in selectedNucleus.synapses) { - INucleus input = synapse.nucleus; + IReceptor input = synapse.nucleus; AddToLayer(currentLayer, input); // Debug.Log($"layer {layerIx} nucleus {input.name}"); } @@ -166,7 +166,7 @@ public class NanoBrainInspector : Editor { } } - private void AddToLayer(NeuroidLayer layer, INucleus nucleus) { + private void AddToLayer(NeuroidLayer layer, IReceptor nucleus) { if (nucleus == null) return; layer.neuroids.Add(nucleus); @@ -223,8 +223,8 @@ public class NanoBrainInspector : Editor { // Determine the maximum value in this layer // This is used to 'scale' the output value colors of the nuclei float maxValue = 0; - foreach (Receiver receiver in nucleus.receivers) { - if (receiver.nucleus is Neuroid neuroid) { + foreach (INucleus receiver in nucleus.receivers) { + if (receiver is Neuroid neuroid) { float value = neuroid.outputValue.magnitude; if (value > maxValue) maxValue = value; @@ -236,8 +236,8 @@ public class NanoBrainInspector : Editor { float margin = 10 + spacing / 2; int row = 0; - foreach (Receiver receiver in nucleus.receivers) { - INucleus receiverNucleus = receiver.nucleus; + foreach (INucleus receiver in nucleus.receivers) { + INucleus receiverNucleus = receiver; if (receiverNucleus == null) continue; @@ -290,7 +290,7 @@ public class NanoBrainInspector : Editor { } } - private void DrawNucleus(INucleus nucleus, Vector3 position, float maxValue, float size) { + private void DrawNucleus(IReceptor nucleus, Vector3 position, float maxValue, float size) { if (nucleus.isSleeping) Handles.color = Color.darkRed; else { @@ -358,7 +358,7 @@ public class NanoBrainInspector : Editor { // To do: add HandleClick (see above) to expand the array } - private void HandleMouseHover(INucleus nucleus, Rect rect) { + private void HandleMouseHover(IReceptor nucleus, Rect rect) { GUIContent tooltip; if (nucleus is Perceptoid perceptoid) { if (perceptoid.receptor != null) { @@ -375,10 +375,15 @@ public class NanoBrainInspector : Editor { $"\nValue: {nucleus.outputValue}"); } } + else if (nucleus is INucleus n) { + tooltip = new( + $"{nucleus.name}" + + $"\nsynapse count {n.synapses.Count}" + + $"\nValue: {nucleus.outputValue}"); + } else { tooltip = new( $"{nucleus.name}" + - $"\nsynapse count {nucleus.synapses.Count}" + $"\nValue: {nucleus.outputValue}"); } @@ -391,9 +396,11 @@ public class NanoBrainInspector : Editor { GUI.Box(tooltipRect, tooltip); } - private void HandleClicked(INucleus nucleus) { - this.currentNucleus = nucleus; - BuildLayers(); + private void HandleClicked(IReceptor nucleus) { + if (nucleus is INucleus n) { + this.currentNucleus = n; + BuildLayers(); + } } void DrawInspector(VisualElement inspectorContainer) { @@ -515,9 +522,9 @@ public class NanoBrainInspector : Editor { return; if (nucleus.cluster != null) this.currentNucleus = nucleus.cluster.output; - foreach (Receiver receiver in nucleus.receivers) { - if (receiver.nucleus != null) { - this.currentNucleus = receiver.nucleus; + foreach (INucleus receiver in nucleus.receivers) { + if (receiver != null) { + this.currentNucleus = receiver; break; } } @@ -561,8 +568,8 @@ public class NanoBrainInspector : Editor { // Nucleus n = this.currentNucleus.brain.nuclei[selectedIndex - perceptei.Count()]; // n.AddReceiver(this.currentNucleus); // } - Nucleus n = this.currentNucleus.cluster.nuclei[selectedIndex]; - n.AddReceiver(this.currentNucleus); + INucleus n = this.currentNucleus.cluster.nuclei[selectedIndex]; + n.AddReceiver(this.currentNucleus); } } diff --git a/Assets/NanoBrain/VisualEditor/NanoBrain.cs b/Assets/NanoBrain/VisualEditor/NanoBrain.cs index 8ac0896..e9b5a8b 100644 --- a/Assets/NanoBrain/VisualEditor/NanoBrain.cs +++ b/Assets/NanoBrain/VisualEditor/NanoBrain.cs @@ -17,7 +17,7 @@ public class NanoBrain : ScriptableObject, ISerializationCallbackReceiver { public NanoBrain() { // this.cluster = new(); // this.output = new Neuroid(this.cluster, "Root"); - } + } public Cluster cluster; @@ -38,7 +38,9 @@ public class NanoBrain : ScriptableObject, ISerializationCallbackReceiver { } public void OnBeforeSerialize() { - this.rootId = output.id; + if (output != null) { + this.rootId = output.id; + } } public void OnAfterDeserialize() { try { diff --git a/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs b/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs index 5be46f1..475e1a0 100644 --- a/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs +++ b/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs @@ -1,11 +1,11 @@ using UnityEngine; public class NanoBrainComponent : MonoBehaviour { - public NanoBrain defaultBrain; - private NanoBrain brainInstance; + public Cluster defaultBrain; + private Cluster brainInstance; - public Nucleus root => brainInstance.output; - public NanoBrain brain { + public INucleus root => brainInstance.output; + public Cluster brain { get { if (brainInstance == null && defaultBrain != null) { brainInstance = Instantiate(defaultBrain); @@ -21,8 +21,8 @@ public class NanoBrainComponent : MonoBehaviour { } } - public static void UpdateWeight(NanoBrain brain, string name, float weight) { - Nucleus root = brain.output; + public static void UpdateWeight(Cluster brain, string name, float weight) { + INucleus root = brain.output; foreach (Synapse synapse in root.synapses) { if (synapse.nucleus.name == name) { synapse.weight = weight; diff --git a/Assets/Scenes/Boids/New Cluster.asset b/Assets/Scenes/Boids/New Cluster.asset deleted file mode 100644 index 4f690b1..0000000 --- a/Assets/Scenes/Boids/New Cluster.asset +++ /dev/null @@ -1,20 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3} - m_Name: New Cluster - m_EditorClassIdentifier: Assembly-CSharp::Cluster - nuclei: - - id: 764290112 - _name: Output - _synapses: [] - _receivers: [] - nucleusType: diff --git a/Assets/Scenes/Boids/NewSwarm.asset b/Assets/Scenes/Boids/NewSwarm.asset new file mode 100644 index 0000000..d64c329 --- /dev/null +++ b/Assets/Scenes/Boids/NewSwarm.asset @@ -0,0 +1,100 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3} + m_Name: NewSwarm + m_EditorClassIdentifier: Assembly-CSharp::Cluster + nuclei: + - rid: 2243601034565648442 + - rid: 2243601034565648443 + references: + version: 2 + RefIds: + - rid: 2243601034565648442 + type: {class: Neuroid, ns: , asm: Assembly-CSharp} + data: + id: 322343360 + _name: Output + _synapses: + - nucleus: + rid: 2243601034565648443 + cluster: {fileID: 0} + weight: 1 + curveMax: 1 + _receivers: [] + nucleusType: + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1000 + value: 1000 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 + - rid: 2243601034565648443 + type: {class: Neuroid, ns: , asm: Assembly-CSharp} + data: + id: -1924138416 + _name: Avoidance + _synapses: [] + _receivers: + - rid: 2243601034565648442 + nucleusType: + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1000 + value: 1000 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + inverse: 0 + exponent: 1 diff --git a/Assets/Scenes/Boids/New Cluster.asset.meta b/Assets/Scenes/Boids/NewSwarm.asset.meta similarity index 100% rename from Assets/Scenes/Boids/New Cluster.asset.meta rename to Assets/Scenes/Boids/NewSwarm.asset.meta diff --git a/Assets/Scenes/Boids/Prefabs/Boid.prefab b/Assets/Scenes/Boids/Prefabs/Boid.prefab index 37277d0..f4f2d9b 100644 --- a/Assets/Scenes/Boids/Prefabs/Boid.prefab +++ b/Assets/Scenes/Boids/Prefabs/Boid.prefab @@ -179,4 +179,4 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 92f34a5e4027a1dc39efd8ce63cf6aba, type: 3} m_Name: m_EditorClassIdentifier: Assembly-CSharp::NanoBrainComponent - defaultBrain: {fileID: 11400000, guid: fc1a4800a8c531eb4855b436bc9084ae, type: 2} + defaultBrain: {fileID: 11400000, guid: eddc759ede59e66cd936ad6ae2c55c46, type: 2} diff --git a/Assets/Scenes/Boids/Scripts/Boid.cs b/Assets/Scenes/Boids/Scripts/Boid.cs index 7b16c88..a3f81d3 100644 --- a/Assets/Scenes/Boids/Scripts/Boid.cs +++ b/Assets/Scenes/Boids/Scripts/Boid.cs @@ -1,104 +1,109 @@ -using UnityEngine; - -//[RequireComponent(typeof(NanoBrain))] -[RequireComponent(typeof(NanoBrainComponent))] -public class Boid : MonoBehaviour { - public static int BoundaryType = 1; - public static int BoidType = 2; - public static int BoidVelocityType =3; - - public SwarmControl sc; - public Vector3 velocity = Vector3.zero; - public Vector3 acceleration = Vector3.zero; - - private Bounds innerBounds; - - public NanoBrainComponent nanoBrain; - public Receptor boundaryReceptor; - public Receptor boidReceptor; - public Receptor boidVelocityReceptor; - - public int id; - - public Material red; - public Material gray; - - void Awake() { - this.id = this.GetInstanceID(); - - nanoBrain = GetComponent(); - boundaryReceptor = Receptor.GetReceptor(nanoBrain.brain, BoundaryType); - boidReceptor = Receptor.GetReceptor(nanoBrain.brain, BoidType); - boidVelocityReceptor = Receptor.GetReceptor(nanoBrain.brain, BoidVelocityType); - - sc = FindFirstObjectByType(); - - innerBounds = new(sc.transform.position, sc.spaceSize - 2 * sc.boundaryWidth); - } - - void Update() { - Collider[] results = Physics.OverlapSphere(this.transform.position, sc.perceptionDistance); - foreach (Collider c in results) { - if (c as CapsuleCollider != null) { - Boid neighbour = c.GetComponentInParent(); - if (neighbour == null || neighbour == this) - continue; - - int thingId = neighbour.GetInstanceID(); - - Vector3 localPosition = this.transform.InverseTransformPoint(neighbour.transform.position); - float d = localPosition.magnitude; - if (d <= sc.separationDistance) - localPosition = localPosition.normalized * 0.01f; - else - localPosition = localPosition.normalized * (localPosition.magnitude - sc.separationDistance); - if (localPosition.sqrMagnitude > 0) - boidReceptor?.ProcessStimulus(thingId, localPosition, neighbour.name); - - Vector3 localVelocity = this.transform.InverseTransformVector(neighbour.velocity); - if (localVelocity.sqrMagnitude > 0) - boidVelocityReceptor?.ProcessStimulus(thingId, localVelocity); - } - } - - if (!innerBounds.Contains(this.transform.position)) { - Vector3 point = this.transform.position; - Vector3 pointOnBounds = innerBounds.ClosestPoint(point); - Vector3 desiredWorldSpace = (pointOnBounds - point).normalized * sc.speed; - Vector3 desiredLocalSpace = -this.transform.InverseTransformPoint(desiredWorldSpace); - boundaryReceptor.ProcessStimulus(777, desiredLocalSpace); - } - - Vector3 worldForce = this.transform.TransformDirection(nanoBrain.root.outputValue); - - this.velocity = (1 - sc.inertia) * (worldForce * Time.deltaTime) + sc.inertia * velocity; - if (this.velocity.magnitude > 0) - this.velocity = this.velocity.normalized * sc.speed; - else - this.velocity = this.transform.forward * sc.speed; - //Debug.DrawRay(this.transform.position, this.velocity, Color.blue); - - this.transform.position += this.velocity * Time.deltaTime; - - if (this.velocity != Vector3.zero) { - Quaternion targetRotation = Quaternion.LookRotation(this.velocity); - transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 5f); // Adjust the speed of rotation - } - - nanoBrain.brain.UpdateNuclei(); - - // Renderer renderer = GetComponentInChildren(); - // results = Physics.OverlapSphere(this.transform.position, 0.1f); - // if (results.Length > 1) { - // // string s= this.name; - // // foreach (Collider c in results) - // // s += " " + c.transform.parent.gameObject.name; - // // Debug.Log(s); - // renderer.sharedMaterial = red; - // } - // else { - // renderer.sharedMaterial = gray; - // } - } - -} +using UnityEngine; + +//[RequireComponent(typeof(NanoBrain))] +[RequireComponent(typeof(NanoBrainComponent))] +public class Boid : MonoBehaviour { + public static int BoundaryType = 1; + public static int BoidType = 2; + public static int BoidVelocityType =3; + + public SwarmControl sc; + public Vector3 velocity = Vector3.zero; + public Vector3 acceleration = Vector3.zero; + + private Bounds innerBounds; + + public NanoBrainComponent nanoBrain; + public Receptor boundaryReceptor; + public Receptor boidReceptor; + public Receptor boidVelocityReceptor; + + public int id; + + public Material red; + public Material gray; + + void Awake() { + this.id = this.GetInstanceID(); + + nanoBrain = GetComponent(); + // boundaryReceptor = Receptor.GetReceptor(nanoBrain.brain, BoundaryType); + // boidReceptor = Receptor.GetReceptor(nanoBrain.brain, BoidType); + // boidVelocityReceptor = Receptor.GetReceptor(nanoBrain.brain, BoidVelocityType); + boundaryReceptor = Receptor.CreateReceptor(nanoBrain.brain, "Avoidance"); + boundaryReceptor.name = "Boundary"; + boundaryReceptor.receivers[0].synapses[0].weight = -1; + boidReceptor = Receptor.CreateReceptor(nanoBrain.brain, "Boid"); + boidVelocityReceptor = Receptor.CreateReceptor(nanoBrain.brain, "Alignment"); + + sc = FindFirstObjectByType(); + + innerBounds = new(sc.transform.position, sc.spaceSize - 2 * sc.boundaryWidth); + } + + void Update() { + Collider[] results = Physics.OverlapSphere(this.transform.position, sc.perceptionDistance); + foreach (Collider c in results) { + if (c as CapsuleCollider != null) { + Boid neighbour = c.GetComponentInParent(); + if (neighbour == null || neighbour == this) + continue; + + int thingId = neighbour.GetInstanceID(); + + Vector3 localPosition = this.transform.InverseTransformPoint(neighbour.transform.position); + float d = localPosition.magnitude; + if (d <= sc.separationDistance) + localPosition = localPosition.normalized * 0.01f; + else + localPosition = localPosition.normalized * (localPosition.magnitude - sc.separationDistance); + if (localPosition.sqrMagnitude > 0) + boidReceptor?.ProcessStimulus(thingId, localPosition, neighbour.name); + + Vector3 localVelocity = this.transform.InverseTransformVector(neighbour.velocity); + if (localVelocity.sqrMagnitude > 0) + boidVelocityReceptor?.ProcessStimulus(thingId, localVelocity); + } + } + + if (!innerBounds.Contains(this.transform.position)) { + Vector3 point = this.transform.position; + Vector3 pointOnBounds = innerBounds.ClosestPoint(point); + Vector3 desiredWorldSpace = (pointOnBounds - point).normalized * sc.speed; + Vector3 desiredLocalSpace = -this.transform.InverseTransformPoint(desiredWorldSpace); + boundaryReceptor.ProcessStimulus(777, desiredLocalSpace); + } + + Vector3 worldForce = this.transform.TransformDirection(nanoBrain.root.outputValue); + + this.velocity = (1 - sc.inertia) * (worldForce * Time.deltaTime) + sc.inertia * velocity; + if (this.velocity.magnitude > 0) + this.velocity = this.velocity.normalized * sc.speed; + else + this.velocity = this.transform.forward * sc.speed; + //Debug.DrawRay(this.transform.position, this.velocity, Color.blue); + + this.transform.position += this.velocity * Time.deltaTime; + + if (this.velocity != Vector3.zero) { + Quaternion targetRotation = Quaternion.LookRotation(this.velocity); + transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 5f); // Adjust the speed of rotation + } + + nanoBrain.brain.UpdateNuclei(); + + // Renderer renderer = GetComponentInChildren(); + // results = Physics.OverlapSphere(this.transform.position, 0.1f); + // if (results.Length > 1) { + // // string s= this.name; + // // foreach (Collider c in results) + // // s += " " + c.transform.parent.gameObject.name; + // // Debug.Log(s); + // renderer.sharedMaterial = red; + // } + // else { + // renderer.sharedMaterial = gray; + // } + } + +} diff --git a/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs b/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs index 5adbcb7..d8dbd3b 100644 --- a/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs +++ b/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs @@ -1,33 +1,33 @@ -using UnityEditor; -using UnityEngine; - -[CustomEditor(typeof(SwarmControl))] -public class SwarmControl_Editor : Editor { - public override void OnInspectorGUI() { - EditorGUI.BeginChangeCheck(); - - DrawDefaultInspector(); - - if (EditorGUI.EndChangeCheck()) { - SwarmControl swarmControl = (SwarmControl)target; - NanoBrain[] nanoBrains = FindObjectsByType(FindObjectsSortMode.None); - - foreach (NanoBrain brain in nanoBrains) { - NanoBrainComponent.UpdateWeight(brain, "Avoidance", swarmControl.avoidanceForce); - NanoBrainComponent.UpdateWeight(brain, "Cohesion", swarmControl.cohesionForce); - NanoBrainComponent.UpdateWeight(brain, "Separation", swarmControl.separationForce); - NanoBrainComponent.UpdateWeight(brain, "Alignment", swarmControl.alignmentForce); - } - Debug.Log("Updated weights"); - } - } - - // protected void UpdateWeight(NanoBrain brain, string name, float weight) { - // Nucleus root = brain.root; - // foreach (Synapse synapse in root.synapses) { - // if (synapse.nucleus.name == name) { - // synapse.weight = weight; - // } - // } - // } +using UnityEditor; +using UnityEngine; + +[CustomEditor(typeof(SwarmControl))] +public class SwarmControl_Editor : Editor { + public override void OnInspectorGUI() { + EditorGUI.BeginChangeCheck(); + + DrawDefaultInspector(); + + if (EditorGUI.EndChangeCheck()) { + SwarmControl swarmControl = (SwarmControl)target; + Cluster[] nanoBrains = FindObjectsByType(FindObjectsSortMode.None); + + foreach (Cluster brain in nanoBrains) { + NanoBrainComponent.UpdateWeight(brain, "Avoidance", swarmControl.avoidanceForce); + NanoBrainComponent.UpdateWeight(brain, "Cohesion", swarmControl.cohesionForce); + NanoBrainComponent.UpdateWeight(brain, "Separation", swarmControl.separationForce); + NanoBrainComponent.UpdateWeight(brain, "Alignment", swarmControl.alignmentForce); + } + Debug.Log("Updated weights"); + } + } + + // protected void UpdateWeight(NanoBrain brain, string name, float weight) { + // Nucleus root = brain.root; + // foreach (Synapse synapse in root.synapses) { + // if (synapse.nucleus.name == name) { + // synapse.weight = weight; + // } + // } + // } } \ No newline at end of file diff --git a/Assets/Scenes/Boids/SwarmingBrain.asset b/Assets/Scenes/Boids/SwarmingBrain.asset index ffe8dd0..a0943f9 100644 --- a/Assets/Scenes/Boids/SwarmingBrain.asset +++ b/Assets/Scenes/Boids/SwarmingBrain.asset @@ -7478,8 +7478,8 @@ MonoBehaviour: array: rid: -2 thingType: 3 - cluster: {fileID: 0} rootId: -1707533328 + cluster: {fileID: 0} references: version: 2 RefIds: From e477ce4814432e35353c4fa4281d101a6efbf75d Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 12 Jan 2026 16:06:12 +0100 Subject: [PATCH 063/179] (re)added nucleus arrays --- Assembly-CSharp.csproj | 2 +- Assets/NanoBrain/Cluster.cs | 10 +- Assets/NanoBrain/INucleus.cs | 6 +- Assets/NanoBrain/Neuroid.cs | 22 +++ Assets/NanoBrain/Nucleus.cs | 106 +++++++-------- Assets/NanoBrain/NucleusArray.cs | 45 +++++++ ...pteiArray.cs.meta => NucleusArray.cs.meta} | 0 Assets/NanoBrain/PercepteiArray.cs | 61 --------- Assets/NanoBrain/Perceptoid.cs | 2 + Assets/NanoBrain/Receptor.cs | 56 ++++---- Assets/NanoBrain/Synapse.cs | 36 ++--- .../VisualEditor/Editor/BrainPickerWindow.cs | 10 +- .../VisualEditor/Editor/ClusterInspector.cs | 125 +++++------------- .../VisualEditor/Editor/NanoBrainInspector.cs | 7 +- Assets/NanoBrain/VisualEditor/NanoBrain.cs | 8 +- 15 files changed, 223 insertions(+), 273 deletions(-) create mode 100644 Assets/NanoBrain/NucleusArray.cs rename Assets/NanoBrain/{PercepteiArray.cs.meta => NucleusArray.cs.meta} (100%) delete mode 100644 Assets/NanoBrain/PercepteiArray.cs diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index d59c742..891c3d0 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -62,7 +62,6 @@ - @@ -83,6 +82,7 @@ + diff --git a/Assets/NanoBrain/Cluster.cs b/Assets/NanoBrain/Cluster.cs index 2216d32..a148a00 100644 --- a/Assets/NanoBrain/Cluster.cs +++ b/Assets/NanoBrain/Cluster.cs @@ -21,6 +21,13 @@ public class Cluster : ScriptableObject, INucleus { private readonly List _synapses = new(); public List synapses => _synapses; + public NucleusArray array { get; set; } + + public INucleus Clone() { + Cluster clone = CreateInstance(); + // Lots to add here... + return clone; + } // Call this function to ensure that there is at least one nucleus // This is an invariant and should be ensured before the nucleus is used @@ -42,9 +49,10 @@ public class Cluster : ScriptableObject, INucleus { get => output.receivers; } - public void AddSynapse(IReceptor sender) { + public Synapse AddSynapse(IReceptor sender) { Synapse synapse = new(sender, 1.0f); synapses.Add(synapse); + return synapse; } public void GarbageCollection() { diff --git a/Assets/NanoBrain/INucleus.cs b/Assets/NanoBrain/INucleus.cs index 45c0acd..535caca 100644 --- a/Assets/NanoBrain/INucleus.cs +++ b/Assets/NanoBrain/INucleus.cs @@ -10,7 +10,9 @@ public interface INucleus : IReceptor { // Senders public List synapses { get; } - public void AddSynapse(IReceptor sender); + public Synapse AddSynapse(IReceptor sender); + + public NucleusArray array { get; set; } #endregion static struct @@ -21,6 +23,8 @@ public interface INucleus : IReceptor { public void IncreaseAge(); #endregion dynamic state + + public INucleus Clone(); } public interface IReceptor { diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index 9e56de1..f14a788 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -16,6 +16,28 @@ public class Neuroid : Nucleus { public Neuroid(string name) : base(name) { } + public override INucleus Clone() { + Neuroid clone = new(this.name) { + cluster = this.cluster, + array = this.array, + curve = this.curve, + curvePreset = this.curvePreset, + curveMax = this.curveMax, + average = this.average + }; + if (clone.cluster != null) + clone.cluster.nuclei.Add(clone); + + foreach (Synapse synapse in this.synapses) { + Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); + clonedSynapse.weight = synapse.weight; + } + foreach (INucleus receiver in this.receivers) { + clone.AddReceiver(receiver); + } + return clone; + } + public void SetWeight(Neuroid input, float weight) { this.SetWeight((Nucleus)input, weight); } diff --git a/Assets/NanoBrain/Nucleus.cs b/Assets/NanoBrain/Nucleus.cs index 41ac085..01f0693 100644 --- a/Assets/NanoBrain/Nucleus.cs +++ b/Assets/NanoBrain/Nucleus.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using UnityEngine; -using UnityEditor; [Serializable] public class Nucleus : INucleus { @@ -23,6 +22,7 @@ public class Nucleus : INucleus { private List _receivers = new(); public List receivers => _receivers; + public NucleusArray array { get; set; } #region Serialization [SerializeField] @@ -67,31 +67,31 @@ public class Nucleus : INucleus { } } - public virtual void Rebuild(NanoBrain brain) { - if (this.synapses != null) { - foreach (Synapse synapse in synapses) - synapse.Rebuild(brain); - } - // foreach (INucleus receiver in receivers.ToArray()) { - // if (receiver.Rebuild(brain) == false) { - // Debug.Log("Rebuilding failed, removing receiver."); - // receivers.Remove(receiver); - // } - // } - } + // public virtual void Rebuild(NanoBrain brain) { + // if (this.synapses != null) { + // foreach (Synapse synapse in synapses) + // synapse.Rebuild(brain); + // } + // // foreach (INucleus receiver in receivers.ToArray()) { + // // if (receiver.Rebuild(brain) == false) { + // // Debug.Log("Rebuilding failed, removing receiver."); + // // receivers.Remove(receiver); + // // } + // // } + // } - public static Nucleus RebuildType(NanoBrain brain, Nucleus nucleus) { - if (string.IsNullOrEmpty(nucleus.nucleusType) == false) { - Type nucleusType = Type.GetType(nucleus.nucleusType); - if (nucleusType != null) { - object[] args = new object[] { brain, nucleus.name }; - Nucleus rebuiltNucleus = (Nucleus)Activator.CreateInstance(nucleusType, args); - rebuiltNucleus.Deserialize(nucleus); - return rebuiltNucleus; - } - } - return nucleus; - } + // public static Nucleus RebuildType(NanoBrain brain, Nucleus nucleus) { + // if (string.IsNullOrEmpty(nucleus.nucleusType) == false) { + // Type nucleusType = Type.GetType(nucleus.nucleusType); + // if (nucleusType != null) { + // object[] args = new object[] { brain, nucleus.name }; + // Nucleus rebuiltNucleus = (Nucleus)Activator.CreateInstance(nucleusType, args); + // rebuiltNucleus.Deserialize(nucleus); + // return rebuiltNucleus; + // } + // } + // return nucleus; + // } public virtual void Deserialize(Nucleus nucleus) { } @@ -133,10 +133,29 @@ public class Nucleus : INucleus { this.id = this.GetHashCode(); } + public virtual INucleus Clone() { + Nucleus clone = new(this.name) { + cluster = this.cluster, + array = this.array, + curve = this.curve, + curvePreset = this.curvePreset, + curveMax = this.curveMax + }; + if (clone.cluster != null) + clone.cluster.nuclei.Add(clone); + + foreach (Synapse synapse in this.synapses) { + Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); + clonedSynapse.weight = synapse.weight; + } + foreach (INucleus receiver in this.receivers) { + clone.AddReceiver(receiver); + } + return clone; + } + public virtual void AddReceiver(INucleus receivingNucleus) { - // this.receivers.Add(new Receiver(receivingNucleus)); this.receivers.Add(receivingNucleus); - //receivingNucleus.SetWeight(this, 1.0f); receivingNucleus.AddSynapse(this); } @@ -182,9 +201,10 @@ public class Nucleus : INucleus { return false; } - public void AddSynapse(IReceptor sendingNucleus) { + public Synapse AddSynapse(IReceptor sendingNucleus) { Synapse synapse = new(sendingNucleus, 1.0f); this.synapses.Add(synapse); + return synapse; } public void SetWeight(Nucleus nucleus, float weight) { foreach (Synapse synapse in synapses) { @@ -211,32 +231,4 @@ public class Nucleus : INucleus { receiver.UpdateState(); } -} - -// [Serializable] -// public class Receiver { -// [NonSerialized] -// public INucleus nucleus; -// //public int nucleusId; - -// public Receiver(INucleus nucleus) { -// this.nucleus = nucleus; -// //this.nucleusId = nucleus.id; -// } - -// public bool Rebuild(NanoBrain brain) { -// if (brain == null) { -// return false; -// } - -// // Use SerializedReference instead? -// // foreach (Nucleus nucleus in brain.nuclei) { -// // if (nucleus.id == this.nucleusId) { -// // this.nucleus = nucleus; -// // return true; -// // } -// // } -// //Debug.LogWarning($"Receiver deserialization error: could not find nucleus with id {this.nucleusId}"); -// return false; -// } -// } \ No newline at end of file +} \ No newline at end of file diff --git a/Assets/NanoBrain/NucleusArray.cs b/Assets/NanoBrain/NucleusArray.cs new file mode 100644 index 0000000..db34958 --- /dev/null +++ b/Assets/NanoBrain/NucleusArray.cs @@ -0,0 +1,45 @@ + +using UnityEngine; + +[System.Serializable] +public class NucleusArray { + [SerializeReference] + public INucleus[] nuclei; + public string name; + + public NucleusArray(INucleus nucleus) { + this.name = nucleus.name; + this.nuclei = new INucleus[1]; + this.nuclei[0] = nucleus; + } + + public void AddNucleus() { + if (this.nuclei.Length == 0) { + Debug.LogError("Empty perceptoid array, cannot add"); + return; + } + int newLength = this.nuclei.Length + 1; + INucleus[] newArray = new INucleus[newLength]; + + for (int i = 0; i < this.nuclei.Length; i++) + newArray[i] = this.nuclei[i]; + newArray[newLength - 1] = this.nuclei[0].Clone(); + + this.nuclei = newArray; + } + + public void RemoveNucleus() { + int newLength = this.nuclei.Length - 1; + if (newLength == 0) { + Debug.LogWarning("Perceptoid array cannot be empty"); + return; + } + INucleus[] newPerceptei = new INucleus[newLength]; + for (int i = 0; i < newLength; i++) + newPerceptei[i++] = this.nuclei[i]; + // Delete the last perception + Nucleus.Delete(this.nuclei[newLength]); + + this.nuclei = newPerceptei; + } +} \ No newline at end of file diff --git a/Assets/NanoBrain/PercepteiArray.cs.meta b/Assets/NanoBrain/NucleusArray.cs.meta similarity index 100% rename from Assets/NanoBrain/PercepteiArray.cs.meta rename to Assets/NanoBrain/NucleusArray.cs.meta diff --git a/Assets/NanoBrain/PercepteiArray.cs b/Assets/NanoBrain/PercepteiArray.cs deleted file mode 100644 index a46f2d0..0000000 --- a/Assets/NanoBrain/PercepteiArray.cs +++ /dev/null @@ -1,61 +0,0 @@ -using UnityEngine; - -[System.Serializable] -public class PercepteiArray { - [SerializeReference] - public Perceptoid[] perceptei; - public string name; - - // public PercepteiArray(NanoBrain brain, int thingType, string baseName, uint count) { - // this.name = baseName; - // this.perceptei = new Perceptoid[count]; - // for (uint i = 0; i < count; i++) { - // this.perceptei[i] = new Perceptoid(brain, thingType, $"{baseName}[{i}]") { - // array = this - // }; - // } - // } - public PercepteiArray(Perceptoid perceptoid) { - this.name = perceptoid.baseName; - this.perceptei = new Perceptoid[1]; - this.perceptei[0] = perceptoid; - } - - public void AddPerceptoid() { - if (this.perceptei.Length == 0) { - Debug.LogError("Empty perceptoid array, cannot add"); - return; - } - int newLength = this.perceptei.Length + 1; - Perceptoid[] newPerceptei = new Perceptoid[newLength]; - - for (int i = 0; i < this.perceptei.Length; i++) - newPerceptei[i] = this.perceptei[i]; - newPerceptei[newLength - 1] = new Perceptoid(this); - - this.perceptei = newPerceptei; - } - - public void RemovePerceptoid() { - int newLength = this.perceptei.Length - 1; - if (newLength == 0) { - Debug.LogWarning("Perceptoid array cannot be empty"); - return; - } - Perceptoid[] newPerceptei = new Perceptoid[newLength]; - for (int i = 0; i < newLength; i++) - newPerceptei[i++] = this.perceptei[i]; - // Delete the last perception - Nucleus.Delete(this.perceptei[newLength]); - - this.perceptei = newPerceptei; - } -} - -// public class ArrayPerceptoid : Perceptoid { -// public PercepteiArray array; - -// public ArrayPerceptoid(NanoBrain brain, int thingType, string name = "sensor") : base(brain, thingType, name) { -// } - -// } \ No newline at end of file diff --git a/Assets/NanoBrain/Perceptoid.cs b/Assets/NanoBrain/Perceptoid.cs index b30847e..447a3d7 100644 --- a/Assets/NanoBrain/Perceptoid.cs +++ b/Assets/NanoBrain/Perceptoid.cs @@ -1,3 +1,4 @@ +/* using UnityEngine; [System.Serializable] @@ -101,3 +102,4 @@ public class Perceptoid : Neuroid { } } +*/ \ No newline at end of file diff --git a/Assets/NanoBrain/Receptor.cs b/Assets/NanoBrain/Receptor.cs index dcd3c28..39f1699 100644 --- a/Assets/NanoBrain/Receptor.cs +++ b/Assets/NanoBrain/Receptor.cs @@ -10,18 +10,12 @@ public class Receptor : IReceptor { set => _name = value; } - public Cluster cluster; - //public INucleus nucleus; - - //[SerializeField] [SerializeReference] private List _receivers = new(); public List receivers => _receivers; public virtual void AddReceiver(INucleus receivingNucleus) { - //this.receivers.Add(new Receiver(receivingNucleus)); this.receivers.Add(receivingNucleus); - //receivingNucleus.SetWeight(this, 1.0f); receivingNucleus.AddSynapse(this); } @@ -35,18 +29,18 @@ public class Receptor : IReceptor { /// /// The list of perceptoid which can process stimuli from this receptor /// - public List perceptei = new(); + //public List perceptei = new(); - private int _thingType = 0; - public int thingType { - get { return _thingType; } - set { - _thingType = value; - foreach (Perceptoid perceptoid in perceptei) { - perceptoid.thingType = _thingType; - } - } - } + // private int _thingType = 0; + // public int thingType { + // get { return _thingType; } + // set { + // _thingType = value; + // foreach (Perceptoid perceptoid in perceptei) { + // perceptoid.thingType = _thingType; + // } + // } + // } public Vector3 localPosition; public float distanceResolution = 0.1f; public float directionResolution = 5; @@ -59,26 +53,24 @@ public class Receptor : IReceptor { } - public Receptor(NanoBrain brain, int thingType) { - this.thingType = thingType; - //this.perceptei.Add(perceptoid); - brain.receptors.Add(this); - } + // public Receptor(NanoBrain brain, int thingType) { + // this.thingType = thingType; + // brain.receptors.Add(this); + // } public Receptor(Cluster cluster, INucleus nucleus) { - this.cluster = cluster; - //nucleus.AddSynapse(this); + //this.cluster = cluster; this.AddReceiver(nucleus); } - public static Receptor GetReceptor(NanoBrain brain, int thingType) { - foreach (Receptor receptor in brain.receptors) { - if (thingType == 0 || receptor.thingType == thingType) - return receptor; - } - Receptor newReceptor = new(brain, thingType); - return newReceptor; - } + // public static Receptor GetReceptor(NanoBrain brain, int thingType) { + // foreach (Receptor receptor in brain.receptors) { + // if (thingType == 0 || receptor.thingType == thingType) + // return receptor; + // } + // Receptor newReceptor = new(brain, thingType); + // return newReceptor; + // } public static Receptor CreateReceptor(Cluster cluster, string nucleusName) { if (cluster == null) diff --git a/Assets/NanoBrain/Synapse.cs b/Assets/NanoBrain/Synapse.cs index 7bcdfde..ef42fb5 100644 --- a/Assets/NanoBrain/Synapse.cs +++ b/Assets/NanoBrain/Synapse.cs @@ -29,25 +29,25 @@ public class Synapse { this.weight = weight; } - public void Rebuild(NanoBrain brain) { - // if (brain == null) { - // return; - // } + // public void Rebuild(NanoBrain brain) { + // // if (brain == null) { + // // return; + // // } - // foreach (Nucleus nucleus in brain.nuclei) { - // if (nucleus.id == this.nucleusId) { - // this.nucleus = nucleus; - // return; - // } - // } - // foreach (Perceptoid perceptoid in brain.perceptei) { - // if (perceptoid.id == this.nucleusId) { - // this.nucleus = perceptoid; - // return; - // } - // } - // Debug.LogError($"Synapse deserialization error: could not find nucleus with id {this.nucleusId}"); - } + // // foreach (Nucleus nucleus in brain.nuclei) { + // // if (nucleus.id == this.nucleusId) { + // // this.nucleus = nucleus; + // // return; + // // } + // // } + // // foreach (Perceptoid perceptoid in brain.perceptei) { + // // if (perceptoid.id == this.nucleusId) { + // // this.nucleus = perceptoid; + // // return; + // // } + // // } + // // Debug.LogError($"Synapse deserialization error: could not find nucleus with id {this.nucleusId}"); + // } // public AnimationCurve GenerateCurve() { // switch (this.curvePreset) { diff --git a/Assets/NanoBrain/VisualEditor/Editor/BrainPickerWindow.cs b/Assets/NanoBrain/VisualEditor/Editor/BrainPickerWindow.cs index d80c282..6e7a849 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/BrainPickerWindow.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/BrainPickerWindow.cs @@ -6,11 +6,11 @@ using System.Linq; public class BrainPickerWindow : EditorWindow { private Vector2 scroll; - private NanoBrain[] items = new NanoBrain[0]; - private Action onPicked; + private Cluster[] items = new Cluster[0]; + private Action onPicked; private string search = ""; - public static void ShowPicker(Action onPicked, string title = "Select NanoBrain") + public static void ShowPicker(Action onPicked, string title = "Select NanoBrain") { var w = CreateInstance(); w.titleContent = new GUIContent(title); @@ -26,7 +26,7 @@ public class BrainPickerWindow : EditorWindow { var guids = AssetDatabase.FindAssets("t:NanoBrain"); items = guids - .Select(g => AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(g))) + .Select(g => AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(g))) .Where(b => b != null) .OrderBy(b => b.name) .ToArray(); @@ -52,7 +52,7 @@ public class BrainPickerWindow : EditorWindow continue; EditorGUILayout.BeginHorizontal(); - EditorGUILayout.LabelField(EditorGUIUtility.ObjectContent(it, typeof(NanoBrain)), GUILayout.Height(20)); + EditorGUILayout.LabelField(EditorGUIUtility.ObjectContent(it, typeof(Cluster)), GUILayout.Height(20)); if (GUILayout.Button("Select", GUILayout.Width(70))) { onPicked?.Invoke(it); diff --git a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs index b3a443b..1d7ae17 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs @@ -271,25 +271,14 @@ public class ClusterInspector : Editor { float margin = 10 + spacing / 2; int row = 0; - List drawnArrays = new(); + List drawnArrays = new(); foreach (Synapse synapse in nucleus.synapses) { Vector3 pos = new(250, margin + row * spacing, 0.0f); Handles.color = Color.white; Handles.DrawLine(parentPos, pos); - // if (synapse.nucleus is Perceptoid perceptoid && perceptoid.array != null) { - // // if (drawnArrays.Contains(perceptoid.array)) - // // // We already drawn this array - // // continue; - - // drawnArrays.Add(perceptoid.array); - // DrawArray(perceptoid.array, pos, size); - // } - // else { - if (synapse.nucleus != null) DrawNucleus(synapse.nucleus, pos, maxValue, size); row++; - // } } } @@ -315,12 +304,12 @@ public class ClusterInspector : Editor { normal = { textColor = Color.white }, fontStyle = FontStyle.Bold, }; - if (nucleus is Perceptoid perceptoid) { - if (perceptoid.array == null || perceptoid.array.perceptei == null || perceptoid.array.perceptei.Length == 0) - perceptoid.array = new PercepteiArray(perceptoid); + if (nucleus is Nucleus perceptoid) { + if (perceptoid.array == null || perceptoid.array.nuclei == null || perceptoid.array.nuclei.Length == 0) + perceptoid.array = new NucleusArray(perceptoid); - if (perceptoid.array.perceptei.Length > 1) { - Handles.Label(labelPosition, perceptoid.array.perceptei.Length.ToString(), style); + if (perceptoid.array.nuclei.Length > 1) { + Handles.Label(labelPosition, perceptoid.array.nuclei.Length.ToString(), style); } } @@ -344,46 +333,15 @@ public class ClusterInspector : Editor { } } - private void DrawArray(PercepteiArray array, Vector3 position, float size) { - Vector3 offset = new(size / 4, size / 4, 0); - Handles.color = Color.black; - Handles.DrawSolidDisc(position, Vector3.forward, size); - - GUIStyle style = new(EditorStyles.label) { - alignment = TextAnchor.UpperCenter, - normal = { textColor = Color.white }, - fontStyle = FontStyle.Bold - }; - Handles.Label(position, array.perceptei.Length.ToString(), style); - Vector3 labelPos = position - Vector3.down * (size + 0.2f); // below disc along up axis - Handles.Label(labelPos, array.name, style); - - // To do: add HandleClick (see above) to expand the array - } - private void HandleMouseHover(IReceptor nucleus, Rect rect) { GUIContent tooltip; - if (nucleus is Perceptoid perceptoid) { - if (perceptoid.receptor != null) { - tooltip = new( - $"{perceptoid.name}" + - $"\nType {perceptoid.receptor.thingType}" + - $" Thing {perceptoid.thingId}" + - $"\nValue: {nucleus.outputValue}"); - } - else { - tooltip = new( - $"{perceptoid.name}" + - $"\nThing {perceptoid.thingId}" + - $"\nValue: {nucleus.outputValue}"); - } - } - else if (nucleus is INucleus n) { + if (nucleus is INucleus n) { tooltip = new( $"{nucleus.name}" + $"\nsynapse count {n.synapses.Count}" + $"\nValue: {nucleus.outputValue}"); - } else { + } + else { tooltip = new( $"{nucleus.name}" + $"\nValue: {nucleus.outputValue}"); @@ -400,8 +358,8 @@ public class ClusterInspector : Editor { private void HandleClicked(IReceptor nucleus) { if (nucleus is INucleus n) { - this.currentNucleus = n; - BuildLayers(); + this.currentNucleus = n; + BuildLayers(); } } @@ -424,29 +382,30 @@ public class ClusterInspector : Editor { return; this.currentNucleus.name = EditorGUILayout.TextField(this.currentNucleus.name); - if (this.currentNucleus is Perceptoid perceptoid) { - perceptoid.receptor.thingType = EditorGUILayout.IntField("Thing Type", perceptoid.receptor.thingType); + if (this.currentNucleus is Nucleus perceptoid) { + // perceptoid.receptor.thingType = EditorGUILayout.IntField("Thing Type", perceptoid.receptor.thingType); - if (perceptoid.array == null || perceptoid.array.perceptei == null || perceptoid.array.perceptei.Length == 0) - perceptoid.array = new PercepteiArray(perceptoid); + if (perceptoid.array == null || perceptoid.array.nuclei == null || perceptoid.array.nuclei.Length == 0) + perceptoid.array = new NucleusArray(perceptoid); EditorGUILayout.BeginHorizontal(); - EditorGUILayout.IntField("Array size", perceptoid.array.perceptei.Length); + EditorGUILayout.IntField("Array size", perceptoid.array.nuclei.Length); if (GUILayout.Button("Add")) - perceptoid.array.AddPerceptoid(); + perceptoid.array.AddNucleus(); if (GUILayout.Button("Del")) - perceptoid.array.RemovePerceptoid(); - EditorGUILayout.EndHorizontal(); - } - else if (this.currentNucleus is Nucleus neuroid) { - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.LabelField("Activation Curve", GUILayout.Width(150)); - if (neuroid.curveMax > 0) - EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, 0, 1, neuroid.curveMax)); - else - EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, neuroid.curveMax, 1, -neuroid.curveMax)); - neuroid.curvePreset = (Neuroid.CurvePresets)EditorGUILayout.EnumPopup(neuroid.curvePreset, GUILayout.Width(100)); + perceptoid.array.RemoveNucleus(); EditorGUILayout.EndHorizontal(); } + else + if (this.currentNucleus is Nucleus neuroid) { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Activation Curve", GUILayout.Width(150)); + if (neuroid.curveMax > 0) + EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, 0, 1, neuroid.curveMax)); + else + EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, neuroid.curveMax, 1, -neuroid.curveMax)); + neuroid.curvePreset = (Neuroid.CurvePresets)EditorGUILayout.EnumPopup(neuroid.curvePreset, GUILayout.Width(100)); + EditorGUILayout.EndHorizontal(); + } if (Application.isPlaying) EditorGUILayout.FloatField("Output", this.currentNucleus.outputValue.magnitude); @@ -465,14 +424,6 @@ public class ClusterInspector : Editor { else { EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField(synapse.nucleus.name); - // if (synapse.nucleus is Perceptoid perceptoid) { - // if (perceptoid.array == null || perceptoid.array.perceptei == null || perceptoid.array.perceptei.Length == 0) { - // perceptoid.array = new PercepteiArray(perceptoid); - // } - // EditorGUILayout.IntField(perceptoid.array.perceptei.Length); - // if (GUILayout.Button("Add")) - // perceptoid.array.AddPerceptoid(); - // } if (GUILayout.Button("Disconnect")) synapse.nucleus.RemoveReceiver(this.currentNucleus); EditorGUILayout.EndHorizontal(); @@ -491,8 +442,6 @@ public class ClusterInspector : Editor { ConnectNucleus(cluster, this.currentNucleus); if (GUILayout.Button("Add Input Neuron")) AddInputNeuron(this.currentNucleus); - // if (GUILayout.Button("Add Input Perceptoid")) - // AddPerceptoid(this.currentNucleus); if (GUILayout.Button("Add Input Cluster")) AddCluster(this.currentNucleus); @@ -501,7 +450,6 @@ public class ClusterInspector : Editor { if (GUILayout.Button("Delete this neuron")) DeleteNeuron(this.currentNucleus); - //DisconnectNucleus(this.currentNucleus); if (this.gameObject != null) { Vector3 worldVector = this.gameObject.transform.TransformVector(this.currentNucleus.outputValue); @@ -534,19 +482,12 @@ public class ClusterInspector : Editor { BuildLayers(); } - // protected virtual void AddPerceptoid(INucleus nucleus) { - // Perceptoid newPerceptoid = new(this.brain, 0, "New Perceptoid"); - // newPerceptoid.AddReceiver(nucleus); - // this.currentNucleus = newPerceptoid; - // BuildLayers(); - // } - protected virtual void AddCluster(INucleus nucleus) { BrainPickerWindow.ShowPicker(brain => OnClusterPicked(nucleus, brain), "Select Cluster"); } - private void OnClusterPicked(INucleus nucleus, NanoBrain brain) { - NanoBrain brainInstance = Instantiate(brain); + private void OnClusterPicked(INucleus nucleus, Cluster brain) { + Cluster brainInstance = Instantiate(brain); brainInstance.AddReceiver(nucleus); } @@ -555,7 +496,7 @@ public class ClusterInspector : Editor { if (cluster == null) return; - IEnumerable synapseNuclei = this.currentNucleus.synapses.Select(synapse => synapse.nucleus != null ? synapse.nucleus.name: ""); + IEnumerable synapseNuclei = this.currentNucleus.synapses.Select(synapse => synapse.nucleus != null ? synapse.nucleus.name : ""); //IEnumerable perceptei = this.currentNucleus.brain.perceptei.Select(i => i.name).Except(synapseNuclei); IEnumerable nuclei = cluster.nuclei.Select(i => i.name).Except(synapseNuclei); //string[] names = perceptei.Concat(nuclei).ToArray(); @@ -572,7 +513,7 @@ public class ClusterInspector : Editor { // n.AddReceiver(this.currentNucleus); // } INucleus n = cluster.nuclei[selectedIndex]; - n.AddReceiver(this.currentNucleus); + n.AddReceiver(this.currentNucleus); } } diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs index c8cc316..447fa70 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs @@ -1,3 +1,4 @@ +/* using System.Collections.Generic; using System.Linq; using UnityEditor; @@ -364,7 +365,7 @@ public class NanoBrainInspector : Editor { if (perceptoid.receptor != null) { tooltip = new( $"{perceptoid.name}" + - $"\nType {perceptoid.receptor.thingType}" + + // $"\nType {perceptoid.receptor.thingType}" + $" Thing {perceptoid.thingId}" + $"\nValue: {nucleus.outputValue}"); } @@ -423,7 +424,7 @@ public class NanoBrainInspector : Editor { this.currentNucleus.name = EditorGUILayout.TextField(this.currentNucleus.name); if (this.currentNucleus is Perceptoid perceptoid) { - perceptoid.receptor.thingType = EditorGUILayout.IntField("Thing Type", perceptoid.receptor.thingType); + // perceptoid.receptor.thingType = EditorGUILayout.IntField("Thing Type", perceptoid.receptor.thingType); if (perceptoid.array == null || perceptoid.array.perceptei == null || perceptoid.array.perceptei.Length == 0) perceptoid.array = new PercepteiArray(perceptoid); @@ -615,6 +616,7 @@ public class NeuroidLayer { } */ +/* public class GraphNodeWrapper : ScriptableObject { // expose fields that map to GraphNode //public string title; @@ -640,3 +642,4 @@ public class GraphNodeWrapper : ScriptableObject { } } } +*/ \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/NanoBrain.cs b/Assets/NanoBrain/VisualEditor/NanoBrain.cs index e9b5a8b..d786da6 100644 --- a/Assets/NanoBrain/VisualEditor/NanoBrain.cs +++ b/Assets/NanoBrain/VisualEditor/NanoBrain.cs @@ -1,3 +1,4 @@ +/* using System; using System.Collections.Generic; using UnityEngine; @@ -58,7 +59,7 @@ public class NanoBrain : ScriptableObject, ISerializationCallbackReceiver { this.cluster.GarbageCollection(); } - /* + public void GarbageCollection() { HashSet visitedNuclei = new(); MarkNuclei(visitedNuclei, this.output); @@ -96,5 +97,6 @@ public class NanoBrain : ScriptableObject, ISerializationCallbackReceiver { nucleus.receivers.RemoveAll(receiver => visitedReceivers.Contains(receiver) == false); } } - */ -} \ No newline at end of file + +} +*/ \ No newline at end of file From b3823ac2e6e71aad3a4efb86e0555e9f5fe5f861 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 12 Jan 2026 16:13:07 +0100 Subject: [PATCH 064/179] Cleanup --- Assets/NanoBrain/Cluster.cs | 8 +---- Assets/NanoBrain/INucleus.cs | 2 +- Assets/NanoBrain/Neuroid.cs | 15 --------- Assets/NanoBrain/Nucleus.cs | 62 ++---------------------------------- Assets/NanoBrain/Receptor.cs | 39 +---------------------- 5 files changed, 6 insertions(+), 120 deletions(-) diff --git a/Assets/NanoBrain/Cluster.cs b/Assets/NanoBrain/Cluster.cs index a148a00..54b9c92 100644 --- a/Assets/NanoBrain/Cluster.cs +++ b/Assets/NanoBrain/Cluster.cs @@ -104,15 +104,9 @@ public class Cluster : ScriptableObject, INucleus { public void UpdateNuclei() { foreach (INucleus nucleus in nuclei) - nucleus.IncreaseAge(); + nucleus.UpdateNuclei(); } - public void IncreaseAge() { - foreach (INucleus nucleus in nuclei) - nucleus.IncreaseAge(); - } - // ha ha ha - #endregion Dynamics } \ No newline at end of file diff --git a/Assets/NanoBrain/INucleus.cs b/Assets/NanoBrain/INucleus.cs index 535caca..dedd500 100644 --- a/Assets/NanoBrain/INucleus.cs +++ b/Assets/NanoBrain/INucleus.cs @@ -20,7 +20,7 @@ public interface INucleus : IReceptor { public void UpdateState(); - public void IncreaseAge(); + public void UpdateNuclei(); #endregion dynamic state diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index f14a788..b8e14d3 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -38,21 +38,6 @@ public class Neuroid : Nucleus { return clone; } - public void SetWeight(Neuroid input, float weight) { - this.SetWeight((Nucleus)input, weight); - } - - public void SetInput(Neuroid input) { - if (this.SynapseExists(input) == false) - this.SetWeight(input, 1.0f); - UpdateState(); - } - - public void SetInput(Neuroid input, float weight) { - this.SetWeight(input, weight); - UpdateState(); - } - public override void UpdateState() { Vector3 sum = Vector3.zero; int n = 0; diff --git a/Assets/NanoBrain/Nucleus.cs b/Assets/NanoBrain/Nucleus.cs index 01f0693..ffe7125 100644 --- a/Assets/NanoBrain/Nucleus.cs +++ b/Assets/NanoBrain/Nucleus.cs @@ -5,8 +5,6 @@ using UnityEngine; [Serializable] public class Nucleus : INucleus { - public int id; // hash code - [SerializeField] protected string _name; public virtual string name { @@ -23,10 +21,8 @@ public class Nucleus : INucleus { public List receivers => _receivers; public NucleusArray array { get; set; } - #region Serialization - [SerializeField] - protected string nucleusType; + #region Serialization public enum CurvePresets { Linear, @@ -67,32 +63,6 @@ public class Nucleus : INucleus { } } - // public virtual void Rebuild(NanoBrain brain) { - // if (this.synapses != null) { - // foreach (Synapse synapse in synapses) - // synapse.Rebuild(brain); - // } - // // foreach (INucleus receiver in receivers.ToArray()) { - // // if (receiver.Rebuild(brain) == false) { - // // Debug.Log("Rebuilding failed, removing receiver."); - // // receivers.Remove(receiver); - // // } - // // } - // } - - // public static Nucleus RebuildType(NanoBrain brain, Nucleus nucleus) { - // if (string.IsNullOrEmpty(nucleus.nucleusType) == false) { - // Type nucleusType = Type.GetType(nucleus.nucleusType); - // if (nucleusType != null) { - // object[] args = new object[] { brain, nucleus.name }; - // Nucleus rebuiltNucleus = (Nucleus)Activator.CreateInstance(nucleusType, args); - // rebuiltNucleus.Deserialize(nucleus); - // return rebuiltNucleus; - // } - // } - // return nucleus; - // } - public virtual void Deserialize(Nucleus nucleus) { } #endregion Serialization @@ -111,26 +81,23 @@ public class Nucleus : INucleus { } } - [System.NonSerialized] + [NonSerialized] private int stale = 1000; private bool _isSleeping = false; public bool isSleeping => _isSleeping; - public void IncreaseAge() { + public void UpdateNuclei() { this.stale++; this._isSleeping = this.stale > 2; if (isSleeping) _outputValue = Vector3.zero; } - [System.NonSerialized] - public int layerIx; #endregion Runtime state public Nucleus(string name) { this._name = name; - this.id = this.GetHashCode(); } public virtual INucleus Clone() { @@ -188,34 +155,11 @@ public class Nucleus : INucleus { } } - public void GetInputFrom(Nucleus input, float weight = 1.0f) { - input.AddReceiver(this); - this.SetWeight(input, weight); - } - - public bool SynapseExists(Nucleus nucleus) { - foreach (Synapse synapse in synapses) { - if (synapse.nucleus == nucleus) - return true; - } - return false; - } - public Synapse AddSynapse(IReceptor sendingNucleus) { Synapse synapse = new(sendingNucleus, 1.0f); this.synapses.Add(synapse); return synapse; } - public void SetWeight(Nucleus nucleus, float weight) { - foreach (Synapse synapse in synapses) { - if (synapse.nucleus == nucleus) { - synapse.weight = weight; - return; - } - } - Synapse newSynapse = new(nucleus, weight); - synapses.Add(newSynapse); - } public virtual void UpdateState() { } diff --git a/Assets/NanoBrain/Receptor.cs b/Assets/NanoBrain/Receptor.cs index 39f1699..403367d 100644 --- a/Assets/NanoBrain/Receptor.cs +++ b/Assets/NanoBrain/Receptor.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using UnityEngine; -using LinearAlgebra; public class Receptor : IReceptor { [SerializeField] @@ -26,52 +25,16 @@ public class Receptor : IReceptor { public bool isSleeping => false; - /// - /// The list of perceptoid which can process stimuli from this receptor - /// - //public List perceptei = new(); - - // private int _thingType = 0; - // public int thingType { - // get { return _thingType; } - // set { - // _thingType = value; - // foreach (Perceptoid perceptoid in perceptei) { - // perceptoid.thingType = _thingType; - // } - // } - // } public Vector3 localPosition; public float distanceResolution = 0.1f; public float directionResolution = 5; - public Vector3 outputValue { - get { return localPosition; } - set { - localPosition = value; - } - } - - - // public Receptor(NanoBrain brain, int thingType) { - // this.thingType = thingType; - // brain.receptors.Add(this); - // } + public Vector3 outputValue => this.localPosition; public Receptor(Cluster cluster, INucleus nucleus) { - //this.cluster = cluster; this.AddReceiver(nucleus); } - // public static Receptor GetReceptor(NanoBrain brain, int thingType) { - // foreach (Receptor receptor in brain.receptors) { - // if (thingType == 0 || receptor.thingType == thingType) - // return receptor; - // } - // Receptor newReceptor = new(brain, thingType); - // return newReceptor; - // } - public static Receptor CreateReceptor(Cluster cluster, string nucleusName) { if (cluster == null) return null; From 3a67652578374e1892fdb940b747ff833dd09f5f Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 12 Jan 2026 17:31:36 +0100 Subject: [PATCH 065/179] Fix resizing neuron array --- Assets/NanoBrain/Nucleus.cs | 7 ++- Assets/NanoBrain/NucleusArray.cs | 2 +- .../VisualEditor/Editor/ClusterInspector.cs | 54 ++++++++++------- Assets/Scenes/Boids/New Cluster.asset | 60 +++++++++++++++++++ Assets/Scenes/Boids/New Cluster.asset.meta | 8 +++ 5 files changed, 106 insertions(+), 25 deletions(-) create mode 100644 Assets/Scenes/Boids/New Cluster.asset create mode 100644 Assets/Scenes/Boids/New Cluster.asset.meta diff --git a/Assets/NanoBrain/Nucleus.cs b/Assets/NanoBrain/Nucleus.cs index ffe7125..9c72fa1 100644 --- a/Assets/NanoBrain/Nucleus.cs +++ b/Assets/NanoBrain/Nucleus.cs @@ -20,7 +20,12 @@ public class Nucleus : INucleus { private List _receivers = new(); public List receivers => _receivers; - public NucleusArray array { get; set; } + [SerializeReference] + private NucleusArray _array; + public NucleusArray array { + get { return _array; } + set { _array = value; } + } #region Serialization diff --git a/Assets/NanoBrain/NucleusArray.cs b/Assets/NanoBrain/NucleusArray.cs index db34958..3e133f1 100644 --- a/Assets/NanoBrain/NucleusArray.cs +++ b/Assets/NanoBrain/NucleusArray.cs @@ -36,7 +36,7 @@ public class NucleusArray { } INucleus[] newPerceptei = new INucleus[newLength]; for (int i = 0; i < newLength; i++) - newPerceptei[i++] = this.nuclei[i]; + newPerceptei[i] = this.nuclei[i]; // Delete the last perception Nucleus.Delete(this.nuclei[newLength]); diff --git a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs index 1d7ae17..e9ee84a 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs @@ -258,8 +258,15 @@ public class ClusterInspector : Editor { // Determine the maximum value in this layer // This is used to 'scale' the output value colors of the nuclei float maxValue = 0; - foreach (Synapse receiver in nucleus.synapses) { - if (receiver.nucleus is Neuroid neuroid) { + int neuronCount = 0; + List drawnArrays = new(); + foreach (Synapse synapse in nucleus.synapses) { + if (synapse.nucleus is Neuroid neuroid) { + if (drawnArrays.Contains(neuroid.array)) + continue; + drawnArrays.Add(neuroid.array); + neuronCount++; + float value = neuroid.outputValue.magnitude; if (value > maxValue) maxValue = value; @@ -267,12 +274,17 @@ public class ClusterInspector : Editor { } // Determine the spacing of the nuclei in the layer - float spacing = 400f / nodeCount; + float spacing = 400f / neuronCount; //nodeCount; float margin = 10 + spacing / 2; int row = 0; - List drawnArrays = new(); + drawnArrays = new(); foreach (Synapse synapse in nucleus.synapses) { + if (synapse.nucleus is Neuroid neuroid) { + if (drawnArrays.Contains(neuroid.array)) + continue; + drawnArrays.Add(neuroid.array); + } Vector3 pos = new(250, margin + row * spacing, 0.0f); Handles.color = Color.white; Handles.DrawLine(parentPos, pos); @@ -382,30 +394,26 @@ public class ClusterInspector : Editor { return; this.currentNucleus.name = EditorGUILayout.TextField(this.currentNucleus.name); - if (this.currentNucleus is Nucleus perceptoid) { - // perceptoid.receptor.thingType = EditorGUILayout.IntField("Thing Type", perceptoid.receptor.thingType); - - if (perceptoid.array == null || perceptoid.array.nuclei == null || perceptoid.array.nuclei.Length == 0) - perceptoid.array = new NucleusArray(perceptoid); + if (this.currentNucleus is Nucleus neuroid) { EditorGUILayout.BeginHorizontal(); - EditorGUILayout.IntField("Array size", perceptoid.array.nuclei.Length); + EditorGUILayout.LabelField("Activation Curve", GUILayout.Width(150)); + if (neuroid.curveMax > 0) + EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, 0, 1, neuroid.curveMax)); + else + EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, neuroid.curveMax, 1, -neuroid.curveMax)); + neuroid.curvePreset = (Neuroid.CurvePresets)EditorGUILayout.EnumPopup(neuroid.curvePreset, GUILayout.Width(100)); + EditorGUILayout.EndHorizontal(); + + if (neuroid.array == null || neuroid.array.nuclei == null || neuroid.array.nuclei.Length == 0) + neuroid.array = new NucleusArray(neuroid); + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.IntField("Array size", neuroid.array.nuclei.Length); if (GUILayout.Button("Add")) - perceptoid.array.AddNucleus(); + neuroid.array.AddNucleus(); if (GUILayout.Button("Del")) - perceptoid.array.RemoveNucleus(); + neuroid.array.RemoveNucleus(); EditorGUILayout.EndHorizontal(); } - else - if (this.currentNucleus is Nucleus neuroid) { - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.LabelField("Activation Curve", GUILayout.Width(150)); - if (neuroid.curveMax > 0) - EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, 0, 1, neuroid.curveMax)); - else - EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, neuroid.curveMax, 1, -neuroid.curveMax)); - neuroid.curvePreset = (Neuroid.CurvePresets)EditorGUILayout.EnumPopup(neuroid.curvePreset, GUILayout.Width(100)); - EditorGUILayout.EndHorizontal(); - } if (Application.isPlaying) EditorGUILayout.FloatField("Output", this.currentNucleus.outputValue.magnitude); diff --git a/Assets/Scenes/Boids/New Cluster.asset b/Assets/Scenes/Boids/New Cluster.asset new file mode 100644 index 0000000..57dc073 --- /dev/null +++ b/Assets/Scenes/Boids/New Cluster.asset @@ -0,0 +1,60 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3} + m_Name: New Cluster + m_EditorClassIdentifier: Assembly-CSharp::Cluster + nuclei: + - rid: 2243601034565648587 + references: + version: 2 + RefIds: + - rid: 2243601034565648587 + type: {class: Neuroid, ns: , asm: Assembly-CSharp} + data: + _name: Output + _synapses: [] + _receivers: [] + _array: + rid: 2243601034565648588 + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1000 + value: 1000 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + - rid: 2243601034565648588 + type: {class: NucleusArray, ns: , asm: Assembly-CSharp} + data: + nuclei: + - rid: 2243601034565648587 + name: Output diff --git a/Assets/Scenes/Boids/New Cluster.asset.meta b/Assets/Scenes/Boids/New Cluster.asset.meta new file mode 100644 index 0000000..db2e437 --- /dev/null +++ b/Assets/Scenes/Boids/New Cluster.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 83e4ef8976534236989bcb1a9342dbf8 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: From 5f6ec71c7b05db442f7e1885e22e4630dc059346 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 12 Jan 2026 17:45:46 +0100 Subject: [PATCH 066/179] move to float3 (to prep for SIMD) --- Assets/NanoBrain/Cluster.cs | 6 ++++-- Assets/NanoBrain/INucleus.cs | 9 +++++++-- Assets/NanoBrain/Neuroid.cs | 20 ++++++++++--------- Assets/NanoBrain/Nucleus.cs | 6 ++++-- Assets/NanoBrain/Receptor.cs | 3 ++- .../VisualEditor/Editor/ClusterInspector.cs | 14 +++++++------ 6 files changed, 36 insertions(+), 22 deletions(-) diff --git a/Assets/NanoBrain/Cluster.cs b/Assets/NanoBrain/Cluster.cs index 54b9c92..0cf80dc 100644 --- a/Assets/NanoBrain/Cluster.cs +++ b/Assets/NanoBrain/Cluster.cs @@ -1,5 +1,7 @@ using System.Collections.Generic; using UnityEngine; +using Unity.Mathematics; +using static Unity.Mathematics.math; [CreateAssetMenu(menuName = "Passer/Cluster")] public class Cluster : ScriptableObject, INucleus { @@ -93,8 +95,8 @@ public class Cluster : ScriptableObject, INucleus { #region Dynamics - public Vector3 outputValue => this.output.outputValue; - public bool isSleeping => this.outputValue.sqrMagnitude == 0; + public float3 outputValue => this.output.outputValue; + public bool isSleeping => lengthsq(this.outputValue) == 0; public void UpdateState() { // Don't know if this is right diff --git a/Assets/NanoBrain/INucleus.cs b/Assets/NanoBrain/INucleus.cs index dedd500..c565c3e 100644 --- a/Assets/NanoBrain/INucleus.cs +++ b/Assets/NanoBrain/INucleus.cs @@ -1,5 +1,8 @@ using System.Collections.Generic; using UnityEngine; +using Unity.Burst; +using Unity.Collections; +using Unity.Mathematics; public interface INucleus : IReceptor { @@ -41,9 +44,11 @@ public interface IReceptor { #region dynamic - public Vector3 outputValue { get; } + // float3 to prepare for SIMD + public float3 outputValue { get; } public bool isSleeping { get; } #endregion dynamic -} \ No newline at end of file +} + diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index b8e14d3..a28583a 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -1,4 +1,6 @@ using UnityEngine; +using Unity.Mathematics; +using static Unity.Mathematics.math; [System.Serializable] public class Neuroid : Nucleus { @@ -39,13 +41,13 @@ public class Neuroid : Nucleus { } public override void UpdateState() { - Vector3 sum = Vector3.zero; + float3 sum = new(0, 0, 0); int n = 0; - + //Applying the weight factgors foreach (Synapse synapse in this.synapses) { - sum += synapse.weight * synapse.nucleus.outputValue; - if (synapse.nucleus.outputValue.sqrMagnitude != 0) + sum = sum + (synapse.weight * synapse.nucleus.outputValue); + if (lengthsq(synapse.nucleus.outputValue) != 0) n++; } if (average) @@ -58,17 +60,17 @@ public class Neuroid : Nucleus { result = sum; break; case CurvePresets.Sqrt: - result = sum.normalized * System.MathF.Sqrt(sum.magnitude); + result = normalize(sum) * System.MathF.Sqrt(length(sum)); break; case CurvePresets.Power: - result = sum.normalized * System.MathF.Pow(sum.magnitude, 2); + result = normalize(sum) * System.MathF.Pow(length(sum), 2); break; case CurvePresets.Reciprocal: - result = sum.normalized * (1 / sum.magnitude); + result = normalize(sum) * (1 / length(sum)); break; default: - float activatedValue = this.curve.Evaluate(sum.magnitude); - result = sum.normalized * activatedValue; + float activatedValue = this.curve.Evaluate(length(sum)); + result = normalize(sum) * activatedValue; break; } UpdateResult(result); diff --git a/Assets/NanoBrain/Nucleus.cs b/Assets/NanoBrain/Nucleus.cs index 9c72fa1..65a30c7 100644 --- a/Assets/NanoBrain/Nucleus.cs +++ b/Assets/NanoBrain/Nucleus.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; using UnityEngine; +using Unity.Mathematics; +using static Unity.Mathematics.math; [Serializable] public class Nucleus : INucleus { @@ -76,8 +78,8 @@ public class Nucleus : INucleus { public Cluster cluster { get; set; } - private Vector3 _outputValue; - public Vector3 outputValue { + private float3 _outputValue; + public float3 outputValue { get { return _outputValue; } set { this.stale = 0; diff --git a/Assets/NanoBrain/Receptor.cs b/Assets/NanoBrain/Receptor.cs index 403367d..fe47dfb 100644 --- a/Assets/NanoBrain/Receptor.cs +++ b/Assets/NanoBrain/Receptor.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using UnityEngine; +using Unity.Mathematics; public class Receptor : IReceptor { [SerializeField] @@ -29,7 +30,7 @@ public class Receptor : IReceptor { public float distanceResolution = 0.1f; public float directionResolution = 5; - public Vector3 outputValue => this.localPosition; + public float3 outputValue => this.localPosition; public Receptor(Cluster cluster, INucleus nucleus) { this.AddReceiver(nucleus); diff --git a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs index e9ee84a..c3744e6 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs @@ -4,6 +4,8 @@ using UnityEditor; using UnityEngine; using UnityEngine.UIElements; +using Unity.Mathematics; +using static Unity.Mathematics.math; [CustomEditor(typeof(Cluster))] public class ClusterInspector : Editor { @@ -216,7 +218,7 @@ public class ClusterInspector : Editor { // Draw selected Nucleus Handles.color = Color.white; Handles.DrawSolidDisc(position, Vector3.forward, size + 2); - DrawNucleus(this.currentNucleus, position, this.currentNucleus.outputValue.magnitude, 20); + DrawNucleus(this.currentNucleus, position, length(this.currentNucleus.outputValue), 20); } private void DrawReceivers(INucleus nucleus, Vector3 parentPos, float size) { @@ -227,7 +229,7 @@ public class ClusterInspector : Editor { float maxValue = 0; foreach (INucleus receiver in nucleus.receivers) { if (receiver is Neuroid neuroid) { - float value = neuroid.outputValue.magnitude; + float value = length(neuroid.outputValue); if (value > maxValue) maxValue = value; } @@ -267,7 +269,7 @@ public class ClusterInspector : Editor { drawnArrays.Add(neuroid.array); neuronCount++; - float value = neuroid.outputValue.magnitude; + float value = length(neuroid.outputValue); if (value > maxValue) maxValue = value; } @@ -299,7 +301,7 @@ public class ClusterInspector : Editor { Handles.color = Color.darkRed; else { if (Application.isPlaying) { - float brightness = nucleus.outputValue.magnitude / maxValue; + float brightness = length(nucleus.outputValue) / maxValue; Handles.color = new Color(brightness, brightness, brightness, 1f); } else @@ -416,7 +418,7 @@ public class ClusterInspector : Editor { } if (Application.isPlaying) - EditorGUILayout.FloatField("Output", this.currentNucleus.outputValue.magnitude); + EditorGUILayout.FloatField("Output", length(this.currentNucleus.outputValue)); else EditorGUILayout.LabelField(" "); @@ -428,7 +430,7 @@ public class ClusterInspector : Editor { EditorGUI.BeginDisabledGroup(synapse.nucleus.isSleeping); if (Application.isPlaying) - EditorGUILayout.FloatField(synapse.nucleus.name, synapse.nucleus.outputValue.magnitude * synapse.weight); + EditorGUILayout.FloatField(synapse.nucleus.name, length(synapse.nucleus.outputValue) * synapse.weight); else { EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField(synapse.nucleus.name); From 4f2f23033575c0e30d7e4b7f5b6c935c8c1396f6 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Tue, 13 Jan 2026 16:33:16 +0100 Subject: [PATCH 067/179] Nucleus+Neuroid->Neuron, improved Receptor support --- Assembly-CSharp-Editor.csproj | 2 +- Assembly-CSharp.csproj | 4 +- Assets/NanoBrain/Cluster.cs | 30 +++++---- Assets/NanoBrain/INucleus.cs | 2 +- Assets/NanoBrain/Neuroid.cs | 4 +- Assets/NanoBrain/{Nucleus.cs => Neuron.cs} | 60 ++++++++++++++--- .../{Nucleus.cs.meta => Neuron.cs.meta} | 0 Assets/NanoBrain/NucleusArray.cs | 2 +- Assets/NanoBrain/Receptor.cs | 36 ++++++++++- .../VisualEditor/Editor/ClusterInspector.cs | 43 +++++++------ Assets/Scenes/Boids/New Cluster.asset | 60 ----------------- Assets/Scenes/Boids/New Cluster.asset.meta | 8 --- Assets/Scenes/Boids/NewSwarm.asset | 64 ++++--------------- Assets/Scenes/Boids/NewSwarm.asset.meta | 2 +- Assets/Scenes/Boids/Prefabs/Boid.prefab | 2 +- 15 files changed, 148 insertions(+), 171 deletions(-) rename Assets/NanoBrain/{Nucleus.cs => Neuron.cs} (70%) rename Assets/NanoBrain/{Nucleus.cs.meta => Neuron.cs.meta} (100%) delete mode 100644 Assets/Scenes/Boids/New Cluster.asset delete mode 100644 Assets/Scenes/Boids/New Cluster.asset.meta diff --git a/Assembly-CSharp-Editor.csproj b/Assembly-CSharp-Editor.csproj index 94f9e7e..36cc367 100644 --- a/Assembly-CSharp-Editor.csproj +++ b/Assembly-CSharp-Editor.csproj @@ -43,7 +43,7 @@ 6000.3.2f1 - + diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index 891c3d0..771999b 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -43,7 +43,7 @@ 6000.3.2f1 - + @@ -67,6 +67,7 @@ + @@ -84,7 +85,6 @@ - diff --git a/Assets/NanoBrain/Cluster.cs b/Assets/NanoBrain/Cluster.cs index 0cf80dc..079279c 100644 --- a/Assets/NanoBrain/Cluster.cs +++ b/Assets/NanoBrain/Cluster.cs @@ -5,18 +5,26 @@ using static Unity.Mathematics.math; [CreateAssetMenu(menuName = "Passer/Cluster")] public class Cluster : ScriptableObject, INucleus { - + public Cluster cluster => this; [SerializeReference] - public List nuclei = new(); + public List nuclei = new(); - public INucleus output => this.nuclei[0]; + public INucleus output => this.nuclei[0] as INucleus; - //private readonly List _inputs = new(); - public List inputs { // = compare receptors in NanoBrain - // for now all nuclei are inputs - get { return this.nuclei; } + public List _inputs = null; + public List inputs { + get { + if (this._inputs == null) { + this._inputs = new(); + foreach (IReceptor receptor in this.nuclei) { + if (receptor is INucleus nucleus) + this._inputs.Add(nucleus); + } + } + return this._inputs; + } } // The synapses of all inputs @@ -35,9 +43,9 @@ public class Cluster : ScriptableObject, INucleus { // This is an invariant and should be ensured before the nucleus is used // because output requires it. public void EnsureInitialization() { - nuclei ??= new List(); + nuclei ??= new List(); if (nuclei.Count == 0) - new Neuroid(this, "Output"); // Every cluster should have at least 1 neuroid + new Neuron(this, "Output"); // Every cluster should have at least 1 neuron } public void AddReceiver(INucleus receiver) { @@ -61,7 +69,7 @@ public class Cluster : ScriptableObject, INucleus { HashSet visitedNuclei = new(); MarkNuclei(visitedNuclei, this.output); //Debug.Log($"Garbage collection found {visitedNuclei.Count} Nuclei"); - this.nuclei.RemoveAll(nucleus => visitedNuclei.Contains(nucleus) == false); + this.nuclei.RemoveAll(nucleus => nucleus is INucleus n && visitedNuclei.Contains(n) == false); //this.perceptei.RemoveAll(perceptoid => visitedNuclei.Contains(perceptoid) == false); } @@ -105,7 +113,7 @@ public class Cluster : ScriptableObject, INucleus { } public void UpdateNuclei() { - foreach (INucleus nucleus in nuclei) + foreach (IReceptor nucleus in this.nuclei) nucleus.UpdateNuclei(); } diff --git a/Assets/NanoBrain/INucleus.cs b/Assets/NanoBrain/INucleus.cs index c565c3e..3ff6947 100644 --- a/Assets/NanoBrain/INucleus.cs +++ b/Assets/NanoBrain/INucleus.cs @@ -23,7 +23,6 @@ public interface INucleus : IReceptor { public void UpdateState(); - public void UpdateNuclei(); #endregion dynamic state @@ -47,6 +46,7 @@ public interface IReceptor { // float3 to prepare for SIMD public float3 outputValue { get; } + public void UpdateNuclei(); public bool isSleeping { get; } #endregion dynamic diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index a28583a..d4a64f2 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -1,9 +1,10 @@ +/* using UnityEngine; using Unity.Mathematics; using static Unity.Mathematics.math; [System.Serializable] -public class Neuroid : Nucleus { +public class Neuroid : Neuron { public bool average = false; @@ -78,3 +79,4 @@ public class Neuroid : Nucleus { } +*/ \ No newline at end of file diff --git a/Assets/NanoBrain/Nucleus.cs b/Assets/NanoBrain/Neuron.cs similarity index 70% rename from Assets/NanoBrain/Nucleus.cs rename to Assets/NanoBrain/Neuron.cs index 65a30c7..67fed76 100644 --- a/Assets/NanoBrain/Nucleus.cs +++ b/Assets/NanoBrain/Neuron.cs @@ -5,7 +5,7 @@ using Unity.Mathematics; using static Unity.Mathematics.math; [Serializable] -public class Nucleus : INucleus { +public class Neuron : INucleus { [SerializeField] protected string _name; @@ -49,6 +49,7 @@ public class Nucleus : INucleus { } public AnimationCurve curve; public float curveMax = 1.0f; + public bool average = false; public AnimationCurve GenerateCurve() { switch (this.curvePreset) { @@ -70,7 +71,7 @@ public class Nucleus : INucleus { } } - public virtual void Deserialize(Nucleus nucleus) { } + public virtual void Deserialize(Neuron nucleus) { } #endregion Serialization @@ -103,17 +104,27 @@ public class Nucleus : INucleus { #endregion Runtime state - public Nucleus(string name) { + public Neuron(Cluster brain, string name) : this(name) { + this.cluster = brain; + if (this.cluster != null) { + this.cluster.nuclei.Add(this); + } + else + Debug.LogError("No neuroid network"); + } + + public Neuron(string name) { this._name = name; } public virtual INucleus Clone() { - Nucleus clone = new(this.name) { + Neuron clone = new(this.name) { cluster = this.cluster, array = this.array, curve = this.curve, curvePreset = this.curvePreset, - curveMax = this.curveMax + curveMax = this.curveMax, + average = this.average }; if (clone.cluster != null) clone.cluster.nuclei.Add(clone); @@ -140,14 +151,14 @@ public class Nucleus : INucleus { public static void Delete(INucleus nucleus) { foreach (Synapse synapse in nucleus.synapses) { - if (synapse.nucleus is Nucleus synapse_nucleus) { + if (synapse.nucleus is Neuron synapse_nucleus) { if (synapse_nucleus.receivers.Count > 1) { // there is another nucleus feeding into this input nucleus synapse_nucleus.receivers.RemoveAll(r => r == nucleus); } else { // No other links, delete it. - Nucleus.Delete(synapse_nucleus); + Neuron.Delete(synapse_nucleus); } } } @@ -168,8 +179,41 @@ public class Nucleus : INucleus { return synapse; } - public virtual void UpdateState() { } + public virtual void UpdateState() { + float3 sum = new(0, 0, 0); + int n = 0; + //Applying the weight factgors + foreach (Synapse synapse in this.synapses) { + sum = sum + (synapse.weight * synapse.nucleus.outputValue); + if (lengthsq(synapse.nucleus.outputValue) != 0) + n++; + } + if (average) + sum /= n; + + // Activation function + Vector3 result; + switch (this.curvePreset) { + case CurvePresets.Linear: + result = sum; + break; + case CurvePresets.Sqrt: + result = normalize(sum) * System.MathF.Sqrt(length(sum)); + break; + case CurvePresets.Power: + result = normalize(sum) * System.MathF.Pow(length(sum), 2); + break; + case CurvePresets.Reciprocal: + result = normalize(sum) * (1 / length(sum)); + break; + default: + float activatedValue = this.curve.Evaluate(length(sum)); + result = normalize(sum) * activatedValue; + break; + } + UpdateResult(result); + } public void UpdateResult(Vector3 result) { // float d = Vector3.Distance(result, this.outputValue); // if (d < 0.5f) { diff --git a/Assets/NanoBrain/Nucleus.cs.meta b/Assets/NanoBrain/Neuron.cs.meta similarity index 100% rename from Assets/NanoBrain/Nucleus.cs.meta rename to Assets/NanoBrain/Neuron.cs.meta diff --git a/Assets/NanoBrain/NucleusArray.cs b/Assets/NanoBrain/NucleusArray.cs index 3e133f1..27f8194 100644 --- a/Assets/NanoBrain/NucleusArray.cs +++ b/Assets/NanoBrain/NucleusArray.cs @@ -38,7 +38,7 @@ public class NucleusArray { for (int i = 0; i < newLength; i++) newPerceptei[i] = this.nuclei[i]; // Delete the last perception - Nucleus.Delete(this.nuclei[newLength]); + Neuron.Delete(this.nuclei[newLength]); this.nuclei = newPerceptei; } diff --git a/Assets/NanoBrain/Receptor.cs b/Assets/NanoBrain/Receptor.cs index fe47dfb..69d3d46 100644 --- a/Assets/NanoBrain/Receptor.cs +++ b/Assets/NanoBrain/Receptor.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using UnityEngine; using Unity.Mathematics; @@ -24,15 +25,37 @@ public class Receptor : IReceptor { receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); } - public bool isSleeping => false; + //public bool isSleeping => false; + private int stale = 1000; - public Vector3 localPosition; + private bool _isSleeping = false; + public bool isSleeping => _isSleeping; + + public Vector3 localPosition { + set { + this.stale = 0; + this._isSleeping = false; + this._outputValue = value; + + } + } public float distanceResolution = 0.1f; public float directionResolution = 5; - public float3 outputValue => this.localPosition; + //public float3 outputValue => this.localPosition; + private float3 _outputValue; + public float3 outputValue { + get { return this._outputValue; } + set { + this.stale = 0; + this._isSleeping = false; + this._outputValue = value; + } + } public Receptor(Cluster cluster, INucleus nucleus) { + if (cluster != null) + cluster.nuclei.Add(this); this.AddReceiver(nucleus); } @@ -100,4 +123,11 @@ public class Receptor : IReceptor { // selectedPerceptoid.name = selectedPerceptoid.baseName + " " + thingName; // selectedPerceptoid.UpdateState(); } + + public void UpdateNuclei() { + this.stale++; + this._isSleeping = this.stale > 2; + if (isSleeping) + this._outputValue = Vector3.zero; + } } \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs index c3744e6..f1109b9 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs @@ -228,7 +228,7 @@ public class ClusterInspector : Editor { // This is used to 'scale' the output value colors of the nuclei float maxValue = 0; foreach (INucleus receiver in nucleus.receivers) { - if (receiver is Neuroid neuroid) { + if (receiver is Neuron neuroid) { float value = length(neuroid.outputValue); if (value > maxValue) maxValue = value; @@ -263,29 +263,29 @@ public class ClusterInspector : Editor { int neuronCount = 0; List drawnArrays = new(); foreach (Synapse synapse in nucleus.synapses) { - if (synapse.nucleus is Neuroid neuroid) { + if (synapse.nucleus is Neuron neuroid) { if (drawnArrays.Contains(neuroid.array)) continue; drawnArrays.Add(neuroid.array); - neuronCount++; - float value = length(neuroid.outputValue); - if (value > maxValue) - maxValue = value; } + float value = length(synapse.nucleus.outputValue); + if (value > maxValue) + maxValue = value; + neuronCount++; } // Determine the spacing of the nuclei in the layer - float spacing = 400f / neuronCount; //nodeCount; + float spacing = 400f / neuronCount; float margin = 10 + spacing / 2; int row = 0; drawnArrays = new(); foreach (Synapse synapse in nucleus.synapses) { - if (synapse.nucleus is Neuroid neuroid) { - if (drawnArrays.Contains(neuroid.array)) + if (synapse.nucleus is Neuron neuron) { + if (drawnArrays.Contains(neuron.array)) continue; - drawnArrays.Add(neuroid.array); + drawnArrays.Add(neuron.array); } Vector3 pos = new(250, margin + row * spacing, 0.0f); Handles.color = Color.white; @@ -318,12 +318,12 @@ public class ClusterInspector : Editor { normal = { textColor = Color.white }, fontStyle = FontStyle.Bold, }; - if (nucleus is Nucleus perceptoid) { - if (perceptoid.array == null || perceptoid.array.nuclei == null || perceptoid.array.nuclei.Length == 0) - perceptoid.array = new NucleusArray(perceptoid); + if (nucleus is Neuron neuron) { + if (neuron.array == null || neuron.array.nuclei == null || neuron.array.nuclei.Length == 0) + neuron.array = new NucleusArray(neuron); - if (perceptoid.array.nuclei.Length > 1) { - Handles.Label(labelPosition, perceptoid.array.nuclei.Length.ToString(), style); + if (neuron.array.nuclei.Length > 1) { + Handles.Label(labelPosition, neuron.array.nuclei.Length.ToString(), style); } } @@ -396,14 +396,14 @@ public class ClusterInspector : Editor { return; this.currentNucleus.name = EditorGUILayout.TextField(this.currentNucleus.name); - if (this.currentNucleus is Nucleus neuroid) { + if (this.currentNucleus is Neuron neuroid) { EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Activation Curve", GUILayout.Width(150)); if (neuroid.curveMax > 0) EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, 0, 1, neuroid.curveMax)); else EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, neuroid.curveMax, 1, -neuroid.curveMax)); - neuroid.curvePreset = (Neuroid.CurvePresets)EditorGUILayout.EnumPopup(neuroid.curvePreset, GUILayout.Width(100)); + neuroid.curvePreset = (Neuron.CurvePresets)EditorGUILayout.EnumPopup(neuroid.curvePreset, GUILayout.Width(100)); EditorGUILayout.EndHorizontal(); if (neuroid.array == null || neuroid.array.nuclei == null || neuroid.array.nuclei.Length == 0) @@ -423,6 +423,7 @@ public class ClusterInspector : Editor { EditorGUILayout.LabelField(" "); if (this.currentNucleus.synapses.Count > 0) { + EditorGUILayout.LabelField("Synapses"); Synapse[] synapses = this.currentNucleus.synapses.ToArray(); foreach (Synapse synapse in synapses) { if (synapse.nucleus != null) { @@ -471,7 +472,7 @@ public class ClusterInspector : Editor { } protected virtual void AddInputNeuron(INucleus nucleus) { - Neuroid newNeuroid = new(this.cluster.cluster, "New neuron"); + Neuron newNeuroid = new(this.cluster.cluster, "New neuron"); newNeuroid.AddReceiver(nucleus); this.currentNucleus = newNeuroid; BuildLayers(); @@ -488,7 +489,7 @@ public class ClusterInspector : Editor { break; } } - Nucleus.Delete(nucleus); + Neuron.Delete(nucleus); BuildLayers(); } @@ -522,12 +523,12 @@ public class ClusterInspector : Editor { // Nucleus n = this.currentNucleus.brain.nuclei[selectedIndex - perceptei.Count()]; // n.AddReceiver(this.currentNucleus); // } - INucleus n = cluster.nuclei[selectedIndex]; + IReceptor n = cluster.nuclei[selectedIndex]; n.AddReceiver(this.currentNucleus); } } - protected virtual void DisconnectNucleus(Nucleus nucleus) { + protected virtual void DisconnectNucleus(Neuron nucleus) { if (this.currentNucleus.cluster == null) return; string[] names = this.currentNucleus.synapses.Select(synapse => synapse.nucleus.name).ToArray(); diff --git a/Assets/Scenes/Boids/New Cluster.asset b/Assets/Scenes/Boids/New Cluster.asset deleted file mode 100644 index 57dc073..0000000 --- a/Assets/Scenes/Boids/New Cluster.asset +++ /dev/null @@ -1,60 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3} - m_Name: New Cluster - m_EditorClassIdentifier: Assembly-CSharp::Cluster - nuclei: - - rid: 2243601034565648587 - references: - version: 2 - RefIds: - - rid: 2243601034565648587 - type: {class: Neuroid, ns: , asm: Assembly-CSharp} - data: - _name: Output - _synapses: [] - _receivers: [] - _array: - rid: 2243601034565648588 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 1 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1000 - value: 1000 - inSlope: 1 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - - rid: 2243601034565648588 - type: {class: NucleusArray, ns: , asm: Assembly-CSharp} - data: - nuclei: - - rid: 2243601034565648587 - name: Output diff --git a/Assets/Scenes/Boids/New Cluster.asset.meta b/Assets/Scenes/Boids/New Cluster.asset.meta deleted file mode 100644 index db2e437..0000000 --- a/Assets/Scenes/Boids/New Cluster.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 83e4ef8976534236989bcb1a9342dbf8 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Scenes/Boids/NewSwarm.asset b/Assets/Scenes/Boids/NewSwarm.asset index d64c329..3f97f61 100644 --- a/Assets/Scenes/Boids/NewSwarm.asset +++ b/Assets/Scenes/Boids/NewSwarm.asset @@ -13,62 +13,18 @@ MonoBehaviour: m_Name: NewSwarm m_EditorClassIdentifier: Assembly-CSharp::Cluster nuclei: - - rid: 2243601034565648442 - - rid: 2243601034565648443 + - rid: 2243601062909444155 references: version: 2 RefIds: - - rid: 2243601034565648442 - type: {class: Neuroid, ns: , asm: Assembly-CSharp} + - rid: 2243601062909444155 + type: {class: Neuron, ns: , asm: Assembly-CSharp} data: - id: 322343360 _name: Output - _synapses: - - nucleus: - rid: 2243601034565648443 - cluster: {fileID: 0} - weight: 1 - curveMax: 1 - _receivers: [] - nucleusType: - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 1 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1000 - value: 1000 - inSlope: 1 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - - rid: 2243601034565648443 - type: {class: Neuroid, ns: , asm: Assembly-CSharp} - data: - id: -1924138416 - _name: Avoidance _synapses: [] - _receivers: - - rid: 2243601034565648442 - nucleusType: + _receivers: [] + _array: + rid: 2243601062909444156 _curvePreset: 0 curve: serializedVersion: 2 @@ -96,5 +52,9 @@ MonoBehaviour: m_RotationOrder: 4 curveMax: 1 average: 0 - inverse: 0 - exponent: 1 + - rid: 2243601062909444156 + type: {class: NucleusArray, ns: , asm: Assembly-CSharp} + data: + nuclei: + - rid: 2243601062909444155 + name: Output diff --git a/Assets/Scenes/Boids/NewSwarm.asset.meta b/Assets/Scenes/Boids/NewSwarm.asset.meta index 575238a..db2e437 100644 --- a/Assets/Scenes/Boids/NewSwarm.asset.meta +++ b/Assets/Scenes/Boids/NewSwarm.asset.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: eddc759ede59e66cd936ad6ae2c55c46 +guid: 83e4ef8976534236989bcb1a9342dbf8 NativeFormatImporter: externalObjects: {} mainObjectFileID: 11400000 diff --git a/Assets/Scenes/Boids/Prefabs/Boid.prefab b/Assets/Scenes/Boids/Prefabs/Boid.prefab index f4f2d9b..f364d47 100644 --- a/Assets/Scenes/Boids/Prefabs/Boid.prefab +++ b/Assets/Scenes/Boids/Prefabs/Boid.prefab @@ -179,4 +179,4 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 92f34a5e4027a1dc39efd8ce63cf6aba, type: 3} m_Name: m_EditorClassIdentifier: Assembly-CSharp::NanoBrainComponent - defaultBrain: {fileID: 11400000, guid: eddc759ede59e66cd936ad6ae2c55c46, type: 2} + defaultBrain: {fileID: 11400000, guid: 83e4ef8976534236989bcb1a9342dbf8, type: 2} From 394df2167db733e221eac06635860adf8fd4ea29 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Tue, 13 Jan 2026 17:18:03 +0100 Subject: [PATCH 068/179] Initial nucleus array UI --- Assets/NanoBrain/Receptor.cs | 111 ++++++++++-------- .../VisualEditor/Editor/ClusterInspector.cs | 96 ++++++++++----- 2 files changed, 133 insertions(+), 74 deletions(-) diff --git a/Assets/NanoBrain/Receptor.cs b/Assets/NanoBrain/Receptor.cs index 69d3d46..1a3a0af 100644 --- a/Assets/NanoBrain/Receptor.cs +++ b/Assets/NanoBrain/Receptor.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using UnityEngine; using Unity.Mathematics; +using static Unity.Mathematics.math; public class Receptor : IReceptor { [SerializeField] @@ -11,10 +12,23 @@ public class Receptor : IReceptor { set => _name = value; } + class Receiver { + public INucleus nucleus; + public int thingId; + public string thingName; + public Receiver(INucleus nucleus, int thingId, string thingName) { + this.nucleus = nucleus; + this.thingId = thingId; + this.thingName = thingName; + } + } + [SerializeReference] private List _receivers = new(); public List receivers => _receivers; + protected int[] thingIds; // every receiver can handle a thing with this id + public virtual void AddReceiver(INucleus receivingNucleus) { this.receivers.Add(receivingNucleus); receivingNucleus.AddSynapse(this); @@ -25,7 +39,6 @@ public class Receptor : IReceptor { receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); } - //public bool isSleeping => false; private int stale = 1000; private bool _isSleeping = false; @@ -42,7 +55,6 @@ public class Receptor : IReceptor { public float distanceResolution = 0.1f; public float directionResolution = 5; - //public float3 outputValue => this.localPosition; private float3 _outputValue; public float3 outputValue { get { return this._outputValue; } @@ -53,6 +65,11 @@ public class Receptor : IReceptor { } } + public Receptor(Cluster cluster) { + if (cluster != null) + cluster.nuclei.Add(this); + } + public Receptor(Cluster cluster, INucleus nucleus) { if (cluster != null) cluster.nuclei.Add(this); @@ -63,65 +80,67 @@ public class Receptor : IReceptor { if (cluster == null) return null; + Receptor receptor = new(cluster); foreach (INucleus nucleus in cluster.inputs) { if (nucleus != null && nucleus.name == nucleusName) { - Receptor receptor = new(cluster, nucleus); - return receptor; + // Receptor receptor = new(cluster, nucleus); + // return receptor; + receptor.AddReceiver(nucleus); } } - return null; + if (receptor.receivers.Count == 0) + return null; + else + return receptor; } public virtual void ProcessStimulus(int thingId, Vector3 newLocalPositionVector, string thingName = null) { this.localPosition = newLocalPositionVector; + thingIds ??= new int[this.receivers.Count]; + + int receiverIx = 0; INucleus selectedReceiver = null; + int selectedReceiverIx = 0; foreach (INucleus receiver in this.receivers) { - selectedReceiver = receiver; + // selectedReceiver = receiver; + // receiverIx++; + + if (thingIds[receiverIx] == thingId) { + // We found an existing receiver for this thing + selectedReceiver = receiver; + selectedReceiverIx = receiverIx; + // Do not look any further + break; + } + else if (receiver.isSleeping) { + // A sleeping receiver is not active and can therefore always be used + selectedReceiver = receiver; + selectedReceiverIx = receiverIx; + // Look further because we may find an existing receiver for this thing + } + else if (selectedReceiver == null) { + // If we haven't found a receiver yet, just start by taking the first + selectedReceiver = receiver; + selectedReceiverIx = receiverIx; + } + else if (selectedReceiver.isSleeping == false) { + // If no existing or sleeping receiver is found, we look for + // the receiver with the furthest/least interesting stimulus + if (length(receiver.outputValue) < length(selectedReceiver.outputValue)) { + // Debug.Log($"{selectedReceiver.name}[{selectedReceiverIx}] {length(selectedReceiver.outputValue)}" + + // $" {receiver.name}[{receiverIx}] {length(receiver.outputValue)} "); + selectedReceiver = receiver; + selectedReceiverIx = receiverIx; + } + } + receiverIx++; } - // selectedReceiver.thingId = thingId; + // Debug.Log($"Receiver {selectedReceiver.name}[{selectedReceiverIx}] for thing {thingId}"); + thingIds[selectedReceiverIx] = thingId; // if (thingName != null) // selectedReceiver.nucleus.name = selectedReceiver.nucleus.baseName + " " + thingName; selectedReceiver.UpdateState(); - - // Perceptoid selectedPerceptoid = null; - // foreach (Perceptoid perceptoid in this.perceptei) { - // if (perceptoid.thingId == thingId) { - // // We found an existing perceptoid for this thing - // selectedPerceptoid = perceptoid; - // // Do not look any further - - // break; - // } - // else if (perceptoid.isSleeping) { - // // A sleeping perceptoid is not active and can therefore always be reused - // selectedPerceptoid = perceptoid; - // // Look further because we could find a existing perceptoid for this thing - // } - - // else if (selectedPerceptoid == null) { - // // If we haven't found a perceptoid yet, just start by taking the first - // selectedPerceptoid = perceptoid; - // } - - // else if (selectedPerceptoid.isSleeping == false) { - // // If no existing or sleeping perceptoid is found, we look for the perceptoid - // // we the furthest (least interesting) stimulus - // if (perceptoid.receptor.localPosition.magnitude < selectedPerceptoid.receptor.localPosition.magnitude) { - // Debug.Log($"{selectedPerceptoid.name} {selectedPerceptoid.receptor.localPosition.magnitude} {perceptoid.receptor.localPosition.magnitude} "); - // selectedPerceptoid = perceptoid; - // } - // } - // } - // if (selectedPerceptoid == null) { - // Debug.Log("No perceptoid selected, stimulus is ignored"); - // return; - // } - // // Debug.Log($"Stimulus {thingType} {thingId} {selectedPerceptoid.name}"); - // selectedPerceptoid.thingId = thingId; - // if (thingName != null) - // selectedPerceptoid.name = selectedPerceptoid.baseName + " " + thingName; - // selectedPerceptoid.UpdateState(); } public void UpdateNuclei() { diff --git a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs index f1109b9..0cf45e5 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs @@ -78,11 +78,12 @@ public class ClusterInspector : Editor { GameObject gameObject; private List layers = new(); private readonly Dictionary neuroidPositions = new(); + private bool expandArray = false; - Vector2 pan = Vector2.zero; + //Vector2 pan = Vector2.zero; //float zoom = 1f; - bool draggingCanvas = false; - Vector2 lastMouse; + //bool draggingCanvas = false; + //Vector2 lastMouse; ClusterWrapper currentWrapper; public GraphView() { @@ -98,9 +99,9 @@ public class ClusterInspector : Editor { Add(imguiContainer); //RegisterCallback(OnWheel); - RegisterCallback(OnMouseDown); - RegisterCallback(OnMouseMove); - RegisterCallback(OnMouseUp); + // RegisterCallback(OnMouseDown); + // RegisterCallback(OnMouseMove); + // RegisterCallback(OnMouseUp); } public void SetGraph(GameObject gameObject, Cluster brain, INucleus nucleus, VisualElement inspectorContainer) { @@ -181,19 +182,19 @@ public class ClusterInspector : Editor { } - void OnMouseDown(MouseDownEvent e) { - if (e.button == 2) { draggingCanvas = true; lastMouse = e.mousePosition; e.StopPropagation(); } - } - void OnMouseMove(MouseMoveEvent e) { - if (draggingCanvas) { - var delta = e.mousePosition - lastMouse; - pan += delta; - //content.style.left = pan.x; - //content.style.top = pan.y; - lastMouse = e.mousePosition; - } - } - void OnMouseUp(MouseUpEvent e) { if (e.button == 2) draggingCanvas = false; } + // void OnMouseDown(MouseDownEvent e) { + // if (e.button == 2) { draggingCanvas = true; lastMouse = e.mousePosition; e.StopPropagation(); } + // } + // void OnMouseMove(MouseMoveEvent e) { + // if (draggingCanvas) { + // var delta = e.mousePosition - lastMouse; + // pan += delta; + // //content.style.left = pan.x; + // //content.style.top = pan.y; + // lastMouse = e.mousePosition; + // } + // } + // void OnMouseUp(MouseUpEvent e) { if (e.button == 2) draggingCanvas = false; } void OnIMGUI() { if (currentNucleus == null) @@ -217,8 +218,23 @@ public class ClusterInspector : Editor { // Draw selected Nucleus Handles.color = Color.white; - Handles.DrawSolidDisc(position, Vector3.forward, size + 2); - DrawNucleus(this.currentNucleus, position, length(this.currentNucleus.outputValue), 20); + if (expandArray) { + float spacing = 400f / this.currentNucleus.array.nuclei.Length; + float margin = 10 + spacing / 2; + int row = 0; + foreach (INucleus nucleus in this.currentNucleus.array.nuclei) { + Vector3 pos = new(150, margin + row * spacing, 0.0f); + Handles.color = Color.white; + //Handles.DrawLine(parentPos, pos); + + DrawNucleus(nucleus, pos, 0, size); + row++; + } + } + else { + Handles.DrawSolidDisc(position, Vector3.forward, size + 2); + DrawNucleus(this.currentNucleus, position, length(this.currentNucleus.outputValue), 20); + } } private void DrawReceivers(INucleus nucleus, Vector3 parentPos, float size) { @@ -318,18 +334,36 @@ public class ClusterInspector : Editor { normal = { textColor = Color.white }, fontStyle = FontStyle.Bold, }; - if (nucleus is Neuron neuron) { + if (nucleus is INucleus neuron) { if (neuron.array == null || neuron.array.nuclei == null || neuron.array.nuclei.Length == 0) neuron.array = new NucleusArray(neuron); - if (neuron.array.nuclei.Length > 1) { + if ((!expandArray || neuron.array.nuclei[0] != this.currentNucleus) && neuron.array.nuclei.Length > 1) { Handles.Label(labelPosition, neuron.array.nuclei.Length.ToString(), style); } + style.alignment = TextAnchor.UpperCenter; + Vector3 labelPos = position - Vector3.down * (size + 0.2f); // below disc along up axis + // if ((!expandArray || neuron.array.nuclei[0] != this.currentNucleus) && neuron.array.nuclei.Length > 1) { + // Handles.Label(labelPos, nucleus.name, style); + // } + // else { + if (expandArray && neuron.array.nuclei[0] == this.currentNucleus) { + int arrayIx = 0; + foreach (INucleus n in neuron.array.nuclei) { + if (n == neuron) + break; + arrayIx++; + } + Handles.Label(labelPos, $"{nucleus.name}[{arrayIx}]", style); + } + else + Handles.Label(labelPos, nucleus.name, style); + } + else { + style.alignment = TextAnchor.UpperCenter; + Vector3 labelPos = position - Vector3.down * (size + 0.2f); // below disc along up axis + Handles.Label(labelPos, nucleus.name, style); } - - style.alignment = TextAnchor.UpperCenter; - Vector3 labelPos = position - Vector3.down * (size + 0.2f); // below disc along up axis - Handles.Label(labelPos, nucleus.name, style); Rect neuronRect = new(position.x - size, position.y - size, size * 2, size * 2); int id = GUIUtility.GetControlID(FocusType.Passive); @@ -371,7 +405,13 @@ public class ClusterInspector : Editor { } private void HandleClicked(IReceptor nucleus) { - if (nucleus is INucleus n) { + if (nucleus == this.currentNucleus) { + if (nucleus is INucleus n) { + expandArray = !expandArray; + return; + } + } + else if (nucleus is INucleus n) { this.currentNucleus = n; BuildLayers(); } From 78e750925dc9eeb7a9fe30e70c5c2d657146afe6 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 14 Jan 2026 20:29:02 +0100 Subject: [PATCH 069/179] Improved array UI --- .../VisualEditor/Editor/ClusterInspector.cs | 45 +- Assets/Scenes/Boids/NewSwarm.asset | 1433 ++++++++++++++++- 2 files changed, 1466 insertions(+), 12 deletions(-) diff --git a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs index 0cf45e5..d33435b 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs @@ -217,21 +217,49 @@ public class ClusterInspector : Editor { DrawSynapses(this.currentNucleus, position, size); // Draw selected Nucleus - Handles.color = Color.white; if (expandArray) { + float maxValue = 0; + foreach (INucleus nucleus in this.currentNucleus.array.nuclei) { + float value = length(nucleus.outputValue); + if (value > maxValue) + maxValue = value; + } + float spacing = 400f / this.currentNucleus.array.nuclei.Length; float margin = 10 + spacing / 2; + float xMin = 150 - size; + float xMax = 150 + size; + float yMin = 10 + margin - size / 2; + float yMax = 400 - margin + size; + Vector3[] verts = new Vector3[4] { + new(xMin, yMin, 0), + new(xMax, yMin, 0), + new(xMax, yMax, 0), + new(xMin, yMax, 0) + }; + Handles.color = Color.black; + Handles.DrawAAConvexPolygon(verts); int row = 0; foreach (INucleus nucleus in this.currentNucleus.array.nuclei) { Vector3 pos = new(150, margin + row * spacing, 0.0f); Handles.color = Color.white; //Handles.DrawLine(parentPos, pos); - DrawNucleus(nucleus, pos, 0, size); + Handles.color = Color.white; + Handles.DrawSolidDisc(pos, Vector3.forward, size + 2); + DrawNucleus(nucleus, pos, maxValue, size); row++; } + GUIStyle style = new(EditorStyles.label) { + alignment = TextAnchor.UpperCenter, + normal = { textColor = Color.white }, + fontStyle = FontStyle.Bold, + }; + Vector3 labelPos = new Vector3(150, yMax, 0) - Vector3.down * (size + 0.2f); // below disc along up axis + Handles.Label(labelPos, this.currentNucleus.name, style); } else { + Handles.color = Color.white; Handles.DrawSolidDisc(position, Vector3.forward, size + 2); DrawNucleus(this.currentNucleus, position, length(this.currentNucleus.outputValue), 20); } @@ -341,12 +369,6 @@ public class ClusterInspector : Editor { if ((!expandArray || neuron.array.nuclei[0] != this.currentNucleus) && neuron.array.nuclei.Length > 1) { Handles.Label(labelPosition, neuron.array.nuclei.Length.ToString(), style); } - style.alignment = TextAnchor.UpperCenter; - Vector3 labelPos = position - Vector3.down * (size + 0.2f); // below disc along up axis - // if ((!expandArray || neuron.array.nuclei[0] != this.currentNucleus) && neuron.array.nuclei.Length > 1) { - // Handles.Label(labelPos, nucleus.name, style); - // } - // else { if (expandArray && neuron.array.nuclei[0] == this.currentNucleus) { int arrayIx = 0; foreach (INucleus n in neuron.array.nuclei) { @@ -354,10 +376,13 @@ public class ClusterInspector : Editor { break; arrayIx++; } - Handles.Label(labelPos, $"{nucleus.name}[{arrayIx}]", style); + Handles.Label(labelPosition, $"[{arrayIx}]", style); } - else + else { + style.alignment = TextAnchor.UpperCenter; + Vector3 labelPos = position - Vector3.down * (size + 0.2f); // below disc along up axis Handles.Label(labelPos, nucleus.name, style); + } } else { style.alignment = TextAnchor.UpperCenter; diff --git a/Assets/Scenes/Boids/NewSwarm.asset b/Assets/Scenes/Boids/NewSwarm.asset index 3f97f61..f9688a6 100644 --- a/Assets/Scenes/Boids/NewSwarm.asset +++ b/Assets/Scenes/Boids/NewSwarm.asset @@ -14,14 +14,40 @@ MonoBehaviour: m_EditorClassIdentifier: Assembly-CSharp::Cluster nuclei: - rid: 2243601062909444155 + - rid: 2243601062909444159 + - rid: 2243601062909444165 + - rid: 2243601062909444167 + - rid: 2243601062909444169 + - rid: 2243601062909444171 + - rid: 2243601062909444178 references: version: 2 RefIds: - rid: 2243601062909444155 type: {class: Neuron, ns: , asm: Assembly-CSharp} data: - _name: Output - _synapses: [] + _name: Velocity delta + _synapses: + - nucleus: + rid: 2243601062909444159 + cluster: {fileID: 0} + weight: 1 + curveMax: 1 + - nucleus: + rid: 2243601062909444165 + cluster: {fileID: 0} + weight: -5 + curveMax: 1 + - nucleus: + rid: 2243601062909444167 + cluster: {fileID: 0} + weight: 1 + curveMax: 1 + - nucleus: + rid: 2243601062909444171 + cluster: {fileID: 0} + weight: -1 + curveMax: 1 _receivers: [] _array: rid: 2243601062909444156 @@ -58,3 +84,1406 @@ MonoBehaviour: nuclei: - rid: 2243601062909444155 name: Output + - rid: 2243601062909444159 + type: {class: Neuron, ns: , asm: Assembly-CSharp} + data: + _name: Alignment + _synapses: [] + _receivers: + - rid: 2243601062909444155 + _array: + rid: 2243601062909444161 + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1000 + value: 1000 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + - rid: 2243601062909444161 + type: {class: NucleusArray, ns: , asm: Assembly-CSharp} + data: + nuclei: + - rid: 2243601062909444159 + name: New neuron + - rid: 2243601062909444165 + type: {class: Neuron, ns: , asm: Assembly-CSharp} + data: + _name: Avoidance + _synapses: [] + _receivers: + - rid: 2243601062909444155 + _array: + rid: 2243601062909444166 + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1000 + value: 1000 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + - rid: 2243601062909444166 + type: {class: NucleusArray, ns: , asm: Assembly-CSharp} + data: + nuclei: + - rid: 2243601062909444165 + name: New neuron + - rid: 2243601062909444167 + type: {class: Neuron, ns: , asm: Assembly-CSharp} + data: + _name: Cohesion + _synapses: + - nucleus: + rid: 2243601062909444169 + cluster: {fileID: 0} + weight: 1 + curveMax: 1 + - nucleus: + rid: 2243601062909444178 + cluster: {fileID: 0} + weight: 1 + curveMax: 1 + _receivers: + - rid: 2243601062909444155 + _array: + rid: 2243601062909444168 + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1000 + value: 1000 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + - rid: 2243601062909444168 + type: {class: NucleusArray, ns: , asm: Assembly-CSharp} + data: + nuclei: + - rid: 2243601062909444167 + name: New neuron + - rid: 2243601062909444169 + type: {class: Neuron, ns: , asm: Assembly-CSharp} + data: + _name: Boid + _synapses: [] + _receivers: + - rid: 2243601062909444167 + - rid: 2243601062909444171 + _array: + rid: 2243601062909444170 + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1000 + value: 1000 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + - rid: 2243601062909444170 + type: {class: NucleusArray, ns: , asm: Assembly-CSharp} + data: + nuclei: + - rid: 2243601062909444169 + - rid: 2243601062909444178 + name: New neuron + - rid: 2243601062909444171 + type: {class: Neuron, ns: , asm: Assembly-CSharp} + data: + _name: Separation + _synapses: + - nucleus: + rid: 2243601062909444169 + cluster: {fileID: 0} + weight: -1 + curveMax: 1 + - nucleus: + rid: 2243601062909444178 + cluster: {fileID: 0} + weight: 1 + curveMax: 1 + _receivers: + - rid: 2243601062909444155 + _array: + rid: 2243601062909444172 + _curvePreset: 3 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.001 + value: 999.99994 + inSlope: 0 + outSlope: -112788.63 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.008866142 + value: 112.788635 + inSlope: -112788.63 + outSlope: -6740.78 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.016732283 + value: 59.76471 + inSlope: -6740.78 + outSlope: -2429.6155 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.024598425 + value: 40.653008 + inSlope: -2429.6155 + outSlope: -1252.2269 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.032464568 + value: 30.802813 + inSlope: -1252.2269 + outSlope: -763.7558 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.040330708 + value: 24.795002 + inSlope: -763.7558 + outSlope: -514.45264 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.04819685 + value: 20.748245 + inSlope: -514.45264 + outSlope: -370.0882 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.056062993 + value: 17.837078 + inSlope: -370.0882 + outSlope: -279.01324 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.06392913 + value: 15.642321 + inSlope: -279.01324 + outSlope: -217.87398 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.07179528 + value: 13.928493 + inSlope: -217.87398 + outSlope: -174.8461 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.079661414 + value: 12.553129 + inSlope: -174.8461 + outSlope: -143.41913 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.087527566 + value: 11.424973 + inSlope: -143.41913 + outSlope: -119.76661 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.0953937 + value: 10.482872 + inSlope: -119.76661 + outSlope: -101.519356 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.10325985 + value: 9.684306 + inSlope: -101.519356 + outSlope: -87.14706 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.11112598 + value: 8.9987955 + inSlope: -87.14706 + outSlope: -75.62513 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.11899213 + value: 8.403917 + inSlope: -75.62513 + outSlope: -66.24654 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.12685826 + value: 7.882813 + inSlope: -66.24654 + outSlope: -58.510654 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.13472441 + value: 7.4225597 + inSlope: -58.510654 + outSlope: -52.055042 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.14259055 + value: 7.0130873 + inSlope: -52.055042 + outSlope: -46.612007 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.1504567 + value: 6.6464305 + inSlope: -46.612007 + outSlope: -41.98024 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.15832284 + value: 6.316208 + inSlope: -41.98024 + outSlope: -38.006134 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.16618897 + value: 6.0172467 + inSlope: -38.006134 + outSlope: -34.570965 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.17405513 + value: 5.745306 + inSlope: -34.570965 + outSlope: -31.581244 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.18192126 + value: 5.496884 + inSlope: -31.581244 + outSlope: -28.963417 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.1897874 + value: 5.2690535 + inSlope: -28.963417 + outSlope: -26.658009 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.19765353 + value: 5.059358 + inSlope: -26.658009 + outSlope: -24.617418 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.20551969 + value: 4.8657136 + inSlope: -24.617418 + outSlope: -22.802412 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.21338584 + value: 4.6863465 + inSlope: -22.802412 + outSlope: -21.181019 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.22125196 + value: 4.519734 + inSlope: -21.181019 + outSlope: -19.72667 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.22911811 + value: 4.364561 + inSlope: -19.72667 + outSlope: -18.417059 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.23698425 + value: 4.21969 + inSlope: -18.417059 + outSlope: -17.233776 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2448504 + value: 4.0841265 + inSlope: -17.233776 + outSlope: -16.160883 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.25271654 + value: 3.9570026 + inSlope: -16.160883 + outSlope: -15.185221 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2605827 + value: 3.8375535 + inSlope: -15.185221 + outSlope: -14.295299 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2684488 + value: 3.725105 + inSlope: -14.295299 + outSlope: -13.481375 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.27631494 + value: 3.6190586 + inSlope: -13.481375 + outSlope: -12.735047 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.28418112 + value: 3.5188825 + inSlope: -12.735047 + outSlope: -12.04901 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.29204726 + value: 3.4241033 + inSlope: -12.04901 + outSlope: -11.416967 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2999134 + value: 3.3342957 + inSlope: -11.416967 + outSlope: -10.8334 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.30777952 + value: 3.249079 + inSlope: -10.8334 + outSlope: -10.293426 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.31564566 + value: 3.1681094 + inSlope: -10.293426 + outSlope: -9.792865 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.3235118 + value: 3.0910773 + inSlope: -9.792865 + outSlope: -9.327949 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.33137795 + value: 3.0177023 + inSlope: -9.327949 + outSlope: -8.895375 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.33924407 + value: 2.9477303 + inSlope: -8.895375 + outSlope: -8.492224 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.34711024 + value: 2.880929 + inSlope: -8.492224 + outSlope: -8.115812 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.3549764 + value: 2.8170888 + inSlope: -8.115812 + outSlope: -7.76395 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.36284253 + value: 2.7560165 + inSlope: -7.76395 + outSlope: -7.434456 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.37070867 + value: 2.697536 + inSlope: -7.434456 + outSlope: -7.1255083 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.3785748 + value: 2.641486 + inSlope: -7.1255083 + outSlope: -6.8354197 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.38644093 + value: 2.5877175 + inSlope: -6.8354197 + outSlope: -6.562695 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.39430708 + value: 2.5360944 + inSlope: -6.562695 + outSlope: -6.305974 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.40217322 + value: 2.4864907 + inSlope: -6.305974 + outSlope: -6.064021 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4100394 + value: 2.43879 + inSlope: -6.064021 + outSlope: -5.835745 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4179055 + value: 2.3928854 + inSlope: -5.835745 + outSlope: -5.6201315 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.42577165 + value: 2.3486767 + inSlope: -5.6201315 + outSlope: -5.4162097 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4336378 + value: 2.306072 + inSlope: -5.4162097 + outSlope: -5.223229 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.44150394 + value: 2.2649853 + inSlope: -5.223229 + outSlope: -5.040342 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4493701 + value: 2.2253373 + inSlope: -5.040342 + outSlope: -4.8669295 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4572362 + value: 2.1870534 + inSlope: -4.8669295 + outSlope: -4.7023005 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.46510234 + value: 2.1500645 + inSlope: -4.7023005 + outSlope: -4.5458865 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.47296852 + value: 2.1143057 + inSlope: -4.5458865 + outSlope: -4.3971753 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.48083466 + value: 2.079717 + inSlope: -4.3971753 + outSlope: -4.2555995 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4887008 + value: 2.0462418 + inSlope: -4.2555995 + outSlope: -4.1207685 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.49656692 + value: 2.0138273 + inSlope: -4.1207685 + outSlope: -3.9922712 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5044331 + value: 1.9824234 + inSlope: -3.9922712 + outSlope: -3.8696532 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5122992 + value: 1.9519844 + inSlope: -3.8696532 + outSlope: -3.7526293 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5201653 + value: 1.9224657 + inSlope: -3.7526293 + outSlope: -3.6408176 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.52803147 + value: 1.8938265 + inSlope: -3.6408176 + outSlope: -3.5339315 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5358976 + value: 1.8660281 + inSlope: -3.5339315 + outSlope: -3.4316826 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.54376376 + value: 1.839034 + inSlope: -3.4316826 + outSlope: -3.3338284 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5516299 + value: 1.8128096 + inSlope: -3.3338284 + outSlope: -3.240066 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.55949605 + value: 1.7873228 + inSlope: -3.240066 + outSlope: -3.1502352 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.56736225 + value: 1.7625424 + inSlope: -3.1502352 + outSlope: -3.0640743 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5752284 + value: 1.7384399 + inSlope: -3.0640743 + outSlope: -2.9814053 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.58309454 + value: 1.7149878 + inSlope: -2.9814053 + outSlope: -2.9020314 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5909606 + value: 1.6921601 + inSlope: -2.9020314 + outSlope: -2.8257964 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.59882677 + value: 1.669932 + inSlope: -2.8257964 + outSlope: -2.7525082 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6066929 + value: 1.6482804 + inSlope: -2.7525082 + outSlope: -2.6820538 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.61455905 + value: 1.627183 + inSlope: -2.6820538 + outSlope: -2.6142666 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6224252 + value: 1.6066188 + inSlope: -2.6142666 + outSlope: -2.5490105 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.63029134 + value: 1.5865679 + inSlope: -2.5490105 + outSlope: -2.4861636 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6381575 + value: 1.5670114 + inSlope: -2.4861636 + outSlope: -2.4256358 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.64602363 + value: 1.547931 + inSlope: -2.4256358 + outSlope: -2.3672597 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6538898 + value: 1.5293097 + inSlope: -2.3672597 + outSlope: -2.3109925 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.66175586 + value: 1.5111313 + inSlope: -2.3109925 + outSlope: -2.2566907 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.669622 + value: 1.4933798 + inSlope: -2.2566907 + outSlope: -2.2042859 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.67748815 + value: 1.4760406 + inSlope: -2.2042859 + outSlope: -2.1536992 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6853543 + value: 1.4590993 + inSlope: -2.1536992 + outSlope: -2.1048093 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6932205 + value: 1.4425424 + inSlope: -2.1048093 + outSlope: -2.0575728 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.70108664 + value: 1.4263573 + inSlope: -2.0575728 + outSlope: -2.011927 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7089528 + value: 1.4105312 + inSlope: -2.011927 + outSlope: -1.9677659 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7168189 + value: 1.3950524 + inSlope: -1.9677659 + outSlope: -1.9250447 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7246851 + value: 1.3799098 + inSlope: -1.9250447 + outSlope: -1.8837026 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7325512 + value: 1.3650923 + inSlope: -1.8837026 + outSlope: -1.8436778 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7404173 + value: 1.3505898 + inSlope: -1.8436778 + outSlope: -1.8049132 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.74828345 + value: 1.336392 + inSlope: -1.8049132 + outSlope: -1.7673749 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7561496 + value: 1.3224896 + inSlope: -1.7673749 + outSlope: -1.7309732 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.76401573 + value: 1.3088735 + inSlope: -1.7309732 + outSlope: -1.695693 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7718819 + value: 1.295535 + inSlope: -1.695693 + outSlope: -1.6614736 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.779748 + value: 1.2824656 + inSlope: -1.6614736 + outSlope: -1.6282848 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.78761417 + value: 1.2696573 + inSlope: -1.6282848 + outSlope: -1.5960962 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7954803 + value: 1.2571021 + inSlope: -1.5960962 + outSlope: -1.564832 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.80334646 + value: 1.2447929 + inSlope: -1.564832 + outSlope: -1.5344887 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.81121254 + value: 1.2327225 + inSlope: -1.5344887 + outSlope: -1.5050048 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.81907874 + value: 1.2208838 + inSlope: -1.5050048 + outSlope: -1.4763738 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8269449 + value: 1.2092705 + inSlope: -1.4763738 + outSlope: -1.4485649 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.83481103 + value: 1.1978759 + inSlope: -1.4485649 + outSlope: -1.4215137 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8426772 + value: 1.186694 + inSlope: -1.4215137 + outSlope: -1.3952202 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8505433 + value: 1.175719 + inSlope: -1.3952202 + outSlope: -1.369639 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.85840946 + value: 1.1649452 + inSlope: -1.369639 + outSlope: -1.3447852 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8662756 + value: 1.154367 + inSlope: -1.3447852 + outSlope: -1.320568 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.87414175 + value: 1.1439792 + inSlope: -1.320568 + outSlope: -1.2970176 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8820079 + value: 1.1337767 + inSlope: -1.2970176 + outSlope: -1.2740829 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.889874 + value: 1.1237546 + inSlope: -1.2740829 + outSlope: -1.2517655 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8977401 + value: 1.113908 + inSlope: -1.2517655 + outSlope: -1.2300034 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.90560627 + value: 1.1042327 + inSlope: -1.2300034 + outSlope: -1.2088321 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9134724 + value: 1.0947238 + inSlope: -1.2088321 + outSlope: -1.1881914 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.92133856 + value: 1.0853773 + inSlope: -1.1881914 + outSlope: -1.1680659 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9292047 + value: 1.0761892 + inSlope: -1.1680659 + outSlope: -1.1484709 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.93707085 + value: 1.0671551 + inSlope: -1.1484709 + outSlope: -1.1293371 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.94493705 + value: 1.0582715 + inSlope: -1.1293371 + outSlope: -1.1106901 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9528032 + value: 1.0495347 + inSlope: -1.1106901 + outSlope: -1.0925045 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.96066934 + value: 1.0409409 + inSlope: -1.0925045 + outSlope: -1.0747513 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9685354 + value: 1.0324868 + inSlope: -1.0747513 + outSlope: -1.0574516 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.97640157 + value: 1.0241687 + inSlope: -1.0574516 + outSlope: -1.0405389 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9842677 + value: 1.0159837 + inSlope: -1.0405389 + outSlope: -1.0240355 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.99213386 + value: 1.0079285 + inSlope: -1.0240355 + outSlope: -1.0079259 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: -1.0079259 + outSlope: 0 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 100 + average: 0 + - rid: 2243601062909444172 + type: {class: NucleusArray, ns: , asm: Assembly-CSharp} + data: + nuclei: + - rid: 2243601062909444171 + name: New neuron + - rid: 2243601062909444178 + type: {class: Neuron, ns: , asm: Assembly-CSharp} + data: + _name: Boid + _synapses: [] + _receivers: + - rid: 2243601062909444167 + - rid: 2243601062909444171 + _array: + rid: 2243601062909444170 + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1000 + value: 1000 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 From e568759d405e960019395f4a8e960c5ac68f236e Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 14 Jan 2026 21:37:04 +0100 Subject: [PATCH 070/179] improved synapse coloring --- Assembly-CSharp.csproj | 1 + Assets/NanoBrain/Scene.meta | 8 + Assets/NanoBrain/Scene/TestScene.unity | 487 ++++++++++++++++++ Assets/NanoBrain/Scene/TestScene.unity.meta | 7 + .../VisualEditor/Editor/ClusterInspector.cs | 29 +- .../Editor/NanoBrainComponent_Editor.cs | 32 +- .../VisualEditor/NanoBrainComponent.cs | 10 +- .../Boids/Prefabs/Stationary Boid.prefab | 87 ++++ .../Boids/Prefabs/Stationary Boid.prefab.meta | 7 + Assets/Scenes/Boids/Scripts/Boid.cs | 4 +- Assets/Scenes/Boids/Scripts/StationaryBoid.cs | 75 +++ .../Boids/Scripts/StationaryBoid.cs.meta | 7 + 12 files changed, 738 insertions(+), 16 deletions(-) create mode 100644 Assets/NanoBrain/Scene.meta create mode 100644 Assets/NanoBrain/Scene/TestScene.unity create mode 100644 Assets/NanoBrain/Scene/TestScene.unity.meta create mode 100644 Assets/Scenes/Boids/Prefabs/Stationary Boid.prefab create mode 100644 Assets/Scenes/Boids/Prefabs/Stationary Boid.prefab.meta create mode 100644 Assets/Scenes/Boids/Scripts/StationaryBoid.cs create mode 100644 Assets/Scenes/Boids/Scripts/StationaryBoid.cs.meta diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index 771999b..4ac4a55 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -69,6 +69,7 @@ + diff --git a/Assets/NanoBrain/Scene.meta b/Assets/NanoBrain/Scene.meta new file mode 100644 index 0000000..d71b5e5 --- /dev/null +++ b/Assets/NanoBrain/Scene.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bfd7dadd61c0891d8a94db0196e61a8a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/NanoBrain/Scene/TestScene.unity b/Assets/NanoBrain/Scene/TestScene.unity new file mode 100644 index 0000000..d852af4 --- /dev/null +++ b/Assets/NanoBrain/Scene/TestScene.unity @@ -0,0 +1,487 @@ +%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: 10 + 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: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 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_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 13 + m_BakeOnSceneLoad: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + 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_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 2 + 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: 1 + m_PVRFilteringGaussRadiusAO: 1 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 20201, guid: 0000000000000000f000000000000000, type: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 3 + 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 + buildHeightMesh: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1001 &551770709 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalPosition.x + value: -1.00054 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalPosition.y + value: -1.02912 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalPosition.z + value: 0.82188 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093763, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_Name + value: Boid2 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} +--- !u!1 &968074744 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 968074747} + - component: {fileID: 968074746} + - component: {fileID: 968074745} + 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 &968074745 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 968074744} + m_Enabled: 1 +--- !u!20 &968074746 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 968074744} + 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_Iso: 200 + m_ShutterSpeed: 0.005 + m_Aperture: 16 + m_FocusDistance: 10 + m_FocalLength: 50 + m_BladeCount: 5 + m_Curvature: {x: 2, y: 11} + m_BarrelClipping: 0.25 + m_Anamorphism: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + 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: 0 + 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 &968074747 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 968074744} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1342149740 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1342149742} + - component: {fileID: 1342149741} + m_Layer: 0 + m_Name: SwamControl + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1342149741 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1342149740} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0464906885ae3494f8fd0314719fb2db, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::SwarmControl + speed: 0.5 + inertia: 0.1 + alignmentForce: 0 + cohesionForce: 10 + separationForce: 5 + avoidanceForce: 5 + separationDistance: 0.5 + perceptionDistance: 1 + spaceSize: {x: 10, y: 10, z: 10} + boundaryWidth: {x: 1, y: 1, z: 1} +--- !u!4 &1342149742 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1342149740} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -1.00377, y: -1.02283, z: 0.72231} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &2011285159 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2011285161} + - component: {fileID: 2011285160} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &2011285160 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2011285159} + m_Enabled: 1 + serializedVersion: 12 + m_Type: 1 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize2D: {x: 0.5, y: 0.5} + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ForceVisible: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 + m_LightUnit: 1 + m_LuxAtDistance: 1 + m_EnableSpotReflector: 1 +--- !u!4 &2011285161 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2011285159} + serializedVersion: 2 + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1001 &4573752827112804207 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093763, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_Name + value: Boid1 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} +--- !u!1660057539 &9223372036854775807 +SceneRoots: + m_ObjectHideFlags: 0 + m_Roots: + - {fileID: 968074747} + - {fileID: 2011285161} + - {fileID: 4573752827112804207} + - {fileID: 551770709} + - {fileID: 1342149742} diff --git a/Assets/NanoBrain/Scene/TestScene.unity.meta b/Assets/NanoBrain/Scene/TestScene.unity.meta new file mode 100644 index 0000000..676153c --- /dev/null +++ b/Assets/NanoBrain/Scene/TestScene.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 1070383882ed0f5379a3b34e8ccb1f75 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs index d33435b..072d8c1 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs @@ -196,7 +196,7 @@ public class ClusterInspector : Editor { // } // void OnMouseUp(MouseUpEvent e) { if (e.button == 2) draggingCanvas = false; } - void OnIMGUI() { + public void OnIMGUI() { if (currentNucleus == null) return; @@ -313,7 +313,8 @@ public class ClusterInspector : Editor { drawnArrays.Add(neuroid.array); } - float value = length(synapse.nucleus.outputValue); + float value = length(synapse.nucleus.outputValue) * synapse.weight; + // Debug.Log($"{synapse.nucleus.name}: {value} {length(synapse.nucleus.outputValue)} {synapse.weight}"); if (value > maxValue) maxValue = value; neuronCount++; @@ -334,23 +335,37 @@ public class ClusterInspector : Editor { Vector3 pos = new(250, margin + row * spacing, 0.0f); Handles.color = Color.white; Handles.DrawLine(parentPos, pos); - if (synapse.nucleus != null) - DrawNucleus(synapse.nucleus, pos, maxValue, size); + if (synapse.nucleus != null) { + Color color = Color.black; + if (synapse.nucleus.isSleeping) + color = Color.darkRed; + else if (Application.isPlaying) { + float brightness = length(synapse.nucleus.outputValue) * synapse.weight / maxValue; + color = new Color(brightness, brightness, brightness, 1f); + } + DrawNucleus(synapse.nucleus, pos, maxValue, size, color); + } row++; } } private void DrawNucleus(IReceptor nucleus, Vector3 position, float maxValue, float size) { + Color color; if (nucleus.isSleeping) - Handles.color = Color.darkRed; + color = Color.darkRed; else { if (Application.isPlaying) { float brightness = length(nucleus.outputValue) / maxValue; - Handles.color = new Color(brightness, brightness, brightness, 1f); + color = new Color(brightness, brightness, brightness, 1f); } else - Handles.color = Color.black; + color = Color.black; } + DrawNucleus(nucleus, position, maxValue, size, color); + } + + private void DrawNucleus(IReceptor nucleus, Vector3 position, float maxValue, float size, Color color) { + Handles.color = color; Handles.DrawSolidDisc(position, Vector3.forward, size); Handles.color = Color.white; diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs index 6da496b..c9ad194 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs @@ -11,11 +11,14 @@ public class NanoBrainComponent_Editor : Editor { protected NanoBrainComponent component; private SerializedProperty brainProp; + ClusterInspector.GraphView board; + public void OnEnable() { component = target as NanoBrainComponent; if (Application.isPlaying == false) brainProp = serializedObject.FindProperty(nameof(NanoBrainComponent.defaultBrain)); + } public override VisualElement CreateInspectorGUI() { @@ -52,9 +55,9 @@ public class NanoBrainComponent_Editor : Editor { minHeight = 500, } }; - ClusterInspector.GraphView board; board = new ClusterInspector.GraphView(); board.style.flexGrow = 1; + mainContainer.Add(board); inspectorContainer = new VisualElement { name = "inspector", @@ -63,7 +66,6 @@ public class NanoBrainComponent_Editor : Editor { } }; - mainContainer.Add(board); mainContainer.Add(inspectorContainer); root.Add(mainContainer); @@ -76,7 +78,7 @@ public class NanoBrainComponent_Editor : Editor { UpdateLayout(evt.newRect.width); }); - if (brain != null) + if (brain != null && board != null) board.SetGraph(component.gameObject, brain, brain.output, inspectorContainer); // else // Debug.LogWarning(" No brain!"); @@ -86,6 +88,30 @@ public class NanoBrainComponent_Editor : Editor { return root; } + // void OnSceneGUI() { + // if (Application.isPlaying && board != null) + // board.OnIMGUI(); + // } + + void OnSceneGui(SceneView sv) { + if (Application.isPlaying == false) + return; + // May need some throttling here... + if (board != null) { + Debug.Log("."); + board.OnIMGUI(); + } + + // EditorApplication.delayCall = UpdateInspectorUI; + } + + void UpdateInspectorUI() { + if (board != null) { + Debug.Log("."); + board.OnIMGUI(); + } + } + private void UpdateLayout(float containerWidth) { if (containerWidth > 800f) { mainContainer.style.flexDirection = FlexDirection.Row; diff --git a/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs b/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs index 475e1a0..09fbfaa 100644 --- a/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs +++ b/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs @@ -12,10 +12,12 @@ public class NanoBrainComponent : MonoBehaviour { brainInstance.name = defaultBrain.name + " (Instance)"; SwarmControl sc = FindFirstObjectByType(); - UpdateWeight(brainInstance, "Avoidance", sc.avoidanceForce); - UpdateWeight(brainInstance, "Cohesion", sc.cohesionForce); - UpdateWeight(brainInstance, "Separation", sc.separationForce); - UpdateWeight(brainInstance, "Alignment", sc.alignmentForce); + if (sc != null) { + UpdateWeight(brainInstance, "Avoidance", sc.avoidanceForce); + UpdateWeight(brainInstance, "Cohesion", sc.cohesionForce); + UpdateWeight(brainInstance, "Separation", sc.separationForce); + UpdateWeight(brainInstance, "Alignment", sc.alignmentForce); + } } return brainInstance; } diff --git a/Assets/Scenes/Boids/Prefabs/Stationary Boid.prefab b/Assets/Scenes/Boids/Prefabs/Stationary Boid.prefab new file mode 100644 index 0000000..b45e904 --- /dev/null +++ b/Assets/Scenes/Boids/Prefabs/Stationary Boid.prefab @@ -0,0 +1,87 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1001 &1401715754342779814 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 8702527964058765412, guid: f9c706268554ce449a8773675b2864b8, type: 3} + propertyPath: m_LocalPosition.x + value: -1.00054 + objectReference: {fileID: 0} + - target: {fileID: 8702527964058765412, guid: f9c706268554ce449a8773675b2864b8, type: 3} + propertyPath: m_LocalPosition.y + value: -1.02912 + objectReference: {fileID: 0} + - target: {fileID: 8702527964058765412, guid: f9c706268554ce449a8773675b2864b8, type: 3} + propertyPath: m_LocalPosition.z + value: 0.82188 + objectReference: {fileID: 0} + - target: {fileID: 8702527964058765412, guid: f9c706268554ce449a8773675b2864b8, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 8702527964058765412, guid: f9c706268554ce449a8773675b2864b8, type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8702527964058765412, guid: f9c706268554ce449a8773675b2864b8, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8702527964058765412, guid: f9c706268554ce449a8773675b2864b8, type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8702527964058765412, guid: f9c706268554ce449a8773675b2864b8, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8702527964058765412, guid: f9c706268554ce449a8773675b2864b8, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8702527964058765412, guid: f9c706268554ce449a8773675b2864b8, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8702527964058765413, guid: f9c706268554ce449a8773675b2864b8, type: 3} + propertyPath: m_Name + value: Boid1 Variant + objectReference: {fileID: 0} + m_RemovedComponents: + - {fileID: 9169912378811971808, guid: f9c706268554ce449a8773675b2864b8, type: 3} + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: + - targetCorrespondingSourceObject: {fileID: 8702527964058765413, guid: f9c706268554ce449a8773675b2864b8, type: 3} + insertIndex: -1 + addedObject: {fileID: 8788086714463777302} + m_SourcePrefab: {fileID: 100100000, guid: f9c706268554ce449a8773675b2864b8, type: 3} +--- !u!1 &7761516481062093763 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 8702527964058765413, guid: f9c706268554ce449a8773675b2864b8, type: 3} + m_PrefabInstance: {fileID: 1401715754342779814} + m_PrefabAsset: {fileID: 0} +--- !u!114 &8788086714463777302 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7761516481062093763} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c156ab45bfd15d213b1be7451d0c0151, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::StationaryBoid + sc: {fileID: 0} + velocity: {x: 0, y: 0, z: 0} + acceleration: {x: 0, y: 0, z: 0} + nanoBrain: {fileID: 0} + id: 0 + red: {fileID: 2100000, guid: 2a7557e54580b6a8b976f12aa6cc761c, type: 2} + gray: {fileID: 2100000, guid: a79ccc131cb43254cb8575d1cedb537e, type: 2} diff --git a/Assets/Scenes/Boids/Prefabs/Stationary Boid.prefab.meta b/Assets/Scenes/Boids/Prefabs/Stationary Boid.prefab.meta new file mode 100644 index 0000000..ea903ab --- /dev/null +++ b/Assets/Scenes/Boids/Prefabs/Stationary Boid.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6860355b30724b5ddb35781dcaf3b57e +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/Boids/Scripts/Boid.cs b/Assets/Scenes/Boids/Scripts/Boid.cs index a3f81d3..5c99655 100644 --- a/Assets/Scenes/Boids/Scripts/Boid.cs +++ b/Assets/Scenes/Boids/Scripts/Boid.cs @@ -11,7 +11,7 @@ public class Boid : MonoBehaviour { public Vector3 velocity = Vector3.zero; public Vector3 acceleration = Vector3.zero; - private Bounds innerBounds; + protected Bounds innerBounds; public NanoBrainComponent nanoBrain; public Receptor boundaryReceptor; @@ -41,7 +41,7 @@ public class Boid : MonoBehaviour { innerBounds = new(sc.transform.position, sc.spaceSize - 2 * sc.boundaryWidth); } - void Update() { + protected virtual void Update() { Collider[] results = Physics.OverlapSphere(this.transform.position, sc.perceptionDistance); foreach (Collider c in results) { if (c as CapsuleCollider != null) { diff --git a/Assets/Scenes/Boids/Scripts/StationaryBoid.cs b/Assets/Scenes/Boids/Scripts/StationaryBoid.cs new file mode 100644 index 0000000..a8e3031 --- /dev/null +++ b/Assets/Scenes/Boids/Scripts/StationaryBoid.cs @@ -0,0 +1,75 @@ +using UnityEngine; + +public class StationaryBoid : Boid +{ + protected override void Update() + { + Collider[] results = Physics.OverlapSphere(this.transform.position, sc.perceptionDistance); + foreach (Collider c in results) + { + if (c as CapsuleCollider != null) + { + Boid neighbour = c.GetComponentInParent(); + if (neighbour == null || neighbour == this) + continue; + + int thingId = neighbour.GetInstanceID(); + + Vector3 localPosition = this.transform.InverseTransformPoint(neighbour.transform.position); + float d = localPosition.magnitude; + if (d <= sc.separationDistance) + localPosition = localPosition.normalized * 0.01f; + else + localPosition = localPosition.normalized * (localPosition.magnitude - sc.separationDistance); + if (localPosition.sqrMagnitude > 0) + boidReceptor?.ProcessStimulus(thingId, localPosition, neighbour.name); + + Vector3 localVelocity = this.transform.InverseTransformVector(neighbour.velocity); + if (localVelocity.sqrMagnitude > 0) + boidVelocityReceptor?.ProcessStimulus(thingId, localVelocity); + } + } + + if (!innerBounds.Contains(this.transform.position)) + { + Vector3 point = this.transform.position; + Vector3 pointOnBounds = innerBounds.ClosestPoint(point); + Vector3 desiredWorldSpace = (pointOnBounds - point).normalized * sc.speed; + Vector3 desiredLocalSpace = -this.transform.InverseTransformPoint(desiredWorldSpace); + boundaryReceptor.ProcessStimulus(777, desiredLocalSpace); + } + + Vector3 worldForce = this.transform.TransformDirection(nanoBrain.root.outputValue); + + this.velocity = (1 - sc.inertia) * (worldForce * Time.deltaTime) + sc.inertia * velocity; + if (this.velocity.magnitude > 0) + this.velocity = this.velocity.normalized * sc.speed; + else + this.velocity = this.transform.forward * sc.speed; + //Debug.DrawRay(this.transform.position, this.velocity, Color.blue); + + // this.transform.position += this.velocity * Time.deltaTime; + + // if (this.velocity != Vector3.zero) + // { + // Quaternion targetRotation = Quaternion.LookRotation(this.velocity); + // transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 5f); // Adjust the speed of rotation + // } + + nanoBrain.brain.UpdateNuclei(); + + // Renderer renderer = GetComponentInChildren(); + // results = Physics.OverlapSphere(this.transform.position, 0.1f); + // if (results.Length > 1) { + // // string s= this.name; + // // foreach (Collider c in results) + // // s += " " + c.transform.parent.gameObject.name; + // // Debug.Log(s); + // renderer.sharedMaterial = red; + // } + // else { + // renderer.sharedMaterial = gray; + // } + } + +} \ No newline at end of file diff --git a/Assets/Scenes/Boids/Scripts/StationaryBoid.cs.meta b/Assets/Scenes/Boids/Scripts/StationaryBoid.cs.meta new file mode 100644 index 0000000..b06bf2e --- /dev/null +++ b/Assets/Scenes/Boids/Scripts/StationaryBoid.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c156ab45bfd15d213b1be7451d0c0151 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: From f2d20dd462cce2eb5f3dd706f028c7a52821fc6c Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 14 Jan 2026 21:53:20 +0100 Subject: [PATCH 071/179] weight tuninh --- Assets/NanoBrain/Scene/TestScene.unity | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Assets/NanoBrain/Scene/TestScene.unity b/Assets/NanoBrain/Scene/TestScene.unity index d852af4..401756e 100644 --- a/Assets/NanoBrain/Scene/TestScene.unity +++ b/Assets/NanoBrain/Scene/TestScene.unity @@ -129,15 +129,15 @@ PrefabInstance: m_Modifications: - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} propertyPath: m_LocalPosition.x - value: -1.00054 + value: 0.71 objectReference: {fileID: 0} - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} propertyPath: m_LocalPosition.y - value: -1.02912 + value: 0 objectReference: {fileID: 0} - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} propertyPath: m_LocalPosition.z - value: 0.82188 + value: 0 objectReference: {fileID: 0} - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} propertyPath: m_LocalRotation.w @@ -300,8 +300,8 @@ MonoBehaviour: speed: 0.5 inertia: 0.1 alignmentForce: 0 - cohesionForce: 10 - separationForce: 5 + cohesionForce: 1 + separationForce: 1 avoidanceForce: 5 separationDistance: 0.5 perceptionDistance: 1 From 14436cbfbadd584b089dc63e790520f0abda6a72 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 21 Jan 2026 13:41:50 +0100 Subject: [PATCH 072/179] Reliable output vector draw line --- .../VisualEditor/Editor/ClusterInspector.cs | 37 +++++++++++++++++-- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs index 072d8c1..9535e72 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs @@ -102,6 +102,25 @@ public class ClusterInspector : Editor { // RegisterCallback(OnMouseDown); // RegisterCallback(OnMouseMove); // RegisterCallback(OnMouseUp); + + // Subscribe when added to panel (editor UI ready) + RegisterCallback(evt => Subscribe()); + RegisterCallback(evt => Unsubscribe()); + } + + + bool subscribed = false; + void Subscribe() { + if (subscribed) return; + SceneView.duringSceneGui += OnSceneGUI; + subscribed = true; + SceneView.RepaintAll(); + } + + void Unsubscribe() { + if (!subscribed) return; + SceneView.duringSceneGui -= OnSceneGUI; + subscribed = false; } public void SetGraph(GameObject gameObject, Cluster brain, INucleus nucleus, VisualElement inspectorContainer) { @@ -542,15 +561,25 @@ public class ClusterInspector : Editor { DeleteNeuron(this.currentNucleus); - if (this.gameObject != null) { - Vector3 worldVector = this.gameObject.transform.TransformVector(this.currentNucleus.outputValue); - Debug.DrawRay(this.gameObject.transform.position, worldVector, Color.yellow); - } + // if (this.gameObject != null) { + // Vector3 worldVector = this.gameObject.transform.TransformVector(this.currentNucleus.outputValue); + // //Debug.DrawRay(this.gameObject.transform.position, worldVector, Color.yellow); + // Handles.color = Color.yellow; + // Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); + // } }); inspectorContainer.Add(container); } + void OnSceneGUI(SceneView sceneView) { + if (this.gameObject != null) { + Vector3 worldVector = this.gameObject.transform.TransformVector(this.currentNucleus.outputValue); + Handles.color = Color.yellow; + Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); + } + } + protected virtual void AddInputNeuron(INucleus nucleus) { Neuron newNeuroid = new(this.cluster.cluster, "New neuron"); newNeuroid.AddReceiver(nucleus); From 4b72e6c712fdb7aab4cd0bcdb1362cd2c31d0189 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 21 Jan 2026 15:17:25 +0100 Subject: [PATCH 073/179] First setup --- Assets/NanoBrain/Cluster.cs | 37 ++++++++--- Assets/NanoBrain/INucleus.cs | 10 +-- Assets/NanoBrain/Identity.asset | 60 ++++++++++++++++++ Assets/NanoBrain/Identity.asset.meta | 8 +++ Assets/NanoBrain/Neuron.cs | 46 +++++++++++--- Assets/NanoBrain/NucleusArray.cs | 1 + Assets/NanoBrain/Receptor.cs | 26 ++++++-- Assets/NanoBrain/Synapse.cs | 63 +++++-------------- .../VisualEditor/Editor/BrainPickerWindow.cs | 22 +++---- .../VisualEditor/Editor/ClusterInspector.cs | 38 +++++------ Assets/Scenes/Boids/New Cluster.asset | 62 ++++++++++++++++++ Assets/Scenes/Boids/New Cluster.asset.meta | 8 +++ Assets/Scenes/Boids/Scripts/Boid.cs | 1 - 13 files changed, 268 insertions(+), 114 deletions(-) create mode 100644 Assets/NanoBrain/Identity.asset create mode 100644 Assets/NanoBrain/Identity.asset.meta create mode 100644 Assets/Scenes/Boids/New Cluster.asset create mode 100644 Assets/Scenes/Boids/New Cluster.asset.meta diff --git a/Assets/NanoBrain/Cluster.cs b/Assets/NanoBrain/Cluster.cs index 079279c..85d3214 100644 --- a/Assets/NanoBrain/Cluster.cs +++ b/Assets/NanoBrain/Cluster.cs @@ -10,6 +10,7 @@ public class Cluster : ScriptableObject, INucleus { [SerializeReference] public List nuclei = new(); + public List subClusters = new(); public INucleus output => this.nuclei[0] as INucleus; @@ -33,6 +34,18 @@ public class Cluster : ScriptableObject, INucleus { public NucleusArray array { get; set; } + public List receivers { + get { return this.output.receivers; } + set { this.output.receivers = value; } + } + public List clusterReceivers { + get { return this.output.clusterReceivers; } + set { this.output.clusterReceivers = clusterReceivers; } + } + public IEnumerable allReceivers { + get => output.allReceivers; + } + public INucleus Clone() { Cluster clone = CreateInstance(); // Lots to add here... @@ -48,19 +61,27 @@ public class Cluster : ScriptableObject, INucleus { new Neuron(this, "Output"); // Every cluster should have at least 1 neuron } - public void AddReceiver(INucleus receiver) { - output.AddReceiver(receiver); + public void AddReceiver(INucleus receivingNucleus) { + //output.AddReceiver(receiver); + this.output.receivers.Add(receivingNucleus); + receivingNucleus.AddClusterSynapse(this); + } + public void AddClusterReceiver(Cluster clusterReceiver) { + this.output.clusterReceivers.Add(clusterReceiver); + clusterReceiver.AddClusterSynapse(this); } public void RemoveReceiver(INucleus receiver) { output.RemoveReceiver(receiver); } - public List receivers { - get => output.receivers; - } public Synapse AddSynapse(IReceptor sender) { - Synapse synapse = new(sender, 1.0f); + Synapse synapse = new(sender); + synapses.Add(synapse); + return synapse; + } + public Synapse AddClusterSynapse(Cluster sender) { + Synapse synapse = new(sender); synapses.Add(synapse); return synapse; } @@ -89,9 +110,9 @@ public class Cluster : ScriptableObject, INucleus { } nucleus.synapses.RemoveAll(synapse => visitedSynapses.Contains(synapse) == false); } - if (nucleus.receivers != null) { + if (nucleus.allReceivers != null) { HashSet visitedReceivers = new(); - foreach (INucleus receiver in nucleus.receivers) { + foreach (INucleus receiver in nucleus.allReceivers) { if (receiver != null && receiver != null) { visitedReceivers.Add(receiver); visitedNuclei.Add(receiver); diff --git a/Assets/NanoBrain/INucleus.cs b/Assets/NanoBrain/INucleus.cs index 3ff6947..19938ed 100644 --- a/Assets/NanoBrain/INucleus.cs +++ b/Assets/NanoBrain/INucleus.cs @@ -1,7 +1,4 @@ using System.Collections.Generic; -using UnityEngine; -using Unity.Burst; -using Unity.Collections; using Unity.Mathematics; public interface INucleus : IReceptor { @@ -14,6 +11,7 @@ public interface INucleus : IReceptor { // Senders public List synapses { get; } public Synapse AddSynapse(IReceptor sender); + public Synapse AddClusterSynapse(Cluster clusterSender); public NucleusArray array { get; set; } @@ -35,8 +33,12 @@ public interface IReceptor { public string name { get; set; } // Receivers - public List receivers { get; } + public List receivers { get; set; } + public List clusterReceivers { get; set; } + public IEnumerable allReceivers { get; } + public void AddReceiver(INucleus receiver); + public void AddClusterReceiver(Cluster clusterReceiver); public void RemoveReceiver(INucleus receiverNucleus); #endregion static diff --git a/Assets/NanoBrain/Identity.asset b/Assets/NanoBrain/Identity.asset new file mode 100644 index 0000000..3d62c75 --- /dev/null +++ b/Assets/NanoBrain/Identity.asset @@ -0,0 +1,60 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3} + m_Name: Identity + m_EditorClassIdentifier: Assembly-CSharp::Cluster + nuclei: + - rid: 2243601242842202169 + references: + version: 2 + RefIds: + - rid: 2243601242842202169 + type: {class: Neuron, ns: , asm: Assembly-CSharp} + data: + _name: Output + _synapses: [] + _receivers: [] + _array: + rid: 2243601242842202170 + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1000 + value: 1000 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + - rid: 2243601242842202170 + type: {class: NucleusArray, ns: , asm: Assembly-CSharp} + data: + nuclei: + - rid: 2243601242842202169 + name: Output diff --git a/Assets/NanoBrain/Identity.asset.meta b/Assets/NanoBrain/Identity.asset.meta new file mode 100644 index 0000000..b2382a6 --- /dev/null +++ b/Assets/NanoBrain/Identity.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5f4d2ea0d0115b3549f8e9aa5e669163 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/NanoBrain/Neuron.cs b/Assets/NanoBrain/Neuron.cs index 67fed76..2d5d5aa 100644 --- a/Assets/NanoBrain/Neuron.cs +++ b/Assets/NanoBrain/Neuron.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using UnityEngine; using Unity.Mathematics; using static Unity.Mathematics.math; @@ -20,7 +21,25 @@ public class Neuron : INucleus { [SerializeReference] private List _receivers = new(); - public List receivers => _receivers; + public List receivers { + get { return _receivers; } + set { _receivers = value; } + } + private List _clusterReceivers = new(); + public List clusterReceivers { + get { return _clusterReceivers; } + set { _clusterReceivers = value; } + } + public IEnumerable allReceivers { //=> _receivers.Concat(_clusterReceivers); + get { + if (_receivers == null) + return _clusterReceivers; + else if (_clusterReceivers == null) + return _receivers; + else + return _receivers.Concat(_clusterReceivers); + } + } [SerializeReference] private NucleusArray _array; @@ -133,28 +152,32 @@ public class Neuron : INucleus { Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); clonedSynapse.weight = synapse.weight; } - foreach (INucleus receiver in this.receivers) { + foreach (INucleus receiver in this.allReceivers) { clone.AddReceiver(receiver); } return clone; } public virtual void AddReceiver(INucleus receivingNucleus) { - this.receivers.Add(receivingNucleus); + this._receivers.Add(receivingNucleus); receivingNucleus.AddSynapse(this); } + public void AddClusterReceiver(Cluster receivingCluster) { + this._clusterReceivers.Add(receivingCluster); + receivingCluster.AddSynapse(this); + } public void RemoveReceiver(INucleus receiverNucleus) { - this.receivers.RemoveAll(receiver => receiver == receiverNucleus); + this._receivers.RemoveAll(receiver => receiver == receiverNucleus); receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); } public static void Delete(INucleus nucleus) { foreach (Synapse synapse in nucleus.synapses) { if (synapse.nucleus is Neuron synapse_nucleus) { - if (synapse_nucleus.receivers.Count > 1) { + if (synapse_nucleus._receivers.Count > 1) { // there is another nucleus feeding into this input nucleus - synapse_nucleus.receivers.RemoveAll(r => r == nucleus); + synapse_nucleus._receivers.RemoveAll(r => r == nucleus); } else { // No other links, delete it. @@ -162,7 +185,7 @@ public class Neuron : INucleus { } } } - foreach (INucleus receiver in nucleus.receivers) { + foreach (INucleus receiver in nucleus.allReceivers) { if (receiver != null && receiver.synapses != null) receiver.synapses.RemoveAll(s => s.nucleus == nucleus); } @@ -174,7 +197,12 @@ public class Neuron : INucleus { } public Synapse AddSynapse(IReceptor sendingNucleus) { - Synapse synapse = new(sendingNucleus, 1.0f); + Synapse synapse = new(sendingNucleus); + this.synapses.Add(synapse); + return synapse; + } + public Synapse AddClusterSynapse(Cluster sendingCluster) { + Synapse synapse = new(sendingCluster); this.synapses.Add(synapse); return synapse; } @@ -222,7 +250,7 @@ public class Neuron : INucleus { // } this.outputValue = result; - foreach (INucleus receiver in this.receivers) + foreach (INucleus receiver in this.allReceivers) receiver.UpdateState(); } diff --git a/Assets/NanoBrain/NucleusArray.cs b/Assets/NanoBrain/NucleusArray.cs index 27f8194..426aac9 100644 --- a/Assets/NanoBrain/NucleusArray.cs +++ b/Assets/NanoBrain/NucleusArray.cs @@ -5,6 +5,7 @@ using UnityEngine; public class NucleusArray { [SerializeReference] public INucleus[] nuclei; + public Cluster[] clusters; public string name; public NucleusArray(INucleus nucleus) { diff --git a/Assets/NanoBrain/Receptor.cs b/Assets/NanoBrain/Receptor.cs index 1a3a0af..cd3bdbf 100644 --- a/Assets/NanoBrain/Receptor.cs +++ b/Assets/NanoBrain/Receptor.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Collections.Generic; using UnityEngine; using Unity.Mathematics; @@ -25,17 +26,30 @@ public class Receptor : IReceptor { [SerializeReference] private List _receivers = new(); - public List receivers => _receivers; + public List receivers { + get { return _receivers; } + set { _receivers = value; } + } + private List _clusterReceivers = new(); + public List clusterReceivers { + get { return _clusterReceivers; } + set { _clusterReceivers = value; } + } + public IEnumerable allReceivers => _receivers.Concat(_clusterReceivers); protected int[] thingIds; // every receiver can handle a thing with this id public virtual void AddReceiver(INucleus receivingNucleus) { - this.receivers.Add(receivingNucleus); + this._receivers.Add(receivingNucleus); receivingNucleus.AddSynapse(this); } + public void AddClusterReceiver(Cluster receivingCluster) { + this._clusterReceivers.Add(receivingCluster); + receivingCluster.AddSynapse(this); + } public void RemoveReceiver(INucleus receiverNucleus) { - this.receivers.RemoveAll(receiver => receiver == receiverNucleus); + this._receivers.RemoveAll(receiver => receiver == receiverNucleus); receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); } @@ -88,7 +102,7 @@ public class Receptor : IReceptor { receptor.AddReceiver(nucleus); } } - if (receptor.receivers.Count == 0) + if (receptor._receivers.Count == 0) return null; else return receptor; @@ -97,12 +111,12 @@ public class Receptor : IReceptor { public virtual void ProcessStimulus(int thingId, Vector3 newLocalPositionVector, string thingName = null) { this.localPosition = newLocalPositionVector; - thingIds ??= new int[this.receivers.Count]; + thingIds ??= new int[this._receivers.Count]; int receiverIx = 0; INucleus selectedReceiver = null; int selectedReceiverIx = 0; - foreach (INucleus receiver in this.receivers) { + foreach (INucleus receiver in this.allReceivers) { // selectedReceiver = receiver; // receiverIx++; diff --git a/Assets/NanoBrain/Synapse.cs b/Assets/NanoBrain/Synapse.cs index ef42fb5..9f4b1d5 100644 --- a/Assets/NanoBrain/Synapse.cs +++ b/Assets/NanoBrain/Synapse.cs @@ -4,12 +4,16 @@ using UnityEditor; [Serializable] public class Synapse { - //[NonSerialized] - [SerializeReference] - public IReceptor nucleus; + // Support access to cluster of basic nucleus + public IReceptor nucleus => clusterNucleus != null ? clusterNucleus : basicNucleus; + [SerializeReference] + private IReceptor basicNucleus; + // The Cluster is a ScriptableObject and can therefore not be serialized using [SerializeReference] + private Cluster clusterNucleus; + public Cluster cluster; - //public int nucleusId; + public float weight; public enum CurvePresets { @@ -19,55 +23,16 @@ public class Synapse { Reciprocal, Custom } - // public CurvePresets curvePreset; - // public AnimationCurve curve; public float curveMax = 1.0f; - public Synapse(IReceptor nucleus, float weight) { - this.nucleus = nucleus; - //this.nucleusId = nucleus.id; + public Synapse(IReceptor nucleus, float weight = 1.0f) { + this.basicNucleus = nucleus; + this.weight = weight; + } + public Synapse(Cluster cluster, float weight = 1.0f) { + this.clusterNucleus = cluster; this.weight = weight; } - - // public void Rebuild(NanoBrain brain) { - // // if (brain == null) { - // // return; - // // } - - // // foreach (Nucleus nucleus in brain.nuclei) { - // // if (nucleus.id == this.nucleusId) { - // // this.nucleus = nucleus; - // // return; - // // } - // // } - // // foreach (Perceptoid perceptoid in brain.perceptei) { - // // if (perceptoid.id == this.nucleusId) { - // // this.nucleus = perceptoid; - // // return; - // // } - // // } - // // Debug.LogError($"Synapse deserialization error: could not find nucleus with id {this.nucleusId}"); - // } - - // public AnimationCurve GenerateCurve() { - // switch (this.curvePreset) { - // case CurvePresets.Linear: - // this.curveMax = this.weight; - // return Presets.Linear(this.weight); - // case CurvePresets.Power: - // this.curveMax = this.weight; - // return Presets.Power(2.0f, this.weight); - // case CurvePresets.Sqrt: - // this.curveMax = this.weight; - // return Presets.Power(0.5f, this.weight); - // case CurvePresets.Reciprocal: - // this.curveMax = 1 / 0.01f * this.weight; - // return Presets.Reciprocal(this.weight); - // default: - // this.curveMax = weight; - // return AnimationCurve.Constant(0, 1, weight); - // } - // } public static class Presets { private const int samples = 32; diff --git a/Assets/NanoBrain/VisualEditor/Editor/BrainPickerWindow.cs b/Assets/NanoBrain/VisualEditor/Editor/BrainPickerWindow.cs index 6e7a849..66ef404 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/BrainPickerWindow.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/BrainPickerWindow.cs @@ -3,15 +3,13 @@ using UnityEngine; using System; using System.Linq; -public class BrainPickerWindow : EditorWindow -{ +public class BrainPickerWindow : EditorWindow { private Vector2 scroll; private Cluster[] items = new Cluster[0]; private Action onPicked; private string search = ""; - public static void ShowPicker(Action onPicked, string title = "Select NanoBrain") - { + public static void ShowPicker(Action onPicked, string title = "Select Cluster") { var w = CreateInstance(); w.titleContent = new GUIContent(title); w.minSize = new Vector2(360, 320); @@ -22,9 +20,8 @@ public class BrainPickerWindow : EditorWindow private void OnEnable() => RefreshList(); - private void RefreshList() - { - var guids = AssetDatabase.FindAssets("t:NanoBrain"); + private void RefreshList() { + var guids = AssetDatabase.FindAssets("t:Cluster"); items = guids .Select(g => AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(g))) .Where(b => b != null) @@ -32,11 +29,10 @@ public class BrainPickerWindow : EditorWindow .ToArray(); } - private void OnGUI() - { + private void OnGUI() { EditorGUILayout.Space(); EditorGUILayout.BeginHorizontal(); - EditorGUILayout.LabelField("Choose NanoBrain:", EditorStyles.boldLabel); + EditorGUILayout.LabelField("Choose Cluster:", EditorStyles.boldLabel); if (GUILayout.Button("Refresh", GUILayout.Width(80))) RefreshList(); GUILayout.FlexibleSpace(); EditorGUILayout.EndHorizontal(); @@ -46,15 +42,13 @@ public class BrainPickerWindow : EditorWindow EditorGUILayout.Space(); scroll = EditorGUILayout.BeginScrollView(scroll); - foreach (var it in items) - { + foreach (var it in items) { if (!string.IsNullOrEmpty(search) && it.name.IndexOf(search, StringComparison.OrdinalIgnoreCase) < 0) continue; EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField(EditorGUIUtility.ObjectContent(it, typeof(Cluster)), GUILayout.Height(20)); - if (GUILayout.Button("Select", GUILayout.Width(70))) - { + if (GUILayout.Button("Select", GUILayout.Width(70))) { onPicked?.Invoke(it); Close(); return; diff --git a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs index 9535e72..260a84d 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs @@ -156,8 +156,8 @@ public class ClusterInspector : Editor { return; NeuroidLayer currentLayer = new() { ix = layerIx }; - if (selectedNucleus.receivers != null) { - foreach (INucleus receiver in selectedNucleus.receivers) { + if (selectedNucleus.allReceivers != null) { + foreach (INucleus receiver in selectedNucleus.allReceivers) { INucleus outputNeuroid = receiver; if (outputNeuroid != null) { AddToLayer(currentLayer, outputNeuroid); @@ -201,19 +201,6 @@ public class ClusterInspector : Editor { } - // void OnMouseDown(MouseDownEvent e) { - // if (e.button == 2) { draggingCanvas = true; lastMouse = e.mousePosition; e.StopPropagation(); } - // } - // void OnMouseMove(MouseMoveEvent e) { - // if (draggingCanvas) { - // var delta = e.mousePosition - lastMouse; - // pan += delta; - // //content.style.left = pan.x; - // //content.style.top = pan.y; - // lastMouse = e.mousePosition; - // } - // } - // void OnMouseUp(MouseUpEvent e) { if (e.button == 2) draggingCanvas = false; } public void OnIMGUI() { if (currentNucleus == null) @@ -285,12 +272,12 @@ public class ClusterInspector : Editor { } private void DrawReceivers(INucleus nucleus, Vector3 parentPos, float size) { - int nodeCount = nucleus.receivers.Count; + int nodeCount = nucleus.allReceivers.Count(); // Determine the maximum value in this layer // This is used to 'scale' the output value colors of the nuclei float maxValue = 0; - foreach (INucleus receiver in nucleus.receivers) { + foreach (INucleus receiver in nucleus.allReceivers) { if (receiver is Neuron neuroid) { float value = length(neuroid.outputValue); if (value > maxValue) @@ -303,7 +290,7 @@ public class ClusterInspector : Editor { float margin = 10 + spacing / 2; int row = 0; - foreach (INucleus receiver in nucleus.receivers) { + foreach (INucleus receiver in nucleus.allReceivers) { INucleus receiverNucleus = receiver; if (receiverNucleus == null) continue; @@ -414,9 +401,14 @@ public class ClusterInspector : Editor { } else { style.alignment = TextAnchor.UpperCenter; - Vector3 labelPos = position - Vector3.down * (size + 0.2f); // below disc along up axis + Vector3 labelPos = position - Vector3.down * (size + 10f); // below disc along up axis Handles.Label(labelPos, nucleus.name, style); } + + if (nucleus is Cluster cluster) { + Handles.color = Color.white; + Handles.DrawWireDisc(position, Vector3.forward, size + 10); + } } else { style.alignment = TextAnchor.UpperCenter; @@ -592,7 +584,7 @@ public class ClusterInspector : Editor { return; if (nucleus.cluster != null) this.currentNucleus = nucleus.cluster.output; - foreach (INucleus receiver in nucleus.receivers) { + foreach (INucleus receiver in nucleus.allReceivers) { if (receiver != null) { this.currentNucleus = receiver; break; @@ -606,9 +598,9 @@ public class ClusterInspector : Editor { BrainPickerWindow.ShowPicker(brain => OnClusterPicked(nucleus, brain), "Select Cluster"); } - private void OnClusterPicked(INucleus nucleus, Cluster brain) { - Cluster brainInstance = Instantiate(brain); - brainInstance.AddReceiver(nucleus); + private void OnClusterPicked(INucleus nucleus, Cluster cluster) { + Cluster clusterInstance = Instantiate(cluster); + clusterInstance.AddReceiver(nucleus); } // Connect to another nucleus in the same cluster diff --git a/Assets/Scenes/Boids/New Cluster.asset b/Assets/Scenes/Boids/New Cluster.asset new file mode 100644 index 0000000..cf65675 --- /dev/null +++ b/Assets/Scenes/Boids/New Cluster.asset @@ -0,0 +1,62 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3} + m_Name: New Cluster + m_EditorClassIdentifier: Assembly-CSharp::Cluster + nuclei: + - rid: 2243601242842202217 + subClusters: [] + references: + version: 2 + RefIds: + - rid: 2243601242842202217 + type: {class: Neuron, ns: , asm: Assembly-CSharp} + data: + _name: Output + _synapses: [] + _receivers: [] + _array: + rid: 2243601242842202218 + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1000 + value: 1000 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + - rid: 2243601242842202218 + type: {class: NucleusArray, ns: , asm: Assembly-CSharp} + data: + nuclei: + - rid: 2243601242842202217 + clusters: [] + name: Output diff --git a/Assets/Scenes/Boids/New Cluster.asset.meta b/Assets/Scenes/Boids/New Cluster.asset.meta new file mode 100644 index 0000000..40fbc5e --- /dev/null +++ b/Assets/Scenes/Boids/New Cluster.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4160a4557d16d7c03833982ab779d28e +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/Boids/Scripts/Boid.cs b/Assets/Scenes/Boids/Scripts/Boid.cs index 5c99655..61c9a08 100644 --- a/Assets/Scenes/Boids/Scripts/Boid.cs +++ b/Assets/Scenes/Boids/Scripts/Boid.cs @@ -32,7 +32,6 @@ public class Boid : MonoBehaviour { // boidVelocityReceptor = Receptor.GetReceptor(nanoBrain.brain, BoidVelocityType); boundaryReceptor = Receptor.CreateReceptor(nanoBrain.brain, "Avoidance"); boundaryReceptor.name = "Boundary"; - boundaryReceptor.receivers[0].synapses[0].weight = -1; boidReceptor = Receptor.CreateReceptor(nanoBrain.brain, "Boid"); boidVelocityReceptor = Receptor.CreateReceptor(nanoBrain.brain, "Alignment"); From f309d4cec6a4e99ee1d2870963585c79b8251b27 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 21 Jan 2026 15:31:48 +0100 Subject: [PATCH 074/179] Fix clusterarray --- Assets/NanoBrain/NucleusArray.cs | 50 +++++++++++++------ .../VisualEditor/Editor/ClusterInspector.cs | 14 +++--- Assets/Scenes/Boids/New Cluster.asset | 13 +++-- 3 files changed, 47 insertions(+), 30 deletions(-) diff --git a/Assets/NanoBrain/NucleusArray.cs b/Assets/NanoBrain/NucleusArray.cs index 426aac9..3cd82d7 100644 --- a/Assets/NanoBrain/NucleusArray.cs +++ b/Assets/NanoBrain/NucleusArray.cs @@ -1,46 +1,64 @@ - +using System.Linq; +using System.Collections.Generic; using UnityEngine; [System.Serializable] public class NucleusArray { [SerializeReference] - public INucleus[] nuclei; - public Cluster[] clusters; + private INucleus[] _nuclei; + private Cluster[] _clusters; + public IEnumerable nuclei { + get { + if (_nuclei == null) + return _clusters; + else if (_clusters == null) + return _nuclei; + else + return _nuclei.Concat(_clusters); + } + } public string name; public NucleusArray(INucleus nucleus) { this.name = nucleus.name; - this.nuclei = new INucleus[1]; - this.nuclei[0] = nucleus; + this._nuclei = new INucleus[1]; + this._nuclei[0] = nucleus; + } + public NucleusArray(Cluster cluster) { + this.name = cluster.name; + this._clusters = new Cluster[1]; + this._clusters[0] = cluster; } public void AddNucleus() { - if (this.nuclei.Length == 0) { + if (this._nuclei.Length == 0) { Debug.LogError("Empty perceptoid array, cannot add"); return; } - int newLength = this.nuclei.Length + 1; + int newLength = this._nuclei.Length + 1; INucleus[] newArray = new INucleus[newLength]; - for (int i = 0; i < this.nuclei.Length; i++) - newArray[i] = this.nuclei[i]; - newArray[newLength - 1] = this.nuclei[0].Clone(); + for (int i = 0; i < this._nuclei.Length; i++) + newArray[i] = this._nuclei[i]; + newArray[newLength - 1] = this._nuclei[0].Clone(); - this.nuclei = newArray; + this._nuclei = newArray; } public void RemoveNucleus() { - int newLength = this.nuclei.Length - 1; + int newLength = this._nuclei.Length - 1; if (newLength == 0) { Debug.LogWarning("Perceptoid array cannot be empty"); return; } INucleus[] newPerceptei = new INucleus[newLength]; for (int i = 0; i < newLength; i++) - newPerceptei[i] = this.nuclei[i]; + newPerceptei[i] = this._nuclei[i]; // Delete the last perception - Neuron.Delete(this.nuclei[newLength]); - - this.nuclei = newPerceptei; + Neuron.Delete(this._nuclei[newLength]); + + this._nuclei = newPerceptei; } + + } \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs index 260a84d..f0ffccf 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs @@ -231,7 +231,7 @@ public class ClusterInspector : Editor { maxValue = value; } - float spacing = 400f / this.currentNucleus.array.nuclei.Length; + float spacing = 400f / this.currentNucleus.array.nuclei.Count(); float margin = 10 + spacing / 2; float xMin = 150 - size; float xMax = 150 + size; @@ -384,13 +384,13 @@ public class ClusterInspector : Editor { fontStyle = FontStyle.Bold, }; if (nucleus is INucleus neuron) { - if (neuron.array == null || neuron.array.nuclei == null || neuron.array.nuclei.Length == 0) + if (neuron.array == null || neuron.array.nuclei == null || neuron.array.nuclei.Count() == 0) neuron.array = new NucleusArray(neuron); - if ((!expandArray || neuron.array.nuclei[0] != this.currentNucleus) && neuron.array.nuclei.Length > 1) { - Handles.Label(labelPosition, neuron.array.nuclei.Length.ToString(), style); + if ((!expandArray || neuron.array.nuclei.First() != this.currentNucleus) && neuron.array.nuclei.Count() > 1) { + Handles.Label(labelPosition, neuron.array.nuclei.Count().ToString(), style); } - if (expandArray && neuron.array.nuclei[0] == this.currentNucleus) { + if (expandArray && neuron.array.nuclei.First() == this.currentNucleus) { int arrayIx = 0; foreach (INucleus n in neuron.array.nuclei) { if (n == neuron) @@ -497,10 +497,10 @@ public class ClusterInspector : Editor { neuroid.curvePreset = (Neuron.CurvePresets)EditorGUILayout.EnumPopup(neuroid.curvePreset, GUILayout.Width(100)); EditorGUILayout.EndHorizontal(); - if (neuroid.array == null || neuroid.array.nuclei == null || neuroid.array.nuclei.Length == 0) + if (neuroid.array == null || neuroid.array.nuclei == null || neuroid.array.nuclei.Count() == 0) neuroid.array = new NucleusArray(neuroid); EditorGUILayout.BeginHorizontal(); - EditorGUILayout.IntField("Array size", neuroid.array.nuclei.Length); + EditorGUILayout.IntField("Array size", neuroid.array.nuclei.Count()); if (GUILayout.Button("Add")) neuroid.array.AddNucleus(); if (GUILayout.Button("Del")) diff --git a/Assets/Scenes/Boids/New Cluster.asset b/Assets/Scenes/Boids/New Cluster.asset index cf65675..81ce16f 100644 --- a/Assets/Scenes/Boids/New Cluster.asset +++ b/Assets/Scenes/Boids/New Cluster.asset @@ -13,19 +13,19 @@ MonoBehaviour: m_Name: New Cluster m_EditorClassIdentifier: Assembly-CSharp::Cluster nuclei: - - rid: 2243601242842202217 + - rid: 2243601242842202225 subClusters: [] references: version: 2 RefIds: - - rid: 2243601242842202217 + - rid: 2243601242842202225 type: {class: Neuron, ns: , asm: Assembly-CSharp} data: _name: Output _synapses: [] _receivers: [] _array: - rid: 2243601242842202218 + rid: 2243601242842202226 _curvePreset: 0 curve: serializedVersion: 2 @@ -53,10 +53,9 @@ MonoBehaviour: m_RotationOrder: 4 curveMax: 1 average: 0 - - rid: 2243601242842202218 + - rid: 2243601242842202226 type: {class: NucleusArray, ns: , asm: Assembly-CSharp} data: - nuclei: - - rid: 2243601242842202217 - clusters: [] + _nuclei: + - rid: 2243601242842202225 name: Output From c6d9f727c0b14a384eca2782f3d9e325fc328ad6 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 21 Jan 2026 15:35:17 +0100 Subject: [PATCH 075/179] Fix nullptr in nucleusarray --- Assets/NanoBrain/NucleusArray.cs | 2 ++ .../NanoBrain/VisualEditor/Editor/ClusterInspector.cs | 4 ++-- Assets/Scenes/Boids/New Cluster.asset | 10 +++++----- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Assets/NanoBrain/NucleusArray.cs b/Assets/NanoBrain/NucleusArray.cs index 3cd82d7..5e10510 100644 --- a/Assets/NanoBrain/NucleusArray.cs +++ b/Assets/NanoBrain/NucleusArray.cs @@ -23,9 +23,11 @@ public class NucleusArray { this.name = nucleus.name; this._nuclei = new INucleus[1]; this._nuclei[0] = nucleus; + this._clusters = new Cluster[0]; } public NucleusArray(Cluster cluster) { this.name = cluster.name; + this._nuclei = new INucleus[0]; this._clusters = new Cluster[1]; this._clusters[0] = cluster; } diff --git a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs index f0ffccf..2764499 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs @@ -261,7 +261,7 @@ public class ClusterInspector : Editor { normal = { textColor = Color.white }, fontStyle = FontStyle.Bold, }; - Vector3 labelPos = new Vector3(150, yMax, 0) - Vector3.down * (size + 0.2f); // below disc along up axis + Vector3 labelPos = new Vector3(150, yMax, 0) - Vector3.down * (size + 10); // below disc along up axis Handles.Label(labelPos, this.currentNucleus.name, style); } else { @@ -412,7 +412,7 @@ public class ClusterInspector : Editor { } else { style.alignment = TextAnchor.UpperCenter; - Vector3 labelPos = position - Vector3.down * (size + 0.2f); // below disc along up axis + Vector3 labelPos = position - Vector3.down * (size + 10); // below disc along up axis Handles.Label(labelPos, nucleus.name, style); } diff --git a/Assets/Scenes/Boids/New Cluster.asset b/Assets/Scenes/Boids/New Cluster.asset index 81ce16f..e0c21c8 100644 --- a/Assets/Scenes/Boids/New Cluster.asset +++ b/Assets/Scenes/Boids/New Cluster.asset @@ -13,19 +13,19 @@ MonoBehaviour: m_Name: New Cluster m_EditorClassIdentifier: Assembly-CSharp::Cluster nuclei: - - rid: 2243601242842202225 + - rid: 2243601242842202229 subClusters: [] references: version: 2 RefIds: - - rid: 2243601242842202225 + - rid: 2243601242842202229 type: {class: Neuron, ns: , asm: Assembly-CSharp} data: _name: Output _synapses: [] _receivers: [] _array: - rid: 2243601242842202226 + rid: 2243601242842202230 _curvePreset: 0 curve: serializedVersion: 2 @@ -53,9 +53,9 @@ MonoBehaviour: m_RotationOrder: 4 curveMax: 1 average: 0 - - rid: 2243601242842202226 + - rid: 2243601242842202230 type: {class: NucleusArray, ns: , asm: Assembly-CSharp} data: _nuclei: - - rid: 2243601242842202225 + - rid: 2243601242842202229 name: Output From b556aa62fc1adab3a82dc10f72801a5bbd339048 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 21 Jan 2026 16:52:46 +0100 Subject: [PATCH 076/179] Improved subcluster support --- Assets/NanoBrain/Cluster.cs | 7 + Assets/NanoBrain/Identity.asset | 13 +- Assets/NanoBrain/Synapse.cs | 2 +- .../VisualEditor/Editor/ClusterInspector.cs | 20 +- Assets/Scenes/Boids/New Cluster.asset | 11 +- Assets/Scenes/Boids/NewSwarm.asset | 1489 ---- Assets/Scenes/Boids/NewSwarm.asset.meta | 8 - Assets/Scenes/Boids/RoamingBrain.asset | 129 - Assets/Scenes/Boids/RoamingBrain.asset.meta | 8 - Assets/Scenes/Boids/SwarmingBrain.asset | 7673 ----------------- Assets/Scenes/Boids/SwarmingBrain.asset.meta | 8 - 11 files changed, 38 insertions(+), 9330 deletions(-) delete mode 100644 Assets/Scenes/Boids/NewSwarm.asset delete mode 100644 Assets/Scenes/Boids/NewSwarm.asset.meta delete mode 100644 Assets/Scenes/Boids/RoamingBrain.asset delete mode 100644 Assets/Scenes/Boids/RoamingBrain.asset.meta delete mode 100644 Assets/Scenes/Boids/SwarmingBrain.asset delete mode 100644 Assets/Scenes/Boids/SwarmingBrain.asset.meta diff --git a/Assets/NanoBrain/Cluster.cs b/Assets/NanoBrain/Cluster.cs index 85d3214..f5c31c9 100644 --- a/Assets/NanoBrain/Cluster.cs +++ b/Assets/NanoBrain/Cluster.cs @@ -8,9 +8,16 @@ public class Cluster : ScriptableObject, INucleus { public Cluster cluster => this; + // The ScriptableObject asset from which the runtime object has been created + public Cluster asset; + [SerializeReference] public List nuclei = new(); + public List subClusters = new(); + public void AddSubCluster(Cluster subCluster) { + this.subClusters.Add(subCluster); + } public INucleus output => this.nuclei[0] as INucleus; diff --git a/Assets/NanoBrain/Identity.asset b/Assets/NanoBrain/Identity.asset index 3d62c75..efe44e6 100644 --- a/Assets/NanoBrain/Identity.asset +++ b/Assets/NanoBrain/Identity.asset @@ -13,18 +13,19 @@ MonoBehaviour: m_Name: Identity m_EditorClassIdentifier: Assembly-CSharp::Cluster nuclei: - - rid: 2243601242842202169 + - rid: 2243601242842202241 + subClusters: [] references: version: 2 RefIds: - - rid: 2243601242842202169 + - rid: 2243601242842202241 type: {class: Neuron, ns: , asm: Assembly-CSharp} data: _name: Output _synapses: [] _receivers: [] _array: - rid: 2243601242842202170 + rid: 2243601242842202242 _curvePreset: 0 curve: serializedVersion: 2 @@ -52,9 +53,9 @@ MonoBehaviour: m_RotationOrder: 4 curveMax: 1 average: 0 - - rid: 2243601242842202170 + - rid: 2243601242842202242 type: {class: NucleusArray, ns: , asm: Assembly-CSharp} data: - nuclei: - - rid: 2243601242842202169 + _nuclei: + - rid: 2243601242842202241 name: Output diff --git a/Assets/NanoBrain/Synapse.cs b/Assets/NanoBrain/Synapse.cs index 9f4b1d5..371dd27 100644 --- a/Assets/NanoBrain/Synapse.cs +++ b/Assets/NanoBrain/Synapse.cs @@ -30,7 +30,7 @@ public class Synapse { this.weight = weight; } public Synapse(Cluster cluster, float weight = 1.0f) { - this.clusterNucleus = cluster; + this.clusterNucleus = cluster.asset; this.weight = weight; } diff --git a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs index 2764499..2243fce 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs @@ -541,7 +541,7 @@ public class ClusterInspector : Editor { EditorGUILayout.Space(); - ConnectNucleus(cluster, this.currentNucleus); + ConnectNucleus(this.cluster, this.currentNucleus); if (GUILayout.Button("Add Input Neuron")) AddInputNeuron(this.currentNucleus); if (GUILayout.Button("Add Input Cluster")) @@ -552,6 +552,10 @@ public class ClusterInspector : Editor { if (GUILayout.Button("Delete this neuron")) DeleteNeuron(this.currentNucleus); + if (this.currentNucleus is Cluster subCluster) { + if (GUILayout.Button("Edit Cluster")) + EditCluster(subCluster); + } // if (this.gameObject != null) { // Vector3 worldVector = this.gameObject.transform.TransformVector(this.currentNucleus.outputValue); @@ -598,11 +602,21 @@ public class ClusterInspector : Editor { BrainPickerWindow.ShowPicker(brain => OnClusterPicked(nucleus, brain), "Select Cluster"); } - private void OnClusterPicked(INucleus nucleus, Cluster cluster) { - Cluster clusterInstance = Instantiate(cluster); + private void OnClusterPicked(INucleus nucleus, Cluster subCluster) { + Cluster clusterInstance = Instantiate(subCluster); + clusterInstance.asset = subCluster; + this.cluster.AddSubCluster(subCluster); clusterInstance.AddReceiver(nucleus); } + private void EditCluster(Cluster subCluster) { + //var currentActiveObject = Selection.activeObject; + Selection.activeObject = subCluster; + EditorGUIUtility.PingObject(subCluster); + var editor = Editor.CreateEditor(subCluster); + //Selection.activeObject = currentActiveObject; + } + // Connect to another nucleus in the same cluster protected virtual void ConnectNucleus(Cluster cluster, INucleus nucleus) { if (cluster == null) diff --git a/Assets/Scenes/Boids/New Cluster.asset b/Assets/Scenes/Boids/New Cluster.asset index e0c21c8..6b60702 100644 --- a/Assets/Scenes/Boids/New Cluster.asset +++ b/Assets/Scenes/Boids/New Cluster.asset @@ -12,20 +12,21 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3} m_Name: New Cluster m_EditorClassIdentifier: Assembly-CSharp::Cluster + asset: {fileID: 0} nuclei: - - rid: 2243601242842202229 + - rid: 2243601242842202259 subClusters: [] references: version: 2 RefIds: - - rid: 2243601242842202229 + - rid: 2243601242842202259 type: {class: Neuron, ns: , asm: Assembly-CSharp} data: _name: Output _synapses: [] _receivers: [] _array: - rid: 2243601242842202230 + rid: 2243601242842202260 _curvePreset: 0 curve: serializedVersion: 2 @@ -53,9 +54,9 @@ MonoBehaviour: m_RotationOrder: 4 curveMax: 1 average: 0 - - rid: 2243601242842202230 + - rid: 2243601242842202260 type: {class: NucleusArray, ns: , asm: Assembly-CSharp} data: _nuclei: - - rid: 2243601242842202229 + - rid: 2243601242842202259 name: Output diff --git a/Assets/Scenes/Boids/NewSwarm.asset b/Assets/Scenes/Boids/NewSwarm.asset deleted file mode 100644 index f9688a6..0000000 --- a/Assets/Scenes/Boids/NewSwarm.asset +++ /dev/null @@ -1,1489 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3} - m_Name: NewSwarm - m_EditorClassIdentifier: Assembly-CSharp::Cluster - nuclei: - - rid: 2243601062909444155 - - rid: 2243601062909444159 - - rid: 2243601062909444165 - - rid: 2243601062909444167 - - rid: 2243601062909444169 - - rid: 2243601062909444171 - - rid: 2243601062909444178 - references: - version: 2 - RefIds: - - rid: 2243601062909444155 - type: {class: Neuron, ns: , asm: Assembly-CSharp} - data: - _name: Velocity delta - _synapses: - - nucleus: - rid: 2243601062909444159 - cluster: {fileID: 0} - weight: 1 - curveMax: 1 - - nucleus: - rid: 2243601062909444165 - cluster: {fileID: 0} - weight: -5 - curveMax: 1 - - nucleus: - rid: 2243601062909444167 - cluster: {fileID: 0} - weight: 1 - curveMax: 1 - - nucleus: - rid: 2243601062909444171 - cluster: {fileID: 0} - weight: -1 - curveMax: 1 - _receivers: [] - _array: - rid: 2243601062909444156 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 1 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1000 - value: 1000 - inSlope: 1 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - - rid: 2243601062909444156 - type: {class: NucleusArray, ns: , asm: Assembly-CSharp} - data: - nuclei: - - rid: 2243601062909444155 - name: Output - - rid: 2243601062909444159 - type: {class: Neuron, ns: , asm: Assembly-CSharp} - data: - _name: Alignment - _synapses: [] - _receivers: - - rid: 2243601062909444155 - _array: - rid: 2243601062909444161 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 1 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1000 - value: 1000 - inSlope: 1 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - - rid: 2243601062909444161 - type: {class: NucleusArray, ns: , asm: Assembly-CSharp} - data: - nuclei: - - rid: 2243601062909444159 - name: New neuron - - rid: 2243601062909444165 - type: {class: Neuron, ns: , asm: Assembly-CSharp} - data: - _name: Avoidance - _synapses: [] - _receivers: - - rid: 2243601062909444155 - _array: - rid: 2243601062909444166 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 1 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1000 - value: 1000 - inSlope: 1 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - - rid: 2243601062909444166 - type: {class: NucleusArray, ns: , asm: Assembly-CSharp} - data: - nuclei: - - rid: 2243601062909444165 - name: New neuron - - rid: 2243601062909444167 - type: {class: Neuron, ns: , asm: Assembly-CSharp} - data: - _name: Cohesion - _synapses: - - nucleus: - rid: 2243601062909444169 - cluster: {fileID: 0} - weight: 1 - curveMax: 1 - - nucleus: - rid: 2243601062909444178 - cluster: {fileID: 0} - weight: 1 - curveMax: 1 - _receivers: - - rid: 2243601062909444155 - _array: - rid: 2243601062909444168 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 1 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1000 - value: 1000 - inSlope: 1 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - - rid: 2243601062909444168 - type: {class: NucleusArray, ns: , asm: Assembly-CSharp} - data: - nuclei: - - rid: 2243601062909444167 - name: New neuron - - rid: 2243601062909444169 - type: {class: Neuron, ns: , asm: Assembly-CSharp} - data: - _name: Boid - _synapses: [] - _receivers: - - rid: 2243601062909444167 - - rid: 2243601062909444171 - _array: - rid: 2243601062909444170 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 1 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1000 - value: 1000 - inSlope: 1 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - - rid: 2243601062909444170 - type: {class: NucleusArray, ns: , asm: Assembly-CSharp} - data: - nuclei: - - rid: 2243601062909444169 - - rid: 2243601062909444178 - name: New neuron - - rid: 2243601062909444171 - type: {class: Neuron, ns: , asm: Assembly-CSharp} - data: - _name: Separation - _synapses: - - nucleus: - rid: 2243601062909444169 - cluster: {fileID: 0} - weight: -1 - curveMax: 1 - - nucleus: - rid: 2243601062909444178 - cluster: {fileID: 0} - weight: 1 - curveMax: 1 - _receivers: - - rid: 2243601062909444155 - _array: - rid: 2243601062909444172 - _curvePreset: 3 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0.001 - value: 999.99994 - inSlope: 0 - outSlope: -112788.63 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.008866142 - value: 112.788635 - inSlope: -112788.63 - outSlope: -6740.78 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.016732283 - value: 59.76471 - inSlope: -6740.78 - outSlope: -2429.6155 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.024598425 - value: 40.653008 - inSlope: -2429.6155 - outSlope: -1252.2269 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.032464568 - value: 30.802813 - inSlope: -1252.2269 - outSlope: -763.7558 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.040330708 - value: 24.795002 - inSlope: -763.7558 - outSlope: -514.45264 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.04819685 - value: 20.748245 - inSlope: -514.45264 - outSlope: -370.0882 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.056062993 - value: 17.837078 - inSlope: -370.0882 - outSlope: -279.01324 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.06392913 - value: 15.642321 - inSlope: -279.01324 - outSlope: -217.87398 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.07179528 - value: 13.928493 - inSlope: -217.87398 - outSlope: -174.8461 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.079661414 - value: 12.553129 - inSlope: -174.8461 - outSlope: -143.41913 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.087527566 - value: 11.424973 - inSlope: -143.41913 - outSlope: -119.76661 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.0953937 - value: 10.482872 - inSlope: -119.76661 - outSlope: -101.519356 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.10325985 - value: 9.684306 - inSlope: -101.519356 - outSlope: -87.14706 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.11112598 - value: 8.9987955 - inSlope: -87.14706 - outSlope: -75.62513 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.11899213 - value: 8.403917 - inSlope: -75.62513 - outSlope: -66.24654 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.12685826 - value: 7.882813 - inSlope: -66.24654 - outSlope: -58.510654 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.13472441 - value: 7.4225597 - inSlope: -58.510654 - outSlope: -52.055042 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.14259055 - value: 7.0130873 - inSlope: -52.055042 - outSlope: -46.612007 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.1504567 - value: 6.6464305 - inSlope: -46.612007 - outSlope: -41.98024 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.15832284 - value: 6.316208 - inSlope: -41.98024 - outSlope: -38.006134 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.16618897 - value: 6.0172467 - inSlope: -38.006134 - outSlope: -34.570965 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.17405513 - value: 5.745306 - inSlope: -34.570965 - outSlope: -31.581244 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.18192126 - value: 5.496884 - inSlope: -31.581244 - outSlope: -28.963417 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.1897874 - value: 5.2690535 - inSlope: -28.963417 - outSlope: -26.658009 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.19765353 - value: 5.059358 - inSlope: -26.658009 - outSlope: -24.617418 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.20551969 - value: 4.8657136 - inSlope: -24.617418 - outSlope: -22.802412 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.21338584 - value: 4.6863465 - inSlope: -22.802412 - outSlope: -21.181019 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.22125196 - value: 4.519734 - inSlope: -21.181019 - outSlope: -19.72667 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.22911811 - value: 4.364561 - inSlope: -19.72667 - outSlope: -18.417059 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.23698425 - value: 4.21969 - inSlope: -18.417059 - outSlope: -17.233776 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.2448504 - value: 4.0841265 - inSlope: -17.233776 - outSlope: -16.160883 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.25271654 - value: 3.9570026 - inSlope: -16.160883 - outSlope: -15.185221 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.2605827 - value: 3.8375535 - inSlope: -15.185221 - outSlope: -14.295299 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.2684488 - value: 3.725105 - inSlope: -14.295299 - outSlope: -13.481375 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.27631494 - value: 3.6190586 - inSlope: -13.481375 - outSlope: -12.735047 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.28418112 - value: 3.5188825 - inSlope: -12.735047 - outSlope: -12.04901 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.29204726 - value: 3.4241033 - inSlope: -12.04901 - outSlope: -11.416967 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.2999134 - value: 3.3342957 - inSlope: -11.416967 - outSlope: -10.8334 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.30777952 - value: 3.249079 - inSlope: -10.8334 - outSlope: -10.293426 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.31564566 - value: 3.1681094 - inSlope: -10.293426 - outSlope: -9.792865 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.3235118 - value: 3.0910773 - inSlope: -9.792865 - outSlope: -9.327949 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.33137795 - value: 3.0177023 - inSlope: -9.327949 - outSlope: -8.895375 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.33924407 - value: 2.9477303 - inSlope: -8.895375 - outSlope: -8.492224 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.34711024 - value: 2.880929 - inSlope: -8.492224 - outSlope: -8.115812 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.3549764 - value: 2.8170888 - inSlope: -8.115812 - outSlope: -7.76395 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.36284253 - value: 2.7560165 - inSlope: -7.76395 - outSlope: -7.434456 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.37070867 - value: 2.697536 - inSlope: -7.434456 - outSlope: -7.1255083 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.3785748 - value: 2.641486 - inSlope: -7.1255083 - outSlope: -6.8354197 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.38644093 - value: 2.5877175 - inSlope: -6.8354197 - outSlope: -6.562695 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.39430708 - value: 2.5360944 - inSlope: -6.562695 - outSlope: -6.305974 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.40217322 - value: 2.4864907 - inSlope: -6.305974 - outSlope: -6.064021 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4100394 - value: 2.43879 - inSlope: -6.064021 - outSlope: -5.835745 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4179055 - value: 2.3928854 - inSlope: -5.835745 - outSlope: -5.6201315 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.42577165 - value: 2.3486767 - inSlope: -5.6201315 - outSlope: -5.4162097 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4336378 - value: 2.306072 - inSlope: -5.4162097 - outSlope: -5.223229 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.44150394 - value: 2.2649853 - inSlope: -5.223229 - outSlope: -5.040342 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4493701 - value: 2.2253373 - inSlope: -5.040342 - outSlope: -4.8669295 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4572362 - value: 2.1870534 - inSlope: -4.8669295 - outSlope: -4.7023005 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.46510234 - value: 2.1500645 - inSlope: -4.7023005 - outSlope: -4.5458865 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.47296852 - value: 2.1143057 - inSlope: -4.5458865 - outSlope: -4.3971753 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.48083466 - value: 2.079717 - inSlope: -4.3971753 - outSlope: -4.2555995 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4887008 - value: 2.0462418 - inSlope: -4.2555995 - outSlope: -4.1207685 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.49656692 - value: 2.0138273 - inSlope: -4.1207685 - outSlope: -3.9922712 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5044331 - value: 1.9824234 - inSlope: -3.9922712 - outSlope: -3.8696532 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5122992 - value: 1.9519844 - inSlope: -3.8696532 - outSlope: -3.7526293 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5201653 - value: 1.9224657 - inSlope: -3.7526293 - outSlope: -3.6408176 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.52803147 - value: 1.8938265 - inSlope: -3.6408176 - outSlope: -3.5339315 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5358976 - value: 1.8660281 - inSlope: -3.5339315 - outSlope: -3.4316826 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.54376376 - value: 1.839034 - inSlope: -3.4316826 - outSlope: -3.3338284 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5516299 - value: 1.8128096 - inSlope: -3.3338284 - outSlope: -3.240066 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.55949605 - value: 1.7873228 - inSlope: -3.240066 - outSlope: -3.1502352 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.56736225 - value: 1.7625424 - inSlope: -3.1502352 - outSlope: -3.0640743 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5752284 - value: 1.7384399 - inSlope: -3.0640743 - outSlope: -2.9814053 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.58309454 - value: 1.7149878 - inSlope: -2.9814053 - outSlope: -2.9020314 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5909606 - value: 1.6921601 - inSlope: -2.9020314 - outSlope: -2.8257964 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.59882677 - value: 1.669932 - inSlope: -2.8257964 - outSlope: -2.7525082 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6066929 - value: 1.6482804 - inSlope: -2.7525082 - outSlope: -2.6820538 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.61455905 - value: 1.627183 - inSlope: -2.6820538 - outSlope: -2.6142666 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6224252 - value: 1.6066188 - inSlope: -2.6142666 - outSlope: -2.5490105 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.63029134 - value: 1.5865679 - inSlope: -2.5490105 - outSlope: -2.4861636 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6381575 - value: 1.5670114 - inSlope: -2.4861636 - outSlope: -2.4256358 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.64602363 - value: 1.547931 - inSlope: -2.4256358 - outSlope: -2.3672597 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6538898 - value: 1.5293097 - inSlope: -2.3672597 - outSlope: -2.3109925 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.66175586 - value: 1.5111313 - inSlope: -2.3109925 - outSlope: -2.2566907 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.669622 - value: 1.4933798 - inSlope: -2.2566907 - outSlope: -2.2042859 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.67748815 - value: 1.4760406 - inSlope: -2.2042859 - outSlope: -2.1536992 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6853543 - value: 1.4590993 - inSlope: -2.1536992 - outSlope: -2.1048093 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6932205 - value: 1.4425424 - inSlope: -2.1048093 - outSlope: -2.0575728 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.70108664 - value: 1.4263573 - inSlope: -2.0575728 - outSlope: -2.011927 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7089528 - value: 1.4105312 - inSlope: -2.011927 - outSlope: -1.9677659 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7168189 - value: 1.3950524 - inSlope: -1.9677659 - outSlope: -1.9250447 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7246851 - value: 1.3799098 - inSlope: -1.9250447 - outSlope: -1.8837026 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7325512 - value: 1.3650923 - inSlope: -1.8837026 - outSlope: -1.8436778 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7404173 - value: 1.3505898 - inSlope: -1.8436778 - outSlope: -1.8049132 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.74828345 - value: 1.336392 - inSlope: -1.8049132 - outSlope: -1.7673749 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7561496 - value: 1.3224896 - inSlope: -1.7673749 - outSlope: -1.7309732 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.76401573 - value: 1.3088735 - inSlope: -1.7309732 - outSlope: -1.695693 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7718819 - value: 1.295535 - inSlope: -1.695693 - outSlope: -1.6614736 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.779748 - value: 1.2824656 - inSlope: -1.6614736 - outSlope: -1.6282848 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.78761417 - value: 1.2696573 - inSlope: -1.6282848 - outSlope: -1.5960962 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7954803 - value: 1.2571021 - inSlope: -1.5960962 - outSlope: -1.564832 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.80334646 - value: 1.2447929 - inSlope: -1.564832 - outSlope: -1.5344887 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.81121254 - value: 1.2327225 - inSlope: -1.5344887 - outSlope: -1.5050048 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.81907874 - value: 1.2208838 - inSlope: -1.5050048 - outSlope: -1.4763738 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8269449 - value: 1.2092705 - inSlope: -1.4763738 - outSlope: -1.4485649 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.83481103 - value: 1.1978759 - inSlope: -1.4485649 - outSlope: -1.4215137 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8426772 - value: 1.186694 - inSlope: -1.4215137 - outSlope: -1.3952202 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8505433 - value: 1.175719 - inSlope: -1.3952202 - outSlope: -1.369639 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.85840946 - value: 1.1649452 - inSlope: -1.369639 - outSlope: -1.3447852 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8662756 - value: 1.154367 - inSlope: -1.3447852 - outSlope: -1.320568 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.87414175 - value: 1.1439792 - inSlope: -1.320568 - outSlope: -1.2970176 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8820079 - value: 1.1337767 - inSlope: -1.2970176 - outSlope: -1.2740829 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.889874 - value: 1.1237546 - inSlope: -1.2740829 - outSlope: -1.2517655 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8977401 - value: 1.113908 - inSlope: -1.2517655 - outSlope: -1.2300034 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.90560627 - value: 1.1042327 - inSlope: -1.2300034 - outSlope: -1.2088321 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9134724 - value: 1.0947238 - inSlope: -1.2088321 - outSlope: -1.1881914 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.92133856 - value: 1.0853773 - inSlope: -1.1881914 - outSlope: -1.1680659 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9292047 - value: 1.0761892 - inSlope: -1.1680659 - outSlope: -1.1484709 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.93707085 - value: 1.0671551 - inSlope: -1.1484709 - outSlope: -1.1293371 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.94493705 - value: 1.0582715 - inSlope: -1.1293371 - outSlope: -1.1106901 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9528032 - value: 1.0495347 - inSlope: -1.1106901 - outSlope: -1.0925045 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.96066934 - value: 1.0409409 - inSlope: -1.0925045 - outSlope: -1.0747513 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9685354 - value: 1.0324868 - inSlope: -1.0747513 - outSlope: -1.0574516 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.97640157 - value: 1.0241687 - inSlope: -1.0574516 - outSlope: -1.0405389 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9842677 - value: 1.0159837 - inSlope: -1.0405389 - outSlope: -1.0240355 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.99213386 - value: 1.0079285 - inSlope: -1.0240355 - outSlope: -1.0079259 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1 - value: 1 - inSlope: -1.0079259 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 100 - average: 0 - - rid: 2243601062909444172 - type: {class: NucleusArray, ns: , asm: Assembly-CSharp} - data: - nuclei: - - rid: 2243601062909444171 - name: New neuron - - rid: 2243601062909444178 - type: {class: Neuron, ns: , asm: Assembly-CSharp} - data: - _name: Boid - _synapses: [] - _receivers: - - rid: 2243601062909444167 - - rid: 2243601062909444171 - _array: - rid: 2243601062909444170 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 1 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1000 - value: 1000 - inSlope: 1 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 diff --git a/Assets/Scenes/Boids/NewSwarm.asset.meta b/Assets/Scenes/Boids/NewSwarm.asset.meta deleted file mode 100644 index db2e437..0000000 --- a/Assets/Scenes/Boids/NewSwarm.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 83e4ef8976534236989bcb1a9342dbf8 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Scenes/Boids/RoamingBrain.asset b/Assets/Scenes/Boids/RoamingBrain.asset deleted file mode 100644 index 0771c4d..0000000 --- a/Assets/Scenes/Boids/RoamingBrain.asset +++ /dev/null @@ -1,129 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 36081359186edfec998d891a1feeb17b, type: 3} - m_Name: RoamingBrain - m_EditorClassIdentifier: Assembly-CSharp::NanoBrainObj - title: - count: 0 - color: {r: 1, g: 1, b: 1, a: 1} - texture: {fileID: 0} - nuclei: - - id: -1707533328 - _name: Root - synapses: - - nucleusId: -112538112 - weight: 10 - curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 0 - receivers: [] - nucleusType: - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 1 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1 - value: 1 - inSlope: 1 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - - id: -112538112 - _name: Avoidance - synapses: - - nucleusId: 407735232 - weight: -1 - curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 0 - receivers: - - nucleusId: -1707533328 - nucleusType: - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 1 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1 - value: 1 - inSlope: 1 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - perceptei: - - id: 407735232 - _name: Boundary - synapses: [] - receivers: - - nucleusId: -112538112 - nucleusType: Perceptoid - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 0 - average: 0 - inverse: 0 - exponent: 1 - thingType: 1 - thingId: 0 - rootId: -1707533328 diff --git a/Assets/Scenes/Boids/RoamingBrain.asset.meta b/Assets/Scenes/Boids/RoamingBrain.asset.meta deleted file mode 100644 index 74e1c7d..0000000 --- a/Assets/Scenes/Boids/RoamingBrain.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: af8d90b8b4b9dcad7837130c4143d91c -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Scenes/Boids/SwarmingBrain.asset b/Assets/Scenes/Boids/SwarmingBrain.asset deleted file mode 100644 index a0943f9..0000000 --- a/Assets/Scenes/Boids/SwarmingBrain.asset +++ /dev/null @@ -1,7673 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 36081359186edfec998d891a1feeb17b, type: 3} - m_Name: SwarmingBrain - m_EditorClassIdentifier: Assembly-CSharp::NanoBrainObj - nuclei: - - id: -1707533328 - _name: Root - _synapses: [] - _receivers: [] - nucleusType: - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 1 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1000 - value: 1000 - inSlope: 1 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - - id: -112538112 - _name: Avoidance - _synapses: [] - _receivers: [] - nucleusType: - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 1 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1000 - value: 1000 - inSlope: 1 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - - id: 1938577052 - _name: Cohesion - _synapses: [] - _receivers: [] - nucleusType: - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 1 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1000 - value: 1000 - inSlope: 1 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - - id: 1641120128 - _name: Separation - _synapses: [] - _receivers: [] - nucleusType: - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 1 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1000 - value: 1000 - inSlope: 1 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - - id: -1857835930 - _name: Alignment - _synapses: [] - _receivers: [] - nucleusType: - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 1 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1000 - value: 1000 - inSlope: 1 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - - id: 1710403072 - _name: Inverse Boid A - _synapses: [] - _receivers: [] - nucleusType: - _curvePreset: 3 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0.001 - value: 999.99994 - inSlope: 0 - outSlope: -112788.63 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.008866142 - value: 112.788635 - inSlope: -112788.63 - outSlope: -6740.78 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.016732283 - value: 59.76471 - inSlope: -6740.78 - outSlope: -2429.6155 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.024598425 - value: 40.653008 - inSlope: -2429.6155 - outSlope: -1252.2269 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.032464568 - value: 30.802813 - inSlope: -1252.2269 - outSlope: -763.7558 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.040330708 - value: 24.795002 - inSlope: -763.7558 - outSlope: -514.45264 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.04819685 - value: 20.748245 - inSlope: -514.45264 - outSlope: -370.0882 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.056062993 - value: 17.837078 - inSlope: -370.0882 - outSlope: -279.01324 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.06392913 - value: 15.642321 - inSlope: -279.01324 - outSlope: -217.87398 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.07179528 - value: 13.928493 - inSlope: -217.87398 - outSlope: -174.8461 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.079661414 - value: 12.553129 - inSlope: -174.8461 - outSlope: -143.41913 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.087527566 - value: 11.424973 - inSlope: -143.41913 - outSlope: -119.76661 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.0953937 - value: 10.482872 - inSlope: -119.76661 - outSlope: -101.519356 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.10325985 - value: 9.684306 - inSlope: -101.519356 - outSlope: -87.14706 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.11112598 - value: 8.9987955 - inSlope: -87.14706 - outSlope: -75.62513 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.11899213 - value: 8.403917 - inSlope: -75.62513 - outSlope: -66.24654 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.12685826 - value: 7.882813 - inSlope: -66.24654 - outSlope: -58.510654 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.13472441 - value: 7.4225597 - inSlope: -58.510654 - outSlope: -52.055042 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.14259055 - value: 7.0130873 - inSlope: -52.055042 - outSlope: -46.612007 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.1504567 - value: 6.6464305 - inSlope: -46.612007 - outSlope: -41.98024 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.15832284 - value: 6.316208 - inSlope: -41.98024 - outSlope: -38.006134 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.16618897 - value: 6.0172467 - inSlope: -38.006134 - outSlope: -34.570965 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.17405513 - value: 5.745306 - inSlope: -34.570965 - outSlope: -31.581244 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.18192126 - value: 5.496884 - inSlope: -31.581244 - outSlope: -28.963417 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.1897874 - value: 5.2690535 - inSlope: -28.963417 - outSlope: -26.658009 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.19765353 - value: 5.059358 - inSlope: -26.658009 - outSlope: -24.617418 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.20551969 - value: 4.8657136 - inSlope: -24.617418 - outSlope: -22.802412 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.21338584 - value: 4.6863465 - inSlope: -22.802412 - outSlope: -21.181019 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.22125196 - value: 4.519734 - inSlope: -21.181019 - outSlope: -19.72667 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.22911811 - value: 4.364561 - inSlope: -19.72667 - outSlope: -18.417059 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.23698425 - value: 4.21969 - inSlope: -18.417059 - outSlope: -17.233776 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.2448504 - value: 4.0841265 - inSlope: -17.233776 - outSlope: -16.160883 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.25271654 - value: 3.9570026 - inSlope: -16.160883 - outSlope: -15.185221 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.2605827 - value: 3.8375535 - inSlope: -15.185221 - outSlope: -14.295299 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.2684488 - value: 3.725105 - inSlope: -14.295299 - outSlope: -13.481375 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.27631494 - value: 3.6190586 - inSlope: -13.481375 - outSlope: -12.735047 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.28418112 - value: 3.5188825 - inSlope: -12.735047 - outSlope: -12.04901 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.29204726 - value: 3.4241033 - inSlope: -12.04901 - outSlope: -11.416967 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.2999134 - value: 3.3342957 - inSlope: -11.416967 - outSlope: -10.8334 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.30777952 - value: 3.249079 - inSlope: -10.8334 - outSlope: -10.293426 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.31564566 - value: 3.1681094 - inSlope: -10.293426 - outSlope: -9.792865 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.3235118 - value: 3.0910773 - inSlope: -9.792865 - outSlope: -9.327949 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.33137795 - value: 3.0177023 - inSlope: -9.327949 - outSlope: -8.895375 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.33924407 - value: 2.9477303 - inSlope: -8.895375 - outSlope: -8.492224 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.34711024 - value: 2.880929 - inSlope: -8.492224 - outSlope: -8.115812 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.3549764 - value: 2.8170888 - inSlope: -8.115812 - outSlope: -7.76395 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.36284253 - value: 2.7560165 - inSlope: -7.76395 - outSlope: -7.434456 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.37070867 - value: 2.697536 - inSlope: -7.434456 - outSlope: -7.1255083 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.3785748 - value: 2.641486 - inSlope: -7.1255083 - outSlope: -6.8354197 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.38644093 - value: 2.5877175 - inSlope: -6.8354197 - outSlope: -6.562695 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.39430708 - value: 2.5360944 - inSlope: -6.562695 - outSlope: -6.305974 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.40217322 - value: 2.4864907 - inSlope: -6.305974 - outSlope: -6.064021 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4100394 - value: 2.43879 - inSlope: -6.064021 - outSlope: -5.835745 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4179055 - value: 2.3928854 - inSlope: -5.835745 - outSlope: -5.6201315 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.42577165 - value: 2.3486767 - inSlope: -5.6201315 - outSlope: -5.4162097 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4336378 - value: 2.306072 - inSlope: -5.4162097 - outSlope: -5.223229 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.44150394 - value: 2.2649853 - inSlope: -5.223229 - outSlope: -5.040342 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4493701 - value: 2.2253373 - inSlope: -5.040342 - outSlope: -4.8669295 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4572362 - value: 2.1870534 - inSlope: -4.8669295 - outSlope: -4.7023005 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.46510234 - value: 2.1500645 - inSlope: -4.7023005 - outSlope: -4.5458865 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.47296852 - value: 2.1143057 - inSlope: -4.5458865 - outSlope: -4.3971753 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.48083466 - value: 2.079717 - inSlope: -4.3971753 - outSlope: -4.2555995 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4887008 - value: 2.0462418 - inSlope: -4.2555995 - outSlope: -4.1207685 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.49656692 - value: 2.0138273 - inSlope: -4.1207685 - outSlope: -3.9922712 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5044331 - value: 1.9824234 - inSlope: -3.9922712 - outSlope: -3.8696532 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5122992 - value: 1.9519844 - inSlope: -3.8696532 - outSlope: -3.7526293 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5201653 - value: 1.9224657 - inSlope: -3.7526293 - outSlope: -3.6408176 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.52803147 - value: 1.8938265 - inSlope: -3.6408176 - outSlope: -3.5339315 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5358976 - value: 1.8660281 - inSlope: -3.5339315 - outSlope: -3.4316826 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.54376376 - value: 1.839034 - inSlope: -3.4316826 - outSlope: -3.3338284 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5516299 - value: 1.8128096 - inSlope: -3.3338284 - outSlope: -3.240066 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.55949605 - value: 1.7873228 - inSlope: -3.240066 - outSlope: -3.1502352 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.56736225 - value: 1.7625424 - inSlope: -3.1502352 - outSlope: -3.0640743 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5752284 - value: 1.7384399 - inSlope: -3.0640743 - outSlope: -2.9814053 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.58309454 - value: 1.7149878 - inSlope: -2.9814053 - outSlope: -2.9020314 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5909606 - value: 1.6921601 - inSlope: -2.9020314 - outSlope: -2.8257964 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.59882677 - value: 1.669932 - inSlope: -2.8257964 - outSlope: -2.7525082 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6066929 - value: 1.6482804 - inSlope: -2.7525082 - outSlope: -2.6820538 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.61455905 - value: 1.627183 - inSlope: -2.6820538 - outSlope: -2.6142666 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6224252 - value: 1.6066188 - inSlope: -2.6142666 - outSlope: -2.5490105 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.63029134 - value: 1.5865679 - inSlope: -2.5490105 - outSlope: -2.4861636 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6381575 - value: 1.5670114 - inSlope: -2.4861636 - outSlope: -2.4256358 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.64602363 - value: 1.547931 - inSlope: -2.4256358 - outSlope: -2.3672597 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6538898 - value: 1.5293097 - inSlope: -2.3672597 - outSlope: -2.3109925 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.66175586 - value: 1.5111313 - inSlope: -2.3109925 - outSlope: -2.2566907 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.669622 - value: 1.4933798 - inSlope: -2.2566907 - outSlope: -2.2042859 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.67748815 - value: 1.4760406 - inSlope: -2.2042859 - outSlope: -2.1536992 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6853543 - value: 1.4590993 - inSlope: -2.1536992 - outSlope: -2.1048093 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6932205 - value: 1.4425424 - inSlope: -2.1048093 - outSlope: -2.0575728 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.70108664 - value: 1.4263573 - inSlope: -2.0575728 - outSlope: -2.011927 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7089528 - value: 1.4105312 - inSlope: -2.011927 - outSlope: -1.9677659 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7168189 - value: 1.3950524 - inSlope: -1.9677659 - outSlope: -1.9250447 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7246851 - value: 1.3799098 - inSlope: -1.9250447 - outSlope: -1.8837026 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7325512 - value: 1.3650923 - inSlope: -1.8837026 - outSlope: -1.8436778 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7404173 - value: 1.3505898 - inSlope: -1.8436778 - outSlope: -1.8049132 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.74828345 - value: 1.336392 - inSlope: -1.8049132 - outSlope: -1.7673749 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7561496 - value: 1.3224896 - inSlope: -1.7673749 - outSlope: -1.7309732 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.76401573 - value: 1.3088735 - inSlope: -1.7309732 - outSlope: -1.695693 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7718819 - value: 1.295535 - inSlope: -1.695693 - outSlope: -1.6614736 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.779748 - value: 1.2824656 - inSlope: -1.6614736 - outSlope: -1.6282848 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.78761417 - value: 1.2696573 - inSlope: -1.6282848 - outSlope: -1.5960962 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7954803 - value: 1.2571021 - inSlope: -1.5960962 - outSlope: -1.564832 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.80334646 - value: 1.2447929 - inSlope: -1.564832 - outSlope: -1.5344887 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.81121254 - value: 1.2327225 - inSlope: -1.5344887 - outSlope: -1.5050048 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.81907874 - value: 1.2208838 - inSlope: -1.5050048 - outSlope: -1.4763738 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8269449 - value: 1.2092705 - inSlope: -1.4763738 - outSlope: -1.4485649 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.83481103 - value: 1.1978759 - inSlope: -1.4485649 - outSlope: -1.4215137 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8426772 - value: 1.186694 - inSlope: -1.4215137 - outSlope: -1.3952202 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8505433 - value: 1.175719 - inSlope: -1.3952202 - outSlope: -1.369639 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.85840946 - value: 1.1649452 - inSlope: -1.369639 - outSlope: -1.3447852 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8662756 - value: 1.154367 - inSlope: -1.3447852 - outSlope: -1.320568 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.87414175 - value: 1.1439792 - inSlope: -1.320568 - outSlope: -1.2970176 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8820079 - value: 1.1337767 - inSlope: -1.2970176 - outSlope: -1.2740829 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.889874 - value: 1.1237546 - inSlope: -1.2740829 - outSlope: -1.2517655 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8977401 - value: 1.113908 - inSlope: -1.2517655 - outSlope: -1.2300034 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.90560627 - value: 1.1042327 - inSlope: -1.2300034 - outSlope: -1.2088321 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9134724 - value: 1.0947238 - inSlope: -1.2088321 - outSlope: -1.1881914 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.92133856 - value: 1.0853773 - inSlope: -1.1881914 - outSlope: -1.1680659 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9292047 - value: 1.0761892 - inSlope: -1.1680659 - outSlope: -1.1484709 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.93707085 - value: 1.0671551 - inSlope: -1.1484709 - outSlope: -1.1293371 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.94493705 - value: 1.0582715 - inSlope: -1.1293371 - outSlope: -1.1106901 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9528032 - value: 1.0495347 - inSlope: -1.1106901 - outSlope: -1.0925045 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.96066934 - value: 1.0409409 - inSlope: -1.0925045 - outSlope: -1.0747513 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9685354 - value: 1.0324868 - inSlope: -1.0747513 - outSlope: -1.0574516 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.97640157 - value: 1.0241687 - inSlope: -1.0574516 - outSlope: -1.0405389 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9842677 - value: 1.0159837 - inSlope: -1.0405389 - outSlope: -1.0240355 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.99213386 - value: 1.0079285 - inSlope: -1.0240355 - outSlope: -1.0079259 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1 - value: 1 - inSlope: -1.0079259 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 100 - average: 0 - inverse: 0 - exponent: 1 - - id: -916054576 - _name: Inverse Boid B - _synapses: [] - _receivers: [] - nucleusType: - _curvePreset: 3 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0.001 - value: 999.99994 - inSlope: 0 - outSlope: -112788.63 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.008866142 - value: 112.788635 - inSlope: -112788.63 - outSlope: -6740.78 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.016732283 - value: 59.76471 - inSlope: -6740.78 - outSlope: -2429.6155 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.024598425 - value: 40.653008 - inSlope: -2429.6155 - outSlope: -1252.2269 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.032464568 - value: 30.802813 - inSlope: -1252.2269 - outSlope: -763.7558 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.040330708 - value: 24.795002 - inSlope: -763.7558 - outSlope: -514.45264 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.04819685 - value: 20.748245 - inSlope: -514.45264 - outSlope: -370.0882 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.056062993 - value: 17.837078 - inSlope: -370.0882 - outSlope: -279.01324 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.06392913 - value: 15.642321 - inSlope: -279.01324 - outSlope: -217.87398 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.07179528 - value: 13.928493 - inSlope: -217.87398 - outSlope: -174.8461 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.079661414 - value: 12.553129 - inSlope: -174.8461 - outSlope: -143.41913 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.087527566 - value: 11.424973 - inSlope: -143.41913 - outSlope: -119.76661 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.0953937 - value: 10.482872 - inSlope: -119.76661 - outSlope: -101.519356 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.10325985 - value: 9.684306 - inSlope: -101.519356 - outSlope: -87.14706 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.11112598 - value: 8.9987955 - inSlope: -87.14706 - outSlope: -75.62513 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.11899213 - value: 8.403917 - inSlope: -75.62513 - outSlope: -66.24654 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.12685826 - value: 7.882813 - inSlope: -66.24654 - outSlope: -58.510654 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.13472441 - value: 7.4225597 - inSlope: -58.510654 - outSlope: -52.055042 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.14259055 - value: 7.0130873 - inSlope: -52.055042 - outSlope: -46.612007 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.1504567 - value: 6.6464305 - inSlope: -46.612007 - outSlope: -41.98024 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.15832284 - value: 6.316208 - inSlope: -41.98024 - outSlope: -38.006134 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.16618897 - value: 6.0172467 - inSlope: -38.006134 - outSlope: -34.570965 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.17405513 - value: 5.745306 - inSlope: -34.570965 - outSlope: -31.581244 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.18192126 - value: 5.496884 - inSlope: -31.581244 - outSlope: -28.963417 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.1897874 - value: 5.2690535 - inSlope: -28.963417 - outSlope: -26.658009 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.19765353 - value: 5.059358 - inSlope: -26.658009 - outSlope: -24.617418 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.20551969 - value: 4.8657136 - inSlope: -24.617418 - outSlope: -22.802412 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.21338584 - value: 4.6863465 - inSlope: -22.802412 - outSlope: -21.181019 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.22125196 - value: 4.519734 - inSlope: -21.181019 - outSlope: -19.72667 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.22911811 - value: 4.364561 - inSlope: -19.72667 - outSlope: -18.417059 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.23698425 - value: 4.21969 - inSlope: -18.417059 - outSlope: -17.233776 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.2448504 - value: 4.0841265 - inSlope: -17.233776 - outSlope: -16.160883 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.25271654 - value: 3.9570026 - inSlope: -16.160883 - outSlope: -15.185221 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.2605827 - value: 3.8375535 - inSlope: -15.185221 - outSlope: -14.295299 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.2684488 - value: 3.725105 - inSlope: -14.295299 - outSlope: -13.481375 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.27631494 - value: 3.6190586 - inSlope: -13.481375 - outSlope: -12.735047 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.28418112 - value: 3.5188825 - inSlope: -12.735047 - outSlope: -12.04901 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.29204726 - value: 3.4241033 - inSlope: -12.04901 - outSlope: -11.416967 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.2999134 - value: 3.3342957 - inSlope: -11.416967 - outSlope: -10.8334 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.30777952 - value: 3.249079 - inSlope: -10.8334 - outSlope: -10.293426 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.31564566 - value: 3.1681094 - inSlope: -10.293426 - outSlope: -9.792865 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.3235118 - value: 3.0910773 - inSlope: -9.792865 - outSlope: -9.327949 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.33137795 - value: 3.0177023 - inSlope: -9.327949 - outSlope: -8.895375 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.33924407 - value: 2.9477303 - inSlope: -8.895375 - outSlope: -8.492224 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.34711024 - value: 2.880929 - inSlope: -8.492224 - outSlope: -8.115812 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.3549764 - value: 2.8170888 - inSlope: -8.115812 - outSlope: -7.76395 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.36284253 - value: 2.7560165 - inSlope: -7.76395 - outSlope: -7.434456 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.37070867 - value: 2.697536 - inSlope: -7.434456 - outSlope: -7.1255083 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.3785748 - value: 2.641486 - inSlope: -7.1255083 - outSlope: -6.8354197 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.38644093 - value: 2.5877175 - inSlope: -6.8354197 - outSlope: -6.562695 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.39430708 - value: 2.5360944 - inSlope: -6.562695 - outSlope: -6.305974 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.40217322 - value: 2.4864907 - inSlope: -6.305974 - outSlope: -6.064021 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4100394 - value: 2.43879 - inSlope: -6.064021 - outSlope: -5.835745 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4179055 - value: 2.3928854 - inSlope: -5.835745 - outSlope: -5.6201315 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.42577165 - value: 2.3486767 - inSlope: -5.6201315 - outSlope: -5.4162097 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4336378 - value: 2.306072 - inSlope: -5.4162097 - outSlope: -5.223229 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.44150394 - value: 2.2649853 - inSlope: -5.223229 - outSlope: -5.040342 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4493701 - value: 2.2253373 - inSlope: -5.040342 - outSlope: -4.8669295 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4572362 - value: 2.1870534 - inSlope: -4.8669295 - outSlope: -4.7023005 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.46510234 - value: 2.1500645 - inSlope: -4.7023005 - outSlope: -4.5458865 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.47296852 - value: 2.1143057 - inSlope: -4.5458865 - outSlope: -4.3971753 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.48083466 - value: 2.079717 - inSlope: -4.3971753 - outSlope: -4.2555995 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4887008 - value: 2.0462418 - inSlope: -4.2555995 - outSlope: -4.1207685 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.49656692 - value: 2.0138273 - inSlope: -4.1207685 - outSlope: -3.9922712 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5044331 - value: 1.9824234 - inSlope: -3.9922712 - outSlope: -3.8696532 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5122992 - value: 1.9519844 - inSlope: -3.8696532 - outSlope: -3.7526293 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5201653 - value: 1.9224657 - inSlope: -3.7526293 - outSlope: -3.6408176 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.52803147 - value: 1.8938265 - inSlope: -3.6408176 - outSlope: -3.5339315 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5358976 - value: 1.8660281 - inSlope: -3.5339315 - outSlope: -3.4316826 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.54376376 - value: 1.839034 - inSlope: -3.4316826 - outSlope: -3.3338284 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5516299 - value: 1.8128096 - inSlope: -3.3338284 - outSlope: -3.240066 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.55949605 - value: 1.7873228 - inSlope: -3.240066 - outSlope: -3.1502352 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.56736225 - value: 1.7625424 - inSlope: -3.1502352 - outSlope: -3.0640743 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5752284 - value: 1.7384399 - inSlope: -3.0640743 - outSlope: -2.9814053 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.58309454 - value: 1.7149878 - inSlope: -2.9814053 - outSlope: -2.9020314 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5909606 - value: 1.6921601 - inSlope: -2.9020314 - outSlope: -2.8257964 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.59882677 - value: 1.669932 - inSlope: -2.8257964 - outSlope: -2.7525082 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6066929 - value: 1.6482804 - inSlope: -2.7525082 - outSlope: -2.6820538 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.61455905 - value: 1.627183 - inSlope: -2.6820538 - outSlope: -2.6142666 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6224252 - value: 1.6066188 - inSlope: -2.6142666 - outSlope: -2.5490105 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.63029134 - value: 1.5865679 - inSlope: -2.5490105 - outSlope: -2.4861636 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6381575 - value: 1.5670114 - inSlope: -2.4861636 - outSlope: -2.4256358 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.64602363 - value: 1.547931 - inSlope: -2.4256358 - outSlope: -2.3672597 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6538898 - value: 1.5293097 - inSlope: -2.3672597 - outSlope: -2.3109925 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.66175586 - value: 1.5111313 - inSlope: -2.3109925 - outSlope: -2.2566907 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.669622 - value: 1.4933798 - inSlope: -2.2566907 - outSlope: -2.2042859 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.67748815 - value: 1.4760406 - inSlope: -2.2042859 - outSlope: -2.1536992 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6853543 - value: 1.4590993 - inSlope: -2.1536992 - outSlope: -2.1048093 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6932205 - value: 1.4425424 - inSlope: -2.1048093 - outSlope: -2.0575728 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.70108664 - value: 1.4263573 - inSlope: -2.0575728 - outSlope: -2.011927 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7089528 - value: 1.4105312 - inSlope: -2.011927 - outSlope: -1.9677659 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7168189 - value: 1.3950524 - inSlope: -1.9677659 - outSlope: -1.9250447 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7246851 - value: 1.3799098 - inSlope: -1.9250447 - outSlope: -1.8837026 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7325512 - value: 1.3650923 - inSlope: -1.8837026 - outSlope: -1.8436778 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7404173 - value: 1.3505898 - inSlope: -1.8436778 - outSlope: -1.8049132 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.74828345 - value: 1.336392 - inSlope: -1.8049132 - outSlope: -1.7673749 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7561496 - value: 1.3224896 - inSlope: -1.7673749 - outSlope: -1.7309732 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.76401573 - value: 1.3088735 - inSlope: -1.7309732 - outSlope: -1.695693 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7718819 - value: 1.295535 - inSlope: -1.695693 - outSlope: -1.6614736 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.779748 - value: 1.2824656 - inSlope: -1.6614736 - outSlope: -1.6282848 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.78761417 - value: 1.2696573 - inSlope: -1.6282848 - outSlope: -1.5960962 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7954803 - value: 1.2571021 - inSlope: -1.5960962 - outSlope: -1.564832 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.80334646 - value: 1.2447929 - inSlope: -1.564832 - outSlope: -1.5344887 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.81121254 - value: 1.2327225 - inSlope: -1.5344887 - outSlope: -1.5050048 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.81907874 - value: 1.2208838 - inSlope: -1.5050048 - outSlope: -1.4763738 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8269449 - value: 1.2092705 - inSlope: -1.4763738 - outSlope: -1.4485649 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.83481103 - value: 1.1978759 - inSlope: -1.4485649 - outSlope: -1.4215137 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8426772 - value: 1.186694 - inSlope: -1.4215137 - outSlope: -1.3952202 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8505433 - value: 1.175719 - inSlope: -1.3952202 - outSlope: -1.369639 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.85840946 - value: 1.1649452 - inSlope: -1.369639 - outSlope: -1.3447852 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8662756 - value: 1.154367 - inSlope: -1.3447852 - outSlope: -1.320568 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.87414175 - value: 1.1439792 - inSlope: -1.320568 - outSlope: -1.2970176 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8820079 - value: 1.1337767 - inSlope: -1.2970176 - outSlope: -1.2740829 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.889874 - value: 1.1237546 - inSlope: -1.2740829 - outSlope: -1.2517655 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8977401 - value: 1.113908 - inSlope: -1.2517655 - outSlope: -1.2300034 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.90560627 - value: 1.1042327 - inSlope: -1.2300034 - outSlope: -1.2088321 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9134724 - value: 1.0947238 - inSlope: -1.2088321 - outSlope: -1.1881914 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.92133856 - value: 1.0853773 - inSlope: -1.1881914 - outSlope: -1.1680659 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9292047 - value: 1.0761892 - inSlope: -1.1680659 - outSlope: -1.1484709 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.93707085 - value: 1.0671551 - inSlope: -1.1484709 - outSlope: -1.1293371 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.94493705 - value: 1.0582715 - inSlope: -1.1293371 - outSlope: -1.1106901 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9528032 - value: 1.0495347 - inSlope: -1.1106901 - outSlope: -1.0925045 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.96066934 - value: 1.0409409 - inSlope: -1.0925045 - outSlope: -1.0747513 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9685354 - value: 1.0324868 - inSlope: -1.0747513 - outSlope: -1.0574516 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.97640157 - value: 1.0241687 - inSlope: -1.0574516 - outSlope: -1.0405389 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9842677 - value: 1.0159837 - inSlope: -1.0405389 - outSlope: -1.0240355 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.99213386 - value: 1.0079285 - inSlope: -1.0240355 - outSlope: -1.0079259 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1 - value: 1 - inSlope: -1.0079259 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 100 - average: 0 - inverse: 0 - exponent: 1 - - id: -1391520368 - _name: Inverse Boid C - _synapses: [] - _receivers: [] - nucleusType: - _curvePreset: 3 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0.001 - value: 999.99994 - inSlope: 0 - outSlope: -112788.63 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.008866142 - value: 112.788635 - inSlope: -112788.63 - outSlope: -6740.78 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.016732283 - value: 59.76471 - inSlope: -6740.78 - outSlope: -2429.6155 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.024598425 - value: 40.653008 - inSlope: -2429.6155 - outSlope: -1252.2269 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.032464568 - value: 30.802813 - inSlope: -1252.2269 - outSlope: -763.7558 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.040330708 - value: 24.795002 - inSlope: -763.7558 - outSlope: -514.45264 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.04819685 - value: 20.748245 - inSlope: -514.45264 - outSlope: -370.0882 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.056062993 - value: 17.837078 - inSlope: -370.0882 - outSlope: -279.01324 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.06392913 - value: 15.642321 - inSlope: -279.01324 - outSlope: -217.87398 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.07179528 - value: 13.928493 - inSlope: -217.87398 - outSlope: -174.8461 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.079661414 - value: 12.553129 - inSlope: -174.8461 - outSlope: -143.41913 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.087527566 - value: 11.424973 - inSlope: -143.41913 - outSlope: -119.76661 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.0953937 - value: 10.482872 - inSlope: -119.76661 - outSlope: -101.519356 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.10325985 - value: 9.684306 - inSlope: -101.519356 - outSlope: -87.14706 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.11112598 - value: 8.9987955 - inSlope: -87.14706 - outSlope: -75.62513 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.11899213 - value: 8.403917 - inSlope: -75.62513 - outSlope: -66.24654 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.12685826 - value: 7.882813 - inSlope: -66.24654 - outSlope: -58.510654 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.13472441 - value: 7.4225597 - inSlope: -58.510654 - outSlope: -52.055042 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.14259055 - value: 7.0130873 - inSlope: -52.055042 - outSlope: -46.612007 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.1504567 - value: 6.6464305 - inSlope: -46.612007 - outSlope: -41.98024 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.15832284 - value: 6.316208 - inSlope: -41.98024 - outSlope: -38.006134 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.16618897 - value: 6.0172467 - inSlope: -38.006134 - outSlope: -34.570965 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.17405513 - value: 5.745306 - inSlope: -34.570965 - outSlope: -31.581244 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.18192126 - value: 5.496884 - inSlope: -31.581244 - outSlope: -28.963417 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.1897874 - value: 5.2690535 - inSlope: -28.963417 - outSlope: -26.658009 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.19765353 - value: 5.059358 - inSlope: -26.658009 - outSlope: -24.617418 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.20551969 - value: 4.8657136 - inSlope: -24.617418 - outSlope: -22.802412 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.21338584 - value: 4.6863465 - inSlope: -22.802412 - outSlope: -21.181019 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.22125196 - value: 4.519734 - inSlope: -21.181019 - outSlope: -19.72667 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.22911811 - value: 4.364561 - inSlope: -19.72667 - outSlope: -18.417059 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.23698425 - value: 4.21969 - inSlope: -18.417059 - outSlope: -17.233776 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.2448504 - value: 4.0841265 - inSlope: -17.233776 - outSlope: -16.160883 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.25271654 - value: 3.9570026 - inSlope: -16.160883 - outSlope: -15.185221 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.2605827 - value: 3.8375535 - inSlope: -15.185221 - outSlope: -14.295299 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.2684488 - value: 3.725105 - inSlope: -14.295299 - outSlope: -13.481375 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.27631494 - value: 3.6190586 - inSlope: -13.481375 - outSlope: -12.735047 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.28418112 - value: 3.5188825 - inSlope: -12.735047 - outSlope: -12.04901 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.29204726 - value: 3.4241033 - inSlope: -12.04901 - outSlope: -11.416967 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.2999134 - value: 3.3342957 - inSlope: -11.416967 - outSlope: -10.8334 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.30777952 - value: 3.249079 - inSlope: -10.8334 - outSlope: -10.293426 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.31564566 - value: 3.1681094 - inSlope: -10.293426 - outSlope: -9.792865 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.3235118 - value: 3.0910773 - inSlope: -9.792865 - outSlope: -9.327949 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.33137795 - value: 3.0177023 - inSlope: -9.327949 - outSlope: -8.895375 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.33924407 - value: 2.9477303 - inSlope: -8.895375 - outSlope: -8.492224 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.34711024 - value: 2.880929 - inSlope: -8.492224 - outSlope: -8.115812 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.3549764 - value: 2.8170888 - inSlope: -8.115812 - outSlope: -7.76395 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.36284253 - value: 2.7560165 - inSlope: -7.76395 - outSlope: -7.434456 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.37070867 - value: 2.697536 - inSlope: -7.434456 - outSlope: -7.1255083 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.3785748 - value: 2.641486 - inSlope: -7.1255083 - outSlope: -6.8354197 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.38644093 - value: 2.5877175 - inSlope: -6.8354197 - outSlope: -6.562695 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.39430708 - value: 2.5360944 - inSlope: -6.562695 - outSlope: -6.305974 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.40217322 - value: 2.4864907 - inSlope: -6.305974 - outSlope: -6.064021 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4100394 - value: 2.43879 - inSlope: -6.064021 - outSlope: -5.835745 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4179055 - value: 2.3928854 - inSlope: -5.835745 - outSlope: -5.6201315 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.42577165 - value: 2.3486767 - inSlope: -5.6201315 - outSlope: -5.4162097 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4336378 - value: 2.306072 - inSlope: -5.4162097 - outSlope: -5.223229 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.44150394 - value: 2.2649853 - inSlope: -5.223229 - outSlope: -5.040342 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4493701 - value: 2.2253373 - inSlope: -5.040342 - outSlope: -4.8669295 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4572362 - value: 2.1870534 - inSlope: -4.8669295 - outSlope: -4.7023005 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.46510234 - value: 2.1500645 - inSlope: -4.7023005 - outSlope: -4.5458865 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.47296852 - value: 2.1143057 - inSlope: -4.5458865 - outSlope: -4.3971753 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.48083466 - value: 2.079717 - inSlope: -4.3971753 - outSlope: -4.2555995 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4887008 - value: 2.0462418 - inSlope: -4.2555995 - outSlope: -4.1207685 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.49656692 - value: 2.0138273 - inSlope: -4.1207685 - outSlope: -3.9922712 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5044331 - value: 1.9824234 - inSlope: -3.9922712 - outSlope: -3.8696532 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5122992 - value: 1.9519844 - inSlope: -3.8696532 - outSlope: -3.7526293 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5201653 - value: 1.9224657 - inSlope: -3.7526293 - outSlope: -3.6408176 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.52803147 - value: 1.8938265 - inSlope: -3.6408176 - outSlope: -3.5339315 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5358976 - value: 1.8660281 - inSlope: -3.5339315 - outSlope: -3.4316826 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.54376376 - value: 1.839034 - inSlope: -3.4316826 - outSlope: -3.3338284 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5516299 - value: 1.8128096 - inSlope: -3.3338284 - outSlope: -3.240066 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.55949605 - value: 1.7873228 - inSlope: -3.240066 - outSlope: -3.1502352 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.56736225 - value: 1.7625424 - inSlope: -3.1502352 - outSlope: -3.0640743 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5752284 - value: 1.7384399 - inSlope: -3.0640743 - outSlope: -2.9814053 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.58309454 - value: 1.7149878 - inSlope: -2.9814053 - outSlope: -2.9020314 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5909606 - value: 1.6921601 - inSlope: -2.9020314 - outSlope: -2.8257964 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.59882677 - value: 1.669932 - inSlope: -2.8257964 - outSlope: -2.7525082 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6066929 - value: 1.6482804 - inSlope: -2.7525082 - outSlope: -2.6820538 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.61455905 - value: 1.627183 - inSlope: -2.6820538 - outSlope: -2.6142666 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6224252 - value: 1.6066188 - inSlope: -2.6142666 - outSlope: -2.5490105 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.63029134 - value: 1.5865679 - inSlope: -2.5490105 - outSlope: -2.4861636 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6381575 - value: 1.5670114 - inSlope: -2.4861636 - outSlope: -2.4256358 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.64602363 - value: 1.547931 - inSlope: -2.4256358 - outSlope: -2.3672597 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6538898 - value: 1.5293097 - inSlope: -2.3672597 - outSlope: -2.3109925 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.66175586 - value: 1.5111313 - inSlope: -2.3109925 - outSlope: -2.2566907 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.669622 - value: 1.4933798 - inSlope: -2.2566907 - outSlope: -2.2042859 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.67748815 - value: 1.4760406 - inSlope: -2.2042859 - outSlope: -2.1536992 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6853543 - value: 1.4590993 - inSlope: -2.1536992 - outSlope: -2.1048093 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6932205 - value: 1.4425424 - inSlope: -2.1048093 - outSlope: -2.0575728 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.70108664 - value: 1.4263573 - inSlope: -2.0575728 - outSlope: -2.011927 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7089528 - value: 1.4105312 - inSlope: -2.011927 - outSlope: -1.9677659 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7168189 - value: 1.3950524 - inSlope: -1.9677659 - outSlope: -1.9250447 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7246851 - value: 1.3799098 - inSlope: -1.9250447 - outSlope: -1.8837026 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7325512 - value: 1.3650923 - inSlope: -1.8837026 - outSlope: -1.8436778 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7404173 - value: 1.3505898 - inSlope: -1.8436778 - outSlope: -1.8049132 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.74828345 - value: 1.336392 - inSlope: -1.8049132 - outSlope: -1.7673749 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7561496 - value: 1.3224896 - inSlope: -1.7673749 - outSlope: -1.7309732 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.76401573 - value: 1.3088735 - inSlope: -1.7309732 - outSlope: -1.695693 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7718819 - value: 1.295535 - inSlope: -1.695693 - outSlope: -1.6614736 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.779748 - value: 1.2824656 - inSlope: -1.6614736 - outSlope: -1.6282848 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.78761417 - value: 1.2696573 - inSlope: -1.6282848 - outSlope: -1.5960962 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7954803 - value: 1.2571021 - inSlope: -1.5960962 - outSlope: -1.564832 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.80334646 - value: 1.2447929 - inSlope: -1.564832 - outSlope: -1.5344887 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.81121254 - value: 1.2327225 - inSlope: -1.5344887 - outSlope: -1.5050048 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.81907874 - value: 1.2208838 - inSlope: -1.5050048 - outSlope: -1.4763738 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8269449 - value: 1.2092705 - inSlope: -1.4763738 - outSlope: -1.4485649 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.83481103 - value: 1.1978759 - inSlope: -1.4485649 - outSlope: -1.4215137 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8426772 - value: 1.186694 - inSlope: -1.4215137 - outSlope: -1.3952202 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8505433 - value: 1.175719 - inSlope: -1.3952202 - outSlope: -1.369639 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.85840946 - value: 1.1649452 - inSlope: -1.369639 - outSlope: -1.3447852 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8662756 - value: 1.154367 - inSlope: -1.3447852 - outSlope: -1.320568 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.87414175 - value: 1.1439792 - inSlope: -1.320568 - outSlope: -1.2970176 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8820079 - value: 1.1337767 - inSlope: -1.2970176 - outSlope: -1.2740829 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.889874 - value: 1.1237546 - inSlope: -1.2740829 - outSlope: -1.2517655 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8977401 - value: 1.113908 - inSlope: -1.2517655 - outSlope: -1.2300034 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.90560627 - value: 1.1042327 - inSlope: -1.2300034 - outSlope: -1.2088321 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9134724 - value: 1.0947238 - inSlope: -1.2088321 - outSlope: -1.1881914 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.92133856 - value: 1.0853773 - inSlope: -1.1881914 - outSlope: -1.1680659 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9292047 - value: 1.0761892 - inSlope: -1.1680659 - outSlope: -1.1484709 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.93707085 - value: 1.0671551 - inSlope: -1.1484709 - outSlope: -1.1293371 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.94493705 - value: 1.0582715 - inSlope: -1.1293371 - outSlope: -1.1106901 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9528032 - value: 1.0495347 - inSlope: -1.1106901 - outSlope: -1.0925045 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.96066934 - value: 1.0409409 - inSlope: -1.0925045 - outSlope: -1.0747513 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9685354 - value: 1.0324868 - inSlope: -1.0747513 - outSlope: -1.0574516 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.97640157 - value: 1.0241687 - inSlope: -1.0574516 - outSlope: -1.0405389 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9842677 - value: 1.0159837 - inSlope: -1.0405389 - outSlope: -1.0240355 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.99213386 - value: 1.0079285 - inSlope: -1.0240355 - outSlope: -1.0079259 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1 - value: 1 - inSlope: -1.0079259 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 100 - average: 0 - inverse: 0 - exponent: 1 - - id: 763145504 - _name: Inverse Boid D - _synapses: [] - _receivers: [] - nucleusType: - _curvePreset: 3 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0.001 - value: 999.99994 - inSlope: 0 - outSlope: -112788.63 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.008866142 - value: 112.788635 - inSlope: -112788.63 - outSlope: -6740.78 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.016732283 - value: 59.76471 - inSlope: -6740.78 - outSlope: -2429.6155 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.024598425 - value: 40.653008 - inSlope: -2429.6155 - outSlope: -1252.2269 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.032464568 - value: 30.802813 - inSlope: -1252.2269 - outSlope: -763.7558 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.040330708 - value: 24.795002 - inSlope: -763.7558 - outSlope: -514.45264 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.04819685 - value: 20.748245 - inSlope: -514.45264 - outSlope: -370.0882 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.056062993 - value: 17.837078 - inSlope: -370.0882 - outSlope: -279.01324 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.06392913 - value: 15.642321 - inSlope: -279.01324 - outSlope: -217.87398 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.07179528 - value: 13.928493 - inSlope: -217.87398 - outSlope: -174.8461 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.079661414 - value: 12.553129 - inSlope: -174.8461 - outSlope: -143.41913 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.087527566 - value: 11.424973 - inSlope: -143.41913 - outSlope: -119.76661 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.0953937 - value: 10.482872 - inSlope: -119.76661 - outSlope: -101.519356 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.10325985 - value: 9.684306 - inSlope: -101.519356 - outSlope: -87.14706 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.11112598 - value: 8.9987955 - inSlope: -87.14706 - outSlope: -75.62513 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.11899213 - value: 8.403917 - inSlope: -75.62513 - outSlope: -66.24654 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.12685826 - value: 7.882813 - inSlope: -66.24654 - outSlope: -58.510654 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.13472441 - value: 7.4225597 - inSlope: -58.510654 - outSlope: -52.055042 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.14259055 - value: 7.0130873 - inSlope: -52.055042 - outSlope: -46.612007 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.1504567 - value: 6.6464305 - inSlope: -46.612007 - outSlope: -41.98024 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.15832284 - value: 6.316208 - inSlope: -41.98024 - outSlope: -38.006134 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.16618897 - value: 6.0172467 - inSlope: -38.006134 - outSlope: -34.570965 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.17405513 - value: 5.745306 - inSlope: -34.570965 - outSlope: -31.581244 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.18192126 - value: 5.496884 - inSlope: -31.581244 - outSlope: -28.963417 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.1897874 - value: 5.2690535 - inSlope: -28.963417 - outSlope: -26.658009 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.19765353 - value: 5.059358 - inSlope: -26.658009 - outSlope: -24.617418 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.20551969 - value: 4.8657136 - inSlope: -24.617418 - outSlope: -22.802412 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.21338584 - value: 4.6863465 - inSlope: -22.802412 - outSlope: -21.181019 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.22125196 - value: 4.519734 - inSlope: -21.181019 - outSlope: -19.72667 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.22911811 - value: 4.364561 - inSlope: -19.72667 - outSlope: -18.417059 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.23698425 - value: 4.21969 - inSlope: -18.417059 - outSlope: -17.233776 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.2448504 - value: 4.0841265 - inSlope: -17.233776 - outSlope: -16.160883 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.25271654 - value: 3.9570026 - inSlope: -16.160883 - outSlope: -15.185221 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.2605827 - value: 3.8375535 - inSlope: -15.185221 - outSlope: -14.295299 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.2684488 - value: 3.725105 - inSlope: -14.295299 - outSlope: -13.481375 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.27631494 - value: 3.6190586 - inSlope: -13.481375 - outSlope: -12.735047 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.28418112 - value: 3.5188825 - inSlope: -12.735047 - outSlope: -12.04901 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.29204726 - value: 3.4241033 - inSlope: -12.04901 - outSlope: -11.416967 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.2999134 - value: 3.3342957 - inSlope: -11.416967 - outSlope: -10.8334 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.30777952 - value: 3.249079 - inSlope: -10.8334 - outSlope: -10.293426 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.31564566 - value: 3.1681094 - inSlope: -10.293426 - outSlope: -9.792865 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.3235118 - value: 3.0910773 - inSlope: -9.792865 - outSlope: -9.327949 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.33137795 - value: 3.0177023 - inSlope: -9.327949 - outSlope: -8.895375 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.33924407 - value: 2.9477303 - inSlope: -8.895375 - outSlope: -8.492224 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.34711024 - value: 2.880929 - inSlope: -8.492224 - outSlope: -8.115812 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.3549764 - value: 2.8170888 - inSlope: -8.115812 - outSlope: -7.76395 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.36284253 - value: 2.7560165 - inSlope: -7.76395 - outSlope: -7.434456 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.37070867 - value: 2.697536 - inSlope: -7.434456 - outSlope: -7.1255083 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.3785748 - value: 2.641486 - inSlope: -7.1255083 - outSlope: -6.8354197 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.38644093 - value: 2.5877175 - inSlope: -6.8354197 - outSlope: -6.562695 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.39430708 - value: 2.5360944 - inSlope: -6.562695 - outSlope: -6.305974 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.40217322 - value: 2.4864907 - inSlope: -6.305974 - outSlope: -6.064021 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4100394 - value: 2.43879 - inSlope: -6.064021 - outSlope: -5.835745 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4179055 - value: 2.3928854 - inSlope: -5.835745 - outSlope: -5.6201315 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.42577165 - value: 2.3486767 - inSlope: -5.6201315 - outSlope: -5.4162097 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4336378 - value: 2.306072 - inSlope: -5.4162097 - outSlope: -5.223229 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.44150394 - value: 2.2649853 - inSlope: -5.223229 - outSlope: -5.040342 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4493701 - value: 2.2253373 - inSlope: -5.040342 - outSlope: -4.8669295 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4572362 - value: 2.1870534 - inSlope: -4.8669295 - outSlope: -4.7023005 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.46510234 - value: 2.1500645 - inSlope: -4.7023005 - outSlope: -4.5458865 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.47296852 - value: 2.1143057 - inSlope: -4.5458865 - outSlope: -4.3971753 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.48083466 - value: 2.079717 - inSlope: -4.3971753 - outSlope: -4.2555995 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4887008 - value: 2.0462418 - inSlope: -4.2555995 - outSlope: -4.1207685 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.49656692 - value: 2.0138273 - inSlope: -4.1207685 - outSlope: -3.9922712 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5044331 - value: 1.9824234 - inSlope: -3.9922712 - outSlope: -3.8696532 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5122992 - value: 1.9519844 - inSlope: -3.8696532 - outSlope: -3.7526293 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5201653 - value: 1.9224657 - inSlope: -3.7526293 - outSlope: -3.6408176 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.52803147 - value: 1.8938265 - inSlope: -3.6408176 - outSlope: -3.5339315 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5358976 - value: 1.8660281 - inSlope: -3.5339315 - outSlope: -3.4316826 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.54376376 - value: 1.839034 - inSlope: -3.4316826 - outSlope: -3.3338284 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5516299 - value: 1.8128096 - inSlope: -3.3338284 - outSlope: -3.240066 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.55949605 - value: 1.7873228 - inSlope: -3.240066 - outSlope: -3.1502352 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.56736225 - value: 1.7625424 - inSlope: -3.1502352 - outSlope: -3.0640743 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5752284 - value: 1.7384399 - inSlope: -3.0640743 - outSlope: -2.9814053 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.58309454 - value: 1.7149878 - inSlope: -2.9814053 - outSlope: -2.9020314 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5909606 - value: 1.6921601 - inSlope: -2.9020314 - outSlope: -2.8257964 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.59882677 - value: 1.669932 - inSlope: -2.8257964 - outSlope: -2.7525082 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6066929 - value: 1.6482804 - inSlope: -2.7525082 - outSlope: -2.6820538 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.61455905 - value: 1.627183 - inSlope: -2.6820538 - outSlope: -2.6142666 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6224252 - value: 1.6066188 - inSlope: -2.6142666 - outSlope: -2.5490105 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.63029134 - value: 1.5865679 - inSlope: -2.5490105 - outSlope: -2.4861636 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6381575 - value: 1.5670114 - inSlope: -2.4861636 - outSlope: -2.4256358 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.64602363 - value: 1.547931 - inSlope: -2.4256358 - outSlope: -2.3672597 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6538898 - value: 1.5293097 - inSlope: -2.3672597 - outSlope: -2.3109925 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.66175586 - value: 1.5111313 - inSlope: -2.3109925 - outSlope: -2.2566907 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.669622 - value: 1.4933798 - inSlope: -2.2566907 - outSlope: -2.2042859 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.67748815 - value: 1.4760406 - inSlope: -2.2042859 - outSlope: -2.1536992 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6853543 - value: 1.4590993 - inSlope: -2.1536992 - outSlope: -2.1048093 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6932205 - value: 1.4425424 - inSlope: -2.1048093 - outSlope: -2.0575728 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.70108664 - value: 1.4263573 - inSlope: -2.0575728 - outSlope: -2.011927 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7089528 - value: 1.4105312 - inSlope: -2.011927 - outSlope: -1.9677659 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7168189 - value: 1.3950524 - inSlope: -1.9677659 - outSlope: -1.9250447 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7246851 - value: 1.3799098 - inSlope: -1.9250447 - outSlope: -1.8837026 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7325512 - value: 1.3650923 - inSlope: -1.8837026 - outSlope: -1.8436778 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7404173 - value: 1.3505898 - inSlope: -1.8436778 - outSlope: -1.8049132 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.74828345 - value: 1.336392 - inSlope: -1.8049132 - outSlope: -1.7673749 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7561496 - value: 1.3224896 - inSlope: -1.7673749 - outSlope: -1.7309732 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.76401573 - value: 1.3088735 - inSlope: -1.7309732 - outSlope: -1.695693 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7718819 - value: 1.295535 - inSlope: -1.695693 - outSlope: -1.6614736 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.779748 - value: 1.2824656 - inSlope: -1.6614736 - outSlope: -1.6282848 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.78761417 - value: 1.2696573 - inSlope: -1.6282848 - outSlope: -1.5960962 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7954803 - value: 1.2571021 - inSlope: -1.5960962 - outSlope: -1.564832 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.80334646 - value: 1.2447929 - inSlope: -1.564832 - outSlope: -1.5344887 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.81121254 - value: 1.2327225 - inSlope: -1.5344887 - outSlope: -1.5050048 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.81907874 - value: 1.2208838 - inSlope: -1.5050048 - outSlope: -1.4763738 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8269449 - value: 1.2092705 - inSlope: -1.4763738 - outSlope: -1.4485649 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.83481103 - value: 1.1978759 - inSlope: -1.4485649 - outSlope: -1.4215137 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8426772 - value: 1.186694 - inSlope: -1.4215137 - outSlope: -1.3952202 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8505433 - value: 1.175719 - inSlope: -1.3952202 - outSlope: -1.369639 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.85840946 - value: 1.1649452 - inSlope: -1.369639 - outSlope: -1.3447852 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8662756 - value: 1.154367 - inSlope: -1.3447852 - outSlope: -1.320568 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.87414175 - value: 1.1439792 - inSlope: -1.320568 - outSlope: -1.2970176 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8820079 - value: 1.1337767 - inSlope: -1.2970176 - outSlope: -1.2740829 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.889874 - value: 1.1237546 - inSlope: -1.2740829 - outSlope: -1.2517655 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8977401 - value: 1.113908 - inSlope: -1.2517655 - outSlope: -1.2300034 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.90560627 - value: 1.1042327 - inSlope: -1.2300034 - outSlope: -1.2088321 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9134724 - value: 1.0947238 - inSlope: -1.2088321 - outSlope: -1.1881914 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.92133856 - value: 1.0853773 - inSlope: -1.1881914 - outSlope: -1.1680659 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9292047 - value: 1.0761892 - inSlope: -1.1680659 - outSlope: -1.1484709 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.93707085 - value: 1.0671551 - inSlope: -1.1484709 - outSlope: -1.1293371 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.94493705 - value: 1.0582715 - inSlope: -1.1293371 - outSlope: -1.1106901 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9528032 - value: 1.0495347 - inSlope: -1.1106901 - outSlope: -1.0925045 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.96066934 - value: 1.0409409 - inSlope: -1.0925045 - outSlope: -1.0747513 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9685354 - value: 1.0324868 - inSlope: -1.0747513 - outSlope: -1.0574516 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.97640157 - value: 1.0241687 - inSlope: -1.0574516 - outSlope: -1.0405389 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9842677 - value: 1.0159837 - inSlope: -1.0405389 - outSlope: -1.0240355 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.99213386 - value: 1.0079285 - inSlope: -1.0240355 - outSlope: -1.0079259 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1 - value: 1 - inSlope: -1.0079259 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 100 - average: 0 - inverse: 0 - exponent: 1 - - id: 1469392160 - _name: Inverse Boid E - _synapses: [] - _receivers: [] - nucleusType: - _curvePreset: 3 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0.001 - value: 999.99994 - inSlope: 0 - outSlope: -112788.63 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.008866142 - value: 112.788635 - inSlope: -112788.63 - outSlope: -6740.78 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.016732283 - value: 59.76471 - inSlope: -6740.78 - outSlope: -2429.6155 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.024598425 - value: 40.653008 - inSlope: -2429.6155 - outSlope: -1252.2269 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.032464568 - value: 30.802813 - inSlope: -1252.2269 - outSlope: -763.7558 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.040330708 - value: 24.795002 - inSlope: -763.7558 - outSlope: -514.45264 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.04819685 - value: 20.748245 - inSlope: -514.45264 - outSlope: -370.0882 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.056062993 - value: 17.837078 - inSlope: -370.0882 - outSlope: -279.01324 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.06392913 - value: 15.642321 - inSlope: -279.01324 - outSlope: -217.87398 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.07179528 - value: 13.928493 - inSlope: -217.87398 - outSlope: -174.8461 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.079661414 - value: 12.553129 - inSlope: -174.8461 - outSlope: -143.41913 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.087527566 - value: 11.424973 - inSlope: -143.41913 - outSlope: -119.76661 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.0953937 - value: 10.482872 - inSlope: -119.76661 - outSlope: -101.519356 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.10325985 - value: 9.684306 - inSlope: -101.519356 - outSlope: -87.14706 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.11112598 - value: 8.9987955 - inSlope: -87.14706 - outSlope: -75.62513 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.11899213 - value: 8.403917 - inSlope: -75.62513 - outSlope: -66.24654 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.12685826 - value: 7.882813 - inSlope: -66.24654 - outSlope: -58.510654 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.13472441 - value: 7.4225597 - inSlope: -58.510654 - outSlope: -52.055042 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.14259055 - value: 7.0130873 - inSlope: -52.055042 - outSlope: -46.612007 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.1504567 - value: 6.6464305 - inSlope: -46.612007 - outSlope: -41.98024 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.15832284 - value: 6.316208 - inSlope: -41.98024 - outSlope: -38.006134 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.16618897 - value: 6.0172467 - inSlope: -38.006134 - outSlope: -34.570965 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.17405513 - value: 5.745306 - inSlope: -34.570965 - outSlope: -31.581244 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.18192126 - value: 5.496884 - inSlope: -31.581244 - outSlope: -28.963417 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.1897874 - value: 5.2690535 - inSlope: -28.963417 - outSlope: -26.658009 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.19765353 - value: 5.059358 - inSlope: -26.658009 - outSlope: -24.617418 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.20551969 - value: 4.8657136 - inSlope: -24.617418 - outSlope: -22.802412 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.21338584 - value: 4.6863465 - inSlope: -22.802412 - outSlope: -21.181019 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.22125196 - value: 4.519734 - inSlope: -21.181019 - outSlope: -19.72667 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.22911811 - value: 4.364561 - inSlope: -19.72667 - outSlope: -18.417059 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.23698425 - value: 4.21969 - inSlope: -18.417059 - outSlope: -17.233776 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.2448504 - value: 4.0841265 - inSlope: -17.233776 - outSlope: -16.160883 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.25271654 - value: 3.9570026 - inSlope: -16.160883 - outSlope: -15.185221 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.2605827 - value: 3.8375535 - inSlope: -15.185221 - outSlope: -14.295299 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.2684488 - value: 3.725105 - inSlope: -14.295299 - outSlope: -13.481375 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.27631494 - value: 3.6190586 - inSlope: -13.481375 - outSlope: -12.735047 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.28418112 - value: 3.5188825 - inSlope: -12.735047 - outSlope: -12.04901 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.29204726 - value: 3.4241033 - inSlope: -12.04901 - outSlope: -11.416967 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.2999134 - value: 3.3342957 - inSlope: -11.416967 - outSlope: -10.8334 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.30777952 - value: 3.249079 - inSlope: -10.8334 - outSlope: -10.293426 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.31564566 - value: 3.1681094 - inSlope: -10.293426 - outSlope: -9.792865 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.3235118 - value: 3.0910773 - inSlope: -9.792865 - outSlope: -9.327949 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.33137795 - value: 3.0177023 - inSlope: -9.327949 - outSlope: -8.895375 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.33924407 - value: 2.9477303 - inSlope: -8.895375 - outSlope: -8.492224 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.34711024 - value: 2.880929 - inSlope: -8.492224 - outSlope: -8.115812 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.3549764 - value: 2.8170888 - inSlope: -8.115812 - outSlope: -7.76395 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.36284253 - value: 2.7560165 - inSlope: -7.76395 - outSlope: -7.434456 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.37070867 - value: 2.697536 - inSlope: -7.434456 - outSlope: -7.1255083 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.3785748 - value: 2.641486 - inSlope: -7.1255083 - outSlope: -6.8354197 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.38644093 - value: 2.5877175 - inSlope: -6.8354197 - outSlope: -6.562695 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.39430708 - value: 2.5360944 - inSlope: -6.562695 - outSlope: -6.305974 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.40217322 - value: 2.4864907 - inSlope: -6.305974 - outSlope: -6.064021 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4100394 - value: 2.43879 - inSlope: -6.064021 - outSlope: -5.835745 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4179055 - value: 2.3928854 - inSlope: -5.835745 - outSlope: -5.6201315 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.42577165 - value: 2.3486767 - inSlope: -5.6201315 - outSlope: -5.4162097 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4336378 - value: 2.306072 - inSlope: -5.4162097 - outSlope: -5.223229 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.44150394 - value: 2.2649853 - inSlope: -5.223229 - outSlope: -5.040342 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4493701 - value: 2.2253373 - inSlope: -5.040342 - outSlope: -4.8669295 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4572362 - value: 2.1870534 - inSlope: -4.8669295 - outSlope: -4.7023005 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.46510234 - value: 2.1500645 - inSlope: -4.7023005 - outSlope: -4.5458865 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.47296852 - value: 2.1143057 - inSlope: -4.5458865 - outSlope: -4.3971753 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.48083466 - value: 2.079717 - inSlope: -4.3971753 - outSlope: -4.2555995 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4887008 - value: 2.0462418 - inSlope: -4.2555995 - outSlope: -4.1207685 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.49656692 - value: 2.0138273 - inSlope: -4.1207685 - outSlope: -3.9922712 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5044331 - value: 1.9824234 - inSlope: -3.9922712 - outSlope: -3.8696532 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5122992 - value: 1.9519844 - inSlope: -3.8696532 - outSlope: -3.7526293 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5201653 - value: 1.9224657 - inSlope: -3.7526293 - outSlope: -3.6408176 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.52803147 - value: 1.8938265 - inSlope: -3.6408176 - outSlope: -3.5339315 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5358976 - value: 1.8660281 - inSlope: -3.5339315 - outSlope: -3.4316826 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.54376376 - value: 1.839034 - inSlope: -3.4316826 - outSlope: -3.3338284 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5516299 - value: 1.8128096 - inSlope: -3.3338284 - outSlope: -3.240066 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.55949605 - value: 1.7873228 - inSlope: -3.240066 - outSlope: -3.1502352 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.56736225 - value: 1.7625424 - inSlope: -3.1502352 - outSlope: -3.0640743 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5752284 - value: 1.7384399 - inSlope: -3.0640743 - outSlope: -2.9814053 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.58309454 - value: 1.7149878 - inSlope: -2.9814053 - outSlope: -2.9020314 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5909606 - value: 1.6921601 - inSlope: -2.9020314 - outSlope: -2.8257964 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.59882677 - value: 1.669932 - inSlope: -2.8257964 - outSlope: -2.7525082 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6066929 - value: 1.6482804 - inSlope: -2.7525082 - outSlope: -2.6820538 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.61455905 - value: 1.627183 - inSlope: -2.6820538 - outSlope: -2.6142666 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6224252 - value: 1.6066188 - inSlope: -2.6142666 - outSlope: -2.5490105 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.63029134 - value: 1.5865679 - inSlope: -2.5490105 - outSlope: -2.4861636 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6381575 - value: 1.5670114 - inSlope: -2.4861636 - outSlope: -2.4256358 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.64602363 - value: 1.547931 - inSlope: -2.4256358 - outSlope: -2.3672597 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6538898 - value: 1.5293097 - inSlope: -2.3672597 - outSlope: -2.3109925 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.66175586 - value: 1.5111313 - inSlope: -2.3109925 - outSlope: -2.2566907 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.669622 - value: 1.4933798 - inSlope: -2.2566907 - outSlope: -2.2042859 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.67748815 - value: 1.4760406 - inSlope: -2.2042859 - outSlope: -2.1536992 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6853543 - value: 1.4590993 - inSlope: -2.1536992 - outSlope: -2.1048093 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6932205 - value: 1.4425424 - inSlope: -2.1048093 - outSlope: -2.0575728 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.70108664 - value: 1.4263573 - inSlope: -2.0575728 - outSlope: -2.011927 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7089528 - value: 1.4105312 - inSlope: -2.011927 - outSlope: -1.9677659 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7168189 - value: 1.3950524 - inSlope: -1.9677659 - outSlope: -1.9250447 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7246851 - value: 1.3799098 - inSlope: -1.9250447 - outSlope: -1.8837026 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7325512 - value: 1.3650923 - inSlope: -1.8837026 - outSlope: -1.8436778 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7404173 - value: 1.3505898 - inSlope: -1.8436778 - outSlope: -1.8049132 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.74828345 - value: 1.336392 - inSlope: -1.8049132 - outSlope: -1.7673749 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7561496 - value: 1.3224896 - inSlope: -1.7673749 - outSlope: -1.7309732 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.76401573 - value: 1.3088735 - inSlope: -1.7309732 - outSlope: -1.695693 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7718819 - value: 1.295535 - inSlope: -1.695693 - outSlope: -1.6614736 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.779748 - value: 1.2824656 - inSlope: -1.6614736 - outSlope: -1.6282848 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.78761417 - value: 1.2696573 - inSlope: -1.6282848 - outSlope: -1.5960962 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7954803 - value: 1.2571021 - inSlope: -1.5960962 - outSlope: -1.564832 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.80334646 - value: 1.2447929 - inSlope: -1.564832 - outSlope: -1.5344887 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.81121254 - value: 1.2327225 - inSlope: -1.5344887 - outSlope: -1.5050048 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.81907874 - value: 1.2208838 - inSlope: -1.5050048 - outSlope: -1.4763738 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8269449 - value: 1.2092705 - inSlope: -1.4763738 - outSlope: -1.4485649 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.83481103 - value: 1.1978759 - inSlope: -1.4485649 - outSlope: -1.4215137 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8426772 - value: 1.186694 - inSlope: -1.4215137 - outSlope: -1.3952202 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8505433 - value: 1.175719 - inSlope: -1.3952202 - outSlope: -1.369639 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.85840946 - value: 1.1649452 - inSlope: -1.369639 - outSlope: -1.3447852 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8662756 - value: 1.154367 - inSlope: -1.3447852 - outSlope: -1.320568 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.87414175 - value: 1.1439792 - inSlope: -1.320568 - outSlope: -1.2970176 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8820079 - value: 1.1337767 - inSlope: -1.2970176 - outSlope: -1.2740829 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.889874 - value: 1.1237546 - inSlope: -1.2740829 - outSlope: -1.2517655 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8977401 - value: 1.113908 - inSlope: -1.2517655 - outSlope: -1.2300034 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.90560627 - value: 1.1042327 - inSlope: -1.2300034 - outSlope: -1.2088321 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9134724 - value: 1.0947238 - inSlope: -1.2088321 - outSlope: -1.1881914 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.92133856 - value: 1.0853773 - inSlope: -1.1881914 - outSlope: -1.1680659 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9292047 - value: 1.0761892 - inSlope: -1.1680659 - outSlope: -1.1484709 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.93707085 - value: 1.0671551 - inSlope: -1.1484709 - outSlope: -1.1293371 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.94493705 - value: 1.0582715 - inSlope: -1.1293371 - outSlope: -1.1106901 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9528032 - value: 1.0495347 - inSlope: -1.1106901 - outSlope: -1.0925045 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.96066934 - value: 1.0409409 - inSlope: -1.0925045 - outSlope: -1.0747513 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9685354 - value: 1.0324868 - inSlope: -1.0747513 - outSlope: -1.0574516 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.97640157 - value: 1.0241687 - inSlope: -1.0574516 - outSlope: -1.0405389 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9842677 - value: 1.0159837 - inSlope: -1.0405389 - outSlope: -1.0240355 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.99213386 - value: 1.0079285 - inSlope: -1.0240355 - outSlope: -1.0079259 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1 - value: 1 - inSlope: -1.0079259 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 100 - average: 0 - inverse: 0 - exponent: 1 - - id: -1828317248 - _name: Inverse Bodi F - _synapses: [] - _receivers: [] - nucleusType: - _curvePreset: 3 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0.001 - value: 999.99994 - inSlope: 0 - outSlope: -112788.63 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.008866142 - value: 112.788635 - inSlope: -112788.63 - outSlope: -6740.78 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.016732283 - value: 59.76471 - inSlope: -6740.78 - outSlope: -2429.6155 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.024598425 - value: 40.653008 - inSlope: -2429.6155 - outSlope: -1252.2269 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.032464568 - value: 30.802813 - inSlope: -1252.2269 - outSlope: -763.7558 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.040330708 - value: 24.795002 - inSlope: -763.7558 - outSlope: -514.45264 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.04819685 - value: 20.748245 - inSlope: -514.45264 - outSlope: -370.0882 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.056062993 - value: 17.837078 - inSlope: -370.0882 - outSlope: -279.01324 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.06392913 - value: 15.642321 - inSlope: -279.01324 - outSlope: -217.87398 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.07179528 - value: 13.928493 - inSlope: -217.87398 - outSlope: -174.8461 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.079661414 - value: 12.553129 - inSlope: -174.8461 - outSlope: -143.41913 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.087527566 - value: 11.424973 - inSlope: -143.41913 - outSlope: -119.76661 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.0953937 - value: 10.482872 - inSlope: -119.76661 - outSlope: -101.519356 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.10325985 - value: 9.684306 - inSlope: -101.519356 - outSlope: -87.14706 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.11112598 - value: 8.9987955 - inSlope: -87.14706 - outSlope: -75.62513 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.11899213 - value: 8.403917 - inSlope: -75.62513 - outSlope: -66.24654 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.12685826 - value: 7.882813 - inSlope: -66.24654 - outSlope: -58.510654 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.13472441 - value: 7.4225597 - inSlope: -58.510654 - outSlope: -52.055042 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.14259055 - value: 7.0130873 - inSlope: -52.055042 - outSlope: -46.612007 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.1504567 - value: 6.6464305 - inSlope: -46.612007 - outSlope: -41.98024 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.15832284 - value: 6.316208 - inSlope: -41.98024 - outSlope: -38.006134 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.16618897 - value: 6.0172467 - inSlope: -38.006134 - outSlope: -34.570965 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.17405513 - value: 5.745306 - inSlope: -34.570965 - outSlope: -31.581244 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.18192126 - value: 5.496884 - inSlope: -31.581244 - outSlope: -28.963417 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.1897874 - value: 5.2690535 - inSlope: -28.963417 - outSlope: -26.658009 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.19765353 - value: 5.059358 - inSlope: -26.658009 - outSlope: -24.617418 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.20551969 - value: 4.8657136 - inSlope: -24.617418 - outSlope: -22.802412 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.21338584 - value: 4.6863465 - inSlope: -22.802412 - outSlope: -21.181019 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.22125196 - value: 4.519734 - inSlope: -21.181019 - outSlope: -19.72667 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.22911811 - value: 4.364561 - inSlope: -19.72667 - outSlope: -18.417059 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.23698425 - value: 4.21969 - inSlope: -18.417059 - outSlope: -17.233776 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.2448504 - value: 4.0841265 - inSlope: -17.233776 - outSlope: -16.160883 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.25271654 - value: 3.9570026 - inSlope: -16.160883 - outSlope: -15.185221 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.2605827 - value: 3.8375535 - inSlope: -15.185221 - outSlope: -14.295299 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.2684488 - value: 3.725105 - inSlope: -14.295299 - outSlope: -13.481375 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.27631494 - value: 3.6190586 - inSlope: -13.481375 - outSlope: -12.735047 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.28418112 - value: 3.5188825 - inSlope: -12.735047 - outSlope: -12.04901 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.29204726 - value: 3.4241033 - inSlope: -12.04901 - outSlope: -11.416967 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.2999134 - value: 3.3342957 - inSlope: -11.416967 - outSlope: -10.8334 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.30777952 - value: 3.249079 - inSlope: -10.8334 - outSlope: -10.293426 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.31564566 - value: 3.1681094 - inSlope: -10.293426 - outSlope: -9.792865 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.3235118 - value: 3.0910773 - inSlope: -9.792865 - outSlope: -9.327949 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.33137795 - value: 3.0177023 - inSlope: -9.327949 - outSlope: -8.895375 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.33924407 - value: 2.9477303 - inSlope: -8.895375 - outSlope: -8.492224 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.34711024 - value: 2.880929 - inSlope: -8.492224 - outSlope: -8.115812 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.3549764 - value: 2.8170888 - inSlope: -8.115812 - outSlope: -7.76395 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.36284253 - value: 2.7560165 - inSlope: -7.76395 - outSlope: -7.434456 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.37070867 - value: 2.697536 - inSlope: -7.434456 - outSlope: -7.1255083 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.3785748 - value: 2.641486 - inSlope: -7.1255083 - outSlope: -6.8354197 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.38644093 - value: 2.5877175 - inSlope: -6.8354197 - outSlope: -6.562695 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.39430708 - value: 2.5360944 - inSlope: -6.562695 - outSlope: -6.305974 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.40217322 - value: 2.4864907 - inSlope: -6.305974 - outSlope: -6.064021 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4100394 - value: 2.43879 - inSlope: -6.064021 - outSlope: -5.835745 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4179055 - value: 2.3928854 - inSlope: -5.835745 - outSlope: -5.6201315 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.42577165 - value: 2.3486767 - inSlope: -5.6201315 - outSlope: -5.4162097 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4336378 - value: 2.306072 - inSlope: -5.4162097 - outSlope: -5.223229 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.44150394 - value: 2.2649853 - inSlope: -5.223229 - outSlope: -5.040342 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4493701 - value: 2.2253373 - inSlope: -5.040342 - outSlope: -4.8669295 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4572362 - value: 2.1870534 - inSlope: -4.8669295 - outSlope: -4.7023005 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.46510234 - value: 2.1500645 - inSlope: -4.7023005 - outSlope: -4.5458865 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.47296852 - value: 2.1143057 - inSlope: -4.5458865 - outSlope: -4.3971753 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.48083466 - value: 2.079717 - inSlope: -4.3971753 - outSlope: -4.2555995 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.4887008 - value: 2.0462418 - inSlope: -4.2555995 - outSlope: -4.1207685 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.49656692 - value: 2.0138273 - inSlope: -4.1207685 - outSlope: -3.9922712 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5044331 - value: 1.9824234 - inSlope: -3.9922712 - outSlope: -3.8696532 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5122992 - value: 1.9519844 - inSlope: -3.8696532 - outSlope: -3.7526293 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5201653 - value: 1.9224657 - inSlope: -3.7526293 - outSlope: -3.6408176 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.52803147 - value: 1.8938265 - inSlope: -3.6408176 - outSlope: -3.5339315 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5358976 - value: 1.8660281 - inSlope: -3.5339315 - outSlope: -3.4316826 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.54376376 - value: 1.839034 - inSlope: -3.4316826 - outSlope: -3.3338284 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5516299 - value: 1.8128096 - inSlope: -3.3338284 - outSlope: -3.240066 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.55949605 - value: 1.7873228 - inSlope: -3.240066 - outSlope: -3.1502352 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.56736225 - value: 1.7625424 - inSlope: -3.1502352 - outSlope: -3.0640743 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5752284 - value: 1.7384399 - inSlope: -3.0640743 - outSlope: -2.9814053 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.58309454 - value: 1.7149878 - inSlope: -2.9814053 - outSlope: -2.9020314 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.5909606 - value: 1.6921601 - inSlope: -2.9020314 - outSlope: -2.8257964 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.59882677 - value: 1.669932 - inSlope: -2.8257964 - outSlope: -2.7525082 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6066929 - value: 1.6482804 - inSlope: -2.7525082 - outSlope: -2.6820538 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.61455905 - value: 1.627183 - inSlope: -2.6820538 - outSlope: -2.6142666 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6224252 - value: 1.6066188 - inSlope: -2.6142666 - outSlope: -2.5490105 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.63029134 - value: 1.5865679 - inSlope: -2.5490105 - outSlope: -2.4861636 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6381575 - value: 1.5670114 - inSlope: -2.4861636 - outSlope: -2.4256358 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.64602363 - value: 1.547931 - inSlope: -2.4256358 - outSlope: -2.3672597 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6538898 - value: 1.5293097 - inSlope: -2.3672597 - outSlope: -2.3109925 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.66175586 - value: 1.5111313 - inSlope: -2.3109925 - outSlope: -2.2566907 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.669622 - value: 1.4933798 - inSlope: -2.2566907 - outSlope: -2.2042859 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.67748815 - value: 1.4760406 - inSlope: -2.2042859 - outSlope: -2.1536992 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6853543 - value: 1.4590993 - inSlope: -2.1536992 - outSlope: -2.1048093 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.6932205 - value: 1.4425424 - inSlope: -2.1048093 - outSlope: -2.0575728 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.70108664 - value: 1.4263573 - inSlope: -2.0575728 - outSlope: -2.011927 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7089528 - value: 1.4105312 - inSlope: -2.011927 - outSlope: -1.9677659 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7168189 - value: 1.3950524 - inSlope: -1.9677659 - outSlope: -1.9250447 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7246851 - value: 1.3799098 - inSlope: -1.9250447 - outSlope: -1.8837026 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7325512 - value: 1.3650923 - inSlope: -1.8837026 - outSlope: -1.8436778 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7404173 - value: 1.3505898 - inSlope: -1.8436778 - outSlope: -1.8049132 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.74828345 - value: 1.336392 - inSlope: -1.8049132 - outSlope: -1.7673749 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7561496 - value: 1.3224896 - inSlope: -1.7673749 - outSlope: -1.7309732 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.76401573 - value: 1.3088735 - inSlope: -1.7309732 - outSlope: -1.695693 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7718819 - value: 1.295535 - inSlope: -1.695693 - outSlope: -1.6614736 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.779748 - value: 1.2824656 - inSlope: -1.6614736 - outSlope: -1.6282848 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.78761417 - value: 1.2696573 - inSlope: -1.6282848 - outSlope: -1.5960962 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.7954803 - value: 1.2571021 - inSlope: -1.5960962 - outSlope: -1.564832 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.80334646 - value: 1.2447929 - inSlope: -1.564832 - outSlope: -1.5344887 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.81121254 - value: 1.2327225 - inSlope: -1.5344887 - outSlope: -1.5050048 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.81907874 - value: 1.2208838 - inSlope: -1.5050048 - outSlope: -1.4763738 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8269449 - value: 1.2092705 - inSlope: -1.4763738 - outSlope: -1.4485649 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.83481103 - value: 1.1978759 - inSlope: -1.4485649 - outSlope: -1.4215137 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8426772 - value: 1.186694 - inSlope: -1.4215137 - outSlope: -1.3952202 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8505433 - value: 1.175719 - inSlope: -1.3952202 - outSlope: -1.369639 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.85840946 - value: 1.1649452 - inSlope: -1.369639 - outSlope: -1.3447852 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8662756 - value: 1.154367 - inSlope: -1.3447852 - outSlope: -1.320568 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.87414175 - value: 1.1439792 - inSlope: -1.320568 - outSlope: -1.2970176 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8820079 - value: 1.1337767 - inSlope: -1.2970176 - outSlope: -1.2740829 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.889874 - value: 1.1237546 - inSlope: -1.2740829 - outSlope: -1.2517655 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.8977401 - value: 1.113908 - inSlope: -1.2517655 - outSlope: -1.2300034 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.90560627 - value: 1.1042327 - inSlope: -1.2300034 - outSlope: -1.2088321 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9134724 - value: 1.0947238 - inSlope: -1.2088321 - outSlope: -1.1881914 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.92133856 - value: 1.0853773 - inSlope: -1.1881914 - outSlope: -1.1680659 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9292047 - value: 1.0761892 - inSlope: -1.1680659 - outSlope: -1.1484709 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.93707085 - value: 1.0671551 - inSlope: -1.1484709 - outSlope: -1.1293371 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.94493705 - value: 1.0582715 - inSlope: -1.1293371 - outSlope: -1.1106901 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9528032 - value: 1.0495347 - inSlope: -1.1106901 - outSlope: -1.0925045 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.96066934 - value: 1.0409409 - inSlope: -1.0925045 - outSlope: -1.0747513 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9685354 - value: 1.0324868 - inSlope: -1.0747513 - outSlope: -1.0574516 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.97640157 - value: 1.0241687 - inSlope: -1.0574516 - outSlope: -1.0405389 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.9842677 - value: 1.0159837 - inSlope: -1.0405389 - outSlope: -1.0240355 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.99213386 - value: 1.0079285 - inSlope: -1.0240355 - outSlope: -1.0079259 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1 - value: 1 - inSlope: -1.0079259 - outSlope: 0 - tangentMode: 69 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 100 - average: 0 - inverse: 0 - exponent: 1 - perceptei: - - id: 407735232 - _name: Boundary - _synapses: [] - _receivers: [] - nucleusType: Perceptoid - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 0 - average: 0 - inverse: 0 - exponent: 1 - brain: {fileID: 0} - baseName: Boundary - thingId: 0 - array: - rid: -2 - thingType: 1 - - id: -1659429232 - _name: BoidA - _synapses: [] - _receivers: [] - nucleusType: Perceptoid - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - brain: {fileID: 0} - baseName: BoidA - thingId: 0 - array: - rid: 2243600969536897085 - thingType: 2 - - id: 839544896 - _name: BoidB - _synapses: [] - _receivers: [] - nucleusType: Perceptoid - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - brain: {fileID: 0} - baseName: BoidB - thingId: 0 - array: - rid: 2243600969536897086 - thingType: 2 - - id: -348340288 - _name: BoidC - _synapses: [] - _receivers: [] - nucleusType: Perceptoid - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - brain: {fileID: 0} - baseName: BoidC - thingId: 0 - array: - rid: 2243600969536897087 - thingType: 2 - - id: -1095934288 - _name: BoidD - _synapses: [] - _receivers: [] - nucleusType: Perceptoid - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - brain: {fileID: 0} - baseName: BoidD - thingId: 0 - array: - rid: 2243600969536897088 - thingType: 2 - - id: -1413006832 - _name: BoidE - _synapses: [] - _receivers: [] - nucleusType: Perceptoid - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - brain: {fileID: 0} - baseName: BoidE - thingId: 0 - array: - rid: 2243600969536897089 - thingType: 2 - - id: -61245040 - _name: BoidF - _synapses: [] - _receivers: [] - nucleusType: Perceptoid - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - brain: {fileID: 0} - baseName: BoidF - thingId: 0 - array: - rid: 2243600969536897090 - thingType: 2 - - id: -1659687600 - _name: BoidA Velocity - _synapses: [] - _receivers: [] - nucleusType: Perceptoid - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - brain: {fileID: 0} - baseName: BoidA Velocity - thingId: 0 - array: - rid: -2 - thingType: 3 - - id: 1322333072 - _name: BoidB Velocity - _synapses: [] - _receivers: [] - nucleusType: Perceptoid - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - brain: {fileID: 0} - baseName: BoidB Velocity - thingId: 0 - array: - rid: -2 - thingType: 3 - - id: -1563920864 - _name: BoidC Velocity - _synapses: [] - _receivers: [] - nucleusType: Perceptoid - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - brain: {fileID: 0} - baseName: BoidC Velocity - thingId: 0 - array: - rid: -2 - thingType: 3 - - id: 182328688 - _name: BoidD Velocity - _synapses: [] - _receivers: [] - nucleusType: Perceptoid - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - brain: {fileID: 0} - baseName: BoidD Velocity - thingId: 0 - array: - rid: -2 - thingType: 3 - - id: -1666561744 - _name: BoidE Velocity - _synapses: [] - _receivers: [] - nucleusType: Perceptoid - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - brain: {fileID: 0} - baseName: BoidE Velocity - thingId: 0 - array: - rid: -2 - thingType: 3 - - id: -1884196224 - _name: BoidF Velocity - _synapses: [] - _receivers: [] - nucleusType: Perceptoid - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - brain: {fileID: 0} - baseName: BoidF Velocity - thingId: 0 - array: - rid: -2 - thingType: 3 - rootId: -1707533328 - cluster: {fileID: 0} - references: - version: 2 - RefIds: - - rid: -2 - type: {class: , ns: , asm: } - - rid: 2243600969536897085 - type: {class: PercepteiArray, ns: , asm: Assembly-CSharp} - data: - perceptei: - - rid: 2243600969536897091 - name: BoidA - - rid: 2243600969536897086 - type: {class: PercepteiArray, ns: , asm: Assembly-CSharp} - data: - perceptei: - - rid: 2243600969536897092 - name: BoidB - - rid: 2243600969536897087 - type: {class: PercepteiArray, ns: , asm: Assembly-CSharp} - data: - perceptei: - - rid: 2243600969536897093 - name: BoidC - - rid: 2243600969536897088 - type: {class: PercepteiArray, ns: , asm: Assembly-CSharp} - data: - perceptei: - - rid: 2243600969536897094 - name: BoidD - - rid: 2243600969536897089 - type: {class: PercepteiArray, ns: , asm: Assembly-CSharp} - data: - perceptei: - - rid: 2243600969536897095 - name: BoidE - - rid: 2243600969536897090 - type: {class: PercepteiArray, ns: , asm: Assembly-CSharp} - data: - perceptei: - - rid: 2243600969536897096 - name: BoidF - - rid: 2243600969536897091 - type: {class: Perceptoid, ns: , asm: Assembly-CSharp} - data: - id: -1659429232 - _name: BoidA - _synapses: [] - _receivers: [] - nucleusType: Perceptoid - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - brain: {fileID: 0} - baseName: BoidA - thingId: 0 - array: - rid: 2243600969536897085 - thingType: 2 - - rid: 2243600969536897092 - type: {class: Perceptoid, ns: , asm: Assembly-CSharp} - data: - id: 839544896 - _name: BoidB - _synapses: [] - _receivers: [] - nucleusType: Perceptoid - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - brain: {fileID: 0} - baseName: BoidB - thingId: 0 - array: - rid: 2243600969536897086 - thingType: 2 - - rid: 2243600969536897093 - type: {class: Perceptoid, ns: , asm: Assembly-CSharp} - data: - id: -348340288 - _name: BoidC - _synapses: [] - _receivers: [] - nucleusType: Perceptoid - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - brain: {fileID: 0} - baseName: BoidC - thingId: 0 - array: - rid: 2243600969536897087 - thingType: 2 - - rid: 2243600969536897094 - type: {class: Perceptoid, ns: , asm: Assembly-CSharp} - data: - id: -1095934288 - _name: BoidD - _synapses: [] - _receivers: [] - nucleusType: Perceptoid - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - brain: {fileID: 0} - baseName: BoidD - thingId: 0 - array: - rid: 2243600969536897088 - thingType: 2 - - rid: 2243600969536897095 - type: {class: Perceptoid, ns: , asm: Assembly-CSharp} - data: - id: -1413006832 - _name: BoidE - _synapses: [] - _receivers: [] - nucleusType: Perceptoid - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - brain: {fileID: 0} - baseName: BoidE - thingId: 0 - array: - rid: 2243600969536897089 - thingType: 2 - - rid: 2243600969536897096 - type: {class: Perceptoid, ns: , asm: Assembly-CSharp} - data: - id: -61245040 - _name: BoidF - _synapses: [] - _receivers: [] - nucleusType: Perceptoid - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - inverse: 0 - exponent: 1 - brain: {fileID: 0} - baseName: BoidF - thingId: 0 - array: - rid: 2243600969536897090 - thingType: 2 diff --git a/Assets/Scenes/Boids/SwarmingBrain.asset.meta b/Assets/Scenes/Boids/SwarmingBrain.asset.meta deleted file mode 100644 index a12ec48..0000000 --- a/Assets/Scenes/Boids/SwarmingBrain.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: fc1a4800a8c531eb4855b436bc9084ae -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: From 8b8e5fc33c1256d1ddf131342fa4ed90e4c4b6cb Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 21 Jan 2026 17:21:06 +0100 Subject: [PATCH 077/179] Starting with clusterinstance --- Assembly-CSharp.csproj | 1 + Assets/NanoBrain/ClusterInstance.cs | 74 ++++++++++++++++++++++++ Assets/NanoBrain/ClusterInstance.cs.meta | 2 + 3 files changed, 77 insertions(+) create mode 100644 Assets/NanoBrain/ClusterInstance.cs create mode 100644 Assets/NanoBrain/ClusterInstance.cs.meta diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index 4ac4a55..1f5f66b 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -73,6 +73,7 @@ + diff --git a/Assets/NanoBrain/ClusterInstance.cs b/Assets/NanoBrain/ClusterInstance.cs new file mode 100644 index 0000000..dd9c4c4 --- /dev/null +++ b/Assets/NanoBrain/ClusterInstance.cs @@ -0,0 +1,74 @@ +public class ClusterInstance { + // The ScriptableObject asset from which the runtime object has been created + public readonly Cluster asset; + + public ClusterInstance parent; + + public ClusterInstance(Cluster asset) { + this.asset = asset; + } + + public NucleusArray array; + + #region Synapses + + private Synapse[] _synapses = new Synapse[0]; + public Synapse[] synapses => _synapses; + + public void AddSynapse(IReceptor sendingNucleus) { + + } + + // Does this even exist already? + public void RemoveSynapse() { + + } + + #endregion Synapses + + #region Receivers + + private INucleus[] _nucleiReceivers = new INucleus[0]; + public INucleus[] nucleiReceivers => _nucleiReceivers; + + public void AddReceiver(INucleus receivingNucleus) { + int newLength = this._nucleiReceivers.Length + 1; + INucleus[] newReceivers = new INucleus[newLength]; + + // Copy the existing receivers + for (int ix = 0; ix < this._nucleiReceivers.Length; ix++) + newReceivers[ix] = this._nucleiReceivers[ix]; + // Add the new receivers + newReceivers[this._nucleiReceivers.Length] = receivingNucleus; + // Replace the receivers with the new receivers + this._nucleiReceivers = newReceivers; + } + + public void RemoveReceiver(INucleus receivingNucleus) { + int newLength = this._nucleiReceivers.Length - 1; + if (newLength < 0) + // Array was empty, so we cannot remove anything + return; + + INucleus[] newReceivers = new INucleus[newLength]; + + int newIx = 0; + // Copy all receivers except receivingNucleus + for (int ix = 0; ix < this._nucleiReceivers.Length; ix++) { + if (this._nucleiReceivers[ix] == receivingNucleus) + // skip the receiver we want to remote + continue; + + if (newIx >= newLength) + // We want to copy more elements than expected + // the receivingNucleus is not found + // and the original array is returned + return; + newReceivers[newIx] = this._nucleiReceivers[ix]; + newIx++; + } + this._nucleiReceivers = newReceivers; + } + + #endregion Receivers +} diff --git a/Assets/NanoBrain/ClusterInstance.cs.meta b/Assets/NanoBrain/ClusterInstance.cs.meta new file mode 100644 index 0000000..a10caff --- /dev/null +++ b/Assets/NanoBrain/ClusterInstance.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f13cdc4a175a9f379a00317ae68d8bea \ No newline at end of file From f0da7c9c9bc829b43a71af5590bfbab99cfe480a Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 21 Jan 2026 20:39:07 +0100 Subject: [PATCH 078/179] ClusterInstance is working a bit --- Assets/NanoBrain/Cluster.cs | 40 ++++---- Assets/NanoBrain/ClusterInstance.cs | 92 ++++++++++++++----- Assets/NanoBrain/INucleus.cs | 10 +- Assets/NanoBrain/Identity.asset | 1 + Assets/NanoBrain/Neuron.cs | 56 +++++------ Assets/NanoBrain/NucleusArray.cs | 10 +- Assets/NanoBrain/Receptor.cs | 22 ++--- Assets/NanoBrain/Synapse.cs | 15 +-- .../VisualEditor/Editor/ClusterInspector.cs | 29 +++--- Assets/Scenes/Boids/New Cluster.asset | 11 +-- 10 files changed, 168 insertions(+), 118 deletions(-) diff --git a/Assets/NanoBrain/Cluster.cs b/Assets/NanoBrain/Cluster.cs index f5c31c9..cae5110 100644 --- a/Assets/NanoBrain/Cluster.cs +++ b/Assets/NanoBrain/Cluster.cs @@ -4,7 +4,7 @@ using Unity.Mathematics; using static Unity.Mathematics.math; [CreateAssetMenu(menuName = "Passer/Cluster")] -public class Cluster : ScriptableObject, INucleus { +public class Cluster : ScriptableObject { public Cluster cluster => this; @@ -14,9 +14,9 @@ public class Cluster : ScriptableObject, INucleus { [SerializeReference] public List nuclei = new(); - public List subClusters = new(); - public void AddSubCluster(Cluster subCluster) { - this.subClusters.Add(subCluster); + // public List subClusters = new(); + public void AddSubCluster(ClusterInstance subCluster) { + this.nuclei.Add(subCluster); } public INucleus output => this.nuclei[0] as INucleus; @@ -45,19 +45,19 @@ public class Cluster : ScriptableObject, INucleus { get { return this.output.receivers; } set { this.output.receivers = value; } } - public List clusterReceivers { - get { return this.output.clusterReceivers; } - set { this.output.clusterReceivers = clusterReceivers; } - } - public IEnumerable allReceivers { - get => output.allReceivers; - } + // public List clusterReceivers { + // get { return this.output.clusterReceivers; } + // set { this.output.clusterReceivers = clusterReceivers; } + // } + // public IEnumerable allReceivers { + // get => output.allReceivers; + // } - public INucleus Clone() { - Cluster clone = CreateInstance(); - // Lots to add here... - return clone; - } + // public INucleus Clone() { + // Cluster clone = CreateInstance(); + // // Lots to add here... + // return clone; + // } // Call this function to ensure that there is at least one nucleus // This is an invariant and should be ensured before the nucleus is used @@ -67,7 +67,7 @@ public class Cluster : ScriptableObject, INucleus { if (nuclei.Count == 0) new Neuron(this, "Output"); // Every cluster should have at least 1 neuron } - +/* public void AddReceiver(INucleus receivingNucleus) { //output.AddReceiver(receiver); this.output.receivers.Add(receivingNucleus); @@ -92,7 +92,7 @@ public class Cluster : ScriptableObject, INucleus { synapses.Add(synapse); return synapse; } - +*/ public void GarbageCollection() { HashSet visitedNuclei = new(); MarkNuclei(visitedNuclei, this.output); @@ -117,9 +117,9 @@ public class Cluster : ScriptableObject, INucleus { } nucleus.synapses.RemoveAll(synapse => visitedSynapses.Contains(synapse) == false); } - if (nucleus.allReceivers != null) { + if (nucleus.receivers != null) { HashSet visitedReceivers = new(); - foreach (INucleus receiver in nucleus.allReceivers) { + foreach (INucleus receiver in nucleus.receivers) { if (receiver != null && receiver != null) { visitedReceivers.Add(receiver); visitedNuclei.Add(receiver); diff --git a/Assets/NanoBrain/ClusterInstance.cs b/Assets/NanoBrain/ClusterInstance.cs index dd9c4c4..e54254d 100644 --- a/Assets/NanoBrain/ClusterInstance.cs +++ b/Assets/NanoBrain/ClusterInstance.cs @@ -1,51 +1,90 @@ -public class ClusterInstance { - // The ScriptableObject asset from which the runtime object has been created - public readonly Cluster asset; +using System; +using System.Collections.Generic; +using UnityEngine; +using Unity.Mathematics; +using static Unity.Mathematics.math; - public ClusterInstance parent; +[System.Serializable] +public class ClusterInstance : INucleus { + // The ScriptableObject asset from which the runtime object has been created + public Cluster asset; + + public Cluster cluster => this.asset; + + public INucleus output => this.asset.nuclei[0] as INucleus; + public float3 outputValue => this.output.outputValue; public ClusterInstance(Cluster asset) { this.asset = asset; } - public NucleusArray array; + public INucleus Clone() { + ClusterInstance clone = new(this.asset); + return clone; + } + + #region Properties + + public string name { + get { return asset.name; } + set { asset.name = value; } + } + + public bool isSleeping => lengthsq(this.outputValue) == 0; + + public NucleusArray array { get; set; } + + #endregion Properties #region Synapses private Synapse[] _synapses = new Synapse[0]; - public Synapse[] synapses => _synapses; + public List synapses => new(_synapses); - public void AddSynapse(IReceptor sendingNucleus) { - + public Synapse AddSynapse(IReceptor sendingNucleus, string nucleusName = null) { + if (nucleusName == null) { + this.asset.inputs[0].AddSynapse(sendingNucleus); + } else { + INucleus receptor = (INucleus)this.asset.nuclei.Find(nucleus => nucleus is INucleus n && nucleus.name == nucleusName); + receptor.AddSynapse(sendingNucleus); + } + // Add synapse to which neuron? + return null; } // Does this even exist already? public void RemoveSynapse() { - + } #endregion Synapses #region Receivers - private INucleus[] _nucleiReceivers = new INucleus[0]; - public INucleus[] nucleiReceivers => _nucleiReceivers; + [SerializeReference] + private List _receivers = new(); + public List receivers { + get { return _receivers; } + set { _receivers = value; } + } public void AddReceiver(INucleus receivingNucleus) { - int newLength = this._nucleiReceivers.Length + 1; + int newLength = this._receivers.Count + 1; INucleus[] newReceivers = new INucleus[newLength]; // Copy the existing receivers - for (int ix = 0; ix < this._nucleiReceivers.Length; ix++) - newReceivers[ix] = this._nucleiReceivers[ix]; + for (int ix = 0; ix < this._receivers.Count; ix++) + newReceivers[ix] = this._receivers[ix]; // Add the new receivers - newReceivers[this._nucleiReceivers.Length] = receivingNucleus; + newReceivers[this._receivers.Count] = receivingNucleus; // Replace the receivers with the new receivers - this._nucleiReceivers = newReceivers; + this._receivers = new(newReceivers); + + receivingNucleus.AddSynapse(this); } public void RemoveReceiver(INucleus receivingNucleus) { - int newLength = this._nucleiReceivers.Length - 1; + int newLength = this._receivers.Count - 1; if (newLength < 0) // Array was empty, so we cannot remove anything return; @@ -54,8 +93,8 @@ public class ClusterInstance { int newIx = 0; // Copy all receivers except receivingNucleus - for (int ix = 0; ix < this._nucleiReceivers.Length; ix++) { - if (this._nucleiReceivers[ix] == receivingNucleus) + for (int ix = 0; ix < this._receivers.Count; ix++) { + if (this._receivers[ix] == receivingNucleus) // skip the receiver we want to remote continue; @@ -64,11 +103,22 @@ public class ClusterInstance { // the receivingNucleus is not found // and the original array is returned return; - newReceivers[newIx] = this._nucleiReceivers[ix]; + newReceivers[newIx] = this._receivers[ix]; newIx++; } - this._nucleiReceivers = newReceivers; + this._receivers = new(newReceivers); } #endregion Receivers + + #region Update + + public void UpdateState() { } + + public void UpdateNuclei() { + foreach (IReceptor nucleus in this.asset.nuclei) + nucleus.UpdateNuclei(); + } + + #endregion Update } diff --git a/Assets/NanoBrain/INucleus.cs b/Assets/NanoBrain/INucleus.cs index 19938ed..0dde236 100644 --- a/Assets/NanoBrain/INucleus.cs +++ b/Assets/NanoBrain/INucleus.cs @@ -10,8 +10,8 @@ public interface INucleus : IReceptor { // Senders public List synapses { get; } - public Synapse AddSynapse(IReceptor sender); - public Synapse AddClusterSynapse(Cluster clusterSender); + public Synapse AddSynapse(IReceptor sender, string nucleusName = null); + // public Synapse AddClusterSynapse(Cluster clusterSender); public NucleusArray array { get; set; } @@ -34,11 +34,11 @@ public interface IReceptor { // Receivers public List receivers { get; set; } - public List clusterReceivers { get; set; } - public IEnumerable allReceivers { get; } + // public List clusterReceivers { get; set; } + // public IEnumerable allReceivers { get; } public void AddReceiver(INucleus receiver); - public void AddClusterReceiver(Cluster clusterReceiver); + // public void AddClusterReceiver(Cluster clusterReceiver); public void RemoveReceiver(INucleus receiverNucleus); #endregion static diff --git a/Assets/NanoBrain/Identity.asset b/Assets/NanoBrain/Identity.asset index efe44e6..ea38020 100644 --- a/Assets/NanoBrain/Identity.asset +++ b/Assets/NanoBrain/Identity.asset @@ -12,6 +12,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3} m_Name: Identity m_EditorClassIdentifier: Assembly-CSharp::Cluster + asset: {fileID: 0} nuclei: - rid: 2243601242842202241 subClusters: [] diff --git a/Assets/NanoBrain/Neuron.cs b/Assets/NanoBrain/Neuron.cs index 2d5d5aa..b6e6a87 100644 --- a/Assets/NanoBrain/Neuron.cs +++ b/Assets/NanoBrain/Neuron.cs @@ -25,21 +25,21 @@ public class Neuron : INucleus { get { return _receivers; } set { _receivers = value; } } - private List _clusterReceivers = new(); - public List clusterReceivers { - get { return _clusterReceivers; } - set { _clusterReceivers = value; } - } - public IEnumerable allReceivers { //=> _receivers.Concat(_clusterReceivers); - get { - if (_receivers == null) - return _clusterReceivers; - else if (_clusterReceivers == null) - return _receivers; - else - return _receivers.Concat(_clusterReceivers); - } - } + // private List _clusterReceivers = new(); + // public List clusterReceivers { + // get { return _clusterReceivers; } + // set { _clusterReceivers = value; } + // } + // public IEnumerable allReceivers { //=> _receivers.Concat(_clusterReceivers); + // get { + // if (_receivers == null) + // return _clusterReceivers; + // else if (_clusterReceivers == null) + // return _receivers; + // else + // return _receivers.Concat(_clusterReceivers); + // } + // } [SerializeReference] private NucleusArray _array; @@ -152,7 +152,7 @@ public class Neuron : INucleus { Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); clonedSynapse.weight = synapse.weight; } - foreach (INucleus receiver in this.allReceivers) { + foreach (INucleus receiver in this.receivers) { clone.AddReceiver(receiver); } return clone; @@ -162,10 +162,10 @@ public class Neuron : INucleus { this._receivers.Add(receivingNucleus); receivingNucleus.AddSynapse(this); } - public void AddClusterReceiver(Cluster receivingCluster) { - this._clusterReceivers.Add(receivingCluster); - receivingCluster.AddSynapse(this); - } + // public void AddClusterReceiver(Cluster receivingCluster) { + // this._clusterReceivers.Add(receivingCluster); + // receivingCluster.AddSynapse(this); + // } public void RemoveReceiver(INucleus receiverNucleus) { this._receivers.RemoveAll(receiver => receiver == receiverNucleus); @@ -185,7 +185,7 @@ public class Neuron : INucleus { } } } - foreach (INucleus receiver in nucleus.allReceivers) { + foreach (INucleus receiver in nucleus.receivers) { if (receiver != null && receiver.synapses != null) receiver.synapses.RemoveAll(s => s.nucleus == nucleus); } @@ -196,16 +196,16 @@ public class Neuron : INucleus { } } - public Synapse AddSynapse(IReceptor sendingNucleus) { + public Synapse AddSynapse(IReceptor sendingNucleus, string nucleusName = null) { Synapse synapse = new(sendingNucleus); this.synapses.Add(synapse); return synapse; } - public Synapse AddClusterSynapse(Cluster sendingCluster) { - Synapse synapse = new(sendingCluster); - this.synapses.Add(synapse); - return synapse; - } + // public Synapse AddClusterSynapse(Cluster sendingCluster) { + // Synapse synapse = new(sendingCluster); + // this.synapses.Add(synapse); + // return synapse; + // } public virtual void UpdateState() { float3 sum = new(0, 0, 0); @@ -250,7 +250,7 @@ public class Neuron : INucleus { // } this.outputValue = result; - foreach (INucleus receiver in this.allReceivers) + foreach (INucleus receiver in this.receivers) receiver.UpdateState(); } diff --git a/Assets/NanoBrain/NucleusArray.cs b/Assets/NanoBrain/NucleusArray.cs index 5e10510..bf46995 100644 --- a/Assets/NanoBrain/NucleusArray.cs +++ b/Assets/NanoBrain/NucleusArray.cs @@ -9,12 +9,12 @@ public class NucleusArray { private Cluster[] _clusters; public IEnumerable nuclei { get { - if (_nuclei == null) - return _clusters; - else if (_clusters == null) + // if (_nuclei == null) + // return _clusters; + // else if (_clusters == null) return _nuclei; - else - return _nuclei.Concat(_clusters); + // else + // return _nuclei.Concat(_clusters); } } public string name; diff --git a/Assets/NanoBrain/Receptor.cs b/Assets/NanoBrain/Receptor.cs index cd3bdbf..c9233c5 100644 --- a/Assets/NanoBrain/Receptor.cs +++ b/Assets/NanoBrain/Receptor.cs @@ -30,12 +30,12 @@ public class Receptor : IReceptor { get { return _receivers; } set { _receivers = value; } } - private List _clusterReceivers = new(); - public List clusterReceivers { - get { return _clusterReceivers; } - set { _clusterReceivers = value; } - } - public IEnumerable allReceivers => _receivers.Concat(_clusterReceivers); + // private List _clusterReceivers = new(); + // public List clusterReceivers { + // get { return _clusterReceivers; } + // set { _clusterReceivers = value; } + // } + // public IEnumerable allReceivers => _receivers.Concat(_clusterReceivers); protected int[] thingIds; // every receiver can handle a thing with this id @@ -43,10 +43,10 @@ public class Receptor : IReceptor { this._receivers.Add(receivingNucleus); receivingNucleus.AddSynapse(this); } - public void AddClusterReceiver(Cluster receivingCluster) { - this._clusterReceivers.Add(receivingCluster); - receivingCluster.AddSynapse(this); - } + // public void AddClusterReceiver(Cluster receivingCluster) { + // this._clusterReceivers.Add(receivingCluster); + // receivingCluster.AddSynapse(this); + // } public void RemoveReceiver(INucleus receiverNucleus) { this._receivers.RemoveAll(receiver => receiver == receiverNucleus); @@ -116,7 +116,7 @@ public class Receptor : IReceptor { int receiverIx = 0; INucleus selectedReceiver = null; int selectedReceiverIx = 0; - foreach (INucleus receiver in this.allReceivers) { + foreach (INucleus receiver in this.receivers) { // selectedReceiver = receiver; // receiverIx++; diff --git a/Assets/NanoBrain/Synapse.cs b/Assets/NanoBrain/Synapse.cs index 371dd27..6772d06 100644 --- a/Assets/NanoBrain/Synapse.cs +++ b/Assets/NanoBrain/Synapse.cs @@ -5,14 +5,15 @@ using UnityEditor; [Serializable] public class Synapse { // Support access to cluster of basic nucleus - public IReceptor nucleus => clusterNucleus != null ? clusterNucleus : basicNucleus; + public IReceptor nucleus => basicNucleus; // clusterNucleus != null ? clusterNucleus : basicNucleus; [SerializeReference] private IReceptor basicNucleus; // The Cluster is a ScriptableObject and can therefore not be serialized using [SerializeReference] - private Cluster clusterNucleus; + // private ClusterInstance clusterNucleus; - public Cluster cluster; + [SerializeReference] + public ClusterInstance cluster; public float weight; @@ -29,10 +30,10 @@ public class Synapse { this.basicNucleus = nucleus; this.weight = weight; } - public Synapse(Cluster cluster, float weight = 1.0f) { - this.clusterNucleus = cluster.asset; - this.weight = weight; - } + // public Synapse(ClusterInstance cluster, float weight = 1.0f) { + // this.clusterNucleus = cluster; + // this.weight = weight; + // } public static class Presets { private const int samples = 32; diff --git a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs index 2243fce..86a09fd 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs @@ -156,8 +156,8 @@ public class ClusterInspector : Editor { return; NeuroidLayer currentLayer = new() { ix = layerIx }; - if (selectedNucleus.allReceivers != null) { - foreach (INucleus receiver in selectedNucleus.allReceivers) { + if (selectedNucleus.receivers != null) { + foreach (INucleus receiver in selectedNucleus.receivers) { INucleus outputNeuroid = receiver; if (outputNeuroid != null) { AddToLayer(currentLayer, outputNeuroid); @@ -272,12 +272,12 @@ public class ClusterInspector : Editor { } private void DrawReceivers(INucleus nucleus, Vector3 parentPos, float size) { - int nodeCount = nucleus.allReceivers.Count(); + int nodeCount = nucleus.receivers.Count(); // Determine the maximum value in this layer // This is used to 'scale' the output value colors of the nuclei float maxValue = 0; - foreach (INucleus receiver in nucleus.allReceivers) { + foreach (INucleus receiver in nucleus.receivers) { if (receiver is Neuron neuroid) { float value = length(neuroid.outputValue); if (value > maxValue) @@ -290,7 +290,7 @@ public class ClusterInspector : Editor { float margin = 10 + spacing / 2; int row = 0; - foreach (INucleus receiver in nucleus.allReceivers) { + foreach (INucleus receiver in nucleus.receivers) { INucleus receiverNucleus = receiver; if (receiverNucleus == null) continue; @@ -405,7 +405,7 @@ public class ClusterInspector : Editor { Handles.Label(labelPos, nucleus.name, style); } - if (nucleus is Cluster cluster) { + if (nucleus is ClusterInstance cluster) { Handles.color = Color.white; Handles.DrawWireDisc(position, Vector3.forward, size + 10); } @@ -552,7 +552,7 @@ public class ClusterInspector : Editor { if (GUILayout.Button("Delete this neuron")) DeleteNeuron(this.currentNucleus); - if (this.currentNucleus is Cluster subCluster) { + if (this.currentNucleus is ClusterInstance subCluster) { if (GUILayout.Button("Edit Cluster")) EditCluster(subCluster); } @@ -588,7 +588,7 @@ public class ClusterInspector : Editor { return; if (nucleus.cluster != null) this.currentNucleus = nucleus.cluster.output; - foreach (INucleus receiver in nucleus.allReceivers) { + foreach (INucleus receiver in nucleus.receivers) { if (receiver != null) { this.currentNucleus = receiver; break; @@ -603,17 +603,16 @@ public class ClusterInspector : Editor { } private void OnClusterPicked(INucleus nucleus, Cluster subCluster) { - Cluster clusterInstance = Instantiate(subCluster); - clusterInstance.asset = subCluster; - this.cluster.AddSubCluster(subCluster); + ClusterInstance clusterInstance = new(subCluster); + this.cluster.AddSubCluster(clusterInstance); clusterInstance.AddReceiver(nucleus); } - private void EditCluster(Cluster subCluster) { + private void EditCluster(ClusterInstance subCluster) { //var currentActiveObject = Selection.activeObject; - Selection.activeObject = subCluster; - EditorGUIUtility.PingObject(subCluster); - var editor = Editor.CreateEditor(subCluster); + Selection.activeObject = subCluster.asset; + EditorGUIUtility.PingObject(subCluster.asset); + var editor = Editor.CreateEditor(subCluster.asset); //Selection.activeObject = currentActiveObject; } diff --git a/Assets/Scenes/Boids/New Cluster.asset b/Assets/Scenes/Boids/New Cluster.asset index 6b60702..cdf9f20 100644 --- a/Assets/Scenes/Boids/New Cluster.asset +++ b/Assets/Scenes/Boids/New Cluster.asset @@ -14,19 +14,18 @@ MonoBehaviour: m_EditorClassIdentifier: Assembly-CSharp::Cluster asset: {fileID: 0} nuclei: - - rid: 2243601242842202259 - subClusters: [] + - rid: 2243601249170358341 references: version: 2 RefIds: - - rid: 2243601242842202259 + - rid: 2243601249170358341 type: {class: Neuron, ns: , asm: Assembly-CSharp} data: _name: Output _synapses: [] _receivers: [] _array: - rid: 2243601242842202260 + rid: 2243601249170358342 _curvePreset: 0 curve: serializedVersion: 2 @@ -54,9 +53,9 @@ MonoBehaviour: m_RotationOrder: 4 curveMax: 1 average: 0 - - rid: 2243601242842202260 + - rid: 2243601249170358342 type: {class: NucleusArray, ns: , asm: Assembly-CSharp} data: _nuclei: - - rid: 2243601242842202259 + - rid: 2243601249170358341 name: Output From c1e6df8df3b1844241ae66765f6daaefaf004393 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 26 Jan 2026 20:02:07 +0100 Subject: [PATCH 079/179] Cleanup --- Assets/NanoBrain/INucleus.cs | 4 -- Assets/NanoBrain/Identity.asset | 106 +++++++++++++++++++++++++++++++- Assets/NanoBrain/Neuron.cs | 26 +------- Assets/NanoBrain/Receptor.cs | 13 ---- 4 files changed, 105 insertions(+), 44 deletions(-) diff --git a/Assets/NanoBrain/INucleus.cs b/Assets/NanoBrain/INucleus.cs index 0dde236..8cc75de 100644 --- a/Assets/NanoBrain/INucleus.cs +++ b/Assets/NanoBrain/INucleus.cs @@ -11,7 +11,6 @@ public interface INucleus : IReceptor { // Senders public List synapses { get; } public Synapse AddSynapse(IReceptor sender, string nucleusName = null); - // public Synapse AddClusterSynapse(Cluster clusterSender); public NucleusArray array { get; set; } @@ -34,11 +33,8 @@ public interface IReceptor { // Receivers public List receivers { get; set; } - // public List clusterReceivers { get; set; } - // public IEnumerable allReceivers { get; } public void AddReceiver(INucleus receiver); - // public void AddClusterReceiver(Cluster clusterReceiver); public void RemoveReceiver(INucleus receiverNucleus); #endregion static diff --git a/Assets/NanoBrain/Identity.asset b/Assets/NanoBrain/Identity.asset index ea38020..94ece11 100644 --- a/Assets/NanoBrain/Identity.asset +++ b/Assets/NanoBrain/Identity.asset @@ -15,15 +15,22 @@ MonoBehaviour: asset: {fileID: 0} nuclei: - rid: 2243601242842202241 - subClusters: [] references: version: 2 RefIds: + - rid: -2 + type: {class: , ns: , asm: } - rid: 2243601242842202241 type: {class: Neuron, ns: , asm: Assembly-CSharp} data: _name: Output - _synapses: [] + _synapses: + - basicNucleus: + rid: 2243601249170358348 + cluster: + rid: -2 + weight: 1 + curveMax: 1 _receivers: [] _array: rid: 2243601242842202242 @@ -60,3 +67,98 @@ MonoBehaviour: _nuclei: - rid: 2243601242842202241 name: Output + - rid: 2243601249170358348 + type: {class: Neuron, ns: , asm: Assembly-CSharp} + data: + _name: New neuron + _synapses: [] + _receivers: + - rid: 2243601249170358349 + _array: + rid: 2243601249170358350 + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1000 + value: 1000 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + - rid: 2243601249170358349 + type: {class: ClusterInstance, ns: , asm: Assembly-CSharp} + data: + asset: {fileID: 11400000} + _receivers: + - rid: 2243601249170358351 + - rid: 2243601249170358350 + type: {class: NucleusArray, ns: , asm: Assembly-CSharp} + data: + _nuclei: + - rid: 2243601249170358348 + name: New neuron + - rid: 2243601249170358351 + type: {class: Neuron, ns: , asm: Assembly-CSharp} + data: + _name: Output + _synapses: + - basicNucleus: + rid: 2243601249170358349 + cluster: + rid: -2 + weight: 1 + curveMax: 1 + _receivers: [] + _array: + rid: 2243601249170358352 + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1000 + value: 1000 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + - rid: 2243601249170358352 + type: {class: NucleusArray, ns: , asm: Assembly-CSharp} + data: + _nuclei: + - rid: 2243601249170358351 + name: Output diff --git a/Assets/NanoBrain/Neuron.cs b/Assets/NanoBrain/Neuron.cs index b6e6a87..f288d7f 100644 --- a/Assets/NanoBrain/Neuron.cs +++ b/Assets/NanoBrain/Neuron.cs @@ -25,21 +25,6 @@ public class Neuron : INucleus { get { return _receivers; } set { _receivers = value; } } - // private List _clusterReceivers = new(); - // public List clusterReceivers { - // get { return _clusterReceivers; } - // set { _clusterReceivers = value; } - // } - // public IEnumerable allReceivers { //=> _receivers.Concat(_clusterReceivers); - // get { - // if (_receivers == null) - // return _clusterReceivers; - // else if (_clusterReceivers == null) - // return _receivers; - // else - // return _receivers.Concat(_clusterReceivers); - // } - // } [SerializeReference] private NucleusArray _array; @@ -162,10 +147,6 @@ public class Neuron : INucleus { this._receivers.Add(receivingNucleus); receivingNucleus.AddSynapse(this); } - // public void AddClusterReceiver(Cluster receivingCluster) { - // this._clusterReceivers.Add(receivingCluster); - // receivingCluster.AddSynapse(this); - // } public void RemoveReceiver(INucleus receiverNucleus) { this._receivers.RemoveAll(receiver => receiver == receiverNucleus); @@ -201,11 +182,6 @@ public class Neuron : INucleus { this.synapses.Add(synapse); return synapse; } - // public Synapse AddClusterSynapse(Cluster sendingCluster) { - // Synapse synapse = new(sendingCluster); - // this.synapses.Add(synapse); - // return synapse; - // } public virtual void UpdateState() { float3 sum = new(0, 0, 0); @@ -213,7 +189,7 @@ public class Neuron : INucleus { //Applying the weight factgors foreach (Synapse synapse in this.synapses) { - sum = sum + (synapse.weight * synapse.nucleus.outputValue); + sum += synapse.weight * synapse.nucleus.outputValue; if (lengthsq(synapse.nucleus.outputValue) != 0) n++; } diff --git a/Assets/NanoBrain/Receptor.cs b/Assets/NanoBrain/Receptor.cs index c9233c5..a743974 100644 --- a/Assets/NanoBrain/Receptor.cs +++ b/Assets/NanoBrain/Receptor.cs @@ -30,12 +30,6 @@ public class Receptor : IReceptor { get { return _receivers; } set { _receivers = value; } } - // private List _clusterReceivers = new(); - // public List clusterReceivers { - // get { return _clusterReceivers; } - // set { _clusterReceivers = value; } - // } - // public IEnumerable allReceivers => _receivers.Concat(_clusterReceivers); protected int[] thingIds; // every receiver can handle a thing with this id @@ -43,10 +37,6 @@ public class Receptor : IReceptor { this._receivers.Add(receivingNucleus); receivingNucleus.AddSynapse(this); } - // public void AddClusterReceiver(Cluster receivingCluster) { - // this._clusterReceivers.Add(receivingCluster); - // receivingCluster.AddSynapse(this); - // } public void RemoveReceiver(INucleus receiverNucleus) { this._receivers.RemoveAll(receiver => receiver == receiverNucleus); @@ -117,9 +107,6 @@ public class Receptor : IReceptor { INucleus selectedReceiver = null; int selectedReceiverIx = 0; foreach (INucleus receiver in this.receivers) { - // selectedReceiver = receiver; - // receiverIx++; - if (thingIds[receiverIx] == thingId) { // We found an existing receiver for this thing selectedReceiver = receiver; From f4559efe40b4107e424a5a9a415f23db3669e9fc Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 26 Jan 2026 20:06:13 +0100 Subject: [PATCH 080/179] Further cleanup --- Assets/NanoBrain/Neuron.cs | 57 +++++++++++++++++++++++++++++++--- Assets/NanoBrain/Synapse.cs | 62 +------------------------------------ 2 files changed, 54 insertions(+), 65 deletions(-) diff --git a/Assets/NanoBrain/Neuron.cs b/Assets/NanoBrain/Neuron.cs index f288d7f..3ccaaa6 100644 --- a/Assets/NanoBrain/Neuron.cs +++ b/Assets/NanoBrain/Neuron.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; using UnityEngine; +using UnityEditor; using Unity.Mathematics; using static Unity.Mathematics.math; @@ -59,16 +60,16 @@ public class Neuron : INucleus { switch (this.curvePreset) { case CurvePresets.Linear: this.curveMax = 1; - return Synapse.Presets.Linear(1); + return Presets.Linear(1); case CurvePresets.Power: this.curveMax = 1; - return Synapse.Presets.Power(2.0f, 1); + return Presets.Power(2.0f, 1); case CurvePresets.Sqrt: this.curveMax = 1; - return Synapse.Presets.Power(0.5f, 1); + return Presets.Power(0.5f, 1); case CurvePresets.Reciprocal: this.curveMax = 1 / 0.01f * 1; - return Synapse.Presets.Reciprocal(1); + return Presets.Reciprocal(1); default: this.curveMax = 1; return this.curve; @@ -83,6 +84,54 @@ public class Neuron : INucleus { public Cluster cluster { get; set; } + #region Activation + + public static class Presets { + private const int samples = 32; + public static AnimationCurve Linear(float weight) { + return AnimationCurve.Linear(0f, 0f, 1000f, weight * 1000); + } + public static AnimationCurve Power(float exponent, float weight) { + // build keyframes + Keyframe[] keys = new Keyframe[samples]; + for (int i = 0; i < samples; i++) { + float t = i / (float)(samples - 1); + float v = Mathf.Pow(t, exponent) * weight; + keys[i] = new Keyframe(t, v); + } + + AnimationCurve curve = new(keys); + + // set tangent modes for each key to Auto (smooth). Use Linear if you prefer straight segments. + for (int i = 0; i < curve.length; i++) { + AnimationUtility.SetKeyLeftTangentMode(curve, i, AnimationUtility.TangentMode.Auto); + AnimationUtility.SetKeyRightTangentMode(curve, i, AnimationUtility.TangentMode.Auto); + } + + return curve; + } + public static AnimationCurve Reciprocal(float weight) { + int samples = 128; + float xMin = 0.001f; + float xMax = 1; + var keys = new Keyframe[samples]; + for (int i = 0; i < samples; i++) { + float t = i / (float)(samples - 1); + float x = Mathf.Lerp(xMin, xMax, t); + float y = 1f / x * weight; + keys[i] = new Keyframe(x, y); + } + var curve = new AnimationCurve(keys); + for (int i = 0; i < curve.length; i++) { + AnimationUtility.SetKeyLeftTangentMode(curve, i, AnimationUtility.TangentMode.Linear); + AnimationUtility.SetKeyRightTangentMode(curve, i, AnimationUtility.TangentMode.Linear); + } + return curve; + } + } + + #endregion Activation + private float3 _outputValue; public float3 outputValue { get { return _outputValue; } diff --git a/Assets/NanoBrain/Synapse.cs b/Assets/NanoBrain/Synapse.cs index 6772d06..40580c0 100644 --- a/Assets/NanoBrain/Synapse.cs +++ b/Assets/NanoBrain/Synapse.cs @@ -1,81 +1,21 @@ using System; using UnityEngine; -using UnityEditor; [Serializable] public class Synapse { // Support access to cluster of basic nucleus - public IReceptor nucleus => basicNucleus; // clusterNucleus != null ? clusterNucleus : basicNucleus; + public IReceptor nucleus => basicNucleus; [SerializeReference] private IReceptor basicNucleus; - // The Cluster is a ScriptableObject and can therefore not be serialized using [SerializeReference] - // private ClusterInstance clusterNucleus; [SerializeReference] public ClusterInstance cluster; public float weight; - public enum CurvePresets { - Linear, - Power, - Sqrt, - Reciprocal, - Custom - } - public float curveMax = 1.0f; - public Synapse(IReceptor nucleus, float weight = 1.0f) { this.basicNucleus = nucleus; this.weight = weight; } - // public Synapse(ClusterInstance cluster, float weight = 1.0f) { - // this.clusterNucleus = cluster; - // this.weight = weight; - // } - - public static class Presets { - private const int samples = 32; - public static AnimationCurve Linear(float weight) { - return AnimationCurve.Linear(0f, 0f, 1000f, weight * 1000); - } - public static AnimationCurve Power(float exponent, float weight) { - // build keyframes - Keyframe[] keys = new Keyframe[samples]; - for (int i = 0; i < samples; i++) { - float t = i / (float)(samples - 1); - float v = Mathf.Pow(t, exponent) * weight; - keys[i] = new Keyframe(t, v); - } - - AnimationCurve curve = new(keys); - - // set tangent modes for each key to Auto (smooth). Use Linear if you prefer straight segments. - for (int i = 0; i < curve.length; i++) { - AnimationUtility.SetKeyLeftTangentMode(curve, i, AnimationUtility.TangentMode.Auto); - AnimationUtility.SetKeyRightTangentMode(curve, i, AnimationUtility.TangentMode.Auto); - } - - return curve; - } - public static AnimationCurve Reciprocal(float weight) { - int samples = 128; - float xMin = 0.001f; - float xMax = 1; - var keys = new Keyframe[samples]; - for (int i = 0; i < samples; i++) { - float t = i / (float)(samples - 1); - float x = Mathf.Lerp(xMin, xMax, t); - float y = 1f / x * weight; - keys[i] = new Keyframe(x, y); - } - var curve = new AnimationCurve(keys); - for (int i = 0; i < curve.length; i++) { - AnimationUtility.SetKeyLeftTangentMode(curve, i, AnimationUtility.TangentMode.Linear); - AnimationUtility.SetKeyRightTangentMode(curve, i, AnimationUtility.TangentMode.Linear); - } - return curve; - } - } } \ No newline at end of file From 8d1a4c3b72fa28d03e0651f92174d84eaa50e064 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 26 Jan 2026 20:59:17 +0100 Subject: [PATCH 081/179] Add memory cell --- Assembly-CSharp.csproj | 1 + Assets/NanoBrain/MemoryCell.cs | 65 +++++++++++++++++++ Assets/NanoBrain/MemoryCell.cs.meta | 2 + Assets/NanoBrain/Neuron.cs | 21 ++++-- Assets/NanoBrain/Velocity.asset | 61 +++++++++++++++++ Assets/NanoBrain/Velocity.asset.meta | 8 +++ .../VisualEditor/Editor/ClusterInspector.cs | 31 ++++++--- 7 files changed, 177 insertions(+), 12 deletions(-) create mode 100644 Assets/NanoBrain/MemoryCell.cs create mode 100644 Assets/NanoBrain/MemoryCell.cs.meta create mode 100644 Assets/NanoBrain/Velocity.asset create mode 100644 Assets/NanoBrain/Velocity.asset.meta diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index 1f5f66b..cc796da 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -76,6 +76,7 @@ + diff --git a/Assets/NanoBrain/MemoryCell.cs b/Assets/NanoBrain/MemoryCell.cs new file mode 100644 index 0000000..5e32009 --- /dev/null +++ b/Assets/NanoBrain/MemoryCell.cs @@ -0,0 +1,65 @@ +using System; +using UnityEngine; +using Unity.Mathematics; +using static Unity.Mathematics.math; + +[Serializable] +public class MemoryCell : Neuron { + + public MemoryCell(Cluster cluster, string name) : base(cluster, name) {} + + #region Parameters + + // Returns the memorized value weighted by time + // return lastValue * (current time - last time) + [SerializeField] + public bool deltaValue = false; + + #endregion Parameters + + #region State + + private float3 _memorizedValue; + private float _memorizedTime; + + public override void UpdateState() { + // A memorycell does not have an activation function + float3 result = new(0, 0, 0); + int n = 0; + + //Applying the weight factgors + foreach (Synapse synapse in this.synapses) { + if (synapse.nucleus == this) { + float deltaTime = Time.time - this.lastTime; + synapse.weight = deltaTime; + } + result += synapse.weight * synapse.nucleus.outputValue; + if (lengthsq(synapse.nucleus.outputValue) != 0) + n++; + } + + if (this.average) + result /= n; + + UpdateResult(result); + } + + public override void UpdateResult(Vector3 result) { + // output value is the previous value + if (this.deltaValue) { + float deltaTime = Time.time - this._memorizedTime; + this._outputValue = this._memorizedValue * deltaTime; + } + else + this._outputValue = this._memorizedValue; + + // Store the result for the next time + this._memorizedValue = result; + this._memorizedTime = Time.time; + + foreach (INucleus receiver in this.receivers) + receiver.UpdateState(); + } + + #endregion State +} diff --git a/Assets/NanoBrain/MemoryCell.cs.meta b/Assets/NanoBrain/MemoryCell.cs.meta new file mode 100644 index 0000000..ef74aba --- /dev/null +++ b/Assets/NanoBrain/MemoryCell.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 29633aa3fe5cd9dcc8d886051f45d4d8 \ No newline at end of file diff --git a/Assets/NanoBrain/Neuron.cs b/Assets/NanoBrain/Neuron.cs index 3ccaaa6..ff14d0c 100644 --- a/Assets/NanoBrain/Neuron.cs +++ b/Assets/NanoBrain/Neuron.cs @@ -54,8 +54,13 @@ public class Neuron : INucleus { } public AnimationCurve curve; public float curveMax = 1.0f; + + #region Parameters + public bool average = false; + #endregion Parameters + public AnimationCurve GenerateCurve() { switch (this.curvePreset) { case CurvePresets.Linear: @@ -132,8 +137,8 @@ public class Neuron : INucleus { #endregion Activation - private float3 _outputValue; - public float3 outputValue { + protected float3 _outputValue; + public virtual float3 outputValue { get { return _outputValue; } set { this.stale = 0; @@ -147,6 +152,7 @@ public class Neuron : INucleus { private bool _isSleeping = false; public bool isSleeping => _isSleeping; + public float lastTime { get; private set; } public void UpdateNuclei() { this.stale++; @@ -238,11 +244,16 @@ public class Neuron : INucleus { //Applying the weight factgors foreach (Synapse synapse in this.synapses) { + if (synapse.nucleus == this) { + float deltaTime = Time.time - this.lastTime; + synapse.weight = deltaTime; + } sum += synapse.weight * synapse.nucleus.outputValue; + // Perhaps synapses should be removed when the output value goes to 0.... if (lengthsq(synapse.nucleus.outputValue) != 0) n++; } - if (average) + if (this.average) sum /= n; // Activation function @@ -267,7 +278,8 @@ public class Neuron : INucleus { } UpdateResult(result); } - public void UpdateResult(Vector3 result) { + + public virtual void UpdateResult(Vector3 result) { // float d = Vector3.Distance(result, this.outputValue); // if (d < 0.5f) { // //Debug.Log($"insignificant update: {d}"); @@ -275,6 +287,7 @@ public class Neuron : INucleus { // } this.outputValue = result; + this.lastTime = Time.time; foreach (INucleus receiver in this.receivers) receiver.UpdateState(); diff --git a/Assets/NanoBrain/Velocity.asset b/Assets/NanoBrain/Velocity.asset new file mode 100644 index 0000000..9615d6d --- /dev/null +++ b/Assets/NanoBrain/Velocity.asset @@ -0,0 +1,61 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3} + m_Name: Velocity + m_EditorClassIdentifier: Assembly-CSharp::Cluster + asset: {fileID: 0} + nuclei: + - rid: 2243601362379866169 + references: + version: 2 + RefIds: + - rid: 2243601362379866169 + type: {class: Neuron, ns: , asm: Assembly-CSharp} + data: + _name: Output + _synapses: [] + _receivers: [] + _array: + rid: 2243601362379866170 + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1000 + value: 1000 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + - rid: 2243601362379866170 + type: {class: NucleusArray, ns: , asm: Assembly-CSharp} + data: + _nuclei: + - rid: 2243601362379866169 + name: Output diff --git a/Assets/NanoBrain/Velocity.asset.meta b/Assets/NanoBrain/Velocity.asset.meta new file mode 100644 index 0000000..07ecb98 --- /dev/null +++ b/Assets/NanoBrain/Velocity.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dd622ac7ed09e70ea8edac595047ac82 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs index 86a09fd..cd4d6c7 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs @@ -488,14 +488,20 @@ public class ClusterInspector : Editor { this.currentNucleus.name = EditorGUILayout.TextField(this.currentNucleus.name); if (this.currentNucleus is Neuron neuroid) { - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.LabelField("Activation Curve", GUILayout.Width(150)); - if (neuroid.curveMax > 0) - EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, 0, 1, neuroid.curveMax)); - else - EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, neuroid.curveMax, 1, -neuroid.curveMax)); - neuroid.curvePreset = (Neuron.CurvePresets)EditorGUILayout.EnumPopup(neuroid.curvePreset, GUILayout.Width(100)); - EditorGUILayout.EndHorizontal(); + if (this.currentNucleus is MemoryCell memory) { + // should use serializedProperty + memory.deltaValue = EditorGUILayout.Toggle("DeltaValue", memory.deltaValue); + } + else { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Activation Curve", GUILayout.Width(150)); + if (neuroid.curveMax > 0) + EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, 0, 1, neuroid.curveMax)); + else + EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, neuroid.curveMax, 1, -neuroid.curveMax)); + neuroid.curvePreset = (Neuron.CurvePresets)EditorGUILayout.EnumPopup(neuroid.curvePreset, GUILayout.Width(100)); + EditorGUILayout.EndHorizontal(); + } if (neuroid.array == null || neuroid.array.nuclei == null || neuroid.array.nuclei.Count() == 0) neuroid.array = new NucleusArray(neuroid); @@ -544,6 +550,8 @@ public class ClusterInspector : Editor { ConnectNucleus(this.cluster, this.currentNucleus); if (GUILayout.Button("Add Input Neuron")) AddInputNeuron(this.currentNucleus); + if (GUILayout.Button("Add Input MemoryCell")) + AddInputMemoryCell(this.currentNucleus); if (GUILayout.Button("Add Input Cluster")) AddCluster(this.currentNucleus); @@ -598,6 +606,13 @@ public class ClusterInspector : Editor { BuildLayers(); } + protected virtual void AddInputMemoryCell(INucleus nucleus) { + MemoryCell newMemory = new(this.cluster.cluster, "New memory cell"); + newMemory.AddReceiver(nucleus); + this.currentNucleus = newMemory; + BuildLayers(); + } + protected virtual void AddCluster(INucleus nucleus) { BrainPickerWindow.ShowPicker(brain => OnClusterPicked(nucleus, brain), "Select Cluster"); } From 296b80453fd817e545f19ae62a3b1f423e5a4afa Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Tue, 27 Jan 2026 19:31:44 +0100 Subject: [PATCH 082/179] Adding synapse to cluster --- Assets/NanoBrain/ClusterInstance.cs | 7 +++++-- Assets/NanoBrain/Neuron.cs | 12 +++++++----- .../VisualEditor/Editor/ClusterInspector.cs | 11 +++++++---- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/Assets/NanoBrain/ClusterInstance.cs b/Assets/NanoBrain/ClusterInstance.cs index e54254d..1dbb40d 100644 --- a/Assets/NanoBrain/ClusterInstance.cs +++ b/Assets/NanoBrain/ClusterInstance.cs @@ -38,12 +38,15 @@ public class ClusterInstance : INucleus { #region Synapses - private Synapse[] _synapses = new Synapse[0]; + [SerializeReference] + private List _synapses = new(); public List synapses => new(_synapses); public Synapse AddSynapse(IReceptor sendingNucleus, string nucleusName = null) { if (nucleusName == null) { - this.asset.inputs[0].AddSynapse(sendingNucleus); + Synapse synapse = new(sendingNucleus); + this._synapses.Add(synapse); + // Nice, but this is not yet connected to the nucleusName } else { INucleus receptor = (INucleus)this.asset.nuclei.Find(nucleus => nucleus is INucleus n && nucleus.name == nucleusName); receptor.AddSynapse(sendingNucleus); diff --git a/Assets/NanoBrain/Neuron.cs b/Assets/NanoBrain/Neuron.cs index ff14d0c..df4e965 100644 --- a/Assets/NanoBrain/Neuron.cs +++ b/Assets/NanoBrain/Neuron.cs @@ -142,7 +142,7 @@ public class Neuron : INucleus { get { return _outputValue; } set { this.stale = 0; - this._isSleeping = false; + // this._isSleeping = false; _outputValue = value; } } @@ -150,14 +150,16 @@ public class Neuron : INucleus { [NonSerialized] private int stale = 1000; - private bool _isSleeping = false; - public bool isSleeping => _isSleeping; + // private bool _isSleeping = false; + // public bool isSleeping => _isSleeping; + public bool isSleeping => lengthsq(this.outputValue) == 0; public float lastTime { get; private set; } public void UpdateNuclei() { this.stale++; - this._isSleeping = this.stale > 2; - if (isSleeping) + // this._isSleeping = this.stale > 2; + // if (isSleeping) + if (this.stale > 2) _outputValue = Vector3.zero; } diff --git a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs index cd4d6c7..f44105d 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs @@ -371,6 +371,11 @@ public class ClusterInspector : Editor { } private void DrawNucleus(IReceptor nucleus, Vector3 position, float maxValue, float size, Color color) { + if (nucleus is MemoryCell memory) { + Handles.color = Color.white; + Handles.DrawWireDisc(position + Vector3.right * 10, Vector3.forward, size); + } + Handles.color = color; Handles.DrawSolidDisc(position, Vector3.forward, size); @@ -489,8 +494,6 @@ public class ClusterInspector : Editor { this.currentNucleus.name = EditorGUILayout.TextField(this.currentNucleus.name); if (this.currentNucleus is Neuron neuroid) { if (this.currentNucleus is MemoryCell memory) { - // should use serializedProperty - memory.deltaValue = EditorGUILayout.Toggle("DeltaValue", memory.deltaValue); } else { EditorGUILayout.BeginHorizontal(); @@ -652,8 +655,8 @@ public class ClusterInspector : Editor { // Nucleus n = this.currentNucleus.brain.nuclei[selectedIndex - perceptei.Count()]; // n.AddReceiver(this.currentNucleus); // } - IReceptor n = cluster.nuclei[selectedIndex]; - n.AddReceiver(this.currentNucleus); + IReceptor receptor = cluster.nuclei[selectedIndex]; + receptor.AddReceiver(this.currentNucleus); } } From 96ed53312d7ee26f4e0fffd73aff54bd9039bdcb Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 28 Jan 2026 14:34:52 +0100 Subject: [PATCH 083/179] Improve custer/clusterinstance --- Assets/NanoBrain/Cluster.cs | 66 ------------------------- Assets/NanoBrain/ClusterInstance.cs | 17 +++++-- Assets/NanoBrain/INucleus.cs | 4 +- Assets/NanoBrain/Neuron.cs | 14 +++--- Assets/NanoBrain/NucleusArray.cs | 3 +- Assets/NanoBrain/Receptor.cs | 75 +++++++++++++++++------------ 6 files changed, 69 insertions(+), 110 deletions(-) diff --git a/Assets/NanoBrain/Cluster.cs b/Assets/NanoBrain/Cluster.cs index cae5110..973ab4e 100644 --- a/Assets/NanoBrain/Cluster.cs +++ b/Assets/NanoBrain/Cluster.cs @@ -1,7 +1,5 @@ using System.Collections.Generic; using UnityEngine; -using Unity.Mathematics; -using static Unity.Mathematics.math; [CreateAssetMenu(menuName = "Passer/Cluster")] public class Cluster : ScriptableObject { @@ -35,30 +33,6 @@ public class Cluster : ScriptableObject { } } - // The synapses of all inputs - private readonly List _synapses = new(); - public List synapses => _synapses; - - public NucleusArray array { get; set; } - - public List receivers { - get { return this.output.receivers; } - set { this.output.receivers = value; } - } - // public List clusterReceivers { - // get { return this.output.clusterReceivers; } - // set { this.output.clusterReceivers = clusterReceivers; } - // } - // public IEnumerable allReceivers { - // get => output.allReceivers; - // } - - // public INucleus Clone() { - // Cluster clone = CreateInstance(); - // // Lots to add here... - // return clone; - // } - // Call this function to ensure that there is at least one nucleus // This is an invariant and should be ensured before the nucleus is used // because output requires it. @@ -67,38 +41,12 @@ public class Cluster : ScriptableObject { if (nuclei.Count == 0) new Neuron(this, "Output"); // Every cluster should have at least 1 neuron } -/* - public void AddReceiver(INucleus receivingNucleus) { - //output.AddReceiver(receiver); - this.output.receivers.Add(receivingNucleus); - receivingNucleus.AddClusterSynapse(this); - } - public void AddClusterReceiver(Cluster clusterReceiver) { - this.output.clusterReceivers.Add(clusterReceiver); - clusterReceiver.AddClusterSynapse(this); - } - public void RemoveReceiver(INucleus receiver) { - output.RemoveReceiver(receiver); - } - - public Synapse AddSynapse(IReceptor sender) { - Synapse synapse = new(sender); - synapses.Add(synapse); - return synapse; - } - public Synapse AddClusterSynapse(Cluster sender) { - Synapse synapse = new(sender); - synapses.Add(synapse); - return synapse; - } -*/ public void GarbageCollection() { HashSet visitedNuclei = new(); MarkNuclei(visitedNuclei, this.output); //Debug.Log($"Garbage collection found {visitedNuclei.Count} Nuclei"); this.nuclei.RemoveAll(nucleus => nucleus is INucleus n && visitedNuclei.Contains(n) == false); - //this.perceptei.RemoveAll(perceptoid => visitedNuclei.Contains(perceptoid) == false); } public void MarkNuclei(HashSet visitedNuclei, INucleus nucleus) { @@ -129,22 +77,8 @@ public class Cluster : ScriptableObject { } } - #region Dynamics - - public float3 outputValue => this.output.outputValue; - public bool isSleeping => lengthsq(this.outputValue) == 0; - - public void UpdateState() { - // Don't know if this is right - this.output.UpdateState(); - // it is not, I should take inputs from the synapses and route them to the right internal nuclei - } - public void UpdateNuclei() { foreach (IReceptor nucleus in this.nuclei) nucleus.UpdateNuclei(); - } - - #endregion Dynamics } \ No newline at end of file diff --git a/Assets/NanoBrain/ClusterInstance.cs b/Assets/NanoBrain/ClusterInstance.cs index 1dbb40d..7236fbe 100644 --- a/Assets/NanoBrain/ClusterInstance.cs +++ b/Assets/NanoBrain/ClusterInstance.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using UnityEngine; using Unity.Mathematics; @@ -11,14 +10,18 @@ public class ClusterInstance : INucleus { public Cluster cluster => this.asset; + public List dynamicNuclei = new(); + public INucleus output => this.asset.nuclei[0] as INucleus; public float3 outputValue => this.output.outputValue; public ClusterInstance(Cluster asset) { this.asset = asset; + foreach (IReceptor nucleus in this.asset.nuclei) + dynamicNuclei.Add(nucleus.Clone()); } - public INucleus Clone() { + public IReceptor Clone() { ClusterInstance clone = new(this.asset); return clone; } @@ -116,7 +119,15 @@ public class ClusterInstance : INucleus { #region Update - public void UpdateState() { } + public void UpdateState() { + float3 sum = new(0, 0, 0); + + //Applying the weight factgors + foreach (Synapse synapse in this.synapses) { + sum += synapse.weight * synapse.nucleus.outputValue; + } + this.asset.inputs[0].UpdateState(); + } public void UpdateNuclei() { foreach (IReceptor nucleus in this.asset.nuclei) diff --git a/Assets/NanoBrain/INucleus.cs b/Assets/NanoBrain/INucleus.cs index 8cc75de..a4b7657 100644 --- a/Assets/NanoBrain/INucleus.cs +++ b/Assets/NanoBrain/INucleus.cs @@ -22,8 +22,6 @@ public interface INucleus : IReceptor { #endregion dynamic state - - public INucleus Clone(); } public interface IReceptor { @@ -48,5 +46,7 @@ public interface IReceptor { public bool isSleeping { get; } #endregion dynamic + + public IReceptor Clone(); } diff --git a/Assets/NanoBrain/Neuron.cs b/Assets/NanoBrain/Neuron.cs index df4e965..17ed928 100644 --- a/Assets/NanoBrain/Neuron.cs +++ b/Assets/NanoBrain/Neuron.cs @@ -165,8 +165,9 @@ public class Neuron : INucleus { #endregion Runtime state - public Neuron(Cluster brain, string name) : this(name) { + public Neuron(Cluster brain, string name) { this.cluster = brain; + this.name = name; if (this.cluster != null) { this.cluster.nuclei.Add(this); } @@ -174,13 +175,12 @@ public class Neuron : INucleus { Debug.LogError("No neuroid network"); } - public Neuron(string name) { - this._name = name; - } + // public Neuron(string name) { + // this._name = name; + // } - public virtual INucleus Clone() { - Neuron clone = new(this.name) { - cluster = this.cluster, + public virtual IReceptor Clone() { + Neuron clone = new(this.cluster, this.name) { array = this.array, curve = this.curve, curvePreset = this.curvePreset, diff --git a/Assets/NanoBrain/NucleusArray.cs b/Assets/NanoBrain/NucleusArray.cs index bf46995..ed14af8 100644 --- a/Assets/NanoBrain/NucleusArray.cs +++ b/Assets/NanoBrain/NucleusArray.cs @@ -42,7 +42,8 @@ public class NucleusArray { for (int i = 0; i < this._nuclei.Length; i++) newArray[i] = this._nuclei[i]; - newArray[newLength - 1] = this._nuclei[0].Clone(); + if (this._nuclei[0] is INucleus nucleus) + newArray[newLength - 1] = (INucleus) nucleus.Clone(); this._nuclei = newArray; } diff --git a/Assets/NanoBrain/Receptor.cs b/Assets/NanoBrain/Receptor.cs index a743974..18443e5 100644 --- a/Assets/NanoBrain/Receptor.cs +++ b/Assets/NanoBrain/Receptor.cs @@ -1,11 +1,12 @@ -using System; -using System.Linq; using System.Collections.Generic; using UnityEngine; using Unity.Mathematics; using static Unity.Mathematics.math; public class Receptor : IReceptor { + + private Cluster cluster; + [SerializeField] protected string _name; public virtual string name { @@ -13,6 +14,47 @@ public class Receptor : IReceptor { set => _name = value; } + public Receptor(Cluster cluster) { + this.cluster = cluster; + if (cluster != null) + cluster.nuclei.Add(this); + } + + public Receptor(Cluster cluster, INucleus nucleus) { + this.cluster = cluster; + if (cluster != null) + cluster.nuclei.Add(this); + this.AddReceiver(nucleus); + } + + public static Receptor CreateReceptor(Cluster cluster, string nucleusName) { + if (cluster == null) + return null; + + Receptor receptor = new(cluster); + foreach (INucleus nucleus in cluster.inputs) { + if (nucleus != null && nucleus.name == nucleusName) { + // Receptor receptor = new(cluster, nucleus); + // return receptor; + receptor.AddReceiver(nucleus); + } + } + if (receptor._receivers.Count == 0) + return null; + else + return receptor; + } + + public virtual IReceptor Clone() { + Receptor clone = new(this.cluster); + + foreach (INucleus receiver in this.receivers) { + clone.AddReceiver(receiver); + } + + return clone; + } + class Receiver { public INucleus nucleus; public int thingId; @@ -69,35 +111,6 @@ public class Receptor : IReceptor { } } - public Receptor(Cluster cluster) { - if (cluster != null) - cluster.nuclei.Add(this); - } - - public Receptor(Cluster cluster, INucleus nucleus) { - if (cluster != null) - cluster.nuclei.Add(this); - this.AddReceiver(nucleus); - } - - public static Receptor CreateReceptor(Cluster cluster, string nucleusName) { - if (cluster == null) - return null; - - Receptor receptor = new(cluster); - foreach (INucleus nucleus in cluster.inputs) { - if (nucleus != null && nucleus.name == nucleusName) { - // Receptor receptor = new(cluster, nucleus); - // return receptor; - receptor.AddReceiver(nucleus); - } - } - if (receptor._receivers.Count == 0) - return null; - else - return receptor; - } - public virtual void ProcessStimulus(int thingId, Vector3 newLocalPositionVector, string thingName = null) { this.localPosition = newLocalPositionVector; From 33f5af32d1329f3c64bf08e314ba57e44294ee04 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 28 Jan 2026 17:44:18 +0100 Subject: [PATCH 084/179] Move to ClusterPfab --- Assembly-CSharp.csproj | 2 +- Assets/NanoBrain/Cluster.cs | 301 ++++++++++++++---- Assets/NanoBrain/Cluster.cs.meta | 2 +- Assets/NanoBrain/ClusterInstance.cs | 138 -------- Assets/NanoBrain/ClusterInstance.cs.meta | 2 - Assets/NanoBrain/ClusterPrefab.cs | 84 +++++ Assets/NanoBrain/ClusterPrefab.cs.meta | 2 + Assets/NanoBrain/INucleus.cs | 6 +- Assets/NanoBrain/Identity.asset | 114 +------ Assets/NanoBrain/MemoryCell.cs | 2 +- Assets/NanoBrain/Neuron.cs | 44 ++- Assets/NanoBrain/NucleusArray.cs | 8 +- Assets/NanoBrain/Receptor.cs | 17 +- Assets/NanoBrain/Synapse.cs | 13 +- Assets/NanoBrain/Velocity.asset | 47 +-- .../VisualEditor/Editor/BrainPickerWindow.cs | 10 +- .../VisualEditor/Editor/ClusterInspector.cs | 43 +-- .../Editor/NanoBrainComponent_Editor.cs | 2 +- .../VisualEditor/NanoBrainComponent.cs | 8 +- Assets/Scenes/Boids/New Cluster.asset | 47 +-- .../Scripts/Editor/SwarmControl_Editor.cs | 4 +- 21 files changed, 432 insertions(+), 464 deletions(-) delete mode 100644 Assets/NanoBrain/ClusterInstance.cs delete mode 100644 Assets/NanoBrain/ClusterInstance.cs.meta create mode 100644 Assets/NanoBrain/ClusterPrefab.cs create mode 100644 Assets/NanoBrain/ClusterPrefab.cs.meta diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index cc796da..cd3cc27 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -73,7 +73,6 @@ - @@ -81,6 +80,7 @@ + diff --git a/Assets/NanoBrain/Cluster.cs b/Assets/NanoBrain/Cluster.cs index 973ab4e..44f68ed 100644 --- a/Assets/NanoBrain/Cluster.cs +++ b/Assets/NanoBrain/Cluster.cs @@ -1,84 +1,259 @@ +using System; using System.Collections.Generic; using UnityEngine; +using Unity.Mathematics; +using static Unity.Mathematics.math; -[CreateAssetMenu(menuName = "Passer/Cluster")] -public class Cluster : ScriptableObject { - - public Cluster cluster => this; - +[System.Serializable] +public class Cluster : INucleus { // The ScriptableObject asset from which the runtime object has been created - public Cluster asset; + public readonly ClusterPrefab prefab; + + public ClusterPrefab cluster { get; set; } + + [SerializeField] + protected string _name; + public virtual string name { + get => _name; + set => _name = value; + } + + // Hmm, a cluster instance can never be part of a scriptable object...(Cluster) + public Cluster(ClusterPrefab parent, ClusterPrefab prefab) { + this.prefab = prefab; + this.cluster = parent; + if (this.cluster != null) + this.cluster.nuclei.Add(this); + + // foreach (IReceptor nucleus in this.prefab.nuclei) { + // IReceptor clone = nucleus.CloneTo(null); + // this.dynamicNuclei.Add(clone); + // } + } + + public virtual IReceptor Clone() { + Neuron clone = new(this.cluster, this.name) { + array = this.array, + }; + + foreach (Synapse synapse in this.synapses) { + Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); + clonedSynapse.weight = synapse.weight; + } + foreach (INucleus receiver in this.receivers) { + clone.AddReceiver(receiver); + } + return clone; + } + + // Not sure if this belongs here... + [SerializeReference] + private NucleusArray _array; + public NucleusArray array { + get { return _array; } + set { _array = value; } + } + + #region Synapses + + // class ClusterSynapse : Synapse { + // public IReceptor receptor; + // public ClusterSynapse(IReceptor nucleus, INucleus receptor, float weight = 1.0f) : base(nucleus, weight) { + // this.receptor = receptor; + // } + // } + [SerializeField] + private List _synapses = new(); + public List synapses => _synapses; + + public Synapse AddSynapse(IReceptor sendingNucleus) { + Synapse synapse = new(sendingNucleus); //, this.prefab.inputs[0]); + this._synapses.Add(synapse); + return synapse; + // else { + // INucleus receptor = (INucleus)this.prefab.nuclei.Find(nucleus => nucleus is INucleus n && nucleus.name == nucleusName); + // ClusterSynapse synapse = new(sendingNucleus, receptor); + // receptor.AddSynapse(sendingNucleus); + // } + // // Add synapse to which neuron? + // return null; + } + + // Does this even exist already? + public void RemoveSynapse() { + + } + + #endregion Synapses + + #region Receivers [SerializeReference] - public List nuclei = new(); - - // public List subClusters = new(); - public void AddSubCluster(ClusterInstance subCluster) { - this.nuclei.Add(subCluster); + private List _receivers = new(); + public List receivers { + get { return _receivers; } + set { _receivers = value; } } - public INucleus output => this.nuclei[0] as INucleus; + public virtual void AddReceiver(INucleus receivingNucleus) { + this._receivers.Add(receivingNucleus); + receivingNucleus.AddSynapse(this); + } - public List _inputs = null; - public List inputs { - get { - if (this._inputs == null) { - this._inputs = new(); - foreach (IReceptor receptor in this.nuclei) { - if (receptor is INucleus nucleus) - this._inputs.Add(nucleus); - } - } - return this._inputs; + public void RemoveReceiver(INucleus receiverNucleus) { + this._receivers.RemoveAll(receiver => receiver == receiverNucleus); + receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); + } + + // public void AddReceiver(INucleus receivingNucleus) { + // int newLength = this._receivers.Count + 1; + // INucleus[] newReceivers = new INucleus[newLength]; + + // // Copy the existing receivers + // for (int ix = 0; ix < this._receivers.Count; ix++) + // newReceivers[ix] = this._receivers[ix]; + // // Add the new receivers + // newReceivers[this._receivers.Count] = receivingNucleus; + // // Replace the receivers with the new receivers + // this._receivers = new(newReceivers); + + // receivingNucleus.AddSynapse(this); + // } + + // public void RemoveReceiver(INucleus receivingNucleus) { + // Debug.Log("Clusterinstance. remote receiver"); + // int newLength = this._receivers.Count - 1; + // if (newLength < 0) + // // Array was empty, so we cannot remove anything + // return; + + // INucleus[] newReceivers = new INucleus[newLength]; + + // int newIx = 0; + // // Copy all receivers except receivingNucleus + // for (int ix = 0; ix < this._receivers.Count; ix++) { + // if (this._receivers[ix] == receivingNucleus) + // // skip the receiver we want to remote + // continue; + + // if (newIx >= newLength) + // // We want to copy more elements than expected + // // the receivingNucleus is not found + // // and the original array is returned + // return; + // newReceivers[newIx] = this._receivers[ix]; + // newIx++; + // } + // this._receivers = new(newReceivers); + // } + + #endregion Receivers + + #region Runtime + + [NonSerialized] + private int stale = 1000; + public bool isSleeping => lengthsq(this.outputValue) == 0; + + [NonSerialized] + protected float3 _outputValue; + public virtual float3 outputValue { + get { return _outputValue; } + set { + this.stale = 0; + _outputValue = value; } } - // Call this function to ensure that there is at least one nucleus - // This is an invariant and should be ensured before the nucleus is used - // because output requires it. - public void EnsureInitialization() { - nuclei ??= new List(); - if (nuclei.Count == 0) - new Neuron(this, "Output"); // Every cluster should have at least 1 neuron + #region Update + + public virtual void UpdateState() { + UpdateState(new float3(0, 0, 0)); } - public void GarbageCollection() { - HashSet visitedNuclei = new(); - MarkNuclei(visitedNuclei, this.output); - //Debug.Log($"Garbage collection found {visitedNuclei.Count} Nuclei"); - this.nuclei.RemoveAll(nucleus => nucleus is INucleus n && visitedNuclei.Contains(n) == false); - } + public void UpdateState(float3 inputValue) { + float3 sum = inputValue; // new(0, 0, 0); - public void MarkNuclei(HashSet visitedNuclei, INucleus nucleus) { - if (nucleus is null) - return; - - visitedNuclei.Add(nucleus); - if (nucleus.synapses != null) { - HashSet visitedSynapses = new(); - foreach (Synapse synapse in nucleus.synapses) { - if (synapse != null && synapse.nucleus != null) { - visitedSynapses.Add(synapse); - if (synapse.nucleus is INucleus synapse_nucleus) - MarkNuclei(visitedNuclei, synapse_nucleus); - } - } - nucleus.synapses.RemoveAll(synapse => visitedSynapses.Contains(synapse) == false); - } - if (nucleus.receivers != null) { - HashSet visitedReceivers = new(); - foreach (INucleus receiver in nucleus.receivers) { - if (receiver != null && receiver != null) { - visitedReceivers.Add(receiver); - visitedNuclei.Add(receiver); - } - } - nucleus.receivers.RemoveAll(receiver => visitedReceivers.Contains(receiver) == false); + //Applying the weight factgors + foreach (Synapse synapse in this.synapses) { + sum += synapse.weight * synapse.nucleus.outputValue; } + + // This does not work because the prefab nucleus does not have a state + this.prefab.inputs[0].UpdateState(sum); } public void UpdateNuclei() { - foreach (IReceptor nucleus in this.nuclei) + this.stale++; + if (this.stale > 2) + _outputValue = Vector3.zero; + + foreach (IReceptor nucleus in this.prefab.nuclei) nucleus.UpdateNuclei(); } -} \ No newline at end of file + + #endregion Update + + #endregion Runtime + + /* + [SerializeField] + private List _dynamicNuclei; + public List dynamicNuclei {// = new(); + get { + if (_dynamicNuclei == null) { + this._dynamicNuclei = new(); + foreach (IReceptor nucleus in this.prefab.nuclei) { + IReceptor clone = nucleus.CloneTo(null); + this._dynamicNuclei.Add(clone); + } + } + return this._dynamicNuclei; + } + } + + public List _inputs = null; + public List inputs { + get { + this._inputs = new(); + if (this.dynamicNuclei != null) { + foreach (IReceptor receptor in this.dynamicNuclei) { + if (receptor is INucleus nucleus) + this._inputs.Add(nucleus); + } + } + return this._inputs; + } + } + + public INucleus output => this.dynamicNuclei[0] as INucleus; + + public float3 outputValue => this.output.outputValue; + + + public IReceptor CloneTo(ClusterPrefab parent) { + Cluster clone = new(parent, this.prefab); + return clone; + } + public IReceptor Clone() { + Cluster clone = new(this.cluster, this.prefab); + return clone; + } + + #region Properties + + public string name { + get { return prefab.name; } + set { prefab.name = value; } + } + + public bool isSleeping => lengthsq(this.outputValue) == 0; + + public NucleusArray array { get; set; } + + #endregion Properties + + + */ + +} diff --git a/Assets/NanoBrain/Cluster.cs.meta b/Assets/NanoBrain/Cluster.cs.meta index ee35e0b..a10caff 100644 --- a/Assets/NanoBrain/Cluster.cs.meta +++ b/Assets/NanoBrain/Cluster.cs.meta @@ -1,2 +1,2 @@ fileFormatVersion: 2 -guid: 60a957541c24c57e78018c202ebb1d9b \ No newline at end of file +guid: f13cdc4a175a9f379a00317ae68d8bea \ No newline at end of file diff --git a/Assets/NanoBrain/ClusterInstance.cs b/Assets/NanoBrain/ClusterInstance.cs deleted file mode 100644 index 7236fbe..0000000 --- a/Assets/NanoBrain/ClusterInstance.cs +++ /dev/null @@ -1,138 +0,0 @@ -using System.Collections.Generic; -using UnityEngine; -using Unity.Mathematics; -using static Unity.Mathematics.math; - -[System.Serializable] -public class ClusterInstance : INucleus { - // The ScriptableObject asset from which the runtime object has been created - public Cluster asset; - - public Cluster cluster => this.asset; - - public List dynamicNuclei = new(); - - public INucleus output => this.asset.nuclei[0] as INucleus; - public float3 outputValue => this.output.outputValue; - - public ClusterInstance(Cluster asset) { - this.asset = asset; - foreach (IReceptor nucleus in this.asset.nuclei) - dynamicNuclei.Add(nucleus.Clone()); - } - - public IReceptor Clone() { - ClusterInstance clone = new(this.asset); - return clone; - } - - #region Properties - - public string name { - get { return asset.name; } - set { asset.name = value; } - } - - public bool isSleeping => lengthsq(this.outputValue) == 0; - - public NucleusArray array { get; set; } - - #endregion Properties - - #region Synapses - - [SerializeReference] - private List _synapses = new(); - public List synapses => new(_synapses); - - public Synapse AddSynapse(IReceptor sendingNucleus, string nucleusName = null) { - if (nucleusName == null) { - Synapse synapse = new(sendingNucleus); - this._synapses.Add(synapse); - // Nice, but this is not yet connected to the nucleusName - } else { - INucleus receptor = (INucleus)this.asset.nuclei.Find(nucleus => nucleus is INucleus n && nucleus.name == nucleusName); - receptor.AddSynapse(sendingNucleus); - } - // Add synapse to which neuron? - return null; - } - - // Does this even exist already? - public void RemoveSynapse() { - - } - - #endregion Synapses - - #region Receivers - - [SerializeReference] - private List _receivers = new(); - public List receivers { - get { return _receivers; } - set { _receivers = value; } - } - - public void AddReceiver(INucleus receivingNucleus) { - int newLength = this._receivers.Count + 1; - INucleus[] newReceivers = new INucleus[newLength]; - - // Copy the existing receivers - for (int ix = 0; ix < this._receivers.Count; ix++) - newReceivers[ix] = this._receivers[ix]; - // Add the new receivers - newReceivers[this._receivers.Count] = receivingNucleus; - // Replace the receivers with the new receivers - this._receivers = new(newReceivers); - - receivingNucleus.AddSynapse(this); - } - - public void RemoveReceiver(INucleus receivingNucleus) { - int newLength = this._receivers.Count - 1; - if (newLength < 0) - // Array was empty, so we cannot remove anything - return; - - INucleus[] newReceivers = new INucleus[newLength]; - - int newIx = 0; - // Copy all receivers except receivingNucleus - for (int ix = 0; ix < this._receivers.Count; ix++) { - if (this._receivers[ix] == receivingNucleus) - // skip the receiver we want to remote - continue; - - if (newIx >= newLength) - // We want to copy more elements than expected - // the receivingNucleus is not found - // and the original array is returned - return; - newReceivers[newIx] = this._receivers[ix]; - newIx++; - } - this._receivers = new(newReceivers); - } - - #endregion Receivers - - #region Update - - public void UpdateState() { - float3 sum = new(0, 0, 0); - - //Applying the weight factgors - foreach (Synapse synapse in this.synapses) { - sum += synapse.weight * synapse.nucleus.outputValue; - } - this.asset.inputs[0].UpdateState(); - } - - public void UpdateNuclei() { - foreach (IReceptor nucleus in this.asset.nuclei) - nucleus.UpdateNuclei(); - } - - #endregion Update -} diff --git a/Assets/NanoBrain/ClusterInstance.cs.meta b/Assets/NanoBrain/ClusterInstance.cs.meta deleted file mode 100644 index a10caff..0000000 --- a/Assets/NanoBrain/ClusterInstance.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: f13cdc4a175a9f379a00317ae68d8bea \ No newline at end of file diff --git a/Assets/NanoBrain/ClusterPrefab.cs b/Assets/NanoBrain/ClusterPrefab.cs new file mode 100644 index 0000000..db65b70 --- /dev/null +++ b/Assets/NanoBrain/ClusterPrefab.cs @@ -0,0 +1,84 @@ +using System.Collections.Generic; +using UnityEngine; + +[CreateAssetMenu(menuName = "Passer/Cluster")] +public class ClusterPrefab : ScriptableObject { + + //public virtual Cluster cluster {get;set;} + + // The ScriptableObject asset from which the runtime object has been created + //public Cluster asset; + + [SerializeReference] + public List nuclei = new(); + + // public List subClusters = new(); + // public void AddSubCluster(ClusterInstance subCluster) { + // this.nuclei.Add(subCluster); + // } + + public virtual INucleus output => this.nuclei[0] as INucleus; + + public List _inputs = null; + public virtual List inputs { + get { + if (this._inputs == null) { + this._inputs = new(); + foreach (IReceptor receptor in this.nuclei) { + if (receptor is INucleus nucleus) + this._inputs.Add(nucleus); + } + } + return this._inputs; + } + } + + // Call this function to ensure that there is at least one nucleus + // This is an invariant and should be ensured before the nucleus is used + // because output requires it. + public void EnsureInitialization() { + nuclei ??= new List(); + if (nuclei.Count == 0) + new Neuron(this, "Output"); // Every cluster should have at least 1 neuron + } + + public void GarbageCollection() { + HashSet visitedNuclei = new(); + MarkNuclei(visitedNuclei, this.output); + //Debug.Log($"Garbage collection found {visitedNuclei.Count} Nuclei"); + this.nuclei.RemoveAll(nucleus => nucleus is INucleus n && visitedNuclei.Contains(n) == false); + } + + public void MarkNuclei(HashSet visitedNuclei, INucleus nucleus) { + if (nucleus is null) + return; + + visitedNuclei.Add(nucleus); + if (nucleus.synapses != null) { + HashSet visitedSynapses = new(); + foreach (Synapse synapse in nucleus.synapses) { + if (synapse != null && synapse.nucleus != null) { + visitedSynapses.Add(synapse); + if (synapse.nucleus is INucleus synapse_nucleus) + MarkNuclei(visitedNuclei, synapse_nucleus); + } + } + nucleus.synapses.RemoveAll(synapse => visitedSynapses.Contains(synapse) == false); + } + if (nucleus.receivers != null) { + HashSet visitedReceivers = new(); + foreach (INucleus receiver in nucleus.receivers) { + if (receiver != null && receiver != null) { + visitedReceivers.Add(receiver); + visitedNuclei.Add(receiver); + } + } + nucleus.receivers.RemoveAll(receiver => visitedReceivers.Contains(receiver) == false); + } + } + + public virtual void UpdateNuclei() { + foreach (IReceptor nucleus in this.nuclei) + nucleus.UpdateNuclei(); + } +} \ No newline at end of file diff --git a/Assets/NanoBrain/ClusterPrefab.cs.meta b/Assets/NanoBrain/ClusterPrefab.cs.meta new file mode 100644 index 0000000..ee35e0b --- /dev/null +++ b/Assets/NanoBrain/ClusterPrefab.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 60a957541c24c57e78018c202ebb1d9b \ No newline at end of file diff --git a/Assets/NanoBrain/INucleus.cs b/Assets/NanoBrain/INucleus.cs index a4b7657..f7272f3 100644 --- a/Assets/NanoBrain/INucleus.cs +++ b/Assets/NanoBrain/INucleus.cs @@ -6,11 +6,11 @@ public interface INucleus : IReceptor { #region static struct // Cluster - public Cluster cluster { get; } + public ClusterPrefab cluster { get; } // Senders public List synapses { get; } - public Synapse AddSynapse(IReceptor sender, string nucleusName = null); + public Synapse AddSynapse(IReceptor sender); public NucleusArray array { get; set; } @@ -19,6 +19,7 @@ public interface INucleus : IReceptor { #region dynamic state public void UpdateState(); + public void UpdateState(float3 inputValue); #endregion dynamic state @@ -47,6 +48,7 @@ public interface IReceptor { #endregion dynamic + //public IReceptor CloneTo(ClusterPrefab parent); public IReceptor Clone(); } diff --git a/Assets/NanoBrain/Identity.asset b/Assets/NanoBrain/Identity.asset index 94ece11..076c284 100644 --- a/Assets/NanoBrain/Identity.asset +++ b/Assets/NanoBrain/Identity.asset @@ -12,123 +12,19 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3} m_Name: Identity m_EditorClassIdentifier: Assembly-CSharp::Cluster - asset: {fileID: 0} nuclei: - - rid: 2243601242842202241 + - rid: 2243601383627161705 references: version: 2 RefIds: - - rid: -2 - type: {class: , ns: , asm: } - - rid: 2243601242842202241 + - rid: 2243601383627161705 type: {class: Neuron, ns: , asm: Assembly-CSharp} data: _name: Output - _synapses: - - basicNucleus: - rid: 2243601249170358348 - cluster: - rid: -2 - weight: 1 - curveMax: 1 - _receivers: [] - _array: - rid: 2243601242842202242 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 1 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1000 - value: 1000 - inSlope: 1 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - - rid: 2243601242842202242 - type: {class: NucleusArray, ns: , asm: Assembly-CSharp} - data: - _nuclei: - - rid: 2243601242842202241 - name: Output - - rid: 2243601249170358348 - type: {class: Neuron, ns: , asm: Assembly-CSharp} - data: - _name: New neuron _synapses: [] - _receivers: - - rid: 2243601249170358349 - _array: - rid: 2243601249170358350 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 1 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1000 - value: 1000 - inSlope: 1 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - - rid: 2243601249170358349 - type: {class: ClusterInstance, ns: , asm: Assembly-CSharp} - data: - asset: {fileID: 11400000} - _receivers: - - rid: 2243601249170358351 - - rid: 2243601249170358350 - type: {class: NucleusArray, ns: , asm: Assembly-CSharp} - data: - _nuclei: - - rid: 2243601249170358348 - name: New neuron - - rid: 2243601249170358351 - type: {class: Neuron, ns: , asm: Assembly-CSharp} - data: - _name: Output - _synapses: - - basicNucleus: - rid: 2243601249170358349 - cluster: - rid: -2 - weight: 1 - curveMax: 1 _receivers: [] _array: - rid: 2243601249170358352 + rid: 2243601383627161706 _curvePreset: 0 curve: serializedVersion: 2 @@ -156,9 +52,9 @@ MonoBehaviour: m_RotationOrder: 4 curveMax: 1 average: 0 - - rid: 2243601249170358352 + - rid: 2243601383627161706 type: {class: NucleusArray, ns: , asm: Assembly-CSharp} data: _nuclei: - - rid: 2243601249170358351 + - rid: 2243601383627161705 name: Output diff --git a/Assets/NanoBrain/MemoryCell.cs b/Assets/NanoBrain/MemoryCell.cs index 5e32009..6e20a75 100644 --- a/Assets/NanoBrain/MemoryCell.cs +++ b/Assets/NanoBrain/MemoryCell.cs @@ -6,7 +6,7 @@ using static Unity.Mathematics.math; [Serializable] public class MemoryCell : Neuron { - public MemoryCell(Cluster cluster, string name) : base(cluster, name) {} + public MemoryCell(ClusterPrefab cluster, string name) : base(cluster, name) {} #region Parameters diff --git a/Assets/NanoBrain/Neuron.cs b/Assets/NanoBrain/Neuron.cs index 17ed928..099ceab 100644 --- a/Assets/NanoBrain/Neuron.cs +++ b/Assets/NanoBrain/Neuron.cs @@ -87,7 +87,7 @@ public class Neuron : INucleus { #region Runtime state (not serialized) - public Cluster cluster { get; set; } + public ClusterPrefab cluster { get; set; } #region Activation @@ -165,20 +165,40 @@ public class Neuron : INucleus { #endregion Runtime state - public Neuron(Cluster brain, string name) { - this.cluster = brain; + public Neuron(ClusterPrefab parent, string name) { + this.cluster = parent; this.name = name; if (this.cluster != null) { this.cluster.nuclei.Add(this); } - else - Debug.LogError("No neuroid network"); + // else + // Debug.LogError("No neuroid network"); } // public Neuron(string name) { // this._name = name; // } + public virtual IReceptor CloneTo(ClusterPrefab parent) { + Neuron clone = new(parent, this.name) { + array = this.array, + curve = this.curve, + curvePreset = this.curvePreset, + curveMax = this.curveMax, + average = this.average + }; + // if (clone.cluster != null) + // clone.cluster.nuclei.Add(clone); + + foreach (Synapse synapse in this.synapses) { + Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); + clonedSynapse.weight = synapse.weight; + } + foreach (INucleus receiver in this.receivers) { + clone.AddReceiver(receiver); + } + return clone; + } public virtual IReceptor Clone() { Neuron clone = new(this.cluster, this.name) { array = this.array, @@ -187,8 +207,8 @@ public class Neuron : INucleus { curveMax = this.curveMax, average = this.average }; - if (clone.cluster != null) - clone.cluster.nuclei.Add(clone); + // if (clone.cluster != null) + // clone.cluster.nuclei.Add(clone); foreach (Synapse synapse in this.synapses) { Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); @@ -234,14 +254,18 @@ public class Neuron : INucleus { } } - public Synapse AddSynapse(IReceptor sendingNucleus, string nucleusName = null) { + public Synapse AddSynapse(IReceptor sendingNucleus) { Synapse synapse = new(sendingNucleus); this.synapses.Add(synapse); return synapse; } public virtual void UpdateState() { - float3 sum = new(0, 0, 0); + UpdateState(new float3(0, 0, 0)); + } + + public virtual void UpdateState(float3 inputValue) { + float3 sum = inputValue;//new(0, 0, 0); int n = 0; //Applying the weight factgors @@ -255,7 +279,7 @@ public class Neuron : INucleus { if (lengthsq(synapse.nucleus.outputValue) != 0) n++; } - if (this.average) + if (this.average && n > 0) sum /= n; // Activation function diff --git a/Assets/NanoBrain/NucleusArray.cs b/Assets/NanoBrain/NucleusArray.cs index ed14af8..82a3b0e 100644 --- a/Assets/NanoBrain/NucleusArray.cs +++ b/Assets/NanoBrain/NucleusArray.cs @@ -6,7 +6,7 @@ using UnityEngine; public class NucleusArray { [SerializeReference] private INucleus[] _nuclei; - private Cluster[] _clusters; + private ClusterPrefab[] _clusters; public IEnumerable nuclei { get { // if (_nuclei == null) @@ -23,12 +23,12 @@ public class NucleusArray { this.name = nucleus.name; this._nuclei = new INucleus[1]; this._nuclei[0] = nucleus; - this._clusters = new Cluster[0]; + this._clusters = new ClusterPrefab[0]; } - public NucleusArray(Cluster cluster) { + public NucleusArray(ClusterPrefab cluster) { this.name = cluster.name; this._nuclei = new INucleus[0]; - this._clusters = new Cluster[1]; + this._clusters = new ClusterPrefab[1]; this._clusters[0] = cluster; } diff --git a/Assets/NanoBrain/Receptor.cs b/Assets/NanoBrain/Receptor.cs index 18443e5..72ef7df 100644 --- a/Assets/NanoBrain/Receptor.cs +++ b/Assets/NanoBrain/Receptor.cs @@ -5,7 +5,7 @@ using static Unity.Mathematics.math; public class Receptor : IReceptor { - private Cluster cluster; + private ClusterPrefab cluster; [SerializeField] protected string _name; @@ -14,20 +14,20 @@ public class Receptor : IReceptor { set => _name = value; } - public Receptor(Cluster cluster) { + public Receptor(ClusterPrefab cluster) { this.cluster = cluster; if (cluster != null) cluster.nuclei.Add(this); } - public Receptor(Cluster cluster, INucleus nucleus) { + public Receptor(ClusterPrefab cluster, INucleus nucleus) { this.cluster = cluster; if (cluster != null) cluster.nuclei.Add(this); this.AddReceiver(nucleus); } - public static Receptor CreateReceptor(Cluster cluster, string nucleusName) { + public static Receptor CreateReceptor(ClusterPrefab cluster, string nucleusName) { if (cluster == null) return null; @@ -45,6 +45,15 @@ public class Receptor : IReceptor { return receptor; } + public virtual IReceptor CloneTo(ClusterPrefab parent) { + Receptor clone = new(parent); + + foreach (INucleus receiver in this.receivers) { + clone.AddReceiver(receiver); + } + + return clone; + } public virtual IReceptor Clone() { Receptor clone = new(this.cluster); diff --git a/Assets/NanoBrain/Synapse.cs b/Assets/NanoBrain/Synapse.cs index 40580c0..e7c8116 100644 --- a/Assets/NanoBrain/Synapse.cs +++ b/Assets/NanoBrain/Synapse.cs @@ -4,18 +4,19 @@ using UnityEngine; [Serializable] public class Synapse { // Support access to cluster of basic nucleus - public IReceptor nucleus => basicNucleus; + //public IReceptor nucleus => basicNucleus; + + + //[SerializeReference] + //public Cluster cluster; [SerializeReference] - private IReceptor basicNucleus; - - [SerializeReference] - public ClusterInstance cluster; + public IReceptor nucleus; public float weight; public Synapse(IReceptor nucleus, float weight = 1.0f) { - this.basicNucleus = nucleus; + this.nucleus = nucleus; this.weight = weight; } } \ No newline at end of file diff --git a/Assets/NanoBrain/Velocity.asset b/Assets/NanoBrain/Velocity.asset index 9615d6d..f659ada 100644 --- a/Assets/NanoBrain/Velocity.asset +++ b/Assets/NanoBrain/Velocity.asset @@ -12,50 +12,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3} m_Name: Velocity m_EditorClassIdentifier: Assembly-CSharp::Cluster - asset: {fileID: 0} - nuclei: - - rid: 2243601362379866169 + nuclei: [] references: version: 2 - RefIds: - - rid: 2243601362379866169 - type: {class: Neuron, ns: , asm: Assembly-CSharp} - data: - _name: Output - _synapses: [] - _receivers: [] - _array: - rid: 2243601362379866170 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 1 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1000 - value: 1000 - inSlope: 1 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - - rid: 2243601362379866170 - type: {class: NucleusArray, ns: , asm: Assembly-CSharp} - data: - _nuclei: - - rid: 2243601362379866169 - name: Output + RefIds: [] diff --git a/Assets/NanoBrain/VisualEditor/Editor/BrainPickerWindow.cs b/Assets/NanoBrain/VisualEditor/Editor/BrainPickerWindow.cs index 66ef404..3a536df 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/BrainPickerWindow.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/BrainPickerWindow.cs @@ -5,11 +5,11 @@ using System.Linq; public class BrainPickerWindow : EditorWindow { private Vector2 scroll; - private Cluster[] items = new Cluster[0]; - private Action onPicked; + private ClusterPrefab[] items = new ClusterPrefab[0]; + private Action onPicked; private string search = ""; - public static void ShowPicker(Action onPicked, string title = "Select Cluster") { + public static void ShowPicker(Action onPicked, string title = "Select Cluster") { var w = CreateInstance(); w.titleContent = new GUIContent(title); w.minSize = new Vector2(360, 320); @@ -23,7 +23,7 @@ public class BrainPickerWindow : EditorWindow { private void RefreshList() { var guids = AssetDatabase.FindAssets("t:Cluster"); items = guids - .Select(g => AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(g))) + .Select(g => AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(g))) .Where(b => b != null) .OrderBy(b => b.name) .ToArray(); @@ -47,7 +47,7 @@ public class BrainPickerWindow : EditorWindow { continue; EditorGUILayout.BeginHorizontal(); - EditorGUILayout.LabelField(EditorGUIUtility.ObjectContent(it, typeof(Cluster)), GUILayout.Height(20)); + EditorGUILayout.LabelField(EditorGUIUtility.ObjectContent(it, typeof(ClusterPrefab)), GUILayout.Height(20)); if (GUILayout.Button("Select", GUILayout.Width(70))) { onPicked?.Invoke(it); Close(); diff --git a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs index f44105d..94273dd 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs @@ -7,7 +7,7 @@ using UnityEngine.UIElements; using Unity.Mathematics; using static Unity.Mathematics.math; -[CustomEditor(typeof(Cluster))] +[CustomEditor(typeof(ClusterPrefab))] public class ClusterInspector : Editor { protected static VisualElement mainContainer; protected static VisualElement inspectorContainer; @@ -17,7 +17,7 @@ public class ClusterInspector : Editor { #region Start public override VisualElement CreateInspectorGUI() { - Cluster cluster = target as Cluster; + ClusterPrefab cluster = target as ClusterPrefab; serializedObject.Update(); @@ -72,7 +72,7 @@ public class ClusterInspector : Editor { } public class GraphView : VisualElement { - Cluster cluster; + ClusterPrefab cluster; SerializedObject serializedBrain; INucleus currentNucleus; GameObject gameObject; @@ -123,7 +123,7 @@ public class ClusterInspector : Editor { subscribed = false; } - public void SetGraph(GameObject gameObject, Cluster brain, INucleus nucleus, VisualElement inspectorContainer) { + public void SetGraph(GameObject gameObject, ClusterPrefab brain, INucleus nucleus, VisualElement inspectorContainer) { this.gameObject = gameObject; this.cluster = brain; if (Application.isPlaying == false) @@ -410,7 +410,7 @@ public class ClusterInspector : Editor { Handles.Label(labelPos, nucleus.name, style); } - if (nucleus is ClusterInstance cluster) { + if (nucleus is Cluster cluster) { Handles.color = Color.white; Handles.DrawWireDisc(position, Vector3.forward, size + 10); } @@ -529,7 +529,7 @@ public class ClusterInspector : Editor { if (synapse.nucleus != null) { EditorGUILayout.Space(); - EditorGUI.BeginDisabledGroup(synapse.nucleus.isSleeping); + //EditorGUI.BeginDisabledGroup(synapse.nucleus.isSleeping); if (Application.isPlaying) EditorGUILayout.FloatField(synapse.nucleus.name, length(synapse.nucleus.outputValue) * synapse.weight); else { @@ -543,7 +543,7 @@ public class ClusterInspector : Editor { EditorGUI.indentLevel++; synapse.weight = EditorGUILayout.FloatField("Weight", synapse.weight); EditorGUI.indentLevel--; - EditorGUI.EndDisabledGroup(); + //EditorGUI.EndDisabledGroup(); } } } @@ -563,7 +563,7 @@ public class ClusterInspector : Editor { if (GUILayout.Button("Delete this neuron")) DeleteNeuron(this.currentNucleus); - if (this.currentNucleus is ClusterInstance subCluster) { + if (this.currentNucleus is Cluster subCluster) { if (GUILayout.Button("Edit Cluster")) EditCluster(subCluster); } @@ -588,7 +588,7 @@ public class ClusterInspector : Editor { } protected virtual void AddInputNeuron(INucleus nucleus) { - Neuron newNeuroid = new(this.cluster.cluster, "New neuron"); + Neuron newNeuroid = new(this.cluster, "New neuron"); newNeuroid.AddReceiver(nucleus); this.currentNucleus = newNeuroid; BuildLayers(); @@ -610,7 +610,7 @@ public class ClusterInspector : Editor { } protected virtual void AddInputMemoryCell(INucleus nucleus) { - MemoryCell newMemory = new(this.cluster.cluster, "New memory cell"); + MemoryCell newMemory = new(this.cluster, "New memory cell"); newMemory.AddReceiver(nucleus); this.currentNucleus = newMemory; BuildLayers(); @@ -620,22 +620,23 @@ public class ClusterInspector : Editor { BrainPickerWindow.ShowPicker(brain => OnClusterPicked(nucleus, brain), "Select Cluster"); } - private void OnClusterPicked(INucleus nucleus, Cluster subCluster) { - ClusterInstance clusterInstance = new(subCluster); - this.cluster.AddSubCluster(clusterInstance); - clusterInstance.AddReceiver(nucleus); + private void OnClusterPicked(INucleus nucleus, ClusterPrefab subCluster) { + Cluster subclusterInstance = new(this.cluster, subCluster); + //this.cluster.AddSubCluster(subclusterInstance); + //this.cluster.nuclei.Add(subclusterInstance); + subclusterInstance.AddReceiver(nucleus); } - private void EditCluster(ClusterInstance subCluster) { + private void EditCluster(Cluster subCluster) { //var currentActiveObject = Selection.activeObject; - Selection.activeObject = subCluster.asset; - EditorGUIUtility.PingObject(subCluster.asset); - var editor = Editor.CreateEditor(subCluster.asset); + Selection.activeObject = subCluster.prefab; + EditorGUIUtility.PingObject(subCluster.prefab); + var editor = Editor.CreateEditor(subCluster.prefab); //Selection.activeObject = currentActiveObject; } // Connect to another nucleus in the same cluster - protected virtual void ConnectNucleus(Cluster cluster, INucleus nucleus) { + protected virtual void ConnectNucleus(ClusterPrefab cluster, INucleus nucleus) { if (cluster == null) return; @@ -705,9 +706,9 @@ public class ClusterWrapper : ScriptableObject { //public string title; public Vector2 position; INucleus node; - Cluster graph; // needed to write back and mark dirty + ClusterPrefab graph; // needed to write back and mark dirty - public ClusterWrapper Init(INucleus node, Cluster graphAsset) { + public ClusterWrapper Init(INucleus node, ClusterPrefab graphAsset) { this.node = node; this.graph = graphAsset; //this.title = " A " + node.name; diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs index c9ad194..253993a 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs @@ -23,7 +23,7 @@ public class NanoBrainComponent_Editor : Editor { public override VisualElement CreateInspectorGUI() { //NanoBrainComponent component = target as NanoBrainComponent; - Cluster brain = Application.isPlaying ? component.brain : component.defaultBrain; + ClusterPrefab brain = Application.isPlaying ? component.brain : component.defaultBrain; if (Application.isPlaying == false) serializedObject.Update(); diff --git a/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs b/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs index 09fbfaa..56c9159 100644 --- a/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs +++ b/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs @@ -1,11 +1,11 @@ using UnityEngine; public class NanoBrainComponent : MonoBehaviour { - public Cluster defaultBrain; - private Cluster brainInstance; + public ClusterPrefab defaultBrain; + private ClusterPrefab brainInstance; public INucleus root => brainInstance.output; - public Cluster brain { + public ClusterPrefab brain { get { if (brainInstance == null && defaultBrain != null) { brainInstance = Instantiate(defaultBrain); @@ -23,7 +23,7 @@ public class NanoBrainComponent : MonoBehaviour { } } - public static void UpdateWeight(Cluster brain, string name, float weight) { + public static void UpdateWeight(ClusterPrefab brain, string name, float weight) { INucleus root = brain.output; foreach (Synapse synapse in root.synapses) { if (synapse.nucleus.name == name) { diff --git a/Assets/Scenes/Boids/New Cluster.asset b/Assets/Scenes/Boids/New Cluster.asset index cdf9f20..1db7fcd 100644 --- a/Assets/Scenes/Boids/New Cluster.asset +++ b/Assets/Scenes/Boids/New Cluster.asset @@ -12,50 +12,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3} m_Name: New Cluster m_EditorClassIdentifier: Assembly-CSharp::Cluster - asset: {fileID: 0} - nuclei: - - rid: 2243601249170358341 + nuclei: [] references: version: 2 - RefIds: - - rid: 2243601249170358341 - type: {class: Neuron, ns: , asm: Assembly-CSharp} - data: - _name: Output - _synapses: [] - _receivers: [] - _array: - rid: 2243601249170358342 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 1 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1000 - value: 1000 - inSlope: 1 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - - rid: 2243601249170358342 - type: {class: NucleusArray, ns: , asm: Assembly-CSharp} - data: - _nuclei: - - rid: 2243601249170358341 - name: Output + RefIds: [] diff --git a/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs b/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs index d8dbd3b..eaca9f7 100644 --- a/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs +++ b/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs @@ -10,9 +10,9 @@ public class SwarmControl_Editor : Editor { if (EditorGUI.EndChangeCheck()) { SwarmControl swarmControl = (SwarmControl)target; - Cluster[] nanoBrains = FindObjectsByType(FindObjectsSortMode.None); + ClusterPrefab[] nanoBrains = FindObjectsByType(FindObjectsSortMode.None); - foreach (Cluster brain in nanoBrains) { + foreach (ClusterPrefab brain in nanoBrains) { NanoBrainComponent.UpdateWeight(brain, "Avoidance", swarmControl.avoidanceForce); NanoBrainComponent.UpdateWeight(brain, "Cohesion", swarmControl.cohesionForce); NanoBrainComponent.UpdateWeight(brain, "Separation", swarmControl.separationForce); From 866dee0b56ae1033f60df34868d6a35e7577f303 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 29 Jan 2026 09:01:43 +0100 Subject: [PATCH 085/179] Updated Velocity asset --- Assets/NanoBrain/Velocity.asset | 94 ++++++++++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 2 deletions(-) diff --git a/Assets/NanoBrain/Velocity.asset b/Assets/NanoBrain/Velocity.asset index f659ada..521ba9b 100644 --- a/Assets/NanoBrain/Velocity.asset +++ b/Assets/NanoBrain/Velocity.asset @@ -12,7 +12,97 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3} m_Name: Velocity m_EditorClassIdentifier: Assembly-CSharp::Cluster - nuclei: [] + nuclei: + - rid: 2243601403683012671 + - rid: 2243601403683012676 references: version: 2 - RefIds: [] + RefIds: + - rid: -2 + type: {class: , ns: , asm: } + - rid: 2243601403683012671 + type: {class: Neuron, ns: , asm: Assembly-CSharp} + data: + _name: Output + _synapses: + - nucleus: + rid: -2 + weight: 1 + _receivers: [] + _array: + rid: 2243601403683012672 + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1000 + value: 1000 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + - rid: 2243601403683012672 + type: {class: NucleusArray, ns: , asm: Assembly-CSharp} + data: + _nuclei: + - rid: 2243601403683012671 + name: Output + - rid: 2243601403683012676 + type: {class: Neuron, ns: , asm: Assembly-CSharp} + data: + _name: Position + _synapses: [] + _receivers: + - rid: 2243601403683012671 + _array: + rid: 2243601403683012677 + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1000 + value: 1000 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + - rid: 2243601403683012677 + type: {class: NucleusArray, ns: , asm: Assembly-CSharp} + data: + _nuclei: + - rid: 2243601403683012676 + name: New neuron From a64ff841ac0dde229f22b4228f8cf479fea3ebff Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 29 Jan 2026 09:04:51 +0100 Subject: [PATCH 086/179] Initial commit from NanoBrain-Unity --- Cluster.cs | 259 +++++++ Cluster.cs.meta | 2 + ClusterPrefab.cs | 84 ++ ClusterPrefab.cs.meta | 2 + Editor.meta | 8 + Editor/NeuroidWindow.cs | 302 ++++++++ Editor/NeuroidWindow.cs.meta | 2 + INucleus.cs | 54 ++ INucleus.cs.meta | 2 + Identity.asset | 60 ++ Identity.asset.meta | 8 + LinearAlgebra.meta | 8 + LinearAlgebra/.editorconfig | 19 + .../.gitea/workflows/unit_tests.yaml | 37 + LinearAlgebra/.gitignore | 5 + LinearAlgebra/LinearAlgebra-csharp.sln | 30 + LinearAlgebra/src/Angle.cs | 341 ++++++++ LinearAlgebra/src/Decomposition.cs | 287 +++++++ LinearAlgebra/src/Direction.cs | 261 +++++++ LinearAlgebra/src/Float.cs | 41 + LinearAlgebra/src/LinearAlgebra.csproj | 14 + LinearAlgebra/src/Matrix.cs | 689 +++++++++++++++++ LinearAlgebra/src/Quat32.cs | 87 +++ LinearAlgebra/src/Quaternion.cs | 582 ++++++++++++++ LinearAlgebra/src/Spherical.cs | 279 +++++++ LinearAlgebra/src/SwingTwist.cs | 136 ++++ LinearAlgebra/src/Vector2Float.cs | 479 ++++++++++++ LinearAlgebra/src/Vector2Int.cs | 185 +++++ LinearAlgebra/src/Vector3Float.cs | 402 ++++++++++ LinearAlgebra/src/Vector3Int.cs | 273 +++++++ LinearAlgebra/src/float16.cs | 322 ++++++++ LinearAlgebra/test/AngleTest.cs | 501 ++++++++++++ LinearAlgebra/test/DirectionTest.cs | 226 ++++++ LinearAlgebra/test/LinearAlgebra_Test.csproj | 19 + LinearAlgebra/test/QuaternionTest.cs | 185 +++++ LinearAlgebra/test/SphericalTest.cs | 271 +++++++ LinearAlgebra/test/SwingTwistTest.cs | 131 ++++ LinearAlgebra/test/Vector2FloatTest.cs | 364 +++++++++ LinearAlgebra/test/Vector2IntTest.cs | 270 +++++++ LinearAlgebra/test/Vector3FloatTest.cs | 581 ++++++++++++++ LinearAlgebra/test/Vector3IntTest.cs | 349 +++++++++ MemoryCell.cs | 65 ++ MemoryCell.cs.meta | 2 + NanoBrain-Unity.code-workspace | 12 + NanoBrain-Unity.code-workspace.meta | 7 + Neuroid.cs | 82 ++ Neuroid.cs.meta | 2 + Neuron.cs | 321 ++++++++ Neuron.cs.meta | 2 + NucleusArray.cs | 67 ++ NucleusArray.cs.meta | 2 + Perceptoid.cs | 105 +++ Perceptoid.cs.meta | 2 + Receptor.cs | 175 +++++ Receptor.cs.meta | 2 + Scene.meta | 8 + Scene/TestScene.unity | 487 ++++++++++++ Scene/TestScene.unity.meta | 7 + Synapse.cs | 22 + Synapse.cs.meta | 2 + Velocity.asset | 108 +++ Velocity.asset.meta | 8 + VisualEditor.meta | 8 + VisualEditor/Editor.meta | 8 + VisualEditor/Editor/BrainPickerWindow.cs | 66 ++ VisualEditor/Editor/BrainPickerWindow.cs.meta | 2 + VisualEditor/Editor/ClusterInspector.cs | 728 ++++++++++++++++++ VisualEditor/Editor/ClusterInspector.cs.meta | 2 + .../Editor/NanoBrainComponent_Editor.cs | 129 ++++ .../Editor/NanoBrainComponent_Editor.cs.meta | 2 + VisualEditor/Editor/NanoBrainEditor.cs | 511 ++++++++++++ VisualEditor/Editor/NanoBrainEditor.cs.meta | 2 + VisualEditor/Editor/NanoBrainInspector.cs | 645 ++++++++++++++++ .../Editor/NanoBrainInspector.cs.meta | 2 + VisualEditor/NanoBrain.cs | 102 +++ VisualEditor/NanoBrain.cs.meta | 2 + VisualEditor/NanoBrainComponent.cs | 35 + VisualEditor/NanoBrainComponent.cs.meta | 2 + VisualEditor/Resources.meta | 8 + VisualEditor/Resources/GraphStyles.uss | 12 + VisualEditor/Resources/GraphStyles.uss.meta | 11 + 81 files changed, 11922 insertions(+) create mode 100644 Cluster.cs create mode 100644 Cluster.cs.meta create mode 100644 ClusterPrefab.cs create mode 100644 ClusterPrefab.cs.meta create mode 100644 Editor.meta create mode 100644 Editor/NeuroidWindow.cs create mode 100644 Editor/NeuroidWindow.cs.meta create mode 100644 INucleus.cs create mode 100644 INucleus.cs.meta create mode 100644 Identity.asset create mode 100644 Identity.asset.meta create mode 100644 LinearAlgebra.meta create mode 100644 LinearAlgebra/.editorconfig create mode 100644 LinearAlgebra/.gitea/workflows/unit_tests.yaml create mode 100644 LinearAlgebra/.gitignore create mode 100644 LinearAlgebra/LinearAlgebra-csharp.sln create mode 100644 LinearAlgebra/src/Angle.cs create mode 100644 LinearAlgebra/src/Decomposition.cs create mode 100644 LinearAlgebra/src/Direction.cs create mode 100644 LinearAlgebra/src/Float.cs create mode 100644 LinearAlgebra/src/LinearAlgebra.csproj create mode 100644 LinearAlgebra/src/Matrix.cs create mode 100644 LinearAlgebra/src/Quat32.cs create mode 100644 LinearAlgebra/src/Quaternion.cs create mode 100644 LinearAlgebra/src/Spherical.cs create mode 100644 LinearAlgebra/src/SwingTwist.cs create mode 100644 LinearAlgebra/src/Vector2Float.cs create mode 100644 LinearAlgebra/src/Vector2Int.cs create mode 100644 LinearAlgebra/src/Vector3Float.cs create mode 100644 LinearAlgebra/src/Vector3Int.cs create mode 100644 LinearAlgebra/src/float16.cs create mode 100644 LinearAlgebra/test/AngleTest.cs create mode 100644 LinearAlgebra/test/DirectionTest.cs create mode 100644 LinearAlgebra/test/LinearAlgebra_Test.csproj create mode 100644 LinearAlgebra/test/QuaternionTest.cs create mode 100644 LinearAlgebra/test/SphericalTest.cs create mode 100644 LinearAlgebra/test/SwingTwistTest.cs create mode 100644 LinearAlgebra/test/Vector2FloatTest.cs create mode 100644 LinearAlgebra/test/Vector2IntTest.cs create mode 100644 LinearAlgebra/test/Vector3FloatTest.cs create mode 100644 LinearAlgebra/test/Vector3IntTest.cs create mode 100644 MemoryCell.cs create mode 100644 MemoryCell.cs.meta create mode 100644 NanoBrain-Unity.code-workspace create mode 100644 NanoBrain-Unity.code-workspace.meta create mode 100644 Neuroid.cs create mode 100644 Neuroid.cs.meta create mode 100644 Neuron.cs create mode 100644 Neuron.cs.meta create mode 100644 NucleusArray.cs create mode 100644 NucleusArray.cs.meta create mode 100644 Perceptoid.cs create mode 100644 Perceptoid.cs.meta create mode 100644 Receptor.cs create mode 100644 Receptor.cs.meta create mode 100644 Scene.meta create mode 100644 Scene/TestScene.unity create mode 100644 Scene/TestScene.unity.meta create mode 100644 Synapse.cs create mode 100644 Synapse.cs.meta create mode 100644 Velocity.asset create mode 100644 Velocity.asset.meta create mode 100644 VisualEditor.meta create mode 100644 VisualEditor/Editor.meta create mode 100644 VisualEditor/Editor/BrainPickerWindow.cs create mode 100644 VisualEditor/Editor/BrainPickerWindow.cs.meta create mode 100644 VisualEditor/Editor/ClusterInspector.cs create mode 100644 VisualEditor/Editor/ClusterInspector.cs.meta create mode 100644 VisualEditor/Editor/NanoBrainComponent_Editor.cs create mode 100644 VisualEditor/Editor/NanoBrainComponent_Editor.cs.meta create mode 100644 VisualEditor/Editor/NanoBrainEditor.cs create mode 100644 VisualEditor/Editor/NanoBrainEditor.cs.meta create mode 100644 VisualEditor/Editor/NanoBrainInspector.cs create mode 100644 VisualEditor/Editor/NanoBrainInspector.cs.meta create mode 100644 VisualEditor/NanoBrain.cs create mode 100644 VisualEditor/NanoBrain.cs.meta create mode 100644 VisualEditor/NanoBrainComponent.cs create mode 100644 VisualEditor/NanoBrainComponent.cs.meta create mode 100644 VisualEditor/Resources.meta create mode 100644 VisualEditor/Resources/GraphStyles.uss create mode 100644 VisualEditor/Resources/GraphStyles.uss.meta diff --git a/Cluster.cs b/Cluster.cs new file mode 100644 index 0000000..44f68ed --- /dev/null +++ b/Cluster.cs @@ -0,0 +1,259 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using Unity.Mathematics; +using static Unity.Mathematics.math; + +[System.Serializable] +public class Cluster : INucleus { + // The ScriptableObject asset from which the runtime object has been created + public readonly ClusterPrefab prefab; + + public ClusterPrefab cluster { get; set; } + + [SerializeField] + protected string _name; + public virtual string name { + get => _name; + set => _name = value; + } + + // Hmm, a cluster instance can never be part of a scriptable object...(Cluster) + public Cluster(ClusterPrefab parent, ClusterPrefab prefab) { + this.prefab = prefab; + this.cluster = parent; + if (this.cluster != null) + this.cluster.nuclei.Add(this); + + // foreach (IReceptor nucleus in this.prefab.nuclei) { + // IReceptor clone = nucleus.CloneTo(null); + // this.dynamicNuclei.Add(clone); + // } + } + + public virtual IReceptor Clone() { + Neuron clone = new(this.cluster, this.name) { + array = this.array, + }; + + foreach (Synapse synapse in this.synapses) { + Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); + clonedSynapse.weight = synapse.weight; + } + foreach (INucleus receiver in this.receivers) { + clone.AddReceiver(receiver); + } + return clone; + } + + // Not sure if this belongs here... + [SerializeReference] + private NucleusArray _array; + public NucleusArray array { + get { return _array; } + set { _array = value; } + } + + #region Synapses + + // class ClusterSynapse : Synapse { + // public IReceptor receptor; + // public ClusterSynapse(IReceptor nucleus, INucleus receptor, float weight = 1.0f) : base(nucleus, weight) { + // this.receptor = receptor; + // } + // } + [SerializeField] + private List _synapses = new(); + public List synapses => _synapses; + + public Synapse AddSynapse(IReceptor sendingNucleus) { + Synapse synapse = new(sendingNucleus); //, this.prefab.inputs[0]); + this._synapses.Add(synapse); + return synapse; + // else { + // INucleus receptor = (INucleus)this.prefab.nuclei.Find(nucleus => nucleus is INucleus n && nucleus.name == nucleusName); + // ClusterSynapse synapse = new(sendingNucleus, receptor); + // receptor.AddSynapse(sendingNucleus); + // } + // // Add synapse to which neuron? + // return null; + } + + // Does this even exist already? + public void RemoveSynapse() { + + } + + #endregion Synapses + + #region Receivers + + [SerializeReference] + private List _receivers = new(); + public List receivers { + get { return _receivers; } + set { _receivers = value; } + } + + public virtual void AddReceiver(INucleus receivingNucleus) { + this._receivers.Add(receivingNucleus); + receivingNucleus.AddSynapse(this); + } + + public void RemoveReceiver(INucleus receiverNucleus) { + this._receivers.RemoveAll(receiver => receiver == receiverNucleus); + receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); + } + + // public void AddReceiver(INucleus receivingNucleus) { + // int newLength = this._receivers.Count + 1; + // INucleus[] newReceivers = new INucleus[newLength]; + + // // Copy the existing receivers + // for (int ix = 0; ix < this._receivers.Count; ix++) + // newReceivers[ix] = this._receivers[ix]; + // // Add the new receivers + // newReceivers[this._receivers.Count] = receivingNucleus; + // // Replace the receivers with the new receivers + // this._receivers = new(newReceivers); + + // receivingNucleus.AddSynapse(this); + // } + + // public void RemoveReceiver(INucleus receivingNucleus) { + // Debug.Log("Clusterinstance. remote receiver"); + // int newLength = this._receivers.Count - 1; + // if (newLength < 0) + // // Array was empty, so we cannot remove anything + // return; + + // INucleus[] newReceivers = new INucleus[newLength]; + + // int newIx = 0; + // // Copy all receivers except receivingNucleus + // for (int ix = 0; ix < this._receivers.Count; ix++) { + // if (this._receivers[ix] == receivingNucleus) + // // skip the receiver we want to remote + // continue; + + // if (newIx >= newLength) + // // We want to copy more elements than expected + // // the receivingNucleus is not found + // // and the original array is returned + // return; + // newReceivers[newIx] = this._receivers[ix]; + // newIx++; + // } + // this._receivers = new(newReceivers); + // } + + #endregion Receivers + + #region Runtime + + [NonSerialized] + private int stale = 1000; + public bool isSleeping => lengthsq(this.outputValue) == 0; + + [NonSerialized] + protected float3 _outputValue; + public virtual float3 outputValue { + get { return _outputValue; } + set { + this.stale = 0; + _outputValue = value; + } + } + + #region Update + + public virtual void UpdateState() { + UpdateState(new float3(0, 0, 0)); + } + + public void UpdateState(float3 inputValue) { + float3 sum = inputValue; // new(0, 0, 0); + + //Applying the weight factgors + foreach (Synapse synapse in this.synapses) { + sum += synapse.weight * synapse.nucleus.outputValue; + } + + // This does not work because the prefab nucleus does not have a state + this.prefab.inputs[0].UpdateState(sum); + } + + public void UpdateNuclei() { + this.stale++; + if (this.stale > 2) + _outputValue = Vector3.zero; + + foreach (IReceptor nucleus in this.prefab.nuclei) + nucleus.UpdateNuclei(); + } + + #endregion Update + + #endregion Runtime + + /* + [SerializeField] + private List _dynamicNuclei; + public List dynamicNuclei {// = new(); + get { + if (_dynamicNuclei == null) { + this._dynamicNuclei = new(); + foreach (IReceptor nucleus in this.prefab.nuclei) { + IReceptor clone = nucleus.CloneTo(null); + this._dynamicNuclei.Add(clone); + } + } + return this._dynamicNuclei; + } + } + + public List _inputs = null; + public List inputs { + get { + this._inputs = new(); + if (this.dynamicNuclei != null) { + foreach (IReceptor receptor in this.dynamicNuclei) { + if (receptor is INucleus nucleus) + this._inputs.Add(nucleus); + } + } + return this._inputs; + } + } + + public INucleus output => this.dynamicNuclei[0] as INucleus; + + public float3 outputValue => this.output.outputValue; + + + public IReceptor CloneTo(ClusterPrefab parent) { + Cluster clone = new(parent, this.prefab); + return clone; + } + public IReceptor Clone() { + Cluster clone = new(this.cluster, this.prefab); + return clone; + } + + #region Properties + + public string name { + get { return prefab.name; } + set { prefab.name = value; } + } + + public bool isSleeping => lengthsq(this.outputValue) == 0; + + public NucleusArray array { get; set; } + + #endregion Properties + + + */ + +} diff --git a/Cluster.cs.meta b/Cluster.cs.meta new file mode 100644 index 0000000..a10caff --- /dev/null +++ b/Cluster.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f13cdc4a175a9f379a00317ae68d8bea \ No newline at end of file diff --git a/ClusterPrefab.cs b/ClusterPrefab.cs new file mode 100644 index 0000000..db65b70 --- /dev/null +++ b/ClusterPrefab.cs @@ -0,0 +1,84 @@ +using System.Collections.Generic; +using UnityEngine; + +[CreateAssetMenu(menuName = "Passer/Cluster")] +public class ClusterPrefab : ScriptableObject { + + //public virtual Cluster cluster {get;set;} + + // The ScriptableObject asset from which the runtime object has been created + //public Cluster asset; + + [SerializeReference] + public List nuclei = new(); + + // public List subClusters = new(); + // public void AddSubCluster(ClusterInstance subCluster) { + // this.nuclei.Add(subCluster); + // } + + public virtual INucleus output => this.nuclei[0] as INucleus; + + public List _inputs = null; + public virtual List inputs { + get { + if (this._inputs == null) { + this._inputs = new(); + foreach (IReceptor receptor in this.nuclei) { + if (receptor is INucleus nucleus) + this._inputs.Add(nucleus); + } + } + return this._inputs; + } + } + + // Call this function to ensure that there is at least one nucleus + // This is an invariant and should be ensured before the nucleus is used + // because output requires it. + public void EnsureInitialization() { + nuclei ??= new List(); + if (nuclei.Count == 0) + new Neuron(this, "Output"); // Every cluster should have at least 1 neuron + } + + public void GarbageCollection() { + HashSet visitedNuclei = new(); + MarkNuclei(visitedNuclei, this.output); + //Debug.Log($"Garbage collection found {visitedNuclei.Count} Nuclei"); + this.nuclei.RemoveAll(nucleus => nucleus is INucleus n && visitedNuclei.Contains(n) == false); + } + + public void MarkNuclei(HashSet visitedNuclei, INucleus nucleus) { + if (nucleus is null) + return; + + visitedNuclei.Add(nucleus); + if (nucleus.synapses != null) { + HashSet visitedSynapses = new(); + foreach (Synapse synapse in nucleus.synapses) { + if (synapse != null && synapse.nucleus != null) { + visitedSynapses.Add(synapse); + if (synapse.nucleus is INucleus synapse_nucleus) + MarkNuclei(visitedNuclei, synapse_nucleus); + } + } + nucleus.synapses.RemoveAll(synapse => visitedSynapses.Contains(synapse) == false); + } + if (nucleus.receivers != null) { + HashSet visitedReceivers = new(); + foreach (INucleus receiver in nucleus.receivers) { + if (receiver != null && receiver != null) { + visitedReceivers.Add(receiver); + visitedNuclei.Add(receiver); + } + } + nucleus.receivers.RemoveAll(receiver => visitedReceivers.Contains(receiver) == false); + } + } + + public virtual void UpdateNuclei() { + foreach (IReceptor nucleus in this.nuclei) + nucleus.UpdateNuclei(); + } +} \ No newline at end of file diff --git a/ClusterPrefab.cs.meta b/ClusterPrefab.cs.meta new file mode 100644 index 0000000..ee35e0b --- /dev/null +++ b/ClusterPrefab.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 60a957541c24c57e78018c202ebb1d9b \ No newline at end of file diff --git a/Editor.meta b/Editor.meta new file mode 100644 index 0000000..090b3ac --- /dev/null +++ b/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3aedf57a50b6dfa46a59457c87b8ef9d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/NeuroidWindow.cs b/Editor/NeuroidWindow.cs new file mode 100644 index 0000000..187df35 --- /dev/null +++ b/Editor/NeuroidWindow.cs @@ -0,0 +1,302 @@ +/* +using UnityEditor; +using UnityEngine; +using System.Linq; +using System.Collections.Generic; + +public class NeuroidLayer { + public int ix = 0; + public List neuroids = new(); +} + +public class GraphEditorWindow : EditorWindow { + private Nucleus currentNucleus; + private List allNeuroids; + private Dictionary neuroidPositions = new(); + + private List layers = new(); + + private void OnEnable() { + EditorApplication.update += EditorUpdate; + Selection.selectionChanged += OnSelectionChange; + SelectNeuron(); + } + + private void AddToLayer(NeuroidLayer layer, Nucleus nucleus) { + layer.neuroids.Add(nucleus); + nucleus.layerIx = layer.ix; + // Store its position + Vector2Int neuroidPosition = new(layer.ix, layer.neuroids.Count - 1); + neuroidPositions[nucleus] = neuroidPosition; + + } + + private void BuildLayers() { + // A temporary list to track what's been added to layers + this.layers = new(); + int layerIx = 0; + + Nucleus selectedNucleus = this.currentNucleus; + if (selectedNucleus == null) + return; + NeuroidLayer currentLayer = new() { ix = layerIx }; + + //foreach (Nucleus outputNeuroid in selectedNucleus.receivers) { + foreach (Receiver receiver in selectedNucleus.receivers) { + Nucleus outputNeuroid = receiver.nucleus; + if (outputNeuroid != null) { + AddToLayer(currentLayer, outputNeuroid); + Debug.Log($"layer {layerIx} nucleus {outputNeuroid.name}"); + } + } + if (currentLayer.neuroids.Count > 0) { + this.layers.Add(currentLayer); + layerIx++; + currentLayer = new() { ix = layerIx }; + } + + AddToLayer(currentLayer, selectedNucleus); + this.layers.Add(currentLayer); + Debug.Log($"layer {layerIx} nucleus {selectedNucleus.name}"); + + layerIx++; + currentLayer = new() { ix = layerIx }; + + int six = 0; + // foreach (Synapse synapse in selectedNucleus.synapses.Values) { + // Debug.Log($"Synapse {six}"); + // Nucleus input = synapse.neuroid; + //foreach ((Nucleus input, Synapse synapse) in selectedNucleus.synapses) { + //foreach ((Nucleus input, float weight) in selectedNucleus.synapses) { + foreach (Synapse synapse in selectedNucleus.synapses) { + Nucleus input = synapse.nucleus; + if (input != null) { + AddToLayer(currentLayer, input); + Debug.Log($"layer {layerIx} nucleus {input.name}"); + } + six++; + } + if (currentLayer.neuroids.Count > 0) { + this.layers.Add(currentLayer); + } + } + + private void BuildLayers_old(List neuroids) { + if (neuroids == null) + return; + + // A temporary list to track what's been added to layers + this.layers = new(); + HashSet neuronVisited = new(); + int layerIx = 0; + + // While there are unvisited neuroid + while (neuroids.Any(neuroid => !neuronVisited.Contains(neuroid))) { + // Create the next layer + NeuroidLayer currentLayer = new() { ix = layerIx }; + int neuroidIx = 0; + + foreach (Neuroid neuroid in neuroids) { + // Skip neurons we already processed + if (neuronVisited.Contains(neuroid)) + continue; + + // if (neuroid.IsStale()) { + // Debug.Log($"neuron {neuroid.name} is stale {neuroid.stale}"); + // neuronVisited.Add(neuroid); + // continue; + // } + + // If the output neuroid is visited + // Note: this does not yet work for multiple outputs yet (see the use of First()) + // if (neuroid.receivers.Count == 0 // make sure the root neuroids are processed directly + // || (neuronVisited.Contains(neuroid.receivers.First()) && neuroid.receivers.First().layerIx == layerIx - 1)) { + if (neuroid.receivers.Count == 0 // make sure the root neuroids are processed directly + || (neuronVisited.Contains(neuroid.receivers.First().nucleus) && neuroid.receivers.First().nucleus.layerIx == layerIx - 1)) { + // Add it to the next layer + currentLayer.neuroids.Add(neuroid); + neuroid.layerIx = layerIx; + // Register it as visited + neuronVisited.Add(neuroid); + // Store its position + Vector2Int neuroidPosition = new(layerIx, neuroidIx); + neuroidPositions[neuroid] = neuroidPosition; + neuroidIx++; + Debug.Log($"Layer {layerIx} neuron {neuroidIx} name {neuroid.name}"); + } + } + + if (currentLayer.neuroids.Count > 0) { + this.layers.Add(currentLayer); + layerIx++; + } + } + } + + private void OnDisable() { + EditorApplication.update -= EditorUpdate; + Selection.selectionChanged -= OnSelectionChange; + } + + private void OnSelectionChange() { + SelectNeuron(); + Repaint(); + } + + private void EditorUpdate() { + if (EditorApplication.isPlaying) + Repaint(); + } + + private void OnGUI() { + GUILayout.Label("Graph Visualizer", EditorStyles.boldLabel); + + DrawGraph(); + } + + private void DrawGraph() { + if (currentNucleus == null) + return; + + foreach (NeuroidLayer layer in layers) + DrawLayer(layer); + } + + private void DrawLayer(NeuroidLayer layer) { + int column = layer.ix * 100; + int nodeCount = layer.neuroids.Count; + float maxValue = 0; + foreach (Nucleus nucleus in layer.neuroids) { + if (nucleus is Neuroid neuroid) { + float value = neuroid.outputValue.magnitude; + if (value > maxValue) + maxValue = value; + } + } + float spacing = 400f / nodeCount; + float margin = 100 + spacing / 2; + foreach (Nucleus layerNucleus in layer.neuroids) { + if (layerNucleus is Neuroid layerNeuroid) { + Vector2Int layerNeuroidPos = this.neuroidPositions[layerNeuroid]; + Vector3 parentPos = new(100 + layerNeuroidPos.x * 100, margin + layerNeuroidPos.y * spacing, 0.1f); + + int i = 0; + float inputSpacing = 400f / layerNeuroid.synapses.Count; + float inputMargin = 100 + inputSpacing / 2; + // foreach (Synapse synapse in layerNeuroid.synapses.Values) { + // if (synapse.neuroid != null) { + // if (this.neuroidPositions.ContainsKey(synapse.neuroid)) { + + // Vector2Int inputNeuroidPos = this.neuroidPositions[synapse.neuroid]; + //foreach ((Nucleus neuroid, Synapse synapse) in layerNeuroid.synapses) { + //foreach ((Nucleus neuroid, float weight) in layerNeuroid.synapses) { + foreach (Synapse synapse in layerNeuroid.synapses) { + Nucleus neuroid = synapse.nucleus; + float weight = synapse.weight; + if (neuroid != null) { + if (this.neuroidPositions.ContainsKey(neuroid)) { + Vector2Int inputNeuroidPos = this.neuroidPositions[neuroid]; + if (inputNeuroidPos.x == layerNeuroidPos.x + 1) { + Vector3 pos = new(100 + inputNeuroidPos.x * 100, inputMargin + inputNeuroidPos.y * inputSpacing, 0.0f); + + //float brightness = synapse.weight / 10.0f; + float brightness = weight / 10.0f; + Handles.color = new Color(brightness, brightness, brightness); + Handles.DrawLine(parentPos, pos); + } + } + } + } + + float size = 20; + if (layerNeuroid.isSleeping) + Handles.color = Color.black; + else { + float brightness = layerNeuroid.outputValue.magnitude / maxValue; + Handles.color = new Color(brightness, brightness, brightness); + } + Handles.DrawSolidDisc(parentPos, Vector3.forward, size); + Vector3 labelPos = parentPos - Vector3.down * (size + 0.2f); // below disc along up axis + GUIStyle style = new GUIStyle(EditorStyles.label) { + alignment = TextAnchor.UpperCenter, + normal = { textColor = Color.white }, + fontStyle = FontStyle.Bold + }; + Handles.Label(labelPos, layerNeuroid.name, style); + + Rect neuronRect = new(parentPos.x - size, parentPos.y - size, size * 2, size * 2); + Event e = Event.current; + if (e != null && neuronRect.Contains(e.mousePosition)) { + HandleMouseHover(layerNeuroid, neuronRect); + // Process click + if (e.type == EventType.MouseDown && e.button == 0) { + // Consume the event so the scene doesn't also handle it + e.Use(); + HandleDiscClicked(layerNeuroid); + } + } + i++; + } + } + } + + private void HandleMouseHover(Neuroid neuroid, Rect rect) { + GUIContent tooltip; + // if (neuroid is SensoryNeuroid sensoryNeuroid) { + // tooltip = new( + // $"{sensoryNeuroid.name}" + + // $"\nThing {sensoryNeuroid.receptor.thingType}" + + // $"\nValue: {neuroid.outputValue}"); + // } + // else { + tooltip = new( + $"{neuroid.name}" + + $"\nsynapse count {neuroid.synapses.Count}" + + $"\nValue: {neuroid.outputValue}"); + // } + + Vector2 mousePosition = Event.current.mousePosition; + + // Display tooltip with some offset + Vector2 tooltipSize = GUI.skin.box.CalcSize(tooltip); + Rect tooltipRect = new Rect(mousePosition.x + 10, mousePosition.y + 10, tooltipSize.x, tooltipSize.y); + + GUI.Box(tooltipRect, tooltip); + } + + private void HandleDiscClicked(Nucleus nucleus) { + this.currentNucleus = nucleus; + BuildLayers(); + } + + // Update node colors based on selected GameObjects + private void SelectNeuron() { + GameObject[] selectedObjects = Selection.gameObjects; + if (selectedObjects.Length == 0) + return; + + GameObject selectedObject = selectedObjects[0]; + Boid boid = selectedObject.GetComponent(); + if (boid == null) + return; + + // Nucleus neuroid = boid.behaviour; + // this.currentNucleus = neuroid; + // if (neuroid == null) + // this.allNeuroids = new(); + // else + // this.allNeuroids = neuroid.brain.neuroids; + + + // Debug.Log($"Neuroncount = {this.allNeuroids.Count}"); + // BuildLayers(); + // Debug.Log($"Layercount = {this.layers.Count}"); + + } + + [MenuItem("Window/Neuroid Visualizer")] + public static void ShowWindow() { + GetWindow("Neuroid Visualizer"); + } +} +*/ \ No newline at end of file diff --git a/Editor/NeuroidWindow.cs.meta b/Editor/NeuroidWindow.cs.meta new file mode 100644 index 0000000..a8a1aa1 --- /dev/null +++ b/Editor/NeuroidWindow.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 26e68838038ea5243ae57bc81f4db8a8 \ No newline at end of file diff --git a/INucleus.cs b/INucleus.cs new file mode 100644 index 0000000..f7272f3 --- /dev/null +++ b/INucleus.cs @@ -0,0 +1,54 @@ +using System.Collections.Generic; +using Unity.Mathematics; + +public interface INucleus : IReceptor { + + #region static struct + + // Cluster + public ClusterPrefab cluster { get; } + + // Senders + public List synapses { get; } + public Synapse AddSynapse(IReceptor sender); + + public NucleusArray array { get; set; } + + #endregion static struct + + #region dynamic state + + public void UpdateState(); + public void UpdateState(float3 inputValue); + + + #endregion dynamic state +} + +public interface IReceptor { + #region static + + public string name { get; set; } + + // Receivers + public List receivers { get; set; } + + public void AddReceiver(INucleus receiver); + public void RemoveReceiver(INucleus receiverNucleus); + + #endregion static + + #region dynamic + + // float3 to prepare for SIMD + public float3 outputValue { get; } + + public void UpdateNuclei(); + public bool isSleeping { get; } + + #endregion dynamic + + //public IReceptor CloneTo(ClusterPrefab parent); + public IReceptor Clone(); +} + diff --git a/INucleus.cs.meta b/INucleus.cs.meta new file mode 100644 index 0000000..aed95bb --- /dev/null +++ b/INucleus.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 6a8a0e8965cea660abff254cab8a4723 \ No newline at end of file diff --git a/Identity.asset b/Identity.asset new file mode 100644 index 0000000..076c284 --- /dev/null +++ b/Identity.asset @@ -0,0 +1,60 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3} + m_Name: Identity + m_EditorClassIdentifier: Assembly-CSharp::Cluster + nuclei: + - rid: 2243601383627161705 + references: + version: 2 + RefIds: + - rid: 2243601383627161705 + type: {class: Neuron, ns: , asm: Assembly-CSharp} + data: + _name: Output + _synapses: [] + _receivers: [] + _array: + rid: 2243601383627161706 + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1000 + value: 1000 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + - rid: 2243601383627161706 + type: {class: NucleusArray, ns: , asm: Assembly-CSharp} + data: + _nuclei: + - rid: 2243601383627161705 + name: Output diff --git a/Identity.asset.meta b/Identity.asset.meta new file mode 100644 index 0000000..b2382a6 --- /dev/null +++ b/Identity.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5f4d2ea0d0115b3549f8e9aa5e669163 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/LinearAlgebra.meta b/LinearAlgebra.meta new file mode 100644 index 0000000..c54c1af --- /dev/null +++ b/LinearAlgebra.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d98555a675e8e5e879de17db950b55fe +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/LinearAlgebra/.editorconfig b/LinearAlgebra/.editorconfig new file mode 100644 index 0000000..1ec7f97 --- /dev/null +++ b/LinearAlgebra/.editorconfig @@ -0,0 +1,19 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = crlf +charset = utf-8 +trim_trailing_whitespace = false +insert_final_newline = false +max_line_length = 80 + +[*.cs] +csharp_new_line_before_open_brace = none +# Suppress warnings everywhere +dotnet_diagnostic.IDE1006.severity = none +dotnet_diagnostic.IDE0130.severity = none \ No newline at end of file diff --git a/LinearAlgebra/.gitea/workflows/unit_tests.yaml b/LinearAlgebra/.gitea/workflows/unit_tests.yaml new file mode 100644 index 0000000..e98b26e --- /dev/null +++ b/LinearAlgebra/.gitea/workflows/unit_tests.yaml @@ -0,0 +1,37 @@ +name: Build and Run C# Unit Tests + +on: + push: + branches: + - '**' + pull_request: + branches: + - '**' + +jobs: + build-and-test: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Setup .NET + uses: actions/setup-dotnet@v1 + with: + dotnet-version: '8.0.x' # Specify the .NET SDK version + + - name: Check Current Directory + run: pwd # Logs the current working directory + + - name: List Files + run: ls -la # Lists all files in the current directory + + - name: Restore Dependencies + run: dotnet restore ./LinearAlgebra-csharp.sln # Restore NuGet packages + + - name: Build the Project + run: dotnet build ./LinearAlgebra-csharp.sln --configuration Release # Build the C# project + + - name: Run Unit Tests + run: dotnet test ./test/LinearAlgebra_Test.csproj --configuration Release # Execute unit tests diff --git a/LinearAlgebra/.gitignore b/LinearAlgebra/.gitignore new file mode 100644 index 0000000..b32a30c --- /dev/null +++ b/LinearAlgebra/.gitignore @@ -0,0 +1,5 @@ +DoxyGen/DoxyWarnLogfile.txt +.vscode/settings.json +**bin +**obj +**.meta diff --git a/LinearAlgebra/LinearAlgebra-csharp.sln b/LinearAlgebra/LinearAlgebra-csharp.sln new file mode 100644 index 0000000..4b13b2b --- /dev/null +++ b/LinearAlgebra/LinearAlgebra-csharp.sln @@ -0,0 +1,30 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.2.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LinearAlgebra", "src\LinearAlgebra.csproj", "{ECB58727-0354-924D-AE7B-22F6B21097EB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LinearAlgebra_Test", "test\LinearAlgebra_Test.csproj", "{715BB399-5FC4-2AC9-3757-177CA0C80774}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {ECB58727-0354-924D-AE7B-22F6B21097EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ECB58727-0354-924D-AE7B-22F6B21097EB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ECB58727-0354-924D-AE7B-22F6B21097EB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ECB58727-0354-924D-AE7B-22F6B21097EB}.Release|Any CPU.Build.0 = Release|Any CPU + {715BB399-5FC4-2AC9-3757-177CA0C80774}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {715BB399-5FC4-2AC9-3757-177CA0C80774}.Debug|Any CPU.Build.0 = Debug|Any CPU + {715BB399-5FC4-2AC9-3757-177CA0C80774}.Release|Any CPU.ActiveCfg = Release|Any CPU + {715BB399-5FC4-2AC9-3757-177CA0C80774}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {E93B8294-87D4-4887-83B7-182A623D5833} + EndGlobalSection +EndGlobal diff --git a/LinearAlgebra/src/Angle.cs b/LinearAlgebra/src/Angle.cs new file mode 100644 index 0000000..7d2fd6b --- /dev/null +++ b/LinearAlgebra/src/Angle.cs @@ -0,0 +1,341 @@ +using System; + +namespace LinearAlgebra { + + public struct AngleFloat { + public const float Rad2Deg = 360.0f / ((float)Math.PI * 2); //0.0174532924F; + public const float Deg2Rad = (float)Math.PI * 2 / 360.0f; //57.29578F; + + private AngleFloat(float degrees) { + this.value = degrees; + } + private readonly float value; + + public static AngleFloat Degrees(float degrees) { + // Reduce it to (-180..180] + if (float.IsFinite(degrees)) { + while (degrees < -180) + degrees += 360; + while (degrees >= 180) + degrees -= 360; + } + return new AngleFloat(degrees); + } + + public static AngleFloat Radians(float radians) { + // Reduce it to (-pi..pi] + if (float.IsFinite(radians)) { + while (radians <= -Math.PI) + radians += 2 * (float)Math.PI; + while (radians > Math.PI) + radians -= 2 * (float)Math.PI; + } + + return new AngleFloat(radians * Rad2Deg); + } + + public static AngleFloat Revolutions(float revolutions) { + // reduce it to (-0.5 .. 0.5] + if (float.IsFinite(revolutions)) { + // Get the integer part + int integerPart = (int)revolutions; + + // Get the decimal part + revolutions -= integerPart; + if (revolutions < -0.5) + revolutions += 1; + if (revolutions >= 0.5) + revolutions -= 1; + } + return new AngleFloat(revolutions * 360); + } + + public readonly float inDegrees => this.value; + + public readonly float inRadians => this.value * Deg2Rad; + + public readonly float inRevolutions => this.value / 360.0f; + + public override string ToString() { + return $"{this.inDegrees}\u00B0"; + } + + public static readonly AngleFloat zero = Degrees(0); + public static readonly AngleFloat deg90 = Degrees(90); + public static readonly AngleFloat deg180 = Degrees(180); + + /// + /// Get the sign of the angle + /// + /// The angle + /// -1 when the angle is negative, 1 when it is positive and 0 in all other cases + public static int Sign(AngleFloat a) { + if (a.value < 0) + return -1; + if (a.value > 0) + return 1; + return 0; + } + + /// + /// Returns the magnitude of the angle + /// + /// The angle + /// The positive magnitude of the angle + /// Negative values are negated to get a positive result + public static AngleFloat Abs(AngleFloat a) { + if (Sign(a) < 0) + return -a; + else + return a; + } + + /// + /// Tests the equality of two angles + /// + /// + /// + /// True when the angles are equal, false otherwise + /// The equality is determine within the limits of precision of a float + public static bool operator ==(AngleFloat a1, AngleFloat a2) { + return a1.value == a2.value; + } + + /// + /// Tests the inequality of two angles + /// + /// + /// + /// True when the angles are not equal, false otherwise + /// The equality is determine within the limits of precision of a float + public static bool operator !=(AngleFloat a1, AngleFloat a2) { + return a1.value != a2.value; + } + + public override readonly bool Equals(object obj) { + if (obj is AngleFloat other) { + return this == other; + } + return false; + } + + public override readonly int GetHashCode() { + return this.value.GetHashCode(); + } + + + /// + /// Tests if the first angle is greater than the second + /// + /// + /// + /// True when a1 is greater than a2, False otherwise + public static bool operator >(AngleFloat a1, AngleFloat a2) { + return a1.value > a2.value; + } + + /// + /// Tests if the first angle is greater than or equal to the second + /// + /// + /// + /// True when a1 is greater than or equal to a2, False otherwise + public static bool operator >=(AngleFloat a1, AngleFloat a2) { + return a1.value >= a2.value; + } + + /// + /// Tests if the first angle is less than the second + /// + /// + /// + /// True when a1 is less than a2, False otherwise + public static bool operator <(AngleFloat a1, AngleFloat a2) { + return a1.value < a2.value; + } + + /// + /// Tests if the first angle is less than or equal to the second + /// + /// + /// + /// True when a1 is less than or equal to a2, False otherwise + public static bool operator <=(AngleFloat a1, AngleFloat a2) { + return a1.value <= a2.value; + } + + /// + /// Negate the angle + /// + /// The angle + /// The negated angle + /// The negation of -180 is still -180 because the range is (-180..180] + public static AngleFloat operator -(AngleFloat a) { + AngleFloat r = new(-a.value); + return r; + } + + /// + /// Subtract two angles + /// + /// Angle 1 + /// Angle 2 + /// The result of the subtraction + public static AngleFloat operator -(AngleFloat a1, AngleFloat a2) { + AngleFloat r = new(a1.value - a2.value); + return r; + } + /// + /// Add two angles + /// + /// Angle 1 + /// Angle 2 + /// The result of the addition + public static AngleFloat operator +(AngleFloat a1, AngleFloat a2) { + AngleFloat r = new(a1.value + a2.value); + return r; + } + + /// + /// Multiplies the angle + /// + /// The angle to multiply + /// The factor by which the angle is multiplied + /// The multiplied angle + public static AngleFloat operator *(AngleFloat a, float factor) { + return Degrees(a.inDegrees * factor); + } + public static AngleFloat operator *(float factor, AngleFloat a) { + return Degrees(factor * a.inDegrees); + } + + /// + /// Clamp the angle between the given min and max values + /// + /// The angle to clamp + /// The minimum angle + /// The maximum angle + /// The clamped angle + /// Angles are normalized + public static float Clamp(AngleFloat angle, AngleFloat min, AngleFloat max) { + return Float.Clamp(angle.inDegrees, min.inDegrees, max.inDegrees); + } + + /// @brief Calculates the cosine of an angle + /// @param angle The given angle + /// @return The cosine of the angle + public static float Cos(AngleFloat angle) { + return MathF.Cos(angle.inRadians); + } + /// @brief Calculates the sine of an angle + /// @param angle The given angle + /// @return The sine of the angle + public static float Sin(AngleFloat angle) { + return MathF.Sin(angle.inRadians); + } + /// @brief Calculates the tangent of an angle + /// @param angle The given angle + /// @return The tangent of the angle + public static float Tan(AngleFloat angle) { + return MathF.Tan(angle.inRadians); + } + + /// @brief Calculates the arc cosine angle + /// @param f The value + /// @return The arc cosine for the given value + public static AngleFloat Acos(float f) { + return Radians(MathF.Acos(f)); + } + /// @brief Calculates the arc sine angle + /// @param f The value + /// @return The arc sine for the given value + public static AngleFloat Asin(float f) { + return Radians(MathF.Asin(f)); + } + /// @brief Calculates the arc tangent angle + /// @param f The value + /// @return The arc tangent for the given value + public static AngleFloat Atan(float f) { + return Radians(MathF.Atan(f)); + } + /// @brief Calculates the tangent for the given values + /// @param y The vertical value + /// @param x The horizontal value + /// @return The tanget for the given values + /// Uses the y and x signs to compute the quadrant + public static AngleFloat Atan2(float y, float x) { + return Radians(MathF.Atan2(y, x)); + } + + /// + /// Rotate from one angle to the other with a maximum degrees + /// + /// Starting angle + /// Target angle + /// Maximum angle to rotate + /// The resulting angle + /// This function is compatible with radian and degrees angles + public static AngleFloat MoveTowards(AngleFloat fromAngle, AngleFloat toAngle, float maxDegrees) { + maxDegrees = Math.Max(0, maxDegrees); // filter out negative distances + AngleFloat d = toAngle - fromAngle; + float dDegrees = Abs(d).inDegrees; + d = Degrees(Float.Clamp(dDegrees, 0, maxDegrees)); + if (Sign(d) < 0) + d = -d; + return fromAngle + d; + } + } + + + /// + /// %Angle utilities + /// + public static class Angles { + public const float pi = 3.1415927410125732421875F; + // public static float Rad2Deg = 360.0f / ((float)Math.PI * 2); + // public static float Deg2Rad = ((float)Math.PI * 2) / 360.0f; + + + /// + /// Determine the angle difference, result is a normalized angle + /// + /// First first angle + /// The second angle + /// the angle between the two angles + /// Angle values should be degrees + public static float Difference(float a, float b) { + float r = Normalize(b - a); + return r; + } + + /// + /// Normalize an angle to the range -180 < angle <= 180 + /// + /// The angle to normalize + /// The normalized angle in interval (-180..180] + /// Angle values should be in degrees + public static float Normalize(float angle) { + if (float.IsInfinity(angle)) + return angle; + + while (angle <= -180) angle += 360; + while (angle > 180) angle -= 360; + return angle; + } + + /// + /// Map interval of angles between vectors [0..Pi] to interval [0..1] + /// + /// The first vector + /// The second vector + /// The resulting factor in interval [0..1] + /// Vectors a and b must be normalized + /// \deprecated Please use Vector2.ToFactor instead. + // [Obsolete("Please use Vector2.ToFactor instead.")] + // public static float ToFactor(Vector2Float v1, Vector2Float v2) { + // return (1 - Vector2Float.Dot(v1, v2)) / 2; + // } + + } + +} \ No newline at end of file diff --git a/LinearAlgebra/src/Decomposition.cs b/LinearAlgebra/src/Decomposition.cs new file mode 100644 index 0000000..ddaf434 --- /dev/null +++ b/LinearAlgebra/src/Decomposition.cs @@ -0,0 +1,287 @@ +using System; +namespace LinearAlgebra { + class QR { + // QR Decomposition of a matrix A + public static (Matrix2 Q, Matrix2 R) Decomposition(Matrix2 A) { + int nRows = A.nRows; + int nCols = A.nCols; + + float[,] Q = new float[nRows, nCols]; + float[,] R = new float[nCols, nCols]; + + // Perform Gram-Schmidt orthogonalization + for (uint colIx = 0; colIx < nCols; colIx++) { + + // Step 1: v = column(ix) of A + float[] v = new float[nRows]; + for (int rowIx = 0; rowIx < nRows; rowIx++) + v[rowIx] = A.data[rowIx, colIx]; + + // Step 2: Subtract projections of v onto previous q's (orthogonalize) + for (uint colIx2 = 0; colIx2 < colIx; colIx2++) { + float dotProd = 0; + for (int i = 0; i < nRows; i++) + dotProd += Q[i, colIx2] * v[i]; + for (int i = 0; i < nRows; i++) + v[i] -= dotProd * Q[i, colIx2]; + } + + // Step 3: Normalize v to get column(ix) of Q + float norm = 0; + for (int rowIx = 0; rowIx < nRows; rowIx++) + norm += v[rowIx] * v[rowIx]; + norm = (float)Math.Sqrt(norm); + + for (int rowIx = 0; rowIx < nRows; rowIx++) + Q[rowIx, colIx] = v[rowIx] / norm; + + // Store the coefficients of R + for (int colIx2 = 0; colIx2 <= colIx; colIx2++) { + R[colIx2, colIx] = 0; + for (int k = 0; k < nRows; k++) + R[colIx2, colIx] += Q[k, colIx2] * A.data[k, colIx]; + } + } + return (new Matrix2(Q), new Matrix2(R)); + } + + // Reduced QR Decomposition of a matrix A + public static (Matrix2 Q, Matrix2 R) ReducedDecomposition(Matrix2 A) { + int nRows = A.nRows; + int nCols = A.nCols; + + float[,] Q = new float[nRows, nCols]; + float[,] R = new float[nCols, nCols]; + + // Perform Gram-Schmidt orthogonalization + for (int colIx = 0; colIx < nCols; colIx++) { + + // Step 1: v = column(colIx) of A + float[] columnIx = new float[nRows]; + bool isZeroColumn = true; + for (int rowIx = 0; rowIx < nRows; rowIx++) { + columnIx[rowIx] = A.data[rowIx, colIx]; + if (columnIx[rowIx] != 0) + isZeroColumn = false; + } + if (isZeroColumn) { + for (int rowIx = 0; rowIx < nRows; rowIx++) + Q[rowIx, colIx] = 0; + // Set corresponding R element to 0 + R[colIx, colIx] = 0; + + Console.WriteLine($"zero column {colIx}"); + + continue; + } + + // Step 2: Subtract projections of v onto previous q's (orthogonalize) + for (int colIx2 = 0; colIx2 < colIx; colIx2++) { + // Compute the dot product of v and column(colIx2) of Q + float dotProduct = 0; + for (int rowIx2 = 0; rowIx2 < nRows; rowIx2++) + dotProduct += columnIx[rowIx2] * Q[rowIx2, colIx2]; + // Subtract the projection from v + for (int rowIx2 = 0; rowIx2 < nRows; rowIx2++) + columnIx[rowIx2] -= dotProduct * Q[rowIx2, colIx2]; + } + + // Step 3: Normalize v to get column(colIx) of Q + float norm = 0; + for (int rowIx = 0; rowIx < nRows; rowIx++) + norm += columnIx[rowIx] * columnIx[rowIx]; + if (norm == 0) + throw new Exception("invalid value"); + + norm = (float)Math.Sqrt(norm); + + for (int rowIx = 0; rowIx < nRows; rowIx++) + Q[rowIx, colIx] = columnIx[rowIx] / norm; + + // Here is where it deviates from the Full QR Decomposition ! + + // Step 4: Compute the row(colIx) of R + for (int colIx2 = colIx; colIx2 < nCols; colIx2++) { + float dotProduct = 0; + for (int rowIx2 = 0; rowIx2 < nRows; rowIx2++) + dotProduct += Q[rowIx2, colIx] * A.data[rowIx2, colIx2]; + R[colIx, colIx2] = dotProduct; + } + } + if (!float.IsFinite(R[0, 0])) + throw new Exception("invalid value"); + + return (new Matrix2(Q), new Matrix2(R)); + } + } + + class SVD { + // According to ChatGPT, Mathnet uses Golub-Reinsch SVD algorithm + // 1. Bidiagonalization: The input matrix AA is reduced to a bidiagonal form using Golub-Kahan bidiagonalization. + // This process involves applying a sequence of Householder reflections to AA to create a bidiagonal matrix. + // This step reduces the complexity by making the matrix simpler while retaining the essential structure needed for SVD. + // + // 2. Diagonalization: Once the matrix is in bidiagonal form, + // the singular values are computed using an iterative process + // (typically involving QR factorization or Jacobi rotations) until convergence. + // This process diagonalizes the bidiagonal matrix and allows extraction of the singular values. + // + // 3. Computing UU and VTVT: After obtaining the singular values, + // the left singular vectors UU and right singular vectors VTVT are computed + // using the accumulated transformations (such as Householder reflections) from the bidiagonalization step. + + // Bidiagnolizations through Householder transformations + public static (Matrix2 U1, Matrix2 B, Matrix2 V1) Bidiagonalization(Matrix2 A) { + int m = A.nRows; // Rows of A + int n = A.nCols; // Columns of A + float[,] U1 = new float[m, m]; // Left orthogonal matrix + float[,] V1 = new float[n, n]; // Right orthogonal matrix + float[,] B = A.Clone().data; // Copy A to B for transformation + + // Initialize U1 and V1 as identity matrices + for (int i = 0; i < m; i++) + U1[i, i] = 1; + for (int i = 0; i < n; i++) + V1[i, i] = 1; + + // Perform Householder reflections to create a bidiagonal matrix B + for (int j = 0; j < n; j++) { + // Step 1: Construct the Householder vector y + float[] y = new float[m - j]; + for (int i = j; i < m; i++) + y[i - j] = B[i, j]; + + // Step 2: Compute the norm and scalar alpha + float norm = 0; + for (int i = 0; i < y.Length; i++) + norm += y[i] * y[i]; + norm = (float)Math.Sqrt(norm); + + if (B[j, j] > 0) + norm = -norm; + + float alpha = (float)Math.Sqrt(0.5 * (norm * (norm - B[j, j]))); + float r = (float)Math.Sqrt(0.5 * (norm * (norm + B[j, j]))); + + // Step 3: Apply the reflection to zero out below diagonal + for (int k = j; k < n; k++) { + float dot = 0; + for (int i = j; i < m; i++) + dot += y[i - j] * B[i, k]; + dot /= r; + + for (int i = j; i < m; i++) + B[i, k] -= 2 * dot * y[i - j]; + } + + // Step 4: Update U1 with the Householder reflection (U1 * Householder) + for (int i = j; i < m; i++) + U1[i, j] = y[i - j] / alpha; + + // Step 5: Update V1 (storing the Householder vector y) + // Correct indexing: we only need to store part of y in V1 from index j to n + for (int i = j; i < n; i++) + V1[j, i] = B[j, i]; + + // Repeat steps for further columns if necessary + } + return (new Matrix2(U1), new Matrix2(B), new Matrix2(V1)); + } + + public static Matrix2 Bidiagonalize(Matrix2 A) { + int m = A.nRows; // Rows of A + int n = A.nCols; // Columns of A + float[,] B = A.Clone().data; // Copy A to B for transformation + + // Perform Householder reflections to create a bidiagonal matrix B + for (int j = 0; j < n; j++) { + // Step 1: Construct the Householder vector y + float[] y = new float[m - j]; + for (int i = j; i < m; i++) + y[i - j] = B[i, j]; + + // Step 2: Compute the norm and scalar alpha + float norm = 0; + for (int i = 0; i < y.Length; i++) + norm += y[i] * y[i]; + norm = (float)Math.Sqrt(norm); + + if (B[j, j] > 0) + norm = -norm; + + float r = (float)Math.Sqrt(0.5 * (norm * (norm + B[j, j]))); + + // Step 3: Apply the reflection to zero out below diagonal + for (int k = j; k < n; k++) { + float dot = 0; + for (int i = j; i < m; i++) + dot += y[i - j] * B[i, k]; + dot /= r; + + for (int i = j; i < m; i++) + B[i, k] -= 2 * dot * y[i - j]; + } + + // Repeat steps for further columns if necessary + } + return new Matrix2(B); + } + + // QR Iteration for diagonalization of a bidiagonal matrix B + public static (Matrix1 singularValues, Matrix2 U, Matrix2 Vt) QRIteration(Matrix2 B) { + int m = B.nRows; + int n = B.nCols; + + Matrix2 U = new(m, m); // Left singular vectors (U) + Matrix2 Vt = new(n, n); // Right singular vectors (V^T) + float[] singularValues = new float[Math.Min(m, n)]; // Singular values + + // Initialize U and Vt as identity matrices + for (int i = 0; i < m; i++) + U.data[i, i] = 1; + for (int i = 0; i < n; i++) + Vt.data[i, i] = 1; + + // Perform QR iterations + float tolerance = 1e-7f; //1e-12f; for double + bool converged = false; + while (!converged) { + // Perform QR decomposition on the matrix B + (Matrix2 Q, Matrix2 R) = QR.Decomposition(B); + + // Update B to be the product Q * R //R * Q + B = R * Q; + + // Accumulate the transformations in U and Vt + U *= Q; + Vt *= R; + + // Check convergence by looking at the off-diagonal elements of B + converged = true; + for (int i = 0; i < m - 1; i++) { + for (int j = i + 1; j < n; j++) { + if (Math.Abs(B.data[i, j]) > tolerance) { + converged = false; + break; + } + } + } + } + + // Extract singular values (diagonal elements of B) + for (int i = 0; i < Math.Min(m, n); i++) + singularValues[i] = B.data[i, i]; + + return (new Matrix1(singularValues), U, Vt); + } + + public static (Matrix2 U, Matrix1 S, Matrix2 Vt) Decomposition(Matrix2 A) { + if (A.nRows != A.nCols) + throw new ArgumentException("SVD: matrix A has to be square."); + + Matrix2 B = Bidiagonalize(A); + (Matrix1 S, Matrix2 U, Matrix2 Vt) = QRIteration(B); + return (U, S, Vt); + } + } +} \ No newline at end of file diff --git a/LinearAlgebra/src/Direction.cs b/LinearAlgebra/src/Direction.cs new file mode 100644 index 0000000..fd25b98 --- /dev/null +++ b/LinearAlgebra/src/Direction.cs @@ -0,0 +1,261 @@ +using System; +#if UNITY_5_3_OR_NEWER +using Vector3Float = UnityEngine.Vector3; +#endif + +namespace LinearAlgebra +{ + + /// + /// A direction in 3D space + /// + /// A direction is represented using two angles: + /// * The horizontal angle ranging from -180 (inclusive) to 180 (exclusive) + /// degrees which is a rotation in the horizontal plane + /// * A vertical angle ranging from -90 (inclusive) to 90 (exclusive) degrees + /// which is the rotation in the up/down direction applied after the horizontal + /// rotation has been applied. + /// The angles are automatically normalized to stay within the abovenmentioned + /// ranges. + public struct Direction + { + /// @brief horizontal angle, range = (-180..180] degrees + public AngleFloat horizontal; + /// @brief vertical angle, range in degrees = (-90..90] degrees + public AngleFloat vertical; + + /// + /// Create a new direction + /// + /// The horizontal angle + /// The vertical angle + /// The direction will be normalized automatically + /// to ensure the angles are within the allowed ranges + public Direction(AngleFloat horizontal, AngleFloat vertical) + { + this.horizontal = horizontal; + this.vertical = vertical; + this.Normalize(); + } + + /// + /// Create a direction using angle values in degrees + /// + /// The horizontal angle in degrees + /// The vertical angle in degrees + /// The direction + /// The direction will be normalized automatically + /// to ensure the angles are within the allowed ranges + public static Direction Degrees(float horizontal, float vertical) + { + Direction d = new() + { + horizontal = AngleFloat.Degrees(horizontal), + vertical = AngleFloat.Degrees(vertical) + }; + d.Normalize(); + return d; + } + /// + /// Create a direction using angle values in radians + /// + /// The horizontal angle in radians + /// The vertical angle in radians + /// The direction + public static Direction Radians(float horizontal, float vertical) + { + Direction d = new() + { + horizontal = AngleFloat.Radians(horizontal), + vertical = AngleFloat.Radians(vertical) + }; + d.Normalize(); + return d; + } + + public override readonly string ToString() { + return $"Direction(h: {this.horizontal}, v: {this.vertical})"; + } + + /// + /// A forward direction with zero for both angles + /// + public readonly static Direction forward = Degrees(0, 0); + /// + /// A backward direction with horizontal angle -180 and zero vertical + /// angle + /// + public readonly static Direction backward = Degrees(-180, 0); + /// + /// A upward direction with zero horizontal angle and vertical angle 90 + /// + public readonly static Direction up = Degrees(0, 90); + /// + /// A downward direction with zero horizontal angle and vertical angle + /// -90 + /// + public readonly static Direction down = Degrees(0, -90); + /// + /// A left-pointing direction with horizontal angle -90 and zero + /// vertical angle + /// + public readonly static Direction left = Degrees(-90, 0); + /// + /// A right-pointing direction with horizontal angle 90 and zero + /// vertical angle + /// + public readonly static Direction right = Degrees(90, 0); + + private void Normalize() + { + if (this.vertical > AngleFloat.deg90 || this.vertical < -AngleFloat.deg90) + { + this.horizontal += AngleFloat.deg180; + this.vertical = AngleFloat.Degrees(180 - this.vertical.inDegrees); + } + } + +#if UNITY_5_3_OR_NEWER + /// + /// Convert the direction into a carthesian vector + /// + /// The carthesian vector corresponding to this direction. + public readonly UnityEngine.Vector3 ToVector3() { + // Convert degrees to radians + float radH = this.horizontal.inRadians; + float radV = this.vertical.inRadians; + + // Calculate Vector + float cosV = MathF.Cos(radV); + float sinV = MathF.Sin(radV); + + float x = cosV * MathF.Sin(radH); + float y = sinV; + float z = cosV * MathF.Cos(radH); + + return new UnityEngine.Vector3(x, y, z); + } + + /// + /// Convert a carthesian vector into a direction + /// + /// The carthesian vector + /// The direction + /// Information about the length of the carthesian vector is not + /// included in this transformation + public static Direction FromVector3(UnityEngine.Vector3 v) { + AngleFloat horizontal = AngleFloat.Atan2(v.x, v.z); + AngleFloat vertical = AngleFloat.deg90 - AngleFloat.Acos(v.y); + Direction d = new(horizontal, vertical); + return d; + } +#else + /// + /// Convert the direction into a carthesian vector + /// + /// The carthesian vector corresponding to this direction. + public readonly Vector3Float ToVector3() { + // Quaternion q = Quaternion.Euler(90 - this.vertical.inDegrees, this.horizontal.inDegrees, 0); + // Vector3Float v = q * Vector3Float.forward; + // return v; + + float radH = this.horizontal.inRadians; + float radV = this.vertical.inRadians; + + float cosV = MathF.Cos(radV); + float sinV = MathF.Sin(radV); + + float horizontal = cosV * MathF.Sin(radH); + float vertical = sinV; + float depth = cosV * MathF.Cos(radH); + + return new Vector3Float(horizontal, vertical, depth); + } + + /// + /// Convert a carthesian vector into a direction + /// + /// The carthesian vector + /// The direction + /// Information about the length of the carthesian vector is not + /// included in this transformation + public static Direction FromVector3(Vector3Float v) + { + AngleFloat horizontal = AngleFloat.Atan2(v.horizontal, v.depth); + AngleFloat vertical = AngleFloat.deg90 - AngleFloat.Acos(v.vertical); + Direction d = new(horizontal, vertical); + return d; + } +#endif + + public static Direction operator -(Direction d) { + AngleFloat horizontal = d.horizontal + AngleFloat.deg180; + AngleFloat vertical = -d.vertical; + return new Direction(horizontal, vertical); + } + + /// + /// Tests the equality of two directions + /// + /// + /// + /// True when the direction angles are equal, false otherwise. + public static bool operator ==(Direction d1, Direction d2) + { + bool horizontalEq = d1.horizontal == d2.horizontal; + bool verticalEq = d1.vertical == d2.vertical; + return horizontalEq && verticalEq; + } + + /// + /// Tests the inequality of two directions + /// + /// + /// + /// True when the direction angles are not equal, false otherwise. + public static bool operator !=(Direction d1, Direction d2) + { + bool horizontalNEq = d1.horizontal != d2.horizontal; + bool verticalNEq = d1.vertical != d2.vertical; + return horizontalNEq || verticalNEq; + } + + public override readonly bool Equals(object obj) + { + if (obj is not Direction d) + return false; + + bool horizontalEq = this.horizontal == d.horizontal; + bool verticalEq = this.vertical == d.vertical; + return horizontalEq && verticalEq; + } + + + public override readonly int GetHashCode() + { + return HashCode.Combine(horizontal, vertical); + } + + public static AngleFloat UnsignedAngle(Direction d1, Direction d2) { + // Convert angles from degrees to radians + float horizontal1Rad = d1.horizontal.inRadians; + float vertical1Rad = d1.vertical.inRadians; + + float horizontal2Rad = d2.horizontal.inRadians; + float vertical2Rad = d2.vertical.inRadians; + + // Calculate the cosine of the angle using the spherical law of cosines + float cosTheta = MathF.Sin(vertical1Rad) * MathF.Sin(vertical2Rad) + + MathF.Cos(vertical1Rad) * MathF.Cos(vertical2Rad) * + MathF.Cos(horizontal1Rad - horizontal2Rad); + + // Clip cosTheta to the valid range for acos + cosTheta = Float.Clamp(cosTheta, -1.0f, 1.0f); + + // Calculate the angle + AngleFloat angle = AngleFloat.Acos(cosTheta); + return angle; + } + } + +} \ No newline at end of file diff --git a/LinearAlgebra/src/Float.cs b/LinearAlgebra/src/Float.cs new file mode 100644 index 0000000..2217b84 --- /dev/null +++ b/LinearAlgebra/src/Float.cs @@ -0,0 +1,41 @@ +namespace LinearAlgebra { + + /// + /// Float number utilities + /// + public class Float { + /// + /// The precision of float numbers + /// + public const float epsilon = 1E-05f; + /// + /// The square of the float number precision + /// + public const float sqrEpsilon = 1e-10f; + + /// + /// Clamp the value between the given minimum and maximum values + /// + /// The value to clamp + /// The minimum value + /// The maximum value + /// The clamped value + public static float Clamp(float f, float min, float max) { + if (f < min) + return min; + if (f > max) + return max; + return f; + } + + /// + /// Clamp the value between to the interval [0..1] + /// + /// The value to clamp + /// The clamped value + public static float Clamp01(float f) { + return Clamp(f, 0, 1); + } + } + +} \ No newline at end of file diff --git a/LinearAlgebra/src/LinearAlgebra.csproj b/LinearAlgebra/src/LinearAlgebra.csproj new file mode 100644 index 0000000..d2d5a85 --- /dev/null +++ b/LinearAlgebra/src/LinearAlgebra.csproj @@ -0,0 +1,14 @@ + + + + false + false + net8.0 + + + + + + + + diff --git a/LinearAlgebra/src/Matrix.cs b/LinearAlgebra/src/Matrix.cs new file mode 100644 index 0000000..37c6c24 --- /dev/null +++ b/LinearAlgebra/src/Matrix.cs @@ -0,0 +1,689 @@ +using System; +#if UNITY_5_3_OR_NEWER +using Vector3Float = UnityEngine.Vector3; +using Vector2Float = UnityEngine.Vector2; +using Quaternion = UnityEngine.Quaternion; +#endif + +namespace LinearAlgebra { + + public readonly struct Slice + { + public int start { get; } + public int stop { get; } + public Slice(int start, int stop) + { + this.start = start; + this.stop = stop; + } + } + + public class Matrix2 { + public float[,] data { get; } + + public int nRows => data.GetLength(0); + public int nCols => data.GetLength(1); + + public Matrix2(int nRows, int nCols) + { + this.data = new float[nRows, nCols]; + } + public Matrix2(float[,] data) { + this.data = data; + } + + public Matrix2 Clone() { + float[,] data = new float[this.nRows, nCols]; + for (int rowIx = 0; rowIx < this.nRows; rowIx++) { + for (int colIx = 0; colIx < this.nCols; colIx++) + data[rowIx, colIx] = this.data[rowIx, colIx]; + } + return new Matrix2(data); + } + + public static Matrix2 Zero(int nRows, int nCols) + { + return new Matrix2(nRows, nCols); + } + + public static Matrix2 FromVector3(Vector3Float v) { + float[,] result = new float[3, 1]; + result[0, 0] = v.horizontal; + result[1, 0] = v.vertical; + result[2, 0] = v.depth; + return new Matrix2(result); + } + + public static Matrix2 Identity(int size) + { + return Diagonal(1, size); + } + public static Matrix2 Identity(int nRows, int nCols) + { + Matrix2 m = Zero(nRows, nCols); + m.FillDiagonal(1); + return m; + } + + public static Matrix2 Diagonal(Matrix1 v) { + float[,] resultData = new float[v.size, v.size]; + for (int ix = 0; ix < v.size; ix++) + resultData[ix, ix] = v.data[ix]; + return new Matrix2(resultData); + } + public static Matrix2 Diagonal(float f, int size) + { + float[,] resultData = new float[size, size]; + for (int ix = 0; ix < size; ix++) + resultData[ix, ix] = f; + return new Matrix2(resultData); + } + public void FillDiagonal(Matrix1 v) + { + int n = (int)Math.Min(Math.Min(this.nRows, this.nCols), v.size); + for (int ix = 0; ix < n; ix++) + this.data[ix, ix] = v.data[ix]; + } + public void FillDiagonal(float f) + { + int n = Math.Min(this.nRows, this.nCols); + for (int ix = 0; ix < n; ix++) + this.data[ix, ix] = f; + } + + public static Matrix2 SkewMatrix(Vector3Float v) { + float[,] result = new float[3, 3] { + {0, -v.depth, v.vertical}, + {v.depth, 0, -v.horizontal}, + {-v.vertical, v.horizontal, 0} + }; + return new Matrix2(result); + } + + public Matrix1 GetRow(int rowIx) { + float[] row = new float[this.nCols]; + for (int colIx = 0; colIx < this.nCols; colIx++) { + row[colIx] = this.data[rowIx, colIx]; + } + return new Matrix1(row); + } + +#if UNITY_5_3_OR_NEWER + public UnityEngine.Vector3 GetRow3(int rowIx) { + int cols = this.nCols; + UnityEngine.Vector3 row = new() { + x = this.data[rowIx, 0], + y = this.data[rowIx, 1], + z = this.data[rowIx, 2] + }; + return row; + } +#endif + public void SetRow(int rowIx, Matrix1 v) { + for (uint ix = 0; ix < v.size; ix++) + this.data[rowIx, ix] = v.data[ix]; + } + public void SetRow3(int rowIx, Vector3Float v) { + this.data[rowIx, 0] = v.horizontal; + this.data[rowIx, 1] = v.vertical; + this.data[rowIx, 2] = v.depth; + } + + public void SwapRows(int row1, int row2) { + for (uint ix = 0; ix < this.nCols; ix++) { + float temp = this.data[row1, ix]; + this.data[row1, ix] = this.data[row2, ix]; + this.data[row2, ix] = temp; + } + } + + public Matrix1 GetColumn(int colIx) + { + float[] column = new float[this.nRows]; + for (int i = 0; i < this.nRows; i++) { + column[i] = this.data[i, colIx]; + } + return new Matrix1(column); + } + public void SetColumn(int colIx, Matrix1 v) { + for (uint ix = 0; ix < v.size; ix++) + this.data[ix, colIx] = v.data[ix]; + } + public void SetColumn(int colIx, Vector3Float v) { + this.data[0, colIx] = v.horizontal; + this.data[1, colIx] = v.vertical; + this.data[2, colIx] = v.depth; + } + + public static bool AllClose(Matrix2 A, Matrix2 B, float atol = 1e-08f) { + for (int i = 0; i < A.nRows; i++) { + for (int j = 0; j < A.nCols; j++) { + float d = MathF.Abs(A.data[i, j] - B.data[i, j]); + if (d > atol) + return false; + } + } + return true; + } + + public Matrix2 Transpose() { + float[,] resultData = new float[this.nCols, this.nRows]; + for (uint rowIx = 0; rowIx < this.nRows; rowIx++) { + for (uint colIx = 0; colIx < this.nCols; colIx++) + resultData[colIx, rowIx] = this.data[rowIx, colIx]; + } + return new Matrix2(resultData); + // double checked code + } + public Matrix2 transposed { + get => Transpose(); + } + + public static Matrix2 operator -(Matrix2 m) { + float[,] result = new float[m.nRows, m.nCols]; + + for (int i = 0; i < m.nRows; i++) { + for (int j = 0; j < m.nCols; j++) + result[i, j] = -m.data[i, j]; + } + return new Matrix2(result); + } + + public static Matrix2 operator -(Matrix2 A, Matrix2 B) { + if (A.nRows != B.nRows || A.nCols != B.nCols) + throw new System.ArgumentException("Size of A must match size of B."); + + float[,] result = new float[A.nRows, B.nCols]; + + for (int i = 0; i < A.nRows; i++) { + for (int j = 0; j < A.nCols; j++) + result[i, j] = A.data[i, j] - B.data[i, j]; + } + return new Matrix2(result); + } + + public static Matrix2 operator +(Matrix2 A, Matrix2 B) { + if (A.nRows != B.nRows || A.nCols != B.nCols) + throw new System.ArgumentException("Size of A must match size of B."); + + float[,] result = new float[A.nRows, B.nCols]; + + for (int i = 0; i < A.nRows; i++) { + for (int j = 0; j < A.nCols; j++) + result[i, j] = A.data[i, j] + B.data[i, j]; + } + return new Matrix2(result); + } + + public static Matrix2 operator *(Matrix2 A, Matrix2 B) { + if (A.nCols != B.nRows) + throw new System.ArgumentException("Number of columns in A must match number of rows in B."); + + float[,] result = new float[A.nRows, B.nCols]; + + for (int i = 0; i < A.nRows; i++) { + for (int j = 0; j < B.nCols; j++) { + float sum = 0.0f; + for (int k = 0; k < A.nCols; k++) + sum += A.data[i, k] * B.data[k, j]; + + result[i, j] = sum; + } + } + + return new Matrix2(result); + // double checked code + } + + public static Matrix1 operator *(Matrix2 A, Matrix1 v) { + float[] result = new float[A.nRows]; + + for (int i = 0; i < A.nRows; i++) { + for (int j = 0; j < A.nCols; j++) { + result[i] += A.data[i, j] * v.data[j]; + } + } + + return new Matrix1(result); + } + + public static Vector3Float operator *(Matrix2 A, Vector3Float v) { + return new Vector3Float( + A.data[0, 0] * v.horizontal + A.data[0, 1] * v.vertical + A.data[0, 2] * v.depth, + A.data[1, 0] * v.horizontal + A.data[1, 1] * v.vertical + A.data[1, 2] * v.depth, + A.data[2, 0] * v.horizontal + A.data[2, 1] * v.vertical + A.data[2, 2] * v.depth + ); + } + + public static Matrix2 operator *(Matrix2 A, float s) { + float[,] result = new float[A.nRows, A.nCols]; + + for (int i = 0; i < A.nRows; i++) { + for (int j = 0; j < A.nCols; j++) + result[i, j] = A.data[i, j] * s; + } + + return new Matrix2(result); + } + public static Matrix2 operator *(float s, Matrix2 A) { + return A * s; + } + + public static Matrix2 operator /(Matrix2 A, float s) { + float[,] result = new float[A.nRows, A.nCols]; + + for (int i = 0; i < A.nRows; i++) { + for (int j = 0; j < A.nCols; j++) + result[i, j] = A.data[i, j] / s; + } + + return new Matrix2(result); + } + public static Matrix2 operator /(float s, Matrix2 A) { + float[,] result = new float[A.nRows, A.nCols]; + + for (int i = 0; i < A.nRows; i++) { + for (int j = 0; j < A.nCols; j++) + result[i, j] = s / A.data[i, j]; + } + + return new Matrix2(result); + } + + public Matrix2 GetRows(Slice slice) { + return GetRows(slice.start, slice.stop); + } + public Matrix2 GetRows(int from, int to) { + if (from < 0 || to >= this.nRows) + throw new System.ArgumentException("Slice index out of range."); + + float[,] result = new float[to - from, this.nCols]; + int resultRowIx = 0; + for (int rowIx = from; rowIx < to; rowIx++) { + for (int colIx = 0; colIx < this.nCols; colIx++) + result[resultRowIx, colIx] = this.data[rowIx, colIx]; + + resultRowIx++; + } + + return new Matrix2(result); + } + + public Matrix2 Slice(Slice slice) + { + return Slice(slice.start, slice.stop); + } + public Matrix2 Slice(int from, int to) + { + if (from < 0 || to >= this.nRows) + throw new System.ArgumentException("Slice index out of range."); + + float[,] result = new float[to - from, this.nCols]; + int resultRowIx = 0; + for (int rowIx = from; rowIx < to; rowIx++) + { + for (int colIx = 0; colIx < this.nCols; colIx++) + { + result[resultRowIx, colIx] = this.data[rowIx, colIx]; + } + resultRowIx++; + } + + return new Matrix2(result); + } + public Matrix2 Slice(Slice rowRange, Slice colRange) { + return Slice((rowRange.start, rowRange.stop), (colRange.start, colRange.stop)); + } + public Matrix2 Slice((int start, int stop) rowRange, (int start, int stop) colRange) + { + float[,] result = new float[rowRange.stop - rowRange.start, colRange.stop - colRange.start]; + + int resultRowIx = 0; + int resultColIx = 0; + for (int i = rowRange.start; i < rowRange.stop; i++) + { + for (int j = colRange.start; j < colRange.stop; j++) + result[resultRowIx, resultColIx] = this.data[i, j]; + } + return new Matrix2(result); + } + + public void UpdateSlice(Slice slice, Matrix2 m) { + UpdateSlice((slice.start, slice.stop), m); + } + public void UpdateSlice((int start, int stop) slice, Matrix2 m) { + // if (slice.start == slice.stop) + // Console.WriteLine("WARNING: no data is updates when start equals stop in a slice!"); + int mRowIx = 0; + for (int rowIx = slice.start; rowIx < slice.stop; rowIx++, mRowIx++) { + for (int colIx = 0; colIx < this.nCols; colIx++) + this.data[rowIx, colIx] = m.data[mRowIx, colIx]; + } + } + + public void UpdateSlice(Slice rowRange, Slice colRange, Matrix2 m) + { + UpdateSlice((rowRange.start, rowRange.stop), (colRange.start, colRange.stop), m); + } + public void UpdateSlice((int start, int stop) rowRange, (int start, int stop) colRange, Matrix2 m) + { + for (int i = rowRange.start; i < rowRange.stop; i++) + { + for (int j = colRange.start; j < colRange.stop; j++) + this.data[i, j] = m.data[i - rowRange.start, j - colRange.start]; + } + } + + public Matrix2 Inverse() { + Matrix2 A = this; + // unchecked + int n = A.nRows; + + // Create an identity matrix of the same size as the original matrix + float[,] augmentedMatrix = new float[n, 2 * n]; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + augmentedMatrix[i, j] = A.data[i, j]; + augmentedMatrix[i, j + n] = (i == j) ? 1 : 0; // Identity matrix + } + } + + // Perform Gaussian elimination + for (int i = 0; i < n; i++) { + // Find the pivot row + float pivot = augmentedMatrix[i, i]; + if (Math.Abs(pivot) < 1e-10) // Check for singular matrix + throw new InvalidOperationException("Matrix is singular and cannot be inverted."); + + // Normalize the pivot row + for (int j = 0; j < 2 * n; j++) + augmentedMatrix[i, j] /= pivot; + + // Eliminate the column below the pivot + for (int j = i + 1; j < n; j++) { + float factor = augmentedMatrix[j, i]; + for (int k = 0; k < 2 * n; k++) + augmentedMatrix[j, k] -= factor * augmentedMatrix[i, k]; + } + } + + // Back substitution + for (int i = n - 1; i >= 0; i--) + { + // Eliminate the column above the pivot + for (int j = i - 1; j >= 0; j--) + { + float factor = augmentedMatrix[j, i]; + for (int k = 0; k < 2 * n; k++) + augmentedMatrix[j, k] -= factor * augmentedMatrix[i, k]; + } + } + + // Extract the inverse matrix from the augmented matrix + float[,] inverse = new float[n, n]; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) + inverse[i, j] = augmentedMatrix[i, j + n]; + } + + return new Matrix2(inverse); + } + + public float Determinant() + { + int n = this.nRows; + if (n != this.nCols) + throw new System.ArgumentException("Matrix must be square."); + + if (n == 1) + return this.data[0, 0]; // Base case for 1x1 matrix + + if (n == 2) // Base case for 2x2 matrix + return this.data[0, 0] * this.data[1, 1] - this.data[0, 1] * this.data[1, 0]; + + float det = 0; + for (int col = 0; col < n; col++) + det += (col % 2 == 0 ? 1 : -1) * this.data[0, col] * this.Minor(0, col).Determinant(); + + return det; + } + + // Helper function to compute the minor of a matrix + private Matrix2 Minor(int rowToRemove, int colToRemove) + { + int n = this.nRows; + float[,] minor = new float[n - 1, n - 1]; + + int r = 0, c = 0; + for (int i = 0; i < n; i++) { + if (i == rowToRemove) continue; + + c = 0; + for (int j = 0; j < n; j++) { + if (j == colToRemove) continue; + + minor[r, c] = this.data[i, j]; + c++; + } + r++; + } + + return new Matrix2(minor); + } + + public static Matrix2 DeleteRows(Matrix2 A, Slice rowRange) { + float[,] result = new float[A.nRows - (rowRange.stop - rowRange.start), A.nCols]; + + int resultRowIx = 0; + for (int i = 0; i < A.nRows; i++) { + if (i >= rowRange.start && i < rowRange.stop) + continue; + + for (int j = 0; j < A.nCols; j++) + result[resultRowIx, j] = A.data[i, j]; + + resultRowIx++; + } + return new Matrix2(result); + } + + internal static Matrix2 DeleteColumns(Matrix2 A, Slice colRange) { + float[,] result = new float[A.nRows, A.nCols - (colRange.stop - colRange.start)]; + + for (int i = 0; i < A.nRows; i++) { + int resultColIx = 0; + for (int j = 0; j < A.nCols; j++) { + if (j >= colRange.start && j < colRange.stop) + continue; + + result[i, resultColIx++] = A.data[i, j]; + } + } + return new Matrix2(result); + } + } + + public class Matrix1 + { + public float[] data { get; } + + public int size => data.GetLength(0); + + public Matrix1(int size) + { + this.data = new float[size]; + } + + public Matrix1(float[] data) { + this.data = data; + } + + public static Matrix1 Zero(int size) + { + return new Matrix1(size); + } + + public static Matrix1 FromVector2(Vector2Float v) { + float[] result = new float[2]; + result[0] = v.horizontal; + result[1] = v.vertical; + return new Matrix1(result); + } + + public static Matrix1 FromVector3(Vector3Float v) { + float[] result = new float[3]; + result[0] = v.horizontal; + result[1] = v.vertical; + result[2] = v.depth; + return new Matrix1(result); + } + +#if UNITY_5_3_OR_NEWER + public static Matrix1 FromQuaternion(Quaternion q) { + float[] result = new float[4]; + result[0] = q.x; + result[1] = q.y; + result[2] = q.z; + result[3] = q.w; + return new Matrix1(result); + } +#endif + + public Vector2Float vector2 { + get { + if (this.size != 2) + throw new System.ArgumentException("Matrix1 must be of size 2"); + return new Vector2Float(this.data[0], this.data[1]); + } + } + public Vector3Float vector3 { + get { + if (this.size != 3) + throw new System.ArgumentException("Matrix1 must be of size 3"); + return new Vector3Float(this.data[0], this.data[1], this.data[2]); + } + } + +#if UNITY_5_3_OR_NEWER + public Quaternion quaternion { + get { + if (this.size != 4) + throw new System.ArgumentException("Matrix1 must be of size 4"); + return new Quaternion(this.data[0], this.data[1], this.data[2], this.data[3]); + } + } +#endif + + public Matrix1 Clone() { + float[] data = new float[this.size]; + for (int rowIx = 0; rowIx < this.size; rowIx++) + data[rowIx] = this.data[rowIx]; + return new Matrix1(data); + } + + + public float magnitude { + get { + float sum = 0; + foreach (var elm in data) + sum += elm; + return sum / data.Length; + } + } + public static Matrix1 operator +(Matrix1 A, Matrix1 B) { + if (A.size != B.size) + throw new System.ArgumentException("Size of A must match size of B."); + + float[] result = new float[A.size]; + + for (int i = 0; i < A.size; i++) { + result[i] = A.data[i] + B.data[i]; + } + return new Matrix1(result); + } + + public Matrix2 Transpose() { + float[,] r = new float[1, this.size]; + for (uint colIx = 0; colIx < this.size; colIx++) + r[1, colIx] = this.data[colIx]; + + return new Matrix2(r); + } + + public static float Dot(Matrix1 a, Matrix1 b) { + if (a.size != b.size) + throw new System.ArgumentException("Vectors must be of the same length."); + + float result = 0.0f; + for (int i = 0; i < a.size; i++) { + result += a.data[i] * b.data[i]; + } + return result; + } + + public static Matrix1 operator -(Matrix1 A, Matrix1 B) { + if (A.size != B.size) + throw new System.ArgumentException("Size of A must match size of B."); + + float[] result = new float[A.size]; + + for (int i = 0; i < A.size; i++) { + result[i] = A.data[i] - B.data[i]; + } + return new Matrix1(result); + } + + public static Matrix1 operator *(Matrix1 A, float f) + { + float[] result = new float[A.size]; + + for (int i = 0; i < A.size; i++) + result[i] += A.data[i] * f; + + return new Matrix1(result); + } + public static Matrix1 operator *(float f, Matrix1 A) { + return A * f; + } + + public static Matrix1 operator /(Matrix1 A, float f) { + float[] result = new float[A.size]; + + for (int i = 0; i < A.size; i++) + result[i] = A.data[i] / f; + + return new Matrix1(result); + } + public static Matrix1 operator /(float f, Matrix1 A) { + float[] result = new float[A.size]; + + for (int i = 0; i < A.size; i++) + result[i] = f / A.data[i]; + + return new Matrix1(result); + } + + public Matrix1 Slice(Slice range) + { + return Slice(range.start, range.stop); + } + public Matrix1 Slice(int from, int to) + { + if (from < 0 || to >= this.size) + throw new System.ArgumentException("Slice index out of range."); + + float[] result = new float[to - from]; + int resultIx = 0; + for (int ix = from; ix < to; ix++) + result[resultIx++] = this.data[ix]; + + return new Matrix1(result); + } + public void UpdateSlice(Slice slice, Matrix1 v) { + int vIx = 0; + for (int ix = slice.start; ix < slice.stop; ix++, vIx++) + this.data[ix] = v.data[vIx]; + } + } + +} \ No newline at end of file diff --git a/LinearAlgebra/src/Quat32.cs b/LinearAlgebra/src/Quat32.cs new file mode 100644 index 0000000..19ee9bc --- /dev/null +++ b/LinearAlgebra/src/Quat32.cs @@ -0,0 +1,87 @@ +using System; + +namespace LinearAlgebra { + public class Quat32 { + public float x; + public float y; + public float z; + public float w; + + public Quat32() { + this.x = 0; + this.y = 0; + this.z = 0; + this.w = 1; + } + + public Quat32(float x, float y, float z, float w) { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + + public static Quat32 FromSwingTwist(SwingTwist s) { + Quat32 q32 = Quat32.Euler(-s.swing.vertical.inDegrees, s.swing.horizontal.inDegrees, s.twist.inDegrees); + return q32; + } + + public static Quat32 Euler(float yaw, float pitch, float roll) { + float rollOver2 = roll * AngleFloat.Deg2Rad * 0.5f; + float sinRollOver2 = (float)Math.Sin((float)rollOver2); + float cosRollOver2 = (float)Math.Cos((float)rollOver2); + float pitchOver2 = pitch * 0.5f; + float sinPitchOver2 = (float)Math.Sin((float)pitchOver2); + float cosPitchOver2 = (float)Math.Cos((float)pitchOver2); + float yawOver2 = yaw * 0.5f; + float sinYawOver2 = (float)Math.Sin((float)yawOver2); + float cosYawOver2 = (float)Math.Cos((float)yawOver2); + Quat32 result = new Quat32() { + w = cosYawOver2 * cosPitchOver2 * cosRollOver2 + + sinYawOver2 * sinPitchOver2 * sinRollOver2, + x = sinYawOver2 * cosPitchOver2 * cosRollOver2 + + cosYawOver2 * sinPitchOver2 * sinRollOver2, + y = cosYawOver2 * sinPitchOver2 * cosRollOver2 - + sinYawOver2 * cosPitchOver2 * sinRollOver2, + z = cosYawOver2 * cosPitchOver2 * sinRollOver2 - + sinYawOver2 * sinPitchOver2 * cosRollOver2 + }; + return result; + } + + public void ToAngles(out float right, out float up, out float forward) { + float test = this.x * this.y + this.z * this.w; + if (test > 0.499f) { // singularity at north pole + right = 0; + up = 2 * (float)Math.Atan2(this.x, this.w) * AngleFloat.Rad2Deg; + forward = 90; + return; + //return Vector3(0, 2 * (float)atan2(this.x, this.w) * Angle.Rad2Deg, 90); + } + else if (test < -0.499f) { // singularity at south pole + right = 0; + up = -2 * (float)Math.Atan2(this.x, this.w) * AngleFloat.Rad2Deg; + forward = -90; + return; + //return Vector3(0, -2 * (float)atan2(this.x, this.w) * Angle.Rad2Deg, -90); + } + else { + float sqx = this.x * this.x; + float sqy = this.y * this.y; + float sqz = this.z * this.z; + + right = (float)Math.Atan2(2 * this.x * this.w - 2 * this.y * this.z, 1 - 2 * sqx - 2 * sqz) * AngleFloat.Rad2Deg; + up = (float)Math.Atan2(2 * this.y * this.w - 2 * this.x * this.z, 1 - 2 * sqy - 2 * sqz) * AngleFloat.Rad2Deg; + forward = (float)Math.Asin(2 * test) * AngleFloat.Rad2Deg; + return; + // return Vector3( + // atan2f(2 * this.x * this.w - 2 * this.y * this.z, 1 - 2 * sqx - 2 * sqz) * + // Rad2Deg, + // atan2f(2 * this.y * this.w - 2 * this.x * this.z, 1 - 2 * sqy - 2 * sqz) * + // Rad2Deg, + // asinf(2 * test) * Angle.Rad2Deg); + } + } + + } +} \ No newline at end of file diff --git a/LinearAlgebra/src/Quaternion.cs b/LinearAlgebra/src/Quaternion.cs new file mode 100644 index 0000000..7936843 --- /dev/null +++ b/LinearAlgebra/src/Quaternion.cs @@ -0,0 +1,582 @@ +using System; +#if UNITY_5_3_OR_NEWER +using Quaternion = UnityEngine.Quaternion; +#endif + +namespace LinearAlgebra { + +#if UNITY_5_3_OR_NEWER + public class QuaternionExtensions { + public static Quaternion Reflect(Quaternion q) { + return new(-q.x, -q.y, -q.z, q.w); + } + + public static Matrix2 ToRotationMatrix(Quaternion q) { + float w = q.x, x = q.y, y = q.z, z = q.w; + + float[,] result = new float[,] + { + { 1 - 2 * (y * y + z * z), 2 * (x * y - w * z), 2 * (x * z + w * y) }, + { 2 * (x * y + w * z), 1 - 2 * (x * x + z * z), 2 * (y * z - w * x) }, + { 2 * (x * z - w * y), 2 * (y * z + w * x), 1 - 2 * (x * x + y * y) } + }; + return new Matrix2(result); + } + + public static Quaternion FromRotationMatrix(Matrix2 m) { + float trace = m.data[0, 0] + m.data[1, 1] + m.data[2, 2]; + float w, x, y, z; + + if (trace > 0) { + float s = 0.5f / (float)Math.Sqrt(trace + 1.0f); + w = 0.25f / s; + x = (m.data[2, 1] - m.data[1, 2]) * s; + y = (m.data[0, 2] - m.data[2, 0]) * s; + z = (m.data[1, 0] - m.data[0, 1]) * s; + } + else { + if (m.data[0, 0] > m.data[1, 1] && m.data[0, 0] > m.data[2, 2]) { + float s = 2.0f * (float)Math.Sqrt(1.0f + m.data[0, 0] - m.data[1, 1] - m.data[2, 2]); + w = (m.data[2, 1] - m.data[1, 2]) / s; + x = 0.25f * s; + y = (m.data[0, 1] + m.data[1, 0]) / s; + z = (m.data[0, 2] + m.data[2, 0]) / s; + } + else if (m.data[1, 1] > m.data[2, 2]) { + float s = 2.0f * (float)Math.Sqrt(1.0f + m.data[1, 1] - m.data[0, 0] - m.data[2, 2]); + w = (m.data[0, 2] - m.data[2, 0]) / s; + x = (m.data[0, 1] + m.data[1, 0]) / s; + y = 0.25f * s; + z = (m.data[1, 2] + m.data[2, 1]) / s; + } + else { + float s = 2.0f * (float)Math.Sqrt(1.0f + m.data[2, 2] - m.data[0, 0] - m.data[1, 1]); + w = (m.data[1, 0] - m.data[0, 1]) / s; + x = (m.data[0, 2] + m.data[2, 0]) / s; + y = (m.data[1, 2] + m.data[2, 1]) / s; + z = 0.25f * s; + } + } + + return new Quaternion(x, y, z, w); + } + } +#else + public struct Quaternion { + public float x; + public float y; + public float z; + public float w; + + /// + /// create a new quaternion with the given values + /// + /// x component + /// y component + /// z component + /// w component + public Quaternion(float x, float y, float z, float w) { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + + /// + /// An identity quaternion + /// + public static readonly Quaternion identity = new(0, 0, 0, 1); + + private readonly Vector3Float xyz => new(x, y, z); + + private readonly float magnitude => MathF.Sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w); + + private readonly float sqrMagnitude => x * x + y * y + z * z + w * w; + + /// + /// Convert to unit quaternion + /// + /// This will preserve the orientation, + /// but ensures that it is a unit quaternion. + public readonly Quaternion normalized { + get { + float length = this.magnitude; + Quaternion q = new(this.x / length, this.y / length, this.z / length, this.w / length); + return q; + } + } + + /// + /// Convert to unity quaternion + /// + /// The quaternion to convert + /// A unit quaternion + /// This will preserve the orientation, + /// but ensures that it is a unit quaternion. + public static Quaternion Normalize(Quaternion q) { + return q.normalized; + } + + /// + /// Convert to euler angles + /// + /// The quaternion to convert + /// A vector containing euler angles + /// The euler angles performed in the order: Z, X, Y + public static Vector3Float ToAngles(Quaternion q) { + // Extract Euler angles in Unity order (X = pitch, Y = yaw, Z = roll), returned in degrees as (x,pitch),(y,yaw),(z,roll) + // Handle singularities/gimbal lock + float test = 2f * (q.w * q.x - q.y * q.z); + // clamp + if (test >= 1f) test = 1f; + if (test <= -1f) test = -1f; + + float pitch = MathF.Asin(test); // X + + float roll = MathF.Atan2(2f * (q.w * q.z + q.x * q.y), + 1f - 2f * (q.x * q.x + q.z * q.z)); // Z + + float yaw = MathF.Atan2(2f * (q.w * q.y + q.x * q.z), + 1f - 2f * (q.y * q.y + q.x * q.x)); // Y + + const float rad2deg = 180f / MathF.PI; + return new Vector3Float(pitch * rad2deg, yaw * rad2deg, roll * rad2deg); + // float test = q.x * q.y + q.z * q.w; + // if (test > 0.499f) // singularity at north pole + // return new Vector3Float(0, 2 * MathF.Atan2(q.x, q.w) * AngleFloat.Rad2Deg, 90); + + // else if (test < -0.499f) // singularity at south pole + // return new Vector3Float(0, -2 * MathF.Atan2(q.x, q.w) * AngleFloat.Rad2Deg, -90); + + // else { + // float sqx = q.x * q.x; + // float sqy = q.y * q.y; + // float sqz = q.z * q.z; + + // return new Vector3Float( + // MathF.Atan2(2 * q.x * q.w - 2 * q.y * q.z, 1 - 2 * sqx - 2 * sqz) * + // AngleFloat.Rad2Deg, + // MathF.Atan2(2 * q.y * q.w - 2 * q.x * q.z, 1 - 2 * sqy - 2 * sqz) * + // AngleFloat.Rad2Deg, + // MathF.Asin(2 * test) * AngleFloat.Rad2Deg); + // } + } + + /// + /// Create a rotation from euler angles + /// + /// The angle around the right axis + /// The angle around the upward axis + /// The angle around the forward axis + /// The resulting quaternion + /// Rotation are appied in the order Z, X, Y. + public static Quaternion Euler(float x, float y, float z) { + return Quaternion.Euler(new Vector3Float(x, y, z)); + } + /// + /// Create a rotation from a vector containing euler angles + /// + /// Vector with the euler angles + /// The resulting quaternion + /// Rotation are appied in the order Z, X, Y. + public static Quaternion Euler(Vector3Float angles) { + Vector3Float euler = angles * AngleFloat.Deg2Rad; + float cx = MathF.Cos(euler.horizontal * 0.5f); + float sx = MathF.Sin(euler.horizontal * 0.5f); + float cy = MathF.Cos(euler.vertical * 0.5f); + float sy = MathF.Sin(euler.vertical * 0.5f); + float cz = MathF.Cos(euler.depth * 0.5f); + float sz = MathF.Sin(euler.depth * 0.5f); + + // Unity uses intrinsic Z, then X, then Y -> q = Qy * Qx * Qz + Quaternion q; + q.w = cy * cx * cz + sy * sx * sz; + q.x = cy * sx * cz + sy * cx * sz; + q.y = sy * cx * cz - cy * sx * sz; + q.z = cy * cx * sz - sy * sx * cz; + return q; + } + + /// + /// Multiply two quaternions + /// + /// + /// + /// The resulting rotation + public static Quaternion operator *(Quaternion q1, Quaternion q2) { + return new Quaternion( + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y + q1.w * q2.x, + -q1.x * q2.z + q1.y * q2.w + q1.z * q2.x + q1.w * q2.y, + q1.x * q2.y - q1.y * q2.x + q1.z * q2.w + q1.w * q2.z, + -q1.x * q2.x - q1.y * q2.y - q1.z * q2.z + q1.w * q2.w); + } + + /// + /// Rotate a vector using this quaterion + /// + /// The rotation + /// The vector to rotate + /// The rotated vector + public static Vector3Float operator *(Quaternion q, Vector3Float v) { + float num = q.x * 2; + float num2 = q.y * 2; + float num3 = q.z * 2; + float num4 = q.x * num; + float num5 = q.y * num2; + float num6 = q.z * num3; + float num7 = q.x * num2; + float num8 = q.x * num3; + float num9 = q.y * num3; + float num10 = q.w * num; + float num11 = q.w * num2; + float num12 = q.w * num3; + + float px = v.horizontal; + float py = v.vertical; + float pz = v.depth; + float rx = + (1 - (num5 + num6)) * px + (num7 - num12) * py + (num8 + num11) * pz; + float ry = + (num7 + num12) * px + (1 - (num4 + num6)) * py + (num9 - num10) * pz; + float rz = + (num8 - num11) * px + (num9 + num10) * py + (1 - (num4 + num5)) * pz; + Vector3Float result = new(rx, ry, rz); + return result; + } + + /// + /// The inverse of quaterion + /// + /// The quaternion for which the inverse is + /// needed The inverted quaternion + public static Quaternion Inverse(Quaternion q) { + float n = MathF.Sqrt(q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w); + return new Quaternion(-q.x / n, -q.y / n, -q.z / n, q.w / n); + } + + /// + /// A rotation which looks in the given direction + /// + /// The look direction + /// The up direction + /// The look rotation + public static Quaternion LookRotation(Vector3Float forward, Vector3Float up) { + Vector3Float nForward = forward.normalized; + Vector3Float nRight = Vector3Float.Normalize(Vector3Float.Cross(up, nForward)); + Vector3Float nUp = Vector3Float.Cross(nForward, nRight); + float m00 = nRight.horizontal; // x; + float m01 = nRight.vertical; // y; + float m02 = nRight.depth; // z; + float m10 = nUp.horizontal; // x; + float m11 = nUp.vertical; // y; + float m12 = nUp.depth; // z; + float m20 = nForward.horizontal; // x; + float m21 = nForward.vertical; // y; + float m22 = nForward.depth; // z; + + float num8 = (m00 + m11) + m22; + float x, y, z, w; + if (num8 > 0) { + float num = MathF.Sqrt(num8 + 1); + w = num * 0.5f; + num = 0.5f / num; + x = (m12 - m21) * num; + y = (m20 - m02) * num; + z = (m01 - m10) * num; + return new Quaternion(x, y, z, w); + } + if ((m00 >= m11) && (m00 >= m22)) { + float num7 = MathF.Sqrt(((1 + m00) - m11) - m22); + float num4 = 0.5F / num7; + x = 0.5f * num7; + y = (m01 + m10) * num4; + z = (m02 + m20) * num4; + w = (m12 - m21) * num4; + return new Quaternion(x, y, z, w); + } + if (m11 > m22) { + float num6 = MathF.Sqrt(((1 + m11) - m00) - m22); + float num3 = 0.5F / num6; + x = (m10 + m01) * num3; + y = 0.5F * num6; + z = (m21 + m12) * num3; + w = (m20 - m02) * num3; + return new Quaternion(x, y, z, w); + } + float num5 = MathF.Sqrt(((1 + m22) - m00) - m11); + float num2 = 0.5F / num5; + x = (m20 + m02) * num2; + y = (m21 + m12) * num2; + z = 0.5F * num5; + w = (m01 - m10) * num2; + return new Quaternion(x, y, z, w); + } + + /// + /// Creates a quaternion with the given forward direction with up = + /// Vector3::up + /// + /// The look direction + /// The rotation for this direction + /// For the rotation, Vector::up is used for the up direction. + /// Note: if the forward direction == Vector3::up, the result is + /// Quaternion::identity + public static Quaternion LookRotation(Vector3Float forward) { + Vector3Float up = new(0, 1, 0); + return LookRotation(forward, up); + } + + /// + /// Calculat the rotation from on vector to another + /// + /// The from direction + /// The to direction + /// The rotation from the first to the second vector + public static Quaternion FromToRotation(Vector3Float fromDirection, Vector3Float toDirection) { + Vector3Float axis = Vector3Float.Cross(fromDirection, toDirection); + axis = axis.normalized; + AngleFloat angle = Vector3Float.SignedAngle(fromDirection, toDirection, axis); + Quaternion rotation = AngleAxis(angle, axis); + return rotation; + + } + + /// + /// Rotate form one orientation to anther with a maximum amount of degrees + /// + /// The from rotation + /// The destination rotation + /// The maximum amount of degrees to + /// rotate The possibly limited rotation + public static Quaternion RotateTowards(Quaternion from, Quaternion to, + float maxDegreesDelta) { + float num = Quaternion.UnsignedAngle(from, to); + if (num == 0) { + return to; + } + float t = MathF.Min(1, maxDegreesDelta / num); + return SlerpUnclamped(from, to, t); + + } + + /// + /// Convert an angle/axis representation to a quaternion + /// + /// The angle + /// The axis + /// The resulting quaternion + public static Quaternion AngleAxis(AngleFloat angle, Vector3Float axis) { + if (axis.sqrMagnitude == 0.0f) + return Quaternion.identity; + + float radians = angle.inRadians; + radians *= 0.5f; + + Vector3Float axis2 = axis * MathF.Sin(radians); + float x = axis2.horizontal; // x; + float y = axis2.vertical; // y; + float z = axis2.depth; // z; + float w = MathF.Cos(radians); + + return new Quaternion(x, y, z, w).normalized; + } + /// + /// Convert this quaternion to angle/axis representation + /// + /// A pointer to the angle for the result + /// A pointer to the axis for the result + public readonly void ToAngleAxis(out AngleFloat angle, out Vector3Float axis) { + Quaternion q1 = (MathF.Abs(this.w) > 1.0f) ? this.normalized : this; + angle = AngleFloat.Radians(2.0f * MathF.Acos(q1.w)); // angle + float den = MathF.Sqrt(1.0F - q1.w * q1.w); + if (den > 0.0001f) { + axis = Vector3Float.Normalize(q1.xyz / den); + } + else { + // This occurs when the angle is zero. + // Not a problem: just set an arbitrary normalized axis. + axis = Vector3Float.right; + } + } + + /// + /// Get the angle between two orientations + /// + /// The first orientation + /// The second orientation + /// The smallest angle in degrees between the two + /// orientations + public static float UnsignedAngle(Quaternion q1, Quaternion q2) { + // float f = Dot(q1, q2); + // return MathF.Acos(MathF.Min(MathF.Abs(f), 1)) * 2 * AngleFloat.Rad2Deg; + + float dot = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w; + dot = MathF.Min(MathF.Max(dot, -1f), 1f); + return 2f * MathF.Acos(MathF.Abs(dot)) * (180f / MathF.PI); + } + + /// + /// Sherical lerp between two rotations + /// + /// The first rotation + /// The second rotation + /// The factor between 0 and 1. + /// The resulting rotation + /// A factor 0 returns rotation1, factor1 returns rotation2. + public static Quaternion Slerp(Quaternion a, + Quaternion b, float t) { + if (t > 1) + t = 1; + if (t < 0) + t = 0; + return SlerpUnclamped(a, b, t); + } + + /// + /// Unclamped sherical lerp between two rotations + /// + /// The first rotation + /// The second rotation + /// The factor + /// The resulting rotation + /// A factor 0 returns rotation1, factor1 returns rotation2. + /// Values outside the 0..1 range will result in extrapolated rotations + public static Quaternion SlerpUnclamped(Quaternion a, + Quaternion b, float t) { + // if either input is zero, return the other. + if (a.sqrMagnitude == 0.0f) { + if (b.sqrMagnitude == 0.0f) { + return identity; + } + return b; + } + else if (b.sqrMagnitude == 0.0f) { + return a; + } + + Vector3Float axyz = a.xyz; + Vector3Float bxyz = b.xyz; + float cosHalfAngle = a.w * b.w + Vector3Float.Dot(axyz, bxyz); + + Quaternion b2 = b; + if (cosHalfAngle >= 1.0f || cosHalfAngle <= -1.0f) { + // angle = 0.0f, so just return one input. + return a; + } + else if (cosHalfAngle < 0.0f) { + b2.x = -b.x; + b2.y = -b.y; + b2.z = -b.z; + b2.w = -b.w; + cosHalfAngle = -cosHalfAngle; + } + + float blendA; + float blendB; + if (cosHalfAngle < 0.99f) { + // do proper slerp for big angles + float halfAngle = MathF.Acos(cosHalfAngle); + float sinHalfAngle = MathF.Sin(halfAngle); + float oneOverSinHalfAngle = 1.0F / sinHalfAngle; + blendA = MathF.Sin(halfAngle * (1.0F - t)) * oneOverSinHalfAngle; + blendB = MathF.Sin(halfAngle * t) * oneOverSinHalfAngle; + } + else { + // do lerp if angle is really small. + blendA = 1.0f - t; + blendB = t; + } + Vector3Float v = axyz * blendA + b2.xyz * blendB; + Quaternion result = + new(v.horizontal, v.vertical, v.depth, blendA * a.w + blendB * b2.w); + if (result.sqrMagnitude > 0.0f) + return result.normalized; + else + return Quaternion.identity; + } + + /// + /// Convert this quaternion to angle/axis representation + /// + /// A pointer to the angle for the result + /// A pointer to the axis for the result + public readonly void ToAngleAxis(out float angle, out Vector3Float axis) { + ToAxisAngleRad(this, out axis, out angle); + angle *= AngleFloat.Rad2Deg; + } + private static void ToAxisAngleRad(Quaternion q, + out Vector3Float axis, + out float angle) { + Quaternion q1 = (MathF.Abs(q.w) > 1.0f) ? Quaternion.Normalize(q) : q; + angle = 2.0f * MathF.Acos(q1.w); // angle + float den = MathF.Sqrt(1.0F - q1.w * q1.w); + if (den > 0.0001f) { + axis = (q1.xyz / den).normalized; + } + else { + // This occurs when the angle is zero. + // Not a problem: just set an arbitrary normalized axis. + axis = new Vector3Float(1, 0, 0); + } + } + + /// + /// Returns the angle of around the give axis for a rotation + /// + /// The axis around which the angle should be + /// computed The source rotation + /// The signed angle around the axis + public static float GetAngleAround(Vector3Float axis, Quaternion rotation) { + Quaternion secondaryRotation = GetRotationAround(axis, rotation); + secondaryRotation.ToAngleAxis(out float rotationAngle, out Vector3Float rotationAxis); + + // Do the axis point in opposite directions? + if (Vector3Float.Dot(axis, rotationAxis) < 0) + rotationAngle = -rotationAngle; + + return rotationAngle; + } + + /// + /// Returns the rotation limited around the given axis + /// + /// The axis which which the rotation should be + /// limited The source rotation + /// The rotation around the given axis + public static Quaternion GetRotationAround(Vector3Float axis, Quaternion rotation) { + Vector3Float ra = new(rotation.x, rotation.y, rotation.z); // rotation axis + Vector3Float p = Vector3Float.Project( + ra, axis); // return projection ra on to axis (parallel component) + Quaternion twist = new(p.horizontal, p.vertical, p.depth, rotation.w); + twist = Normalize(twist); + return twist; + + } + + /// + /// Swing-twist decomposition of a rotation + /// + /// The base direction for the decomposition + /// The source rotation + /// A pointer to the quaternion for the swing + /// result A pointer to the quaternion for the + /// twist result + static void GetSwingTwist(Vector3Float axis, Quaternion q, + out Quaternion swing, out Quaternion twist) { + twist = GetRotationAround(axis, q); + swing = q * Inverse(twist); + } + + /// + /// Calculate the dot product of two quaternions + /// + /// The first rotation + /// The second rotation + /// + public static float Dot(Quaternion q1, Quaternion q2) { + return q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w; + } + } +#endif + +} \ No newline at end of file diff --git a/LinearAlgebra/src/Spherical.cs b/LinearAlgebra/src/Spherical.cs new file mode 100644 index 0000000..318839d --- /dev/null +++ b/LinearAlgebra/src/Spherical.cs @@ -0,0 +1,279 @@ +using System; +using System.Collections.Generic; + +#if UNITY_5_3_OR_NEWER +using Vector3 = UnityEngine.Vector3; +#endif + +namespace LinearAlgebra { + /// + /// A spherical vector + /// + /// This is a struct such that it is a value type and cannot be null + public struct Spherical { + /// + /// Create a spherical vector + /// + /// The distance in meters + /// The direction of the vector + public Spherical(float distance, Direction direction) { + if (distance > 0) { + this.distance = distance; + this.direction = direction; + } + else { + this.distance = -distance; + this.direction = -direction; + } + } + + /// + /// Create spherical vector. All given angles are in degrees + /// + /// The distance in meters + /// The horizontal angle in degrees + /// The vertical angle in degrees + /// + public static Spherical Degrees(float distance, float horizontal, float vertical) { + Direction direction = Direction.Degrees(horizontal, vertical); + Spherical s = new(distance, direction); + return s; + } + + public static Spherical Radians(float distance, float horizontal, float vertical) { + Direction direction = Direction.Radians(horizontal, vertical); + Spherical s = new(distance, direction); + return s; + } + + /// + /// The distance in meters + /// + /// @remark The distance should never be negative + public float distance; + /// + /// The direction of the vector + /// + public Direction direction; + + /// + /// A spherical vector with zero degree angles and distance + /// + public readonly static Spherical zero = new(0, Direction.forward); + /// + /// A normalized forward-oriented vector + /// + public readonly static Spherical forward = new(1, Direction.forward); + +#if UNITY_5_3_OR_NEWER + public static Spherical FromVector3(Vector3 v) { + float distance = v.magnitude; + Direction direction = Direction.FromVector3(v / distance); + return new Spherical(distance, direction); + } + + public readonly Vector3 ToVector3() { + Vector3 v = this.direction.ToVector3(); + v *= this.distance; + return v; + } +#else + public static Spherical FromVector3(Vector3Float v) { + float distance = v.magnitude; + if (distance == 0.0f) + return Spherical.zero; + else { + float verticalAngle = (float)(Math.PI / 2 - Math.Acos(v.vertical / distance)) * AngleFloat.Rad2Deg; + float horizontalAngle = (float)Math.Atan2(v.horizontal, v.depth) * AngleFloat.Rad2Deg; + return Degrees(distance, horizontalAngle, verticalAngle); + } + } + + public readonly Vector3Float ToVector3() { + // float verticalRad = (AngleFloat.deg90 - this.direction.vertical).inRadians; + // float horizontalRad = this.direction.horizontal.inRadians; + // float cosVertical = (float)Math.Cos(verticalRad); + // float sinVertical = (float)Math.Sin(verticalRad); + // float cosHorizontal = (float)Math.Cos(horizontalRad); + // float sinHorizontal = (float)Math.Sin(horizontalRad); + + // float x = this.distance * sinVertical * sinHorizontal; + // float y = this.distance * cosVertical; + // float z = this.distance * sinVertical * cosHorizontal; + + // Vector3Float v = new(x, y, z); + Vector3Float v = this.direction.ToVector3(); + v *= this.distance; + return v; + } +#endif + + public override readonly string ToString() { + return $"Spherical({this.distance}, h: {this.direction.horizontal}, v: {this.direction.vertical})"; + } + + + public readonly float magnitude => this.distance; + + public Spherical normalized { + get { + Spherical r = new() { + distance = 1, + direction = this.direction + }; + return r; + } + } + + public static Spherical operator +(Spherical s1, Spherical s2) { + // let's do it the easy way... + // using vars to be compatible with both unity (Vector3) and native (Vector3Float) + var v1 = s1.ToVector3(); + var v2 = s2.ToVector3(); + var v = v1 + v2; + Spherical r = FromVector3(v); + return r; + } + + public static Spherical operator *(Spherical v, float d) { + Spherical r = new(v.distance * d, v.direction); + return r; + } + + public static bool operator ==(Spherical v1, Spherical v2) { + return (v1.distance == v2.distance && v1.direction == v2.direction); + } + + public static bool operator !=(Spherical v1, Spherical v2) { + return (v1.distance != v2.distance || v1.direction != v2.direction); + } + + public override readonly bool Equals(object o) { + if (o is Spherical s) + return this == s; + return false; + } + + public override readonly int GetHashCode() { + return HashCode.Combine(this.distance, this.direction); + } + + public static float Distance(Spherical v1, Spherical v2) { + // Convert degrees to radians + float thetaARadians = v1.direction.horizontal.inRadians; + float phiARadians = v1.direction.vertical.inRadians;// DegreesToRadians(phiA); + float thetaBRadians = v2.direction.horizontal.inRadians; // DegreesToRadians(thetaB); + float phiBRadians = v2.direction.vertical.inRadians; // DegreesToRadians(phiB); + + // Calculate sine and cosine values + float sinPhiA = MathF.Sin(phiARadians); + float cosPhiA = MathF.Cos(phiARadians); + float sinPhiB = MathF.Sin(phiBRadians); + float cosPhiB = MathF.Cos(phiBRadians); + + // Calculate the cosine of the difference in azimuthal angles + float cosThetaDifference = MathF.Cos(thetaARadians - thetaBRadians); + + // Apply the spherical law of cosines + float distance = MathF.Sqrt( + v1.distance * v1.distance + + v2.distance * v2.distance - + 2 * v1.distance * v2.distance * (sinPhiA * sinPhiB * cosThetaDifference + cosPhiA * cosPhiB) + ); + + return distance; + } + + public static Spherical Average(Spherical v1, Spherical v2) { + const float EPS = 1e-6f; + + // Angles in radians + float a1 = v1.direction.horizontal.inRadians; + float a2 = v2.direction.horizontal.inRadians; + float e1 = v1.direction.vertical.inRadians; + float e2 = v2.direction.vertical.inRadians; + + // Fast path: exactly same direction (allowing wrap for azimuth) -> preserve exact angles + bool sameAz = MathF.Abs(MathF.IEEERemainder(a1 - a2, MathF.PI * 2f)) < EPS; + bool sameEl = MathF.Abs(e1 - e2) < EPS; + if (sameAz && sameEl) { + // Distances may differ; average distance but keep exact angles from v1 + float rAvgExact = 0.5f * (v1.distance + v2.distance); + return new Spherical(rAvgExact, v1.direction); + } + + // Horizontal unit-circle sum + float cx = MathF.Cos(a1) + MathF.Cos(a2); + float cy = MathF.Sin(a1) + MathF.Sin(a2); + + // Vertical as z = sin(el) + float z1 = MathF.Sin(e1); + float z2 = MathF.Sin(e2); + float cz = z1 + z2; + + // Magnitude of summed unit-direction vectors + float sumX = cx; + float sumY = cy; + float sumZ = cz; + float magSum = MathF.Sqrt(sumX * sumX + sumY * sumY + sumZ * sumZ); + + // If the two direction unit-vectors cancel (or nearly), return zero distance. + if (magSum < EPS) { + return Spherical.Radians(0f, 0f, 0f); + } + + // Normalized averaged direction components + float ux = sumX / magSum; + float uy = sumY / magSum; + float uz = sumZ / magSum; + + // Compute averaged angles from normalized vector + float azAvgRad = MathF.Atan2(uy, ux); + float elAvgRad = MathF.Asin(Float.Clamp(uz, -1f, 1f)); + + // Average distance (arithmetic mean) + float rAvg = 0.5f * (v1.distance + v2.distance); + + return Spherical.Radians(rAvg, azAvgRad, elAvgRad); + } + + public static Spherical Sum(List vectors) { + if (vectors == null || vectors.Count == 0) + throw new ArgumentException("vectors must contain at least one element", nameof(vectors)); + +#if UNITY_5_3_OR_NEWER + Vector3 sum = Vector3.zero; +#else + Vector3Float sum = Vector3Float.zero; +#endif + foreach (Spherical v in vectors) + sum += v.ToVector3(); + + return FromVector3(sum); + } + + + public static Spherical Average(List vectors) { + if (vectors == null || vectors.Count == 0) + throw new ArgumentException("vectors must contain at least one element", nameof(vectors)); + +#if UNITY_5_3_OR_NEWER + Vector3 sum = Vector3.zero; +#else + Vector3Float sum = Vector3Float.zero; +#endif + int n = 0; + foreach (Spherical v in vectors) { + sum += v.ToVector3(); + n++; + } + var avg = sum / n; + + // if (avg.sqrMagnitude == 0f) + // return new Spherical(0f, new Direction(AngleFloat.Radians(0f), AngleFloat.Radians(0f))); + // else + return FromVector3(avg); + } + + } +} \ No newline at end of file diff --git a/LinearAlgebra/src/SwingTwist.cs b/LinearAlgebra/src/SwingTwist.cs new file mode 100644 index 0000000..df6e048 --- /dev/null +++ b/LinearAlgebra/src/SwingTwist.cs @@ -0,0 +1,136 @@ +// #if !UNITY_5_3_OR_NEWER +// using UnityEngine; +// #endif + +namespace LinearAlgebra { + + /// + /// An orientation using swing and twist angles + /// + /// The swing rotation + /// The twist rotation + public struct SwingTwist { + public Direction swing; + public AngleFloat twist; + + public SwingTwist(Direction swing, AngleFloat twist) { + this.swing = swing; + this.twist = twist; + } + + /// + /// Create a swing/twist rotation using angles in degrees + /// + /// The swing angle in the horizontal plane in degrees + /// The swing angle in the vertical plan in degrees + /// The twist angle in degrees + /// The swing/twist rotation + public static SwingTwist Degrees(float horizontalSwing, float verticalSwing, float twist) { + Direction swing = Direction.Degrees(horizontalSwing, verticalSwing); + AngleFloat twistAngle = AngleFloat.Degrees(twist); + SwingTwist s = new(swing, twistAngle); + return s; + } + + /// + /// Create a swing/twist rotation using angles in degrees + /// + /// The swing angle in the horizontal plane in degrees + /// The swing angle in the vertical plan in degrees + /// The twist angle in degrees + /// The swing/twist rotation + public static SwingTwist Radians(float horizontalSwing, float verticalSwing, float twist) { + Direction swing = Direction.Radians(horizontalSwing, verticalSwing); + AngleFloat twistAngle = AngleFloat.Radians(twist); + SwingTwist s = new(swing, twistAngle); + return s; + } + +#if UNITY_5_3_OR_NEWER + /// + /// A zero angle rotation + /// + public static readonly SwingTwist zero = Degrees(0, 0, 0); + + public Spherical ToAngleAxis() { + UnityEngine.Quaternion q = this.ToQuaternion(); + q.ToAngleAxis(out float angle, out UnityEngine.Vector3 axis); + Direction direction = Direction.FromVector3(axis); + + Spherical r = new(angle, direction); + return r; + } + + public static SwingTwist FromAngleAxis(Spherical r) { + UnityEngine.Vector3 vectorAxis = r.direction.ToVector3(); + UnityEngine.Quaternion q = UnityEngine.Quaternion.AngleAxis(r.distance, vectorAxis); + return FromQuaternion(q); + } + + /// + /// Convert a quaternion in a swing/twist rotation + /// + /// The quaternion to convert + /// The swing/twist rotation + public static SwingTwist FromQuaternion(UnityEngine.Quaternion q) { + UnityEngine.Vector3 angles = q.eulerAngles; + SwingTwist r = Degrees(angles.y, -angles.x, -angles.z); + return r; + } + + public UnityEngine.Quaternion ToQuaternion() { + UnityEngine.Quaternion q = UnityEngine.Quaternion.Euler(this.swing.vertical.inDegrees, + this.swing.horizontal.inDegrees, + this.twist.inDegrees); + return q; + } +#else + /// + /// A zero angle rotation + /// + public static readonly SwingTwist zero = Degrees(0, 0, 0); + + public Spherical ToAngleAxis() { + LinearAlgebra.Quaternion q = this.ToQuaternion(); + q.ToAngleAxis(out float angle, out Vector3Float axis); + Direction direction = Direction.FromVector3(axis); + + Spherical r = new(angle, direction); + return r; + } + + public static SwingTwist FromAngleAxis(Spherical r) { + Vector3Float vectorAxis = r.direction.ToVector3(); + LinearAlgebra.Quaternion q = LinearAlgebra.Quaternion.AngleAxis(AngleFloat.Degrees(r.distance), vectorAxis); + return FromQuaternion(q); + } + + /// + /// Convert a quaternion in a swing/twist rotation + /// + /// The quaternion to convert + /// The swing/twist rotation + public static SwingTwist FromQuaternion(LinearAlgebra.Quaternion q) { + Vector3Float v = LinearAlgebra.Quaternion.ToAngles(q); + SwingTwist r = Degrees(v.vertical, v.horizontal, v.depth); + return r; + } + + public LinearAlgebra.Quaternion ToQuaternion() { + LinearAlgebra.Quaternion q = LinearAlgebra.Quaternion.Euler(this.swing.vertical.inDegrees, + this.swing.horizontal.inDegrees, + this.twist.inDegrees); + return q; + + } + + public static SwingTwist FromQuat32(Quat32 q32) { + q32.ToAngles(out float right, out float up, out float forward); + SwingTwist r = Degrees(up, right, forward); + return r; + } +#endif + + } + +} \ No newline at end of file diff --git a/LinearAlgebra/src/Vector2Float.cs b/LinearAlgebra/src/Vector2Float.cs new file mode 100644 index 0000000..ac1867c --- /dev/null +++ b/LinearAlgebra/src/Vector2Float.cs @@ -0,0 +1,479 @@ +using System; +using System.Numerics; + +namespace LinearAlgebra { + + /* + public struct Vector2Int { + public int horizontal; + public int vertical; + + public Vector2Int(int horizontal, int vertical) { + this.horizontal = horizontal; + this.vertical = vertical; + } + + /// + /// A vector with zero for all axis + /// + public static readonly Vector2Int zero = new(0, 0); + /// + /// A vector with values (1, 1) + /// + public static readonly Vector2Int one = new(1, 1); + /// + /// A vector with values (0, 1) + /// + public static readonly Vector2Int up = new(0, 1); + /// + /// A vector with values (0, -1) + /// + public static readonly Vector2Int down = new(0, -1); + /// + /// A vector with values (0, 1) + /// + public static readonly Vector2Int forward = new(0, 1); + /// + /// A vector with values (0, -1) + /// + public static readonly Vector2Int back = new(0, -1); + /// + /// A vector3 with values (-1, 0) + /// + public static readonly Vector2Int left = new(-1, 0); + /// + /// A vector with values (1, 0) + /// + public static readonly Vector2Int right = new(1, 0); + + /// + /// Tests if the vector has equal values as the given vector + /// + /// The vector to compare to + /// true if the vector values are equal + public readonly bool Equals(Vector2Int v) => this.horizontal == v.horizontal && vertical == v.vertical; + + /// + /// Tests if the vector is equal to the given object + /// + /// The object to compare to + /// false when the object is not a Vector2 or does not have equal values + public override readonly bool Equals(object obj) { + if (obj is not Vector2Int v) + return false; + + return (this.horizontal == v.horizontal && this.vertical == v.vertical); + } + + /// + /// Tests if the two vectors have equal values + /// + /// The first vector + /// The second vector + /// truewhen the vectors have equal values + /// Note that this uses a Float equality check which cannot be not exact in all cases. + /// In most cases it is better to check if the Vector2.Distance between the vectors is smaller than Float.epsilon + /// Or more efficient: (v1 - v2).sqrMagnitude < Float.sqrEpsilon + public static bool operator ==(Vector2Int v1, Vector2Int v2) { + return (v1.horizontal == v2.horizontal && v1.vertical == v2.vertical); + } + /// + /// Tests if two vectors have different values + /// + /// The first vector + /// The second vector + /// truewhen the vectors have different values + /// Note that this uses a Float equality check which cannot be not exact in all case. + /// In most cases it is better to check if the Vector2.Distance between the vectors is smaller than Float.epsilon. + /// Or more efficient: (v1 - v2).sqrMagnitude < Float.sqrEpsilon + public static bool operator !=(Vector2Int v1, Vector2Int v2) { + return (v1.horizontal != v2.horizontal || v1.vertical != v2.vertical); + } + public readonly float magnitude { + get { + int h = this.horizontal; + int v = this.vertical; + return MathF.Sqrt(h * h + v * v); + } + } + + public static float MagnitudeOf(Vector2Int v) { + return v.magnitude; + } + + public static Vector2Int operator -(Vector2Int v1, Vector2Int v2) { + return new Vector2Int(v1.horizontal - v2.horizontal, v1.vertical - v2.vertical); + } + public static Vector2Int operator +(Vector2Int v1, Vector2Int v2) { + return new Vector2Int(v1.horizontal + v2.horizontal, v1.vertical + v2.vertical); + } + + public static float Distance(Vector2Int v1, Vector2Int v2) { + return (v1 - v2).magnitude; + } + } + + public struct Vector2Float { + public float horizontal; + public float vertical; + + public Vector2Float(float horizontal, float vertical) { + this.horizontal = horizontal; + this.vertical = vertical; + } + + public readonly float magnitude { + get { + float h = this.horizontal; + float v = this.vertical; + return MathF.Sqrt(h * h + v * v); + } + } + + public static Vector2Float operator -(Vector2Float v1, Vector2Float v2) { + return new Vector2Float(v1.horizontal - v2.horizontal, v1.vertical - v2.vertical); + } + + public static float Distance(Vector2Float v1, Vector2Float v2) { + return (v1 - v2).magnitude; + } + } + */ + + /// + /// 2-dimensional vectors + /// + public struct Vector2Float { + + /// + /// The right axis of the vector + /// + public float horizontal; // left/right + /// + /// The upward/forward axis of the vector + /// + public float vertical; // forward/backward + // directions are to be inline with Vector3 as much as possible... + + /// + /// Create a new 2-dimensional vector + /// + /// x axis value + /// y axis value + public Vector2Float(float x, float y) { + this.horizontal = x; + this.vertical = y; + } + + /// + /// Convert a Vector2Int into a Vector2Float + /// + /// The Vector2Int + public Vector2Float(Vector2Int v) { + this.horizontal = v.horizontal; + this.vertical = v.vertical; + } + + /// + /// A vector with zero for all axis + /// + public static readonly Vector2Float zero = new Vector2Float(0, 0); + /// + /// A vector with values (1, 1) + /// + public static readonly Vector2Float one = new Vector2Float(1, 1); + /// + /// A vector with values (0, 1) + /// + public static readonly Vector2Float up = new Vector2Float(0, 1); + /// + /// A vector with values (0, -1) + /// + public static readonly Vector2Float down = new Vector2Float(0, -1); + /// + /// A vector with values (0, 1) + /// + public static readonly Vector2Float forward = new Vector2Float(0, 1); + /// + /// A vector with values (0, -1) + /// + public static readonly Vector2Float back = new Vector2Float(0, -1); + /// + /// A vector3 with values (-1, 0) + /// + public static readonly Vector2Float left = new Vector2Float(-1, 0); + /// + /// A vector with values (1, 0) + /// + public static readonly Vector2Float right = new Vector2Float(1, 0); + + /// + /// The squared length of this vector + /// + /// The squared length + /// The squared length is computationally simpler than the real length. + /// Think of Pythagoras A^2 + B^2 = C^2. + /// This leaves out the calculation of the squared root of C. + public readonly float sqrMagnitude => horizontal * horizontal + vertical * vertical; + public static float SqrMagnitudeOf(Vector2Float v) { + return v.sqrMagnitude; + } + + /// + /// The length of this vector + /// + /// The length of this vector + public readonly float magnitude => MathF.Sqrt(horizontal * horizontal + vertical * vertical); + public static float MagnitudeOf(Vector2Float v) { + return v.magnitude; + } + + /// + /// Convert the vector to a length of a 1 + /// + /// The vector with length 1 + public Vector2Float normalized { + get { + float l = magnitude; + Vector2Float v = zero; + if (l > Float.epsilon) + v = this / l; + return v; + } + } + public static Vector2Float Normalize(Vector2Float v) { + return v.normalized; + } + + /// + /// Add two vectors + /// + /// The first vector + /// The second vector + /// The result of adding the two vectors + public static Vector2Float operator +(Vector2Float v1, Vector2Float v2) { + Vector2Float v = new Vector2Float(v1.horizontal + v2.horizontal, v1.vertical + v2.vertical); + return v; + } + + /// + /// Subtract two vectors + /// + /// The first vector + /// The second vector + /// The result of adding the two vectors + public static Vector2Float operator -(Vector2Float v1, Vector2Float v2) { + Vector2Float v = new Vector2Float(v1.horizontal - v2.horizontal, v1.vertical - v2.vertical); + return v; + } + + /// + /// Negate the vector + /// + /// The vector to negate + /// The negated vector + /// This will result in a vector pointing in the opposite direction + public static Vector2Float operator -(Vector2Float v1) { + Vector2Float v = new Vector2Float(-v1.horizontal, -v1.vertical); + return v; + } + + /// + /// Scale a vector uniformly down + /// + /// The vector to scale + /// The scaling factor + /// The scaled vector + /// Each component of the vector will be devided by the same factor. + public static Vector2Float operator /(Vector2Float v, float f) { + Vector2Float r = new(v.horizontal / f, v.vertical / f); + return r; + } + + + /// + /// Scale a vector uniformly up + /// + /// The vector to scale + /// The scaling factor + /// The scaled vector + /// Each component of the vector will be multipled with the same factor. + public static Vector2Float operator *(Vector2Float v1, float f) { + Vector2Float v = new Vector2Float(v1.horizontal * f, v1.vertical * f); + return v; + } + + /// + /// Scale a vector uniformly up + /// + /// The scaling factor + /// The vector to scale + /// The scaled vector + /// Each component of the vector will be multipled with the same factor. + public static Vector2Float operator *(float f, Vector2Float v1) { + Vector2Float v = new Vector2Float(f * v1.horizontal, f * v1.vertical); + return v; + } + + /// @brief Scale the vector using another vector + /// @param v1 The vector to scale + /// @param v2 A vector with the scaling factors + /// @return The scaled vector + /// @remark Each component of the vector v1 will be multiplied with the + /// matching component from the scaling vector v2. + public static Vector2Float Scale(Vector2Float v1, Vector2Float v2) { + return new Vector2Float(v1.horizontal * v2.horizontal, v1.vertical * v2.vertical); + } + + /// + /// Tests if the vector has equal values as the given vector + /// + /// The vector to compare to + /// true if the vector values are equal + //public readonly bool Equals(Vector2Float v1) => horizontal == v1.horizontal && vertical == v1.vertical; + + /// + /// Tests if the two vectors have equal values + /// + /// The first vector + /// The second vector + /// truewhen the vectors have equal values + /// Note that this uses a Float equality check which cannot be not exact in all cases. + /// In most cases it is better to check if the Vector2.Distance between the vectors is smaller than Float.epsilon + /// Or more efficient: (v1 - v2).sqrMagnitude < Float.sqrEpsilon + public static bool operator ==(Vector2Float v1, Vector2Float v2) { + return (v1.horizontal == v2.horizontal && v1.vertical == v2.vertical); + } + + /// + /// Tests if two vectors have different values + /// + /// The first vector + /// The second vector + /// truewhen the vectors have different values + /// Note that this uses a Float equality check which cannot be not exact in all case. + /// In most cases it is better to check if the Vector2.Distance between the vectors is smaller than Float.epsilon. + /// Or more efficient: (v1 - v2).sqrMagnitude < Float.sqrEpsilon + public static bool operator !=(Vector2Float v1, Vector2Float v2) { + return (v1.horizontal != v2.horizontal || v1.vertical != v2.vertical); + } + + /// + /// Tests if the vector is equal to the given object + /// + /// The object to compare to + /// false when the object is not a Vector2 or does not have equal values + public override readonly bool Equals(object obj) { + if (obj is not Vector2Float v) + return false; + + return (horizontal == v.horizontal && vertical == v.vertical); + } + + /// + /// Get an hash code for the vector + /// + /// The hash code + public override readonly int GetHashCode() { + return HashCode.Combine(horizontal, vertical); + } + + /// + /// Get the distance between two vectors + /// + /// The first vector + /// The second vector + /// The distance between the two vectors + public static float Distance(Vector2Float v1, Vector2Float v2) { + float x = v1.horizontal - v2.horizontal; + float y = v1.vertical - v2.vertical; + float d = (float)Math.Sqrt(x * x + y * y); + return d; + } + + /// + /// The dot product of two vectors + /// + /// The first vector + /// The second vector + /// The dot product of the two vectors + public static float Dot(Vector2Float v1, Vector2Float v2) { + return v1.horizontal * v2.horizontal + v1.vertical * v2.vertical; + } + + /// + /// Calculate the signed angle between two vectors. + /// + /// The starting vector + /// The ending vector + /// The axis to rotate around + /// The signed angle in degrees + public static float SignedAngle(Vector2Float from, Vector2Float to) { + //float sign = Math.Sign(v1.y * v2.x - v1.x * v2.y); + //return Vector2.Angle(v1, v2) * sign; + + float sqrMagFrom = from.sqrMagnitude; + float sqrMagTo = to.sqrMagnitude; + + if (sqrMagFrom == 0 || sqrMagTo == 0) + return 0; + //if (!isfinite(sqrMagFrom) || !isfinite(sqrMagTo)) + // return nanf(""); + + float angleFrom = (float)Math.Atan2(from.vertical, from.horizontal); + float angleTo = (float)Math.Atan2(to.vertical, to.horizontal); + return -(angleTo - angleFrom) * AngleFloat.Rad2Deg; + } + + public static float UnsignedAngle(Vector2Float from, Vector2Float to) { + return MathF.Abs(SignedAngle(from, to)); + } + + /// + /// Rotates the vector with the given angle + /// + /// The vector to rotate + /// The angle in degrees + /// + public static Vector2Float Rotate(Vector2Float v1, AngleFloat angle) { + float sin = (float)Math.Sin(angle.inRadians); + float cos = (float)Math.Cos(angle.inRadians); + // float sin = AngleFloat.Sin(angle); + // float cos = AngleFloat.Cos(angle); + + float tx = v1.horizontal; + float ty = v1.vertical; + Vector2Float v = new Vector2Float() { + horizontal = (cos * tx) - (sin * ty), + vertical = (sin * tx) + (cos * ty) + }; + return v; + } + + /// + /// Lerp between two vectors + /// + /// The from vector + /// The to vector + /// The interpolation distance [0..1] + /// The lerped vector + /// The factor f is unclamped. Value 0 matches the *v1* vector, Value 1 + /// matches the *v2* vector Value -1 is *v1* vector minus the difference + /// between *v1* and *v2* etc. + public static Vector2Float Lerp(Vector2Float v1, Vector2Float v2, float f) { + Vector2Float v = v1 + (v2 - v1) * f; + return v; + } + + /// + /// Map interval of angles between vectors [0..Pi] to interval [0..1] + /// + /// The first vector + /// The second vector + /// The resulting factor in interval [0..1] + /// Vectors a and b must be normalized + public static float ToFactor(Vector2Float v1, Vector2Float v2) { + return (1 - Vector2Float.Dot(v1, v2)) / 2; + } + } +} \ No newline at end of file diff --git a/LinearAlgebra/src/Vector2Int.cs b/LinearAlgebra/src/Vector2Int.cs new file mode 100644 index 0000000..ed68e8b --- /dev/null +++ b/LinearAlgebra/src/Vector2Int.cs @@ -0,0 +1,185 @@ +using System; + +namespace LinearAlgebra { + + public struct Vector2Int { + public int horizontal; + public int vertical; + + public Vector2Int(int horizontal, int vertical) { + this.horizontal = horizontal; + this.vertical = vertical; + } + + /// + /// A vector with zero for all axis + /// + public static readonly Vector2Int zero = new(0, 0); + /// + /// A vector with values (1, 1) + /// + public static readonly Vector2Int one = new(1, 1); + /// + /// A vector with values (0, 1) + /// + public static readonly Vector2Int up = new(0, 1); + /// + /// A vector with values (0, -1) + /// + public static readonly Vector2Int down = new(0, -1); + /// + /// A vector with values (0, 1) + /// + public static readonly Vector2Int forward = new(0, 1); + /// + /// A vector with values (0, -1) + /// + public static readonly Vector2Int back = new(0, -1); + /// + /// A vector3 with values (-1, 0) + /// + public static readonly Vector2Int left = new(-1, 0); + /// + /// A vector with values (1, 0) + /// + public static readonly Vector2Int right = new(1, 0); + + /* + /// + /// Get an hash code for the vector + /// + /// The hash code + public override int GetHashCode() { + return (this.horizontal, this.vertical).GetHashCode(); + } + + /// + /// Tests if the vector has equal values as the given vector + /// + /// The vector to compare to + /// true if the vector values are equal + public readonly bool Equals(Vector2Int v) => this.horizontal == v.horizontal && vertical == v.vertical; + + */ + + /// + /// Tests if the two vectors have equal values + /// + /// The first vector + /// The second vector + /// truewhen the vectors have equal values + /// Note that this uses a Float equality check which cannot be not exact in all cases. + /// In most cases it is better to check if the Vector2.Distance between the vectors is smaller than Float.epsilon + /// Or more efficient: (v1 - v2).sqrMagnitude < Float.sqrEpsilon + public static bool operator ==(Vector2Int v1, Vector2Int v2) { + return (v1.horizontal == v2.horizontal && v1.vertical == v2.vertical); + } + /// + /// Tests if two vectors have different values + /// + /// The first vector + /// The second vector + /// truewhen the vectors have different values + /// Note that this uses a Float equality check which cannot be not exact in all case. + /// In most cases it is better to check if the Vector2.Distance between the vectors is smaller than Float.epsilon. + /// Or more efficient: (v1 - v2).sqrMagnitude < Float.sqrEpsilon + public static bool operator !=(Vector2Int v1, Vector2Int v2) { + return (v1.horizontal != v2.horizontal || v1.vertical != v2.vertical); + } + + /// + /// Tests if the vector is equal to the given object + /// + /// The object to compare to + /// false when the object is not a Vector2 or does not have equal values + public override readonly bool Equals(object obj) { + if (obj is not Vector2Int v) + return false; + + return (this.horizontal == v.horizontal && this.vertical == v.vertical); + } + + /// + /// Get an hash code for the vector + /// + /// The hash code + public override readonly int GetHashCode() { + return HashCode.Combine(horizontal, vertical); + } + + public readonly float sqrMagnitude => this.horizontal * this.horizontal + this.vertical * this.vertical; + + public static float SqrMagnitudeOf(Vector2Int v) { + return v.sqrMagnitude; + } + + public readonly float magnitude => + MathF.Sqrt(this.horizontal * this.horizontal + this.vertical * this.vertical); + + public static float MagnitudeOf(Vector2Int v) { + return v.magnitude; + } + + /// @brief Convert the vector to a length of 1 + /// @return The vector normalized to a length of 1 + public readonly Vector2Float normalized { + get { + float l = magnitude; + Vector2Float v = Vector2Float.zero; + if (l > Float.epsilon) + v = new Vector2Float(this) / l; + return v; + } + } + /// @brief Convert the vector to a length of 1 + /// @param v The vector to convert + /// @return The vector normalized to a length of 1 + public static Vector2Float Normalize(Vector2Int v) { + float num = v.magnitude; + Vector2Float result = Vector2Float.zero; + if (num > Float.epsilon) + result = new Vector2Float(v) / num; + + return result; + } + + public static Vector2Int operator -(Vector2Int v) { + return new Vector2Int(-v.horizontal, -v.vertical); + } + + public static Vector2Int operator -(Vector2Int v1, Vector2Int v2) { + return new Vector2Int(v1.horizontal - v2.horizontal, v1.vertical - v2.vertical); + } + public static Vector2Int operator +(Vector2Int v1, Vector2Int v2) { + return new Vector2Int(v1.horizontal + v2.horizontal, v1.vertical + v2.vertical); + } + + public static Vector2Int operator /(Vector2Int v, int f) { + return new Vector2Int(v.horizontal / f, v.vertical / f); + } + + public static Vector2Int operator *(Vector2Int v1, int d) { + return new Vector2Int(v1.horizontal * d, v1.vertical * d); + } + + public static Vector2Int operator *(int d, Vector2Int v1) { + return new Vector2Int(d * v1.horizontal, d * v1.vertical); + } + + public static Vector2Int Scale(Vector2Int v1, Vector2Int v2) { + return new Vector2Int(v1.horizontal * v2.horizontal, v1.vertical * v2.vertical); + } + + /// @brief The dot product of two vectors + /// @param v1 The first vector + /// @param v2 The second vector + /// @return The dot product of the two vectors + public static int Dot(Vector2Int v1, Vector2Int v2) { + return v1.horizontal * v2.horizontal + v1.vertical * v2.vertical; + } + + public static float Distance(Vector2Int v1, Vector2Int v2) { + return (v1 - v2).magnitude; + } + } +} \ No newline at end of file diff --git a/LinearAlgebra/src/Vector3Float.cs b/LinearAlgebra/src/Vector3Float.cs new file mode 100644 index 0000000..bcf8626 --- /dev/null +++ b/LinearAlgebra/src/Vector3Float.cs @@ -0,0 +1,402 @@ +//#if !UNITY_5_3_OR_NEWER +using System; + +namespace LinearAlgebra { + /* + public struct Vector3Float { + public float horizontal; + public float vertical; + public float depth; + + public Vector3Float(float horizontal, float vertical, float depth) { + this.horizontal = horizontal; + this.vertical = vertical; + this.depth = depth; + } + + /// + /// A vector with zero for all axis + /// + public static readonly Vector3Float zero = new(0, 0, 0); + + public readonly float magnitude { + get => (float)Math.Sqrt(this.horizontal * this.horizontal + this.vertical * this.vertical + this.depth * this.depth); + } + + /// + /// Convert the vector to a length of a 1 + /// + /// The vector with length 1 + public readonly Vector3Float normalized { + get { + float l = magnitude; + Vector3Float v = zero; + if (l > Float.epsilon) + v = this / l; + return v; + } + } + + + public static Vector3Float operator *(Vector3Float v, float f) { + Vector3Float r = new(v.horizontal * f, v.vertical * f, v.depth * f); + return r; + } + public static Vector3Float operator /(Vector3Float v, float f) { + Vector3Float r = new(v.horizontal / f, v.vertical / f, v.depth / f); + return r; + } + + public static float Dot(Vector3Float v1, Vector3Float v2) { + return v1.horizontal * v2.horizontal + v1.vertical * v2.vertical + + v1.depth * v2.depth; + } + + const float epsilon = 1E-05f; + public static Vector3Float Project(Vector3Float v, Vector3Float n) { + float sqrMagnitude = Dot(n, n); + if (sqrMagnitude < epsilon) + return zero; + else { + float dot = Dot(v, n); + Vector3Float r = n * dot; + r /= sqrMagnitude; + return r; + } + + } + } + */ + + /// + /// 3-dimensional vectors + /// + /// This uses the right-handed coordinate system. + public struct Vector3Float { + + /// + /// The right axis of the vector + /// + public float horizontal; //> left/right + /// + /// The upward axis of the vector + /// + public float vertical; //> up/down + /// + /// The forward axis of the vector + /// + public float depth; //> forward/backward + + /// + /// Create a new 3-dimensional vector + /// + /// x axis value + /// y axis value + /// z axis value + public Vector3Float(float horizontal, float vertical, float depth) { + this.horizontal = horizontal; + this.vertical = vertical; + this.depth = depth; + } + + public Vector3Float(Vector3Int v) { + this.horizontal = v.horizontal; + this.vertical = v.vertical; + this.depth = v.depth; + } + + public static Vector3Float FromSpherical(Spherical s) { + float verticalRad = (AngleFloat.deg90 - s.direction.vertical).inRadians; + float horizontalRad = s.direction.horizontal.inRadians; + float cosVertical = MathF.Cos(verticalRad); + float sinVertical = MathF.Sin(verticalRad); + float cosHorizontal = MathF.Cos(horizontalRad); + float sinHorizontal = MathF.Sin(horizontalRad); + + float horizontal = s.distance * sinVertical * sinHorizontal; + float vertical = s.distance * cosVertical; + float depth = s.distance * sinVertical * cosHorizontal; + return new Vector3Float(horizontal, vertical, depth); + } + + public override string ToString() { + return $"({this.horizontal}, {this.vertical}, {this.depth})"; + } + + /// + /// A vector with zero for all axis + /// + public static readonly Vector3Float zero = new Vector3Float(0, 0, 0); + /// + /// A vector with one for all axis + /// + public static readonly Vector3Float one = new Vector3Float(1, 1, 1); + /// + /// A Vector3Float with values (-1, 0, 0) + /// + public static readonly Vector3Float left = new Vector3Float(-1, 0, 0); + /// + /// A vector with values (1, 0, 0) + /// + public static readonly Vector3Float right = new Vector3Float(1, 0, 0); + /// + /// A vector with values (0, -1, 0) + /// + public static readonly Vector3Float down = new Vector3Float(0, -1, 0); + /// + /// A vector with values (0, 1, 0) + /// + public static readonly Vector3Float up = new Vector3Float(0, 1, 0); + /// + /// A vector with values (0, 0, -1) + /// + public static readonly Vector3Float back = new Vector3Float(0, -1, 0); + /// + /// A vector with values (0, 0, 1) + /// + public static readonly Vector3Float forward = new Vector3Float(0, 1, 0); + + /// @brief The vector length + /// @return The vector length + public readonly float magnitude => MathF.Sqrt(horizontal * horizontal + vertical * vertical + depth * depth); + /// + /// The vector length + /// + /// The vector for which you need the length + /// The vector length + public static float MagnitudeOf(Vector3Float v) { + return v.magnitude; + } + + /// @brief The squared vector length + /// @return The squared vector length + /// @remark The squared length is computationally simpler than the real + /// length. Think of Pythagoras A^2 + B^2 = C^2. This leaves out the + /// calculation of the squared root of C. + public readonly float sqrMagnitude => (horizontal * horizontal + vertical * vertical + depth * depth); + + /// + /// The squared vector length + /// + /// The vector for which you need the squared length + /// The squared vector length + /// The squared length is computationally simpler than the real + /// length. Think of Pythagoras A^2 + B^2 = C^2. This leaves out the + /// calculation of the squared root of C. + public static float SqrMagnitudeOf(Vector3Float v) { + return v.sqrMagnitude; + } + + /// @brief Convert the vector to a length of 1 + /// @return The vector normalized to a length of 1 + public readonly Vector3Float normalized { + get { + float l = magnitude; + Vector3Float v = zero; + if (l > Float.epsilon) + v = this / l; + return v; + } + } + /// @brief Convert the vector to a length of 1 + /// @param v The vector to convert + /// @return The vector normalized to a length of 1 + public static Vector3Float Normalize(Vector3Float v) { + float num = v.magnitude; + Vector3Float result = zero; + if (num > Float.epsilon) + result = v / num; + + return result; + } + + /// + /// Negate te vector such that it points in the opposite direction + /// + /// + /// The negated vector + public static Vector3Float operator -(Vector3Float v1) { + Vector3Float v = new(-v1.horizontal, -v1.vertical, -v1.depth); + return v; + } + + /// + /// Subtract two vectors + /// + /// + /// + /// The result of the subtraction + public static Vector3Float operator -(Vector3Float v1, Vector3Float v2) { + Vector3Float v = new(v1.horizontal - v2.horizontal, v1.vertical - v2.vertical, v1.depth - v2.depth); + return v; + } + + /// + /// Add two vectors + /// + /// + /// + /// The result of the addition + public static Vector3Float operator +(Vector3Float v1, Vector3Float v2) { + Vector3Float v = new(v1.horizontal + v2.horizontal, v1.vertical + v2.vertical, v1.depth + v2.depth); + return v; + } + + /// @brief Scale the vector using another vector + /// @param v1 The vector to scale + /// @param v2 A vector with the scaling factors + /// @return The scaled vector + /// @remark Each component of the vector v1 will be multiplied with the + /// matching component from the scaling vector v2. + public static Vector3Float Scale(Vector3Float v1, Vector3Float v2) { + return new Vector3Float(v1.horizontal * v2.horizontal, v1.vertical * v2.vertical, v1.depth * v2.depth); + } + + + public static Vector3Float operator *(Vector3Float v1, float d) { + Vector3Float v = new(v1.horizontal * d, v1.vertical * d, v1.depth * d); + return v; + } + + public static Vector3Float operator *(float d, Vector3Float v1) { + Vector3Float v = new(d * v1.horizontal, d * v1.vertical, d * v1.depth); + return v; + } + + public static Vector3Float operator /(Vector3Float v1, float d) { + Vector3Float v = new(v1.horizontal / d, v1.vertical / d, v1.depth / d); + return v; + } + + + //public bool Equals(Vector3Float v) => (horizontal == v.horizontal && vertical == v.vertical && depth == v.depth); + + public static bool operator ==(Vector3Float v1, Vector3Float v2) { + return (v1.horizontal == v2.horizontal && v1.vertical == v2.vertical && v1.depth == v2.depth); + } + + public static bool operator !=(Vector3Float v1, Vector3Float v2) { + return (v1.horizontal != v2.horizontal || v1.vertical != v2.vertical || v1.depth != v2.depth); + } + + public override readonly bool Equals(object obj) { + if (obj is not Vector3Float v) + return false; + + return (horizontal == v.horizontal && vertical == v.vertical && depth == v.depth); + } + + public override readonly int GetHashCode() { + return HashCode.Combine(horizontal, vertical, depth); + } + + /// @brief The distance between two vectors + /// @param v1 The first vector + /// @param v2 The second vector + /// @return The distance between the two vectors + public static float Distance(Vector3Float v1, Vector3Float v2) { + return (v2 - v1).magnitude; + } + + /// @brief The dot product of two vectors + /// @param v1 The first vector + /// @param v2 The second vector + /// @return The dot product of the two vectors + public static float Dot(Vector3Float v1, Vector3Float v2) { + return v1.horizontal * v2.horizontal + v1.vertical * v2.vertical + v1.depth * v2.depth; + } + + /// @brief The cross product of two vectors + /// @param v1 The first vector + /// @param v2 The second vector + /// @return The cross product of the two vectors + public static Vector3Float Cross(Vector3Float v1, Vector3Float v2) { + return new Vector3Float(v1.vertical * v2.depth - v1.depth * v2.vertical, v1.depth * v2.horizontal - v1.horizontal * v2.depth, + v1.horizontal * v2.vertical - v1.vertical * v2.horizontal); + + } + + /// @brief Project the vector on another vector + /// @param v The vector to project + /// @param n The normal vecto to project on + /// @return The projected vector + public static Vector3Float Project(Vector3Float v, Vector3Float n) { + float sqrMagnitude = Dot(n, n); + if (sqrMagnitude < Float.epsilon) + return zero; + else { + float dot = Dot(v, n); + Vector3Float r = n * dot / sqrMagnitude; + return r; + } + } + + /// @brief Project the vector on a plane defined by a normal orthogonal to the + /// plane. + /// @param v The vector to project + /// @param n The normal of the plane to project on + /// @return Teh projected vector + public static Vector3Float ProjectOnPlane(Vector3Float v, Vector3Float n) { + Vector3Float r = v - Project(v, n); + return r; + } + + /// @brief The angle between two vectors + /// @param v1 The first vector + /// @param v2 The second vector + /// @return The angle between the two vectors + /// @remark This reterns an unsigned angle which is the shortest distance + /// between the two vectors. Use Vector3::SignedAngle if a signed angle is + /// needed. + public static AngleFloat UnsignedAngle(Vector3Float v1, Vector3Float v2) { + float denominator = MathF.Sqrt(v1.sqrMagnitude * v2.sqrMagnitude); + if (denominator < Float.epsilon) + return AngleFloat.zero; + + float dot = Dot(v1, v2); + float fraction = dot / denominator; + if (float.IsNaN(fraction)) + return AngleFloat.Degrees( + fraction); // short cut to returning NaN universally + + float cdot = Float.Clamp(fraction, -1.0f, 1.0f); + float r = MathF.Acos(cdot); + return AngleFloat.Radians(r); + } + /// @brief The signed angle between two vectors + /// @param v1 The starting vector + /// @param v2 The ending vector + /// @param axis The axis to rotate around + /// @return The signed angle between the two vectors + public static AngleFloat SignedAngle(Vector3Float v1, Vector3Float v2, + Vector3Float axis) { + // angle in [0,180] + AngleFloat angle = UnsignedAngle(v1, v2); + + Vector3Float cross = Cross(v1, v2); + float b = Dot(axis, cross); + float signd = b < 0 ? -1.0F : (b > 0 ? 1.0F : 0.0F); + + // angle in [-179,180] + AngleFloat signed_angle = angle * signd; + + return signed_angle; + } + + + /// @brief Lerp (linear interpolation) between two vectors + /// @param v1 The starting vector + /// @param v2 The ending vector + /// @param f The interpolation distance + /// @return The lerped vector + /// @remark The factor f is unclamped. Value 0 matches the vector *v1*, Value + /// 1 matches vector *v2*. Value -1 is vector *v1* minus the difference + /// between *v1* and *v2* etc. + public static Vector3Float Lerp(Vector3Float v1, Vector3Float v2, float f) { + Vector3Float v = v1 + (v2 - v1) * f; + return v; + } + + } +} +//#endif \ No newline at end of file diff --git a/LinearAlgebra/src/Vector3Int.cs b/LinearAlgebra/src/Vector3Int.cs new file mode 100644 index 0000000..18edf40 --- /dev/null +++ b/LinearAlgebra/src/Vector3Int.cs @@ -0,0 +1,273 @@ +//#if !UNITY_5_3_OR_NEWER +using System; + +namespace LinearAlgebra { + + /// + /// 3-dimensional vectors + /// + /// This uses the right-handed coordinate system. + /// + /// Create a new 3-dimensional vector + /// + /// x axis value + /// y axis value + /// z axis value + public struct Vector3Int { + + /// + /// The right axis of the vector + /// + public int horizontal; //> left/right + /// + /// The upward axis of the vector + /// + public int vertical; //> up/down + /// + /// The forward axis of the vector + /// + public int depth; //> forward/backward + + public Vector3Int(int horizontal, int vertical, int depth) { + this.horizontal = horizontal; + this.vertical = vertical; + this.depth = depth; + } + + /// + /// A vector with zero for all axis + /// + public static readonly Vector3Int zero = new(0, 0, 0); + /// + /// A vector with one for all axis + /// + public static readonly Vector3Int one = new(1, 1, 1); + /// + /// A Vector3Int with values (-1, 0, 0) + /// + public static readonly Vector3Int left = new(-1, 0, 0); + /// + /// A vector with values (1, 0, 0) + /// + public static readonly Vector3Int right = new(1, 0, 0); + /// + /// A vector with values (0, -1, 0) + /// + public static readonly Vector3Int down = new(0, -1, 0); + /// + /// A vector with values (0, 1, 0) + /// + public static readonly Vector3Int up = new(0, 1, 0); + /// + /// A vector with values (0, 0, -1) + /// + public static readonly Vector3Int back = new(0, -1, 0); + /// + /// A vector with values (0, 0, 1) + /// + public static readonly Vector3Int forward = new(0, 1, 0); + + /// @brief The vector length + /// @return The vector length + public readonly float magnitude => MathF.Sqrt(horizontal * horizontal + vertical * vertical + depth * depth); + /// + /// The vector length + /// + /// The vector for which you need the length + /// The vector length + public static float MagnitudeOf(Vector3Int v) { + return v.magnitude; + } + + /// @brief The squared vector length + /// @return The squared vector length + /// @remark The squared length is computationally simpler than the real + /// length. Think of Pythagoras A^2 + B^2 = C^2. This leaves out the + /// calculation of the squared root of C. + public readonly float sqrMagnitude => (horizontal * horizontal + vertical * vertical + depth * depth); + + /// + /// The squared vector length + /// + /// The vector for which you need the squared length + /// The squared vector length + /// The squared length is computationally simpler than the real + /// length. Think of Pythagoras A^2 + B^2 = C^2. This leaves out the + /// calculation of the squared root of C. + public static float SqrMagnitudeOf(Vector3Int v) { + return v.sqrMagnitude; + } + + /// @brief Convert the vector to a length of 1 + /// @return The vector normalized to a length of 1 + public readonly Vector3Float normalized { + get { + float l = magnitude; + Vector3Float v = Vector3Float.zero; + if (l > Float.epsilon) + v = new Vector3Float(this) / l; + return v; + } + } + /// @brief Convert the vector to a length of 1 + /// @param v The vector to convert + /// @return The vector normalized to a length of 1 + public static Vector3Float Normalize(Vector3Int v) { + float num = v.magnitude; + Vector3Float result = Vector3Float.zero; + if (num > Float.epsilon) + result = new Vector3Float(v) / num; + + return result; + } + + /// + /// Negate te vector such that it points in the opposite direction + /// + /// + /// The negated vector + public static Vector3Int operator -(Vector3Int v1) { + Vector3Int v = new(-v1.horizontal, -v1.vertical, -v1.depth); + return v; + } + + /// + /// Subtract two vectors + /// + /// + /// + /// The result of the subtraction + public static Vector3Int operator -(Vector3Int v1, Vector3Int v2) { + Vector3Int v = new(v1.horizontal - v2.horizontal, v1.vertical - v2.vertical, v1.depth - v2.depth); + return v; + } + + /// + /// Add two vectors + /// + /// + /// + /// The result of the addition + public static Vector3Int operator +(Vector3Int v1, Vector3Int v2) { + Vector3Int v = new(v1.horizontal + v2.horizontal, v1.vertical + v2.vertical, v1.depth + v2.depth); + return v; + } + + /// @brief Scale the vector using another vector + /// @param v1 The vector to scale + /// @param v2 A vector with the scaling factors + /// @return The scaled vector + /// @remark Each component of the vector v1 will be multiplied with the + /// matching component from the scaling vector v2. + public static Vector3Int Scale(Vector3Int v1, Vector3Int v2) { + return new Vector3Int(v1.horizontal * v2.horizontal, v1.vertical * v2.vertical, v1.depth * v2.depth); + } + + + public static Vector3Int operator *(Vector3Int v1, int d) { + Vector3Int v = new(v1.horizontal * d, v1.vertical * d, v1.depth * d); + return v; + } + + public static Vector3Int operator *(int d, Vector3Int v1) { + Vector3Int v = new(d * v1.horizontal, d * v1.vertical, d * v1.depth); + return v; + } + + public static Vector3Int operator /(Vector3Int v1, int d) { + Vector3Int v = new(v1.horizontal / d, v1.vertical / d, v1.depth / d); + return v; + } + + public bool Equals(Vector3Int v) => (horizontal == v.horizontal && vertical == v.vertical && depth == v.depth); + + public override bool Equals(object obj) { + if (!(obj is Vector3Int v)) + return false; + + return (horizontal == v.horizontal && vertical == v.vertical && depth == v.depth); + } + + public static bool operator ==(Vector3Int v1, Vector3Int v2) { + return (v1.horizontal == v2.horizontal && v1.vertical == v2.vertical && v1.depth == v2.depth); + } + + public static bool operator !=(Vector3Int v1, Vector3Int v2) { + return (v1.horizontal != v2.horizontal || v1.vertical != v2.vertical || v1.depth != v2.depth); + } + + public override int GetHashCode() { + return (horizontal, vertical, depth).GetHashCode(); + } + + /// @brief The distance between two vectors + /// @param v1 The first vector + /// @param v2 The second vector + /// @return The distance between the two vectors + public static float Distance(Vector3Int v1, Vector3Int v2) { + return (v2 - v1).magnitude; + } + + /// @brief The dot product of two vectors + /// @param v1 The first vector + /// @param v2 The second vector + /// @return The dot product of the two vectors + public static float Dot(Vector3Int v1, Vector3Int v2) { + return v1.horizontal * v2.horizontal + v1.vertical * v2.vertical + v1.depth * v2.depth; + } + + /// @brief The cross product of two vectors + /// @param v1 The first vector + /// @param v2 The second vector + /// @return The cross product of the two vectors + public static Vector3Int Cross(Vector3Int v1, Vector3Int v2) { + return new Vector3Int(v1.vertical * v2.depth - v1.depth * v2.vertical, v1.depth * v2.horizontal - v1.horizontal * v2.depth, + v1.horizontal * v2.vertical - v1.vertical * v2.horizontal); + + } + + /// @brief The angle between two vectors + /// @param v1 The first vector + /// @param v2 The second vector + /// @return The angle between the two vectors + /// @remark This reterns an unsigned angle which is the shortest distance + /// between the two vectors. Use Vector3::SignedAngle if a signed angle is + /// needed. + public static AngleFloat UnsignedAngle(Vector3Int v1, Vector3Int v2) { + float denominator = MathF.Sqrt(v1.sqrMagnitude * v2.sqrMagnitude); + if (denominator < Float.epsilon) + return AngleFloat.zero; + + float dot = Dot(v1, v2); + float fraction = dot / denominator; + if (float.IsNaN(fraction)) + return AngleFloat.Degrees( + fraction); // short cut to returning NaN universally + + float cdot = Float.Clamp(fraction, -1.0f, 1.0f); + float r = MathF.Acos(cdot); + return AngleFloat.Radians(r); + } + /// @brief The signed angle between two vectors + /// @param v1 The starting vector + /// @param v2 The ending vector + /// @param axis The axis to rotate around + /// @return The signed angle between the two vectors + public static AngleFloat SignedAngle(Vector3Int v1, Vector3Int v2, + Vector3Int axis) { + // angle in [0,180] + AngleFloat angle = UnsignedAngle(v1, v2); + + Vector3Int cross = Cross(v1, v2); + float b = Dot(axis, cross); + float signd = b < 0 ? -1.0F : (b > 0 ? 1.0F : 0.0F); + + // angle in [-179,180] + AngleFloat signed_angle = angle * signd; + + return signed_angle; + } + + } +} +//#endif \ No newline at end of file diff --git a/LinearAlgebra/src/float16.cs b/LinearAlgebra/src/float16.cs new file mode 100644 index 0000000..4b58cdd --- /dev/null +++ b/LinearAlgebra/src/float16.cs @@ -0,0 +1,322 @@ +using System; + +namespace LinearAlgebra { + + public class float16 { + // + // FILE: float16.cpp + // AUTHOR: Rob Tillaart + // VERSION: 0.1.8 + // PURPOSE: library for Float16s for Arduino + // URL: http://en.wikipedia.org/wiki/Half-precision_floating-point_format + + ushort _value; + + public float16() { _value = 0; } + + public float16(float f) { + //_value = f32tof16(f); + _value = F32ToF16__(f); + } + + public float toFloat() { + return f16tof32(_value); + } + + public ushort GetBinary() { return _value; } + public void SetBinary(ushort value) { _value = value; } + + ////////////////////////////////////////////////////////// + // + // EQUALITIES + // + /* + bool float16::operator ==(const float16 &f) { return (_value == f._value); } + + bool float16::operator !=(const float16 &f) { return (_value != f._value); } + + bool float16::operator >(const float16 &f) { + if ((_value & 0x8000) && (f._value & 0x8000)) + return _value < f._value; + if (_value & 0x8000) + return false; + if (f._value & 0x8000) + return true; + return _value > f._value; + } + + bool float16::operator >=(const float16 &f) { + if ((_value & 0x8000) && (f._value & 0x8000)) + return _value <= f._value; + if (_value & 0x8000) + return false; + if (f._value & 0x8000) + return true; + return _value >= f._value; + } + + bool float16::operator <(const float16 &f) { + if ((_value & 0x8000) && (f._value & 0x8000)) + return _value > f._value; + if (_value & 0x8000) + return true; + if (f._value & 0x8000) + return false; + return _value < f._value; + } + + bool float16::operator <=(const float16 &f) { + if ((_value & 0x8000) && (f._value & 0x8000)) + return _value >= f._value; + if (_value & 0x8000) + return true; + if (f._value & 0x8000) + return false; + return _value <= f._value; + } + + ////////////////////////////////////////////////////////// + // + // NEGATION + // + float16 float16::operator -() { + float16 f16; + f16.setBinary(_value ^ 0x8000); + return f16; + } + + ////////////////////////////////////////////////////////// + // + // MATH + // + float16 float16::operator +(const float16 &f) { + return float16(this->toDouble() + f.toDouble()); + } + + float16 float16::operator -(const float16 &f) { + return float16(this->toDouble() - f.toDouble()); + } + + float16 float16::operator *(const float16 &f) { + return float16(this->toDouble() * f.toDouble()); + } + + float16 float16::operator /(const float16 &f) { + return float16(this->toDouble() / f.toDouble()); + } + + float16 & float16::operator+=(const float16 &f) { + *this = this->toDouble() + f.toDouble(); + return *this; + } + + float16 & float16::operator-=(const float16 &f) { + *this = this->toDouble() - f.toDouble(); + return *this; + } + + float16 & float16::operator*=(const float16 &f) { + *this = this->toDouble() * f.toDouble(); + return *this; + } + + float16 & float16::operator/=(const float16 &f) { + *this = this->toDouble() / f.toDouble(); + return *this; + } + + ////////////////////////////////////////////////////////// + // + // MATH HELPER FUNCTIONS + // + int float16::sign() { + if (_value & 0x8000) + return -1; + if (_value & 0xFFFF) + return 1; + return 0; + } + + bool float16::isZero() { return ((_value & 0x7FFF) == 0x0000); } + + bool float16::isNaN() { + if ((_value & 0x7C00) != 0x7C00) + return false; + if ((_value & 0x03FF) == 0x0000) + return false; + return true; + } + + bool float16::isInf() { return ((_value == 0x7C00) || (_value == 0xFC00)); } + */ + ////////////////////////////////////////////////////////// + // + // CORE CONVERSION + // + float f16tof32(ushort _value) { + //ushort sgn; + ushort man; + int exp; + float f; + + //Debug.Log($"{_value}"); + + bool sgn = (_value & 0x8000) > 0; + exp = (_value & 0x7C00) >> 10; + man = (ushort)(_value & 0x03FF); + + //Debug.Log($"{sgn} {exp} {man}"); + + // ZERO + if ((_value & 0x7FFF) == 0) { + return sgn ? -0 : 0; + } + // NAN & INF + if (exp == 0x001F) { + if (man == 0) + return sgn ? float.NegativeInfinity : float.PositiveInfinity; //-INFINITY : INFINITY; + else + return float.NaN; // NAN; + } + + // SUBNORMAL/NORMAL + if (exp == 0) + f = 0; + else + f = 1; + + // PROCESS MANTISSE + for (int i = 9; i >= 0; i--) { + f *= 2; + if ((man & (1 << i)) != 0) + f = f + 1; + } + //Debug.Log($"{f}"); + f = f * (float)Math.Pow(2.0f, exp - 25); + if (exp == 0) { + f = f * (float)Math.Pow(2.0f, -13); // 5.96046447754e-8; + } + //Debug.Log($"{f}"); + return sgn ? -f : f; + } + + public static uint SingleToInt32Bits(float value) { + byte[] bytes = BitConverter.GetBytes(value); + if (BitConverter.IsLittleEndian) + Array.Reverse(bytes); // If the system is little-endian, reverse the byte order + return BitConverter.ToUInt32(bytes, 0); + } + + public ushort F32ToF16__(float f) { + uint t = BitConverter.ToUInt32(BitConverter.GetBytes(f), 0); + ushort man = (ushort)((t & 0x007FFFFF) >> 12); + int exp = (int)((t & 0x7F800000) >> 23); + bool sgn = (t & 0x80000000) != 0; + + // handle 0 + if ((t & 0x7FFFFFFF) == 0) { + return sgn ? (ushort)0x8000 : (ushort)0x0000; + } + // denormalized float32 does not fit in float16 + if (exp == 0x00) { + return sgn ? (ushort)0x8000 : (ushort)0x0000; + } + // handle infinity & NAN + if (exp == 0x00FF) { + if (man != 0) + return 0xFE00; // NAN + return sgn ? (ushort)0xFC00 : (ushort)0x7C00; // -INF : INF + } + + // normal numbers + exp = exp - 127 + 15; + // overflow does not fit => INF + if (exp > 30) { + return sgn ? (ushort)0xFC00 : (ushort)0x7C00; // -INF : INF + } + // subnormal numbers + if (exp < -38) { + return sgn ? (ushort)0x8000 : (ushort)0x0000; // -0 or 0 ? just 0 ? + } + if (exp <= 0) // subnormal + { + man >>= (exp + 14); + // rounding + man++; + man >>= 1; + if (sgn) + return (ushort)(0x8000 | man); + return man; + } + + // normal + // TODO rounding + exp <<= 10; + man++; + man >>= 1; + if (sgn) + return (ushort)(0x8000 | exp | man); + return (ushort)(exp | man); + } + + //This function is faulty!!!! + ushort f32tof16(float f) { + //uint t = *(uint*)&f; + //uint t = (uint)BitConverter.SingleToInt32Bits(f); + uint t = SingleToInt32Bits(f); + // man bits = 10; but we keep 11 for rounding + ushort man = (ushort)((t & 0x007FFFFF) >> 12); + short exp = (short)((t & 0x7F800000) >> 23); + bool sgn = (t & 0x80000000) != 0; + + // handle 0 + if ((t & 0x7FFFFFFF) == 0) { + return sgn ? (ushort)0x8000 : (ushort)0x0000; + } + // denormalized float32 does not fit in float16 + if (exp == 0x00) { + return sgn ? (ushort)0x8000 : (ushort)0x0000; + } + // handle infinity & NAN + if (exp == 0x00FF) { + if (man != 0) + return 0xFE00; // NAN + return sgn ? (ushort)0xFC00 : (ushort)0x7C00; // -INF : INF + } + + // normal numbers + exp = (short)(exp - 127 + 15); + // overflow does not fit => INF + if (exp > 30) { + return sgn ? (ushort)0xFC00 : (ushort)0x7C00; // -INF : INF + } + // subnormal numbers + if (exp < -38) { + return sgn ? (ushort)0x8000 : (ushort)0x0000; // -0 or 0 ? just 0 ? + } + if (exp <= 0) // subnormal + { + man >>= (exp + 14); + // rounding + man++; + man >>= 1; + if (sgn) + return (ushort)(0x8000 | man); + return man; + } + + // normal + // TODO rounding + exp <<= 10; + man++; + man >>= 1; + ushort uexp = (ushort)exp; + if (sgn) + return (ushort)(0x8000 | uexp | man); + return (ushort)(uexp | man); + } + + // -- END OF FILE -- + } + +} \ No newline at end of file diff --git a/LinearAlgebra/test/AngleTest.cs b/LinearAlgebra/test/AngleTest.cs new file mode 100644 index 0000000..8362d82 --- /dev/null +++ b/LinearAlgebra/test/AngleTest.cs @@ -0,0 +1,501 @@ +#if !UNITY_5_6_OR_NEWER +using System; +using System.Formats.Asn1; +using NUnit.Framework; + +namespace LinearAlgebra.Test { + public class AngleTests { + [SetUp] + public void Setup() { + } + + [Test] + public void Construct() { + // Degrees + float angle = 0.0f; + AngleFloat a = AngleFloat.Degrees(angle); + Assert.AreEqual(angle, a.inDegrees); + + angle = -180.0f; + a = AngleFloat.Degrees(angle); + Assert.AreEqual(angle, a.inDegrees); + + angle = 270.0f; + a = AngleFloat.Degrees(angle); + Assert.AreEqual(-90, a.inDegrees); + + angle = -270.0f; + a = AngleFloat.Degrees(angle); + Assert.AreEqual(90, a.inDegrees); + + // Radians + angle = 0.0f; + a = AngleFloat.Radians(angle); + Assert.AreEqual(angle, a.inRadians); + + angle = (float)-Math.PI; + a = AngleFloat.Radians(angle); + Assert.AreEqual(angle, a.inRadians); + + angle = (float)Math.PI * 1.5f; + a = AngleFloat.Radians(angle); + Assert.AreEqual(-Math.PI * 0.5f, a.inRadians, 1.0E-05F); + + // Revolutions + angle = 0.0f; + a = AngleFloat.Revolutions(angle); + Assert.AreEqual(angle, a.inRevolutions); + + angle = -0.5f; + a = AngleFloat.Revolutions(angle); + Assert.AreEqual(angle, a.inRevolutions); + + angle = 0.75f; + a = AngleFloat.Revolutions(angle); + Assert.AreEqual(-0.25f, a.inRevolutions); + + } + + [Test] + public void Revolutions() { + AngleFloat a; + + // Test zero + a = AngleFloat.Revolutions(0.0f); + Assert.AreEqual(0.0f, a.inRevolutions); + + // Test positive values within range + a = AngleFloat.Revolutions(0.25f); + Assert.AreEqual(0.25f, a.inRevolutions); + + a = AngleFloat.Revolutions(0.5f); + Assert.AreEqual(-0.5f, a.inRevolutions); + + // Test negative values within range + a = AngleFloat.Revolutions(-0.25f); + Assert.AreEqual(-0.25f, a.inRevolutions); + + a = AngleFloat.Revolutions(-0.5f); + Assert.AreEqual(-0.5f, a.inRevolutions); + + // Test values outside range (positive) + a = AngleFloat.Revolutions(1.0f); + Assert.AreEqual(0.0f, a.inRevolutions); + + a = AngleFloat.Revolutions(1.25f); + Assert.AreEqual(0.25f, a.inRevolutions); + + a = AngleFloat.Revolutions(1.75f); + Assert.AreEqual(-0.25f, a.inRevolutions); + + // Test values outside range (negative) + a = AngleFloat.Revolutions(-1.0f); + Assert.AreEqual(0.0f, a.inRevolutions); + + a = AngleFloat.Revolutions(-1.25f); + Assert.AreEqual(-0.25f, a.inRevolutions); + + a = AngleFloat.Revolutions(-1.75f); + Assert.AreEqual(0.25f, a.inRevolutions); + + // Test infinity + a = AngleFloat.Revolutions(float.PositiveInfinity); + Assert.AreEqual(float.PositiveInfinity, a.inRevolutions); + + a = AngleFloat.Revolutions(float.NegativeInfinity); + Assert.AreEqual(float.NegativeInfinity, a.inRevolutions); + } + + [Test] + public void Equality() { + // Test equality operator + Assert.IsTrue(AngleFloat.Degrees(90) == AngleFloat.Degrees(90), "90 == 90"); + Assert.IsFalse(AngleFloat.Degrees(90) == AngleFloat.Degrees(45), "90 == 45"); + Assert.IsTrue(AngleFloat.Degrees(0) == AngleFloat.Degrees(0), "0 == 0"); + Assert.IsTrue(AngleFloat.Degrees(-180) == AngleFloat.Degrees(-180), "-180 == -180"); + + // Test inequality operator + Assert.IsTrue(AngleFloat.Degrees(90) != AngleFloat.Degrees(45), "90 != 45"); + Assert.IsFalse(AngleFloat.Degrees(90) != AngleFloat.Degrees(90), "90 != 90"); + Assert.IsTrue(AngleFloat.Degrees(0) != AngleFloat.Degrees(1), "0 != 1"); + + // Test greater than operator + Assert.IsTrue(AngleFloat.Degrees(90) > AngleFloat.Degrees(45), "90 > 45"); + Assert.IsFalse(AngleFloat.Degrees(45) > AngleFloat.Degrees(90), "45 > 90"); + Assert.IsFalse(AngleFloat.Degrees(90) > AngleFloat.Degrees(90), "90 > 90"); + + // Test greater than or equal operator + Assert.IsTrue(AngleFloat.Degrees(90) >= AngleFloat.Degrees(45), "90 >= 45"); + Assert.IsTrue(AngleFloat.Degrees(90) >= AngleFloat.Degrees(90), "90 >= 90"); + Assert.IsFalse(AngleFloat.Degrees(45) >= AngleFloat.Degrees(90), "45 >= 90"); + + // Test less than operator + Assert.IsTrue(AngleFloat.Degrees(45) < AngleFloat.Degrees(90), "45 < 90"); + Assert.IsFalse(AngleFloat.Degrees(90) < AngleFloat.Degrees(45), "90 < 45"); + Assert.IsFalse(AngleFloat.Degrees(90) < AngleFloat.Degrees(90), "90 < 90"); + + // Test less than or equal operator + Assert.IsTrue(AngleFloat.Degrees(45) <= AngleFloat.Degrees(90), "45 <= 90"); + Assert.IsTrue(AngleFloat.Degrees(90) <= AngleFloat.Degrees(90), "90 <= 90"); + Assert.IsFalse(AngleFloat.Degrees(90) <= AngleFloat.Degrees(45), "90 <= 45"); + } + + // [Test] + // public void Normalize() { + // float r = 0; + + // r = Angle.Normalize(90); + // Assert.AreEqual(r, 90, "Normalize 90"); + + // r = Angle.Normalize(-90); + // Assert.AreEqual(r, -90, "Normalize -90"); + + // r = Angle.Normalize(270); + // Assert.AreEqual(r, -90, "Normalize 270"); + + // r = Angle.Normalize(270 + 360); + // Assert.AreEqual(r, -90, "Normalize 270+360"); + + // r = Angle.Normalize(-270); + // Assert.AreEqual(r, 90, "Normalize -270"); + + // r = Angle.Normalize(-270 - 360); + // Assert.AreEqual(r, 90, "Normalize -270-360"); + + // r = Angle.Normalize(0); + // Assert.AreEqual(r, 0, "Normalize 0"); + + // r = Angle.Normalize(float.PositiveInfinity); + // Assert.AreEqual(r, float.PositiveInfinity, "Normalize INFINITY"); + + // r = Angle.Normalize(float.NegativeInfinity); + // Assert.AreEqual(r, float.NegativeInfinity, "Normalize INFINITY"); + // } + + [Test] + public void Clamp() { + float r = 0; + + r = AngleFloat.Clamp(AngleFloat.Degrees(1), AngleFloat.Degrees(0), AngleFloat.Degrees(2)); + Assert.AreEqual(1, r, "Clamp 1 0 2"); + + r = AngleFloat.Clamp(AngleFloat.Degrees(-1), AngleFloat.Degrees(0), AngleFloat.Degrees(2)); + Assert.AreEqual(0, r, "Clamp -1 0 2"); + + r = AngleFloat.Clamp(AngleFloat.Degrees(3), AngleFloat.Degrees(0), AngleFloat.Degrees(2)); + Assert.AreEqual(2, r, "Clamp 3 0 2"); + + r = AngleFloat.Clamp(AngleFloat.Degrees(1), AngleFloat.Degrees(0), AngleFloat.Degrees(0)); + Assert.AreEqual(0, r, "Clamp 1 0 0"); + + r = AngleFloat.Clamp(AngleFloat.Degrees(0), AngleFloat.Degrees(0), AngleFloat.Degrees(0)); + Assert.AreEqual(0, r, "Clamp 0 0 0"); + + r = AngleFloat.Clamp(AngleFloat.Degrees(0), AngleFloat.Degrees(1), AngleFloat.Degrees(-1)); + Assert.AreEqual(1, r, "Clamp 0 1 -1"); + + r = AngleFloat.Clamp(AngleFloat.Degrees(1), AngleFloat.Degrees(0), AngleFloat.Degrees(float.PositiveInfinity)); + Assert.AreEqual(1, r, "Clamp 1 0 INFINITY"); + + r = AngleFloat.Clamp(AngleFloat.Degrees(1), AngleFloat.Degrees(float.NegativeInfinity), AngleFloat.Degrees(1)); + Assert.AreEqual(1, r, "Clamp 1 -INFINITY 1"); + } + + [Test] + public void Cos() { + // Test zero + Assert.AreEqual(1.0f, AngleFloat.Cos(AngleFloat.Degrees(0)), 1.0E-05F, "Cos(0°)"); + + // Test 90 degrees + Assert.AreEqual(0.0f, AngleFloat.Cos(AngleFloat.Degrees(90)), 1.0E-05F, "Cos(90°)"); + + // Test 180 degrees + Assert.AreEqual(-1.0f, AngleFloat.Cos(AngleFloat.Degrees(180)), 1.0E-05F, "Cos(180°)"); + + // Test 270 degrees + Assert.AreEqual(0.0f, AngleFloat.Cos(AngleFloat.Degrees(270)), 1.0E-05F, "Cos(270°)"); + + // Test 45 degrees + Assert.AreEqual(MathF.Sqrt(2) / 2, AngleFloat.Cos(AngleFloat.Degrees(45)), 1.0E-05F, "Cos(45°)"); + + // Test negative angle + Assert.AreEqual(1.0f, AngleFloat.Cos(AngleFloat.Degrees(-360)), 1.0E-05F, "Cos(-360°)"); + + // Test using radians + Assert.AreEqual(1.0f, AngleFloat.Cos(AngleFloat.Radians(0)), 1.0E-05F, "Cos(0 rad)"); + Assert.AreEqual(0.0f, AngleFloat.Cos(AngleFloat.Radians((float)Math.PI / 2)), 1.0E-05F, "Cos(π/2)"); + Assert.AreEqual(-1.0f, AngleFloat.Cos(AngleFloat.Radians((float)Math.PI)), 1.0E-05F, "Cos(π)"); + } + + [Test] + public void Sin() { + // Test zero + Assert.AreEqual(0.0f, AngleFloat.Sin(AngleFloat.Degrees(0)), 1.0E-05F, "Sin(0°)"); + + // Test 90 degrees + Assert.AreEqual(1.0f, AngleFloat.Sin(AngleFloat.Degrees(90)), 1.0E-05F, "Sin(90°)"); + + // Test 180 degrees + Assert.AreEqual(0.0f, AngleFloat.Sin(AngleFloat.Degrees(180)), 1.0E-05F, "Sin(180°)"); + + // Test 270 degrees + Assert.AreEqual(-1.0f, AngleFloat.Sin(AngleFloat.Degrees(270)), 1.0E-05F, "Sin(270°)"); + + // Test 45 degrees + Assert.AreEqual(MathF.Sqrt(2) / 2, AngleFloat.Sin(AngleFloat.Degrees(45)), 1.0E-05F, "Sin(45°)"); + + // Test negative angle + Assert.AreEqual(0.0f, AngleFloat.Sin(AngleFloat.Degrees(-360)), 1.0E-05F, "Sin(-360°)"); + + // Test using radians + Assert.AreEqual(0.0f, AngleFloat.Sin(AngleFloat.Radians(0)), 1.0E-05F, "Sin(0 rad)"); + Assert.AreEqual(1.0f, AngleFloat.Sin(AngleFloat.Radians((float)Math.PI / 2)), 1.0E-05F, "Sin(π/2)"); + Assert.AreEqual(0.0f, AngleFloat.Sin(AngleFloat.Radians((float)Math.PI)), 1.0E-05F, "Sin(π)"); + } + + [Test] + public void Tan() { + // Test zero + Assert.AreEqual(0.0f, AngleFloat.Tan(AngleFloat.Degrees(0)), 1.0E-05F, "Tan(0°)"); + + // Test 45 degrees + Assert.AreEqual(1.0f, AngleFloat.Tan(AngleFloat.Degrees(45)), 1.0E-05F, "Tan(45°)"); + + // Test -45 degrees + Assert.AreEqual(-1.0f, AngleFloat.Tan(AngleFloat.Degrees(-45)), 1.0E-05F, "Tan(-45°)"); + + // Test using radians + Assert.AreEqual(0.0f, AngleFloat.Tan(AngleFloat.Radians(0)), 1.0E-05F, "Tan(0 rad)"); + Assert.AreEqual(1.0f, AngleFloat.Tan(AngleFloat.Radians((float)Math.PI / 4)), 1.0E-05F, "Tan(π/4)"); + } + + [Test] + public void Acos() { + // Test 1 (0 degrees) + Assert.AreEqual(0.0f, AngleFloat.Acos(1.0f).inRadians, 1.0E-05F, "Acos(1)"); + + // Test 0 (90 degrees or π/2 radians) + Assert.AreEqual((float)Math.PI / 2, AngleFloat.Acos(0.0f).inRadians, 1.0E-05F, "Acos(0)"); + + // Test -1 (-180 degrees or π radians) + Assert.AreEqual((float)-Math.PI, AngleFloat.Acos(-1.0f).inRadians, 1.0E-05F, "Acos(-1)"); + + // Test 0.5 (60 degrees or π/3 radians) + Assert.AreEqual((float)Math.PI / 3, AngleFloat.Acos(0.5f).inRadians, 1.0E-05F, "Acos(0.5)"); + + // Test sqrt(2)/2 (45 degrees or π/4 radians) + Assert.AreEqual((float)Math.PI / 4, AngleFloat.Acos(MathF.Sqrt(2) / 2).inRadians, 1.0E-05F, "Acos(√2/2)"); + } + + [Test] + public void Asin() { + // Test 0 (0 degrees) + Assert.AreEqual(0.0f, AngleFloat.Asin(0.0f).inRadians, 1.0E-05F, "Asin(0)"); + + // Test 1 (90 degrees or π/2 radians) + Assert.AreEqual((float)Math.PI / 2, AngleFloat.Asin(1.0f).inRadians, 1.0E-05F, "Asin(1)"); + + // Test -1 (-90 degrees or -π/2 radians) + Assert.AreEqual(-(float)Math.PI / 2, AngleFloat.Asin(-1.0f).inRadians, 1.0E-05F, "Asin(-1)"); + + // Test 0.5 (30 degrees or π/6 radians) + Assert.AreEqual((float)Math.PI / 6, AngleFloat.Asin(0.5f).inRadians, 1.0E-05F, "Asin(0.5)"); + + // Test sqrt(2)/2 (45 degrees or π/4 radians) + Assert.AreEqual((float)Math.PI / 4, AngleFloat.Asin(MathF.Sqrt(2) / 2).inRadians, 1.0E-05F, "Asin(√2/2)"); + } + + + [Test] + public void Atan() { + // Test zero + Assert.AreEqual(0.0f, AngleFloat.Atan(0.0f).inRadians, 1.0E-05F, "Atan(0)"); + + // Test 1 (45 degrees or π/4 radians) + Assert.AreEqual((float)Math.PI / 4, AngleFloat.Atan(1.0f).inRadians, 1.0E-05F, "Atan(1)"); + + // Test -1 (-45 degrees or -π/4 radians) + Assert.AreEqual(-(float)Math.PI / 4, AngleFloat.Atan(-1.0f).inRadians, 1.0E-05F, "Atan(-1)"); + + // Test sqrt(3) (60 degrees or π/3 radians) + Assert.AreEqual((float)Math.PI / 3, AngleFloat.Atan(MathF.Sqrt(3)).inRadians, 1.0E-05F, "Atan(√3)"); + + // Test 1/sqrt(3) (30 degrees or π/6 radians) + Assert.AreEqual((float)Math.PI / 6, AngleFloat.Atan(1.0f / MathF.Sqrt(3)).inRadians, 1.0E-05F, "Atan(1/√3)"); + + // Test positive infinity + Assert.AreEqual((float)Math.PI / 2, AngleFloat.Atan(float.PositiveInfinity).inRadians, 1.0E-05F, "Atan(+∞)"); + + // Test negative infinity + Assert.AreEqual(-(float)Math.PI / 2, AngleFloat.Atan(float.NegativeInfinity).inRadians, 1.0E-05F, "Atan(-∞)"); + } + + [Test] + public void Atan2() { + // Test basic quadrant I + Assert.AreEqual((float)Math.PI / 4, AngleFloat.Atan2(1.0f, 1.0f).inRadians, 1.0E-05F, "Atan2(1, 1)"); + + // Test quadrant II + Assert.AreEqual(3 * (float)Math.PI / 4, AngleFloat.Atan2(1.0f, -1.0f).inRadians, 1.0E-05F, "Atan2(1, -1)"); + + // Test quadrant III + Assert.AreEqual(-(float)Math.PI * 0.75f, AngleFloat.Atan2(-1.0f, -1.0f).inRadians, 1.0E-05F, "Atan2(-1, -1)"); + + // Test quadrant IV + Assert.AreEqual(-(float)Math.PI / 4, AngleFloat.Atan2(-1.0f, 1.0f).inRadians, 1.0E-05F, "Atan2(-1, 1)"); + + // Test positive x-axis + Assert.AreEqual(0.0f, AngleFloat.Atan2(0.0f, 1.0f).inRadians, 1.0E-05F, "Atan2(0, 1)"); + + // Test positive y-axis + Assert.AreEqual((float)Math.PI / 2, AngleFloat.Atan2(1.0f, 0.0f).inRadians, 1.0E-05F, "Atan2(1, 0)"); + + // Test negative y-axis + Assert.AreEqual(-(float)Math.PI / 2, AngleFloat.Atan2(-1.0f, 0.0f).inRadians, 1.0E-05F, "Atan2(-1, 0)"); + + // Test origin + Assert.AreEqual(0.0f, AngleFloat.Atan2(0.0f, 0.0f).inRadians, 1.0E-05F, "Atan2(0, 0)"); + + // Test with different magnitudes + Assert.AreEqual((float)Math.PI / 3, AngleFloat.Atan2(MathF.Sqrt(3), 1.0f).inRadians, 1.0E-05F, "Atan2(√3, 1)"); + + // Test negative x-axis + Assert.AreEqual((float)-Math.PI, AngleFloat.Atan2(0.0f, -1.0f).inRadians, 1.0E-05F, "Atan2(0, -1)"); + } + + [Test] + public void Multiplication() { + AngleFloat r = AngleFloat.zero; + + // Angle * float + r = AngleFloat.Degrees(90) * 2; + Assert.AreEqual(-180, r.inDegrees, "Multiply 90 * 2"); + + r = AngleFloat.Degrees(45) * 0.5f; + Assert.AreEqual(22.5f, r.inDegrees, "Multiply 45 * 0.5"); + + r = AngleFloat.Degrees(90) * 0; + Assert.AreEqual(0, r.inDegrees, "Multiply 90 * 0"); + + r = AngleFloat.Degrees(-90) * 2; + Assert.AreEqual(-180, r.inDegrees, "Multiply -90 * 2"); + + r = AngleFloat.Degrees(270) * 2; + Assert.AreEqual(-180, r.inDegrees, "Multiply 270 * 2 (normalized)"); + + // float * Angle + r = 2 * AngleFloat.Degrees(90); + Assert.AreEqual(-180, r.inDegrees, "Multiply 2 * 90"); + + r = 0.5f * AngleFloat.Degrees(45); + Assert.AreEqual(22.5, r.inDegrees, "Multiply 0.5 * 45"); + + r = 0 * AngleFloat.Degrees(90); + Assert.AreEqual(0, r.inDegrees, "Multiply 0 * 90"); + + r = 2 * AngleFloat.Degrees(-90); + Assert.AreEqual(-180, r.inDegrees, "Multiply 2 * -90"); + + // Negative factor + r = AngleFloat.Degrees(90) * -1; + Assert.AreEqual(-90, r.inDegrees, "Multiply 90 * -1"); + + r = -1 * AngleFloat.Degrees(90); + Assert.AreEqual(-90, r.inDegrees, "Multiply -1 * 90"); + } + + [Test] + public void MoveTowards() { + AngleFloat r = AngleFloat.zero; + + r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(90), 30); + Assert.AreEqual(30, r.inDegrees, "MoveTowards 0 90 30"); + + r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(90), 90); + Assert.AreEqual(90, r.inDegrees, "MoveTowards 0 90 90"); + + r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(90), 180); + Assert.AreEqual(90, r.inDegrees, "MoveTowards 0 90 180"); + + r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(90), 270); + Assert.AreEqual(90, r.inDegrees, "MoveTowrads 0 90 270"); + + r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(90), -30); + Assert.AreEqual(0, r.inDegrees, "MoveTowards 0 90 -30"); + + r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(-90), -30); + Assert.AreEqual(0, r.inDegrees, "MoveTowards 0 -90 -30"); + + r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(-90), -90); + Assert.AreEqual(0, r.inDegrees, "MoveTowards 0 -90 -90"); + + r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(-90), -180); + Assert.AreEqual(0, r.inDegrees, "MoveTowards 0 -90 -180"); + + r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(-90), -270); + Assert.AreEqual(0, r.inDegrees, "MoveTowrads 0 -90 -270"); + + r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(90), 0); + Assert.AreEqual(0, r.inDegrees, "MoveTowards 0 90 0"); + + r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(0), 0); + Assert.AreEqual(0, r.inDegrees, "MoveTowards 0 0 0"); + + r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(0), 30); + Assert.AreEqual(0, r.inDegrees, "MoveTowrads 0 0 30"); + + r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(90), float.PositiveInfinity); + Assert.AreEqual(90, r.inDegrees, "MoveTowards 0 90 INFINITY"); + + r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(float.PositiveInfinity), 30); + Assert.AreEqual(30, r.inDegrees, "MoveTowrads 0 INFINITY 30"); + + r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(-90), float.NegativeInfinity); + Assert.AreEqual(0, r.inDegrees, "MoveTowards 0 -90 -INFINITY"); + + r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(float.NegativeInfinity), -30); + Assert.AreEqual(0, r.inDegrees, "MoveTowrads 0 -INFINITY -30"); + + } + + [Test] + public void Difference() { + float r = 0; + + r = Angles.Difference(0, 90); + Assert.AreEqual(90, r, "Difference 0 90"); + + r = Angles.Difference(0, -90); + Assert.AreEqual(-90, r, "Difference 0 -90"); + + r = Angles.Difference(0, 270); + Assert.AreEqual(-90, r, "Difference 0 270"); + + r = Angles.Difference(0, -270); + Assert.AreEqual(90, r, "Difference 0 -270"); + + r = Angles.Difference(90, 0); + Assert.AreEqual(-90, r, "Difference 90 0"); + + r = Angles.Difference(-90, 0); + Assert.AreEqual(90, r, "Difference -90 0"); + + r = Angles.Difference(0, 0); + Assert.AreEqual(0, r, "Difference 0 0"); + + r = Angles.Difference(90, 90); + Assert.AreEqual(0, r, "Difference 90 90"); + + r = Angles.Difference(0, float.PositiveInfinity); + Assert.AreEqual(float.PositiveInfinity, r, "Difference 0 INFINITY"); + + r = Angles.Difference(0, float.NegativeInfinity); + Assert.AreEqual(float.NegativeInfinity, r, "Difference 0 -INFINITY"); + + r = Angles.Difference(float.NegativeInfinity, float.PositiveInfinity); + Assert.AreEqual(float.PositiveInfinity, r, "Difference -INFINITY INFINITY"); + } + } + +} +#endif diff --git a/LinearAlgebra/test/DirectionTest.cs b/LinearAlgebra/test/DirectionTest.cs new file mode 100644 index 0000000..0eb9882 --- /dev/null +++ b/LinearAlgebra/test/DirectionTest.cs @@ -0,0 +1,226 @@ +#if !UNITY_5_6_OR_NEWER +using System; +using NUnit.Framework; + +namespace LinearAlgebra.Test { + public class DirectionTest { + + [Test] + public void RadiansForward() { + Direction d = Direction.Radians(0, 0); + Assert.AreEqual(0, d.horizontal.inDegrees, 0.0001f); + Assert.AreEqual(0, d.vertical.inDegrees, 0.0001f); + } + + [Test] + public void RadiansUp() { + Direction d = Direction.Radians(0, (float)Math.PI / 2); + Assert.AreEqual(0, d.horizontal.inDegrees, 0.0001f); + Assert.AreEqual(90, d.vertical.inDegrees, 0.0001f); + } + + [Test] + public void RadiansDown() { + Direction d = Direction.Radians(0, -(float)Math.PI / 2); + Assert.AreEqual(0, d.horizontal.inDegrees, 0.0001f); + Assert.AreEqual(-90, d.vertical.inDegrees, 0.0001f); + } + + [Test] + public void RadiansArbitrary() { + Direction d = Direction.Radians((float)Math.PI / 4, (float)Math.PI / 6); + Assert.AreEqual(45, d.horizontal.inDegrees, 0.0001f); + Assert.AreEqual(30, d.vertical.inDegrees, 0.0001f); + } + + [Test] + public void DegreesNormalize1() { + Direction d = Direction.Degrees(112, 91); + Assert.AreEqual(-68, d.horizontal.inDegrees, 0.0001f); + Assert.AreEqual(89, d.vertical.inDegrees, 0.0001f); + } + + [Test] + public void RadiansEquivalentToDegreesConversion() { + Direction d1 = Direction.Radians((float)Math.PI / 3, (float)Math.PI / 4); + Direction d2 = Direction.Degrees(60, 45); + Assert.AreEqual(d1.horizontal.inDegrees, d2.horizontal.inDegrees, 0.0001f); + Assert.AreEqual(d1.vertical.inDegrees, d2.vertical.inDegrees, 0.0001f); + } + + [Test] + public void ToVector3Forward() { + Direction d = Direction.forward; + Vector3Float v = d.ToVector3(); + Assert.AreEqual(0, v.horizontal, 0.0001f); + Assert.AreEqual(0, v.vertical, 0.0001f); + Assert.AreEqual(1, v.depth, 0.0001f); + } + + [Test] + public void ToVector3Up() { + Direction d = Direction.up; + Vector3Float v = d.ToVector3(); + Assert.AreEqual(0, v.horizontal, 0.0001f); + Assert.AreEqual(1, v.vertical, 0.0001f); + Assert.AreEqual(0, v.depth, 0.0001f); + } + + [Test] + public void ToVector3Down() { + Direction d = Direction.down; + Vector3Float v = d.ToVector3(); + Assert.AreEqual(0, v.horizontal, 0.0001f); + Assert.AreEqual(-1, v.vertical, 0.0001f); + Assert.AreEqual(0, v.depth, 0.0001f); + } + + [Test] + public void ToVector3Left() { + Direction d = Direction.left; + Vector3Float v = d.ToVector3(); + Assert.AreEqual(-1, v.horizontal, 0.0001f); + Assert.AreEqual(0, v.vertical, 0.0001f); + Assert.AreEqual(0, v.depth, 0.0001f); + } + + [Test] + public void FromVector3Forward() { + Vector3Float v = new(0, 0, 1); + Direction d = Direction.FromVector3(v); + Assert.AreEqual(0, d.horizontal.inDegrees, 0.0001f); + Assert.AreEqual(0, d.vertical.inDegrees, 0.0001f); + } + + [Test] + public void ToVector3AndBack() { + Direction d1 = Direction.Degrees(45, 30); + Vector3Float v = d1.ToVector3(); + Direction d2 = Direction.FromVector3(v); + Assert.AreEqual(d1.horizontal.inDegrees, d2.horizontal.inDegrees, 0.0001f); + Assert.AreEqual(d1.vertical.inDegrees, d2.vertical.inDegrees, 0.0001f); + } + + [Test] + public void ToVector3AndBack2() { + Direction d1 = Direction.Degrees(-135, 85); + Vector3Float v = d1.ToVector3(); + Direction d2 = Direction.FromVector3(v); + Assert.AreEqual(d1.horizontal.inDegrees, d2.horizontal.inDegrees, 0.0001f); + Assert.AreEqual(d1.vertical.inDegrees, d2.vertical.inDegrees, 0.0001f); + } + + [Test] + public void Compare() { + Direction d1 = Direction.Degrees(45, 135); + Direction d2 = new(AngleFloat.Degrees(45), AngleFloat.Degrees(135)); + bool r; + r = d1 == d2; + Assert.True(r); + Assert.AreEqual(d1, d2); + } + + [Test] + public void NotEqualWithDifferentHorizontal() { + Direction d1 = Direction.Degrees(45, 30); + Direction d2 = Direction.Degrees(90, 30); + Assert.True(d1 != d2); + } + + [Test] + public void NotEqualWithDifferentVertical() { + Direction d1 = Direction.Degrees(45, 30); + Direction d2 = Direction.Degrees(45, 60); + Assert.True(d1 != d2); + } + + [Test] + public void NotEqualWithDifferentBoth() { + Direction d1 = Direction.Degrees(45, 30); + Direction d2 = Direction.Degrees(90, 60); + Assert.True(d1 != d2); + } + + [Test] + public void NotEqualWithSameValues() { + Direction d1 = Direction.Degrees(45, 30); + Direction d2 = Direction.Degrees(45, 30); + Assert.False(d1 != d2); + } + + + [Test] + public void EqualsWithSameValues() { + Direction d1 = Direction.Degrees(45, 30); + Direction d2 = Direction.Degrees(45, 30); + Assert.True(d1.Equals(d2)); + } + + [Test] + public void EqualsWithDifferentHorizontal() { + Direction d1 = Direction.Degrees(45, 30); + Direction d2 = Direction.Degrees(90, 30); + Assert.False(d1.Equals(d2)); + } + + [Test] + public void EqualsWithDifferentVertical() { + Direction d1 = Direction.Degrees(45, 30); + Direction d2 = Direction.Degrees(45, 60); + Assert.False(d1.Equals(d2)); + } + + [Test] + public void EqualsWithDifferentBoth() { + Direction d1 = Direction.Degrees(45, 30); + Direction d2 = Direction.Degrees(90, 60); + Assert.False(d1.Equals(d2)); + } + + [Test] + public void EqualsWithNonDirectionObject() { + Direction d = Direction.Degrees(45, 30); + Assert.False(d.Equals("not a direction")); + } + + [Test] + public void EqualsWithNull() { + Direction d = Direction.Degrees(45, 30); + Assert.False(d.Equals(null)); + } + + [Test] + public void EqualsWithZeros() { + Direction d1 = Direction.forward; + Direction d2 = Direction.Degrees(0, 0); + Assert.True(d1.Equals(d2)); + } + + [Test] + public void HashCode() { + Direction d1 = Direction.Degrees(45, 30); + Direction d2 = Direction.Degrees(45, 30); + Assert.AreEqual(d1.GetHashCode(), d2.GetHashCode()); + + d1 = Direction.Degrees(45, 30); + d2 = Direction.Degrees(90, 30); + Assert.AreNotEqual(d1.GetHashCode(), d2.GetHashCode()); + + d1 = Direction.Degrees(45, 30); + d2 = Direction.Degrees(45, 60); + Assert.AreNotEqual(d1.GetHashCode(), d2.GetHashCode()); + + Direction d = Direction.Degrees(45, 30); + int hash1 = d.GetHashCode(); + int hash2 = d.GetHashCode(); + Assert.AreEqual(hash1, hash2); + + d1 = Direction.forward; + d2 = Direction.Degrees(0, 0); + Assert.AreEqual(d1.GetHashCode(), d2.GetHashCode()); + } + + }; +} +#endif + diff --git a/LinearAlgebra/test/LinearAlgebra_Test.csproj b/LinearAlgebra/test/LinearAlgebra_Test.csproj new file mode 100644 index 0000000..5b48e60 --- /dev/null +++ b/LinearAlgebra/test/LinearAlgebra_Test.csproj @@ -0,0 +1,19 @@ + + + + net8.0 + false + true + + + + + + + + + + + + + diff --git a/LinearAlgebra/test/QuaternionTest.cs b/LinearAlgebra/test/QuaternionTest.cs new file mode 100644 index 0000000..9dd5a96 --- /dev/null +++ b/LinearAlgebra/test/QuaternionTest.cs @@ -0,0 +1,185 @@ +#if !UNITY_5_6_OR_NEWER +using NUnit.Framework; + +namespace LinearAlgebra.Test { + + public class QuaternionTest { + + [SetUp] + public void Setup() { + } + + [Test] + public void Normalize() { + Quaternion q1 = new(0, 0, 0, 1); + Quaternion r = Quaternion.identity; + + r = q1.normalized; + Assert.AreEqual(r, q1, "q.normalized 0 0 0 1"); + + r = Quaternion.Normalize(q1); + Assert.AreEqual(r, q1, "q.normalized 0 0 0 1"); + } + + [Test] + public void ToAngles() { + Quaternion q1 = new(0, 0, 0, 1); + Vector3Float v = Vector3Float.zero; + + v = Quaternion.ToAngles(q1); + Assert.AreEqual(v, new Vector3Float(0, 0, 0), "ToAngles 0 0 0 1"); + + q1 = new(1, 0, 0, 0); + v = Quaternion.ToAngles(q1); + Assert.AreEqual(0, v.horizontal, "1 0 0 0 H"); + Assert.AreEqual(180, v.vertical, "1 0 0 0 V"); + Assert.AreEqual(180, v.depth, "1 0 0 0 D"); + + } + + [Test] + public void Multiplication() { + Quaternion q1 = new(0, 0, 0, 1); + Quaternion q2 = new(1, 0, 0, 0); + Quaternion r; + + r = q1 * q2; + Assert.AreEqual(r, new Quaternion(1, 0, 0, 0), "0 0 0 1 * 1 0 0 0 "); + } + + [Test] + public void MultiplicationVector() { + Quaternion q1 = new(0, 0, 0, 1); + Vector3Float v1 = new(0, 1, 0); + Vector3Float r; + + r = q1 * v1; + Assert.AreEqual(r, new Vector3Float(0, 1, 0), "0 0 0 1 * Vector 0 1 0"); + + q1 = new(1, 0, 0, 0); + r = q1 * v1; + Assert.AreEqual(r, new Vector3Float(0, -1, 0), "1 0 0 0 * Vector 0 1 0"); + } + + [Test] + public void Equality() { + Quaternion q1 = new(0, 0, 0, 1); + Quaternion q2 = new(1, 0, 0, 0); + Assert.AreNotEqual(q1, q2, "0 0 0 1 == 1 0 0 0"); + + q2 = new(0, 0, 0, 1); + Assert.AreEqual(q1, q2, "0 0 0 1 == 1 0 0 0"); + } + + [Test, Ignore("ToDo")] + public void Inverse() { } + + [Test, Ignore("ToDo")] + public void LookRotation() { } + + [Test, Ignore("ToDo")] + public void FromToRotation() { } + + [Test, Ignore("ToDo")] + public void RotateTowards() { } + + [Test, Ignore("ToDo")] + public void AngleAxis() { } + + [Test, Ignore("ToDo")] + public void Angle() { } + + [Test, Ignore("ToDo")] + public void Slerp() { } + + [Test, Ignore("ToDo")] + public void SlerpUnclamped() { } + + [Test] + public void Euler() { + Vector3Float v1 = new(0, 0, 0); + Quaternion q; + + q = Quaternion.Euler(v1); + Assert.AreEqual(q, Quaternion.identity, "Euler Vector 0 0 0"); + + q = Quaternion.Euler(0, 0, 0); + Assert.AreEqual(q, Quaternion.identity, "Euler 0 0 0"); + + v1 = new(90, 90, -90); + q = Quaternion.Euler(v1); + Assert.AreEqual(q, new Quaternion(0, 0.707106709F, -0.707106709F, 0), "Euler Vector 90 90 -90"); + + q = Quaternion.Euler(90, 90, -90); + Assert.AreEqual(q, new Quaternion(0, 0.707106709F, -0.707106709F, 0), "Euler 90 90 -90"); + } + + [Test] + public void EulerToAngles() { + Vector3Float v; + Quaternion q; + Quaternion r; + + //v = new(0, 0, 0); + q = Quaternion.Euler(0, 0 , 0); + v = Quaternion.ToAngles(q); + r = Quaternion.Euler(v); + Assert.AreEqual(0, Quaternion.UnsignedAngle(q, r), 10e-2f, "0 0 0"); + + q = Quaternion.Euler(-45, -30, -15); + v = Quaternion.ToAngles(q); + r = Quaternion.Euler(v); + Assert.AreEqual(0, Quaternion.UnsignedAngle(q, r), 10e-2f, "-45, -30, -15"); + + // Gimball lock + // q = Quaternion.Euler(90, 90, -90); + // v = Quaternion.ToAngles(q); + // r = Quaternion.Euler(v); + // Assert.AreEqual(0, Quaternion.UnsignedAngle(q, r), 10e-2f, "0 0 0"); + + } + + [Test] + public void GetAngleAround() { + Vector3Float v1 = new(0, 1, 0); + Quaternion q1 = new(0, 0, 0, 1); + + float f = Quaternion.GetAngleAround(v1, q1); + Assert.AreEqual(f, 0, "GetAngleAround 0 1 0 , 0 0 0 1"); + + q1 = new(0, 0.707106709F, -0.707106709F, 0); + f = Quaternion.GetAngleAround(v1, q1); + Assert.AreEqual(f, 180, "GetAngleAround 0 1 0 , 0 0.7 -0.7 0"); + + v1 = new(0, 0, 0); + f = Quaternion.GetAngleAround(v1, q1); + Assert.IsTrue(float.IsNaN(f), "GetAngleAround 0 0 0 , 0 0.7 -0.7 0"); + } + + [Test] + public void GetRotationAround() { + Vector3Float v1 = new(0, 1, 0); + Quaternion q1 = new(0, 0, 0, 1); + + Quaternion q = Quaternion.GetRotationAround(v1, q1); + Assert.AreEqual(q, new Quaternion(0, 0, 0, 1), "GetRotationAround 0 1 0 , 0 0 0 1"); + + q1 = new(0, 0.707106709F, -0.707106709F, 0); + q = Quaternion.GetRotationAround(v1, q1); + Assert.AreEqual(q, new Quaternion(0, 1, 0, 0), "GetRotationAround 0 1 0 , 0 0.7 -0.7 0"); + + v1 = new(0, 0, 0); + q = Quaternion.GetRotationAround(v1, q1); + bool r = float.IsNaN(q.x) && float.IsNaN(q.y) && float.IsNaN(q.z) && float.IsNaN(q.w); + Assert.IsTrue(r, "GetRotationAround 0 0 0 , 0 0.7 -0.7 0"); + } + + [Test, Ignore("ToDo")] + public void GetSwingTwist() { } + + [Test, Ignore("ToDo")] + public void Dot() { } + + } +} +#endif \ No newline at end of file diff --git a/LinearAlgebra/test/SphericalTest.cs b/LinearAlgebra/test/SphericalTest.cs new file mode 100644 index 0000000..b28b9d9 --- /dev/null +++ b/LinearAlgebra/test/SphericalTest.cs @@ -0,0 +1,271 @@ +//#if !UNITY_5_6_OR_NEWER +using System; +using System.Collections.Generic; +using NUnit.Framework; + +namespace LinearAlgebra.Test { + public class SphericalTest { + [SetUp] + public void Setup() { + } + + [Test] + public void FromVector3() { +#if UNITY_5_6_OR_NEWER + UnityEngine.Vector3 v = new(0, 0, 1); +#else + Vector3Float v = new(0, 0, 1); +#endif + Spherical s = Spherical.FromVector3(v); + Assert.AreEqual(1.0f, s.distance, "s.distance 0 0 1"); + Assert.AreEqual(0.0f, s.direction.horizontal.inDegrees, "s.hor 0 0 1"); + Assert.AreEqual(0.0f, s.direction.vertical.inDegrees, 1.0E-05F, "s.vert 0 0 1"); + + v = new(0, 1, 0); + s = Spherical.FromVector3(v); + Assert.AreEqual(1.0f, s.distance, "s.distance 0 1 0"); + Assert.AreEqual(0.0f, s.direction.horizontal.inDegrees, "s.hor 0 1 0"); + Assert.AreEqual(90.0f, s.direction.vertical.inDegrees, "s.vert 0 1 0"); + + v = new(1, 0, 0); + s = Spherical.FromVector3(v); + Assert.AreEqual(1.0f, s.distance, "s.distance 1 0 0"); + Assert.AreEqual(90.0f, s.direction.horizontal.inDegrees, "s.hor 1 0 0"); + Assert.AreEqual(0.0f, s.direction.vertical.inDegrees, 1.0E-05F, "s.vert 1 0 0"); + } + + [Test] + public void Addition() { + Spherical v1 = Spherical.Degrees(1, 45, 0); + Spherical v2 = Spherical.zero; + Spherical r = Spherical.zero; + + r = v1 + v2; + Assert.AreEqual(v1.distance, r.distance, 1.0E-05F, "Addition(0,0,0)"); + + r = v1; + r += v2; + Assert.AreEqual(v1.distance, r.distance, 1.0E-05F, "Addition(0,0,0)"); + + v2 = Spherical.Degrees(1, 0, 90); + r = v1 + v2; + Assert.AreEqual(Math.Sqrt(2), r.distance, 1.0E-05F, "Addition(1 0 90)"); + Assert.AreEqual(45.0f, r.direction.horizontal.inDegrees, 1e-5f, "Addition(1 0 90)"); + Assert.AreEqual(45.0f, r.direction.vertical.inDegrees, 1.0E-05F, "Addition(1 0 90)"); + } + + [Test] + public void Average2_IdenticalVectors() { + Direction dir = Direction.Radians(MathF.PI / 4f, MathF.PI / 6f); + Spherical v = new(2.5f, dir); + + Spherical avg = Spherical.Average(v, v); + + Assert.AreEqual(2.5f, avg.distance, 1e-5f); + Assert.AreEqual(dir.horizontal, avg.direction.horizontal); + Assert.AreEqual(dir.vertical, avg.direction.vertical); + } + + [Test] + public void Average2_OppositeUnitVectors() { + // Two opposite vectors: same distance, horizontal opposite (pi apart), same vertical + Spherical v1 = Spherical.Radians(1f, 0f, 0f); + Spherical v2 = Spherical.Radians(1f, MathF.PI, 0f); + Spherical avg = Spherical.Average(v1, v2); + + Assert.AreEqual(0f, avg.distance, 1e-4f); + // When distance is zero, angles may be undefined; allow any angle but ensure near-zero magnitude + } + + [Test] + public void Average2_WeightedByDistance() { + // Two vectors same direction but different distances -> weighted average distance + Direction dir = Direction.Radians(MathF.PI / 3f, MathF.PI / 4f); + Spherical a = new(1f, dir); + Spherical b = new(3f, dir); + Spherical avg = Spherical.Average(a, b); + + // average distance should be (1+3)/2 = 2 + Assert.AreEqual(2f, avg.distance, 1e-5f); + Assert.AreEqual(dir.horizontal.inRadians, avg.direction.horizontal.inRadians, 1e-5f); + Assert.AreEqual(dir.vertical.inRadians, avg.direction.vertical.inRadians, 1e-5f); + } + + [Test] + public void Average2_OppositeButNotExact_NotZero() { + // Nearly opposite but not exact; expect a valid averaged direction and averaged distance + Direction d1 = Direction.Radians(0f, 0f); + Direction d2 = Direction.Radians(MathF.PI - 1e-3f, 0.0f); // slight offset + Spherical v1 = new(2.0f, d1); + Spherical v2 = new(4.0f, d2); + + Spherical avg = Spherical.Average(v1, v2); + + // Distance is arithmetic mean + Assert.AreEqual(3.0f, avg.distance, 1e-5f); + + // Averaged azimuth should be near +pi/2 or -pi/2? we can check it's not NaN and unit-vector properties hold + float ux = MathF.Cos(avg.direction.horizontal.inRadians) * MathF.Cos(avg.direction.vertical.inRadians); + float uy = MathF.Sin(avg.direction.horizontal.inRadians) * MathF.Cos(avg.direction.vertical.inRadians); + float uz = MathF.Sin(avg.direction.vertical.inRadians); + float mag = MathF.Sqrt(ux * ux + uy * uy + uz * uz); + Assert.IsTrue(mag > 0.999f && mag < 1.001f); + + } + + [Test] + public void Average2_BasicAverageDirectionAndDistance() { + // Two different directions not cancelling: expect vector-average result + Direction d1 = Direction.Radians(MathF.PI / 6f, MathF.PI / 12f); // 30°, 15° + Direction d2 = Direction.Radians(MathF.PI / 3f, MathF.PI / 18f); // 60°, 10° + Spherical v1 = new(2.0f, d1); + Spherical v2 = new(4.0f, d2); + + Spherical avg = Spherical.Average(v1, v2); + + // Distance is arithmetic mean + Assert.AreEqual(3.0f, avg.distance, 1e-5f); + + // Check averaged unit-vector equals normalized sum of unit vectors computed here + float a1 = d1.horizontal.inRadians; + float a2 = d2.horizontal.inRadians; + float e1 = d1.vertical.inRadians; + float e2 = d2.vertical.inRadians; + + float cx = MathF.Cos(a1) + MathF.Cos(a2); + float cy = MathF.Sin(a1) + MathF.Sin(a2); + float z1 = MathF.Sin(e1); + float z2 = MathF.Sin(e2); + float cz = z1 + z2; + float mag = MathF.Sqrt(cx * cx + cy * cy + cz * cz); + Assert.IsTrue(mag > 1e-6f); + + float ux = cx / mag; + float uy = cy / mag; + float uz = cz / mag; + + // Reconstruct direction from avg result + float uxAvg = MathF.Cos(avg.direction.horizontal.inRadians) * MathF.Cos(avg.direction.vertical.inRadians); + float uyAvg = MathF.Sin(avg.direction.horizontal.inRadians) * MathF.Cos(avg.direction.vertical.inRadians); + float uzAvg = MathF.Sin(avg.direction.vertical.inRadians); + + Assert.AreEqual(ux, uxAvg, 1e-4f); + Assert.AreEqual(uy, uyAvg, 1e-4f); + Assert.AreEqual(uz, uzAvg, 1e-4f); + } + + [Test] + public void Average_IdenticalVectors() { + var dir = Direction.Radians(MathF.PI / 4f, MathF.PI / 6f); + var v = new Spherical(2.5f, dir); + var list = new List { v, v, v }; + + var avg = Spherical.Average(list); + + Assert.AreEqual(2.5f, avg.distance, 1e-5f); + Assert.AreEqual(dir.horizontal, avg.direction.horizontal); + Assert.AreEqual(dir.vertical, avg.direction.vertical); + } + + [Test] + public void Average_SingleElement() { + Spherical s = Spherical.Radians(1.234f, 0.3f, -0.7f); + Spherical avg = Spherical.Average(new List { s }); + + Assert.AreEqual(s.distance, avg.distance, 1e-5f); + Assert.AreEqual(s.direction.horizontal.inRadians, avg.direction.horizontal.inRadians, 1e-5f); + Assert.AreEqual(s.direction.vertical.inRadians, avg.direction.vertical.inRadians, 1e-5f); + } + + [Test] + public void Average_OppositeUnitVectors() { + // Two opposite vectors: same distance, horizontal opposite (pi apart), same vertical + Spherical v1 = Spherical.Radians(1f, 0f, 0f); + Spherical v2 = Spherical.Radians(1f, MathF.PI, 0f); + Spherical avg = Spherical.Average(new List { v1, v2 }); + + Assert.AreEqual(0f, avg.distance, 1e-4f); + // When distance is zero, angles may be undefined; allow any angle but ensure near-zero magnitude + } + + [Test] + public void Average_WeightedByDistance() { + // Two vectors same direction but different distances -> weighted average distance + Direction dir = Direction.Radians(MathF.PI / 3f, MathF.PI / 4f); + Spherical a = new(1f, dir); + Spherical b = new(3f, dir); + Spherical avg = Spherical.Average(new List { a, b }); + + // average distance should be (1+3)/2 = 2 + Assert.AreEqual(2f, avg.distance, 1e-5f); + Assert.AreEqual(dir.horizontal.inRadians, avg.direction.horizontal.inRadians, 1e-5f); + Assert.AreEqual(dir.vertical.inRadians, avg.direction.vertical.inRadians, 1e-5f); + } + + [Test] + public void Average_AxisSymmetricAroundVertical() { + // Four vectors around azimuth 0, pi/2, pi, 3pi/2 at same elevation (vertical) angle phi + float phi = MathF.PI / 6f; // elevation from horizontal plane + var dirs = new List { + new(1f, Direction.Radians(0f, phi)), + new(1f, Direction.Radians(MathF.PI/2, phi)), + new(1f, Direction.Radians(MathF.PI, phi)), + new(1f, Direction.Radians(3*MathF.PI/2, phi)) + }; + + Spherical avg = Spherical.Average(dirs); + + // rAvg should equal r * sin(elevation) = sin(phi) + Assert.AreEqual(MathF.Sin(phi), avg.distance, 1e-4f); + // vertical angle undefined when horizontal xy components cancel; allow any angle but ensure r matches + } + + [Test] + public void Average_AxisSymmetricAroundVertical2() { + // Four vectors around azimuth 0, pi/2, pi, 3pi/2 at same polar angle from vertical (alpha) + float alpha = MathF.PI / 6f; // polar angle from vertical + float elevation = MathF.PI / 2f - alpha; // convert polar-from-vertical to elevation + var dirs = new List { + new(1f, Direction.Radians(0f, elevation)), + new(1f, Direction.Radians(MathF.PI/2, elevation)), + new(1f, Direction.Radians(MathF.PI, elevation)), + new(1f, Direction.Radians(3*MathF.PI/2, elevation)) + }; + + Spherical avg = Spherical.Average(dirs); + + // rAvg should equal r * sin(elevation) which equals cos(alpha) + Assert.AreEqual(MathF.Cos(alpha), avg.distance, 1e-4f); + } + + [Test] + public void Average_CompareWithVector3() { + // Four vectors around azimuth 0, pi/2, pi, 3pi/2 at same polar angle from vertical (alpha) + float alpha = MathF.PI / 6f; // polar angle from vertical + float elevation = MathF.PI / 2f - alpha; // convert polar-from-vertical to elevation + List dirs = new List { + new(1f, Direction.Radians(0f, elevation)), + new(2f, Direction.Radians(MathF.PI/2, elevation+1)), + new(3f, Direction.Radians(MathF.PI, elevation+2)), + new(4f, Direction.Radians(3*MathF.PI/2, elevation+3)) + }; + + Spherical avg = Spherical.Average(dirs); + +#if UNITY_5_3_OR_NEWER + UnityEngine.Vector3 r = UnityEngine.Vector3.zero; +#else + Vector3Float r = Vector3Float.zero; +#endif + foreach (Spherical dir in dirs) { + r += dir.ToVector3(); + } + r = r / 4; + Spherical avg2 = Spherical.FromVector3(r); + + Assert.AreEqual(avg, avg2); + } + + } +} +//#endif \ No newline at end of file diff --git a/LinearAlgebra/test/SwingTwistTest.cs b/LinearAlgebra/test/SwingTwistTest.cs new file mode 100644 index 0000000..5f05a96 --- /dev/null +++ b/LinearAlgebra/test/SwingTwistTest.cs @@ -0,0 +1,131 @@ +#if !UNITY_5_6_OR_NEWER +using NUnit.Framework; + +namespace LinearAlgebra.Test { + + [TestFixture] + public class SwingTwistTest { + + [Test] + public void Degrees_CreatesSwingTwistWithDegreeAngles() { + SwingTwist st = SwingTwist.Degrees(45, 30, 15); + Assert.IsNotNull(st); + Assert.AreEqual(45, st.swing.horizontal.inDegrees, 0.01f); + Assert.AreEqual(30, st.swing.vertical.inDegrees, 0.01f); + Assert.AreEqual(15, st.twist.inDegrees, 0.01f); + } + + [Test] + public void Radians_CreatesSwingTwistWithRadianAngles() { + float pi = (float)System.Math.PI; + SwingTwist st = SwingTwist.Radians(pi / 4, pi / 6, pi / 12); + Assert.IsNotNull(st); + Assert.AreEqual(45, st.swing.horizontal.inDegrees, 0.01f); + Assert.AreEqual(30, st.swing.vertical.inDegrees, 0.01f); + Assert.AreEqual(15, st.twist.inDegrees, 0.01f); + } + + [Test] + public void Zero_CreatesZeroRotation() { + SwingTwist st = SwingTwist.zero; + Assert.AreEqual(0, st.swing.horizontal.inDegrees, 0.01f); + Assert.AreEqual(0, st.swing.vertical.inDegrees, 0.01f); + Assert.AreEqual(0, st.twist.inDegrees, 0.01f); + } + + [Test] + public void QuaternionTest() { + Quaternion q; + SwingTwist s; + Quaternion r; + + q = Quaternion.identity; + s = SwingTwist.FromQuaternion(q); + r = s.ToQuaternion(); + Assert.AreEqual(q, r); + + q = Quaternion.Euler(90, 0, 0); + s = SwingTwist.FromQuaternion(q); + Assert.AreEqual(0, s.swing.horizontal.inDegrees, 10e-2f); + Assert.AreEqual(90, s.swing.vertical.inDegrees, 10e-2f); + Assert.AreEqual(0, s.twist.inDegrees, 0.01f); + r = s.ToQuaternion(); + Assert.AreEqual(0, Quaternion.UnsignedAngle(q, r), 10e-2f); + + q = Quaternion.Euler(0, 90, 0); + s = SwingTwist.FromQuaternion(q); + Assert.AreEqual(90, s.swing.horizontal.inDegrees,10e-2f); + Assert.AreEqual(0, s.swing.vertical.inDegrees, 0.01f); + Assert.AreEqual(0, s.twist.inDegrees, 0.01f); + r = s.ToQuaternion(); + Assert.AreEqual(0, Quaternion.UnsignedAngle(q, r), 10e-2f); + + q = Quaternion.Euler(0, 0, 90); + s = SwingTwist.FromQuaternion(q); + Assert.AreEqual(0, s.swing.horizontal.inDegrees, 0.01f); + Assert.AreEqual(0, s.swing.vertical.inDegrees, 0.01f); + Assert.AreEqual(90, s.twist.inDegrees, 0.01f); + r = s.ToQuaternion(); + Assert.AreEqual(0, Quaternion.UnsignedAngle(q, r), 10e-2f); + + q = Quaternion.Euler(0, 180, 0); + s = SwingTwist.FromQuaternion(q); + Assert.AreEqual(-180, s.swing.horizontal.inDegrees, 0.01f); + Assert.AreEqual(0, s.swing.vertical.inDegrees, 0.01f); + Assert.AreEqual(0, s.twist.inDegrees, 0.01f); + r = s.ToQuaternion(); + Assert.AreEqual(0, Quaternion.UnsignedAngle(q, r), 10e-2f); + + q = Quaternion.Euler(0, 135, 0); + s = SwingTwist.FromQuaternion(q); + Assert.AreEqual(135, s.swing.horizontal.inDegrees, 0.01f); + Assert.AreEqual(0, s.swing.vertical.inDegrees, 0.01f); + Assert.AreEqual(0, s.twist.inDegrees, 0.01f); + r = s.ToQuaternion(); + Assert.AreEqual(0, Quaternion.UnsignedAngle(q, r), 10e-2f); + + q = Quaternion.Euler(60, 45, 30); + s = SwingTwist.FromQuaternion(q); + Assert.AreEqual(45, s.swing.horizontal.inDegrees, 0.01f); + Assert.AreEqual(60, s.swing.vertical.inDegrees, 0.01f); + Assert.AreEqual(30, s.twist.inDegrees, 0.01f); + // r = s.ToQuaternion(); + // Assert.AreEqual(0, Quaternion.UnsignedAngle(q, r), 10e-2f); + + // q = Quaternion.Euler(-45, -30, -15); + // s = SwingTwist.FromQuaternion(q); + // Assert.AreEqual(-30, s.swing.horizontal.inDegrees, 0.01f); + // Assert.AreEqual(-45, s.swing.vertical.inDegrees, 0.01f); + // Assert.AreEqual(-15, s.twist.inDegrees, 0.01f); + // r = s.ToQuaternion(); + // Assert.AreEqual(0, Quaternion.UnsignedAngle(q, r), 10e-2f); + + // q = Quaternion.Euler(180, 180, 180); + // s = SwingTwist.FromQuaternion(q); + // Assert.AreEqual(-180, s.swing.horizontal.inDegrees, 0.01f); + // Assert.AreEqual(-180, s.swing.vertical.inDegrees, 0.01f); + // Assert.AreEqual(-180, s.twist.inDegrees, 0.01f); + // r = s.ToQuaternion(); + // Assert.AreEqual(0, Quaternion.UnsignedAngle(q, r), 10e-2f); + + } + + [Test] + public void ToAngleAxis_ConvertsToSpherical() { + SwingTwist st = SwingTwist.Degrees(45, 30, 15); + Spherical s = st.ToAngleAxis(); + Assert.IsNotNull(s); + } + + [Test] + public void FromAngleAxis_ConvertsFromSpherical() { + Spherical s = new(90, Direction.Degrees(45, 0)); + SwingTwist st = SwingTwist.FromAngleAxis(s); + Assert.IsNotNull(st); + } + + } + +} + +#endif \ No newline at end of file diff --git a/LinearAlgebra/test/Vector2FloatTest.cs b/LinearAlgebra/test/Vector2FloatTest.cs new file mode 100644 index 0000000..867765a --- /dev/null +++ b/LinearAlgebra/test/Vector2FloatTest.cs @@ -0,0 +1,364 @@ +#if !UNITY_5_6_OR_NEWER +using NUnit.Framework; + +namespace LinearAlgebra.Test { + using Vector2 = Vector2Float; + + public class Vector2FloatTest { + + [SetUp] + public void Setup() { + } + + [Test] + public void FromPolar() { + } + + [Test] + public void Equality() { + Vector2 v1 = new(4, 5); + Vector2 v2 = new(1, 2); + + Assert.IsFalse(v1 == v2, "4 5 == 1 2"); + Assert.IsTrue(v1 != v2, "4 5 != 1 2"); + + v2 = new(4, 5); + Assert.IsTrue(v1 == v2, "4 5 == 4 5"); + Assert.IsFalse(v1 != v2, "4 5 != 4 5"); + } + + [Test] + public void Magnitude() { + Vector2 v = new(1, 2); + float m = 0; + m = v.magnitude; + Assert.AreEqual(m, 2.236068F, "v.magnitude 1 2"); + + m = Vector2.MagnitudeOf(v); + Assert.AreEqual(m, 2.236068F, "MagnitudeOf 1 2"); + + v = new(-1, -2); + m = v.magnitude; + Assert.AreEqual(m, 2.236068F, "v.magnitude -1 -2"); + + v = new(0, 0); + m = v.magnitude; + Assert.AreEqual(m, 0, "v.magnitude 0 0"); + } + + [Test] + public void SqrMagnitude() { + Vector2 v = new(1, 2); + float m = 0; + + m = v.sqrMagnitude; + Assert.AreEqual(m, 5, "v.sqrMagnitude 1 2"); + + m = Vector2.SqrMagnitudeOf(v); + Assert.AreEqual(m, 5, "SqrMagnitudeOf 1 2"); + + v = new(-1, -2); + m = v.sqrMagnitude; + Assert.AreEqual(m, 5, "v.sqrMagnitude -1 -2"); + + v = new(0, 0); + m = v.sqrMagnitude; + Assert.AreEqual(m, 0, "v.sqrMagnitude 0 0"); + } + + [Test] + public void Distance() { + Vector2 v1 = new(4, 5); + Vector2 v2 = new(1, 2); + float f = 0; + + f = Vector2.Distance(v1, v2); + Assert.AreEqual(f, 4.24264002f, 1.0E-05F, "Distance(4 5, 1 2)"); + + v2 = new(-1, -2); + f = Vector2.Distance(v1, v2); + Assert.AreEqual(f, 8.602325F, "Distance(4 5, 1 2)"); + + v2 = new(0, 0); + f = Vector2.Distance(v1, v2); + Assert.AreEqual(f, 6.403124F, 1.0E-05F, "Distance(4 5, 1 2)"); + } + + [Test] + public void Normalize() { + Vector2 v = new(0, 3); + Vector2Float r; + + r = v.normalized; + Assert.AreEqual(0, r.horizontal, "normalized 0 3 H"); + Assert.AreEqual(1, r.vertical, "normalized 0 3 V"); + + r = Vector2.Normalize(v); + Assert.AreEqual(0, r.horizontal, "Normalize 0 3 H"); + Assert.AreEqual(1, r.vertical, "Normalize 0 3 V"); + + v = new(0, -3); + r = v.normalized; + Assert.AreEqual(0, r.horizontal, "normalized 0 -3 H"); + Assert.AreEqual(-1, r.vertical, "normalized 0 -3 V"); + + v = new(0, 0); + r = v.normalized; + Assert.AreEqual(0, r.horizontal, "normalized 0 0 H"); + Assert.AreEqual(0, r.vertical, "normalized 0 0 V"); + } + + [Test] + public void Negate() { + Vector2 v = new(4, 5); + Vector2 r; + + r = -v; + Assert.AreEqual(-4, r.horizontal, "- 4 5 H"); + Assert.AreEqual(-5, r.vertical, "- 4 5 V"); + + v = new(-4, -5); + r = -v; + Assert.AreEqual(4, r.horizontal, "- -4 -5 H"); + Assert.AreEqual(5, r.vertical, "- -4 -5 V"); + + v = new(0, 0); + r = -v; + Assert.AreEqual(0, r.horizontal, "- 0 0 H"); + Assert.AreEqual(0, r.vertical, "- 0 0 V"); + } + + [Test] + public void Subtract() { + Vector2 v1 = new(4, 5); + Vector2 v2 = new(1, 2); + Vector2 r = Vector2.zero; + + r = v1 - v2; + Assert.IsTrue(r == new Vector2(3, 3), "4 5 - 1 2"); + + v2 = new(-1, -2); + r = v1 - v2; + Assert.IsTrue(r == new Vector2(5, 7), "4 5 - -1 -2"); + + v2 = new(4, 5); + r = v1 - v2; + Assert.IsTrue(r == new Vector2(0, 0), "4 5 - 4 5"); + r = v1; + r -= v2; + Assert.AreEqual(r, new Vector2(0, 0), "4 5 - 4 5"); + + v2 = new(0, 0); + r = v1 - v2; + Assert.AreEqual(r, new Vector2(4, 5), "4 5 - 0 0"); + r -= v2; + Assert.AreEqual(r, new Vector2(4, 5), "4 5 - 0 0"); + } + + [Test] + public void Addition() { + Vector2 v1 = new(4, 5); + Vector2 v2 = new(1, 2); + Vector2 r = Vector2.zero; + + r = v1 + v2; + Assert.IsTrue(r == new Vector2(5, 7), "4 5 + 1 2"); + + v2 = new(-1, -2); + r = v1 + v2; + Assert.IsTrue(r == new Vector2(3, 3), "4 5 + -1 -2"); + r = v1; + r += v2; + Assert.AreEqual(r, new Vector2(3, 3), "4 5 + -1 -2"); + + v2 = new(0, 0); + r = v1 + v2; + Assert.AreEqual(r, new Vector2(4, 5), "4 5 + 0 0"); + r += v2; + Assert.AreEqual(r, new Vector2(4, 5), "4 5 + 0 0"); + } + + [Test] + public void Scale() { + Vector2 v1 = new(4, 5); + Vector2 v2 = new(1, 2); + Vector2 r; + + r = Vector2.Scale(v1, v2); + Assert.AreEqual(4, r.horizontal, "Scale 4 5 , 1 2 H"); + Assert.AreEqual(10, r.vertical, "Scale 4 5 , 1 2 V"); + + v2 = new(-1, -2); + r = Vector2.Scale(v1, v2); + Assert.AreEqual(-4, r.horizontal, "Scale 4 5 , -1 -2 H"); + Assert.AreEqual(-10, r.vertical, "Scale 4 5 , -1 -2 V"); + + v2 = new(0, 0); + r = Vector2.Scale(v1, v2); + Assert.AreEqual(0, r.horizontal, "Scale 4 5 , 0 0 H"); + Assert.AreEqual(0, r.vertical, "Scale 4 5 , 0 0 V"); + } + + [Test] + public void Multiply() { + Vector2 v1 = new(4, 5); + int f = 3; + Vector2 r; + + r = v1 * f; + Assert.AreEqual(12, r.horizontal, "4 5 * 3 H"); + Assert.AreEqual(15, r.vertical, "4 5 * 3 V"); + + r = f * v1; + Assert.AreEqual(12, r.horizontal, "3 * 4 5 H"); + Assert.AreEqual(15, r.vertical, "3 * 4 5 V"); + + f = -3; + r = v1 * f; + Assert.AreEqual(-12, r.horizontal, "4 5 * -3 H"); + Assert.AreEqual(-15, r.vertical, "4 5 * -3 V"); + + f = 0; + r = v1 * f; + Assert.AreEqual(0, r.horizontal, "4 5 * 0 H"); + Assert.AreEqual(0, r.vertical, "4 5 * 0 V"); + } + + [Test] + public void Divide() { + Vector2 v1 = new(4, 5); + float f = 2; + Vector2 r; + + r = v1 / f; + Assert.AreEqual(2, r.horizontal, "4 5 / 2 H"); + Assert.AreEqual(2.5, r.vertical, "4 5 / 2 V"); + + f = -2; + r = v1 / f; + Assert.AreEqual(-2, r.horizontal, "4 5 / -2 H"); + Assert.AreEqual(-2.5, r.vertical, "4 5 / -2 V"); + + f = 0; + r = v1 / f; + Assert.AreEqual(float.PositiveInfinity, r.horizontal, "4 5 / 0 H"); + Assert.AreEqual(float.PositiveInfinity, r.vertical, "4 5 / 0 V"); + } + + [Test] + public void Dot() { + Vector2 v1 = new(4, 5); + Vector2 v2 = new(1, 2); + float f; + + f = Vector2.Dot(v1, v2); + Assert.AreEqual(14, f, "Dot(4 5, 1 2)"); + + v2 = new(-1, -2); + f = Vector2.Dot(v1, v2); + Assert.AreEqual(-14, f, "Dot(4 5, -1 -2)"); + + v2 = new(0, 0); + f = Vector2.Dot(v1, v2); + Assert.AreEqual(0, f, "Dot(4 5, 0 0)"); + } + + [Test] + public void SignedAngle() { + Vector2 v1 = new(4, 5); + Vector2 v2 = new(1, 2); + float f; + + f = Vector2.SignedAngle(v1, v2); + Assert.AreEqual(-12.094758f, f); + + v2 = new(-1, -2); + f = Vector2.SignedAngle(v1, v2); + Assert.AreEqual(167.905228f, f); + + v2 = new(0, 0); + f = Vector2.SignedAngle(v1, v2); + Assert.AreEqual(0, f); + + v1 = new(0, 1); + v2 = new(1, 0); + f = Vector2.SignedAngle(v1, v2); + Assert.AreEqual(90, f); + + v1 = new(0, 1); + v2 = new(0, -1); + f = Vector2.SignedAngle(v1, v2); + Assert.AreEqual(180, f); + } + + [Test] + public void UnsignedAngle() { + Vector2 v1 = new(4, 5); + Vector2 v2 = new(1, 2); + float f; + + f = Vector2.UnsignedAngle(v1, v2); + Assert.AreEqual(12.094758f, f); + + v2 = new(-1, -2); + f = Vector2.UnsignedAngle(v1, v2); + Assert.AreEqual(167.905228f, f); + + v2 = new(0, 0); + f = Vector2.UnsignedAngle(v1, v2); + Assert.AreEqual(0, f); + + v1 = new(0, 1); + v2 = new(1, 0); + f = Vector2.UnsignedAngle(v1, v2); + Assert.AreEqual(90, f); + + v1 = new(0, 1); + v2 = new(0, -1); + f = Vector2.UnsignedAngle(v1, v2); + Assert.AreEqual(180, f); + } + + [Test] + public void Rotate() { + Vector2 v1 = new(1, 2); + Vector2 r; + + r = Vector2.Rotate(v1, AngleFloat.Degrees(0)); + Assert.AreEqual(0, Vector2.Distance(r, v1)); + + r = Vector2.Rotate(v1, AngleFloat.Degrees(180)); + Assert.AreEqual(0, Vector2.Distance(r, new Vector2(-1, -2)), 1.0e-06); + + r = Vector2.Rotate(v1, AngleFloat.Degrees(-90)); + Assert.AreEqual(0, Vector2.Distance(r, new Vector2(2, -1)), 1.0e-06); + + r = Vector2.Rotate(v1, AngleFloat.Degrees(270)); + Assert.AreEqual(0, Vector2.Distance(r, new Vector2(2, -1)), 1.0e-06); + } + + [Test] + public void Lerp() { + Vector2 v1 = new(4, 5); + Vector2 v2 = new(1, 2); + Vector2 r; + + r = Vector2.Lerp(v1, v2, 0); + Assert.AreEqual(0, Vector2.Distance(r, v1), 0); + + r = Vector2.Lerp(v1, v2, 1); + Assert.AreEqual(0, Vector2.Distance(r, v2), 0); + + r = Vector2.Lerp(v1, v2, 0.5f); + Assert.AreEqual(0, Vector2.Distance(r, new Vector2(2.5f, 3.5f)), 0); + + r = Vector2.Lerp(v1, v2, -1); + Assert.AreEqual(0, Vector2.Distance(r, new Vector2(7, 8)), 0); + + r = Vector2.Lerp(v1, v2, 2); + Assert.AreEqual(0, Vector2.Distance(r, new Vector2(-2, -1)), 0); + } + + } +} +#endif \ No newline at end of file diff --git a/LinearAlgebra/test/Vector2IntTest.cs b/LinearAlgebra/test/Vector2IntTest.cs new file mode 100644 index 0000000..3647ca0 --- /dev/null +++ b/LinearAlgebra/test/Vector2IntTest.cs @@ -0,0 +1,270 @@ +#if !UNITY_5_6_OR_NEWER +using NUnit.Framework; + +namespace LinearAlgebra.Test { + using Vector2 = Vector2Int; + + public class Vector2IntTest { + + [SetUp] + public void Setup() { + } + + [Test] + public void FromPolar() { + } + + [Test] + public void Equality() { + Vector2 v1 = new(4, 5); + Vector2 v2 = new(1, 2); + + Assert.IsFalse(v1 == v2, "4 5 == 1 2"); + Assert.IsTrue(v1 != v2, "4 5 != 1 2"); + + v2 = new(4, 5); + Assert.IsTrue(v1 == v2, "4 5 == 4 5"); + Assert.IsFalse(v1 != v2, "4 5 != 4 5"); + } + + [Test] + public void Magnitude() { + Vector2 v = new(1, 2); + float m = 0; + m = v.magnitude; + Assert.AreEqual(m, 2.236068F, "v.magnitude 1 2"); + + m = Vector2.MagnitudeOf(v); + Assert.AreEqual(m, 2.236068F, "MagnitudeOf 1 2"); + + v = new(-1, -2); + m = v.magnitude; + Assert.AreEqual(m, 2.236068F, "v.magnitude -1 -2"); + + v = new(0, 0); + m = v.magnitude; + Assert.AreEqual(m, 0, "v.magnitude 0 0"); + } + + [Test] + public void SqrMagnitude() { + Vector2 v = new(1, 2); + float m = 0; + + m = v.sqrMagnitude; + Assert.AreEqual(m, 5, "v.sqrMagnitude 1 2"); + + m = Vector2.SqrMagnitudeOf(v); + Assert.AreEqual(m, 5, "SqrMagnitudeOf 1 2"); + + v = new(-1, -2); + m = v.sqrMagnitude; + Assert.AreEqual(m, 5, "v.sqrMagnitude -1 -2"); + + v = new(0, 0); + m = v.sqrMagnitude; + Assert.AreEqual(m, 0, "v.sqrMagnitude 0 0"); + } + + [Test] + public void Distance() { + Vector2 v1 = new(4, 5); + Vector2 v2 = new(1, 2); + float f = 0; + + f = Vector2.Distance(v1, v2); + Assert.AreEqual(f, 4.24264002f, 1.0E-05F, "Distance(4 5, 1 2)"); + + v2 = new(-1, -2); + f = Vector2.Distance(v1, v2); + Assert.AreEqual(f, 8.602325F, "Distance(4 5, 1 2)"); + + v2 = new(0, 0); + f = Vector2.Distance(v1, v2); + Assert.AreEqual(f, 6.403124F, 1.0E-05F, "Distance(4 5, 1 2)"); + } + + [Test] + public void Normalize() { + Vector2 v = new(0, 3); + Vector2Float r; + + r = v.normalized; + Assert.AreEqual(0, r.horizontal, "normalized 0 3 H"); + Assert.AreEqual(1, r.vertical, "normalized 0 3 V"); + + r = Vector2.Normalize(v); + Assert.AreEqual(0, r.horizontal, "Normalize 0 3 H"); + Assert.AreEqual(1, r.vertical, "Normalize 0 3 V"); + + v = new(0, -3); + r = v.normalized; + Assert.AreEqual(0, r.horizontal, "normalized 0 -3 H"); + Assert.AreEqual(-1, r.vertical, "normalized 0 -3 V"); + + v = new(0, 0); + r = v.normalized; + Assert.AreEqual(0, r.horizontal, "normalized 0 0 H"); + Assert.AreEqual(0, r.vertical, "normalized 0 0 V"); + } + + [Test] + public void Negate() { + Vector2 v = new(4, 5); + Vector2 r; + + r = -v; + Assert.AreEqual(-4, r.horizontal, "- 4 5 H"); + Assert.AreEqual(-5, r.vertical, "- 4 5 V"); + + v = new(-4, -5); + r = -v; + Assert.AreEqual(4, r.horizontal, "- -4 -5 H"); + Assert.AreEqual(5, r.vertical, "- -4 -5 V"); + + v = new(0, 0); + r = -v; + Assert.AreEqual(0, r.horizontal, "- 0 0 H"); + Assert.AreEqual(0, r.vertical, "- 0 0 V"); + } + + [Test] + public void Subtract() { + Vector2 v1 = new(4, 5); + Vector2 v2 = new(1, 2); + Vector2 r = Vector2.zero; + + r = v1 - v2; + Assert.IsTrue(r == new Vector2(3, 3), "4 5 - 1 2"); + + v2 = new(-1, -2); + r = v1 - v2; + Assert.IsTrue(r == new Vector2(5, 7), "4 5 - -1 -2"); + + v2 = new(4, 5); + r = v1 - v2; + Assert.IsTrue(r == new Vector2(0, 0), "4 5 - 4 5"); + r = v1; + r -= v2; + Assert.AreEqual(r, new Vector2(0, 0), "4 5 - 4 5"); + + v2 = new(0, 0); + r = v1 - v2; + Assert.AreEqual(r, new Vector2(4, 5), "4 5 - 0 0"); + r -= v2; + Assert.AreEqual(r, new Vector2(4, 5), "4 5 - 0 0"); + } + + [Test] + public void Addition() { + Vector2 v1 = new(4, 5); + Vector2 v2 = new(1, 2); + Vector2 r = Vector2.zero; + + r = v1 + v2; + Assert.IsTrue(r == new Vector2(5, 7), "4 5 + 1 2"); + + v2 = new(-1, -2); + r = v1 + v2; + Assert.IsTrue(r == new Vector2(3, 3), "4 5 + -1 -2"); + r = v1; + r += v2; + Assert.AreEqual(r, new Vector2(3, 3), "4 5 + -1 -2"); + + v2 = new(0, 0); + r = v1 + v2; + Assert.AreEqual(r, new Vector2(4, 5), "4 5 + 0 0"); + r += v2; + Assert.AreEqual(r, new Vector2(4, 5), "4 5 + 0 0"); + } + + [Test] + public void Scale() { + Vector2 v1 = new(4, 5); + Vector2 v2 = new(1, 2); + Vector2 r; + + r = Vector2.Scale(v1, v2); + Assert.AreEqual(4, r.horizontal, "Scale 4 5 , 1 2 H"); + Assert.AreEqual(10, r.vertical, "Scale 4 5 , 1 2 V"); + + v2 = new(-1, -2); + r = Vector2.Scale(v1, v2); + Assert.AreEqual(-4, r.horizontal, "Scale 4 5 , -1 -2 H"); + Assert.AreEqual(-10, r.vertical, "Scale 4 5 , -1 -2 V"); + + v2 = new(0, 0); + r = Vector2.Scale(v1, v2); + Assert.AreEqual(0, r.horizontal, "Scale 4 5 , 0 0 H"); + Assert.AreEqual(0, r.vertical, "Scale 4 5 , 0 0 V"); + } + + [Test] + public void Multiply() { + Vector2 v1 = new(4, 5); + int f = 3; + Vector2 r; + + r = v1 * f; + Assert.AreEqual(12, r.horizontal, "4 5 * 3 H"); + Assert.AreEqual(15, r.vertical, "4 5 * 3 V"); + + r = f * v1; + Assert.AreEqual(12, r.horizontal, "3 * 4 5 H"); + Assert.AreEqual(15, r.vertical, "3 * 4 5 V"); + + f = -3; + r = v1 * f; + Assert.AreEqual(-12, r.horizontal, "4 5 * -3 H"); + Assert.AreEqual(-15, r.vertical, "4 5 * -3 V"); + + f = 0; + r = v1 * f; + Assert.AreEqual(0, r.horizontal, "4 5 * 0 H"); + Assert.AreEqual(0, r.vertical, "4 5 * 0 V"); + } + + [Test] + public void Divide() { + Vector2 v1 = new(4, 5); + int f = 2; + Vector2 r; + + r = v1 / f; + Assert.AreEqual(2, r.horizontal, "4 5 / 2 H"); + Assert.AreEqual(2, r.vertical, "4 5 / 2 V"); + + f = -2; + r = v1 / f; + Assert.AreEqual(-2, r.horizontal, "4 5 / -2 H"); + Assert.AreEqual(-2, r.vertical, "4 5 / -2 V"); + + Assert.Throws(() => { + f = 0; + r = v1 / f; + Assert.AreEqual(float.PositiveInfinity, r.horizontal, "4 5 / 0 H"); + Assert.AreEqual(float.PositiveInfinity, r.vertical, "4 5 / 0 V"); + }); + } + + [Test] + public void Dot() { + Vector2 v1 = new(4, 5); + Vector2 v2 = new(1, 2); + int f; + + f = Vector2.Dot(v1, v2); + Assert.AreEqual(14, f, "Dot(4 5, 1 2)"); + + v2 = new(-1, -2); + f = Vector2.Dot(v1, v2); + Assert.AreEqual(-14, f, "Dot(4 5, -1 -2)"); + + v2 = new(0, 0); + f = Vector2.Dot(v1, v2); + Assert.AreEqual(0, f, "Dot(4 5, 0 0)"); + } + + } +} +#endif \ No newline at end of file diff --git a/LinearAlgebra/test/Vector3FloatTest.cs b/LinearAlgebra/test/Vector3FloatTest.cs new file mode 100644 index 0000000..fd3c2dc --- /dev/null +++ b/LinearAlgebra/test/Vector3FloatTest.cs @@ -0,0 +1,581 @@ +#if !UNITY_5_6_OR_NEWER +using NUnit.Framework; + +namespace LinearAlgebra.Test { + using Vector3 = Vector3Float; + + public class Vector3FloatTest { + + [Test] + public void FromSpherical() { + Vector3 v = new(0, 0, 1); + Spherical s = Spherical.FromVector3(v); + Vector3 r = Vector3.FromSpherical(s); + + Assert.AreEqual(0, r.horizontal, "0 0 1"); + Assert.AreEqual(0, r.vertical, 1.0e-06, "0 0 1"); + Assert.AreEqual(1, r.depth, "0 0 1"); + + v = new(0, 1, 0); + s = Spherical.FromVector3(v); + r = Vector3.FromSpherical(s); + Assert.AreEqual(0, r.horizontal, "0 0 1"); + Assert.AreEqual(1, r.vertical, "0 0 1"); + Assert.AreEqual(0, r.depth, 1.0e-06, "0 0 1"); + + v = new(1, 0, 0); + s = Spherical.FromVector3(v); + r = Vector3.FromSpherical(s); + Assert.AreEqual(1, r.horizontal, "0 0 1"); + Assert.AreEqual(0, r.vertical, 1.0e-06, "0 0 1"); + Assert.AreEqual(0, r.depth, 1.0e-06, "0 0 1"); + } + + [Test] + public void Magnitude() { + Vector3 v = new(1, 2, 3); + float m = 0; + + m = v.magnitude; + Assert.AreEqual(3.7416575f, m, "magnitude 1 2 3"); + + m = Vector3.MagnitudeOf(v); + Assert.AreEqual(3.7416575f, m, "MagnitudeOf 1 2 3"); + + v = new(-1, -2, -3); + m = v.magnitude; + Assert.AreEqual(3.7416575f, m, "magnitude -1 -2 -3"); + + v = new(0, 0, 0); + m = v.magnitude; + Assert.AreEqual(0, m, "magnitude 0 0 0"); + + // Infinity tests are still missing + } + + [Test] + public void SqrMagnitude() { + Vector3 v = new(1, 2, 3); + float m = 0; + + m = v.sqrMagnitude; + Assert.AreEqual(14, m, "sqrMagnitude 1 2 3"); + + m = Vector3.SqrMagnitudeOf(v); + Assert.AreEqual(14, m, "SqrMagnitudeOf 1 2 3"); + + v = new(-1, -2, -3); + m = v.sqrMagnitude; + Assert.AreEqual(14, m, "sqrMagnitude -1 -2 -3"); + + v = new(0, 0, 0); + m = v.sqrMagnitude; + Assert.AreEqual(0, m, "sqrMagnitude 0 0 0"); + + // Infinity tests are still missing + } + + [Test] + public void Normalize() { + Vector3 v = new(0, 2, 0); + Vector3 r; + + r = v.normalized; + Assert.AreEqual(new Vector3(0, 1, 0), r, "normalized 0 2 0"); + + r = Vector3.Normalize(v); + Assert.AreEqual(new Vector3(0, 1, 0), r, "Normalize 0 2 0"); + + v = new(0, -2, 0); + r = v.normalized; + Assert.AreEqual(new Vector3(0, -1, 0), r, "normalized 0 -2 0"); + v = new(0, 0, 0); + r = v.normalized; + Assert.AreEqual(new Vector3(0, 0, 0), r, "normalized 0 0 0"); + + v = new(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); + r = v.normalized; + Assert.IsTrue(float.IsNaN(r.horizontal), "normalized infinity infinity infinity"); + Assert.IsTrue(float.IsNaN(r.vertical), "normalized infinity infinity infinity"); + Assert.IsTrue(float.IsNaN(r.depth), "normalized infinity infinity infinity"); + + v = new(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); + r = v.normalized; + Assert.IsTrue(float.IsNaN(r.horizontal), "normalized -infinity -infinity -infinity"); + Assert.IsTrue(float.IsNaN(r.vertical), "normalized -infinity -infinity -infinity"); + Assert.IsTrue(float.IsNaN(r.depth), "normalized -infinity -infinity -infinity"); + } + + [Test] + public void Negate() { + Vector3 v = new(4, 5, 6); + Vector3 r; + + r = -v; + Assert.AreEqual(-4, r.horizontal, "- 4 5 6 H"); + Assert.AreEqual(-5, r.vertical, "- 4 5 6 V"); + Assert.AreEqual(-6, r.depth, "- 4 5 6 D"); + + v = new(-4, -5, -6); + r = -v; + Assert.AreEqual(4, r.horizontal, "- -4 -5 -6 H"); + Assert.AreEqual(5, r.vertical, "- -4 -5 -6 V"); + Assert.AreEqual(6, r.depth, "- -4 -5 -6 D"); + + v = new(0, 0, 0); + r = -v; + Assert.AreEqual(new Vector3(0, 0, 0), r, "- 0 0 0"); + Assert.AreEqual(0, r.horizontal, "- 0 0 0 H"); + Assert.AreEqual(0, r.vertical, "- 0 0 0 V"); + Assert.AreEqual(0, r.depth, "- 0 0 0 D"); + + + v = new(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); + r = -v; + Assert.AreEqual(new Vector3(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity), r, "- inifinty infinity infinity"); + + v = new(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); + r = -v; + Assert.AreEqual(new Vector3(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity), r, "- -inifinty -infinity -infinity"); + } + + [Test] + public void Subtract() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + Vector3 r = Vector3.zero; + + r = v1 - v2; + Assert.IsTrue(r == new Vector3(3, 3, 3), "4 5 6 - 1 2 3"); + + v2 = new(-1, -2, -3); + r = v1 - v2; + Assert.IsTrue(r == new Vector3(5, 7, 9), "4 5 6 - -1 -2 -3"); + + v2 = new(4, 5, 6); + r = v1 - v2; + Assert.IsTrue(r == new Vector3(0, 0, 0), "4 5 6 - 4 5 6"); + r = v1; + r -= v2; + Assert.AreEqual(r, new Vector3(0, 0, 0), "4 5 6 - 4 5 6"); + + v2 = new(0, 0, 0); + r = v1 - v2; + Assert.AreEqual(r, new Vector3(4, 5, 6), "4 5 6 - 0 0 0"); + r -= v2; + Assert.AreEqual(r, new Vector3(4, 5, 6), "4 5 6 - 0 0 0"); + + // Infinity tests are still missing + } + + [Test] + public void Addition() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + Vector3 r = Vector3.zero; + + r = v1 + v2; + Assert.IsTrue(r == new Vector3(5, 7, 9), "4 5 6 + 1 2 3"); + + v2 = new(-1, -2, -3); + r = v1 + v2; + Assert.IsTrue(r == new Vector3(3, 3, 3), "4 5 6 + -1 -2 -3"); + r = v1; + r += v2; + Assert.AreEqual(r, new Vector3(3, 3, 3), "4 5 6 + -1 -2 -3"); + + v2 = new(0, 0, 0); + r = v1 + v2; + Assert.AreEqual(r, new Vector3(4, 5, 6), "4 5 6 + 0 0 0"); + r += v2; + Assert.AreEqual(r, new Vector3(4, 5, 6), "4 5 6 + 0 0 0"); + + // Infinity tests are still missing + } + + [Test] + public void Scale() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + Vector3 r; + + r = Vector3.Scale(v1, v2); + Assert.AreEqual(4, r.horizontal, "Scale 4 5 6 , 1 2 3 H"); + Assert.AreEqual(10, r.vertical, "Scale 4 5 6 , 1 2 3 V"); + Assert.AreEqual(18, r.depth, "Scale 4 5 6 , 1 2 3 D"); + + v2 = new(-1, -2, -3); + r = Vector3.Scale(v1, v2); + Assert.AreEqual(-4, r.horizontal, "Scale 4 5 6 , -1 -2 -3 H"); + Assert.AreEqual(-10, r.vertical, "Scale 4 5 6 , -1 -2 -3 V"); + Assert.AreEqual(-18, r.depth, "Scale 4 5 6 , -1 -2 -3 D"); + + v2 = new(0, 0, 0); + r = Vector3.Scale(v1, v2); + Assert.AreEqual(0, r.horizontal, "Scale 4 5 6 , 0 0 0 H"); + Assert.AreEqual(0, r.vertical, "Scale 4 5 6 , 0 0 0 V"); + Assert.AreEqual(0, r.depth, "Scale 4 5 6 , 0 0 0 D"); + + v2 = new(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); + r = Vector3.Scale(v1, v2); + Assert.AreEqual(float.PositiveInfinity, r.horizontal, "Scale 4 5 6 , inf inf inf H"); + Assert.AreEqual(float.PositiveInfinity, r.vertical, "Scale 4 5 6 , inf inf inf V"); + Assert.AreEqual(float.PositiveInfinity, r.depth, "Scale 4 5 6 , inf inf inf D"); + + v2 = new(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); + r = Vector3.Scale(v1, v2); + Assert.AreEqual(float.NegativeInfinity, r.horizontal, "Scale 4 5 6 , -inf -inf -inf H"); + Assert.AreEqual(float.NegativeInfinity, r.vertical, "Scale 4 5 6 , -inf -inf -inf V"); + Assert.AreEqual(float.NegativeInfinity, r.depth, "Scale 4 5 6 , -inf -inf -inf D"); + } + + [Test] + public void Multiply() { + Vector3 v1 = new(4, 5, 6); + float f = 3; + Vector3 r; + + r = v1 * f; + Assert.AreEqual(12, r.horizontal, "4 5 6 * 3 H"); + Assert.AreEqual(15, r.vertical, "4 5 6 * 3 V"); + Assert.AreEqual(18, r.depth, "4 5 6 * 3 D"); + + f = -3; + r = v1 * f; + Assert.AreEqual(-12, r.horizontal, "4 5 6 * -3 H"); + Assert.AreEqual(-15, r.vertical, "4 5 6 * -3 V"); + Assert.AreEqual(-18, r.depth, "4 5 6 * -3 D"); + + f = 0; + r = v1 * f; + Assert.AreEqual(0, r.horizontal, "4 5 6 * 0 H"); + Assert.AreEqual(0, r.vertical, "4 5 6 * 0 V"); + Assert.AreEqual(0, r.depth, "4 5 6 * 0 D"); + + f = float.PositiveInfinity; + r = v1 * f; + Assert.AreEqual(float.PositiveInfinity, r.horizontal, "4 5 6 * inf H"); + Assert.AreEqual(float.PositiveInfinity, r.vertical, "4 5 6 * inf V"); + Assert.AreEqual(float.PositiveInfinity, r.depth, "4 5 6 * inf D"); + + f = float.NegativeInfinity; + r = v1 * f; + Assert.AreEqual(float.NegativeInfinity, r.horizontal, "4 5 6 * -inf H"); + Assert.AreEqual(float.NegativeInfinity, r.vertical, "4 5 6 * -inf V"); + Assert.AreEqual(float.NegativeInfinity, r.depth, "4 5 6 * -inf D"); + } + + [Test] + public void Divide() { + Vector3 v1 = new(4, 5, 6); + float f = 2; + Vector3 r; + + r = v1 / f; + Assert.AreEqual(2, r.horizontal, "4 5 6 / 2 H"); + Assert.AreEqual(2.5, r.vertical, "4 5 6 / 2 V"); + Assert.AreEqual(3, r.depth, "4 5 6 / 2 D"); + + f = -2; + r = v1 / f; + Assert.AreEqual(-2, r.horizontal, "4 5 6 / -2 H"); + Assert.AreEqual(-2.5, r.vertical, "4 5 6 / -2 V"); + Assert.AreEqual(-3, r.depth, "4 5 6 / -2 D"); + + f = 0; + r = v1 / f; + Assert.AreEqual(float.PositiveInfinity, r.horizontal, "4 5 6 / 0 H"); + Assert.AreEqual(float.PositiveInfinity, r.vertical, "4 5 6 / 0 V"); + Assert.AreEqual(float.PositiveInfinity, r.depth, "4 5 6 / 0 D"); + + f = float.PositiveInfinity; + r = v1 / f; + Assert.AreEqual(0, r.horizontal, "4 5 6 / inf H"); + Assert.AreEqual(0, r.vertical, "4 5 6 / inf V"); + Assert.AreEqual(0, r.depth, "4 5 6 / inf D"); + + f = float.NegativeInfinity; + r = v1 / f; + Assert.AreEqual(0, r.horizontal, "4 5 6 / -inf H"); + Assert.AreEqual(0, r.vertical, "4 5 6 / -inf V"); + Assert.AreEqual(0, r.depth, "4 5 6 / -inf D"); + } + + [Test] + public void Dot() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + float f; + + f = Vector3.Dot(v1, v2); + Assert.AreEqual(32, f, "Dot(4 5 6, 1 2 3)"); + + v2 = new(-1, -2, -3); + f = Vector3.Dot(v1, v2); + Assert.AreEqual(-32, f, "Dot(4 5 6, -1 -2 -3)"); + + v2 = new(0, 0, 0); + f = Vector3.Dot(v1, v2); + Assert.AreEqual(0, f, "Dot(4 5 6, 0 0 0)"); + + v2 = new(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); + f = Vector3.Dot(v1, v2); + Assert.AreEqual(float.PositiveInfinity, f, "Dot(4 5 6, inf inf inf)"); + + v2 = new(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); + f = Vector3.Dot(v1, v2); + Assert.AreEqual(float.NegativeInfinity, f, "Dot(4 5 6, -inf -inf -inf)"); + } + + [Test] + public void Equality() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + bool r; + + r = v1 == v2; + Assert.IsFalse(r, "4 5 6 == 1 2 3"); + + v2 = new(4, 5, 6); + r = v1 == v2; + Assert.IsTrue(r, "4 5 6 == 4 5 6"); + + v2 = new(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); + r = v1 == v2; + Assert.IsFalse(r, "4 5 6 == inf inf inf"); + + v1 = new(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); + r = v1 == v2; + Assert.IsFalse(r, "-inf -inf -inf == inf inf inf"); + } + + [Test] + public void Distance() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + float f; + + f = Vector3.Distance(v1, v2); + Assert.AreEqual(5.19615221F, f, "Distance(4 5 6, 1 2 3)"); + + v2 = new(-1, -2, -3); + f = Vector3.Distance(v1, v2); + Assert.AreEqual(12.4498997F, f, "Distance(4 5 6, -1 -2 -3)"); + + v2 = new(0, 0, 0); + f = Vector3.Distance(v1, v2); + Assert.AreEqual(v1.magnitude, f, "Distance(4 5 6, 0 0 0)"); + + v2 = new(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); + f = Vector3.Distance(v1, v2); + Assert.AreEqual(float.PositiveInfinity, f, "Distance(4 5 6, inf inf inf)"); + + v2 = new(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); + f = Vector3.Distance(v1, v2); + Assert.AreEqual(float.PositiveInfinity, f, "Distance(4 5 6, -inf -inf -inf)"); + } + + [Test] + public void Cross() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + Vector3 r; + + r = Vector3.Cross(v1, v2); + Assert.AreEqual(3, r.horizontal, "Cross(4 5 6, 1 2 3) H"); + Assert.AreEqual(-6, r.vertical, "Cross(4 5 6, 1 2 3) V"); + Assert.AreEqual(3, r.depth, "Cross(4 5 6, 1 2 3) D"); + + v2 = new(-1, -2, -3); + r = Vector3.Cross(v1, v2); + Assert.AreEqual(-3, r.horizontal, "Cross(4 5 6, -1 -2 -3) H"); + Assert.AreEqual(6, r.vertical, "Cross(4 5 6, -1 -2 -3) V"); + Assert.AreEqual(-3, r.depth, "Cross(4 5 6, -1 -2 -3) D"); + + v2 = new(0, 0, 0); + r = Vector3.Cross(v1, v2); + Assert.AreEqual(0, r.horizontal, "Cross(4 5 6, 0 0 0) H"); + Assert.AreEqual(0, r.vertical, "Cross(4 5 6, 0 0 0) V"); + Assert.AreEqual(0, r.depth, "Cross(4 5 6, 0 0 0) D"); + + v2 = new(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); + r = Vector3.Cross(v1, v2); + Assert.IsTrue(float.IsNaN(r.horizontal), "Cross(4 5 6, inf inf inf) H"); + Assert.IsTrue(float.IsNaN(r.vertical), "Cross(4 5 6, inf inf inf) V"); + Assert.IsTrue(float.IsNaN(r.depth), "Cross(4 5 6, inf inf inf) D"); + + v2 = new(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); + r = Vector3.Cross(v1, v2); + Assert.IsTrue(float.IsNaN(r.horizontal), "Cross(4 5 6, -inf -inf -inf) H"); + Assert.IsTrue(float.IsNaN(r.vertical), "Cross(4 5 6, -inf -inf -inf) V"); + Assert.IsTrue(float.IsNaN(r.depth), "Cross(4 5 6, -inf -inf -inf) D"); + } + + [Test] + public void Project() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + Vector3 r; + + r = Vector3.Project(v1, v2); + Assert.AreEqual(2.28571439F, r.horizontal, "Project(4 5 6, 1 2 3) H"); + Assert.AreEqual(4.57142878F, r.vertical, "Project(4 5 6, 1 2 3) V"); + Assert.AreEqual(6.85714293F, r.depth, "Project(4 5 6, 1 2 3) D"); + + v2 = new(-1, -2, -3); + r = Vector3.Project(v1, v2); + Assert.AreEqual(2.28571439F, r.horizontal, "Project(4 5 6, -1 -2 -3) H"); + Assert.AreEqual(4.57142878F, r.vertical, "Project(4 5 6, -1 -2 -3) V"); + Assert.AreEqual(6.85714293F, r.depth, "Project(4 5 6, -1 -2 -3) D"); + + v2 = new(0, 0, 0); + r = Vector3.Project(v1, v2); + Assert.AreEqual(0, r.horizontal, "Project(4 5 6, 0 0 0) H"); + Assert.AreEqual(0, r.vertical, "Project(4 5 6, 0 0 0) V"); + Assert.AreEqual(0, r.depth, "Project(4 5 6, 0 0 0) D"); + + r = Vector3.Project(v2, v1); + Assert.AreEqual(0, r.horizontal, "Project(0 0 0, 4 5 6) H"); + Assert.AreEqual(0, r.vertical, "Project(0 0 0, 4 5 6) V"); + Assert.AreEqual(0, r.depth, "Project(0 0 0, 4 5 6) D"); + + v2 = new(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); + r = Vector3.Project(v1, v2); + Assert.IsTrue(float.IsNaN(r.horizontal), "Project(4 5 6, inf inf inf) H"); + Assert.IsTrue(float.IsNaN(r.vertical), "Project(4 5 6, inf inf inf) V"); + Assert.IsTrue(float.IsNaN(r.depth), "Project(4 5 6, inf inf inf) D"); + + v2 = new(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); + r = Vector3.Project(v1, v2); + Assert.IsTrue(float.IsNaN(r.horizontal), "Project(4 5 6, -inf -inf -inf) H"); + Assert.IsTrue(float.IsNaN(r.vertical), "Project(4 5 6, -inf -inf -inf) V"); + Assert.IsTrue(float.IsNaN(r.depth), "Project(4 5 6, -inf -inf -inf) D"); + } + + [Test] + public void ProjectOnPlane() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + Vector3 r; + + r = Vector3.ProjectOnPlane(v1, v2); + Assert.AreEqual(1.71428561F, r.horizontal, "ProjectOnPlane(4 5 6, 1 2 3) H"); + Assert.AreEqual(0.428571224F, r.vertical, "ProjectOnPlane(4 5 6, 1 2 3) V"); + Assert.AreEqual(-0.857142925F, r.depth, "ProjectOnPlane(4 5 6, 1 2 3) D"); + + v2 = new(-1, -2, -3); + r = Vector3.ProjectOnPlane(v1, v2); + Assert.AreEqual(1.71428561F, r.horizontal, "ProjectOnPlane(4 5 6, -1 -2 -3) H"); + Assert.AreEqual(0.428571224F, r.vertical, "ProjectOnPlane(4 5 6, -1 -2 -3) V"); + Assert.AreEqual(-0.857142925F, r.depth, "ProjectOnPlane(4 5 6, -1 -2 -3) D"); + + v2 = new(0, 0, 0); + r = Vector3.ProjectOnPlane(v1, v2); + Assert.AreEqual(4, r.horizontal, "ProjectOnPlane(4 5 6, 0 0 0) H"); + Assert.AreEqual(5, r.vertical, "ProjectOnPlane(4 5 6, 0 0 0) V"); + Assert.AreEqual(6, r.depth, "ProjectOnPlane(4 5 6, 0 0 0) D"); + + r = Vector3.ProjectOnPlane(v2, v1); + Assert.AreEqual(0, r.horizontal, "ProjectOnPlane(0 0 0, 4 5 6) H"); + Assert.AreEqual(0, r.vertical, "ProjectOnPlane(0 0 0, 4 5 6) V"); + Assert.AreEqual(0, r.depth, "ProjectOnPlane(0 0 0, 4 5 6) D"); + + v2 = new(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); + r = Vector3.ProjectOnPlane(v1, v2); + Assert.IsTrue(float.IsNaN(r.horizontal), "ProjectOnPlane(4 5 6, inf inf inf) H"); + Assert.IsTrue(float.IsNaN(r.vertical), "ProjectOnPlane(4 5 6, inf inf inf) V"); + Assert.IsTrue(float.IsNaN(r.depth), "ProjectOnPlane(4 5 6, inf inf inf) D"); + + v2 = new(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); + r = Vector3.ProjectOnPlane(v1, v2); + Assert.IsTrue(float.IsNaN(r.horizontal), "ProjectOnPlane(4 5 6, -inf -inf -inf) H"); + Assert.IsTrue(float.IsNaN(r.vertical), "ProjectOnPlane(4 5 6, -inf -inf -inf) V"); + Assert.IsTrue(float.IsNaN(r.depth), "ProjectOnPlane(4 5 6, -inf -inf -inf) D"); + } + + [Test] + public void UnsignedAngle() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + AngleFloat a; + + a = Vector3.UnsignedAngle(v1, v2); + Assert.AreEqual(12.9331379F, a.inDegrees, "Angle(4 5 6, 1 2 3)"); + + v2 = new(-1, -2, -3); + a = Vector3.UnsignedAngle(v1, v2); + Assert.AreEqual(167.066849F, a.inDegrees, "Angle(4 5 6, -1 -2 -3)"); + + v2 = new(0, 0, 0); + a = Vector3.UnsignedAngle(v1, v2); + Assert.AreEqual(0, a.inDegrees, "Angle(4 5 6, 0 0 0)"); + + v2 = new(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); + a = Vector3.UnsignedAngle(v1, v2); + Assert.IsTrue(float.IsNaN(a.inDegrees), "Angle(4 5 6, inf inf inf)"); + + v2 = new(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); + a = Vector3.UnsignedAngle(v1, v2); + Assert.IsTrue(float.IsNaN(a.inDegrees), "Angle(4 5 6, inf inf inf)"); + } + + [Test] + public void SignedAngle() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + Vector3 v3 = new(7, 8, -9); + AngleFloat a; + + a = Vector3.SignedAngle(v1, v2, v3); + Assert.AreEqual(-12.9331379F, a.inDegrees, "SignedAngle(4 5 6, 1 2 3, 7 8 -9)"); + + v2 = new(-1, -2, -3); + a = Vector3.SignedAngle(v1, v2, v3); + Assert.AreEqual(167.066849F, a.inDegrees, "SignedAngle(4 5 6, -1 -2 -3, 7 8 -9)"); + + v2 = new(0, 0, 0); + a = Vector3.SignedAngle(v1, v2, v3); + Assert.AreEqual(0, a.inDegrees, "SignedAngle(4 5 6, 0 0 0, 7 8 -9)"); + + v2 = new(1, 2, 3); + v3 = new(-7, -8, 9); + a = Vector3.SignedAngle(v1, v2, v3); + Assert.AreEqual(12.9331379F, a.inDegrees, "SignedAngle(4 5 6, 1 2 3, -7 -8 9)"); + + v3 = new(0, 0, 0); + a = Vector3.SignedAngle(v1, v2, v3); + Assert.AreEqual(0, a.inDegrees, "SignedAngle(4 5 6, 1 2 3, 0 0 0)"); + + v2 = new(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); + a = Vector3.SignedAngle(v1, v2, v3); + Assert.IsTrue(float.IsNaN(a.inDegrees), "SignedAngle(4 5 6, inf inf inf, 0 0 0)"); + + v2 = new(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); + a = Vector3.SignedAngle(v1, v2, v3); + Assert.IsTrue(float.IsNaN(a.inDegrees), "SignedAngle(4 5 6, -inf -inf -inf, 0 0 0)"); + } + + [Test] + public void Lerp() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + Vector3 r; + + r = Vector3.Lerp(v1, v2, 0); + Assert.AreEqual(0, Vector3.Distance(r, v1), 0); + + r = Vector3.Lerp(v1, v2, 1); + Assert.AreEqual(0, Vector3.Distance(r, v2), 0); + + r = Vector3.Lerp(v1, v2, 0.5f); + Assert.AreEqual(0, Vector3.Distance(r, new Vector3(2.5f, 3.5f, 4.5f)), 0); + + r = Vector3.Lerp(v1, v2, -1); + Assert.AreEqual(0, Vector3.Distance(r, new Vector3(7, 8, 9)), 0); + + r = Vector3.Lerp(v1, v2, 2); + Assert.AreEqual(0, Vector3.Distance(r, new Vector3(-2, -1, 0)), 0); + } + } +} +#endif \ No newline at end of file diff --git a/LinearAlgebra/test/Vector3IntTest.cs b/LinearAlgebra/test/Vector3IntTest.cs new file mode 100644 index 0000000..b718178 --- /dev/null +++ b/LinearAlgebra/test/Vector3IntTest.cs @@ -0,0 +1,349 @@ +#if !UNITY_5_6_OR_NEWER +using NUnit.Framework; + +namespace LinearAlgebra.Test { + using Vector3 = Vector3Int; + + public class Vector3IntTest { + + [Test] + public void Equality() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + + Assert.IsFalse(v1 == v2, "4 5 6 == 1 2 3"); + Assert.IsTrue(v1 != v2, "4 5 6 != 1 2 3"); + + v2 = new(4, 5, 6); + Assert.IsTrue(v1 == v2, "4 5 6 == 4 5 6"); + Assert.IsFalse(v1 != v2, "4 5 6 != 4 5 6"); + } + + [Test] + public void Magnitude() { + Vector3 v = new(1, 2, 3); + float m = 0; + + m = v.magnitude; + Assert.AreEqual(3.7416575f, m, "magnitude 1 2 3"); + + m = Vector3.MagnitudeOf(v); + Assert.AreEqual(3.7416575f, m, "MagnitudeOf 1 2 3"); + + v = new(-1, -2, -3); + m = v.magnitude; + Assert.AreEqual(3.7416575f, m, "magnitude -1 -2 -3"); + + v = new(0, 0, 0); + m = v.magnitude; + Assert.AreEqual(0, m, "magnitude 0 0 0"); + + // Infinity tests are still missing + } + + [Test] + public void SqrMagnitude() { + Vector3 v = new(1, 2, 3); + float m = 0; + + m = v.sqrMagnitude; + Assert.AreEqual(14, m, "sqrMagnitude 1 2 3"); + + m = Vector3.SqrMagnitudeOf(v); + Assert.AreEqual(14, m, "SqrMagnitudeOf 1 2 3"); + + v = new(-1, -2, -3); + m = v.sqrMagnitude; + Assert.AreEqual(14, m, "sqrMagnitude -1 -2 -3"); + + v = new(0, 0, 0); + m = v.sqrMagnitude; + Assert.AreEqual(0, m, "sqrMagnitude 0 0 0"); + + // Infinity tests are still missing + } + + [Test] + public void Distance() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + float f; + + f = Vector3.Distance(v1, v2); + Assert.AreEqual(5.19615221F, f, "Distance(4 5 6, 1 2 3)"); + + v2 = new(-1, -2, -3); + f = Vector3.Distance(v1, v2); + Assert.AreEqual(12.4498997F, f, "Distance(4 5 6, -1 -2 -3)"); + + v2 = new(0, 0, 0); + f = Vector3.Distance(v1, v2); + Assert.AreEqual(v1.magnitude, f, "Distance(4 5 6, 0 0 0)"); + } + + [Test] + public void Normalize() { + Vector3 v = new(0, 2, 0); + Vector3Float r; + + r = v.normalized; + //Assert.AreEqual(new Vector3(0, 1, 0), r, "normalized 0 2 0"); + Assert.AreEqual(0, r.horizontal, "normalized 0 2 0"); + Assert.AreEqual(1, r.vertical, "normalized 0 2 0"); + Assert.AreEqual(0, r.depth, "normalized 0 2 0"); + + r = Vector3.Normalize(v); + Assert.AreEqual(new Vector3Float(0, 1, 0), r, "Normalize 0 2 0"); + + v = new(0, -2, 0); + r = v.normalized; + Assert.AreEqual(new Vector3Float(0, -1, 0), r, "normalized 0 -2 0"); + v = new(0, 0, 0); + r = v.normalized; + Assert.AreEqual(new Vector3Float(0, 0, 0), r, "normalized 0 0 0"); + } + + [Test] + public void Negate() { + Vector3 v = new(4, 5, 6); + Vector3 r; + + r = -v; + Assert.AreEqual(-4, r.horizontal, "- 4 5 6 H"); + Assert.AreEqual(-5, r.vertical, "- 4 5 6 V"); + Assert.AreEqual(-6, r.depth, "- 4 5 6 D"); + + v = new(-4, -5, -6); + r = -v; + Assert.AreEqual(4, r.horizontal, "- -4 -5 -6 H"); + Assert.AreEqual(5, r.vertical, "- -4 -5 -6 V"); + Assert.AreEqual(6, r.depth, "- -4 -5 -6 D"); + + v = new(0, 0, 0); + r = -v; + Assert.AreEqual(new Vector3(0, 0, 0), r, "- 0 0 0"); + Assert.AreEqual(0, r.horizontal, "- 0 0 0 H"); + Assert.AreEqual(0, r.vertical, "- 0 0 0 V"); + Assert.AreEqual(0, r.depth, "- 0 0 0 D"); + } + + [Test] + public void Subtract() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + Vector3 r = Vector3.zero; + + r = v1 - v2; + Assert.IsTrue(r == new Vector3(3, 3, 3), "4 5 6 - 1 2 3"); + + v2 = new(-1, -2, -3); + r = v1 - v2; + Assert.IsTrue(r == new Vector3(5, 7, 9), "4 5 6 - -1 -2 -3"); + + v2 = new(4, 5, 6); + r = v1 - v2; + Assert.IsTrue(r == new Vector3(0, 0, 0), "4 5 6 - 4 5 6"); + r = v1; + r -= v2; + Assert.AreEqual(r, new Vector3(0, 0, 0), "4 5 6 - 4 5 6"); + + v2 = new(0, 0, 0); + r = v1 - v2; + Assert.AreEqual(r, new Vector3(4, 5, 6), "4 5 6 - 0 0 0"); + r -= v2; + Assert.AreEqual(r, new Vector3(4, 5, 6), "4 5 6 - 0 0 0"); + + // Infinity tests are still missing + } + + [Test] + public void Addition() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + Vector3 r = Vector3.zero; + + r = v1 + v2; + Assert.IsTrue(r == new Vector3(5, 7, 9), "4 5 6 + 1 2 3"); + + v2 = new(-1, -2, -3); + r = v1 + v2; + Assert.IsTrue(r == new Vector3(3, 3, 3), "4 5 6 + -1 -2 -3"); + r = v1; + r += v2; + Assert.AreEqual(r, new Vector3(3, 3, 3), "4 5 6 + -1 -2 -3"); + + v2 = new(0, 0, 0); + r = v1 + v2; + Assert.AreEqual(r, new Vector3(4, 5, 6), "4 5 6 + 0 0 0"); + r += v2; + Assert.AreEqual(r, new Vector3(4, 5, 6), "4 5 6 + 0 0 0"); + + // Infinity tests are still missing + } + + [Test] + public void Scale() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + Vector3 r; + + r = Vector3.Scale(v1, v2); + Assert.AreEqual(4, r.horizontal, "Scale 4 5 6 , 1 2 3 H"); + Assert.AreEqual(10, r.vertical, "Scale 4 5 6 , 1 2 3 V"); + Assert.AreEqual(18, r.depth, "Scale 4 5 6 , 1 2 3 D"); + + v2 = new(-1, -2, -3); + r = Vector3.Scale(v1, v2); + Assert.AreEqual(-4, r.horizontal, "Scale 4 5 6 , -1 -2 -3 H"); + Assert.AreEqual(-10, r.vertical, "Scale 4 5 6 , -1 -2 -3 V"); + Assert.AreEqual(-18, r.depth, "Scale 4 5 6 , -1 -2 -3 D"); + + v2 = new(0, 0, 0); + r = Vector3.Scale(v1, v2); + Assert.AreEqual(0, r.horizontal, "Scale 4 5 6 , 0 0 0 H"); + Assert.AreEqual(0, r.vertical, "Scale 4 5 6 , 0 0 0 V"); + Assert.AreEqual(0, r.depth, "Scale 4 5 6 , 0 0 0 D"); + } + + [Test] + public void Multiply() { + Vector3 v1 = new(4, 5, 6); + int f = 3; + Vector3 r; + + r = v1 * f; + Assert.AreEqual(12, r.horizontal, "4 5 6 * 3 H"); + Assert.AreEqual(15, r.vertical, "4 5 6 * 3 V"); + Assert.AreEqual(18, r.depth, "4 5 6 * 3 D"); + + r = f * v1; + Assert.AreEqual(12, r.horizontal, "3 * 4 5 6 H"); + Assert.AreEqual(15, r.vertical, "3 * 4 5 6 V"); + Assert.AreEqual(18, r.depth, "3 * 4 5 6 D"); + + f = -3; + r = v1 * f; + Assert.AreEqual(-12, r.horizontal, "4 5 6 * -3 H"); + Assert.AreEqual(-15, r.vertical, "4 5 6 * -3 V"); + Assert.AreEqual(-18, r.depth, "4 5 6 * -3 D"); + + f = 0; + r = v1 * f; + Assert.AreEqual(0, r.horizontal, "4 5 6 * 0 H"); + Assert.AreEqual(0, r.vertical, "4 5 6 * 0 V"); + Assert.AreEqual(0, r.depth, "4 5 6 * 0 D"); + } + + [Test] + public void Divide() { + Vector3 v1 = new(4, 5, 6); + int f = 2; + Vector3 r; + + r = v1 / f; + Assert.AreEqual(2, r.horizontal, "4 5 6 / 2 H"); + Assert.AreEqual(2, r.vertical, "4 5 6 / 2 V"); + Assert.AreEqual(3, r.depth, "4 5 6 / 2 D"); + + f = -2; + r = v1 / f; + Assert.AreEqual(-2, r.horizontal, "4 5 6 / -2 H"); + Assert.AreEqual(-2, r.vertical, "4 5 6 / -2 V"); + Assert.AreEqual(-3, r.depth, "4 5 6 / -2 D"); + + Assert.Throws(() => { + f = 0; + r = v1 / f; + }); + } + + [Test] + public void Dot() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + float f; + + f = Vector3.Dot(v1, v2); + Assert.AreEqual(32, f, "Dot(4 5 6, 1 2 3)"); + + v2 = new(-1, -2, -3); + f = Vector3.Dot(v1, v2); + Assert.AreEqual(-32, f, "Dot(4 5 6, -1 -2 -3)"); + + v2 = new(0, 0, 0); + f = Vector3.Dot(v1, v2); + Assert.AreEqual(0, f, "Dot(4 5 6, 0 0 0)"); + } + + [Test] + public void Cross() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + Vector3 r; + + r = Vector3.Cross(v1, v2); + Assert.AreEqual(3, r.horizontal, "Cross(4 5 6, 1 2 3) H"); + Assert.AreEqual(-6, r.vertical, "Cross(4 5 6, 1 2 3) V"); + Assert.AreEqual(3, r.depth, "Cross(4 5 6, 1 2 3) D"); + + v2 = new(-1, -2, -3); + r = Vector3.Cross(v1, v2); + Assert.AreEqual(-3, r.horizontal, "Cross(4 5 6, -1 -2 -3) H"); + Assert.AreEqual(6, r.vertical, "Cross(4 5 6, -1 -2 -3) V"); + Assert.AreEqual(-3, r.depth, "Cross(4 5 6, -1 -2 -3) D"); + + v2 = new(0, 0, 0); + r = Vector3.Cross(v1, v2); + Assert.AreEqual(0, r.horizontal, "Cross(4 5 6, 0 0 0) H"); + Assert.AreEqual(0, r.vertical, "Cross(4 5 6, 0 0 0) V"); + Assert.AreEqual(0, r.depth, "Cross(4 5 6, 0 0 0) D"); + } + + [Test] + public void UnsignedAngle() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + AngleFloat a; + + a = Vector3.UnsignedAngle(v1, v2); + Assert.AreEqual(12.9331379F, a.inDegrees, "Angle(4 5 6, 1 2 3)"); + + v2 = new(-1, -2, -3); + a = Vector3.UnsignedAngle(v1, v2); + Assert.AreEqual(167.066849F, a.inDegrees, "Angle(4 5 6, -1 -2 -3)"); + + v2 = new(0, 0, 0); + a = Vector3.UnsignedAngle(v1, v2); + Assert.AreEqual(0, a.inDegrees, "Angle(4 5 6, 0 0 0)"); + } + + [Test] + public void SignedAngle() { + Vector3 v1 = new(4, 5, 6); + Vector3 v2 = new(1, 2, 3); + Vector3 v3 = new(7, 8, -9); + AngleFloat a; + + a = Vector3.SignedAngle(v1, v2, v3); + Assert.AreEqual(-12.9331379F, a.inDegrees, "SignedAngle(4 5 6, 1 2 3, 7 8 -9)"); + + v2 = new(-1, -2, -3); + a = Vector3.SignedAngle(v1, v2, v3); + Assert.AreEqual(167.066849F, a.inDegrees, "SignedAngle(4 5 6, -1 -2 -3, 7 8 -9)"); + + v2 = new(0, 0, 0); + a = Vector3.SignedAngle(v1, v2, v3); + Assert.AreEqual(0, a.inDegrees, "SignedAngle(4 5 6, 0 0 0, 7 8 -9)"); + + v2 = new(1, 2, 3); + v3 = new(-7, -8, 9); + a = Vector3.SignedAngle(v1, v2, v3); + Assert.AreEqual(12.9331379F, a.inDegrees, "SignedAngle(4 5 6, 1 2 3, -7 -8 9)"); + + v3 = new(0, 0, 0); + a = Vector3.SignedAngle(v1, v2, v3); + Assert.AreEqual(0, a.inDegrees, "SignedAngle(4 5 6, 1 2 3, 0 0 0)"); + } + } +} +#endif \ No newline at end of file diff --git a/MemoryCell.cs b/MemoryCell.cs new file mode 100644 index 0000000..6e20a75 --- /dev/null +++ b/MemoryCell.cs @@ -0,0 +1,65 @@ +using System; +using UnityEngine; +using Unity.Mathematics; +using static Unity.Mathematics.math; + +[Serializable] +public class MemoryCell : Neuron { + + public MemoryCell(ClusterPrefab cluster, string name) : base(cluster, name) {} + + #region Parameters + + // Returns the memorized value weighted by time + // return lastValue * (current time - last time) + [SerializeField] + public bool deltaValue = false; + + #endregion Parameters + + #region State + + private float3 _memorizedValue; + private float _memorizedTime; + + public override void UpdateState() { + // A memorycell does not have an activation function + float3 result = new(0, 0, 0); + int n = 0; + + //Applying the weight factgors + foreach (Synapse synapse in this.synapses) { + if (synapse.nucleus == this) { + float deltaTime = Time.time - this.lastTime; + synapse.weight = deltaTime; + } + result += synapse.weight * synapse.nucleus.outputValue; + if (lengthsq(synapse.nucleus.outputValue) != 0) + n++; + } + + if (this.average) + result /= n; + + UpdateResult(result); + } + + public override void UpdateResult(Vector3 result) { + // output value is the previous value + if (this.deltaValue) { + float deltaTime = Time.time - this._memorizedTime; + this._outputValue = this._memorizedValue * deltaTime; + } + else + this._outputValue = this._memorizedValue; + + // Store the result for the next time + this._memorizedValue = result; + this._memorizedTime = Time.time; + + foreach (INucleus receiver in this.receivers) + receiver.UpdateState(); + } + + #endregion State +} diff --git a/MemoryCell.cs.meta b/MemoryCell.cs.meta new file mode 100644 index 0000000..ef74aba --- /dev/null +++ b/MemoryCell.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 29633aa3fe5cd9dcc8d886051f45d4d8 \ No newline at end of file diff --git a/NanoBrain-Unity.code-workspace b/NanoBrain-Unity.code-workspace new file mode 100644 index 0000000..5194438 --- /dev/null +++ b/NanoBrain-Unity.code-workspace @@ -0,0 +1,12 @@ +{ + "folders": [ + { + "path": "../.." + }, + { + "name": "LinearAlgebra-csharp", + "path": "LinearAlgebra-csharp" + } + ], + "settings": {} +} \ No newline at end of file diff --git a/NanoBrain-Unity.code-workspace.meta b/NanoBrain-Unity.code-workspace.meta new file mode 100644 index 0000000..65bb132 --- /dev/null +++ b/NanoBrain-Unity.code-workspace.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: cfec45da5945b94d684a763d86b0dcf8 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Neuroid.cs b/Neuroid.cs new file mode 100644 index 0000000..d4a64f2 --- /dev/null +++ b/Neuroid.cs @@ -0,0 +1,82 @@ +/* +using UnityEngine; +using Unity.Mathematics; +using static Unity.Mathematics.math; + +[System.Serializable] +public class Neuroid : Neuron { + + public bool average = false; + + public Neuroid(Cluster brain, string name) : base(name) { + this.cluster = brain; + if (this.cluster != null) { + this.cluster.nuclei.Add(this); + } + else + Debug.LogError("No neuroid network"); + } + + public Neuroid(string name) : base(name) { } + + public override INucleus Clone() { + Neuroid clone = new(this.name) { + cluster = this.cluster, + array = this.array, + curve = this.curve, + curvePreset = this.curvePreset, + curveMax = this.curveMax, + average = this.average + }; + if (clone.cluster != null) + clone.cluster.nuclei.Add(clone); + + foreach (Synapse synapse in this.synapses) { + Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); + clonedSynapse.weight = synapse.weight; + } + foreach (INucleus receiver in this.receivers) { + clone.AddReceiver(receiver); + } + return clone; + } + + public override void UpdateState() { + float3 sum = new(0, 0, 0); + int n = 0; + + //Applying the weight factgors + foreach (Synapse synapse in this.synapses) { + sum = sum + (synapse.weight * synapse.nucleus.outputValue); + if (lengthsq(synapse.nucleus.outputValue) != 0) + n++; + } + if (average) + sum /= n; + + // Activation function + Vector3 result; + switch (this.curvePreset) { + case CurvePresets.Linear: + result = sum; + break; + case CurvePresets.Sqrt: + result = normalize(sum) * System.MathF.Sqrt(length(sum)); + break; + case CurvePresets.Power: + result = normalize(sum) * System.MathF.Pow(length(sum), 2); + break; + case CurvePresets.Reciprocal: + result = normalize(sum) * (1 / length(sum)); + break; + default: + float activatedValue = this.curve.Evaluate(length(sum)); + result = normalize(sum) * activatedValue; + break; + } + UpdateResult(result); + } + +} + +*/ \ No newline at end of file diff --git a/Neuroid.cs.meta b/Neuroid.cs.meta new file mode 100644 index 0000000..1c633f0 --- /dev/null +++ b/Neuroid.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 771f64aec709af240a39b1d918bbc829 \ No newline at end of file diff --git a/Neuron.cs b/Neuron.cs new file mode 100644 index 0000000..099ceab --- /dev/null +++ b/Neuron.cs @@ -0,0 +1,321 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEditor; +using Unity.Mathematics; +using static Unity.Mathematics.math; + +[Serializable] +public class Neuron : INucleus { + + [SerializeField] + protected string _name; + public virtual string name { + get => _name; + set => _name = value; + } + + [SerializeField] + private List _synapses = new(); + public List synapses => _synapses; + + [SerializeReference] + private List _receivers = new(); + public List receivers { + get { return _receivers; } + set { _receivers = value; } + } + + [SerializeReference] + private NucleusArray _array; + public NucleusArray array { + get { return _array; } + set { _array = value; } + } + + #region Serialization + + public enum CurvePresets { + Linear, + Power, + Sqrt, + Reciprocal, + Custom + } + [SerializeField] + private CurvePresets _curvePreset; + public CurvePresets curvePreset { + get { return _curvePreset; } + set { + _curvePreset = value; + this.curve = GenerateCurve(); + } + } + public AnimationCurve curve; + public float curveMax = 1.0f; + + #region Parameters + + public bool average = false; + + #endregion Parameters + + public AnimationCurve GenerateCurve() { + switch (this.curvePreset) { + case CurvePresets.Linear: + this.curveMax = 1; + return Presets.Linear(1); + case CurvePresets.Power: + this.curveMax = 1; + return Presets.Power(2.0f, 1); + case CurvePresets.Sqrt: + this.curveMax = 1; + return Presets.Power(0.5f, 1); + case CurvePresets.Reciprocal: + this.curveMax = 1 / 0.01f * 1; + return Presets.Reciprocal(1); + default: + this.curveMax = 1; + return this.curve; + } + } + + public virtual void Deserialize(Neuron nucleus) { } + + #endregion Serialization + + #region Runtime state (not serialized) + + public ClusterPrefab cluster { get; set; } + + #region Activation + + public static class Presets { + private const int samples = 32; + public static AnimationCurve Linear(float weight) { + return AnimationCurve.Linear(0f, 0f, 1000f, weight * 1000); + } + public static AnimationCurve Power(float exponent, float weight) { + // build keyframes + Keyframe[] keys = new Keyframe[samples]; + for (int i = 0; i < samples; i++) { + float t = i / (float)(samples - 1); + float v = Mathf.Pow(t, exponent) * weight; + keys[i] = new Keyframe(t, v); + } + + AnimationCurve curve = new(keys); + + // set tangent modes for each key to Auto (smooth). Use Linear if you prefer straight segments. + for (int i = 0; i < curve.length; i++) { + AnimationUtility.SetKeyLeftTangentMode(curve, i, AnimationUtility.TangentMode.Auto); + AnimationUtility.SetKeyRightTangentMode(curve, i, AnimationUtility.TangentMode.Auto); + } + + return curve; + } + public static AnimationCurve Reciprocal(float weight) { + int samples = 128; + float xMin = 0.001f; + float xMax = 1; + var keys = new Keyframe[samples]; + for (int i = 0; i < samples; i++) { + float t = i / (float)(samples - 1); + float x = Mathf.Lerp(xMin, xMax, t); + float y = 1f / x * weight; + keys[i] = new Keyframe(x, y); + } + var curve = new AnimationCurve(keys); + for (int i = 0; i < curve.length; i++) { + AnimationUtility.SetKeyLeftTangentMode(curve, i, AnimationUtility.TangentMode.Linear); + AnimationUtility.SetKeyRightTangentMode(curve, i, AnimationUtility.TangentMode.Linear); + } + return curve; + } + } + + #endregion Activation + + protected float3 _outputValue; + public virtual float3 outputValue { + get { return _outputValue; } + set { + this.stale = 0; + // this._isSleeping = false; + _outputValue = value; + } + } + + [NonSerialized] + private int stale = 1000; + + // private bool _isSleeping = false; + // public bool isSleeping => _isSleeping; + public bool isSleeping => lengthsq(this.outputValue) == 0; + public float lastTime { get; private set; } + + public void UpdateNuclei() { + this.stale++; + // this._isSleeping = this.stale > 2; + // if (isSleeping) + if (this.stale > 2) + _outputValue = Vector3.zero; + } + + #endregion Runtime state + + public Neuron(ClusterPrefab parent, string name) { + this.cluster = parent; + this.name = name; + if (this.cluster != null) { + this.cluster.nuclei.Add(this); + } + // else + // Debug.LogError("No neuroid network"); + } + + // public Neuron(string name) { + // this._name = name; + // } + + public virtual IReceptor CloneTo(ClusterPrefab parent) { + Neuron clone = new(parent, this.name) { + array = this.array, + curve = this.curve, + curvePreset = this.curvePreset, + curveMax = this.curveMax, + average = this.average + }; + // if (clone.cluster != null) + // clone.cluster.nuclei.Add(clone); + + foreach (Synapse synapse in this.synapses) { + Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); + clonedSynapse.weight = synapse.weight; + } + foreach (INucleus receiver in this.receivers) { + clone.AddReceiver(receiver); + } + return clone; + } + public virtual IReceptor Clone() { + Neuron clone = new(this.cluster, this.name) { + array = this.array, + curve = this.curve, + curvePreset = this.curvePreset, + curveMax = this.curveMax, + average = this.average + }; + // if (clone.cluster != null) + // clone.cluster.nuclei.Add(clone); + + foreach (Synapse synapse in this.synapses) { + Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); + clonedSynapse.weight = synapse.weight; + } + foreach (INucleus receiver in this.receivers) { + clone.AddReceiver(receiver); + } + return clone; + } + + public virtual void AddReceiver(INucleus receivingNucleus) { + this._receivers.Add(receivingNucleus); + receivingNucleus.AddSynapse(this); + } + + public void RemoveReceiver(INucleus receiverNucleus) { + this._receivers.RemoveAll(receiver => receiver == receiverNucleus); + receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); + } + + public static void Delete(INucleus nucleus) { + foreach (Synapse synapse in nucleus.synapses) { + if (synapse.nucleus is Neuron synapse_nucleus) { + if (synapse_nucleus._receivers.Count > 1) { + // there is another nucleus feeding into this input nucleus + synapse_nucleus._receivers.RemoveAll(r => r == nucleus); + } + else { + // No other links, delete it. + Neuron.Delete(synapse_nucleus); + } + } + } + foreach (INucleus receiver in nucleus.receivers) { + if (receiver != null && receiver.synapses != null) + receiver.synapses.RemoveAll(s => s.nucleus == nucleus); + } + + if (nucleus.cluster != null) { + nucleus.cluster.nuclei.RemoveAll(n => n == nucleus); + nucleus.cluster.GarbageCollection(); + } + } + + public Synapse AddSynapse(IReceptor sendingNucleus) { + Synapse synapse = new(sendingNucleus); + this.synapses.Add(synapse); + return synapse; + } + + public virtual void UpdateState() { + UpdateState(new float3(0, 0, 0)); + } + + public virtual void UpdateState(float3 inputValue) { + float3 sum = inputValue;//new(0, 0, 0); + int n = 0; + + //Applying the weight factgors + foreach (Synapse synapse in this.synapses) { + if (synapse.nucleus == this) { + float deltaTime = Time.time - this.lastTime; + synapse.weight = deltaTime; + } + sum += synapse.weight * synapse.nucleus.outputValue; + // Perhaps synapses should be removed when the output value goes to 0.... + if (lengthsq(synapse.nucleus.outputValue) != 0) + n++; + } + if (this.average && n > 0) + sum /= n; + + // Activation function + Vector3 result; + switch (this.curvePreset) { + case CurvePresets.Linear: + result = sum; + break; + case CurvePresets.Sqrt: + result = normalize(sum) * System.MathF.Sqrt(length(sum)); + break; + case CurvePresets.Power: + result = normalize(sum) * System.MathF.Pow(length(sum), 2); + break; + case CurvePresets.Reciprocal: + result = normalize(sum) * (1 / length(sum)); + break; + default: + float activatedValue = this.curve.Evaluate(length(sum)); + result = normalize(sum) * activatedValue; + break; + } + UpdateResult(result); + } + + public virtual void UpdateResult(Vector3 result) { + // float d = Vector3.Distance(result, this.outputValue); + // if (d < 0.5f) { + // //Debug.Log($"insignificant update: {d}"); + // return; + // } + + this.outputValue = result; + this.lastTime = Time.time; + foreach (INucleus receiver in this.receivers) + receiver.UpdateState(); + + } +} \ No newline at end of file diff --git a/Neuron.cs.meta b/Neuron.cs.meta new file mode 100644 index 0000000..e520090 --- /dev/null +++ b/Neuron.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 750748f3f0e7d472fbf88ab02987074c \ No newline at end of file diff --git a/NucleusArray.cs b/NucleusArray.cs new file mode 100644 index 0000000..82a3b0e --- /dev/null +++ b/NucleusArray.cs @@ -0,0 +1,67 @@ +using System.Linq; +using System.Collections.Generic; +using UnityEngine; + +[System.Serializable] +public class NucleusArray { + [SerializeReference] + private INucleus[] _nuclei; + private ClusterPrefab[] _clusters; + public IEnumerable nuclei { + get { + // if (_nuclei == null) + // return _clusters; + // else if (_clusters == null) + return _nuclei; + // else + // return _nuclei.Concat(_clusters); + } + } + public string name; + + public NucleusArray(INucleus nucleus) { + this.name = nucleus.name; + this._nuclei = new INucleus[1]; + this._nuclei[0] = nucleus; + this._clusters = new ClusterPrefab[0]; + } + public NucleusArray(ClusterPrefab cluster) { + this.name = cluster.name; + this._nuclei = new INucleus[0]; + this._clusters = new ClusterPrefab[1]; + this._clusters[0] = cluster; + } + + public void AddNucleus() { + if (this._nuclei.Length == 0) { + Debug.LogError("Empty perceptoid array, cannot add"); + return; + } + int newLength = this._nuclei.Length + 1; + INucleus[] newArray = new INucleus[newLength]; + + for (int i = 0; i < this._nuclei.Length; i++) + newArray[i] = this._nuclei[i]; + if (this._nuclei[0] is INucleus nucleus) + newArray[newLength - 1] = (INucleus) nucleus.Clone(); + + this._nuclei = newArray; + } + + public void RemoveNucleus() { + int newLength = this._nuclei.Length - 1; + if (newLength == 0) { + Debug.LogWarning("Perceptoid array cannot be empty"); + return; + } + INucleus[] newPerceptei = new INucleus[newLength]; + for (int i = 0; i < newLength; i++) + newPerceptei[i] = this._nuclei[i]; + // Delete the last perception + Neuron.Delete(this._nuclei[newLength]); + + this._nuclei = newPerceptei; + } + + +} \ No newline at end of file diff --git a/NucleusArray.cs.meta b/NucleusArray.cs.meta new file mode 100644 index 0000000..61e26b7 --- /dev/null +++ b/NucleusArray.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f8cac60bd79854595a8571c042f77998 \ No newline at end of file diff --git a/Perceptoid.cs b/Perceptoid.cs new file mode 100644 index 0000000..447a3d7 --- /dev/null +++ b/Perceptoid.cs @@ -0,0 +1,105 @@ +/* +using UnityEngine; + +[System.Serializable] +public class Perceptoid : Neuroid { + // A neuroid which has no neurons as input + // But receives value from a receptor + + public NanoBrain brain; + public Receptor receptor; + public string baseName; + + public int thingId; + + //[SerializeField] + // Needs serialization!!!! + [SerializeReference] + public PercepteiArray array; + + #region Serialization + + [SerializeField] + public int thingType; + + public override void Rebuild(NanoBrain brain) { + base.Rebuild(brain); + this.receptor = Receptor.GetReceptor(brain, thingType); + this.receptor.perceptei.Add(this); + if (string.IsNullOrEmpty(this.baseName)) + this.baseName = this.name; + } + + public override void Deserialize(Nucleus nucleus) { + base.Deserialize(nucleus); + + if (nucleus is Perceptoid perceptoid) + this.receptor.thingType = perceptoid.thingType; + + // Point all receivers to this perceptoid instead of the default nucleus + foreach (INucleus receiver in nucleus.receivers) { + foreach (Synapse synapse in receiver.synapses) { + if (synapse.nucleus == nucleus) + synapse.nucleus = this; + } + } + // Point all synapses to this perceptoid instead of the default nucleus + // foreach (Synapse synapse in nucleus.synapses) { + // foreach (INucleus r in synapse.nucleus.receivers) { + // if (r == nucleus) + // this.receiver = this; + // } + // } + // Copying disabled for now + // // Copy all the synapses + // this.synapses = nucleus.synapses; + // // Copy all receivers + // this.receivers = nucleus.receivers; + } + + #endregion Serialization + + public Perceptoid(NanoBrain brain, int thingType, string name = "sensor") : base(name) { + this.brain = brain; + this.cluster = brain.cluster; + if (this.cluster != null) { + brain.perceptei.Add(this); + } + else + Debug.LogError("No neuroid network"); + + this.nucleusType = nameof(Perceptoid); + this.name = name; + this.baseName = name; + this.thingType = thingType; + this.receptor = Receptor.GetReceptor(brain, thingType); + this.receptor.perceptei.Add(this); + this.array = new PercepteiArray(this); + } + + public Perceptoid(PercepteiArray array) : base(array.name) { + this.array = array; + Perceptoid source = array.perceptei[0]; + this.brain = source.brain; + this.cluster = source.cluster; + if (this.brain != null) { + this.brain.perceptei.Add(this); + } + else + Debug.LogError("No neuroid network"); + + this.nucleusType = nameof(Perceptoid); + this.name = source.baseName; + this.baseName = source.baseName; + this.thingType = source.thingType; + this.receptor = Receptor.GetReceptor(this.brain, this.thingType); + this.receptor.perceptei.Add(this); + } + + public override void UpdateState() { + Vector3 result = this.receptor.localPosition; + UpdateResult(result); + } + +} +*/ \ No newline at end of file diff --git a/Perceptoid.cs.meta b/Perceptoid.cs.meta new file mode 100644 index 0000000..ebac122 --- /dev/null +++ b/Perceptoid.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 702f634001a21a9d7ae1057c8ce356e9 \ No newline at end of file diff --git a/Receptor.cs b/Receptor.cs new file mode 100644 index 0000000..72ef7df --- /dev/null +++ b/Receptor.cs @@ -0,0 +1,175 @@ +using System.Collections.Generic; +using UnityEngine; +using Unity.Mathematics; +using static Unity.Mathematics.math; + +public class Receptor : IReceptor { + + private ClusterPrefab cluster; + + [SerializeField] + protected string _name; + public virtual string name { + get => _name; + set => _name = value; + } + + public Receptor(ClusterPrefab cluster) { + this.cluster = cluster; + if (cluster != null) + cluster.nuclei.Add(this); + } + + public Receptor(ClusterPrefab cluster, INucleus nucleus) { + this.cluster = cluster; + if (cluster != null) + cluster.nuclei.Add(this); + this.AddReceiver(nucleus); + } + + public static Receptor CreateReceptor(ClusterPrefab cluster, string nucleusName) { + if (cluster == null) + return null; + + Receptor receptor = new(cluster); + foreach (INucleus nucleus in cluster.inputs) { + if (nucleus != null && nucleus.name == nucleusName) { + // Receptor receptor = new(cluster, nucleus); + // return receptor; + receptor.AddReceiver(nucleus); + } + } + if (receptor._receivers.Count == 0) + return null; + else + return receptor; + } + + public virtual IReceptor CloneTo(ClusterPrefab parent) { + Receptor clone = new(parent); + + foreach (INucleus receiver in this.receivers) { + clone.AddReceiver(receiver); + } + + return clone; + } + public virtual IReceptor Clone() { + Receptor clone = new(this.cluster); + + foreach (INucleus receiver in this.receivers) { + clone.AddReceiver(receiver); + } + + return clone; + } + + class Receiver { + public INucleus nucleus; + public int thingId; + public string thingName; + public Receiver(INucleus nucleus, int thingId, string thingName) { + this.nucleus = nucleus; + this.thingId = thingId; + this.thingName = thingName; + } + } + + [SerializeReference] + private List _receivers = new(); + public List receivers { + get { return _receivers; } + set { _receivers = value; } + } + + protected int[] thingIds; // every receiver can handle a thing with this id + + public virtual void AddReceiver(INucleus receivingNucleus) { + this._receivers.Add(receivingNucleus); + receivingNucleus.AddSynapse(this); + } + + public void RemoveReceiver(INucleus receiverNucleus) { + this._receivers.RemoveAll(receiver => receiver == receiverNucleus); + receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); + } + + private int stale = 1000; + + private bool _isSleeping = false; + public bool isSleeping => _isSleeping; + + public Vector3 localPosition { + set { + this.stale = 0; + this._isSleeping = false; + this._outputValue = value; + + } + } + public float distanceResolution = 0.1f; + public float directionResolution = 5; + + private float3 _outputValue; + public float3 outputValue { + get { return this._outputValue; } + set { + this.stale = 0; + this._isSleeping = false; + this._outputValue = value; + } + } + + public virtual void ProcessStimulus(int thingId, Vector3 newLocalPositionVector, string thingName = null) { + this.localPosition = newLocalPositionVector; + + thingIds ??= new int[this._receivers.Count]; + + int receiverIx = 0; + INucleus selectedReceiver = null; + int selectedReceiverIx = 0; + foreach (INucleus receiver in this.receivers) { + if (thingIds[receiverIx] == thingId) { + // We found an existing receiver for this thing + selectedReceiver = receiver; + selectedReceiverIx = receiverIx; + // Do not look any further + break; + } + else if (receiver.isSleeping) { + // A sleeping receiver is not active and can therefore always be used + selectedReceiver = receiver; + selectedReceiverIx = receiverIx; + // Look further because we may find an existing receiver for this thing + } + else if (selectedReceiver == null) { + // If we haven't found a receiver yet, just start by taking the first + selectedReceiver = receiver; + selectedReceiverIx = receiverIx; + } + else if (selectedReceiver.isSleeping == false) { + // If no existing or sleeping receiver is found, we look for + // the receiver with the furthest/least interesting stimulus + if (length(receiver.outputValue) < length(selectedReceiver.outputValue)) { + // Debug.Log($"{selectedReceiver.name}[{selectedReceiverIx}] {length(selectedReceiver.outputValue)}" + + // $" {receiver.name}[{receiverIx}] {length(receiver.outputValue)} "); + selectedReceiver = receiver; + selectedReceiverIx = receiverIx; + } + } + receiverIx++; + } + // Debug.Log($"Receiver {selectedReceiver.name}[{selectedReceiverIx}] for thing {thingId}"); + thingIds[selectedReceiverIx] = thingId; + // if (thingName != null) + // selectedReceiver.nucleus.name = selectedReceiver.nucleus.baseName + " " + thingName; + selectedReceiver.UpdateState(); + } + + public void UpdateNuclei() { + this.stale++; + this._isSleeping = this.stale > 2; + if (isSleeping) + this._outputValue = Vector3.zero; + } +} \ No newline at end of file diff --git a/Receptor.cs.meta b/Receptor.cs.meta new file mode 100644 index 0000000..56793ae --- /dev/null +++ b/Receptor.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: cfb9734aebc3ab85aacf87d26fb92e55 \ No newline at end of file diff --git a/Scene.meta b/Scene.meta new file mode 100644 index 0000000..d71b5e5 --- /dev/null +++ b/Scene.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bfd7dadd61c0891d8a94db0196e61a8a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scene/TestScene.unity b/Scene/TestScene.unity new file mode 100644 index 0000000..401756e --- /dev/null +++ b/Scene/TestScene.unity @@ -0,0 +1,487 @@ +%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: 10 + 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: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 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_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 13 + m_BakeOnSceneLoad: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + 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_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 2 + 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: 1 + m_PVRFilteringGaussRadiusAO: 1 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 20201, guid: 0000000000000000f000000000000000, type: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 3 + 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 + buildHeightMesh: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1001 &551770709 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalPosition.x + value: 0.71 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093763, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_Name + value: Boid2 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} +--- !u!1 &968074744 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 968074747} + - component: {fileID: 968074746} + - component: {fileID: 968074745} + 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 &968074745 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 968074744} + m_Enabled: 1 +--- !u!20 &968074746 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 968074744} + 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_Iso: 200 + m_ShutterSpeed: 0.005 + m_Aperture: 16 + m_FocusDistance: 10 + m_FocalLength: 50 + m_BladeCount: 5 + m_Curvature: {x: 2, y: 11} + m_BarrelClipping: 0.25 + m_Anamorphism: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + 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: 0 + 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 &968074747 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 968074744} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1342149740 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1342149742} + - component: {fileID: 1342149741} + m_Layer: 0 + m_Name: SwamControl + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1342149741 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1342149740} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0464906885ae3494f8fd0314719fb2db, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::SwarmControl + speed: 0.5 + inertia: 0.1 + alignmentForce: 0 + cohesionForce: 1 + separationForce: 1 + avoidanceForce: 5 + separationDistance: 0.5 + perceptionDistance: 1 + spaceSize: {x: 10, y: 10, z: 10} + boundaryWidth: {x: 1, y: 1, z: 1} +--- !u!4 &1342149742 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1342149740} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -1.00377, y: -1.02283, z: 0.72231} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &2011285159 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2011285161} + - component: {fileID: 2011285160} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &2011285160 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2011285159} + m_Enabled: 1 + serializedVersion: 12 + m_Type: 1 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize2D: {x: 0.5, y: 0.5} + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ForceVisible: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 + m_LightUnit: 1 + m_LuxAtDistance: 1 + m_EnableSpotReflector: 1 +--- !u!4 &2011285161 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2011285159} + serializedVersion: 2 + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1001 &4573752827112804207 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7761516481062093763, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} + propertyPath: m_Name + value: Boid1 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} +--- !u!1660057539 &9223372036854775807 +SceneRoots: + m_ObjectHideFlags: 0 + m_Roots: + - {fileID: 968074747} + - {fileID: 2011285161} + - {fileID: 4573752827112804207} + - {fileID: 551770709} + - {fileID: 1342149742} diff --git a/Scene/TestScene.unity.meta b/Scene/TestScene.unity.meta new file mode 100644 index 0000000..676153c --- /dev/null +++ b/Scene/TestScene.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 1070383882ed0f5379a3b34e8ccb1f75 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Synapse.cs b/Synapse.cs new file mode 100644 index 0000000..e7c8116 --- /dev/null +++ b/Synapse.cs @@ -0,0 +1,22 @@ +using System; +using UnityEngine; + +[Serializable] +public class Synapse { + // Support access to cluster of basic nucleus + //public IReceptor nucleus => basicNucleus; + + + //[SerializeReference] + //public Cluster cluster; + + [SerializeReference] + public IReceptor nucleus; + + public float weight; + + public Synapse(IReceptor nucleus, float weight = 1.0f) { + this.nucleus = nucleus; + this.weight = weight; + } +} \ No newline at end of file diff --git a/Synapse.cs.meta b/Synapse.cs.meta new file mode 100644 index 0000000..e62612c --- /dev/null +++ b/Synapse.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 334a58eafccd60cbdb32f719e9e861c6 \ No newline at end of file diff --git a/Velocity.asset b/Velocity.asset new file mode 100644 index 0000000..521ba9b --- /dev/null +++ b/Velocity.asset @@ -0,0 +1,108 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3} + m_Name: Velocity + m_EditorClassIdentifier: Assembly-CSharp::Cluster + nuclei: + - rid: 2243601403683012671 + - rid: 2243601403683012676 + references: + version: 2 + RefIds: + - rid: -2 + type: {class: , ns: , asm: } + - rid: 2243601403683012671 + type: {class: Neuron, ns: , asm: Assembly-CSharp} + data: + _name: Output + _synapses: + - nucleus: + rid: -2 + weight: 1 + _receivers: [] + _array: + rid: 2243601403683012672 + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1000 + value: 1000 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + - rid: 2243601403683012672 + type: {class: NucleusArray, ns: , asm: Assembly-CSharp} + data: + _nuclei: + - rid: 2243601403683012671 + name: Output + - rid: 2243601403683012676 + type: {class: Neuron, ns: , asm: Assembly-CSharp} + data: + _name: Position + _synapses: [] + _receivers: + - rid: 2243601403683012671 + _array: + rid: 2243601403683012677 + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1000 + value: 1000 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + - rid: 2243601403683012677 + type: {class: NucleusArray, ns: , asm: Assembly-CSharp} + data: + _nuclei: + - rid: 2243601403683012676 + name: New neuron diff --git a/Velocity.asset.meta b/Velocity.asset.meta new file mode 100644 index 0000000..07ecb98 --- /dev/null +++ b/Velocity.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dd622ac7ed09e70ea8edac595047ac82 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualEditor.meta b/VisualEditor.meta new file mode 100644 index 0000000..d012778 --- /dev/null +++ b/VisualEditor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 62a58c801eda0c9eab7a49fb1d0840cb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualEditor/Editor.meta b/VisualEditor/Editor.meta new file mode 100644 index 0000000..c068f8e --- /dev/null +++ b/VisualEditor/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e47ea55fc051fcdcb8ae6197d1105cc0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualEditor/Editor/BrainPickerWindow.cs b/VisualEditor/Editor/BrainPickerWindow.cs new file mode 100644 index 0000000..3a536df --- /dev/null +++ b/VisualEditor/Editor/BrainPickerWindow.cs @@ -0,0 +1,66 @@ +using UnityEditor; +using UnityEngine; +using System; +using System.Linq; + +public class BrainPickerWindow : EditorWindow { + private Vector2 scroll; + private ClusterPrefab[] items = new ClusterPrefab[0]; + private Action onPicked; + private string search = ""; + + public static void ShowPicker(Action onPicked, string title = "Select Cluster") { + var w = CreateInstance(); + w.titleContent = new GUIContent(title); + w.minSize = new Vector2(360, 320); + w.onPicked = onPicked; + w.RefreshList(); + w.ShowModalUtility(); // modal dialog + } + + private void OnEnable() => RefreshList(); + + private void RefreshList() { + var guids = AssetDatabase.FindAssets("t:Cluster"); + items = guids + .Select(g => AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(g))) + .Where(b => b != null) + .OrderBy(b => b.name) + .ToArray(); + } + + private void OnGUI() { + EditorGUILayout.Space(); + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Choose Cluster:", EditorStyles.boldLabel); + if (GUILayout.Button("Refresh", GUILayout.Width(80))) RefreshList(); + GUILayout.FlexibleSpace(); + EditorGUILayout.EndHorizontal(); + + EditorGUILayout.Space(); + search = EditorGUILayout.TextField(search); + + EditorGUILayout.Space(); + scroll = EditorGUILayout.BeginScrollView(scroll); + foreach (var it in items) { + if (!string.IsNullOrEmpty(search) && it.name.IndexOf(search, StringComparison.OrdinalIgnoreCase) < 0) + continue; + + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField(EditorGUIUtility.ObjectContent(it, typeof(ClusterPrefab)), GUILayout.Height(20)); + if (GUILayout.Button("Select", GUILayout.Width(70))) { + onPicked?.Invoke(it); + Close(); + return; + } + EditorGUILayout.EndHorizontal(); + } + EditorGUILayout.EndScrollView(); + + EditorGUILayout.Space(); + EditorGUILayout.BeginHorizontal(); + if (GUILayout.Button("Cancel")) { onPicked?.Invoke(null); Close(); } + GUILayout.FlexibleSpace(); + EditorGUILayout.EndHorizontal(); + } +} diff --git a/VisualEditor/Editor/BrainPickerWindow.cs.meta b/VisualEditor/Editor/BrainPickerWindow.cs.meta new file mode 100644 index 0000000..b2de114 --- /dev/null +++ b/VisualEditor/Editor/BrainPickerWindow.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 9197e2d322d23b5798ab4aef729815b0 \ No newline at end of file diff --git a/VisualEditor/Editor/ClusterInspector.cs b/VisualEditor/Editor/ClusterInspector.cs new file mode 100644 index 0000000..94273dd --- /dev/null +++ b/VisualEditor/Editor/ClusterInspector.cs @@ -0,0 +1,728 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEditor; + +using UnityEngine; +using UnityEngine.UIElements; +using Unity.Mathematics; +using static Unity.Mathematics.math; + +[CustomEditor(typeof(ClusterPrefab))] +public class ClusterInspector : Editor { + protected static VisualElement mainContainer; + protected static VisualElement inspectorContainer; + + protected bool breakOnWake = false; + + #region Start + + public override VisualElement CreateInspectorGUI() { + ClusterPrefab cluster = target as ClusterPrefab; + + serializedObject.Update(); + + VisualElement root = new(); + //root.style.flexDirection = FlexDirection.Row; // side-by-side layout + //root.style.flexGrow = 1; + //root.style.minHeight = 600; + root.style.paddingLeft = 0; + root.style.paddingRight = 0; + root.style.paddingTop = 0; + root.style.paddingBottom = 0; + + root.styleSheets.Add(Resources.Load("GraphStyles")); + + mainContainer = new() { + // name = "main", + style = { + // flexDirection = FlexDirection.Row, + // flexGrow = 1, + height = 450, + } + }; + GraphView graph = new(); + graph.style.flexGrow = 1; + + inspectorContainer = new VisualElement { + // name = "inspector" + }; + + mainContainer.Add(graph); + mainContainer.Add(inspectorContainer); + root.Add(mainContainer); + + // Run once for initial state (use resolved style width if available) + float initialWidth = root.layout.width > 0 ? root.layout.width : root.contentRect.width; + UpdateLayout(initialWidth); + + // React to size changes of root (or parent if appropriate) + root.RegisterCallback(evt => { + UpdateLayout(evt.newRect.width); + }); + + if (cluster != null) { + cluster.EnsureInitialization(); + graph.SetGraph(null, cluster, cluster.output, inspectorContainer); + } + else + Debug.LogWarning(" No brain!"); + + serializedObject.ApplyModifiedProperties(); + return root; + } + + public class GraphView : VisualElement { + ClusterPrefab cluster; + SerializedObject serializedBrain; + INucleus currentNucleus; + GameObject gameObject; + private List layers = new(); + private readonly Dictionary neuroidPositions = new(); + private bool expandArray = false; + + //Vector2 pan = Vector2.zero; + //float zoom = 1f; + //bool draggingCanvas = false; + //Vector2 lastMouse; + ClusterWrapper currentWrapper; + + public GraphView() { + name = "content"; + style.flexGrow = 1; + + IMGUIContainer imguiContainer = new(OnIMGUI); + imguiContainer.style.position = Position.Absolute; + imguiContainer.style.left = 0; imguiContainer.style.top = 0; + imguiContainer.style.right = 0; imguiContainer.style.bottom = 0; + imguiContainer.pickingMode = PickingMode.Position; + imguiContainer.focusable = true; + Add(imguiContainer); + + //RegisterCallback(OnWheel); + // RegisterCallback(OnMouseDown); + // RegisterCallback(OnMouseMove); + // RegisterCallback(OnMouseUp); + + // Subscribe when added to panel (editor UI ready) + RegisterCallback(evt => Subscribe()); + RegisterCallback(evt => Unsubscribe()); + } + + + bool subscribed = false; + void Subscribe() { + if (subscribed) return; + SceneView.duringSceneGui += OnSceneGUI; + subscribed = true; + SceneView.RepaintAll(); + } + + void Unsubscribe() { + if (!subscribed) return; + SceneView.duringSceneGui -= OnSceneGUI; + subscribed = false; + } + + public void SetGraph(GameObject gameObject, ClusterPrefab brain, INucleus nucleus, VisualElement inspectorContainer) { + this.gameObject = gameObject; + this.cluster = brain; + if (Application.isPlaying == false) + this.serializedBrain = new SerializedObject(brain); + this.currentNucleus = nucleus; + Rebuild(inspectorContainer); + } + + void Rebuild(VisualElement inspectorContainer) { + BuildLayers(); + + if (this.currentNucleus == null) { + inspectorContainer.Clear(); + return; + } + + if (currentWrapper != null) + DestroyImmediate(currentWrapper); + currentWrapper = CreateInstance().Init(this.currentNucleus, cluster); + DrawInspector(inspectorContainer); + } + + private void BuildLayers() { + // A temporary list to track what's been added to layers + this.layers = new(); + int layerIx = 0; + + INucleus selectedNucleus = this.currentNucleus; + if (selectedNucleus == null) + return; + NeuroidLayer currentLayer = new() { ix = layerIx }; + + if (selectedNucleus.receivers != null) { + foreach (INucleus receiver in selectedNucleus.receivers) { + INucleus outputNeuroid = receiver; + if (outputNeuroid != null) { + AddToLayer(currentLayer, outputNeuroid); + // Debug.Log($"layer {layerIx} nucleus {outputNeuroid.name}"); + } + } + } + if (currentLayer.neuroids.Count > 0) { + this.layers.Add(currentLayer); + layerIx++; + currentLayer = new() { ix = layerIx }; + } + + AddToLayer(currentLayer, selectedNucleus); + this.layers.Add(currentLayer); + // Debug.Log($"layer {layerIx} nucleus {selectedNucleus.name}"); + + layerIx++; + currentLayer = new() { ix = layerIx }; + + if (selectedNucleus.synapses != null) { + foreach (Synapse synapse in selectedNucleus.synapses) { + IReceptor input = synapse.nucleus; + AddToLayer(currentLayer, input); + // Debug.Log($"layer {layerIx} nucleus {input.name}"); + } + } + if (currentLayer.neuroids.Count > 0) { + this.layers.Add(currentLayer); + } + } + + private void AddToLayer(NeuroidLayer layer, IReceptor nucleus) { + if (nucleus == null) + return; + layer.neuroids.Add(nucleus); + //nucleus.layerIx = layer.ix; + // Store its position + Vector2Int neuroidPosition = new(layer.ix, layer.neuroids.Count - 1); + neuroidPositions[nucleus] = neuroidPosition; + + } + + + public void OnIMGUI() { + if (currentNucleus == null) + return; + + if (Application.isPlaying == false) + serializedBrain.Update(); + + Handles.BeginGUI(); + DrawGraph(); + Handles.EndGUI(); + + } + + private void DrawGraph() { + float size = 20; + Vector3 position = new(150, 210, 0); + + DrawReceivers(this.currentNucleus, position, size); + DrawSynapses(this.currentNucleus, position, size); + + // Draw selected Nucleus + if (expandArray) { + float maxValue = 0; + foreach (INucleus nucleus in this.currentNucleus.array.nuclei) { + float value = length(nucleus.outputValue); + if (value > maxValue) + maxValue = value; + } + + float spacing = 400f / this.currentNucleus.array.nuclei.Count(); + float margin = 10 + spacing / 2; + float xMin = 150 - size; + float xMax = 150 + size; + float yMin = 10 + margin - size / 2; + float yMax = 400 - margin + size; + Vector3[] verts = new Vector3[4] { + new(xMin, yMin, 0), + new(xMax, yMin, 0), + new(xMax, yMax, 0), + new(xMin, yMax, 0) + }; + Handles.color = Color.black; + Handles.DrawAAConvexPolygon(verts); + int row = 0; + foreach (INucleus nucleus in this.currentNucleus.array.nuclei) { + Vector3 pos = new(150, margin + row * spacing, 0.0f); + Handles.color = Color.white; + //Handles.DrawLine(parentPos, pos); + + Handles.color = Color.white; + Handles.DrawSolidDisc(pos, Vector3.forward, size + 2); + DrawNucleus(nucleus, pos, maxValue, size); + row++; + } + GUIStyle style = new(EditorStyles.label) { + alignment = TextAnchor.UpperCenter, + normal = { textColor = Color.white }, + fontStyle = FontStyle.Bold, + }; + Vector3 labelPos = new Vector3(150, yMax, 0) - Vector3.down * (size + 10); // below disc along up axis + Handles.Label(labelPos, this.currentNucleus.name, style); + } + else { + Handles.color = Color.white; + Handles.DrawSolidDisc(position, Vector3.forward, size + 2); + DrawNucleus(this.currentNucleus, position, length(this.currentNucleus.outputValue), 20); + } + } + + private void DrawReceivers(INucleus nucleus, Vector3 parentPos, float size) { + int nodeCount = nucleus.receivers.Count(); + + // Determine the maximum value in this layer + // This is used to 'scale' the output value colors of the nuclei + float maxValue = 0; + foreach (INucleus receiver in nucleus.receivers) { + if (receiver is Neuron neuroid) { + float value = length(neuroid.outputValue); + if (value > maxValue) + maxValue = value; + } + } + + // Determine the spacing of the nuclei in the layer + float spacing = 400f / nodeCount; + float margin = 10 + spacing / 2; + + int row = 0; + foreach (INucleus receiver in nucleus.receivers) { + INucleus receiverNucleus = receiver; + if (receiverNucleus == null) + continue; + + Vector3 pos = new(50, margin + row * spacing, 0.0f); + Handles.color = Color.white; + Handles.DrawLine(parentPos, pos); + + DrawNucleus(receiverNucleus, pos, maxValue, size); + row++; + } + } + + private void DrawSynapses(INucleus nucleus, Vector3 parentPos, float size) { + int nodeCount = nucleus.synapses.Count; + + // Determine the maximum value in this layer + // This is used to 'scale' the output value colors of the nuclei + float maxValue = 0; + int neuronCount = 0; + List drawnArrays = new(); + foreach (Synapse synapse in nucleus.synapses) { + if (synapse.nucleus is Neuron neuroid) { + if (drawnArrays.Contains(neuroid.array)) + continue; + drawnArrays.Add(neuroid.array); + + } + float value = length(synapse.nucleus.outputValue) * synapse.weight; + // Debug.Log($"{synapse.nucleus.name}: {value} {length(synapse.nucleus.outputValue)} {synapse.weight}"); + if (value > maxValue) + maxValue = value; + neuronCount++; + } + + // Determine the spacing of the nuclei in the layer + float spacing = 400f / neuronCount; + float margin = 10 + spacing / 2; + + int row = 0; + drawnArrays = new(); + foreach (Synapse synapse in nucleus.synapses) { + if (synapse.nucleus is Neuron neuron) { + if (drawnArrays.Contains(neuron.array)) + continue; + drawnArrays.Add(neuron.array); + } + Vector3 pos = new(250, margin + row * spacing, 0.0f); + Handles.color = Color.white; + Handles.DrawLine(parentPos, pos); + if (synapse.nucleus != null) { + Color color = Color.black; + if (synapse.nucleus.isSleeping) + color = Color.darkRed; + else if (Application.isPlaying) { + float brightness = length(synapse.nucleus.outputValue) * synapse.weight / maxValue; + color = new Color(brightness, brightness, brightness, 1f); + } + DrawNucleus(synapse.nucleus, pos, maxValue, size, color); + } + row++; + } + } + + private void DrawNucleus(IReceptor nucleus, Vector3 position, float maxValue, float size) { + Color color; + if (nucleus.isSleeping) + color = Color.darkRed; + else { + if (Application.isPlaying) { + float brightness = length(nucleus.outputValue) / maxValue; + color = new Color(brightness, brightness, brightness, 1f); + } + else + color = Color.black; + } + DrawNucleus(nucleus, position, maxValue, size, color); + } + + private void DrawNucleus(IReceptor nucleus, Vector3 position, float maxValue, float size, Color color) { + if (nucleus is MemoryCell memory) { + Handles.color = Color.white; + Handles.DrawWireDisc(position + Vector3.right * 10, Vector3.forward, size); + } + + Handles.color = color; + Handles.DrawSolidDisc(position, Vector3.forward, size); + + Handles.color = Color.white; + // Position the label in front of the disc + Vector3 labelPosition = position + (Vector3.forward * 0.1f); + + GUIStyle style = new(EditorStyles.label) { + alignment = TextAnchor.MiddleCenter, + normal = { textColor = Color.white }, + fontStyle = FontStyle.Bold, + }; + if (nucleus is INucleus neuron) { + if (neuron.array == null || neuron.array.nuclei == null || neuron.array.nuclei.Count() == 0) + neuron.array = new NucleusArray(neuron); + + if ((!expandArray || neuron.array.nuclei.First() != this.currentNucleus) && neuron.array.nuclei.Count() > 1) { + Handles.Label(labelPosition, neuron.array.nuclei.Count().ToString(), style); + } + if (expandArray && neuron.array.nuclei.First() == this.currentNucleus) { + int arrayIx = 0; + foreach (INucleus n in neuron.array.nuclei) { + if (n == neuron) + break; + arrayIx++; + } + Handles.Label(labelPosition, $"[{arrayIx}]", style); + } + else { + style.alignment = TextAnchor.UpperCenter; + Vector3 labelPos = position - Vector3.down * (size + 10f); // below disc along up axis + Handles.Label(labelPos, nucleus.name, style); + } + + if (nucleus is Cluster cluster) { + Handles.color = Color.white; + Handles.DrawWireDisc(position, Vector3.forward, size + 10); + } + } + else { + style.alignment = TextAnchor.UpperCenter; + Vector3 labelPos = position - Vector3.down * (size + 10); // below disc along up axis + Handles.Label(labelPos, nucleus.name, style); + } + + Rect neuronRect = new(position.x - size, position.y - size, size * 2, size * 2); + int id = GUIUtility.GetControlID(FocusType.Passive); + Event e = Event.current; + EventType et = e.GetTypeForControl(id); + if (e != null && neuronRect.Contains(e.mousePosition)) { + // Process Hover + HandleMouseHover(nucleus, neuronRect); + // Process click + if (e.type == EventType.MouseDown && e.button == 0) { + // Consume the event so the scene doesn't also handle it + e.Use(); + HandleClicked(nucleus); + } + } + } + + private void HandleMouseHover(IReceptor nucleus, Rect rect) { + GUIContent tooltip; + if (nucleus is INucleus n) { + tooltip = new( + $"{nucleus.name}" + + $"\nsynapse count {n.synapses.Count}" + + $"\nValue: {nucleus.outputValue}"); + } + else { + tooltip = new( + $"{nucleus.name}" + + $"\nValue: {nucleus.outputValue}"); + } + + Vector2 mousePosition = Event.current.mousePosition; + + // Display tooltip with some offset + Vector2 tooltipSize = GUI.skin.box.CalcSize(tooltip); + Rect tooltipRect = new Rect(mousePosition.x + 10, mousePosition.y + 10, tooltipSize.x, tooltipSize.y); + + GUI.Box(tooltipRect, tooltip); + } + + private void HandleClicked(IReceptor nucleus) { + if (nucleus == this.currentNucleus) { + if (nucleus is INucleus n) { + expandArray = !expandArray; + return; + } + } + else if (nucleus is INucleus n) { + this.currentNucleus = n; + BuildLayers(); + } + } + + void DrawInspector(VisualElement inspectorContainer) { + if (inspectorContainer == null) + return; + + inspectorContainer.Clear(); + if (this.currentNucleus == null) + return; + + // create a SerializedObject wrapper so Unity inspector controls work (and Undo) + SerializedObject so = new(currentWrapper); + IMGUIContainer container = new(() => { + if (so.targetObject == null) + return; + so.Update(); + + if (this.currentNucleus == null) + return; + + this.currentNucleus.name = EditorGUILayout.TextField(this.currentNucleus.name); + if (this.currentNucleus is Neuron neuroid) { + if (this.currentNucleus is MemoryCell memory) { + } + else { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Activation Curve", GUILayout.Width(150)); + if (neuroid.curveMax > 0) + EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, 0, 1, neuroid.curveMax)); + else + EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, neuroid.curveMax, 1, -neuroid.curveMax)); + neuroid.curvePreset = (Neuron.CurvePresets)EditorGUILayout.EnumPopup(neuroid.curvePreset, GUILayout.Width(100)); + EditorGUILayout.EndHorizontal(); + } + + if (neuroid.array == null || neuroid.array.nuclei == null || neuroid.array.nuclei.Count() == 0) + neuroid.array = new NucleusArray(neuroid); + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.IntField("Array size", neuroid.array.nuclei.Count()); + if (GUILayout.Button("Add")) + neuroid.array.AddNucleus(); + if (GUILayout.Button("Del")) + neuroid.array.RemoveNucleus(); + EditorGUILayout.EndHorizontal(); + } + + if (Application.isPlaying) + EditorGUILayout.FloatField("Output", length(this.currentNucleus.outputValue)); + else + EditorGUILayout.LabelField(" "); + + if (this.currentNucleus.synapses.Count > 0) { + EditorGUILayout.LabelField("Synapses"); + Synapse[] synapses = this.currentNucleus.synapses.ToArray(); + foreach (Synapse synapse in synapses) { + if (synapse.nucleus != null) { + EditorGUILayout.Space(); + + //EditorGUI.BeginDisabledGroup(synapse.nucleus.isSleeping); + if (Application.isPlaying) + EditorGUILayout.FloatField(synapse.nucleus.name, length(synapse.nucleus.outputValue) * synapse.weight); + else { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField(synapse.nucleus.name); + if (GUILayout.Button("Disconnect")) + synapse.nucleus.RemoveReceiver(this.currentNucleus); + EditorGUILayout.EndHorizontal(); + } + + EditorGUI.indentLevel++; + synapse.weight = EditorGUILayout.FloatField("Weight", synapse.weight); + EditorGUI.indentLevel--; + //EditorGUI.EndDisabledGroup(); + } + } + } + + EditorGUILayout.Space(); + + ConnectNucleus(this.cluster, this.currentNucleus); + if (GUILayout.Button("Add Input Neuron")) + AddInputNeuron(this.currentNucleus); + if (GUILayout.Button("Add Input MemoryCell")) + AddInputMemoryCell(this.currentNucleus); + if (GUILayout.Button("Add Input Cluster")) + AddCluster(this.currentNucleus); + + EditorGUILayout.Space(); + + if (GUILayout.Button("Delete this neuron")) + DeleteNeuron(this.currentNucleus); + + if (this.currentNucleus is Cluster subCluster) { + if (GUILayout.Button("Edit Cluster")) + EditCluster(subCluster); + } + + // if (this.gameObject != null) { + // Vector3 worldVector = this.gameObject.transform.TransformVector(this.currentNucleus.outputValue); + // //Debug.DrawRay(this.gameObject.transform.position, worldVector, Color.yellow); + // Handles.color = Color.yellow; + // Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); + // } + }); + + inspectorContainer.Add(container); + } + + void OnSceneGUI(SceneView sceneView) { + if (this.gameObject != null) { + Vector3 worldVector = this.gameObject.transform.TransformVector(this.currentNucleus.outputValue); + Handles.color = Color.yellow; + Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); + } + } + + protected virtual void AddInputNeuron(INucleus nucleus) { + Neuron newNeuroid = new(this.cluster, "New neuron"); + newNeuroid.AddReceiver(nucleus); + this.currentNucleus = newNeuroid; + BuildLayers(); + } + + protected virtual void DeleteNeuron(INucleus nucleus) { + if (nucleus == null) + return; + if (nucleus.cluster != null) + this.currentNucleus = nucleus.cluster.output; + foreach (INucleus receiver in nucleus.receivers) { + if (receiver != null) { + this.currentNucleus = receiver; + break; + } + } + Neuron.Delete(nucleus); + BuildLayers(); + } + + protected virtual void AddInputMemoryCell(INucleus nucleus) { + MemoryCell newMemory = new(this.cluster, "New memory cell"); + newMemory.AddReceiver(nucleus); + this.currentNucleus = newMemory; + BuildLayers(); + } + + protected virtual void AddCluster(INucleus nucleus) { + BrainPickerWindow.ShowPicker(brain => OnClusterPicked(nucleus, brain), "Select Cluster"); + } + + private void OnClusterPicked(INucleus nucleus, ClusterPrefab subCluster) { + Cluster subclusterInstance = new(this.cluster, subCluster); + //this.cluster.AddSubCluster(subclusterInstance); + //this.cluster.nuclei.Add(subclusterInstance); + subclusterInstance.AddReceiver(nucleus); + } + + private void EditCluster(Cluster subCluster) { + //var currentActiveObject = Selection.activeObject; + Selection.activeObject = subCluster.prefab; + EditorGUIUtility.PingObject(subCluster.prefab); + var editor = Editor.CreateEditor(subCluster.prefab); + //Selection.activeObject = currentActiveObject; + } + + // Connect to another nucleus in the same cluster + protected virtual void ConnectNucleus(ClusterPrefab cluster, INucleus nucleus) { + if (cluster == null) + return; + + IEnumerable synapseNuclei = this.currentNucleus.synapses.Select(synapse => synapse.nucleus != null ? synapse.nucleus.name : ""); + //IEnumerable perceptei = this.currentNucleus.brain.perceptei.Select(i => i.name).Except(synapseNuclei); + IEnumerable nuclei = cluster.nuclei.Select(i => i.name).Except(synapseNuclei); + //string[] names = perceptei.Concat(nuclei).ToArray(); + string[] names = nuclei.ToArray(); + int selectedIndex = -1; + selectedIndex = EditorGUILayout.Popup("Connect to", selectedIndex, names); + if (selectedIndex >= 0) { + // if (selectedIndex < perceptei.Count()) { + // Nucleus n = this.currentNucleus.brain.perceptei[selectedIndex]; + // n.AddReceiver(this.currentNucleus); + // } + // else { + // Nucleus n = this.currentNucleus.brain.nuclei[selectedIndex - perceptei.Count()]; + // n.AddReceiver(this.currentNucleus); + // } + IReceptor receptor = cluster.nuclei[selectedIndex]; + receptor.AddReceiver(this.currentNucleus); + } + } + + protected virtual void DisconnectNucleus(Neuron nucleus) { + if (this.currentNucleus.cluster == null) + return; + string[] names = this.currentNucleus.synapses.Select(synapse => synapse.nucleus.name).ToArray(); + int selectedIndex = -1; + selectedIndex = EditorGUILayout.Popup("Disconnect from", selectedIndex, names); + //if (selectedIndex >= 0 && selectedIndex < this.currentNucleus.brain.perceptei.Count) { + if (selectedIndex >= 0 && selectedIndex < this.currentNucleus.cluster.nuclei.Count) { + Synapse synapse = this.currentNucleus.synapses[selectedIndex]; + synapse.nucleus.RemoveReceiver(this.currentNucleus); + } + } + } + + #endregion Start + + #region Update + + private void UpdateLayout(float containerWidth) { + if (containerWidth > 600f) { + mainContainer.style.flexDirection = FlexDirection.Row; + inspectorContainer.style.width = 300; // fixed sidebar width + inspectorContainer.style.flexGrow = 0; + } + else { + mainContainer.style.flexDirection = FlexDirection.Column; + inspectorContainer.style.width = Length.Percent(100); // full width below + inspectorContainer.style.flexDirection = FlexDirection.Column; + inspectorContainer.style.flexGrow = 1; // can set 0 or keep as needed + } + } + + #endregion Update +} + +public class NeuroidLayer { + public int ix = 0; + public List neuroids = new(); +} + +public class ClusterWrapper : ScriptableObject { + // expose fields that map to GraphNode + //public string title; + public Vector2 position; + INucleus node; + ClusterPrefab graph; // needed to write back and mark dirty + + public ClusterWrapper Init(INucleus node, ClusterPrefab graphAsset) { + this.node = node; + this.graph = graphAsset; + //this.title = " A " + node.name; + //position = node.position; + return this; + } + void OnValidate() { + if (node != null) { + //node.name = title; + //node.position = position; +#if UNITY_EDITOR + if (graph != null) + UnityEditor.EditorUtility.SetDirty(graph); +#endif + } + } +} \ No newline at end of file diff --git a/VisualEditor/Editor/ClusterInspector.cs.meta b/VisualEditor/Editor/ClusterInspector.cs.meta new file mode 100644 index 0000000..a1a18f5 --- /dev/null +++ b/VisualEditor/Editor/ClusterInspector.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 1fc1fb7db9f7ad54a87d31313e7f457d \ No newline at end of file diff --git a/VisualEditor/Editor/NanoBrainComponent_Editor.cs b/VisualEditor/Editor/NanoBrainComponent_Editor.cs new file mode 100644 index 0000000..253993a --- /dev/null +++ b/VisualEditor/Editor/NanoBrainComponent_Editor.cs @@ -0,0 +1,129 @@ +using UnityEditor; +using UnityEditor.UIElements; +using UnityEngine; +using UnityEngine.UIElements; + +[CustomEditor(typeof(NanoBrainComponent))] +public class NanoBrainComponent_Editor : Editor { + protected static VisualElement mainContainer; + protected static VisualElement inspectorContainer; + + protected NanoBrainComponent component; + private SerializedProperty brainProp; + + ClusterInspector.GraphView board; + + public void OnEnable() { + component = target as NanoBrainComponent; + + if (Application.isPlaying == false) + brainProp = serializedObject.FindProperty(nameof(NanoBrainComponent.defaultBrain)); + + } + + public override VisualElement CreateInspectorGUI() { + //NanoBrainComponent component = target as NanoBrainComponent; + ClusterPrefab brain = Application.isPlaying ? component.brain : component.defaultBrain; + + if (Application.isPlaying == false) + serializedObject.Update(); + + + VisualElement root = new(); + root.style.flexDirection = FlexDirection.Column; // side-by-side layout + root.style.flexGrow = 1; + root.style.minHeight = 600; + root.style.paddingLeft = 0; + root.style.paddingRight = 0; + root.style.paddingTop = 0; + root.style.paddingBottom = 0; + + root.styleSheets.Add(Resources.Load("GraphStyles")); + + if (Application.isPlaying == false) { + PropertyField brainField = new(brainProp) { + label = "Nano Brain" + }; + root.Add(brainField); + } + + mainContainer = new() { + name = "main", + style = { + flexDirection = FlexDirection.Row, + flexGrow = 1, + minHeight = 500, + } + }; + board = new ClusterInspector.GraphView(); + board.style.flexGrow = 1; + mainContainer.Add(board); + + inspectorContainer = new VisualElement { + name = "inspector", + style = { + width = 400, + } + }; + + mainContainer.Add(inspectorContainer); + root.Add(mainContainer); + + // Run once for initial state (use resolved style width if available) + float initialWidth = root.layout.width > 0 ? root.layout.width : root.contentRect.width; + UpdateLayout(initialWidth); + + // React to size changes of root (or parent if appropriate) + root.RegisterCallback(evt => { + UpdateLayout(evt.newRect.width); + }); + + if (brain != null && board != null) + board.SetGraph(component.gameObject, brain, brain.output, inspectorContainer); + // else + // Debug.LogWarning(" No brain!"); + + if (Application.isPlaying == false) + serializedObject.ApplyModifiedProperties(); + return root; + } + + // void OnSceneGUI() { + // if (Application.isPlaying && board != null) + // board.OnIMGUI(); + // } + + void OnSceneGui(SceneView sv) { + if (Application.isPlaying == false) + return; + // May need some throttling here... + if (board != null) { + Debug.Log("."); + board.OnIMGUI(); + } + + // EditorApplication.delayCall = UpdateInspectorUI; + } + + void UpdateInspectorUI() { + if (board != null) { + Debug.Log("."); + board.OnIMGUI(); + } + } + + private void UpdateLayout(float containerWidth) { + if (containerWidth > 800f) { + mainContainer.style.flexDirection = FlexDirection.Row; + inspectorContainer.style.width = 400; // fixed sidebar width + inspectorContainer.style.flexGrow = 0; + } + else { + mainContainer.style.flexDirection = FlexDirection.Column; + inspectorContainer.style.width = Length.Percent(100); // full width below + inspectorContainer.style.flexDirection = FlexDirection.Column; + inspectorContainer.style.flexGrow = 1; // can set 0 or keep as needed + } + } + +} \ No newline at end of file diff --git a/VisualEditor/Editor/NanoBrainComponent_Editor.cs.meta b/VisualEditor/Editor/NanoBrainComponent_Editor.cs.meta new file mode 100644 index 0000000..eaf830b --- /dev/null +++ b/VisualEditor/Editor/NanoBrainComponent_Editor.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f05072314d39990639a2dbf99f322664 \ No newline at end of file diff --git a/VisualEditor/Editor/NanoBrainEditor.cs b/VisualEditor/Editor/NanoBrainEditor.cs new file mode 100644 index 0000000..230bfa1 --- /dev/null +++ b/VisualEditor/Editor/NanoBrainEditor.cs @@ -0,0 +1,511 @@ +/* +using UnityEditor; +using UnityEngine; +using UnityEngine.UIElements; +using UnityEditor.Callbacks; +using System.Linq; +using System.Collections.Generic; + +public class NucleusLayer { + public int ix = 0; + public List neuroids = new(); +} + +public class NanoBrainEditor : EditorWindow { + public NanoBrain brain; + + public static VisualElement inspectorContainer; + + [MenuItem("Window/NanoBrain Editor")] + public static void ShowWindow() { + GetWindow("NanoBrain Editor"); + } + + public static void Open(NanoBrain asset) { + NanoBrainEditor editor = GetWindow("NanoBrain Editor"); + editor.brain = asset; + editor.Show(); + } + + GraphBoardView board; + + private void OnEnable() { + OnFocus(); + } + private void OnFocus() { + if (brain == null) { + // brain = CreateInstance(); + // EditorUtility.SetDirty(brain); + return; + } + + VisualElement root = rootVisualElement; + root.Clear(); + root.styleSheets.Add(Resources.Load("GraphStyles")); + + VisualElement main = new() { + name = "main", + style = { + flexDirection = FlexDirection.Row, + flexGrow = 1 + } + }; + board = new GraphBoardView(); + board.style.flexGrow = 1; + inspectorContainer = new VisualElement { + name = "inspector", + style = { + width = 400 + } + }; + + main.Add(board); + main.Add(inspectorContainer); + root.Add(main); + + board.SetGraph(brain, brain.root); + + } + +} + +public class GraphBoardView : VisualElement { + NanoBrain brain; + SerializedObject serializedBrain; + Nucleus currentNucleus; + private List layers = new(); + private Dictionary neuroidPositions = new(); + + Vector2 pan = Vector2.zero; + //float zoom = 1f; + bool draggingCanvas = false; + Vector2 lastMouse; + GraphNodeWrapper currentWrapper; + + public GraphBoardView() { + name = "content"; + style.flexGrow = 1; + + IMGUIContainer imguiContainer = new(OnIMGUI); + imguiContainer.style.position = Position.Absolute; + imguiContainer.style.left = 0; imguiContainer.style.top = 0; + imguiContainer.style.right = 0; imguiContainer.style.bottom = 0; + imguiContainer.pickingMode = PickingMode.Position; + imguiContainer.focusable = true; + Add(imguiContainer); + + //RegisterCallback(OnWheel); + RegisterCallback(OnMouseDown); + RegisterCallback(OnMouseMove); + RegisterCallback(OnMouseUp); + } + + public void SetGraph(NanoBrain brain, Nucleus nucleus) { + this.brain = brain; + this.serializedBrain = new SerializedObject(brain); + this.currentNucleus = nucleus; + Rebuild(); + } + + void Rebuild() { + BuildLayers(); + + if (currentNucleus == null) { + NanoBrainEditor.inspectorContainer.Clear(); + return; + } + + if (currentWrapper != null) + Object.DestroyImmediate(currentWrapper); + currentWrapper = ScriptableObject.CreateInstance().Init(currentNucleus, brain); + DrawInspector(); + } + + private void BuildLayers() { + // A temporary list to track what's been added to layers + this.layers = new(); + int layerIx = 0; + + Nucleus selectedNucleus = this.currentNucleus; + if (selectedNucleus == null) + return; + NeuroidLayer currentLayer = new() { ix = layerIx }; + + //foreach (Nucleus outputNeuroid in selectedNucleus.receivers) { + foreach (Receiver receiver in selectedNucleus.receivers) { + Nucleus outputNeuroid = receiver.nucleus; + if (outputNeuroid != null) { + AddToLayer(currentLayer, outputNeuroid); + // Debug.Log($"layer {layerIx} nucleus {outputNeuroid.name}"); + } + } + if (currentLayer.neuroids.Count > 0) { + this.layers.Add(currentLayer); + layerIx++; + currentLayer = new() { ix = layerIx }; + } + + AddToLayer(currentLayer, selectedNucleus); + this.layers.Add(currentLayer); + // Debug.Log($"layer {layerIx} nucleus {selectedNucleus.name}"); + + layerIx++; + currentLayer = new() { ix = layerIx }; + + //foreach (Nucleus input in selectedNucleus.synapses.Keys) { + foreach (Synapse synapse in selectedNucleus.synapses) { + Nucleus input = synapse.nucleus; + AddToLayer(currentLayer, input); + // Debug.Log($"layer {layerIx} nucleus {input.name}"); + } + if (currentLayer.neuroids.Count > 0) { + this.layers.Add(currentLayer); + } + } + + private void AddToLayer(NeuroidLayer layer, Nucleus nucleus) { + if (nucleus == null) + return; + layer.neuroids.Add(nucleus); + nucleus.layerIx = layer.ix; + // Store its position + Vector2Int neuroidPosition = new(layer.ix, layer.neuroids.Count - 1); + neuroidPositions[nucleus] = neuroidPosition; + + } + + // basic pan/zoom handling + // void OnWheel(WheelEvent e) { + // if (e.ctrlKey) { + // float delta = -e.delta.y * 0.001f; + // zoom = Mathf.Clamp(zoom + delta, 0.25f, 2f); + // content.transform.rotation = Quaternion.identity; // keep transform accessible + // content.transform.scale = new Vector3(zoom, zoom, 1); + // e.StopPropagation(); + // } + // else { + // pan += e.delta; + // content.style.left = pan.x; + // content.style.top = pan.y; + // } + // } + + void OnMouseDown(MouseDownEvent e) { + if (e.button == 2) { draggingCanvas = true; lastMouse = e.mousePosition; e.StopPropagation(); } + } + void OnMouseMove(MouseMoveEvent e) { + if (draggingCanvas) { + var delta = e.mousePosition - lastMouse; + pan += delta; + //content.style.left = pan.x; + //content.style.top = pan.y; + lastMouse = e.mousePosition; + } + } + void OnMouseUp(MouseUpEvent e) { if (e.button == 2) draggingCanvas = false; } + + void OnIMGUI() { + if (currentNucleus == null) + return; + + serializedBrain.Update(); + + Handles.BeginGUI(); + foreach (NeuroidLayer layer in layers) + DrawLayer(layer); + Handles.EndGUI(); + + } + + private void DrawLayer(NeuroidLayer layer) { + int nodeCount = layer.neuroids.Count; + float maxValue = 0; + foreach (Nucleus nucleus in layer.neuroids) { + if (nucleus is Neuroid neuroid) { + float value = neuroid.outputValue.magnitude; + if (value > maxValue) + maxValue = value; + } + } + float spacing = 400f / nodeCount; + float margin = 10 + spacing / 2; + foreach (Nucleus layerNucleus in layer.neuroids) { + Vector2Int layerNeuroidPos = this.neuroidPositions[layerNucleus]; + Vector3 parentPos = new(100 + layerNeuroidPos.x * 100, margin + layerNeuroidPos.y * spacing, 0.1f); + + //int i = 0; + float inputSpacing = 400f / layerNucleus.synapses.Count; + float inputMargin = 10 + inputSpacing / 2; + // int minStale = 10000; + //foreach ((Nucleus nucleus, float weight) in layerNucleus.synapses) { + foreach (Synapse synapse in layerNucleus.synapses) { + Nucleus nucleus = synapse.nucleus; + if (nucleus != null) { + float weight = synapse.weight; + if (this.neuroidPositions.ContainsKey(nucleus)) { + Vector2Int inputNeuroidPos = this.neuroidPositions[nucleus]; + if (inputNeuroidPos.x == layerNeuroidPos.x + 1) { + Vector3 pos = new(100 + inputNeuroidPos.x * 100, inputMargin + inputNeuroidPos.y * inputSpacing, 0.0f); + + float brightness = weight / 10.0f; + Handles.color = new Color(brightness, brightness, brightness); + Handles.DrawLine(parentPos, pos); + } + } + // if (nucleus is Neuroid neuroid && neuroid.stale < minStale) + // minStale = neuroid.stale; + } + } + + // if (layerNucleus.synapses.Count > 0 && minStale > 2 && layerNucleus.stale < 3) + // Debug.LogWarning($"Strange {minStale} is big duing update"); + + + float size = 20; + if (layerNucleus.isSleeping) + Handles.color = Color.darkRed; + else { + float brightness = layerNucleus.outputValue.magnitude / maxValue; + Handles.color = new Color(brightness, brightness, brightness); + } + Handles.DrawSolidDisc(parentPos, Vector3.forward, size); + Vector3 labelPos = parentPos - Vector3.down * (size + 0.2f); // below disc along up axis + GUIStyle style = new GUIStyle(EditorStyles.label) { + alignment = TextAnchor.UpperCenter, + normal = { textColor = Color.white }, + fontStyle = FontStyle.Bold + }; + Handles.Label(labelPos, layerNucleus.name, style); + + Rect neuronRect = new(parentPos.x - size, parentPos.y - size, size * 2, size * 2); + int id = GUIUtility.GetControlID(FocusType.Passive); + Event e = Event.current; + EventType et = e.GetTypeForControl(id); + if (e != null && neuronRect.Contains(e.mousePosition)) { + // Process Hover + HandleMouseHover(layerNucleus, neuronRect); + // Process click + // Debug.Log($"{et} {e.type}"); + if (e.type == EventType.MouseDown && e.button == 0) { + // Consume the event so the scene doesn't also handle it + e.Use(); + HandleDiscClicked(layerNucleus); + } + } + } + } + + private void HandleMouseHover(Nucleus neuroid, Rect rect) { + GUIContent tooltip; + // if (neuroid is SensoryNeuroid sensoryNeuroid) { + // tooltip = new( + // $"{sensoryNeuroid.name}" + + // $"\nThing {sensoryNeuroid.receptor.thingType}" + + // $"\nValue: {neuroid.outputValue}"); + // } + // else { + tooltip = new( + $"{neuroid.name}" + + $"\nsynapse count {neuroid.synapses.Count}" + + $"\nValue: {neuroid.outputValue}"); + // } + + Vector2 mousePosition = Event.current.mousePosition; + + // Display tooltip with some offset + Vector2 tooltipSize = GUI.skin.box.CalcSize(tooltip); + Rect tooltipRect = new Rect(mousePosition.x + 10, mousePosition.y + 10, tooltipSize.x, tooltipSize.y); + + GUI.Box(tooltipRect, tooltip); + } + + private void HandleDiscClicked(Nucleus nucleus) { + this.currentNucleus = nucleus; + BuildLayers(); + } + + + void DrawInspector() { + if (NanoBrainEditor.inspectorContainer == null) + return; + + NanoBrainEditor.inspectorContainer.Clear(); + if (this.currentNucleus == null) + return; + + // create a SerializedObject wrapper so Unity inspector controls work (and Undo) + SerializedObject so = new SerializedObject(currentWrapper); + IMGUIContainer container = new IMGUIContainer(() => { + so.Update(); + currentNucleus.name = EditorGUILayout.TextField(currentNucleus.name); + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Output Value", GUILayout.Width(100)); + EditorGUILayout.Vector3Field(GUIContent.none, currentNucleus.outputValue); + EditorGUILayout.EndHorizontal(); + if (currentNucleus.synapses.Count > 0) { + EditorGUILayout.LabelField("Synapses"); + EditorGUI.indentLevel++; + + //List nuclei = currentNucleus.synapses.Keys.ToList(); + // foreach (Nucleus nucleus in nuclei) { + foreach (Synapse synapse in currentNucleus.synapses) { + EditorGUI.BeginDisabledGroup(synapse.nucleus.isSleeping); + + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField(synapse.nucleus.name, GUILayout.Width(120)); + EditorGUI.indentLevel--; + EditorGUILayout.LabelField("Weight", GUILayout.Width(45)); + // float weight = currentNucleus.synapses[nucleus]; + // currentNucleus.synapses[nucleus] = EditorGUILayout.FloatField(weight, GUILayout.Width(40)); + synapse.weight = EditorGUILayout.FloatField(synapse.weight, GUILayout.Width(40)); + EditorGUI.indentLevel++; + EditorGUILayout.Vector3Field(GUIContent.none, synapse.nucleus.outputValue, GUILayout.Width(180)); + EditorGUILayout.EndHorizontal(); + + EditorGUI.EndDisabledGroup(); + } + EditorGUI.indentLevel--; + } + if (GUILayout.Button("Add Neuron")) + AddInputNeuron(currentNucleus); + + }); + + NanoBrainEditor.inspectorContainer.Add(container); + } + + protected virtual void AddInputNeuron(Nucleus receiver) { + Neuroid newNeuroid = new(brain, "New neuron"); + newNeuroid.AddReceiver(receiver); + Rebuild(); + } + + private Vector3 NodePosition(Nucleus nucleus, int layerNodeCount = 1) { + if (this.neuroidPositions.ContainsKey(nucleus)) { + Vector2Int nucleusPos = this.neuroidPositions[nucleus]; + return NodePosition(nucleusPos, layerNodeCount); + } + else { + return Vector3.zero; + } + } + private Vector3 NodePosition(Vector2Int location, int layerNodeCount = 1) { + float spacing = 400f / layerNodeCount; + float margin = 10 + spacing / 2; + float size = 20; + Vector3 parentPos = new(100 + location.x * 100 - size, margin + location.y * spacing - size, 0.1f); + return parentPos; + } + + + // public void CreateEdge(string fromId, string toId) { + // if (fromId == toId) return; + // Undo.RecordObject(graph, "Create Edge"); + // graph.edges.Add(new GraphEdge { fromNodeId = fromId, toNodeId = toId }); + // EditorUtility.SetDirty(graph); + // Rebuild(); + // } +} + + +public class NodeView : VisualElement { + Nucleus data; + GraphBoardView board; + Label titleLabel; + //bool dragging = false; + Vector2 localDragStart; + + public NodeView(Nucleus node, GraphBoardView boardView) { + data = node; + board = boardView; + name = "node"; + style.width = 20; //node.size.x; + style.height = 20; //node.size.y; + + titleLabel = new Label(node.name) { name = "title" }; + Add(titleLabel); + + // ports + // var outPort = new Button(() => StartEdgeDrag(true)) { text = "◀", name = "out" }; + // var inPort = new Button(() => StartEdgeDrag(false)) { text = "▶", name = "in" }; + // Add(outPort); + // Add(inPort); + + RegisterCallback(OnMouseDown); + // RegisterCallback(OnMouseMove); + RegisterCallback(OnMouseUp); + //RegisterCallback(e => dragging = false); + } + + // void StartEdgeDrag(bool isOutput) { + // // simplified: on first click store source; on second click on target port call board.CreateEdge + // if (EdgeDragState.active == null) EdgeDragState.active = new EdgeDragState { fromNode = data, fromIsOutput = isOutput }; + // else { + // var src = EdgeDragState.active.fromNode; + // if (src != null && src.id != data.id) board.CreateEdge(src.id, data.id); + // EdgeDragState.active = null; + // } + // } + + void OnMouseDown(MouseDownEvent e) { + if (e.button == 0 && e.target == this) { + //dragging = true; + localDragStart = e.mousePosition; + e.StopPropagation(); + } + } + // void OnMouseMove(MouseMoveEvent e) { + // if (!dragging) return; + // var delta = e.mousePosition - localDragStart; + // var worldPos = new Vector2(layout.x + delta.x, layout.y + delta.y); + // style.left = worldPos.x; + // style.top = worldPos.y; + // // commit on every move + // board.UpdateNodePosition(data, worldPos); + // } + void OnMouseUp(MouseUpEvent e) { + //dragging = false; + } +} + + +public class GraphNodeWrapper : ScriptableObject { + // expose fields that map to GraphNode + public string title; + public Vector2 position; + Nucleus node; + NanoBrain graph; // needed to write back and mark dirty + + public GraphNodeWrapper Init(Nucleus node, NanoBrain graphAsset) { + this.node = node; + this.graph = graphAsset; + this.title = " A " + node.name; + //position = node.position; + return this; + } + void OnValidate() { + if (node != null) { + node.name = title; + //node.position = position; +#if UNITY_EDITOR + if (graph != null) + UnityEditor.EditorUtility.SetDirty(graph); +#endif + } + } +} +//static class EdgeDragState { public static EdgeDragState active; public GraphNode fromNode; public bool fromIsOutput; } + +public static class OpenAssetHandler { + // Called when an asset is double-clicked or opened. + [OnOpenAsset] + public static bool OpenMyScriptableObject(int instanceID, int line) { + NanoBrain obj = EditorUtility.EntityIdToObject(instanceID) as NanoBrain; + if (obj != null) { + NanoBrainEditor.Open(obj); + return true; // handled + } + return false; // let Unity open normally + } +} +*/ \ No newline at end of file diff --git a/VisualEditor/Editor/NanoBrainEditor.cs.meta b/VisualEditor/Editor/NanoBrainEditor.cs.meta new file mode 100644 index 0000000..99dedcd --- /dev/null +++ b/VisualEditor/Editor/NanoBrainEditor.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c57f78e25f0e55b96a50fd5592b26317 \ No newline at end of file diff --git a/VisualEditor/Editor/NanoBrainInspector.cs b/VisualEditor/Editor/NanoBrainInspector.cs new file mode 100644 index 0000000..447fa70 --- /dev/null +++ b/VisualEditor/Editor/NanoBrainInspector.cs @@ -0,0 +1,645 @@ +/* +using System.Collections.Generic; +using System.Linq; +using UnityEditor; + +using UnityEngine; +using UnityEngine.UIElements; + +[CustomEditor(typeof(NanoBrain))] +public class NanoBrainInspector : Editor { + protected static VisualElement mainContainer; + protected static VisualElement inspectorContainer; + + protected bool breakOnWake = false; + + #region Start + + public override VisualElement CreateInspectorGUI() { + NanoBrain brain = target as NanoBrain; + + serializedObject.Update(); + + VisualElement root = new(); + //root.style.flexDirection = FlexDirection.Row; // side-by-side layout + //root.style.flexGrow = 1; + //root.style.minHeight = 600; + root.style.paddingLeft = 0; + root.style.paddingRight = 0; + root.style.paddingTop = 0; + root.style.paddingBottom = 0; + + root.styleSheets.Add(Resources.Load("GraphStyles")); + + mainContainer = new() { + // name = "main", + style = { + // flexDirection = FlexDirection.Row, + // flexGrow = 1, + height = 450, + } + }; + GraphView graph = new(); + graph.style.flexGrow = 1; + + inspectorContainer = new VisualElement { + // name = "inspector" + }; + + mainContainer.Add(graph); + mainContainer.Add(inspectorContainer); + root.Add(mainContainer); + + // Run once for initial state (use resolved style width if available) + float initialWidth = root.layout.width > 0 ? root.layout.width : root.contentRect.width; + UpdateLayout(initialWidth); + + // React to size changes of root (or parent if appropriate) + root.RegisterCallback(evt => { + UpdateLayout(evt.newRect.width); + }); + + if (brain != null) + graph.SetGraph(null, brain, brain.output, inspectorContainer); + else + Debug.LogWarning(" No brain!"); + + serializedObject.ApplyModifiedProperties(); + return root; + } + + public class GraphView : VisualElement { + NanoBrain brain; + SerializedObject serializedBrain; + INucleus currentNucleus; + GameObject gameObject; + private List layers = new(); + private readonly Dictionary neuroidPositions = new(); + + Vector2 pan = Vector2.zero; + //float zoom = 1f; + bool draggingCanvas = false; + Vector2 lastMouse; + GraphNodeWrapper currentWrapper; + + public GraphView() { + name = "content"; + style.flexGrow = 1; + + IMGUIContainer imguiContainer = new(OnIMGUI); + imguiContainer.style.position = Position.Absolute; + imguiContainer.style.left = 0; imguiContainer.style.top = 0; + imguiContainer.style.right = 0; imguiContainer.style.bottom = 0; + imguiContainer.pickingMode = PickingMode.Position; + imguiContainer.focusable = true; + Add(imguiContainer); + + //RegisterCallback(OnWheel); + RegisterCallback(OnMouseDown); + RegisterCallback(OnMouseMove); + RegisterCallback(OnMouseUp); + } + + public void SetGraph(GameObject gameObject, NanoBrain brain, Nucleus nucleus, VisualElement inspectorContainer) { + this.gameObject = gameObject; + this.brain = brain; + if (Application.isPlaying == false) + this.serializedBrain = new SerializedObject(brain); + this.currentNucleus = nucleus; + Rebuild(inspectorContainer); + } + + void Rebuild(VisualElement inspectorContainer) { + BuildLayers(); + + if (this.currentNucleus == null) { + inspectorContainer.Clear(); + return; + } + + if (currentWrapper != null) + DestroyImmediate(currentWrapper); + currentWrapper = CreateInstance().Init(this.currentNucleus, brain); + DrawInspector(inspectorContainer); + } + + private void BuildLayers() { + // A temporary list to track what's been added to layers + this.layers = new(); + int layerIx = 0; + + INucleus selectedNucleus = this.currentNucleus; + if (selectedNucleus == null) + return; + NeuroidLayer currentLayer = new() { ix = layerIx }; + + if (selectedNucleus.receivers != null) { + foreach (INucleus receiver in selectedNucleus.receivers) { + INucleus outputNeuroid = receiver; + if (outputNeuroid != null) { + AddToLayer(currentLayer, outputNeuroid); + // Debug.Log($"layer {layerIx} nucleus {outputNeuroid.name}"); + } + } + } + if (currentLayer.neuroids.Count > 0) { + this.layers.Add(currentLayer); + layerIx++; + currentLayer = new() { ix = layerIx }; + } + + AddToLayer(currentLayer, selectedNucleus); + this.layers.Add(currentLayer); + // Debug.Log($"layer {layerIx} nucleus {selectedNucleus.name}"); + + layerIx++; + currentLayer = new() { ix = layerIx }; + + if (selectedNucleus.synapses != null) { + foreach (Synapse synapse in selectedNucleus.synapses) { + IReceptor input = synapse.nucleus; + AddToLayer(currentLayer, input); + // Debug.Log($"layer {layerIx} nucleus {input.name}"); + } + } + if (currentLayer.neuroids.Count > 0) { + this.layers.Add(currentLayer); + } + } + + private void AddToLayer(NeuroidLayer layer, IReceptor nucleus) { + if (nucleus == null) + return; + layer.neuroids.Add(nucleus); + //nucleus.layerIx = layer.ix; + // Store its position + Vector2Int neuroidPosition = new(layer.ix, layer.neuroids.Count - 1); + neuroidPositions[nucleus] = neuroidPosition; + + } + + void OnMouseDown(MouseDownEvent e) { + if (e.button == 2) { draggingCanvas = true; lastMouse = e.mousePosition; e.StopPropagation(); } + } + void OnMouseMove(MouseMoveEvent e) { + if (draggingCanvas) { + var delta = e.mousePosition - lastMouse; + pan += delta; + //content.style.left = pan.x; + //content.style.top = pan.y; + lastMouse = e.mousePosition; + } + } + void OnMouseUp(MouseUpEvent e) { if (e.button == 2) draggingCanvas = false; } + + void OnIMGUI() { + if (currentNucleus == null) + return; + + if (Application.isPlaying == false) + serializedBrain.Update(); + + Handles.BeginGUI(); + DrawGraph(); + Handles.EndGUI(); + + } + + private void DrawGraph() { + float size = 20; + Vector3 position = new(150, 210, 0); + + DrawReceivers(this.currentNucleus, position, size); + DrawSynapses(this.currentNucleus, position, size); + + // Draw selected Nucleus + Handles.color = Color.white; + Handles.DrawSolidDisc(position, Vector3.forward, size + 2); + DrawNucleus(this.currentNucleus, position, this.currentNucleus.outputValue.magnitude, 20); + } + + private void DrawReceivers(INucleus nucleus, Vector3 parentPos, float size) { + int nodeCount = nucleus.receivers.Count; + + // Determine the maximum value in this layer + // This is used to 'scale' the output value colors of the nuclei + float maxValue = 0; + foreach (INucleus receiver in nucleus.receivers) { + if (receiver is Neuroid neuroid) { + float value = neuroid.outputValue.magnitude; + if (value > maxValue) + maxValue = value; + } + } + + // Determine the spacing of the nuclei in the layer + float spacing = 400f / nodeCount; + float margin = 10 + spacing / 2; + + int row = 0; + foreach (INucleus receiver in nucleus.receivers) { + INucleus receiverNucleus = receiver; + if (receiverNucleus == null) + continue; + + Vector3 pos = new(50, margin + row * spacing, 0.0f); + Handles.color = Color.white; + Handles.DrawLine(parentPos, pos); + + DrawNucleus(receiverNucleus, pos, maxValue, size); + row++; + } + } + + private void DrawSynapses(INucleus nucleus, Vector3 parentPos, float size) { + int nodeCount = nucleus.synapses.Count; + + // Determine the maximum value in this layer + // This is used to 'scale' the output value colors of the nuclei + float maxValue = 0; + foreach (Synapse receiver in nucleus.synapses) { + if (receiver.nucleus is Neuroid neuroid) { + float value = neuroid.outputValue.magnitude; + if (value > maxValue) + maxValue = value; + } + } + + // Determine the spacing of the nuclei in the layer + float spacing = 400f / nodeCount; + float margin = 10 + spacing / 2; + + int row = 0; + List drawnArrays = new(); + foreach (Synapse synapse in nucleus.synapses) { + Vector3 pos = new(250, margin + row * spacing, 0.0f); + Handles.color = Color.white; + Handles.DrawLine(parentPos, pos); + // if (synapse.nucleus is Perceptoid perceptoid && perceptoid.array != null) { + // // if (drawnArrays.Contains(perceptoid.array)) + // // // We already drawn this array + // // continue; + + // drawnArrays.Add(perceptoid.array); + // DrawArray(perceptoid.array, pos, size); + // } + // else { + + DrawNucleus(synapse.nucleus, pos, maxValue, size); + row++; + // } + } + } + + private void DrawNucleus(IReceptor nucleus, Vector3 position, float maxValue, float size) { + if (nucleus.isSleeping) + Handles.color = Color.darkRed; + else { + if (Application.isPlaying) { + float brightness = nucleus.outputValue.magnitude / maxValue; + Handles.color = new Color(brightness, brightness, brightness, 1f); + } + else + Handles.color = Color.black; + } + Handles.DrawSolidDisc(position, Vector3.forward, size); + + Handles.color = Color.white; + // Position the label in front of the disc + Vector3 labelPosition = position + (Vector3.forward * 0.1f); + + GUIStyle style = new(EditorStyles.label) { + alignment = TextAnchor.MiddleCenter, + normal = { textColor = Color.white }, + fontStyle = FontStyle.Bold, + }; + if (nucleus is Perceptoid perceptoid) { + if (perceptoid.array == null || perceptoid.array.perceptei == null || perceptoid.array.perceptei.Length == 0) + perceptoid.array = new PercepteiArray(perceptoid); + + if (perceptoid.array.perceptei.Length > 1) { + Handles.Label(labelPosition, perceptoid.array.perceptei.Length.ToString(), style); + } + } + + style.alignment = TextAnchor.UpperCenter; + Vector3 labelPos = position - Vector3.down * (size + 0.2f); // below disc along up axis + Handles.Label(labelPos, nucleus.name, style); + + Rect neuronRect = new(position.x - size, position.y - size, size * 2, size * 2); + int id = GUIUtility.GetControlID(FocusType.Passive); + Event e = Event.current; + EventType et = e.GetTypeForControl(id); + if (e != null && neuronRect.Contains(e.mousePosition)) { + // Process Hover + HandleMouseHover(nucleus, neuronRect); + // Process click + if (e.type == EventType.MouseDown && e.button == 0) { + // Consume the event so the scene doesn't also handle it + e.Use(); + HandleClicked(nucleus); + } + } + } + + private void DrawArray(PercepteiArray array, Vector3 position, float size) { + Vector3 offset = new(size / 4, size / 4, 0); + Handles.color = Color.black; + Handles.DrawSolidDisc(position, Vector3.forward, size); + + GUIStyle style = new(EditorStyles.label) { + alignment = TextAnchor.UpperCenter, + normal = { textColor = Color.white }, + fontStyle = FontStyle.Bold + }; + Handles.Label(position, array.perceptei.Length.ToString(), style); + Vector3 labelPos = position - Vector3.down * (size + 0.2f); // below disc along up axis + Handles.Label(labelPos, array.name, style); + + // To do: add HandleClick (see above) to expand the array + } + + private void HandleMouseHover(IReceptor nucleus, Rect rect) { + GUIContent tooltip; + if (nucleus is Perceptoid perceptoid) { + if (perceptoid.receptor != null) { + tooltip = new( + $"{perceptoid.name}" + + // $"\nType {perceptoid.receptor.thingType}" + + $" Thing {perceptoid.thingId}" + + $"\nValue: {nucleus.outputValue}"); + } + else { + tooltip = new( + $"{perceptoid.name}" + + $"\nThing {perceptoid.thingId}" + + $"\nValue: {nucleus.outputValue}"); + } + } + else if (nucleus is INucleus n) { + tooltip = new( + $"{nucleus.name}" + + $"\nsynapse count {n.synapses.Count}" + + $"\nValue: {nucleus.outputValue}"); + } + else { + tooltip = new( + $"{nucleus.name}" + + $"\nValue: {nucleus.outputValue}"); + } + + Vector2 mousePosition = Event.current.mousePosition; + + // Display tooltip with some offset + Vector2 tooltipSize = GUI.skin.box.CalcSize(tooltip); + Rect tooltipRect = new Rect(mousePosition.x + 10, mousePosition.y + 10, tooltipSize.x, tooltipSize.y); + + GUI.Box(tooltipRect, tooltip); + } + + private void HandleClicked(IReceptor nucleus) { + if (nucleus is INucleus n) { + this.currentNucleus = n; + BuildLayers(); + } + } + + void DrawInspector(VisualElement inspectorContainer) { + if (inspectorContainer == null) + return; + + inspectorContainer.Clear(); + if (this.currentNucleus == null) + return; + + // create a SerializedObject wrapper so Unity inspector controls work (and Undo) + SerializedObject so = new(currentWrapper); + IMGUIContainer container = new(() => { + if (so.targetObject == null) + return; + so.Update(); + + if (this.currentNucleus == null) + return; + + this.currentNucleus.name = EditorGUILayout.TextField(this.currentNucleus.name); + if (this.currentNucleus is Perceptoid perceptoid) { + // perceptoid.receptor.thingType = EditorGUILayout.IntField("Thing Type", perceptoid.receptor.thingType); + + if (perceptoid.array == null || perceptoid.array.perceptei == null || perceptoid.array.perceptei.Length == 0) + perceptoid.array = new PercepteiArray(perceptoid); + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.IntField("Array size", perceptoid.array.perceptei.Length); + if (GUILayout.Button("Add")) + perceptoid.array.AddPerceptoid(); + if (GUILayout.Button("Del")) + perceptoid.array.RemovePerceptoid(); + EditorGUILayout.EndHorizontal(); + } + else if (this.currentNucleus is Neuroid neuroid) { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Activation Curve", GUILayout.Width(150)); + if (neuroid.curveMax > 0) + EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, 0, 1, neuroid.curveMax)); + else + EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, neuroid.curveMax, 1, -neuroid.curveMax)); + neuroid.curvePreset = (Neuroid.CurvePresets)EditorGUILayout.EnumPopup(neuroid.curvePreset, GUILayout.Width(100)); + EditorGUILayout.EndHorizontal(); + } + + if (Application.isPlaying) + EditorGUILayout.FloatField("Output", this.currentNucleus.outputValue.magnitude); + else + EditorGUILayout.LabelField(" "); + + if (this.currentNucleus.synapses.Count > 0) { + Synapse[] synapses = this.currentNucleus.synapses.ToArray(); + foreach (Synapse synapse in synapses) { + if (synapse.nucleus != null) { + EditorGUILayout.Space(); + + EditorGUI.BeginDisabledGroup(synapse.nucleus.isSleeping); + if (Application.isPlaying) + EditorGUILayout.FloatField(synapse.nucleus.name, synapse.nucleus.outputValue.magnitude * synapse.weight); + else { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField(synapse.nucleus.name); + // if (synapse.nucleus is Perceptoid perceptoid) { + // if (perceptoid.array == null || perceptoid.array.perceptei == null || perceptoid.array.perceptei.Length == 0) { + // perceptoid.array = new PercepteiArray(perceptoid); + // } + // EditorGUILayout.IntField(perceptoid.array.perceptei.Length); + // if (GUILayout.Button("Add")) + // perceptoid.array.AddPerceptoid(); + // } + if (GUILayout.Button("Disconnect")) + synapse.nucleus.RemoveReceiver(this.currentNucleus); + EditorGUILayout.EndHorizontal(); + } + + EditorGUI.indentLevel++; + synapse.weight = EditorGUILayout.FloatField("Weight", synapse.weight); + EditorGUI.indentLevel--; + EditorGUI.EndDisabledGroup(); + } + } + } + + EditorGUILayout.Space(); + + ConnectNucleus(this.currentNucleus); + if (GUILayout.Button("Add Input Neuron")) + AddInputNeuron(this.currentNucleus); + if (GUILayout.Button("Add Input Perceptoid")) + AddPerceptoid(this.currentNucleus); + if (GUILayout.Button("Add Input Cluster")) + AddCluster(this.currentNucleus); + + EditorGUILayout.Space(); + + if (GUILayout.Button("Delete this neuron")) + DeleteNeuron(this.currentNucleus); + + //DisconnectNucleus(this.currentNucleus); + + if (this.gameObject != null) { + Vector3 worldVector = this.gameObject.transform.TransformVector(this.currentNucleus.outputValue); + Debug.DrawRay(this.gameObject.transform.position, worldVector, Color.yellow); + } + }); + + inspectorContainer.Add(container); + } + + protected virtual void AddInputNeuron(INucleus nucleus) { + Neuroid newNeuroid = new(this.brain.cluster, "New neuron"); + newNeuroid.AddReceiver(nucleus); + this.currentNucleus = newNeuroid; + BuildLayers(); + } + + protected virtual void DeleteNeuron(INucleus nucleus) { + if (nucleus == null) + return; + if (nucleus.cluster != null) + this.currentNucleus = nucleus.cluster.output; + foreach (INucleus receiver in nucleus.receivers) { + if (receiver != null) { + this.currentNucleus = receiver; + break; + } + } + Nucleus.Delete(nucleus); + BuildLayers(); + } + + protected virtual void AddPerceptoid(INucleus nucleus) { + Perceptoid newPerceptoid = new(this.brain, 0, "New Perceptoid"); + newPerceptoid.AddReceiver(nucleus); + this.currentNucleus = newPerceptoid; + BuildLayers(); + } + + protected virtual void AddCluster(INucleus nucleus) { + BrainPickerWindow.ShowPicker(brain => OnClusterPicked(nucleus, brain), "Select Cluster"); + } + + private void OnClusterPicked(INucleus nucleus, NanoBrain brain) { + NanoBrain brainInstance = Instantiate(brain); + brainInstance.AddReceiver(nucleus); + } + + protected virtual void ConnectNucleus(INucleus nucleus) { + if (this.currentNucleus.cluster == null) + return; + + IEnumerable synapseNuclei = this.currentNucleus.synapses.Select(synapse => synapse.nucleus.name); + //IEnumerable perceptei = this.currentNucleus.brain.perceptei.Select(i => i.name).Except(synapseNuclei); + IEnumerable nuclei = this.currentNucleus.cluster.nuclei.Select(i => i.name).Except(synapseNuclei); + //string[] names = perceptei.Concat(nuclei).ToArray(); + string[] names = nuclei.ToArray(); + int selectedIndex = -1; + selectedIndex = EditorGUILayout.Popup("Connect to", selectedIndex, names); + if (selectedIndex >= 0) { + // if (selectedIndex < perceptei.Count()) { + // Nucleus n = this.currentNucleus.brain.perceptei[selectedIndex]; + // n.AddReceiver(this.currentNucleus); + // } + // else { + // Nucleus n = this.currentNucleus.brain.nuclei[selectedIndex - perceptei.Count()]; + // n.AddReceiver(this.currentNucleus); + // } + INucleus n = this.currentNucleus.cluster.nuclei[selectedIndex]; + n.AddReceiver(this.currentNucleus); + } + } + + protected virtual void DisconnectNucleus(Nucleus nucleus) { + if (this.currentNucleus.cluster == null) + return; + string[] names = this.currentNucleus.synapses.Select(synapse => synapse.nucleus.name).ToArray(); + int selectedIndex = -1; + selectedIndex = EditorGUILayout.Popup("Disconnect from", selectedIndex, names); + //if (selectedIndex >= 0 && selectedIndex < this.currentNucleus.brain.perceptei.Count) { + if (selectedIndex >= 0 && selectedIndex < this.currentNucleus.cluster.nuclei.Count) { + Synapse synapse = this.currentNucleus.synapses[selectedIndex]; + synapse.nucleus.RemoveReceiver(this.currentNucleus); + } + } + } + + #endregion Start + + #region Update + + private void UpdateLayout(float containerWidth) { + if (containerWidth > 600f) { + mainContainer.style.flexDirection = FlexDirection.Row; + inspectorContainer.style.width = 300; // fixed sidebar width + inspectorContainer.style.flexGrow = 0; + } + else { + mainContainer.style.flexDirection = FlexDirection.Column; + inspectorContainer.style.width = Length.Percent(100); // full width below + inspectorContainer.style.flexDirection = FlexDirection.Column; + inspectorContainer.style.flexGrow = 1; // can set 0 or keep as needed + } + } + + #endregion Update +} + +/* +public class NeuroidLayer { + public int ix = 0; + public List neuroids = new(); +} +*/ + +/* +public class GraphNodeWrapper : ScriptableObject { + // expose fields that map to GraphNode + //public string title; + public Vector2 position; + INucleus node; + NanoBrain graph; // needed to write back and mark dirty + + public GraphNodeWrapper Init(INucleus node, NanoBrain graphAsset) { + this.node = node; + this.graph = graphAsset; + //this.title = " A " + node.name; + //position = node.position; + return this; + } + void OnValidate() { + if (node != null) { + //node.name = title; + //node.position = position; +#if UNITY_EDITOR + if (graph != null) + UnityEditor.EditorUtility.SetDirty(graph); +#endif + } + } +} +*/ \ No newline at end of file diff --git a/VisualEditor/Editor/NanoBrainInspector.cs.meta b/VisualEditor/Editor/NanoBrainInspector.cs.meta new file mode 100644 index 0000000..e71178e --- /dev/null +++ b/VisualEditor/Editor/NanoBrainInspector.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c96ad47c3d4498640b52630789e38573 \ No newline at end of file diff --git a/VisualEditor/NanoBrain.cs b/VisualEditor/NanoBrain.cs new file mode 100644 index 0000000..d786da6 --- /dev/null +++ b/VisualEditor/NanoBrain.cs @@ -0,0 +1,102 @@ +/* +using System; +using System.Collections.Generic; +using UnityEngine; + +[CreateAssetMenu(menuName = "Passer/NanoBrain")] +public class NanoBrain : ScriptableObject, ISerializationCallbackReceiver { + public List nuclei = new(); + public List perceptei = new(); + public List receptors = new(); + + + // This is probably always the first element in the nuclei list... + [System.NonSerialized] + public Nucleus output; + public int rootId; + + public NanoBrain() { + // this.cluster = new(); + // this.output = new Neuroid(this.cluster, "Root"); + } + + public Cluster cluster; + + public void AddReceiver(INucleus receiver) { + output.AddReceiver(receiver); + } + + public Neuroid AddNeuron(string name) { + Neuroid neuroid = new(this.cluster, name); + return neuroid; + } + + public void UpdateNuclei() { + foreach (Nucleus nucleus in nuclei) + nucleus.IncreaseAge(); + foreach (Perceptoid perception in perceptei) + perception.IncreaseAge(); + } + + public void OnBeforeSerialize() { + if (output != null) { + this.rootId = output.id; + } + } + public void OnAfterDeserialize() { + try { + foreach (Nucleus nucleus in this.nuclei.ToArray()) { + if (this.rootId == nucleus.id) + this.output = nucleus; + nucleus.Rebuild(this); + } + + foreach (Perceptoid perceptoid in this.perceptei.ToArray()) + perceptoid.Rebuild(this); + } + catch (System.Exception) { } + if (this.cluster != null) + this.cluster.GarbageCollection(); + } + + + public void GarbageCollection() { + HashSet visitedNuclei = new(); + MarkNuclei(visitedNuclei, this.output); + //Debug.Log($"Garbage collection found {visitedNuclei.Count} Nuclei"); + this.nuclei.RemoveAll(nucleus => visitedNuclei.Contains(nucleus) == false); + this.perceptei.RemoveAll(perceptoid => visitedNuclei.Contains(perceptoid) == false); + } + + public void MarkNuclei(HashSet visitedNuclei, INucleus nucleus) { + if (nucleus is null) + return; + + if (nucleus.brain == null) + nucleus.brain = this; + + visitedNuclei.Add(nucleus); + if (nucleus.synapses != null) { + HashSet visitedSynapses = new(); + foreach (Synapse synapse in nucleus.synapses) { + if (synapse != null && synapse.nucleus != null) { + visitedSynapses.Add(synapse); + MarkNuclei(visitedNuclei, synapse.nucleus); + } + } + nucleus.synapses.RemoveAll(synapse => visitedSynapses.Contains(synapse) == false); + } + if (nucleus.receivers != null) { + HashSet visitedReceivers = new(); + foreach (Receiver receiver in nucleus.receivers) { + if (receiver != null && receiver.nucleus != null) { + visitedReceivers.Add(receiver); + visitedNuclei.Add(receiver.nucleus); + } + } + nucleus.receivers.RemoveAll(receiver => visitedReceivers.Contains(receiver) == false); + } + } + +} +*/ \ No newline at end of file diff --git a/VisualEditor/NanoBrain.cs.meta b/VisualEditor/NanoBrain.cs.meta new file mode 100644 index 0000000..40e85f2 --- /dev/null +++ b/VisualEditor/NanoBrain.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 36081359186edfec998d891a1feeb17b \ No newline at end of file diff --git a/VisualEditor/NanoBrainComponent.cs b/VisualEditor/NanoBrainComponent.cs new file mode 100644 index 0000000..56c9159 --- /dev/null +++ b/VisualEditor/NanoBrainComponent.cs @@ -0,0 +1,35 @@ +using UnityEngine; + +public class NanoBrainComponent : MonoBehaviour { + public ClusterPrefab defaultBrain; + private ClusterPrefab brainInstance; + + public INucleus root => brainInstance.output; + public ClusterPrefab brain { + get { + if (brainInstance == null && defaultBrain != null) { + brainInstance = Instantiate(defaultBrain); + brainInstance.name = defaultBrain.name + " (Instance)"; + + SwarmControl sc = FindFirstObjectByType(); + if (sc != null) { + UpdateWeight(brainInstance, "Avoidance", sc.avoidanceForce); + UpdateWeight(brainInstance, "Cohesion", sc.cohesionForce); + UpdateWeight(brainInstance, "Separation", sc.separationForce); + UpdateWeight(brainInstance, "Alignment", sc.alignmentForce); + } + } + return brainInstance; + } + } + + public static void UpdateWeight(ClusterPrefab brain, string name, float weight) { + INucleus root = brain.output; + foreach (Synapse synapse in root.synapses) { + if (synapse.nucleus.name == name) { + synapse.weight = weight; + } + } + } + +} \ No newline at end of file diff --git a/VisualEditor/NanoBrainComponent.cs.meta b/VisualEditor/NanoBrainComponent.cs.meta new file mode 100644 index 0000000..1666c60 --- /dev/null +++ b/VisualEditor/NanoBrainComponent.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 92f34a5e4027a1dc39efd8ce63cf6aba \ No newline at end of file diff --git a/VisualEditor/Resources.meta b/VisualEditor/Resources.meta new file mode 100644 index 0000000..e9c19e4 --- /dev/null +++ b/VisualEditor/Resources.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7b61a93fc9332d2adae74fe4abe92d53 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualEditor/Resources/GraphStyles.uss b/VisualEditor/Resources/GraphStyles.uss new file mode 100644 index 0000000..79bafe8 --- /dev/null +++ b/VisualEditor/Resources/GraphStyles.uss @@ -0,0 +1,12 @@ +#content { + background-color: #2b2b2b; +} +#inspector { + border-left-width: 1px; + border-left-color: #000; + padding: 3px; +} +#title { + -unity-font-style: bold; + color: white; + } diff --git a/VisualEditor/Resources/GraphStyles.uss.meta b/VisualEditor/Resources/GraphStyles.uss.meta new file mode 100644 index 0000000..2546c45 --- /dev/null +++ b/VisualEditor/Resources/GraphStyles.uss.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 28268b644fa8f3948851b25e41f5b03b +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} + disableValidation: 0 From 5ab15926e47a1d2a25bc1e911b100d207c8d166e Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 29 Jan 2026 09:10:48 +0100 Subject: [PATCH 087/179] Delete Nanobrain to prep for subtree --- Assets/NanoBrain/Cluster.cs | 259 ------- Assets/NanoBrain/Cluster.cs.meta | 2 - Assets/NanoBrain/ClusterPrefab.cs | 84 -- Assets/NanoBrain/ClusterPrefab.cs.meta | 2 - Assets/NanoBrain/Editor.meta | 8 - Assets/NanoBrain/Editor/NeuroidWindow.cs | 302 -------- Assets/NanoBrain/Editor/NeuroidWindow.cs.meta | 2 - Assets/NanoBrain/INucleus.cs | 54 -- Assets/NanoBrain/INucleus.cs.meta | 2 - Assets/NanoBrain/Identity.asset | 60 -- Assets/NanoBrain/Identity.asset.meta | 8 - Assets/NanoBrain/LinearAlgebra.meta | 8 - Assets/NanoBrain/LinearAlgebra/.editorconfig | 19 - .../.gitea/workflows/unit_tests.yaml | 37 - Assets/NanoBrain/LinearAlgebra/.gitignore | 5 - .../LinearAlgebra/LinearAlgebra-csharp.sln | 30 - Assets/NanoBrain/LinearAlgebra/src/Angle.cs | 341 -------- .../LinearAlgebra/src/Decomposition.cs | 287 ------- .../NanoBrain/LinearAlgebra/src/Direction.cs | 261 ------- Assets/NanoBrain/LinearAlgebra/src/Float.cs | 41 - .../LinearAlgebra/src/LinearAlgebra.csproj | 14 - Assets/NanoBrain/LinearAlgebra/src/Matrix.cs | 689 ----------------- Assets/NanoBrain/LinearAlgebra/src/Quat32.cs | 87 --- .../NanoBrain/LinearAlgebra/src/Quaternion.cs | 582 -------------- .../NanoBrain/LinearAlgebra/src/Spherical.cs | 279 ------- .../NanoBrain/LinearAlgebra/src/SwingTwist.cs | 136 ---- .../LinearAlgebra/src/Vector2Float.cs | 479 ------------ .../NanoBrain/LinearAlgebra/src/Vector2Int.cs | 185 ----- .../LinearAlgebra/src/Vector3Float.cs | 402 ---------- .../NanoBrain/LinearAlgebra/src/Vector3Int.cs | 273 ------- Assets/NanoBrain/LinearAlgebra/src/float16.cs | 322 -------- .../NanoBrain/LinearAlgebra/test/AngleTest.cs | 501 ------------ .../LinearAlgebra/test/DirectionTest.cs | 226 ------ .../test/LinearAlgebra_Test.csproj | 19 - .../LinearAlgebra/test/QuaternionTest.cs | 185 ----- .../LinearAlgebra/test/SphericalTest.cs | 271 ------- .../LinearAlgebra/test/SwingTwistTest.cs | 131 ---- .../LinearAlgebra/test/Vector2FloatTest.cs | 364 --------- .../LinearAlgebra/test/Vector2IntTest.cs | 270 ------- .../LinearAlgebra/test/Vector3FloatTest.cs | 581 -------------- .../LinearAlgebra/test/Vector3IntTest.cs | 349 --------- Assets/NanoBrain/MemoryCell.cs | 65 -- Assets/NanoBrain/MemoryCell.cs.meta | 2 - .../NanoBrain/NanoBrain-Unity.code-workspace | 12 - .../NanoBrain-Unity.code-workspace.meta | 7 - Assets/NanoBrain/Neuroid.cs | 82 -- Assets/NanoBrain/Neuroid.cs.meta | 2 - Assets/NanoBrain/Neuron.cs | 321 -------- Assets/NanoBrain/Neuron.cs.meta | 2 - Assets/NanoBrain/NucleusArray.cs | 67 -- Assets/NanoBrain/NucleusArray.cs.meta | 2 - Assets/NanoBrain/Perceptoid.cs | 105 --- Assets/NanoBrain/Perceptoid.cs.meta | 2 - Assets/NanoBrain/Receptor.cs | 175 ----- Assets/NanoBrain/Receptor.cs.meta | 2 - Assets/NanoBrain/Scene.meta | 8 - Assets/NanoBrain/Scene/TestScene.unity | 487 ------------ Assets/NanoBrain/Scene/TestScene.unity.meta | 7 - Assets/NanoBrain/Synapse.cs | 22 - Assets/NanoBrain/Synapse.cs.meta | 2 - Assets/NanoBrain/Velocity.asset | 108 --- Assets/NanoBrain/Velocity.asset.meta | 8 - Assets/NanoBrain/VisualEditor.meta | 8 - Assets/NanoBrain/VisualEditor/Editor.meta | 8 - .../VisualEditor/Editor/BrainPickerWindow.cs | 66 -- .../Editor/BrainPickerWindow.cs.meta | 2 - .../VisualEditor/Editor/ClusterInspector.cs | 728 ------------------ .../Editor/ClusterInspector.cs.meta | 2 - .../Editor/NanoBrainComponent_Editor.cs | 129 ---- .../Editor/NanoBrainComponent_Editor.cs.meta | 2 - .../VisualEditor/Editor/NanoBrainEditor.cs | 511 ------------ .../Editor/NanoBrainEditor.cs.meta | 2 - .../VisualEditor/Editor/NanoBrainInspector.cs | 645 ---------------- .../Editor/NanoBrainInspector.cs.meta | 2 - Assets/NanoBrain/VisualEditor/NanoBrain.cs | 102 --- .../NanoBrain/VisualEditor/NanoBrain.cs.meta | 2 - .../VisualEditor/NanoBrainComponent.cs | 35 - .../VisualEditor/NanoBrainComponent.cs.meta | 2 - Assets/NanoBrain/VisualEditor/Resources.meta | 8 - .../VisualEditor/Resources/GraphStyles.uss | 12 - .../Resources/GraphStyles.uss.meta | 11 - 81 files changed, 11922 deletions(-) delete mode 100644 Assets/NanoBrain/Cluster.cs delete mode 100644 Assets/NanoBrain/Cluster.cs.meta delete mode 100644 Assets/NanoBrain/ClusterPrefab.cs delete mode 100644 Assets/NanoBrain/ClusterPrefab.cs.meta delete mode 100644 Assets/NanoBrain/Editor.meta delete mode 100644 Assets/NanoBrain/Editor/NeuroidWindow.cs delete mode 100644 Assets/NanoBrain/Editor/NeuroidWindow.cs.meta delete mode 100644 Assets/NanoBrain/INucleus.cs delete mode 100644 Assets/NanoBrain/INucleus.cs.meta delete mode 100644 Assets/NanoBrain/Identity.asset delete mode 100644 Assets/NanoBrain/Identity.asset.meta delete mode 100644 Assets/NanoBrain/LinearAlgebra.meta delete mode 100644 Assets/NanoBrain/LinearAlgebra/.editorconfig delete mode 100644 Assets/NanoBrain/LinearAlgebra/.gitea/workflows/unit_tests.yaml delete mode 100644 Assets/NanoBrain/LinearAlgebra/.gitignore delete mode 100644 Assets/NanoBrain/LinearAlgebra/LinearAlgebra-csharp.sln delete mode 100644 Assets/NanoBrain/LinearAlgebra/src/Angle.cs delete mode 100644 Assets/NanoBrain/LinearAlgebra/src/Decomposition.cs delete mode 100644 Assets/NanoBrain/LinearAlgebra/src/Direction.cs delete mode 100644 Assets/NanoBrain/LinearAlgebra/src/Float.cs delete mode 100644 Assets/NanoBrain/LinearAlgebra/src/LinearAlgebra.csproj delete mode 100644 Assets/NanoBrain/LinearAlgebra/src/Matrix.cs delete mode 100644 Assets/NanoBrain/LinearAlgebra/src/Quat32.cs delete mode 100644 Assets/NanoBrain/LinearAlgebra/src/Quaternion.cs delete mode 100644 Assets/NanoBrain/LinearAlgebra/src/Spherical.cs delete mode 100644 Assets/NanoBrain/LinearAlgebra/src/SwingTwist.cs delete mode 100644 Assets/NanoBrain/LinearAlgebra/src/Vector2Float.cs delete mode 100644 Assets/NanoBrain/LinearAlgebra/src/Vector2Int.cs delete mode 100644 Assets/NanoBrain/LinearAlgebra/src/Vector3Float.cs delete mode 100644 Assets/NanoBrain/LinearAlgebra/src/Vector3Int.cs delete mode 100644 Assets/NanoBrain/LinearAlgebra/src/float16.cs delete mode 100644 Assets/NanoBrain/LinearAlgebra/test/AngleTest.cs delete mode 100644 Assets/NanoBrain/LinearAlgebra/test/DirectionTest.cs delete mode 100644 Assets/NanoBrain/LinearAlgebra/test/LinearAlgebra_Test.csproj delete mode 100644 Assets/NanoBrain/LinearAlgebra/test/QuaternionTest.cs delete mode 100644 Assets/NanoBrain/LinearAlgebra/test/SphericalTest.cs delete mode 100644 Assets/NanoBrain/LinearAlgebra/test/SwingTwistTest.cs delete mode 100644 Assets/NanoBrain/LinearAlgebra/test/Vector2FloatTest.cs delete mode 100644 Assets/NanoBrain/LinearAlgebra/test/Vector2IntTest.cs delete mode 100644 Assets/NanoBrain/LinearAlgebra/test/Vector3FloatTest.cs delete mode 100644 Assets/NanoBrain/LinearAlgebra/test/Vector3IntTest.cs delete mode 100644 Assets/NanoBrain/MemoryCell.cs delete mode 100644 Assets/NanoBrain/MemoryCell.cs.meta delete mode 100644 Assets/NanoBrain/NanoBrain-Unity.code-workspace delete mode 100644 Assets/NanoBrain/NanoBrain-Unity.code-workspace.meta delete mode 100644 Assets/NanoBrain/Neuroid.cs delete mode 100644 Assets/NanoBrain/Neuroid.cs.meta delete mode 100644 Assets/NanoBrain/Neuron.cs delete mode 100644 Assets/NanoBrain/Neuron.cs.meta delete mode 100644 Assets/NanoBrain/NucleusArray.cs delete mode 100644 Assets/NanoBrain/NucleusArray.cs.meta delete mode 100644 Assets/NanoBrain/Perceptoid.cs delete mode 100644 Assets/NanoBrain/Perceptoid.cs.meta delete mode 100644 Assets/NanoBrain/Receptor.cs delete mode 100644 Assets/NanoBrain/Receptor.cs.meta delete mode 100644 Assets/NanoBrain/Scene.meta delete mode 100644 Assets/NanoBrain/Scene/TestScene.unity delete mode 100644 Assets/NanoBrain/Scene/TestScene.unity.meta delete mode 100644 Assets/NanoBrain/Synapse.cs delete mode 100644 Assets/NanoBrain/Synapse.cs.meta delete mode 100644 Assets/NanoBrain/Velocity.asset delete mode 100644 Assets/NanoBrain/Velocity.asset.meta delete mode 100644 Assets/NanoBrain/VisualEditor.meta delete mode 100644 Assets/NanoBrain/VisualEditor/Editor.meta delete mode 100644 Assets/NanoBrain/VisualEditor/Editor/BrainPickerWindow.cs delete mode 100644 Assets/NanoBrain/VisualEditor/Editor/BrainPickerWindow.cs.meta delete mode 100644 Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs delete mode 100644 Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs.meta delete mode 100644 Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs delete mode 100644 Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs.meta delete mode 100644 Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs delete mode 100644 Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs.meta delete mode 100644 Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs delete mode 100644 Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs.meta delete mode 100644 Assets/NanoBrain/VisualEditor/NanoBrain.cs delete mode 100644 Assets/NanoBrain/VisualEditor/NanoBrain.cs.meta delete mode 100644 Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs delete mode 100644 Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs.meta delete mode 100644 Assets/NanoBrain/VisualEditor/Resources.meta delete mode 100644 Assets/NanoBrain/VisualEditor/Resources/GraphStyles.uss delete mode 100644 Assets/NanoBrain/VisualEditor/Resources/GraphStyles.uss.meta diff --git a/Assets/NanoBrain/Cluster.cs b/Assets/NanoBrain/Cluster.cs deleted file mode 100644 index 44f68ed..0000000 --- a/Assets/NanoBrain/Cluster.cs +++ /dev/null @@ -1,259 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; -using Unity.Mathematics; -using static Unity.Mathematics.math; - -[System.Serializable] -public class Cluster : INucleus { - // The ScriptableObject asset from which the runtime object has been created - public readonly ClusterPrefab prefab; - - public ClusterPrefab cluster { get; set; } - - [SerializeField] - protected string _name; - public virtual string name { - get => _name; - set => _name = value; - } - - // Hmm, a cluster instance can never be part of a scriptable object...(Cluster) - public Cluster(ClusterPrefab parent, ClusterPrefab prefab) { - this.prefab = prefab; - this.cluster = parent; - if (this.cluster != null) - this.cluster.nuclei.Add(this); - - // foreach (IReceptor nucleus in this.prefab.nuclei) { - // IReceptor clone = nucleus.CloneTo(null); - // this.dynamicNuclei.Add(clone); - // } - } - - public virtual IReceptor Clone() { - Neuron clone = new(this.cluster, this.name) { - array = this.array, - }; - - foreach (Synapse synapse in this.synapses) { - Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); - clonedSynapse.weight = synapse.weight; - } - foreach (INucleus receiver in this.receivers) { - clone.AddReceiver(receiver); - } - return clone; - } - - // Not sure if this belongs here... - [SerializeReference] - private NucleusArray _array; - public NucleusArray array { - get { return _array; } - set { _array = value; } - } - - #region Synapses - - // class ClusterSynapse : Synapse { - // public IReceptor receptor; - // public ClusterSynapse(IReceptor nucleus, INucleus receptor, float weight = 1.0f) : base(nucleus, weight) { - // this.receptor = receptor; - // } - // } - [SerializeField] - private List _synapses = new(); - public List synapses => _synapses; - - public Synapse AddSynapse(IReceptor sendingNucleus) { - Synapse synapse = new(sendingNucleus); //, this.prefab.inputs[0]); - this._synapses.Add(synapse); - return synapse; - // else { - // INucleus receptor = (INucleus)this.prefab.nuclei.Find(nucleus => nucleus is INucleus n && nucleus.name == nucleusName); - // ClusterSynapse synapse = new(sendingNucleus, receptor); - // receptor.AddSynapse(sendingNucleus); - // } - // // Add synapse to which neuron? - // return null; - } - - // Does this even exist already? - public void RemoveSynapse() { - - } - - #endregion Synapses - - #region Receivers - - [SerializeReference] - private List _receivers = new(); - public List receivers { - get { return _receivers; } - set { _receivers = value; } - } - - public virtual void AddReceiver(INucleus receivingNucleus) { - this._receivers.Add(receivingNucleus); - receivingNucleus.AddSynapse(this); - } - - public void RemoveReceiver(INucleus receiverNucleus) { - this._receivers.RemoveAll(receiver => receiver == receiverNucleus); - receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); - } - - // public void AddReceiver(INucleus receivingNucleus) { - // int newLength = this._receivers.Count + 1; - // INucleus[] newReceivers = new INucleus[newLength]; - - // // Copy the existing receivers - // for (int ix = 0; ix < this._receivers.Count; ix++) - // newReceivers[ix] = this._receivers[ix]; - // // Add the new receivers - // newReceivers[this._receivers.Count] = receivingNucleus; - // // Replace the receivers with the new receivers - // this._receivers = new(newReceivers); - - // receivingNucleus.AddSynapse(this); - // } - - // public void RemoveReceiver(INucleus receivingNucleus) { - // Debug.Log("Clusterinstance. remote receiver"); - // int newLength = this._receivers.Count - 1; - // if (newLength < 0) - // // Array was empty, so we cannot remove anything - // return; - - // INucleus[] newReceivers = new INucleus[newLength]; - - // int newIx = 0; - // // Copy all receivers except receivingNucleus - // for (int ix = 0; ix < this._receivers.Count; ix++) { - // if (this._receivers[ix] == receivingNucleus) - // // skip the receiver we want to remote - // continue; - - // if (newIx >= newLength) - // // We want to copy more elements than expected - // // the receivingNucleus is not found - // // and the original array is returned - // return; - // newReceivers[newIx] = this._receivers[ix]; - // newIx++; - // } - // this._receivers = new(newReceivers); - // } - - #endregion Receivers - - #region Runtime - - [NonSerialized] - private int stale = 1000; - public bool isSleeping => lengthsq(this.outputValue) == 0; - - [NonSerialized] - protected float3 _outputValue; - public virtual float3 outputValue { - get { return _outputValue; } - set { - this.stale = 0; - _outputValue = value; - } - } - - #region Update - - public virtual void UpdateState() { - UpdateState(new float3(0, 0, 0)); - } - - public void UpdateState(float3 inputValue) { - float3 sum = inputValue; // new(0, 0, 0); - - //Applying the weight factgors - foreach (Synapse synapse in this.synapses) { - sum += synapse.weight * synapse.nucleus.outputValue; - } - - // This does not work because the prefab nucleus does not have a state - this.prefab.inputs[0].UpdateState(sum); - } - - public void UpdateNuclei() { - this.stale++; - if (this.stale > 2) - _outputValue = Vector3.zero; - - foreach (IReceptor nucleus in this.prefab.nuclei) - nucleus.UpdateNuclei(); - } - - #endregion Update - - #endregion Runtime - - /* - [SerializeField] - private List _dynamicNuclei; - public List dynamicNuclei {// = new(); - get { - if (_dynamicNuclei == null) { - this._dynamicNuclei = new(); - foreach (IReceptor nucleus in this.prefab.nuclei) { - IReceptor clone = nucleus.CloneTo(null); - this._dynamicNuclei.Add(clone); - } - } - return this._dynamicNuclei; - } - } - - public List _inputs = null; - public List inputs { - get { - this._inputs = new(); - if (this.dynamicNuclei != null) { - foreach (IReceptor receptor in this.dynamicNuclei) { - if (receptor is INucleus nucleus) - this._inputs.Add(nucleus); - } - } - return this._inputs; - } - } - - public INucleus output => this.dynamicNuclei[0] as INucleus; - - public float3 outputValue => this.output.outputValue; - - - public IReceptor CloneTo(ClusterPrefab parent) { - Cluster clone = new(parent, this.prefab); - return clone; - } - public IReceptor Clone() { - Cluster clone = new(this.cluster, this.prefab); - return clone; - } - - #region Properties - - public string name { - get { return prefab.name; } - set { prefab.name = value; } - } - - public bool isSleeping => lengthsq(this.outputValue) == 0; - - public NucleusArray array { get; set; } - - #endregion Properties - - - */ - -} diff --git a/Assets/NanoBrain/Cluster.cs.meta b/Assets/NanoBrain/Cluster.cs.meta deleted file mode 100644 index a10caff..0000000 --- a/Assets/NanoBrain/Cluster.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: f13cdc4a175a9f379a00317ae68d8bea \ No newline at end of file diff --git a/Assets/NanoBrain/ClusterPrefab.cs b/Assets/NanoBrain/ClusterPrefab.cs deleted file mode 100644 index db65b70..0000000 --- a/Assets/NanoBrain/ClusterPrefab.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System.Collections.Generic; -using UnityEngine; - -[CreateAssetMenu(menuName = "Passer/Cluster")] -public class ClusterPrefab : ScriptableObject { - - //public virtual Cluster cluster {get;set;} - - // The ScriptableObject asset from which the runtime object has been created - //public Cluster asset; - - [SerializeReference] - public List nuclei = new(); - - // public List subClusters = new(); - // public void AddSubCluster(ClusterInstance subCluster) { - // this.nuclei.Add(subCluster); - // } - - public virtual INucleus output => this.nuclei[0] as INucleus; - - public List _inputs = null; - public virtual List inputs { - get { - if (this._inputs == null) { - this._inputs = new(); - foreach (IReceptor receptor in this.nuclei) { - if (receptor is INucleus nucleus) - this._inputs.Add(nucleus); - } - } - return this._inputs; - } - } - - // Call this function to ensure that there is at least one nucleus - // This is an invariant and should be ensured before the nucleus is used - // because output requires it. - public void EnsureInitialization() { - nuclei ??= new List(); - if (nuclei.Count == 0) - new Neuron(this, "Output"); // Every cluster should have at least 1 neuron - } - - public void GarbageCollection() { - HashSet visitedNuclei = new(); - MarkNuclei(visitedNuclei, this.output); - //Debug.Log($"Garbage collection found {visitedNuclei.Count} Nuclei"); - this.nuclei.RemoveAll(nucleus => nucleus is INucleus n && visitedNuclei.Contains(n) == false); - } - - public void MarkNuclei(HashSet visitedNuclei, INucleus nucleus) { - if (nucleus is null) - return; - - visitedNuclei.Add(nucleus); - if (nucleus.synapses != null) { - HashSet visitedSynapses = new(); - foreach (Synapse synapse in nucleus.synapses) { - if (synapse != null && synapse.nucleus != null) { - visitedSynapses.Add(synapse); - if (synapse.nucleus is INucleus synapse_nucleus) - MarkNuclei(visitedNuclei, synapse_nucleus); - } - } - nucleus.synapses.RemoveAll(synapse => visitedSynapses.Contains(synapse) == false); - } - if (nucleus.receivers != null) { - HashSet visitedReceivers = new(); - foreach (INucleus receiver in nucleus.receivers) { - if (receiver != null && receiver != null) { - visitedReceivers.Add(receiver); - visitedNuclei.Add(receiver); - } - } - nucleus.receivers.RemoveAll(receiver => visitedReceivers.Contains(receiver) == false); - } - } - - public virtual void UpdateNuclei() { - foreach (IReceptor nucleus in this.nuclei) - nucleus.UpdateNuclei(); - } -} \ No newline at end of file diff --git a/Assets/NanoBrain/ClusterPrefab.cs.meta b/Assets/NanoBrain/ClusterPrefab.cs.meta deleted file mode 100644 index ee35e0b..0000000 --- a/Assets/NanoBrain/ClusterPrefab.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 60a957541c24c57e78018c202ebb1d9b \ No newline at end of file diff --git a/Assets/NanoBrain/Editor.meta b/Assets/NanoBrain/Editor.meta deleted file mode 100644 index 090b3ac..0000000 --- a/Assets/NanoBrain/Editor.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 3aedf57a50b6dfa46a59457c87b8ef9d -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/NanoBrain/Editor/NeuroidWindow.cs b/Assets/NanoBrain/Editor/NeuroidWindow.cs deleted file mode 100644 index 187df35..0000000 --- a/Assets/NanoBrain/Editor/NeuroidWindow.cs +++ /dev/null @@ -1,302 +0,0 @@ -/* -using UnityEditor; -using UnityEngine; -using System.Linq; -using System.Collections.Generic; - -public class NeuroidLayer { - public int ix = 0; - public List neuroids = new(); -} - -public class GraphEditorWindow : EditorWindow { - private Nucleus currentNucleus; - private List allNeuroids; - private Dictionary neuroidPositions = new(); - - private List layers = new(); - - private void OnEnable() { - EditorApplication.update += EditorUpdate; - Selection.selectionChanged += OnSelectionChange; - SelectNeuron(); - } - - private void AddToLayer(NeuroidLayer layer, Nucleus nucleus) { - layer.neuroids.Add(nucleus); - nucleus.layerIx = layer.ix; - // Store its position - Vector2Int neuroidPosition = new(layer.ix, layer.neuroids.Count - 1); - neuroidPositions[nucleus] = neuroidPosition; - - } - - private void BuildLayers() { - // A temporary list to track what's been added to layers - this.layers = new(); - int layerIx = 0; - - Nucleus selectedNucleus = this.currentNucleus; - if (selectedNucleus == null) - return; - NeuroidLayer currentLayer = new() { ix = layerIx }; - - //foreach (Nucleus outputNeuroid in selectedNucleus.receivers) { - foreach (Receiver receiver in selectedNucleus.receivers) { - Nucleus outputNeuroid = receiver.nucleus; - if (outputNeuroid != null) { - AddToLayer(currentLayer, outputNeuroid); - Debug.Log($"layer {layerIx} nucleus {outputNeuroid.name}"); - } - } - if (currentLayer.neuroids.Count > 0) { - this.layers.Add(currentLayer); - layerIx++; - currentLayer = new() { ix = layerIx }; - } - - AddToLayer(currentLayer, selectedNucleus); - this.layers.Add(currentLayer); - Debug.Log($"layer {layerIx} nucleus {selectedNucleus.name}"); - - layerIx++; - currentLayer = new() { ix = layerIx }; - - int six = 0; - // foreach (Synapse synapse in selectedNucleus.synapses.Values) { - // Debug.Log($"Synapse {six}"); - // Nucleus input = synapse.neuroid; - //foreach ((Nucleus input, Synapse synapse) in selectedNucleus.synapses) { - //foreach ((Nucleus input, float weight) in selectedNucleus.synapses) { - foreach (Synapse synapse in selectedNucleus.synapses) { - Nucleus input = synapse.nucleus; - if (input != null) { - AddToLayer(currentLayer, input); - Debug.Log($"layer {layerIx} nucleus {input.name}"); - } - six++; - } - if (currentLayer.neuroids.Count > 0) { - this.layers.Add(currentLayer); - } - } - - private void BuildLayers_old(List neuroids) { - if (neuroids == null) - return; - - // A temporary list to track what's been added to layers - this.layers = new(); - HashSet neuronVisited = new(); - int layerIx = 0; - - // While there are unvisited neuroid - while (neuroids.Any(neuroid => !neuronVisited.Contains(neuroid))) { - // Create the next layer - NeuroidLayer currentLayer = new() { ix = layerIx }; - int neuroidIx = 0; - - foreach (Neuroid neuroid in neuroids) { - // Skip neurons we already processed - if (neuronVisited.Contains(neuroid)) - continue; - - // if (neuroid.IsStale()) { - // Debug.Log($"neuron {neuroid.name} is stale {neuroid.stale}"); - // neuronVisited.Add(neuroid); - // continue; - // } - - // If the output neuroid is visited - // Note: this does not yet work for multiple outputs yet (see the use of First()) - // if (neuroid.receivers.Count == 0 // make sure the root neuroids are processed directly - // || (neuronVisited.Contains(neuroid.receivers.First()) && neuroid.receivers.First().layerIx == layerIx - 1)) { - if (neuroid.receivers.Count == 0 // make sure the root neuroids are processed directly - || (neuronVisited.Contains(neuroid.receivers.First().nucleus) && neuroid.receivers.First().nucleus.layerIx == layerIx - 1)) { - // Add it to the next layer - currentLayer.neuroids.Add(neuroid); - neuroid.layerIx = layerIx; - // Register it as visited - neuronVisited.Add(neuroid); - // Store its position - Vector2Int neuroidPosition = new(layerIx, neuroidIx); - neuroidPositions[neuroid] = neuroidPosition; - neuroidIx++; - Debug.Log($"Layer {layerIx} neuron {neuroidIx} name {neuroid.name}"); - } - } - - if (currentLayer.neuroids.Count > 0) { - this.layers.Add(currentLayer); - layerIx++; - } - } - } - - private void OnDisable() { - EditorApplication.update -= EditorUpdate; - Selection.selectionChanged -= OnSelectionChange; - } - - private void OnSelectionChange() { - SelectNeuron(); - Repaint(); - } - - private void EditorUpdate() { - if (EditorApplication.isPlaying) - Repaint(); - } - - private void OnGUI() { - GUILayout.Label("Graph Visualizer", EditorStyles.boldLabel); - - DrawGraph(); - } - - private void DrawGraph() { - if (currentNucleus == null) - return; - - foreach (NeuroidLayer layer in layers) - DrawLayer(layer); - } - - private void DrawLayer(NeuroidLayer layer) { - int column = layer.ix * 100; - int nodeCount = layer.neuroids.Count; - float maxValue = 0; - foreach (Nucleus nucleus in layer.neuroids) { - if (nucleus is Neuroid neuroid) { - float value = neuroid.outputValue.magnitude; - if (value > maxValue) - maxValue = value; - } - } - float spacing = 400f / nodeCount; - float margin = 100 + spacing / 2; - foreach (Nucleus layerNucleus in layer.neuroids) { - if (layerNucleus is Neuroid layerNeuroid) { - Vector2Int layerNeuroidPos = this.neuroidPositions[layerNeuroid]; - Vector3 parentPos = new(100 + layerNeuroidPos.x * 100, margin + layerNeuroidPos.y * spacing, 0.1f); - - int i = 0; - float inputSpacing = 400f / layerNeuroid.synapses.Count; - float inputMargin = 100 + inputSpacing / 2; - // foreach (Synapse synapse in layerNeuroid.synapses.Values) { - // if (synapse.neuroid != null) { - // if (this.neuroidPositions.ContainsKey(synapse.neuroid)) { - - // Vector2Int inputNeuroidPos = this.neuroidPositions[synapse.neuroid]; - //foreach ((Nucleus neuroid, Synapse synapse) in layerNeuroid.synapses) { - //foreach ((Nucleus neuroid, float weight) in layerNeuroid.synapses) { - foreach (Synapse synapse in layerNeuroid.synapses) { - Nucleus neuroid = synapse.nucleus; - float weight = synapse.weight; - if (neuroid != null) { - if (this.neuroidPositions.ContainsKey(neuroid)) { - Vector2Int inputNeuroidPos = this.neuroidPositions[neuroid]; - if (inputNeuroidPos.x == layerNeuroidPos.x + 1) { - Vector3 pos = new(100 + inputNeuroidPos.x * 100, inputMargin + inputNeuroidPos.y * inputSpacing, 0.0f); - - //float brightness = synapse.weight / 10.0f; - float brightness = weight / 10.0f; - Handles.color = new Color(brightness, brightness, brightness); - Handles.DrawLine(parentPos, pos); - } - } - } - } - - float size = 20; - if (layerNeuroid.isSleeping) - Handles.color = Color.black; - else { - float brightness = layerNeuroid.outputValue.magnitude / maxValue; - Handles.color = new Color(brightness, brightness, brightness); - } - Handles.DrawSolidDisc(parentPos, Vector3.forward, size); - Vector3 labelPos = parentPos - Vector3.down * (size + 0.2f); // below disc along up axis - GUIStyle style = new GUIStyle(EditorStyles.label) { - alignment = TextAnchor.UpperCenter, - normal = { textColor = Color.white }, - fontStyle = FontStyle.Bold - }; - Handles.Label(labelPos, layerNeuroid.name, style); - - Rect neuronRect = new(parentPos.x - size, parentPos.y - size, size * 2, size * 2); - Event e = Event.current; - if (e != null && neuronRect.Contains(e.mousePosition)) { - HandleMouseHover(layerNeuroid, neuronRect); - // Process click - if (e.type == EventType.MouseDown && e.button == 0) { - // Consume the event so the scene doesn't also handle it - e.Use(); - HandleDiscClicked(layerNeuroid); - } - } - i++; - } - } - } - - private void HandleMouseHover(Neuroid neuroid, Rect rect) { - GUIContent tooltip; - // if (neuroid is SensoryNeuroid sensoryNeuroid) { - // tooltip = new( - // $"{sensoryNeuroid.name}" + - // $"\nThing {sensoryNeuroid.receptor.thingType}" + - // $"\nValue: {neuroid.outputValue}"); - // } - // else { - tooltip = new( - $"{neuroid.name}" + - $"\nsynapse count {neuroid.synapses.Count}" + - $"\nValue: {neuroid.outputValue}"); - // } - - Vector2 mousePosition = Event.current.mousePosition; - - // Display tooltip with some offset - Vector2 tooltipSize = GUI.skin.box.CalcSize(tooltip); - Rect tooltipRect = new Rect(mousePosition.x + 10, mousePosition.y + 10, tooltipSize.x, tooltipSize.y); - - GUI.Box(tooltipRect, tooltip); - } - - private void HandleDiscClicked(Nucleus nucleus) { - this.currentNucleus = nucleus; - BuildLayers(); - } - - // Update node colors based on selected GameObjects - private void SelectNeuron() { - GameObject[] selectedObjects = Selection.gameObjects; - if (selectedObjects.Length == 0) - return; - - GameObject selectedObject = selectedObjects[0]; - Boid boid = selectedObject.GetComponent(); - if (boid == null) - return; - - // Nucleus neuroid = boid.behaviour; - // this.currentNucleus = neuroid; - // if (neuroid == null) - // this.allNeuroids = new(); - // else - // this.allNeuroids = neuroid.brain.neuroids; - - - // Debug.Log($"Neuroncount = {this.allNeuroids.Count}"); - // BuildLayers(); - // Debug.Log($"Layercount = {this.layers.Count}"); - - } - - [MenuItem("Window/Neuroid Visualizer")] - public static void ShowWindow() { - GetWindow("Neuroid Visualizer"); - } -} -*/ \ No newline at end of file diff --git a/Assets/NanoBrain/Editor/NeuroidWindow.cs.meta b/Assets/NanoBrain/Editor/NeuroidWindow.cs.meta deleted file mode 100644 index a8a1aa1..0000000 --- a/Assets/NanoBrain/Editor/NeuroidWindow.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 26e68838038ea5243ae57bc81f4db8a8 \ No newline at end of file diff --git a/Assets/NanoBrain/INucleus.cs b/Assets/NanoBrain/INucleus.cs deleted file mode 100644 index f7272f3..0000000 --- a/Assets/NanoBrain/INucleus.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System.Collections.Generic; -using Unity.Mathematics; - -public interface INucleus : IReceptor { - - #region static struct - - // Cluster - public ClusterPrefab cluster { get; } - - // Senders - public List synapses { get; } - public Synapse AddSynapse(IReceptor sender); - - public NucleusArray array { get; set; } - - #endregion static struct - - #region dynamic state - - public void UpdateState(); - public void UpdateState(float3 inputValue); - - - #endregion dynamic state -} - -public interface IReceptor { - #region static - - public string name { get; set; } - - // Receivers - public List receivers { get; set; } - - public void AddReceiver(INucleus receiver); - public void RemoveReceiver(INucleus receiverNucleus); - - #endregion static - - #region dynamic - - // float3 to prepare for SIMD - public float3 outputValue { get; } - - public void UpdateNuclei(); - public bool isSleeping { get; } - - #endregion dynamic - - //public IReceptor CloneTo(ClusterPrefab parent); - public IReceptor Clone(); -} - diff --git a/Assets/NanoBrain/INucleus.cs.meta b/Assets/NanoBrain/INucleus.cs.meta deleted file mode 100644 index aed95bb..0000000 --- a/Assets/NanoBrain/INucleus.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 6a8a0e8965cea660abff254cab8a4723 \ No newline at end of file diff --git a/Assets/NanoBrain/Identity.asset b/Assets/NanoBrain/Identity.asset deleted file mode 100644 index 076c284..0000000 --- a/Assets/NanoBrain/Identity.asset +++ /dev/null @@ -1,60 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3} - m_Name: Identity - m_EditorClassIdentifier: Assembly-CSharp::Cluster - nuclei: - - rid: 2243601383627161705 - references: - version: 2 - RefIds: - - rid: 2243601383627161705 - type: {class: Neuron, ns: , asm: Assembly-CSharp} - data: - _name: Output - _synapses: [] - _receivers: [] - _array: - rid: 2243601383627161706 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 1 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1000 - value: 1000 - inSlope: 1 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - - rid: 2243601383627161706 - type: {class: NucleusArray, ns: , asm: Assembly-CSharp} - data: - _nuclei: - - rid: 2243601383627161705 - name: Output diff --git a/Assets/NanoBrain/Identity.asset.meta b/Assets/NanoBrain/Identity.asset.meta deleted file mode 100644 index b2382a6..0000000 --- a/Assets/NanoBrain/Identity.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 5f4d2ea0d0115b3549f8e9aa5e669163 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/NanoBrain/LinearAlgebra.meta b/Assets/NanoBrain/LinearAlgebra.meta deleted file mode 100644 index c54c1af..0000000 --- a/Assets/NanoBrain/LinearAlgebra.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: d98555a675e8e5e879de17db950b55fe -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/NanoBrain/LinearAlgebra/.editorconfig b/Assets/NanoBrain/LinearAlgebra/.editorconfig deleted file mode 100644 index 1ec7f97..0000000 --- a/Assets/NanoBrain/LinearAlgebra/.editorconfig +++ /dev/null @@ -1,19 +0,0 @@ -# EditorConfig is awesome: https://EditorConfig.org - -# top-most EditorConfig file -root = true - -[*] -indent_style = space -indent_size = 4 -end_of_line = crlf -charset = utf-8 -trim_trailing_whitespace = false -insert_final_newline = false -max_line_length = 80 - -[*.cs] -csharp_new_line_before_open_brace = none -# Suppress warnings everywhere -dotnet_diagnostic.IDE1006.severity = none -dotnet_diagnostic.IDE0130.severity = none \ No newline at end of file diff --git a/Assets/NanoBrain/LinearAlgebra/.gitea/workflows/unit_tests.yaml b/Assets/NanoBrain/LinearAlgebra/.gitea/workflows/unit_tests.yaml deleted file mode 100644 index e98b26e..0000000 --- a/Assets/NanoBrain/LinearAlgebra/.gitea/workflows/unit_tests.yaml +++ /dev/null @@ -1,37 +0,0 @@ -name: Build and Run C# Unit Tests - -on: - push: - branches: - - '**' - pull_request: - branches: - - '**' - -jobs: - build-and-test: - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v2 - - - name: Setup .NET - uses: actions/setup-dotnet@v1 - with: - dotnet-version: '8.0.x' # Specify the .NET SDK version - - - name: Check Current Directory - run: pwd # Logs the current working directory - - - name: List Files - run: ls -la # Lists all files in the current directory - - - name: Restore Dependencies - run: dotnet restore ./LinearAlgebra-csharp.sln # Restore NuGet packages - - - name: Build the Project - run: dotnet build ./LinearAlgebra-csharp.sln --configuration Release # Build the C# project - - - name: Run Unit Tests - run: dotnet test ./test/LinearAlgebra_Test.csproj --configuration Release # Execute unit tests diff --git a/Assets/NanoBrain/LinearAlgebra/.gitignore b/Assets/NanoBrain/LinearAlgebra/.gitignore deleted file mode 100644 index b32a30c..0000000 --- a/Assets/NanoBrain/LinearAlgebra/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -DoxyGen/DoxyWarnLogfile.txt -.vscode/settings.json -**bin -**obj -**.meta diff --git a/Assets/NanoBrain/LinearAlgebra/LinearAlgebra-csharp.sln b/Assets/NanoBrain/LinearAlgebra/LinearAlgebra-csharp.sln deleted file mode 100644 index 4b13b2b..0000000 --- a/Assets/NanoBrain/LinearAlgebra/LinearAlgebra-csharp.sln +++ /dev/null @@ -1,30 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.5.2.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LinearAlgebra", "src\LinearAlgebra.csproj", "{ECB58727-0354-924D-AE7B-22F6B21097EB}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LinearAlgebra_Test", "test\LinearAlgebra_Test.csproj", "{715BB399-5FC4-2AC9-3757-177CA0C80774}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {ECB58727-0354-924D-AE7B-22F6B21097EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {ECB58727-0354-924D-AE7B-22F6B21097EB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {ECB58727-0354-924D-AE7B-22F6B21097EB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {ECB58727-0354-924D-AE7B-22F6B21097EB}.Release|Any CPU.Build.0 = Release|Any CPU - {715BB399-5FC4-2AC9-3757-177CA0C80774}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {715BB399-5FC4-2AC9-3757-177CA0C80774}.Debug|Any CPU.Build.0 = Debug|Any CPU - {715BB399-5FC4-2AC9-3757-177CA0C80774}.Release|Any CPU.ActiveCfg = Release|Any CPU - {715BB399-5FC4-2AC9-3757-177CA0C80774}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {E93B8294-87D4-4887-83B7-182A623D5833} - EndGlobalSection -EndGlobal diff --git a/Assets/NanoBrain/LinearAlgebra/src/Angle.cs b/Assets/NanoBrain/LinearAlgebra/src/Angle.cs deleted file mode 100644 index 7d2fd6b..0000000 --- a/Assets/NanoBrain/LinearAlgebra/src/Angle.cs +++ /dev/null @@ -1,341 +0,0 @@ -using System; - -namespace LinearAlgebra { - - public struct AngleFloat { - public const float Rad2Deg = 360.0f / ((float)Math.PI * 2); //0.0174532924F; - public const float Deg2Rad = (float)Math.PI * 2 / 360.0f; //57.29578F; - - private AngleFloat(float degrees) { - this.value = degrees; - } - private readonly float value; - - public static AngleFloat Degrees(float degrees) { - // Reduce it to (-180..180] - if (float.IsFinite(degrees)) { - while (degrees < -180) - degrees += 360; - while (degrees >= 180) - degrees -= 360; - } - return new AngleFloat(degrees); - } - - public static AngleFloat Radians(float radians) { - // Reduce it to (-pi..pi] - if (float.IsFinite(radians)) { - while (radians <= -Math.PI) - radians += 2 * (float)Math.PI; - while (radians > Math.PI) - radians -= 2 * (float)Math.PI; - } - - return new AngleFloat(radians * Rad2Deg); - } - - public static AngleFloat Revolutions(float revolutions) { - // reduce it to (-0.5 .. 0.5] - if (float.IsFinite(revolutions)) { - // Get the integer part - int integerPart = (int)revolutions; - - // Get the decimal part - revolutions -= integerPart; - if (revolutions < -0.5) - revolutions += 1; - if (revolutions >= 0.5) - revolutions -= 1; - } - return new AngleFloat(revolutions * 360); - } - - public readonly float inDegrees => this.value; - - public readonly float inRadians => this.value * Deg2Rad; - - public readonly float inRevolutions => this.value / 360.0f; - - public override string ToString() { - return $"{this.inDegrees}\u00B0"; - } - - public static readonly AngleFloat zero = Degrees(0); - public static readonly AngleFloat deg90 = Degrees(90); - public static readonly AngleFloat deg180 = Degrees(180); - - /// - /// Get the sign of the angle - /// - /// The angle - /// -1 when the angle is negative, 1 when it is positive and 0 in all other cases - public static int Sign(AngleFloat a) { - if (a.value < 0) - return -1; - if (a.value > 0) - return 1; - return 0; - } - - /// - /// Returns the magnitude of the angle - /// - /// The angle - /// The positive magnitude of the angle - /// Negative values are negated to get a positive result - public static AngleFloat Abs(AngleFloat a) { - if (Sign(a) < 0) - return -a; - else - return a; - } - - /// - /// Tests the equality of two angles - /// - /// - /// - /// True when the angles are equal, false otherwise - /// The equality is determine within the limits of precision of a float - public static bool operator ==(AngleFloat a1, AngleFloat a2) { - return a1.value == a2.value; - } - - /// - /// Tests the inequality of two angles - /// - /// - /// - /// True when the angles are not equal, false otherwise - /// The equality is determine within the limits of precision of a float - public static bool operator !=(AngleFloat a1, AngleFloat a2) { - return a1.value != a2.value; - } - - public override readonly bool Equals(object obj) { - if (obj is AngleFloat other) { - return this == other; - } - return false; - } - - public override readonly int GetHashCode() { - return this.value.GetHashCode(); - } - - - /// - /// Tests if the first angle is greater than the second - /// - /// - /// - /// True when a1 is greater than a2, False otherwise - public static bool operator >(AngleFloat a1, AngleFloat a2) { - return a1.value > a2.value; - } - - /// - /// Tests if the first angle is greater than or equal to the second - /// - /// - /// - /// True when a1 is greater than or equal to a2, False otherwise - public static bool operator >=(AngleFloat a1, AngleFloat a2) { - return a1.value >= a2.value; - } - - /// - /// Tests if the first angle is less than the second - /// - /// - /// - /// True when a1 is less than a2, False otherwise - public static bool operator <(AngleFloat a1, AngleFloat a2) { - return a1.value < a2.value; - } - - /// - /// Tests if the first angle is less than or equal to the second - /// - /// - /// - /// True when a1 is less than or equal to a2, False otherwise - public static bool operator <=(AngleFloat a1, AngleFloat a2) { - return a1.value <= a2.value; - } - - /// - /// Negate the angle - /// - /// The angle - /// The negated angle - /// The negation of -180 is still -180 because the range is (-180..180] - public static AngleFloat operator -(AngleFloat a) { - AngleFloat r = new(-a.value); - return r; - } - - /// - /// Subtract two angles - /// - /// Angle 1 - /// Angle 2 - /// The result of the subtraction - public static AngleFloat operator -(AngleFloat a1, AngleFloat a2) { - AngleFloat r = new(a1.value - a2.value); - return r; - } - /// - /// Add two angles - /// - /// Angle 1 - /// Angle 2 - /// The result of the addition - public static AngleFloat operator +(AngleFloat a1, AngleFloat a2) { - AngleFloat r = new(a1.value + a2.value); - return r; - } - - /// - /// Multiplies the angle - /// - /// The angle to multiply - /// The factor by which the angle is multiplied - /// The multiplied angle - public static AngleFloat operator *(AngleFloat a, float factor) { - return Degrees(a.inDegrees * factor); - } - public static AngleFloat operator *(float factor, AngleFloat a) { - return Degrees(factor * a.inDegrees); - } - - /// - /// Clamp the angle between the given min and max values - /// - /// The angle to clamp - /// The minimum angle - /// The maximum angle - /// The clamped angle - /// Angles are normalized - public static float Clamp(AngleFloat angle, AngleFloat min, AngleFloat max) { - return Float.Clamp(angle.inDegrees, min.inDegrees, max.inDegrees); - } - - /// @brief Calculates the cosine of an angle - /// @param angle The given angle - /// @return The cosine of the angle - public static float Cos(AngleFloat angle) { - return MathF.Cos(angle.inRadians); - } - /// @brief Calculates the sine of an angle - /// @param angle The given angle - /// @return The sine of the angle - public static float Sin(AngleFloat angle) { - return MathF.Sin(angle.inRadians); - } - /// @brief Calculates the tangent of an angle - /// @param angle The given angle - /// @return The tangent of the angle - public static float Tan(AngleFloat angle) { - return MathF.Tan(angle.inRadians); - } - - /// @brief Calculates the arc cosine angle - /// @param f The value - /// @return The arc cosine for the given value - public static AngleFloat Acos(float f) { - return Radians(MathF.Acos(f)); - } - /// @brief Calculates the arc sine angle - /// @param f The value - /// @return The arc sine for the given value - public static AngleFloat Asin(float f) { - return Radians(MathF.Asin(f)); - } - /// @brief Calculates the arc tangent angle - /// @param f The value - /// @return The arc tangent for the given value - public static AngleFloat Atan(float f) { - return Radians(MathF.Atan(f)); - } - /// @brief Calculates the tangent for the given values - /// @param y The vertical value - /// @param x The horizontal value - /// @return The tanget for the given values - /// Uses the y and x signs to compute the quadrant - public static AngleFloat Atan2(float y, float x) { - return Radians(MathF.Atan2(y, x)); - } - - /// - /// Rotate from one angle to the other with a maximum degrees - /// - /// Starting angle - /// Target angle - /// Maximum angle to rotate - /// The resulting angle - /// This function is compatible with radian and degrees angles - public static AngleFloat MoveTowards(AngleFloat fromAngle, AngleFloat toAngle, float maxDegrees) { - maxDegrees = Math.Max(0, maxDegrees); // filter out negative distances - AngleFloat d = toAngle - fromAngle; - float dDegrees = Abs(d).inDegrees; - d = Degrees(Float.Clamp(dDegrees, 0, maxDegrees)); - if (Sign(d) < 0) - d = -d; - return fromAngle + d; - } - } - - - /// - /// %Angle utilities - /// - public static class Angles { - public const float pi = 3.1415927410125732421875F; - // public static float Rad2Deg = 360.0f / ((float)Math.PI * 2); - // public static float Deg2Rad = ((float)Math.PI * 2) / 360.0f; - - - /// - /// Determine the angle difference, result is a normalized angle - /// - /// First first angle - /// The second angle - /// the angle between the two angles - /// Angle values should be degrees - public static float Difference(float a, float b) { - float r = Normalize(b - a); - return r; - } - - /// - /// Normalize an angle to the range -180 < angle <= 180 - /// - /// The angle to normalize - /// The normalized angle in interval (-180..180] - /// Angle values should be in degrees - public static float Normalize(float angle) { - if (float.IsInfinity(angle)) - return angle; - - while (angle <= -180) angle += 360; - while (angle > 180) angle -= 360; - return angle; - } - - /// - /// Map interval of angles between vectors [0..Pi] to interval [0..1] - /// - /// The first vector - /// The second vector - /// The resulting factor in interval [0..1] - /// Vectors a and b must be normalized - /// \deprecated Please use Vector2.ToFactor instead. - // [Obsolete("Please use Vector2.ToFactor instead.")] - // public static float ToFactor(Vector2Float v1, Vector2Float v2) { - // return (1 - Vector2Float.Dot(v1, v2)) / 2; - // } - - } - -} \ No newline at end of file diff --git a/Assets/NanoBrain/LinearAlgebra/src/Decomposition.cs b/Assets/NanoBrain/LinearAlgebra/src/Decomposition.cs deleted file mode 100644 index ddaf434..0000000 --- a/Assets/NanoBrain/LinearAlgebra/src/Decomposition.cs +++ /dev/null @@ -1,287 +0,0 @@ -using System; -namespace LinearAlgebra { - class QR { - // QR Decomposition of a matrix A - public static (Matrix2 Q, Matrix2 R) Decomposition(Matrix2 A) { - int nRows = A.nRows; - int nCols = A.nCols; - - float[,] Q = new float[nRows, nCols]; - float[,] R = new float[nCols, nCols]; - - // Perform Gram-Schmidt orthogonalization - for (uint colIx = 0; colIx < nCols; colIx++) { - - // Step 1: v = column(ix) of A - float[] v = new float[nRows]; - for (int rowIx = 0; rowIx < nRows; rowIx++) - v[rowIx] = A.data[rowIx, colIx]; - - // Step 2: Subtract projections of v onto previous q's (orthogonalize) - for (uint colIx2 = 0; colIx2 < colIx; colIx2++) { - float dotProd = 0; - for (int i = 0; i < nRows; i++) - dotProd += Q[i, colIx2] * v[i]; - for (int i = 0; i < nRows; i++) - v[i] -= dotProd * Q[i, colIx2]; - } - - // Step 3: Normalize v to get column(ix) of Q - float norm = 0; - for (int rowIx = 0; rowIx < nRows; rowIx++) - norm += v[rowIx] * v[rowIx]; - norm = (float)Math.Sqrt(norm); - - for (int rowIx = 0; rowIx < nRows; rowIx++) - Q[rowIx, colIx] = v[rowIx] / norm; - - // Store the coefficients of R - for (int colIx2 = 0; colIx2 <= colIx; colIx2++) { - R[colIx2, colIx] = 0; - for (int k = 0; k < nRows; k++) - R[colIx2, colIx] += Q[k, colIx2] * A.data[k, colIx]; - } - } - return (new Matrix2(Q), new Matrix2(R)); - } - - // Reduced QR Decomposition of a matrix A - public static (Matrix2 Q, Matrix2 R) ReducedDecomposition(Matrix2 A) { - int nRows = A.nRows; - int nCols = A.nCols; - - float[,] Q = new float[nRows, nCols]; - float[,] R = new float[nCols, nCols]; - - // Perform Gram-Schmidt orthogonalization - for (int colIx = 0; colIx < nCols; colIx++) { - - // Step 1: v = column(colIx) of A - float[] columnIx = new float[nRows]; - bool isZeroColumn = true; - for (int rowIx = 0; rowIx < nRows; rowIx++) { - columnIx[rowIx] = A.data[rowIx, colIx]; - if (columnIx[rowIx] != 0) - isZeroColumn = false; - } - if (isZeroColumn) { - for (int rowIx = 0; rowIx < nRows; rowIx++) - Q[rowIx, colIx] = 0; - // Set corresponding R element to 0 - R[colIx, colIx] = 0; - - Console.WriteLine($"zero column {colIx}"); - - continue; - } - - // Step 2: Subtract projections of v onto previous q's (orthogonalize) - for (int colIx2 = 0; colIx2 < colIx; colIx2++) { - // Compute the dot product of v and column(colIx2) of Q - float dotProduct = 0; - for (int rowIx2 = 0; rowIx2 < nRows; rowIx2++) - dotProduct += columnIx[rowIx2] * Q[rowIx2, colIx2]; - // Subtract the projection from v - for (int rowIx2 = 0; rowIx2 < nRows; rowIx2++) - columnIx[rowIx2] -= dotProduct * Q[rowIx2, colIx2]; - } - - // Step 3: Normalize v to get column(colIx) of Q - float norm = 0; - for (int rowIx = 0; rowIx < nRows; rowIx++) - norm += columnIx[rowIx] * columnIx[rowIx]; - if (norm == 0) - throw new Exception("invalid value"); - - norm = (float)Math.Sqrt(norm); - - for (int rowIx = 0; rowIx < nRows; rowIx++) - Q[rowIx, colIx] = columnIx[rowIx] / norm; - - // Here is where it deviates from the Full QR Decomposition ! - - // Step 4: Compute the row(colIx) of R - for (int colIx2 = colIx; colIx2 < nCols; colIx2++) { - float dotProduct = 0; - for (int rowIx2 = 0; rowIx2 < nRows; rowIx2++) - dotProduct += Q[rowIx2, colIx] * A.data[rowIx2, colIx2]; - R[colIx, colIx2] = dotProduct; - } - } - if (!float.IsFinite(R[0, 0])) - throw new Exception("invalid value"); - - return (new Matrix2(Q), new Matrix2(R)); - } - } - - class SVD { - // According to ChatGPT, Mathnet uses Golub-Reinsch SVD algorithm - // 1. Bidiagonalization: The input matrix AA is reduced to a bidiagonal form using Golub-Kahan bidiagonalization. - // This process involves applying a sequence of Householder reflections to AA to create a bidiagonal matrix. - // This step reduces the complexity by making the matrix simpler while retaining the essential structure needed for SVD. - // - // 2. Diagonalization: Once the matrix is in bidiagonal form, - // the singular values are computed using an iterative process - // (typically involving QR factorization or Jacobi rotations) until convergence. - // This process diagonalizes the bidiagonal matrix and allows extraction of the singular values. - // - // 3. Computing UU and VTVT: After obtaining the singular values, - // the left singular vectors UU and right singular vectors VTVT are computed - // using the accumulated transformations (such as Householder reflections) from the bidiagonalization step. - - // Bidiagnolizations through Householder transformations - public static (Matrix2 U1, Matrix2 B, Matrix2 V1) Bidiagonalization(Matrix2 A) { - int m = A.nRows; // Rows of A - int n = A.nCols; // Columns of A - float[,] U1 = new float[m, m]; // Left orthogonal matrix - float[,] V1 = new float[n, n]; // Right orthogonal matrix - float[,] B = A.Clone().data; // Copy A to B for transformation - - // Initialize U1 and V1 as identity matrices - for (int i = 0; i < m; i++) - U1[i, i] = 1; - for (int i = 0; i < n; i++) - V1[i, i] = 1; - - // Perform Householder reflections to create a bidiagonal matrix B - for (int j = 0; j < n; j++) { - // Step 1: Construct the Householder vector y - float[] y = new float[m - j]; - for (int i = j; i < m; i++) - y[i - j] = B[i, j]; - - // Step 2: Compute the norm and scalar alpha - float norm = 0; - for (int i = 0; i < y.Length; i++) - norm += y[i] * y[i]; - norm = (float)Math.Sqrt(norm); - - if (B[j, j] > 0) - norm = -norm; - - float alpha = (float)Math.Sqrt(0.5 * (norm * (norm - B[j, j]))); - float r = (float)Math.Sqrt(0.5 * (norm * (norm + B[j, j]))); - - // Step 3: Apply the reflection to zero out below diagonal - for (int k = j; k < n; k++) { - float dot = 0; - for (int i = j; i < m; i++) - dot += y[i - j] * B[i, k]; - dot /= r; - - for (int i = j; i < m; i++) - B[i, k] -= 2 * dot * y[i - j]; - } - - // Step 4: Update U1 with the Householder reflection (U1 * Householder) - for (int i = j; i < m; i++) - U1[i, j] = y[i - j] / alpha; - - // Step 5: Update V1 (storing the Householder vector y) - // Correct indexing: we only need to store part of y in V1 from index j to n - for (int i = j; i < n; i++) - V1[j, i] = B[j, i]; - - // Repeat steps for further columns if necessary - } - return (new Matrix2(U1), new Matrix2(B), new Matrix2(V1)); - } - - public static Matrix2 Bidiagonalize(Matrix2 A) { - int m = A.nRows; // Rows of A - int n = A.nCols; // Columns of A - float[,] B = A.Clone().data; // Copy A to B for transformation - - // Perform Householder reflections to create a bidiagonal matrix B - for (int j = 0; j < n; j++) { - // Step 1: Construct the Householder vector y - float[] y = new float[m - j]; - for (int i = j; i < m; i++) - y[i - j] = B[i, j]; - - // Step 2: Compute the norm and scalar alpha - float norm = 0; - for (int i = 0; i < y.Length; i++) - norm += y[i] * y[i]; - norm = (float)Math.Sqrt(norm); - - if (B[j, j] > 0) - norm = -norm; - - float r = (float)Math.Sqrt(0.5 * (norm * (norm + B[j, j]))); - - // Step 3: Apply the reflection to zero out below diagonal - for (int k = j; k < n; k++) { - float dot = 0; - for (int i = j; i < m; i++) - dot += y[i - j] * B[i, k]; - dot /= r; - - for (int i = j; i < m; i++) - B[i, k] -= 2 * dot * y[i - j]; - } - - // Repeat steps for further columns if necessary - } - return new Matrix2(B); - } - - // QR Iteration for diagonalization of a bidiagonal matrix B - public static (Matrix1 singularValues, Matrix2 U, Matrix2 Vt) QRIteration(Matrix2 B) { - int m = B.nRows; - int n = B.nCols; - - Matrix2 U = new(m, m); // Left singular vectors (U) - Matrix2 Vt = new(n, n); // Right singular vectors (V^T) - float[] singularValues = new float[Math.Min(m, n)]; // Singular values - - // Initialize U and Vt as identity matrices - for (int i = 0; i < m; i++) - U.data[i, i] = 1; - for (int i = 0; i < n; i++) - Vt.data[i, i] = 1; - - // Perform QR iterations - float tolerance = 1e-7f; //1e-12f; for double - bool converged = false; - while (!converged) { - // Perform QR decomposition on the matrix B - (Matrix2 Q, Matrix2 R) = QR.Decomposition(B); - - // Update B to be the product Q * R //R * Q - B = R * Q; - - // Accumulate the transformations in U and Vt - U *= Q; - Vt *= R; - - // Check convergence by looking at the off-diagonal elements of B - converged = true; - for (int i = 0; i < m - 1; i++) { - for (int j = i + 1; j < n; j++) { - if (Math.Abs(B.data[i, j]) > tolerance) { - converged = false; - break; - } - } - } - } - - // Extract singular values (diagonal elements of B) - for (int i = 0; i < Math.Min(m, n); i++) - singularValues[i] = B.data[i, i]; - - return (new Matrix1(singularValues), U, Vt); - } - - public static (Matrix2 U, Matrix1 S, Matrix2 Vt) Decomposition(Matrix2 A) { - if (A.nRows != A.nCols) - throw new ArgumentException("SVD: matrix A has to be square."); - - Matrix2 B = Bidiagonalize(A); - (Matrix1 S, Matrix2 U, Matrix2 Vt) = QRIteration(B); - return (U, S, Vt); - } - } -} \ No newline at end of file diff --git a/Assets/NanoBrain/LinearAlgebra/src/Direction.cs b/Assets/NanoBrain/LinearAlgebra/src/Direction.cs deleted file mode 100644 index fd25b98..0000000 --- a/Assets/NanoBrain/LinearAlgebra/src/Direction.cs +++ /dev/null @@ -1,261 +0,0 @@ -using System; -#if UNITY_5_3_OR_NEWER -using Vector3Float = UnityEngine.Vector3; -#endif - -namespace LinearAlgebra -{ - - /// - /// A direction in 3D space - /// - /// A direction is represented using two angles: - /// * The horizontal angle ranging from -180 (inclusive) to 180 (exclusive) - /// degrees which is a rotation in the horizontal plane - /// * A vertical angle ranging from -90 (inclusive) to 90 (exclusive) degrees - /// which is the rotation in the up/down direction applied after the horizontal - /// rotation has been applied. - /// The angles are automatically normalized to stay within the abovenmentioned - /// ranges. - public struct Direction - { - /// @brief horizontal angle, range = (-180..180] degrees - public AngleFloat horizontal; - /// @brief vertical angle, range in degrees = (-90..90] degrees - public AngleFloat vertical; - - /// - /// Create a new direction - /// - /// The horizontal angle - /// The vertical angle - /// The direction will be normalized automatically - /// to ensure the angles are within the allowed ranges - public Direction(AngleFloat horizontal, AngleFloat vertical) - { - this.horizontal = horizontal; - this.vertical = vertical; - this.Normalize(); - } - - /// - /// Create a direction using angle values in degrees - /// - /// The horizontal angle in degrees - /// The vertical angle in degrees - /// The direction - /// The direction will be normalized automatically - /// to ensure the angles are within the allowed ranges - public static Direction Degrees(float horizontal, float vertical) - { - Direction d = new() - { - horizontal = AngleFloat.Degrees(horizontal), - vertical = AngleFloat.Degrees(vertical) - }; - d.Normalize(); - return d; - } - /// - /// Create a direction using angle values in radians - /// - /// The horizontal angle in radians - /// The vertical angle in radians - /// The direction - public static Direction Radians(float horizontal, float vertical) - { - Direction d = new() - { - horizontal = AngleFloat.Radians(horizontal), - vertical = AngleFloat.Radians(vertical) - }; - d.Normalize(); - return d; - } - - public override readonly string ToString() { - return $"Direction(h: {this.horizontal}, v: {this.vertical})"; - } - - /// - /// A forward direction with zero for both angles - /// - public readonly static Direction forward = Degrees(0, 0); - /// - /// A backward direction with horizontal angle -180 and zero vertical - /// angle - /// - public readonly static Direction backward = Degrees(-180, 0); - /// - /// A upward direction with zero horizontal angle and vertical angle 90 - /// - public readonly static Direction up = Degrees(0, 90); - /// - /// A downward direction with zero horizontal angle and vertical angle - /// -90 - /// - public readonly static Direction down = Degrees(0, -90); - /// - /// A left-pointing direction with horizontal angle -90 and zero - /// vertical angle - /// - public readonly static Direction left = Degrees(-90, 0); - /// - /// A right-pointing direction with horizontal angle 90 and zero - /// vertical angle - /// - public readonly static Direction right = Degrees(90, 0); - - private void Normalize() - { - if (this.vertical > AngleFloat.deg90 || this.vertical < -AngleFloat.deg90) - { - this.horizontal += AngleFloat.deg180; - this.vertical = AngleFloat.Degrees(180 - this.vertical.inDegrees); - } - } - -#if UNITY_5_3_OR_NEWER - /// - /// Convert the direction into a carthesian vector - /// - /// The carthesian vector corresponding to this direction. - public readonly UnityEngine.Vector3 ToVector3() { - // Convert degrees to radians - float radH = this.horizontal.inRadians; - float radV = this.vertical.inRadians; - - // Calculate Vector - float cosV = MathF.Cos(radV); - float sinV = MathF.Sin(radV); - - float x = cosV * MathF.Sin(radH); - float y = sinV; - float z = cosV * MathF.Cos(radH); - - return new UnityEngine.Vector3(x, y, z); - } - - /// - /// Convert a carthesian vector into a direction - /// - /// The carthesian vector - /// The direction - /// Information about the length of the carthesian vector is not - /// included in this transformation - public static Direction FromVector3(UnityEngine.Vector3 v) { - AngleFloat horizontal = AngleFloat.Atan2(v.x, v.z); - AngleFloat vertical = AngleFloat.deg90 - AngleFloat.Acos(v.y); - Direction d = new(horizontal, vertical); - return d; - } -#else - /// - /// Convert the direction into a carthesian vector - /// - /// The carthesian vector corresponding to this direction. - public readonly Vector3Float ToVector3() { - // Quaternion q = Quaternion.Euler(90 - this.vertical.inDegrees, this.horizontal.inDegrees, 0); - // Vector3Float v = q * Vector3Float.forward; - // return v; - - float radH = this.horizontal.inRadians; - float radV = this.vertical.inRadians; - - float cosV = MathF.Cos(radV); - float sinV = MathF.Sin(radV); - - float horizontal = cosV * MathF.Sin(radH); - float vertical = sinV; - float depth = cosV * MathF.Cos(radH); - - return new Vector3Float(horizontal, vertical, depth); - } - - /// - /// Convert a carthesian vector into a direction - /// - /// The carthesian vector - /// The direction - /// Information about the length of the carthesian vector is not - /// included in this transformation - public static Direction FromVector3(Vector3Float v) - { - AngleFloat horizontal = AngleFloat.Atan2(v.horizontal, v.depth); - AngleFloat vertical = AngleFloat.deg90 - AngleFloat.Acos(v.vertical); - Direction d = new(horizontal, vertical); - return d; - } -#endif - - public static Direction operator -(Direction d) { - AngleFloat horizontal = d.horizontal + AngleFloat.deg180; - AngleFloat vertical = -d.vertical; - return new Direction(horizontal, vertical); - } - - /// - /// Tests the equality of two directions - /// - /// - /// - /// True when the direction angles are equal, false otherwise. - public static bool operator ==(Direction d1, Direction d2) - { - bool horizontalEq = d1.horizontal == d2.horizontal; - bool verticalEq = d1.vertical == d2.vertical; - return horizontalEq && verticalEq; - } - - /// - /// Tests the inequality of two directions - /// - /// - /// - /// True when the direction angles are not equal, false otherwise. - public static bool operator !=(Direction d1, Direction d2) - { - bool horizontalNEq = d1.horizontal != d2.horizontal; - bool verticalNEq = d1.vertical != d2.vertical; - return horizontalNEq || verticalNEq; - } - - public override readonly bool Equals(object obj) - { - if (obj is not Direction d) - return false; - - bool horizontalEq = this.horizontal == d.horizontal; - bool verticalEq = this.vertical == d.vertical; - return horizontalEq && verticalEq; - } - - - public override readonly int GetHashCode() - { - return HashCode.Combine(horizontal, vertical); - } - - public static AngleFloat UnsignedAngle(Direction d1, Direction d2) { - // Convert angles from degrees to radians - float horizontal1Rad = d1.horizontal.inRadians; - float vertical1Rad = d1.vertical.inRadians; - - float horizontal2Rad = d2.horizontal.inRadians; - float vertical2Rad = d2.vertical.inRadians; - - // Calculate the cosine of the angle using the spherical law of cosines - float cosTheta = MathF.Sin(vertical1Rad) * MathF.Sin(vertical2Rad) + - MathF.Cos(vertical1Rad) * MathF.Cos(vertical2Rad) * - MathF.Cos(horizontal1Rad - horizontal2Rad); - - // Clip cosTheta to the valid range for acos - cosTheta = Float.Clamp(cosTheta, -1.0f, 1.0f); - - // Calculate the angle - AngleFloat angle = AngleFloat.Acos(cosTheta); - return angle; - } - } - -} \ No newline at end of file diff --git a/Assets/NanoBrain/LinearAlgebra/src/Float.cs b/Assets/NanoBrain/LinearAlgebra/src/Float.cs deleted file mode 100644 index 2217b84..0000000 --- a/Assets/NanoBrain/LinearAlgebra/src/Float.cs +++ /dev/null @@ -1,41 +0,0 @@ -namespace LinearAlgebra { - - /// - /// Float number utilities - /// - public class Float { - /// - /// The precision of float numbers - /// - public const float epsilon = 1E-05f; - /// - /// The square of the float number precision - /// - public const float sqrEpsilon = 1e-10f; - - /// - /// Clamp the value between the given minimum and maximum values - /// - /// The value to clamp - /// The minimum value - /// The maximum value - /// The clamped value - public static float Clamp(float f, float min, float max) { - if (f < min) - return min; - if (f > max) - return max; - return f; - } - - /// - /// Clamp the value between to the interval [0..1] - /// - /// The value to clamp - /// The clamped value - public static float Clamp01(float f) { - return Clamp(f, 0, 1); - } - } - -} \ No newline at end of file diff --git a/Assets/NanoBrain/LinearAlgebra/src/LinearAlgebra.csproj b/Assets/NanoBrain/LinearAlgebra/src/LinearAlgebra.csproj deleted file mode 100644 index d2d5a85..0000000 --- a/Assets/NanoBrain/LinearAlgebra/src/LinearAlgebra.csproj +++ /dev/null @@ -1,14 +0,0 @@ - - - - false - false - net8.0 - - - - - - - - diff --git a/Assets/NanoBrain/LinearAlgebra/src/Matrix.cs b/Assets/NanoBrain/LinearAlgebra/src/Matrix.cs deleted file mode 100644 index 37c6c24..0000000 --- a/Assets/NanoBrain/LinearAlgebra/src/Matrix.cs +++ /dev/null @@ -1,689 +0,0 @@ -using System; -#if UNITY_5_3_OR_NEWER -using Vector3Float = UnityEngine.Vector3; -using Vector2Float = UnityEngine.Vector2; -using Quaternion = UnityEngine.Quaternion; -#endif - -namespace LinearAlgebra { - - public readonly struct Slice - { - public int start { get; } - public int stop { get; } - public Slice(int start, int stop) - { - this.start = start; - this.stop = stop; - } - } - - public class Matrix2 { - public float[,] data { get; } - - public int nRows => data.GetLength(0); - public int nCols => data.GetLength(1); - - public Matrix2(int nRows, int nCols) - { - this.data = new float[nRows, nCols]; - } - public Matrix2(float[,] data) { - this.data = data; - } - - public Matrix2 Clone() { - float[,] data = new float[this.nRows, nCols]; - for (int rowIx = 0; rowIx < this.nRows; rowIx++) { - for (int colIx = 0; colIx < this.nCols; colIx++) - data[rowIx, colIx] = this.data[rowIx, colIx]; - } - return new Matrix2(data); - } - - public static Matrix2 Zero(int nRows, int nCols) - { - return new Matrix2(nRows, nCols); - } - - public static Matrix2 FromVector3(Vector3Float v) { - float[,] result = new float[3, 1]; - result[0, 0] = v.horizontal; - result[1, 0] = v.vertical; - result[2, 0] = v.depth; - return new Matrix2(result); - } - - public static Matrix2 Identity(int size) - { - return Diagonal(1, size); - } - public static Matrix2 Identity(int nRows, int nCols) - { - Matrix2 m = Zero(nRows, nCols); - m.FillDiagonal(1); - return m; - } - - public static Matrix2 Diagonal(Matrix1 v) { - float[,] resultData = new float[v.size, v.size]; - for (int ix = 0; ix < v.size; ix++) - resultData[ix, ix] = v.data[ix]; - return new Matrix2(resultData); - } - public static Matrix2 Diagonal(float f, int size) - { - float[,] resultData = new float[size, size]; - for (int ix = 0; ix < size; ix++) - resultData[ix, ix] = f; - return new Matrix2(resultData); - } - public void FillDiagonal(Matrix1 v) - { - int n = (int)Math.Min(Math.Min(this.nRows, this.nCols), v.size); - for (int ix = 0; ix < n; ix++) - this.data[ix, ix] = v.data[ix]; - } - public void FillDiagonal(float f) - { - int n = Math.Min(this.nRows, this.nCols); - for (int ix = 0; ix < n; ix++) - this.data[ix, ix] = f; - } - - public static Matrix2 SkewMatrix(Vector3Float v) { - float[,] result = new float[3, 3] { - {0, -v.depth, v.vertical}, - {v.depth, 0, -v.horizontal}, - {-v.vertical, v.horizontal, 0} - }; - return new Matrix2(result); - } - - public Matrix1 GetRow(int rowIx) { - float[] row = new float[this.nCols]; - for (int colIx = 0; colIx < this.nCols; colIx++) { - row[colIx] = this.data[rowIx, colIx]; - } - return new Matrix1(row); - } - -#if UNITY_5_3_OR_NEWER - public UnityEngine.Vector3 GetRow3(int rowIx) { - int cols = this.nCols; - UnityEngine.Vector3 row = new() { - x = this.data[rowIx, 0], - y = this.data[rowIx, 1], - z = this.data[rowIx, 2] - }; - return row; - } -#endif - public void SetRow(int rowIx, Matrix1 v) { - for (uint ix = 0; ix < v.size; ix++) - this.data[rowIx, ix] = v.data[ix]; - } - public void SetRow3(int rowIx, Vector3Float v) { - this.data[rowIx, 0] = v.horizontal; - this.data[rowIx, 1] = v.vertical; - this.data[rowIx, 2] = v.depth; - } - - public void SwapRows(int row1, int row2) { - for (uint ix = 0; ix < this.nCols; ix++) { - float temp = this.data[row1, ix]; - this.data[row1, ix] = this.data[row2, ix]; - this.data[row2, ix] = temp; - } - } - - public Matrix1 GetColumn(int colIx) - { - float[] column = new float[this.nRows]; - for (int i = 0; i < this.nRows; i++) { - column[i] = this.data[i, colIx]; - } - return new Matrix1(column); - } - public void SetColumn(int colIx, Matrix1 v) { - for (uint ix = 0; ix < v.size; ix++) - this.data[ix, colIx] = v.data[ix]; - } - public void SetColumn(int colIx, Vector3Float v) { - this.data[0, colIx] = v.horizontal; - this.data[1, colIx] = v.vertical; - this.data[2, colIx] = v.depth; - } - - public static bool AllClose(Matrix2 A, Matrix2 B, float atol = 1e-08f) { - for (int i = 0; i < A.nRows; i++) { - for (int j = 0; j < A.nCols; j++) { - float d = MathF.Abs(A.data[i, j] - B.data[i, j]); - if (d > atol) - return false; - } - } - return true; - } - - public Matrix2 Transpose() { - float[,] resultData = new float[this.nCols, this.nRows]; - for (uint rowIx = 0; rowIx < this.nRows; rowIx++) { - for (uint colIx = 0; colIx < this.nCols; colIx++) - resultData[colIx, rowIx] = this.data[rowIx, colIx]; - } - return new Matrix2(resultData); - // double checked code - } - public Matrix2 transposed { - get => Transpose(); - } - - public static Matrix2 operator -(Matrix2 m) { - float[,] result = new float[m.nRows, m.nCols]; - - for (int i = 0; i < m.nRows; i++) { - for (int j = 0; j < m.nCols; j++) - result[i, j] = -m.data[i, j]; - } - return new Matrix2(result); - } - - public static Matrix2 operator -(Matrix2 A, Matrix2 B) { - if (A.nRows != B.nRows || A.nCols != B.nCols) - throw new System.ArgumentException("Size of A must match size of B."); - - float[,] result = new float[A.nRows, B.nCols]; - - for (int i = 0; i < A.nRows; i++) { - for (int j = 0; j < A.nCols; j++) - result[i, j] = A.data[i, j] - B.data[i, j]; - } - return new Matrix2(result); - } - - public static Matrix2 operator +(Matrix2 A, Matrix2 B) { - if (A.nRows != B.nRows || A.nCols != B.nCols) - throw new System.ArgumentException("Size of A must match size of B."); - - float[,] result = new float[A.nRows, B.nCols]; - - for (int i = 0; i < A.nRows; i++) { - for (int j = 0; j < A.nCols; j++) - result[i, j] = A.data[i, j] + B.data[i, j]; - } - return new Matrix2(result); - } - - public static Matrix2 operator *(Matrix2 A, Matrix2 B) { - if (A.nCols != B.nRows) - throw new System.ArgumentException("Number of columns in A must match number of rows in B."); - - float[,] result = new float[A.nRows, B.nCols]; - - for (int i = 0; i < A.nRows; i++) { - for (int j = 0; j < B.nCols; j++) { - float sum = 0.0f; - for (int k = 0; k < A.nCols; k++) - sum += A.data[i, k] * B.data[k, j]; - - result[i, j] = sum; - } - } - - return new Matrix2(result); - // double checked code - } - - public static Matrix1 operator *(Matrix2 A, Matrix1 v) { - float[] result = new float[A.nRows]; - - for (int i = 0; i < A.nRows; i++) { - for (int j = 0; j < A.nCols; j++) { - result[i] += A.data[i, j] * v.data[j]; - } - } - - return new Matrix1(result); - } - - public static Vector3Float operator *(Matrix2 A, Vector3Float v) { - return new Vector3Float( - A.data[0, 0] * v.horizontal + A.data[0, 1] * v.vertical + A.data[0, 2] * v.depth, - A.data[1, 0] * v.horizontal + A.data[1, 1] * v.vertical + A.data[1, 2] * v.depth, - A.data[2, 0] * v.horizontal + A.data[2, 1] * v.vertical + A.data[2, 2] * v.depth - ); - } - - public static Matrix2 operator *(Matrix2 A, float s) { - float[,] result = new float[A.nRows, A.nCols]; - - for (int i = 0; i < A.nRows; i++) { - for (int j = 0; j < A.nCols; j++) - result[i, j] = A.data[i, j] * s; - } - - return new Matrix2(result); - } - public static Matrix2 operator *(float s, Matrix2 A) { - return A * s; - } - - public static Matrix2 operator /(Matrix2 A, float s) { - float[,] result = new float[A.nRows, A.nCols]; - - for (int i = 0; i < A.nRows; i++) { - for (int j = 0; j < A.nCols; j++) - result[i, j] = A.data[i, j] / s; - } - - return new Matrix2(result); - } - public static Matrix2 operator /(float s, Matrix2 A) { - float[,] result = new float[A.nRows, A.nCols]; - - for (int i = 0; i < A.nRows; i++) { - for (int j = 0; j < A.nCols; j++) - result[i, j] = s / A.data[i, j]; - } - - return new Matrix2(result); - } - - public Matrix2 GetRows(Slice slice) { - return GetRows(slice.start, slice.stop); - } - public Matrix2 GetRows(int from, int to) { - if (from < 0 || to >= this.nRows) - throw new System.ArgumentException("Slice index out of range."); - - float[,] result = new float[to - from, this.nCols]; - int resultRowIx = 0; - for (int rowIx = from; rowIx < to; rowIx++) { - for (int colIx = 0; colIx < this.nCols; colIx++) - result[resultRowIx, colIx] = this.data[rowIx, colIx]; - - resultRowIx++; - } - - return new Matrix2(result); - } - - public Matrix2 Slice(Slice slice) - { - return Slice(slice.start, slice.stop); - } - public Matrix2 Slice(int from, int to) - { - if (from < 0 || to >= this.nRows) - throw new System.ArgumentException("Slice index out of range."); - - float[,] result = new float[to - from, this.nCols]; - int resultRowIx = 0; - for (int rowIx = from; rowIx < to; rowIx++) - { - for (int colIx = 0; colIx < this.nCols; colIx++) - { - result[resultRowIx, colIx] = this.data[rowIx, colIx]; - } - resultRowIx++; - } - - return new Matrix2(result); - } - public Matrix2 Slice(Slice rowRange, Slice colRange) { - return Slice((rowRange.start, rowRange.stop), (colRange.start, colRange.stop)); - } - public Matrix2 Slice((int start, int stop) rowRange, (int start, int stop) colRange) - { - float[,] result = new float[rowRange.stop - rowRange.start, colRange.stop - colRange.start]; - - int resultRowIx = 0; - int resultColIx = 0; - for (int i = rowRange.start; i < rowRange.stop; i++) - { - for (int j = colRange.start; j < colRange.stop; j++) - result[resultRowIx, resultColIx] = this.data[i, j]; - } - return new Matrix2(result); - } - - public void UpdateSlice(Slice slice, Matrix2 m) { - UpdateSlice((slice.start, slice.stop), m); - } - public void UpdateSlice((int start, int stop) slice, Matrix2 m) { - // if (slice.start == slice.stop) - // Console.WriteLine("WARNING: no data is updates when start equals stop in a slice!"); - int mRowIx = 0; - for (int rowIx = slice.start; rowIx < slice.stop; rowIx++, mRowIx++) { - for (int colIx = 0; colIx < this.nCols; colIx++) - this.data[rowIx, colIx] = m.data[mRowIx, colIx]; - } - } - - public void UpdateSlice(Slice rowRange, Slice colRange, Matrix2 m) - { - UpdateSlice((rowRange.start, rowRange.stop), (colRange.start, colRange.stop), m); - } - public void UpdateSlice((int start, int stop) rowRange, (int start, int stop) colRange, Matrix2 m) - { - for (int i = rowRange.start; i < rowRange.stop; i++) - { - for (int j = colRange.start; j < colRange.stop; j++) - this.data[i, j] = m.data[i - rowRange.start, j - colRange.start]; - } - } - - public Matrix2 Inverse() { - Matrix2 A = this; - // unchecked - int n = A.nRows; - - // Create an identity matrix of the same size as the original matrix - float[,] augmentedMatrix = new float[n, 2 * n]; - for (int i = 0; i < n; i++) { - for (int j = 0; j < n; j++) { - augmentedMatrix[i, j] = A.data[i, j]; - augmentedMatrix[i, j + n] = (i == j) ? 1 : 0; // Identity matrix - } - } - - // Perform Gaussian elimination - for (int i = 0; i < n; i++) { - // Find the pivot row - float pivot = augmentedMatrix[i, i]; - if (Math.Abs(pivot) < 1e-10) // Check for singular matrix - throw new InvalidOperationException("Matrix is singular and cannot be inverted."); - - // Normalize the pivot row - for (int j = 0; j < 2 * n; j++) - augmentedMatrix[i, j] /= pivot; - - // Eliminate the column below the pivot - for (int j = i + 1; j < n; j++) { - float factor = augmentedMatrix[j, i]; - for (int k = 0; k < 2 * n; k++) - augmentedMatrix[j, k] -= factor * augmentedMatrix[i, k]; - } - } - - // Back substitution - for (int i = n - 1; i >= 0; i--) - { - // Eliminate the column above the pivot - for (int j = i - 1; j >= 0; j--) - { - float factor = augmentedMatrix[j, i]; - for (int k = 0; k < 2 * n; k++) - augmentedMatrix[j, k] -= factor * augmentedMatrix[i, k]; - } - } - - // Extract the inverse matrix from the augmented matrix - float[,] inverse = new float[n, n]; - for (int i = 0; i < n; i++) { - for (int j = 0; j < n; j++) - inverse[i, j] = augmentedMatrix[i, j + n]; - } - - return new Matrix2(inverse); - } - - public float Determinant() - { - int n = this.nRows; - if (n != this.nCols) - throw new System.ArgumentException("Matrix must be square."); - - if (n == 1) - return this.data[0, 0]; // Base case for 1x1 matrix - - if (n == 2) // Base case for 2x2 matrix - return this.data[0, 0] * this.data[1, 1] - this.data[0, 1] * this.data[1, 0]; - - float det = 0; - for (int col = 0; col < n; col++) - det += (col % 2 == 0 ? 1 : -1) * this.data[0, col] * this.Minor(0, col).Determinant(); - - return det; - } - - // Helper function to compute the minor of a matrix - private Matrix2 Minor(int rowToRemove, int colToRemove) - { - int n = this.nRows; - float[,] minor = new float[n - 1, n - 1]; - - int r = 0, c = 0; - for (int i = 0; i < n; i++) { - if (i == rowToRemove) continue; - - c = 0; - for (int j = 0; j < n; j++) { - if (j == colToRemove) continue; - - minor[r, c] = this.data[i, j]; - c++; - } - r++; - } - - return new Matrix2(minor); - } - - public static Matrix2 DeleteRows(Matrix2 A, Slice rowRange) { - float[,] result = new float[A.nRows - (rowRange.stop - rowRange.start), A.nCols]; - - int resultRowIx = 0; - for (int i = 0; i < A.nRows; i++) { - if (i >= rowRange.start && i < rowRange.stop) - continue; - - for (int j = 0; j < A.nCols; j++) - result[resultRowIx, j] = A.data[i, j]; - - resultRowIx++; - } - return new Matrix2(result); - } - - internal static Matrix2 DeleteColumns(Matrix2 A, Slice colRange) { - float[,] result = new float[A.nRows, A.nCols - (colRange.stop - colRange.start)]; - - for (int i = 0; i < A.nRows; i++) { - int resultColIx = 0; - for (int j = 0; j < A.nCols; j++) { - if (j >= colRange.start && j < colRange.stop) - continue; - - result[i, resultColIx++] = A.data[i, j]; - } - } - return new Matrix2(result); - } - } - - public class Matrix1 - { - public float[] data { get; } - - public int size => data.GetLength(0); - - public Matrix1(int size) - { - this.data = new float[size]; - } - - public Matrix1(float[] data) { - this.data = data; - } - - public static Matrix1 Zero(int size) - { - return new Matrix1(size); - } - - public static Matrix1 FromVector2(Vector2Float v) { - float[] result = new float[2]; - result[0] = v.horizontal; - result[1] = v.vertical; - return new Matrix1(result); - } - - public static Matrix1 FromVector3(Vector3Float v) { - float[] result = new float[3]; - result[0] = v.horizontal; - result[1] = v.vertical; - result[2] = v.depth; - return new Matrix1(result); - } - -#if UNITY_5_3_OR_NEWER - public static Matrix1 FromQuaternion(Quaternion q) { - float[] result = new float[4]; - result[0] = q.x; - result[1] = q.y; - result[2] = q.z; - result[3] = q.w; - return new Matrix1(result); - } -#endif - - public Vector2Float vector2 { - get { - if (this.size != 2) - throw new System.ArgumentException("Matrix1 must be of size 2"); - return new Vector2Float(this.data[0], this.data[1]); - } - } - public Vector3Float vector3 { - get { - if (this.size != 3) - throw new System.ArgumentException("Matrix1 must be of size 3"); - return new Vector3Float(this.data[0], this.data[1], this.data[2]); - } - } - -#if UNITY_5_3_OR_NEWER - public Quaternion quaternion { - get { - if (this.size != 4) - throw new System.ArgumentException("Matrix1 must be of size 4"); - return new Quaternion(this.data[0], this.data[1], this.data[2], this.data[3]); - } - } -#endif - - public Matrix1 Clone() { - float[] data = new float[this.size]; - for (int rowIx = 0; rowIx < this.size; rowIx++) - data[rowIx] = this.data[rowIx]; - return new Matrix1(data); - } - - - public float magnitude { - get { - float sum = 0; - foreach (var elm in data) - sum += elm; - return sum / data.Length; - } - } - public static Matrix1 operator +(Matrix1 A, Matrix1 B) { - if (A.size != B.size) - throw new System.ArgumentException("Size of A must match size of B."); - - float[] result = new float[A.size]; - - for (int i = 0; i < A.size; i++) { - result[i] = A.data[i] + B.data[i]; - } - return new Matrix1(result); - } - - public Matrix2 Transpose() { - float[,] r = new float[1, this.size]; - for (uint colIx = 0; colIx < this.size; colIx++) - r[1, colIx] = this.data[colIx]; - - return new Matrix2(r); - } - - public static float Dot(Matrix1 a, Matrix1 b) { - if (a.size != b.size) - throw new System.ArgumentException("Vectors must be of the same length."); - - float result = 0.0f; - for (int i = 0; i < a.size; i++) { - result += a.data[i] * b.data[i]; - } - return result; - } - - public static Matrix1 operator -(Matrix1 A, Matrix1 B) { - if (A.size != B.size) - throw new System.ArgumentException("Size of A must match size of B."); - - float[] result = new float[A.size]; - - for (int i = 0; i < A.size; i++) { - result[i] = A.data[i] - B.data[i]; - } - return new Matrix1(result); - } - - public static Matrix1 operator *(Matrix1 A, float f) - { - float[] result = new float[A.size]; - - for (int i = 0; i < A.size; i++) - result[i] += A.data[i] * f; - - return new Matrix1(result); - } - public static Matrix1 operator *(float f, Matrix1 A) { - return A * f; - } - - public static Matrix1 operator /(Matrix1 A, float f) { - float[] result = new float[A.size]; - - for (int i = 0; i < A.size; i++) - result[i] = A.data[i] / f; - - return new Matrix1(result); - } - public static Matrix1 operator /(float f, Matrix1 A) { - float[] result = new float[A.size]; - - for (int i = 0; i < A.size; i++) - result[i] = f / A.data[i]; - - return new Matrix1(result); - } - - public Matrix1 Slice(Slice range) - { - return Slice(range.start, range.stop); - } - public Matrix1 Slice(int from, int to) - { - if (from < 0 || to >= this.size) - throw new System.ArgumentException("Slice index out of range."); - - float[] result = new float[to - from]; - int resultIx = 0; - for (int ix = from; ix < to; ix++) - result[resultIx++] = this.data[ix]; - - return new Matrix1(result); - } - public void UpdateSlice(Slice slice, Matrix1 v) { - int vIx = 0; - for (int ix = slice.start; ix < slice.stop; ix++, vIx++) - this.data[ix] = v.data[vIx]; - } - } - -} \ No newline at end of file diff --git a/Assets/NanoBrain/LinearAlgebra/src/Quat32.cs b/Assets/NanoBrain/LinearAlgebra/src/Quat32.cs deleted file mode 100644 index 19ee9bc..0000000 --- a/Assets/NanoBrain/LinearAlgebra/src/Quat32.cs +++ /dev/null @@ -1,87 +0,0 @@ -using System; - -namespace LinearAlgebra { - public class Quat32 { - public float x; - public float y; - public float z; - public float w; - - public Quat32() { - this.x = 0; - this.y = 0; - this.z = 0; - this.w = 1; - } - - public Quat32(float x, float y, float z, float w) { - this.x = x; - this.y = y; - this.z = z; - this.w = w; - } - - public static Quat32 FromSwingTwist(SwingTwist s) { - Quat32 q32 = Quat32.Euler(-s.swing.vertical.inDegrees, s.swing.horizontal.inDegrees, s.twist.inDegrees); - return q32; - } - - public static Quat32 Euler(float yaw, float pitch, float roll) { - float rollOver2 = roll * AngleFloat.Deg2Rad * 0.5f; - float sinRollOver2 = (float)Math.Sin((float)rollOver2); - float cosRollOver2 = (float)Math.Cos((float)rollOver2); - float pitchOver2 = pitch * 0.5f; - float sinPitchOver2 = (float)Math.Sin((float)pitchOver2); - float cosPitchOver2 = (float)Math.Cos((float)pitchOver2); - float yawOver2 = yaw * 0.5f; - float sinYawOver2 = (float)Math.Sin((float)yawOver2); - float cosYawOver2 = (float)Math.Cos((float)yawOver2); - Quat32 result = new Quat32() { - w = cosYawOver2 * cosPitchOver2 * cosRollOver2 + - sinYawOver2 * sinPitchOver2 * sinRollOver2, - x = sinYawOver2 * cosPitchOver2 * cosRollOver2 + - cosYawOver2 * sinPitchOver2 * sinRollOver2, - y = cosYawOver2 * sinPitchOver2 * cosRollOver2 - - sinYawOver2 * cosPitchOver2 * sinRollOver2, - z = cosYawOver2 * cosPitchOver2 * sinRollOver2 - - sinYawOver2 * sinPitchOver2 * cosRollOver2 - }; - return result; - } - - public void ToAngles(out float right, out float up, out float forward) { - float test = this.x * this.y + this.z * this.w; - if (test > 0.499f) { // singularity at north pole - right = 0; - up = 2 * (float)Math.Atan2(this.x, this.w) * AngleFloat.Rad2Deg; - forward = 90; - return; - //return Vector3(0, 2 * (float)atan2(this.x, this.w) * Angle.Rad2Deg, 90); - } - else if (test < -0.499f) { // singularity at south pole - right = 0; - up = -2 * (float)Math.Atan2(this.x, this.w) * AngleFloat.Rad2Deg; - forward = -90; - return; - //return Vector3(0, -2 * (float)atan2(this.x, this.w) * Angle.Rad2Deg, -90); - } - else { - float sqx = this.x * this.x; - float sqy = this.y * this.y; - float sqz = this.z * this.z; - - right = (float)Math.Atan2(2 * this.x * this.w - 2 * this.y * this.z, 1 - 2 * sqx - 2 * sqz) * AngleFloat.Rad2Deg; - up = (float)Math.Atan2(2 * this.y * this.w - 2 * this.x * this.z, 1 - 2 * sqy - 2 * sqz) * AngleFloat.Rad2Deg; - forward = (float)Math.Asin(2 * test) * AngleFloat.Rad2Deg; - return; - // return Vector3( - // atan2f(2 * this.x * this.w - 2 * this.y * this.z, 1 - 2 * sqx - 2 * sqz) * - // Rad2Deg, - // atan2f(2 * this.y * this.w - 2 * this.x * this.z, 1 - 2 * sqy - 2 * sqz) * - // Rad2Deg, - // asinf(2 * test) * Angle.Rad2Deg); - } - } - - } -} \ No newline at end of file diff --git a/Assets/NanoBrain/LinearAlgebra/src/Quaternion.cs b/Assets/NanoBrain/LinearAlgebra/src/Quaternion.cs deleted file mode 100644 index 7936843..0000000 --- a/Assets/NanoBrain/LinearAlgebra/src/Quaternion.cs +++ /dev/null @@ -1,582 +0,0 @@ -using System; -#if UNITY_5_3_OR_NEWER -using Quaternion = UnityEngine.Quaternion; -#endif - -namespace LinearAlgebra { - -#if UNITY_5_3_OR_NEWER - public class QuaternionExtensions { - public static Quaternion Reflect(Quaternion q) { - return new(-q.x, -q.y, -q.z, q.w); - } - - public static Matrix2 ToRotationMatrix(Quaternion q) { - float w = q.x, x = q.y, y = q.z, z = q.w; - - float[,] result = new float[,] - { - { 1 - 2 * (y * y + z * z), 2 * (x * y - w * z), 2 * (x * z + w * y) }, - { 2 * (x * y + w * z), 1 - 2 * (x * x + z * z), 2 * (y * z - w * x) }, - { 2 * (x * z - w * y), 2 * (y * z + w * x), 1 - 2 * (x * x + y * y) } - }; - return new Matrix2(result); - } - - public static Quaternion FromRotationMatrix(Matrix2 m) { - float trace = m.data[0, 0] + m.data[1, 1] + m.data[2, 2]; - float w, x, y, z; - - if (trace > 0) { - float s = 0.5f / (float)Math.Sqrt(trace + 1.0f); - w = 0.25f / s; - x = (m.data[2, 1] - m.data[1, 2]) * s; - y = (m.data[0, 2] - m.data[2, 0]) * s; - z = (m.data[1, 0] - m.data[0, 1]) * s; - } - else { - if (m.data[0, 0] > m.data[1, 1] && m.data[0, 0] > m.data[2, 2]) { - float s = 2.0f * (float)Math.Sqrt(1.0f + m.data[0, 0] - m.data[1, 1] - m.data[2, 2]); - w = (m.data[2, 1] - m.data[1, 2]) / s; - x = 0.25f * s; - y = (m.data[0, 1] + m.data[1, 0]) / s; - z = (m.data[0, 2] + m.data[2, 0]) / s; - } - else if (m.data[1, 1] > m.data[2, 2]) { - float s = 2.0f * (float)Math.Sqrt(1.0f + m.data[1, 1] - m.data[0, 0] - m.data[2, 2]); - w = (m.data[0, 2] - m.data[2, 0]) / s; - x = (m.data[0, 1] + m.data[1, 0]) / s; - y = 0.25f * s; - z = (m.data[1, 2] + m.data[2, 1]) / s; - } - else { - float s = 2.0f * (float)Math.Sqrt(1.0f + m.data[2, 2] - m.data[0, 0] - m.data[1, 1]); - w = (m.data[1, 0] - m.data[0, 1]) / s; - x = (m.data[0, 2] + m.data[2, 0]) / s; - y = (m.data[1, 2] + m.data[2, 1]) / s; - z = 0.25f * s; - } - } - - return new Quaternion(x, y, z, w); - } - } -#else - public struct Quaternion { - public float x; - public float y; - public float z; - public float w; - - /// - /// create a new quaternion with the given values - /// - /// x component - /// y component - /// z component - /// w component - public Quaternion(float x, float y, float z, float w) { - this.x = x; - this.y = y; - this.z = z; - this.w = w; - } - - /// - /// An identity quaternion - /// - public static readonly Quaternion identity = new(0, 0, 0, 1); - - private readonly Vector3Float xyz => new(x, y, z); - - private readonly float magnitude => MathF.Sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w); - - private readonly float sqrMagnitude => x * x + y * y + z * z + w * w; - - /// - /// Convert to unit quaternion - /// - /// This will preserve the orientation, - /// but ensures that it is a unit quaternion. - public readonly Quaternion normalized { - get { - float length = this.magnitude; - Quaternion q = new(this.x / length, this.y / length, this.z / length, this.w / length); - return q; - } - } - - /// - /// Convert to unity quaternion - /// - /// The quaternion to convert - /// A unit quaternion - /// This will preserve the orientation, - /// but ensures that it is a unit quaternion. - public static Quaternion Normalize(Quaternion q) { - return q.normalized; - } - - /// - /// Convert to euler angles - /// - /// The quaternion to convert - /// A vector containing euler angles - /// The euler angles performed in the order: Z, X, Y - public static Vector3Float ToAngles(Quaternion q) { - // Extract Euler angles in Unity order (X = pitch, Y = yaw, Z = roll), returned in degrees as (x,pitch),(y,yaw),(z,roll) - // Handle singularities/gimbal lock - float test = 2f * (q.w * q.x - q.y * q.z); - // clamp - if (test >= 1f) test = 1f; - if (test <= -1f) test = -1f; - - float pitch = MathF.Asin(test); // X - - float roll = MathF.Atan2(2f * (q.w * q.z + q.x * q.y), - 1f - 2f * (q.x * q.x + q.z * q.z)); // Z - - float yaw = MathF.Atan2(2f * (q.w * q.y + q.x * q.z), - 1f - 2f * (q.y * q.y + q.x * q.x)); // Y - - const float rad2deg = 180f / MathF.PI; - return new Vector3Float(pitch * rad2deg, yaw * rad2deg, roll * rad2deg); - // float test = q.x * q.y + q.z * q.w; - // if (test > 0.499f) // singularity at north pole - // return new Vector3Float(0, 2 * MathF.Atan2(q.x, q.w) * AngleFloat.Rad2Deg, 90); - - // else if (test < -0.499f) // singularity at south pole - // return new Vector3Float(0, -2 * MathF.Atan2(q.x, q.w) * AngleFloat.Rad2Deg, -90); - - // else { - // float sqx = q.x * q.x; - // float sqy = q.y * q.y; - // float sqz = q.z * q.z; - - // return new Vector3Float( - // MathF.Atan2(2 * q.x * q.w - 2 * q.y * q.z, 1 - 2 * sqx - 2 * sqz) * - // AngleFloat.Rad2Deg, - // MathF.Atan2(2 * q.y * q.w - 2 * q.x * q.z, 1 - 2 * sqy - 2 * sqz) * - // AngleFloat.Rad2Deg, - // MathF.Asin(2 * test) * AngleFloat.Rad2Deg); - // } - } - - /// - /// Create a rotation from euler angles - /// - /// The angle around the right axis - /// The angle around the upward axis - /// The angle around the forward axis - /// The resulting quaternion - /// Rotation are appied in the order Z, X, Y. - public static Quaternion Euler(float x, float y, float z) { - return Quaternion.Euler(new Vector3Float(x, y, z)); - } - /// - /// Create a rotation from a vector containing euler angles - /// - /// Vector with the euler angles - /// The resulting quaternion - /// Rotation are appied in the order Z, X, Y. - public static Quaternion Euler(Vector3Float angles) { - Vector3Float euler = angles * AngleFloat.Deg2Rad; - float cx = MathF.Cos(euler.horizontal * 0.5f); - float sx = MathF.Sin(euler.horizontal * 0.5f); - float cy = MathF.Cos(euler.vertical * 0.5f); - float sy = MathF.Sin(euler.vertical * 0.5f); - float cz = MathF.Cos(euler.depth * 0.5f); - float sz = MathF.Sin(euler.depth * 0.5f); - - // Unity uses intrinsic Z, then X, then Y -> q = Qy * Qx * Qz - Quaternion q; - q.w = cy * cx * cz + sy * sx * sz; - q.x = cy * sx * cz + sy * cx * sz; - q.y = sy * cx * cz - cy * sx * sz; - q.z = cy * cx * sz - sy * sx * cz; - return q; - } - - /// - /// Multiply two quaternions - /// - /// - /// - /// The resulting rotation - public static Quaternion operator *(Quaternion q1, Quaternion q2) { - return new Quaternion( - q1.x * q2.w + q1.y * q2.z - q1.z * q2.y + q1.w * q2.x, - -q1.x * q2.z + q1.y * q2.w + q1.z * q2.x + q1.w * q2.y, - q1.x * q2.y - q1.y * q2.x + q1.z * q2.w + q1.w * q2.z, - -q1.x * q2.x - q1.y * q2.y - q1.z * q2.z + q1.w * q2.w); - } - - /// - /// Rotate a vector using this quaterion - /// - /// The rotation - /// The vector to rotate - /// The rotated vector - public static Vector3Float operator *(Quaternion q, Vector3Float v) { - float num = q.x * 2; - float num2 = q.y * 2; - float num3 = q.z * 2; - float num4 = q.x * num; - float num5 = q.y * num2; - float num6 = q.z * num3; - float num7 = q.x * num2; - float num8 = q.x * num3; - float num9 = q.y * num3; - float num10 = q.w * num; - float num11 = q.w * num2; - float num12 = q.w * num3; - - float px = v.horizontal; - float py = v.vertical; - float pz = v.depth; - float rx = - (1 - (num5 + num6)) * px + (num7 - num12) * py + (num8 + num11) * pz; - float ry = - (num7 + num12) * px + (1 - (num4 + num6)) * py + (num9 - num10) * pz; - float rz = - (num8 - num11) * px + (num9 + num10) * py + (1 - (num4 + num5)) * pz; - Vector3Float result = new(rx, ry, rz); - return result; - } - - /// - /// The inverse of quaterion - /// - /// The quaternion for which the inverse is - /// needed The inverted quaternion - public static Quaternion Inverse(Quaternion q) { - float n = MathF.Sqrt(q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w); - return new Quaternion(-q.x / n, -q.y / n, -q.z / n, q.w / n); - } - - /// - /// A rotation which looks in the given direction - /// - /// The look direction - /// The up direction - /// The look rotation - public static Quaternion LookRotation(Vector3Float forward, Vector3Float up) { - Vector3Float nForward = forward.normalized; - Vector3Float nRight = Vector3Float.Normalize(Vector3Float.Cross(up, nForward)); - Vector3Float nUp = Vector3Float.Cross(nForward, nRight); - float m00 = nRight.horizontal; // x; - float m01 = nRight.vertical; // y; - float m02 = nRight.depth; // z; - float m10 = nUp.horizontal; // x; - float m11 = nUp.vertical; // y; - float m12 = nUp.depth; // z; - float m20 = nForward.horizontal; // x; - float m21 = nForward.vertical; // y; - float m22 = nForward.depth; // z; - - float num8 = (m00 + m11) + m22; - float x, y, z, w; - if (num8 > 0) { - float num = MathF.Sqrt(num8 + 1); - w = num * 0.5f; - num = 0.5f / num; - x = (m12 - m21) * num; - y = (m20 - m02) * num; - z = (m01 - m10) * num; - return new Quaternion(x, y, z, w); - } - if ((m00 >= m11) && (m00 >= m22)) { - float num7 = MathF.Sqrt(((1 + m00) - m11) - m22); - float num4 = 0.5F / num7; - x = 0.5f * num7; - y = (m01 + m10) * num4; - z = (m02 + m20) * num4; - w = (m12 - m21) * num4; - return new Quaternion(x, y, z, w); - } - if (m11 > m22) { - float num6 = MathF.Sqrt(((1 + m11) - m00) - m22); - float num3 = 0.5F / num6; - x = (m10 + m01) * num3; - y = 0.5F * num6; - z = (m21 + m12) * num3; - w = (m20 - m02) * num3; - return new Quaternion(x, y, z, w); - } - float num5 = MathF.Sqrt(((1 + m22) - m00) - m11); - float num2 = 0.5F / num5; - x = (m20 + m02) * num2; - y = (m21 + m12) * num2; - z = 0.5F * num5; - w = (m01 - m10) * num2; - return new Quaternion(x, y, z, w); - } - - /// - /// Creates a quaternion with the given forward direction with up = - /// Vector3::up - /// - /// The look direction - /// The rotation for this direction - /// For the rotation, Vector::up is used for the up direction. - /// Note: if the forward direction == Vector3::up, the result is - /// Quaternion::identity - public static Quaternion LookRotation(Vector3Float forward) { - Vector3Float up = new(0, 1, 0); - return LookRotation(forward, up); - } - - /// - /// Calculat the rotation from on vector to another - /// - /// The from direction - /// The to direction - /// The rotation from the first to the second vector - public static Quaternion FromToRotation(Vector3Float fromDirection, Vector3Float toDirection) { - Vector3Float axis = Vector3Float.Cross(fromDirection, toDirection); - axis = axis.normalized; - AngleFloat angle = Vector3Float.SignedAngle(fromDirection, toDirection, axis); - Quaternion rotation = AngleAxis(angle, axis); - return rotation; - - } - - /// - /// Rotate form one orientation to anther with a maximum amount of degrees - /// - /// The from rotation - /// The destination rotation - /// The maximum amount of degrees to - /// rotate The possibly limited rotation - public static Quaternion RotateTowards(Quaternion from, Quaternion to, - float maxDegreesDelta) { - float num = Quaternion.UnsignedAngle(from, to); - if (num == 0) { - return to; - } - float t = MathF.Min(1, maxDegreesDelta / num); - return SlerpUnclamped(from, to, t); - - } - - /// - /// Convert an angle/axis representation to a quaternion - /// - /// The angle - /// The axis - /// The resulting quaternion - public static Quaternion AngleAxis(AngleFloat angle, Vector3Float axis) { - if (axis.sqrMagnitude == 0.0f) - return Quaternion.identity; - - float radians = angle.inRadians; - radians *= 0.5f; - - Vector3Float axis2 = axis * MathF.Sin(radians); - float x = axis2.horizontal; // x; - float y = axis2.vertical; // y; - float z = axis2.depth; // z; - float w = MathF.Cos(radians); - - return new Quaternion(x, y, z, w).normalized; - } - /// - /// Convert this quaternion to angle/axis representation - /// - /// A pointer to the angle for the result - /// A pointer to the axis for the result - public readonly void ToAngleAxis(out AngleFloat angle, out Vector3Float axis) { - Quaternion q1 = (MathF.Abs(this.w) > 1.0f) ? this.normalized : this; - angle = AngleFloat.Radians(2.0f * MathF.Acos(q1.w)); // angle - float den = MathF.Sqrt(1.0F - q1.w * q1.w); - if (den > 0.0001f) { - axis = Vector3Float.Normalize(q1.xyz / den); - } - else { - // This occurs when the angle is zero. - // Not a problem: just set an arbitrary normalized axis. - axis = Vector3Float.right; - } - } - - /// - /// Get the angle between two orientations - /// - /// The first orientation - /// The second orientation - /// The smallest angle in degrees between the two - /// orientations - public static float UnsignedAngle(Quaternion q1, Quaternion q2) { - // float f = Dot(q1, q2); - // return MathF.Acos(MathF.Min(MathF.Abs(f), 1)) * 2 * AngleFloat.Rad2Deg; - - float dot = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w; - dot = MathF.Min(MathF.Max(dot, -1f), 1f); - return 2f * MathF.Acos(MathF.Abs(dot)) * (180f / MathF.PI); - } - - /// - /// Sherical lerp between two rotations - /// - /// The first rotation - /// The second rotation - /// The factor between 0 and 1. - /// The resulting rotation - /// A factor 0 returns rotation1, factor1 returns rotation2. - public static Quaternion Slerp(Quaternion a, - Quaternion b, float t) { - if (t > 1) - t = 1; - if (t < 0) - t = 0; - return SlerpUnclamped(a, b, t); - } - - /// - /// Unclamped sherical lerp between two rotations - /// - /// The first rotation - /// The second rotation - /// The factor - /// The resulting rotation - /// A factor 0 returns rotation1, factor1 returns rotation2. - /// Values outside the 0..1 range will result in extrapolated rotations - public static Quaternion SlerpUnclamped(Quaternion a, - Quaternion b, float t) { - // if either input is zero, return the other. - if (a.sqrMagnitude == 0.0f) { - if (b.sqrMagnitude == 0.0f) { - return identity; - } - return b; - } - else if (b.sqrMagnitude == 0.0f) { - return a; - } - - Vector3Float axyz = a.xyz; - Vector3Float bxyz = b.xyz; - float cosHalfAngle = a.w * b.w + Vector3Float.Dot(axyz, bxyz); - - Quaternion b2 = b; - if (cosHalfAngle >= 1.0f || cosHalfAngle <= -1.0f) { - // angle = 0.0f, so just return one input. - return a; - } - else if (cosHalfAngle < 0.0f) { - b2.x = -b.x; - b2.y = -b.y; - b2.z = -b.z; - b2.w = -b.w; - cosHalfAngle = -cosHalfAngle; - } - - float blendA; - float blendB; - if (cosHalfAngle < 0.99f) { - // do proper slerp for big angles - float halfAngle = MathF.Acos(cosHalfAngle); - float sinHalfAngle = MathF.Sin(halfAngle); - float oneOverSinHalfAngle = 1.0F / sinHalfAngle; - blendA = MathF.Sin(halfAngle * (1.0F - t)) * oneOverSinHalfAngle; - blendB = MathF.Sin(halfAngle * t) * oneOverSinHalfAngle; - } - else { - // do lerp if angle is really small. - blendA = 1.0f - t; - blendB = t; - } - Vector3Float v = axyz * blendA + b2.xyz * blendB; - Quaternion result = - new(v.horizontal, v.vertical, v.depth, blendA * a.w + blendB * b2.w); - if (result.sqrMagnitude > 0.0f) - return result.normalized; - else - return Quaternion.identity; - } - - /// - /// Convert this quaternion to angle/axis representation - /// - /// A pointer to the angle for the result - /// A pointer to the axis for the result - public readonly void ToAngleAxis(out float angle, out Vector3Float axis) { - ToAxisAngleRad(this, out axis, out angle); - angle *= AngleFloat.Rad2Deg; - } - private static void ToAxisAngleRad(Quaternion q, - out Vector3Float axis, - out float angle) { - Quaternion q1 = (MathF.Abs(q.w) > 1.0f) ? Quaternion.Normalize(q) : q; - angle = 2.0f * MathF.Acos(q1.w); // angle - float den = MathF.Sqrt(1.0F - q1.w * q1.w); - if (den > 0.0001f) { - axis = (q1.xyz / den).normalized; - } - else { - // This occurs when the angle is zero. - // Not a problem: just set an arbitrary normalized axis. - axis = new Vector3Float(1, 0, 0); - } - } - - /// - /// Returns the angle of around the give axis for a rotation - /// - /// The axis around which the angle should be - /// computed The source rotation - /// The signed angle around the axis - public static float GetAngleAround(Vector3Float axis, Quaternion rotation) { - Quaternion secondaryRotation = GetRotationAround(axis, rotation); - secondaryRotation.ToAngleAxis(out float rotationAngle, out Vector3Float rotationAxis); - - // Do the axis point in opposite directions? - if (Vector3Float.Dot(axis, rotationAxis) < 0) - rotationAngle = -rotationAngle; - - return rotationAngle; - } - - /// - /// Returns the rotation limited around the given axis - /// - /// The axis which which the rotation should be - /// limited The source rotation - /// The rotation around the given axis - public static Quaternion GetRotationAround(Vector3Float axis, Quaternion rotation) { - Vector3Float ra = new(rotation.x, rotation.y, rotation.z); // rotation axis - Vector3Float p = Vector3Float.Project( - ra, axis); // return projection ra on to axis (parallel component) - Quaternion twist = new(p.horizontal, p.vertical, p.depth, rotation.w); - twist = Normalize(twist); - return twist; - - } - - /// - /// Swing-twist decomposition of a rotation - /// - /// The base direction for the decomposition - /// The source rotation - /// A pointer to the quaternion for the swing - /// result A pointer to the quaternion for the - /// twist result - static void GetSwingTwist(Vector3Float axis, Quaternion q, - out Quaternion swing, out Quaternion twist) { - twist = GetRotationAround(axis, q); - swing = q * Inverse(twist); - } - - /// - /// Calculate the dot product of two quaternions - /// - /// The first rotation - /// The second rotation - /// - public static float Dot(Quaternion q1, Quaternion q2) { - return q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w; - } - } -#endif - -} \ No newline at end of file diff --git a/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs b/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs deleted file mode 100644 index 318839d..0000000 --- a/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs +++ /dev/null @@ -1,279 +0,0 @@ -using System; -using System.Collections.Generic; - -#if UNITY_5_3_OR_NEWER -using Vector3 = UnityEngine.Vector3; -#endif - -namespace LinearAlgebra { - /// - /// A spherical vector - /// - /// This is a struct such that it is a value type and cannot be null - public struct Spherical { - /// - /// Create a spherical vector - /// - /// The distance in meters - /// The direction of the vector - public Spherical(float distance, Direction direction) { - if (distance > 0) { - this.distance = distance; - this.direction = direction; - } - else { - this.distance = -distance; - this.direction = -direction; - } - } - - /// - /// Create spherical vector. All given angles are in degrees - /// - /// The distance in meters - /// The horizontal angle in degrees - /// The vertical angle in degrees - /// - public static Spherical Degrees(float distance, float horizontal, float vertical) { - Direction direction = Direction.Degrees(horizontal, vertical); - Spherical s = new(distance, direction); - return s; - } - - public static Spherical Radians(float distance, float horizontal, float vertical) { - Direction direction = Direction.Radians(horizontal, vertical); - Spherical s = new(distance, direction); - return s; - } - - /// - /// The distance in meters - /// - /// @remark The distance should never be negative - public float distance; - /// - /// The direction of the vector - /// - public Direction direction; - - /// - /// A spherical vector with zero degree angles and distance - /// - public readonly static Spherical zero = new(0, Direction.forward); - /// - /// A normalized forward-oriented vector - /// - public readonly static Spherical forward = new(1, Direction.forward); - -#if UNITY_5_3_OR_NEWER - public static Spherical FromVector3(Vector3 v) { - float distance = v.magnitude; - Direction direction = Direction.FromVector3(v / distance); - return new Spherical(distance, direction); - } - - public readonly Vector3 ToVector3() { - Vector3 v = this.direction.ToVector3(); - v *= this.distance; - return v; - } -#else - public static Spherical FromVector3(Vector3Float v) { - float distance = v.magnitude; - if (distance == 0.0f) - return Spherical.zero; - else { - float verticalAngle = (float)(Math.PI / 2 - Math.Acos(v.vertical / distance)) * AngleFloat.Rad2Deg; - float horizontalAngle = (float)Math.Atan2(v.horizontal, v.depth) * AngleFloat.Rad2Deg; - return Degrees(distance, horizontalAngle, verticalAngle); - } - } - - public readonly Vector3Float ToVector3() { - // float verticalRad = (AngleFloat.deg90 - this.direction.vertical).inRadians; - // float horizontalRad = this.direction.horizontal.inRadians; - // float cosVertical = (float)Math.Cos(verticalRad); - // float sinVertical = (float)Math.Sin(verticalRad); - // float cosHorizontal = (float)Math.Cos(horizontalRad); - // float sinHorizontal = (float)Math.Sin(horizontalRad); - - // float x = this.distance * sinVertical * sinHorizontal; - // float y = this.distance * cosVertical; - // float z = this.distance * sinVertical * cosHorizontal; - - // Vector3Float v = new(x, y, z); - Vector3Float v = this.direction.ToVector3(); - v *= this.distance; - return v; - } -#endif - - public override readonly string ToString() { - return $"Spherical({this.distance}, h: {this.direction.horizontal}, v: {this.direction.vertical})"; - } - - - public readonly float magnitude => this.distance; - - public Spherical normalized { - get { - Spherical r = new() { - distance = 1, - direction = this.direction - }; - return r; - } - } - - public static Spherical operator +(Spherical s1, Spherical s2) { - // let's do it the easy way... - // using vars to be compatible with both unity (Vector3) and native (Vector3Float) - var v1 = s1.ToVector3(); - var v2 = s2.ToVector3(); - var v = v1 + v2; - Spherical r = FromVector3(v); - return r; - } - - public static Spherical operator *(Spherical v, float d) { - Spherical r = new(v.distance * d, v.direction); - return r; - } - - public static bool operator ==(Spherical v1, Spherical v2) { - return (v1.distance == v2.distance && v1.direction == v2.direction); - } - - public static bool operator !=(Spherical v1, Spherical v2) { - return (v1.distance != v2.distance || v1.direction != v2.direction); - } - - public override readonly bool Equals(object o) { - if (o is Spherical s) - return this == s; - return false; - } - - public override readonly int GetHashCode() { - return HashCode.Combine(this.distance, this.direction); - } - - public static float Distance(Spherical v1, Spherical v2) { - // Convert degrees to radians - float thetaARadians = v1.direction.horizontal.inRadians; - float phiARadians = v1.direction.vertical.inRadians;// DegreesToRadians(phiA); - float thetaBRadians = v2.direction.horizontal.inRadians; // DegreesToRadians(thetaB); - float phiBRadians = v2.direction.vertical.inRadians; // DegreesToRadians(phiB); - - // Calculate sine and cosine values - float sinPhiA = MathF.Sin(phiARadians); - float cosPhiA = MathF.Cos(phiARadians); - float sinPhiB = MathF.Sin(phiBRadians); - float cosPhiB = MathF.Cos(phiBRadians); - - // Calculate the cosine of the difference in azimuthal angles - float cosThetaDifference = MathF.Cos(thetaARadians - thetaBRadians); - - // Apply the spherical law of cosines - float distance = MathF.Sqrt( - v1.distance * v1.distance + - v2.distance * v2.distance - - 2 * v1.distance * v2.distance * (sinPhiA * sinPhiB * cosThetaDifference + cosPhiA * cosPhiB) - ); - - return distance; - } - - public static Spherical Average(Spherical v1, Spherical v2) { - const float EPS = 1e-6f; - - // Angles in radians - float a1 = v1.direction.horizontal.inRadians; - float a2 = v2.direction.horizontal.inRadians; - float e1 = v1.direction.vertical.inRadians; - float e2 = v2.direction.vertical.inRadians; - - // Fast path: exactly same direction (allowing wrap for azimuth) -> preserve exact angles - bool sameAz = MathF.Abs(MathF.IEEERemainder(a1 - a2, MathF.PI * 2f)) < EPS; - bool sameEl = MathF.Abs(e1 - e2) < EPS; - if (sameAz && sameEl) { - // Distances may differ; average distance but keep exact angles from v1 - float rAvgExact = 0.5f * (v1.distance + v2.distance); - return new Spherical(rAvgExact, v1.direction); - } - - // Horizontal unit-circle sum - float cx = MathF.Cos(a1) + MathF.Cos(a2); - float cy = MathF.Sin(a1) + MathF.Sin(a2); - - // Vertical as z = sin(el) - float z1 = MathF.Sin(e1); - float z2 = MathF.Sin(e2); - float cz = z1 + z2; - - // Magnitude of summed unit-direction vectors - float sumX = cx; - float sumY = cy; - float sumZ = cz; - float magSum = MathF.Sqrt(sumX * sumX + sumY * sumY + sumZ * sumZ); - - // If the two direction unit-vectors cancel (or nearly), return zero distance. - if (magSum < EPS) { - return Spherical.Radians(0f, 0f, 0f); - } - - // Normalized averaged direction components - float ux = sumX / magSum; - float uy = sumY / magSum; - float uz = sumZ / magSum; - - // Compute averaged angles from normalized vector - float azAvgRad = MathF.Atan2(uy, ux); - float elAvgRad = MathF.Asin(Float.Clamp(uz, -1f, 1f)); - - // Average distance (arithmetic mean) - float rAvg = 0.5f * (v1.distance + v2.distance); - - return Spherical.Radians(rAvg, azAvgRad, elAvgRad); - } - - public static Spherical Sum(List vectors) { - if (vectors == null || vectors.Count == 0) - throw new ArgumentException("vectors must contain at least one element", nameof(vectors)); - -#if UNITY_5_3_OR_NEWER - Vector3 sum = Vector3.zero; -#else - Vector3Float sum = Vector3Float.zero; -#endif - foreach (Spherical v in vectors) - sum += v.ToVector3(); - - return FromVector3(sum); - } - - - public static Spherical Average(List vectors) { - if (vectors == null || vectors.Count == 0) - throw new ArgumentException("vectors must contain at least one element", nameof(vectors)); - -#if UNITY_5_3_OR_NEWER - Vector3 sum = Vector3.zero; -#else - Vector3Float sum = Vector3Float.zero; -#endif - int n = 0; - foreach (Spherical v in vectors) { - sum += v.ToVector3(); - n++; - } - var avg = sum / n; - - // if (avg.sqrMagnitude == 0f) - // return new Spherical(0f, new Direction(AngleFloat.Radians(0f), AngleFloat.Radians(0f))); - // else - return FromVector3(avg); - } - - } -} \ No newline at end of file diff --git a/Assets/NanoBrain/LinearAlgebra/src/SwingTwist.cs b/Assets/NanoBrain/LinearAlgebra/src/SwingTwist.cs deleted file mode 100644 index df6e048..0000000 --- a/Assets/NanoBrain/LinearAlgebra/src/SwingTwist.cs +++ /dev/null @@ -1,136 +0,0 @@ -// #if !UNITY_5_3_OR_NEWER -// using UnityEngine; -// #endif - -namespace LinearAlgebra { - - /// - /// An orientation using swing and twist angles - /// - /// The swing rotation - /// The twist rotation - public struct SwingTwist { - public Direction swing; - public AngleFloat twist; - - public SwingTwist(Direction swing, AngleFloat twist) { - this.swing = swing; - this.twist = twist; - } - - /// - /// Create a swing/twist rotation using angles in degrees - /// - /// The swing angle in the horizontal plane in degrees - /// The swing angle in the vertical plan in degrees - /// The twist angle in degrees - /// The swing/twist rotation - public static SwingTwist Degrees(float horizontalSwing, float verticalSwing, float twist) { - Direction swing = Direction.Degrees(horizontalSwing, verticalSwing); - AngleFloat twistAngle = AngleFloat.Degrees(twist); - SwingTwist s = new(swing, twistAngle); - return s; - } - - /// - /// Create a swing/twist rotation using angles in degrees - /// - /// The swing angle in the horizontal plane in degrees - /// The swing angle in the vertical plan in degrees - /// The twist angle in degrees - /// The swing/twist rotation - public static SwingTwist Radians(float horizontalSwing, float verticalSwing, float twist) { - Direction swing = Direction.Radians(horizontalSwing, verticalSwing); - AngleFloat twistAngle = AngleFloat.Radians(twist); - SwingTwist s = new(swing, twistAngle); - return s; - } - -#if UNITY_5_3_OR_NEWER - /// - /// A zero angle rotation - /// - public static readonly SwingTwist zero = Degrees(0, 0, 0); - - public Spherical ToAngleAxis() { - UnityEngine.Quaternion q = this.ToQuaternion(); - q.ToAngleAxis(out float angle, out UnityEngine.Vector3 axis); - Direction direction = Direction.FromVector3(axis); - - Spherical r = new(angle, direction); - return r; - } - - public static SwingTwist FromAngleAxis(Spherical r) { - UnityEngine.Vector3 vectorAxis = r.direction.ToVector3(); - UnityEngine.Quaternion q = UnityEngine.Quaternion.AngleAxis(r.distance, vectorAxis); - return FromQuaternion(q); - } - - /// - /// Convert a quaternion in a swing/twist rotation - /// - /// The quaternion to convert - /// The swing/twist rotation - public static SwingTwist FromQuaternion(UnityEngine.Quaternion q) { - UnityEngine.Vector3 angles = q.eulerAngles; - SwingTwist r = Degrees(angles.y, -angles.x, -angles.z); - return r; - } - - public UnityEngine.Quaternion ToQuaternion() { - UnityEngine.Quaternion q = UnityEngine.Quaternion.Euler(this.swing.vertical.inDegrees, - this.swing.horizontal.inDegrees, - this.twist.inDegrees); - return q; - } -#else - /// - /// A zero angle rotation - /// - public static readonly SwingTwist zero = Degrees(0, 0, 0); - - public Spherical ToAngleAxis() { - LinearAlgebra.Quaternion q = this.ToQuaternion(); - q.ToAngleAxis(out float angle, out Vector3Float axis); - Direction direction = Direction.FromVector3(axis); - - Spherical r = new(angle, direction); - return r; - } - - public static SwingTwist FromAngleAxis(Spherical r) { - Vector3Float vectorAxis = r.direction.ToVector3(); - LinearAlgebra.Quaternion q = LinearAlgebra.Quaternion.AngleAxis(AngleFloat.Degrees(r.distance), vectorAxis); - return FromQuaternion(q); - } - - /// - /// Convert a quaternion in a swing/twist rotation - /// - /// The quaternion to convert - /// The swing/twist rotation - public static SwingTwist FromQuaternion(LinearAlgebra.Quaternion q) { - Vector3Float v = LinearAlgebra.Quaternion.ToAngles(q); - SwingTwist r = Degrees(v.vertical, v.horizontal, v.depth); - return r; - } - - public LinearAlgebra.Quaternion ToQuaternion() { - LinearAlgebra.Quaternion q = LinearAlgebra.Quaternion.Euler(this.swing.vertical.inDegrees, - this.swing.horizontal.inDegrees, - this.twist.inDegrees); - return q; - - } - - public static SwingTwist FromQuat32(Quat32 q32) { - q32.ToAngles(out float right, out float up, out float forward); - SwingTwist r = Degrees(up, right, forward); - return r; - } -#endif - - } - -} \ No newline at end of file diff --git a/Assets/NanoBrain/LinearAlgebra/src/Vector2Float.cs b/Assets/NanoBrain/LinearAlgebra/src/Vector2Float.cs deleted file mode 100644 index ac1867c..0000000 --- a/Assets/NanoBrain/LinearAlgebra/src/Vector2Float.cs +++ /dev/null @@ -1,479 +0,0 @@ -using System; -using System.Numerics; - -namespace LinearAlgebra { - - /* - public struct Vector2Int { - public int horizontal; - public int vertical; - - public Vector2Int(int horizontal, int vertical) { - this.horizontal = horizontal; - this.vertical = vertical; - } - - /// - /// A vector with zero for all axis - /// - public static readonly Vector2Int zero = new(0, 0); - /// - /// A vector with values (1, 1) - /// - public static readonly Vector2Int one = new(1, 1); - /// - /// A vector with values (0, 1) - /// - public static readonly Vector2Int up = new(0, 1); - /// - /// A vector with values (0, -1) - /// - public static readonly Vector2Int down = new(0, -1); - /// - /// A vector with values (0, 1) - /// - public static readonly Vector2Int forward = new(0, 1); - /// - /// A vector with values (0, -1) - /// - public static readonly Vector2Int back = new(0, -1); - /// - /// A vector3 with values (-1, 0) - /// - public static readonly Vector2Int left = new(-1, 0); - /// - /// A vector with values (1, 0) - /// - public static readonly Vector2Int right = new(1, 0); - - /// - /// Tests if the vector has equal values as the given vector - /// - /// The vector to compare to - /// true if the vector values are equal - public readonly bool Equals(Vector2Int v) => this.horizontal == v.horizontal && vertical == v.vertical; - - /// - /// Tests if the vector is equal to the given object - /// - /// The object to compare to - /// false when the object is not a Vector2 or does not have equal values - public override readonly bool Equals(object obj) { - if (obj is not Vector2Int v) - return false; - - return (this.horizontal == v.horizontal && this.vertical == v.vertical); - } - - /// - /// Tests if the two vectors have equal values - /// - /// The first vector - /// The second vector - /// truewhen the vectors have equal values - /// Note that this uses a Float equality check which cannot be not exact in all cases. - /// In most cases it is better to check if the Vector2.Distance between the vectors is smaller than Float.epsilon - /// Or more efficient: (v1 - v2).sqrMagnitude < Float.sqrEpsilon - public static bool operator ==(Vector2Int v1, Vector2Int v2) { - return (v1.horizontal == v2.horizontal && v1.vertical == v2.vertical); - } - /// - /// Tests if two vectors have different values - /// - /// The first vector - /// The second vector - /// truewhen the vectors have different values - /// Note that this uses a Float equality check which cannot be not exact in all case. - /// In most cases it is better to check if the Vector2.Distance between the vectors is smaller than Float.epsilon. - /// Or more efficient: (v1 - v2).sqrMagnitude < Float.sqrEpsilon - public static bool operator !=(Vector2Int v1, Vector2Int v2) { - return (v1.horizontal != v2.horizontal || v1.vertical != v2.vertical); - } - public readonly float magnitude { - get { - int h = this.horizontal; - int v = this.vertical; - return MathF.Sqrt(h * h + v * v); - } - } - - public static float MagnitudeOf(Vector2Int v) { - return v.magnitude; - } - - public static Vector2Int operator -(Vector2Int v1, Vector2Int v2) { - return new Vector2Int(v1.horizontal - v2.horizontal, v1.vertical - v2.vertical); - } - public static Vector2Int operator +(Vector2Int v1, Vector2Int v2) { - return new Vector2Int(v1.horizontal + v2.horizontal, v1.vertical + v2.vertical); - } - - public static float Distance(Vector2Int v1, Vector2Int v2) { - return (v1 - v2).magnitude; - } - } - - public struct Vector2Float { - public float horizontal; - public float vertical; - - public Vector2Float(float horizontal, float vertical) { - this.horizontal = horizontal; - this.vertical = vertical; - } - - public readonly float magnitude { - get { - float h = this.horizontal; - float v = this.vertical; - return MathF.Sqrt(h * h + v * v); - } - } - - public static Vector2Float operator -(Vector2Float v1, Vector2Float v2) { - return new Vector2Float(v1.horizontal - v2.horizontal, v1.vertical - v2.vertical); - } - - public static float Distance(Vector2Float v1, Vector2Float v2) { - return (v1 - v2).magnitude; - } - } - */ - - /// - /// 2-dimensional vectors - /// - public struct Vector2Float { - - /// - /// The right axis of the vector - /// - public float horizontal; // left/right - /// - /// The upward/forward axis of the vector - /// - public float vertical; // forward/backward - // directions are to be inline with Vector3 as much as possible... - - /// - /// Create a new 2-dimensional vector - /// - /// x axis value - /// y axis value - public Vector2Float(float x, float y) { - this.horizontal = x; - this.vertical = y; - } - - /// - /// Convert a Vector2Int into a Vector2Float - /// - /// The Vector2Int - public Vector2Float(Vector2Int v) { - this.horizontal = v.horizontal; - this.vertical = v.vertical; - } - - /// - /// A vector with zero for all axis - /// - public static readonly Vector2Float zero = new Vector2Float(0, 0); - /// - /// A vector with values (1, 1) - /// - public static readonly Vector2Float one = new Vector2Float(1, 1); - /// - /// A vector with values (0, 1) - /// - public static readonly Vector2Float up = new Vector2Float(0, 1); - /// - /// A vector with values (0, -1) - /// - public static readonly Vector2Float down = new Vector2Float(0, -1); - /// - /// A vector with values (0, 1) - /// - public static readonly Vector2Float forward = new Vector2Float(0, 1); - /// - /// A vector with values (0, -1) - /// - public static readonly Vector2Float back = new Vector2Float(0, -1); - /// - /// A vector3 with values (-1, 0) - /// - public static readonly Vector2Float left = new Vector2Float(-1, 0); - /// - /// A vector with values (1, 0) - /// - public static readonly Vector2Float right = new Vector2Float(1, 0); - - /// - /// The squared length of this vector - /// - /// The squared length - /// The squared length is computationally simpler than the real length. - /// Think of Pythagoras A^2 + B^2 = C^2. - /// This leaves out the calculation of the squared root of C. - public readonly float sqrMagnitude => horizontal * horizontal + vertical * vertical; - public static float SqrMagnitudeOf(Vector2Float v) { - return v.sqrMagnitude; - } - - /// - /// The length of this vector - /// - /// The length of this vector - public readonly float magnitude => MathF.Sqrt(horizontal * horizontal + vertical * vertical); - public static float MagnitudeOf(Vector2Float v) { - return v.magnitude; - } - - /// - /// Convert the vector to a length of a 1 - /// - /// The vector with length 1 - public Vector2Float normalized { - get { - float l = magnitude; - Vector2Float v = zero; - if (l > Float.epsilon) - v = this / l; - return v; - } - } - public static Vector2Float Normalize(Vector2Float v) { - return v.normalized; - } - - /// - /// Add two vectors - /// - /// The first vector - /// The second vector - /// The result of adding the two vectors - public static Vector2Float operator +(Vector2Float v1, Vector2Float v2) { - Vector2Float v = new Vector2Float(v1.horizontal + v2.horizontal, v1.vertical + v2.vertical); - return v; - } - - /// - /// Subtract two vectors - /// - /// The first vector - /// The second vector - /// The result of adding the two vectors - public static Vector2Float operator -(Vector2Float v1, Vector2Float v2) { - Vector2Float v = new Vector2Float(v1.horizontal - v2.horizontal, v1.vertical - v2.vertical); - return v; - } - - /// - /// Negate the vector - /// - /// The vector to negate - /// The negated vector - /// This will result in a vector pointing in the opposite direction - public static Vector2Float operator -(Vector2Float v1) { - Vector2Float v = new Vector2Float(-v1.horizontal, -v1.vertical); - return v; - } - - /// - /// Scale a vector uniformly down - /// - /// The vector to scale - /// The scaling factor - /// The scaled vector - /// Each component of the vector will be devided by the same factor. - public static Vector2Float operator /(Vector2Float v, float f) { - Vector2Float r = new(v.horizontal / f, v.vertical / f); - return r; - } - - - /// - /// Scale a vector uniformly up - /// - /// The vector to scale - /// The scaling factor - /// The scaled vector - /// Each component of the vector will be multipled with the same factor. - public static Vector2Float operator *(Vector2Float v1, float f) { - Vector2Float v = new Vector2Float(v1.horizontal * f, v1.vertical * f); - return v; - } - - /// - /// Scale a vector uniformly up - /// - /// The scaling factor - /// The vector to scale - /// The scaled vector - /// Each component of the vector will be multipled with the same factor. - public static Vector2Float operator *(float f, Vector2Float v1) { - Vector2Float v = new Vector2Float(f * v1.horizontal, f * v1.vertical); - return v; - } - - /// @brief Scale the vector using another vector - /// @param v1 The vector to scale - /// @param v2 A vector with the scaling factors - /// @return The scaled vector - /// @remark Each component of the vector v1 will be multiplied with the - /// matching component from the scaling vector v2. - public static Vector2Float Scale(Vector2Float v1, Vector2Float v2) { - return new Vector2Float(v1.horizontal * v2.horizontal, v1.vertical * v2.vertical); - } - - /// - /// Tests if the vector has equal values as the given vector - /// - /// The vector to compare to - /// true if the vector values are equal - //public readonly bool Equals(Vector2Float v1) => horizontal == v1.horizontal && vertical == v1.vertical; - - /// - /// Tests if the two vectors have equal values - /// - /// The first vector - /// The second vector - /// truewhen the vectors have equal values - /// Note that this uses a Float equality check which cannot be not exact in all cases. - /// In most cases it is better to check if the Vector2.Distance between the vectors is smaller than Float.epsilon - /// Or more efficient: (v1 - v2).sqrMagnitude < Float.sqrEpsilon - public static bool operator ==(Vector2Float v1, Vector2Float v2) { - return (v1.horizontal == v2.horizontal && v1.vertical == v2.vertical); - } - - /// - /// Tests if two vectors have different values - /// - /// The first vector - /// The second vector - /// truewhen the vectors have different values - /// Note that this uses a Float equality check which cannot be not exact in all case. - /// In most cases it is better to check if the Vector2.Distance between the vectors is smaller than Float.epsilon. - /// Or more efficient: (v1 - v2).sqrMagnitude < Float.sqrEpsilon - public static bool operator !=(Vector2Float v1, Vector2Float v2) { - return (v1.horizontal != v2.horizontal || v1.vertical != v2.vertical); - } - - /// - /// Tests if the vector is equal to the given object - /// - /// The object to compare to - /// false when the object is not a Vector2 or does not have equal values - public override readonly bool Equals(object obj) { - if (obj is not Vector2Float v) - return false; - - return (horizontal == v.horizontal && vertical == v.vertical); - } - - /// - /// Get an hash code for the vector - /// - /// The hash code - public override readonly int GetHashCode() { - return HashCode.Combine(horizontal, vertical); - } - - /// - /// Get the distance between two vectors - /// - /// The first vector - /// The second vector - /// The distance between the two vectors - public static float Distance(Vector2Float v1, Vector2Float v2) { - float x = v1.horizontal - v2.horizontal; - float y = v1.vertical - v2.vertical; - float d = (float)Math.Sqrt(x * x + y * y); - return d; - } - - /// - /// The dot product of two vectors - /// - /// The first vector - /// The second vector - /// The dot product of the two vectors - public static float Dot(Vector2Float v1, Vector2Float v2) { - return v1.horizontal * v2.horizontal + v1.vertical * v2.vertical; - } - - /// - /// Calculate the signed angle between two vectors. - /// - /// The starting vector - /// The ending vector - /// The axis to rotate around - /// The signed angle in degrees - public static float SignedAngle(Vector2Float from, Vector2Float to) { - //float sign = Math.Sign(v1.y * v2.x - v1.x * v2.y); - //return Vector2.Angle(v1, v2) * sign; - - float sqrMagFrom = from.sqrMagnitude; - float sqrMagTo = to.sqrMagnitude; - - if (sqrMagFrom == 0 || sqrMagTo == 0) - return 0; - //if (!isfinite(sqrMagFrom) || !isfinite(sqrMagTo)) - // return nanf(""); - - float angleFrom = (float)Math.Atan2(from.vertical, from.horizontal); - float angleTo = (float)Math.Atan2(to.vertical, to.horizontal); - return -(angleTo - angleFrom) * AngleFloat.Rad2Deg; - } - - public static float UnsignedAngle(Vector2Float from, Vector2Float to) { - return MathF.Abs(SignedAngle(from, to)); - } - - /// - /// Rotates the vector with the given angle - /// - /// The vector to rotate - /// The angle in degrees - /// - public static Vector2Float Rotate(Vector2Float v1, AngleFloat angle) { - float sin = (float)Math.Sin(angle.inRadians); - float cos = (float)Math.Cos(angle.inRadians); - // float sin = AngleFloat.Sin(angle); - // float cos = AngleFloat.Cos(angle); - - float tx = v1.horizontal; - float ty = v1.vertical; - Vector2Float v = new Vector2Float() { - horizontal = (cos * tx) - (sin * ty), - vertical = (sin * tx) + (cos * ty) - }; - return v; - } - - /// - /// Lerp between two vectors - /// - /// The from vector - /// The to vector - /// The interpolation distance [0..1] - /// The lerped vector - /// The factor f is unclamped. Value 0 matches the *v1* vector, Value 1 - /// matches the *v2* vector Value -1 is *v1* vector minus the difference - /// between *v1* and *v2* etc. - public static Vector2Float Lerp(Vector2Float v1, Vector2Float v2, float f) { - Vector2Float v = v1 + (v2 - v1) * f; - return v; - } - - /// - /// Map interval of angles between vectors [0..Pi] to interval [0..1] - /// - /// The first vector - /// The second vector - /// The resulting factor in interval [0..1] - /// Vectors a and b must be normalized - public static float ToFactor(Vector2Float v1, Vector2Float v2) { - return (1 - Vector2Float.Dot(v1, v2)) / 2; - } - } -} \ No newline at end of file diff --git a/Assets/NanoBrain/LinearAlgebra/src/Vector2Int.cs b/Assets/NanoBrain/LinearAlgebra/src/Vector2Int.cs deleted file mode 100644 index ed68e8b..0000000 --- a/Assets/NanoBrain/LinearAlgebra/src/Vector2Int.cs +++ /dev/null @@ -1,185 +0,0 @@ -using System; - -namespace LinearAlgebra { - - public struct Vector2Int { - public int horizontal; - public int vertical; - - public Vector2Int(int horizontal, int vertical) { - this.horizontal = horizontal; - this.vertical = vertical; - } - - /// - /// A vector with zero for all axis - /// - public static readonly Vector2Int zero = new(0, 0); - /// - /// A vector with values (1, 1) - /// - public static readonly Vector2Int one = new(1, 1); - /// - /// A vector with values (0, 1) - /// - public static readonly Vector2Int up = new(0, 1); - /// - /// A vector with values (0, -1) - /// - public static readonly Vector2Int down = new(0, -1); - /// - /// A vector with values (0, 1) - /// - public static readonly Vector2Int forward = new(0, 1); - /// - /// A vector with values (0, -1) - /// - public static readonly Vector2Int back = new(0, -1); - /// - /// A vector3 with values (-1, 0) - /// - public static readonly Vector2Int left = new(-1, 0); - /// - /// A vector with values (1, 0) - /// - public static readonly Vector2Int right = new(1, 0); - - /* - /// - /// Get an hash code for the vector - /// - /// The hash code - public override int GetHashCode() { - return (this.horizontal, this.vertical).GetHashCode(); - } - - /// - /// Tests if the vector has equal values as the given vector - /// - /// The vector to compare to - /// true if the vector values are equal - public readonly bool Equals(Vector2Int v) => this.horizontal == v.horizontal && vertical == v.vertical; - - */ - - /// - /// Tests if the two vectors have equal values - /// - /// The first vector - /// The second vector - /// truewhen the vectors have equal values - /// Note that this uses a Float equality check which cannot be not exact in all cases. - /// In most cases it is better to check if the Vector2.Distance between the vectors is smaller than Float.epsilon - /// Or more efficient: (v1 - v2).sqrMagnitude < Float.sqrEpsilon - public static bool operator ==(Vector2Int v1, Vector2Int v2) { - return (v1.horizontal == v2.horizontal && v1.vertical == v2.vertical); - } - /// - /// Tests if two vectors have different values - /// - /// The first vector - /// The second vector - /// truewhen the vectors have different values - /// Note that this uses a Float equality check which cannot be not exact in all case. - /// In most cases it is better to check if the Vector2.Distance between the vectors is smaller than Float.epsilon. - /// Or more efficient: (v1 - v2).sqrMagnitude < Float.sqrEpsilon - public static bool operator !=(Vector2Int v1, Vector2Int v2) { - return (v1.horizontal != v2.horizontal || v1.vertical != v2.vertical); - } - - /// - /// Tests if the vector is equal to the given object - /// - /// The object to compare to - /// false when the object is not a Vector2 or does not have equal values - public override readonly bool Equals(object obj) { - if (obj is not Vector2Int v) - return false; - - return (this.horizontal == v.horizontal && this.vertical == v.vertical); - } - - /// - /// Get an hash code for the vector - /// - /// The hash code - public override readonly int GetHashCode() { - return HashCode.Combine(horizontal, vertical); - } - - public readonly float sqrMagnitude => this.horizontal * this.horizontal + this.vertical * this.vertical; - - public static float SqrMagnitudeOf(Vector2Int v) { - return v.sqrMagnitude; - } - - public readonly float magnitude => - MathF.Sqrt(this.horizontal * this.horizontal + this.vertical * this.vertical); - - public static float MagnitudeOf(Vector2Int v) { - return v.magnitude; - } - - /// @brief Convert the vector to a length of 1 - /// @return The vector normalized to a length of 1 - public readonly Vector2Float normalized { - get { - float l = magnitude; - Vector2Float v = Vector2Float.zero; - if (l > Float.epsilon) - v = new Vector2Float(this) / l; - return v; - } - } - /// @brief Convert the vector to a length of 1 - /// @param v The vector to convert - /// @return The vector normalized to a length of 1 - public static Vector2Float Normalize(Vector2Int v) { - float num = v.magnitude; - Vector2Float result = Vector2Float.zero; - if (num > Float.epsilon) - result = new Vector2Float(v) / num; - - return result; - } - - public static Vector2Int operator -(Vector2Int v) { - return new Vector2Int(-v.horizontal, -v.vertical); - } - - public static Vector2Int operator -(Vector2Int v1, Vector2Int v2) { - return new Vector2Int(v1.horizontal - v2.horizontal, v1.vertical - v2.vertical); - } - public static Vector2Int operator +(Vector2Int v1, Vector2Int v2) { - return new Vector2Int(v1.horizontal + v2.horizontal, v1.vertical + v2.vertical); - } - - public static Vector2Int operator /(Vector2Int v, int f) { - return new Vector2Int(v.horizontal / f, v.vertical / f); - } - - public static Vector2Int operator *(Vector2Int v1, int d) { - return new Vector2Int(v1.horizontal * d, v1.vertical * d); - } - - public static Vector2Int operator *(int d, Vector2Int v1) { - return new Vector2Int(d * v1.horizontal, d * v1.vertical); - } - - public static Vector2Int Scale(Vector2Int v1, Vector2Int v2) { - return new Vector2Int(v1.horizontal * v2.horizontal, v1.vertical * v2.vertical); - } - - /// @brief The dot product of two vectors - /// @param v1 The first vector - /// @param v2 The second vector - /// @return The dot product of the two vectors - public static int Dot(Vector2Int v1, Vector2Int v2) { - return v1.horizontal * v2.horizontal + v1.vertical * v2.vertical; - } - - public static float Distance(Vector2Int v1, Vector2Int v2) { - return (v1 - v2).magnitude; - } - } -} \ No newline at end of file diff --git a/Assets/NanoBrain/LinearAlgebra/src/Vector3Float.cs b/Assets/NanoBrain/LinearAlgebra/src/Vector3Float.cs deleted file mode 100644 index bcf8626..0000000 --- a/Assets/NanoBrain/LinearAlgebra/src/Vector3Float.cs +++ /dev/null @@ -1,402 +0,0 @@ -//#if !UNITY_5_3_OR_NEWER -using System; - -namespace LinearAlgebra { - /* - public struct Vector3Float { - public float horizontal; - public float vertical; - public float depth; - - public Vector3Float(float horizontal, float vertical, float depth) { - this.horizontal = horizontal; - this.vertical = vertical; - this.depth = depth; - } - - /// - /// A vector with zero for all axis - /// - public static readonly Vector3Float zero = new(0, 0, 0); - - public readonly float magnitude { - get => (float)Math.Sqrt(this.horizontal * this.horizontal + this.vertical * this.vertical + this.depth * this.depth); - } - - /// - /// Convert the vector to a length of a 1 - /// - /// The vector with length 1 - public readonly Vector3Float normalized { - get { - float l = magnitude; - Vector3Float v = zero; - if (l > Float.epsilon) - v = this / l; - return v; - } - } - - - public static Vector3Float operator *(Vector3Float v, float f) { - Vector3Float r = new(v.horizontal * f, v.vertical * f, v.depth * f); - return r; - } - public static Vector3Float operator /(Vector3Float v, float f) { - Vector3Float r = new(v.horizontal / f, v.vertical / f, v.depth / f); - return r; - } - - public static float Dot(Vector3Float v1, Vector3Float v2) { - return v1.horizontal * v2.horizontal + v1.vertical * v2.vertical + - v1.depth * v2.depth; - } - - const float epsilon = 1E-05f; - public static Vector3Float Project(Vector3Float v, Vector3Float n) { - float sqrMagnitude = Dot(n, n); - if (sqrMagnitude < epsilon) - return zero; - else { - float dot = Dot(v, n); - Vector3Float r = n * dot; - r /= sqrMagnitude; - return r; - } - - } - } - */ - - /// - /// 3-dimensional vectors - /// - /// This uses the right-handed coordinate system. - public struct Vector3Float { - - /// - /// The right axis of the vector - /// - public float horizontal; //> left/right - /// - /// The upward axis of the vector - /// - public float vertical; //> up/down - /// - /// The forward axis of the vector - /// - public float depth; //> forward/backward - - /// - /// Create a new 3-dimensional vector - /// - /// x axis value - /// y axis value - /// z axis value - public Vector3Float(float horizontal, float vertical, float depth) { - this.horizontal = horizontal; - this.vertical = vertical; - this.depth = depth; - } - - public Vector3Float(Vector3Int v) { - this.horizontal = v.horizontal; - this.vertical = v.vertical; - this.depth = v.depth; - } - - public static Vector3Float FromSpherical(Spherical s) { - float verticalRad = (AngleFloat.deg90 - s.direction.vertical).inRadians; - float horizontalRad = s.direction.horizontal.inRadians; - float cosVertical = MathF.Cos(verticalRad); - float sinVertical = MathF.Sin(verticalRad); - float cosHorizontal = MathF.Cos(horizontalRad); - float sinHorizontal = MathF.Sin(horizontalRad); - - float horizontal = s.distance * sinVertical * sinHorizontal; - float vertical = s.distance * cosVertical; - float depth = s.distance * sinVertical * cosHorizontal; - return new Vector3Float(horizontal, vertical, depth); - } - - public override string ToString() { - return $"({this.horizontal}, {this.vertical}, {this.depth})"; - } - - /// - /// A vector with zero for all axis - /// - public static readonly Vector3Float zero = new Vector3Float(0, 0, 0); - /// - /// A vector with one for all axis - /// - public static readonly Vector3Float one = new Vector3Float(1, 1, 1); - /// - /// A Vector3Float with values (-1, 0, 0) - /// - public static readonly Vector3Float left = new Vector3Float(-1, 0, 0); - /// - /// A vector with values (1, 0, 0) - /// - public static readonly Vector3Float right = new Vector3Float(1, 0, 0); - /// - /// A vector with values (0, -1, 0) - /// - public static readonly Vector3Float down = new Vector3Float(0, -1, 0); - /// - /// A vector with values (0, 1, 0) - /// - public static readonly Vector3Float up = new Vector3Float(0, 1, 0); - /// - /// A vector with values (0, 0, -1) - /// - public static readonly Vector3Float back = new Vector3Float(0, -1, 0); - /// - /// A vector with values (0, 0, 1) - /// - public static readonly Vector3Float forward = new Vector3Float(0, 1, 0); - - /// @brief The vector length - /// @return The vector length - public readonly float magnitude => MathF.Sqrt(horizontal * horizontal + vertical * vertical + depth * depth); - /// - /// The vector length - /// - /// The vector for which you need the length - /// The vector length - public static float MagnitudeOf(Vector3Float v) { - return v.magnitude; - } - - /// @brief The squared vector length - /// @return The squared vector length - /// @remark The squared length is computationally simpler than the real - /// length. Think of Pythagoras A^2 + B^2 = C^2. This leaves out the - /// calculation of the squared root of C. - public readonly float sqrMagnitude => (horizontal * horizontal + vertical * vertical + depth * depth); - - /// - /// The squared vector length - /// - /// The vector for which you need the squared length - /// The squared vector length - /// The squared length is computationally simpler than the real - /// length. Think of Pythagoras A^2 + B^2 = C^2. This leaves out the - /// calculation of the squared root of C. - public static float SqrMagnitudeOf(Vector3Float v) { - return v.sqrMagnitude; - } - - /// @brief Convert the vector to a length of 1 - /// @return The vector normalized to a length of 1 - public readonly Vector3Float normalized { - get { - float l = magnitude; - Vector3Float v = zero; - if (l > Float.epsilon) - v = this / l; - return v; - } - } - /// @brief Convert the vector to a length of 1 - /// @param v The vector to convert - /// @return The vector normalized to a length of 1 - public static Vector3Float Normalize(Vector3Float v) { - float num = v.magnitude; - Vector3Float result = zero; - if (num > Float.epsilon) - result = v / num; - - return result; - } - - /// - /// Negate te vector such that it points in the opposite direction - /// - /// - /// The negated vector - public static Vector3Float operator -(Vector3Float v1) { - Vector3Float v = new(-v1.horizontal, -v1.vertical, -v1.depth); - return v; - } - - /// - /// Subtract two vectors - /// - /// - /// - /// The result of the subtraction - public static Vector3Float operator -(Vector3Float v1, Vector3Float v2) { - Vector3Float v = new(v1.horizontal - v2.horizontal, v1.vertical - v2.vertical, v1.depth - v2.depth); - return v; - } - - /// - /// Add two vectors - /// - /// - /// - /// The result of the addition - public static Vector3Float operator +(Vector3Float v1, Vector3Float v2) { - Vector3Float v = new(v1.horizontal + v2.horizontal, v1.vertical + v2.vertical, v1.depth + v2.depth); - return v; - } - - /// @brief Scale the vector using another vector - /// @param v1 The vector to scale - /// @param v2 A vector with the scaling factors - /// @return The scaled vector - /// @remark Each component of the vector v1 will be multiplied with the - /// matching component from the scaling vector v2. - public static Vector3Float Scale(Vector3Float v1, Vector3Float v2) { - return new Vector3Float(v1.horizontal * v2.horizontal, v1.vertical * v2.vertical, v1.depth * v2.depth); - } - - - public static Vector3Float operator *(Vector3Float v1, float d) { - Vector3Float v = new(v1.horizontal * d, v1.vertical * d, v1.depth * d); - return v; - } - - public static Vector3Float operator *(float d, Vector3Float v1) { - Vector3Float v = new(d * v1.horizontal, d * v1.vertical, d * v1.depth); - return v; - } - - public static Vector3Float operator /(Vector3Float v1, float d) { - Vector3Float v = new(v1.horizontal / d, v1.vertical / d, v1.depth / d); - return v; - } - - - //public bool Equals(Vector3Float v) => (horizontal == v.horizontal && vertical == v.vertical && depth == v.depth); - - public static bool operator ==(Vector3Float v1, Vector3Float v2) { - return (v1.horizontal == v2.horizontal && v1.vertical == v2.vertical && v1.depth == v2.depth); - } - - public static bool operator !=(Vector3Float v1, Vector3Float v2) { - return (v1.horizontal != v2.horizontal || v1.vertical != v2.vertical || v1.depth != v2.depth); - } - - public override readonly bool Equals(object obj) { - if (obj is not Vector3Float v) - return false; - - return (horizontal == v.horizontal && vertical == v.vertical && depth == v.depth); - } - - public override readonly int GetHashCode() { - return HashCode.Combine(horizontal, vertical, depth); - } - - /// @brief The distance between two vectors - /// @param v1 The first vector - /// @param v2 The second vector - /// @return The distance between the two vectors - public static float Distance(Vector3Float v1, Vector3Float v2) { - return (v2 - v1).magnitude; - } - - /// @brief The dot product of two vectors - /// @param v1 The first vector - /// @param v2 The second vector - /// @return The dot product of the two vectors - public static float Dot(Vector3Float v1, Vector3Float v2) { - return v1.horizontal * v2.horizontal + v1.vertical * v2.vertical + v1.depth * v2.depth; - } - - /// @brief The cross product of two vectors - /// @param v1 The first vector - /// @param v2 The second vector - /// @return The cross product of the two vectors - public static Vector3Float Cross(Vector3Float v1, Vector3Float v2) { - return new Vector3Float(v1.vertical * v2.depth - v1.depth * v2.vertical, v1.depth * v2.horizontal - v1.horizontal * v2.depth, - v1.horizontal * v2.vertical - v1.vertical * v2.horizontal); - - } - - /// @brief Project the vector on another vector - /// @param v The vector to project - /// @param n The normal vecto to project on - /// @return The projected vector - public static Vector3Float Project(Vector3Float v, Vector3Float n) { - float sqrMagnitude = Dot(n, n); - if (sqrMagnitude < Float.epsilon) - return zero; - else { - float dot = Dot(v, n); - Vector3Float r = n * dot / sqrMagnitude; - return r; - } - } - - /// @brief Project the vector on a plane defined by a normal orthogonal to the - /// plane. - /// @param v The vector to project - /// @param n The normal of the plane to project on - /// @return Teh projected vector - public static Vector3Float ProjectOnPlane(Vector3Float v, Vector3Float n) { - Vector3Float r = v - Project(v, n); - return r; - } - - /// @brief The angle between two vectors - /// @param v1 The first vector - /// @param v2 The second vector - /// @return The angle between the two vectors - /// @remark This reterns an unsigned angle which is the shortest distance - /// between the two vectors. Use Vector3::SignedAngle if a signed angle is - /// needed. - public static AngleFloat UnsignedAngle(Vector3Float v1, Vector3Float v2) { - float denominator = MathF.Sqrt(v1.sqrMagnitude * v2.sqrMagnitude); - if (denominator < Float.epsilon) - return AngleFloat.zero; - - float dot = Dot(v1, v2); - float fraction = dot / denominator; - if (float.IsNaN(fraction)) - return AngleFloat.Degrees( - fraction); // short cut to returning NaN universally - - float cdot = Float.Clamp(fraction, -1.0f, 1.0f); - float r = MathF.Acos(cdot); - return AngleFloat.Radians(r); - } - /// @brief The signed angle between two vectors - /// @param v1 The starting vector - /// @param v2 The ending vector - /// @param axis The axis to rotate around - /// @return The signed angle between the two vectors - public static AngleFloat SignedAngle(Vector3Float v1, Vector3Float v2, - Vector3Float axis) { - // angle in [0,180] - AngleFloat angle = UnsignedAngle(v1, v2); - - Vector3Float cross = Cross(v1, v2); - float b = Dot(axis, cross); - float signd = b < 0 ? -1.0F : (b > 0 ? 1.0F : 0.0F); - - // angle in [-179,180] - AngleFloat signed_angle = angle * signd; - - return signed_angle; - } - - - /// @brief Lerp (linear interpolation) between two vectors - /// @param v1 The starting vector - /// @param v2 The ending vector - /// @param f The interpolation distance - /// @return The lerped vector - /// @remark The factor f is unclamped. Value 0 matches the vector *v1*, Value - /// 1 matches vector *v2*. Value -1 is vector *v1* minus the difference - /// between *v1* and *v2* etc. - public static Vector3Float Lerp(Vector3Float v1, Vector3Float v2, float f) { - Vector3Float v = v1 + (v2 - v1) * f; - return v; - } - - } -} -//#endif \ No newline at end of file diff --git a/Assets/NanoBrain/LinearAlgebra/src/Vector3Int.cs b/Assets/NanoBrain/LinearAlgebra/src/Vector3Int.cs deleted file mode 100644 index 18edf40..0000000 --- a/Assets/NanoBrain/LinearAlgebra/src/Vector3Int.cs +++ /dev/null @@ -1,273 +0,0 @@ -//#if !UNITY_5_3_OR_NEWER -using System; - -namespace LinearAlgebra { - - /// - /// 3-dimensional vectors - /// - /// This uses the right-handed coordinate system. - /// - /// Create a new 3-dimensional vector - /// - /// x axis value - /// y axis value - /// z axis value - public struct Vector3Int { - - /// - /// The right axis of the vector - /// - public int horizontal; //> left/right - /// - /// The upward axis of the vector - /// - public int vertical; //> up/down - /// - /// The forward axis of the vector - /// - public int depth; //> forward/backward - - public Vector3Int(int horizontal, int vertical, int depth) { - this.horizontal = horizontal; - this.vertical = vertical; - this.depth = depth; - } - - /// - /// A vector with zero for all axis - /// - public static readonly Vector3Int zero = new(0, 0, 0); - /// - /// A vector with one for all axis - /// - public static readonly Vector3Int one = new(1, 1, 1); - /// - /// A Vector3Int with values (-1, 0, 0) - /// - public static readonly Vector3Int left = new(-1, 0, 0); - /// - /// A vector with values (1, 0, 0) - /// - public static readonly Vector3Int right = new(1, 0, 0); - /// - /// A vector with values (0, -1, 0) - /// - public static readonly Vector3Int down = new(0, -1, 0); - /// - /// A vector with values (0, 1, 0) - /// - public static readonly Vector3Int up = new(0, 1, 0); - /// - /// A vector with values (0, 0, -1) - /// - public static readonly Vector3Int back = new(0, -1, 0); - /// - /// A vector with values (0, 0, 1) - /// - public static readonly Vector3Int forward = new(0, 1, 0); - - /// @brief The vector length - /// @return The vector length - public readonly float magnitude => MathF.Sqrt(horizontal * horizontal + vertical * vertical + depth * depth); - /// - /// The vector length - /// - /// The vector for which you need the length - /// The vector length - public static float MagnitudeOf(Vector3Int v) { - return v.magnitude; - } - - /// @brief The squared vector length - /// @return The squared vector length - /// @remark The squared length is computationally simpler than the real - /// length. Think of Pythagoras A^2 + B^2 = C^2. This leaves out the - /// calculation of the squared root of C. - public readonly float sqrMagnitude => (horizontal * horizontal + vertical * vertical + depth * depth); - - /// - /// The squared vector length - /// - /// The vector for which you need the squared length - /// The squared vector length - /// The squared length is computationally simpler than the real - /// length. Think of Pythagoras A^2 + B^2 = C^2. This leaves out the - /// calculation of the squared root of C. - public static float SqrMagnitudeOf(Vector3Int v) { - return v.sqrMagnitude; - } - - /// @brief Convert the vector to a length of 1 - /// @return The vector normalized to a length of 1 - public readonly Vector3Float normalized { - get { - float l = magnitude; - Vector3Float v = Vector3Float.zero; - if (l > Float.epsilon) - v = new Vector3Float(this) / l; - return v; - } - } - /// @brief Convert the vector to a length of 1 - /// @param v The vector to convert - /// @return The vector normalized to a length of 1 - public static Vector3Float Normalize(Vector3Int v) { - float num = v.magnitude; - Vector3Float result = Vector3Float.zero; - if (num > Float.epsilon) - result = new Vector3Float(v) / num; - - return result; - } - - /// - /// Negate te vector such that it points in the opposite direction - /// - /// - /// The negated vector - public static Vector3Int operator -(Vector3Int v1) { - Vector3Int v = new(-v1.horizontal, -v1.vertical, -v1.depth); - return v; - } - - /// - /// Subtract two vectors - /// - /// - /// - /// The result of the subtraction - public static Vector3Int operator -(Vector3Int v1, Vector3Int v2) { - Vector3Int v = new(v1.horizontal - v2.horizontal, v1.vertical - v2.vertical, v1.depth - v2.depth); - return v; - } - - /// - /// Add two vectors - /// - /// - /// - /// The result of the addition - public static Vector3Int operator +(Vector3Int v1, Vector3Int v2) { - Vector3Int v = new(v1.horizontal + v2.horizontal, v1.vertical + v2.vertical, v1.depth + v2.depth); - return v; - } - - /// @brief Scale the vector using another vector - /// @param v1 The vector to scale - /// @param v2 A vector with the scaling factors - /// @return The scaled vector - /// @remark Each component of the vector v1 will be multiplied with the - /// matching component from the scaling vector v2. - public static Vector3Int Scale(Vector3Int v1, Vector3Int v2) { - return new Vector3Int(v1.horizontal * v2.horizontal, v1.vertical * v2.vertical, v1.depth * v2.depth); - } - - - public static Vector3Int operator *(Vector3Int v1, int d) { - Vector3Int v = new(v1.horizontal * d, v1.vertical * d, v1.depth * d); - return v; - } - - public static Vector3Int operator *(int d, Vector3Int v1) { - Vector3Int v = new(d * v1.horizontal, d * v1.vertical, d * v1.depth); - return v; - } - - public static Vector3Int operator /(Vector3Int v1, int d) { - Vector3Int v = new(v1.horizontal / d, v1.vertical / d, v1.depth / d); - return v; - } - - public bool Equals(Vector3Int v) => (horizontal == v.horizontal && vertical == v.vertical && depth == v.depth); - - public override bool Equals(object obj) { - if (!(obj is Vector3Int v)) - return false; - - return (horizontal == v.horizontal && vertical == v.vertical && depth == v.depth); - } - - public static bool operator ==(Vector3Int v1, Vector3Int v2) { - return (v1.horizontal == v2.horizontal && v1.vertical == v2.vertical && v1.depth == v2.depth); - } - - public static bool operator !=(Vector3Int v1, Vector3Int v2) { - return (v1.horizontal != v2.horizontal || v1.vertical != v2.vertical || v1.depth != v2.depth); - } - - public override int GetHashCode() { - return (horizontal, vertical, depth).GetHashCode(); - } - - /// @brief The distance between two vectors - /// @param v1 The first vector - /// @param v2 The second vector - /// @return The distance between the two vectors - public static float Distance(Vector3Int v1, Vector3Int v2) { - return (v2 - v1).magnitude; - } - - /// @brief The dot product of two vectors - /// @param v1 The first vector - /// @param v2 The second vector - /// @return The dot product of the two vectors - public static float Dot(Vector3Int v1, Vector3Int v2) { - return v1.horizontal * v2.horizontal + v1.vertical * v2.vertical + v1.depth * v2.depth; - } - - /// @brief The cross product of two vectors - /// @param v1 The first vector - /// @param v2 The second vector - /// @return The cross product of the two vectors - public static Vector3Int Cross(Vector3Int v1, Vector3Int v2) { - return new Vector3Int(v1.vertical * v2.depth - v1.depth * v2.vertical, v1.depth * v2.horizontal - v1.horizontal * v2.depth, - v1.horizontal * v2.vertical - v1.vertical * v2.horizontal); - - } - - /// @brief The angle between two vectors - /// @param v1 The first vector - /// @param v2 The second vector - /// @return The angle between the two vectors - /// @remark This reterns an unsigned angle which is the shortest distance - /// between the two vectors. Use Vector3::SignedAngle if a signed angle is - /// needed. - public static AngleFloat UnsignedAngle(Vector3Int v1, Vector3Int v2) { - float denominator = MathF.Sqrt(v1.sqrMagnitude * v2.sqrMagnitude); - if (denominator < Float.epsilon) - return AngleFloat.zero; - - float dot = Dot(v1, v2); - float fraction = dot / denominator; - if (float.IsNaN(fraction)) - return AngleFloat.Degrees( - fraction); // short cut to returning NaN universally - - float cdot = Float.Clamp(fraction, -1.0f, 1.0f); - float r = MathF.Acos(cdot); - return AngleFloat.Radians(r); - } - /// @brief The signed angle between two vectors - /// @param v1 The starting vector - /// @param v2 The ending vector - /// @param axis The axis to rotate around - /// @return The signed angle between the two vectors - public static AngleFloat SignedAngle(Vector3Int v1, Vector3Int v2, - Vector3Int axis) { - // angle in [0,180] - AngleFloat angle = UnsignedAngle(v1, v2); - - Vector3Int cross = Cross(v1, v2); - float b = Dot(axis, cross); - float signd = b < 0 ? -1.0F : (b > 0 ? 1.0F : 0.0F); - - // angle in [-179,180] - AngleFloat signed_angle = angle * signd; - - return signed_angle; - } - - } -} -//#endif \ No newline at end of file diff --git a/Assets/NanoBrain/LinearAlgebra/src/float16.cs b/Assets/NanoBrain/LinearAlgebra/src/float16.cs deleted file mode 100644 index 4b58cdd..0000000 --- a/Assets/NanoBrain/LinearAlgebra/src/float16.cs +++ /dev/null @@ -1,322 +0,0 @@ -using System; - -namespace LinearAlgebra { - - public class float16 { - // - // FILE: float16.cpp - // AUTHOR: Rob Tillaart - // VERSION: 0.1.8 - // PURPOSE: library for Float16s for Arduino - // URL: http://en.wikipedia.org/wiki/Half-precision_floating-point_format - - ushort _value; - - public float16() { _value = 0; } - - public float16(float f) { - //_value = f32tof16(f); - _value = F32ToF16__(f); - } - - public float toFloat() { - return f16tof32(_value); - } - - public ushort GetBinary() { return _value; } - public void SetBinary(ushort value) { _value = value; } - - ////////////////////////////////////////////////////////// - // - // EQUALITIES - // - /* - bool float16::operator ==(const float16 &f) { return (_value == f._value); } - - bool float16::operator !=(const float16 &f) { return (_value != f._value); } - - bool float16::operator >(const float16 &f) { - if ((_value & 0x8000) && (f._value & 0x8000)) - return _value < f._value; - if (_value & 0x8000) - return false; - if (f._value & 0x8000) - return true; - return _value > f._value; - } - - bool float16::operator >=(const float16 &f) { - if ((_value & 0x8000) && (f._value & 0x8000)) - return _value <= f._value; - if (_value & 0x8000) - return false; - if (f._value & 0x8000) - return true; - return _value >= f._value; - } - - bool float16::operator <(const float16 &f) { - if ((_value & 0x8000) && (f._value & 0x8000)) - return _value > f._value; - if (_value & 0x8000) - return true; - if (f._value & 0x8000) - return false; - return _value < f._value; - } - - bool float16::operator <=(const float16 &f) { - if ((_value & 0x8000) && (f._value & 0x8000)) - return _value >= f._value; - if (_value & 0x8000) - return true; - if (f._value & 0x8000) - return false; - return _value <= f._value; - } - - ////////////////////////////////////////////////////////// - // - // NEGATION - // - float16 float16::operator -() { - float16 f16; - f16.setBinary(_value ^ 0x8000); - return f16; - } - - ////////////////////////////////////////////////////////// - // - // MATH - // - float16 float16::operator +(const float16 &f) { - return float16(this->toDouble() + f.toDouble()); - } - - float16 float16::operator -(const float16 &f) { - return float16(this->toDouble() - f.toDouble()); - } - - float16 float16::operator *(const float16 &f) { - return float16(this->toDouble() * f.toDouble()); - } - - float16 float16::operator /(const float16 &f) { - return float16(this->toDouble() / f.toDouble()); - } - - float16 & float16::operator+=(const float16 &f) { - *this = this->toDouble() + f.toDouble(); - return *this; - } - - float16 & float16::operator-=(const float16 &f) { - *this = this->toDouble() - f.toDouble(); - return *this; - } - - float16 & float16::operator*=(const float16 &f) { - *this = this->toDouble() * f.toDouble(); - return *this; - } - - float16 & float16::operator/=(const float16 &f) { - *this = this->toDouble() / f.toDouble(); - return *this; - } - - ////////////////////////////////////////////////////////// - // - // MATH HELPER FUNCTIONS - // - int float16::sign() { - if (_value & 0x8000) - return -1; - if (_value & 0xFFFF) - return 1; - return 0; - } - - bool float16::isZero() { return ((_value & 0x7FFF) == 0x0000); } - - bool float16::isNaN() { - if ((_value & 0x7C00) != 0x7C00) - return false; - if ((_value & 0x03FF) == 0x0000) - return false; - return true; - } - - bool float16::isInf() { return ((_value == 0x7C00) || (_value == 0xFC00)); } - */ - ////////////////////////////////////////////////////////// - // - // CORE CONVERSION - // - float f16tof32(ushort _value) { - //ushort sgn; - ushort man; - int exp; - float f; - - //Debug.Log($"{_value}"); - - bool sgn = (_value & 0x8000) > 0; - exp = (_value & 0x7C00) >> 10; - man = (ushort)(_value & 0x03FF); - - //Debug.Log($"{sgn} {exp} {man}"); - - // ZERO - if ((_value & 0x7FFF) == 0) { - return sgn ? -0 : 0; - } - // NAN & INF - if (exp == 0x001F) { - if (man == 0) - return sgn ? float.NegativeInfinity : float.PositiveInfinity; //-INFINITY : INFINITY; - else - return float.NaN; // NAN; - } - - // SUBNORMAL/NORMAL - if (exp == 0) - f = 0; - else - f = 1; - - // PROCESS MANTISSE - for (int i = 9; i >= 0; i--) { - f *= 2; - if ((man & (1 << i)) != 0) - f = f + 1; - } - //Debug.Log($"{f}"); - f = f * (float)Math.Pow(2.0f, exp - 25); - if (exp == 0) { - f = f * (float)Math.Pow(2.0f, -13); // 5.96046447754e-8; - } - //Debug.Log($"{f}"); - return sgn ? -f : f; - } - - public static uint SingleToInt32Bits(float value) { - byte[] bytes = BitConverter.GetBytes(value); - if (BitConverter.IsLittleEndian) - Array.Reverse(bytes); // If the system is little-endian, reverse the byte order - return BitConverter.ToUInt32(bytes, 0); - } - - public ushort F32ToF16__(float f) { - uint t = BitConverter.ToUInt32(BitConverter.GetBytes(f), 0); - ushort man = (ushort)((t & 0x007FFFFF) >> 12); - int exp = (int)((t & 0x7F800000) >> 23); - bool sgn = (t & 0x80000000) != 0; - - // handle 0 - if ((t & 0x7FFFFFFF) == 0) { - return sgn ? (ushort)0x8000 : (ushort)0x0000; - } - // denormalized float32 does not fit in float16 - if (exp == 0x00) { - return sgn ? (ushort)0x8000 : (ushort)0x0000; - } - // handle infinity & NAN - if (exp == 0x00FF) { - if (man != 0) - return 0xFE00; // NAN - return sgn ? (ushort)0xFC00 : (ushort)0x7C00; // -INF : INF - } - - // normal numbers - exp = exp - 127 + 15; - // overflow does not fit => INF - if (exp > 30) { - return sgn ? (ushort)0xFC00 : (ushort)0x7C00; // -INF : INF - } - // subnormal numbers - if (exp < -38) { - return sgn ? (ushort)0x8000 : (ushort)0x0000; // -0 or 0 ? just 0 ? - } - if (exp <= 0) // subnormal - { - man >>= (exp + 14); - // rounding - man++; - man >>= 1; - if (sgn) - return (ushort)(0x8000 | man); - return man; - } - - // normal - // TODO rounding - exp <<= 10; - man++; - man >>= 1; - if (sgn) - return (ushort)(0x8000 | exp | man); - return (ushort)(exp | man); - } - - //This function is faulty!!!! - ushort f32tof16(float f) { - //uint t = *(uint*)&f; - //uint t = (uint)BitConverter.SingleToInt32Bits(f); - uint t = SingleToInt32Bits(f); - // man bits = 10; but we keep 11 for rounding - ushort man = (ushort)((t & 0x007FFFFF) >> 12); - short exp = (short)((t & 0x7F800000) >> 23); - bool sgn = (t & 0x80000000) != 0; - - // handle 0 - if ((t & 0x7FFFFFFF) == 0) { - return sgn ? (ushort)0x8000 : (ushort)0x0000; - } - // denormalized float32 does not fit in float16 - if (exp == 0x00) { - return sgn ? (ushort)0x8000 : (ushort)0x0000; - } - // handle infinity & NAN - if (exp == 0x00FF) { - if (man != 0) - return 0xFE00; // NAN - return sgn ? (ushort)0xFC00 : (ushort)0x7C00; // -INF : INF - } - - // normal numbers - exp = (short)(exp - 127 + 15); - // overflow does not fit => INF - if (exp > 30) { - return sgn ? (ushort)0xFC00 : (ushort)0x7C00; // -INF : INF - } - // subnormal numbers - if (exp < -38) { - return sgn ? (ushort)0x8000 : (ushort)0x0000; // -0 or 0 ? just 0 ? - } - if (exp <= 0) // subnormal - { - man >>= (exp + 14); - // rounding - man++; - man >>= 1; - if (sgn) - return (ushort)(0x8000 | man); - return man; - } - - // normal - // TODO rounding - exp <<= 10; - man++; - man >>= 1; - ushort uexp = (ushort)exp; - if (sgn) - return (ushort)(0x8000 | uexp | man); - return (ushort)(uexp | man); - } - - // -- END OF FILE -- - } - -} \ No newline at end of file diff --git a/Assets/NanoBrain/LinearAlgebra/test/AngleTest.cs b/Assets/NanoBrain/LinearAlgebra/test/AngleTest.cs deleted file mode 100644 index 8362d82..0000000 --- a/Assets/NanoBrain/LinearAlgebra/test/AngleTest.cs +++ /dev/null @@ -1,501 +0,0 @@ -#if !UNITY_5_6_OR_NEWER -using System; -using System.Formats.Asn1; -using NUnit.Framework; - -namespace LinearAlgebra.Test { - public class AngleTests { - [SetUp] - public void Setup() { - } - - [Test] - public void Construct() { - // Degrees - float angle = 0.0f; - AngleFloat a = AngleFloat.Degrees(angle); - Assert.AreEqual(angle, a.inDegrees); - - angle = -180.0f; - a = AngleFloat.Degrees(angle); - Assert.AreEqual(angle, a.inDegrees); - - angle = 270.0f; - a = AngleFloat.Degrees(angle); - Assert.AreEqual(-90, a.inDegrees); - - angle = -270.0f; - a = AngleFloat.Degrees(angle); - Assert.AreEqual(90, a.inDegrees); - - // Radians - angle = 0.0f; - a = AngleFloat.Radians(angle); - Assert.AreEqual(angle, a.inRadians); - - angle = (float)-Math.PI; - a = AngleFloat.Radians(angle); - Assert.AreEqual(angle, a.inRadians); - - angle = (float)Math.PI * 1.5f; - a = AngleFloat.Radians(angle); - Assert.AreEqual(-Math.PI * 0.5f, a.inRadians, 1.0E-05F); - - // Revolutions - angle = 0.0f; - a = AngleFloat.Revolutions(angle); - Assert.AreEqual(angle, a.inRevolutions); - - angle = -0.5f; - a = AngleFloat.Revolutions(angle); - Assert.AreEqual(angle, a.inRevolutions); - - angle = 0.75f; - a = AngleFloat.Revolutions(angle); - Assert.AreEqual(-0.25f, a.inRevolutions); - - } - - [Test] - public void Revolutions() { - AngleFloat a; - - // Test zero - a = AngleFloat.Revolutions(0.0f); - Assert.AreEqual(0.0f, a.inRevolutions); - - // Test positive values within range - a = AngleFloat.Revolutions(0.25f); - Assert.AreEqual(0.25f, a.inRevolutions); - - a = AngleFloat.Revolutions(0.5f); - Assert.AreEqual(-0.5f, a.inRevolutions); - - // Test negative values within range - a = AngleFloat.Revolutions(-0.25f); - Assert.AreEqual(-0.25f, a.inRevolutions); - - a = AngleFloat.Revolutions(-0.5f); - Assert.AreEqual(-0.5f, a.inRevolutions); - - // Test values outside range (positive) - a = AngleFloat.Revolutions(1.0f); - Assert.AreEqual(0.0f, a.inRevolutions); - - a = AngleFloat.Revolutions(1.25f); - Assert.AreEqual(0.25f, a.inRevolutions); - - a = AngleFloat.Revolutions(1.75f); - Assert.AreEqual(-0.25f, a.inRevolutions); - - // Test values outside range (negative) - a = AngleFloat.Revolutions(-1.0f); - Assert.AreEqual(0.0f, a.inRevolutions); - - a = AngleFloat.Revolutions(-1.25f); - Assert.AreEqual(-0.25f, a.inRevolutions); - - a = AngleFloat.Revolutions(-1.75f); - Assert.AreEqual(0.25f, a.inRevolutions); - - // Test infinity - a = AngleFloat.Revolutions(float.PositiveInfinity); - Assert.AreEqual(float.PositiveInfinity, a.inRevolutions); - - a = AngleFloat.Revolutions(float.NegativeInfinity); - Assert.AreEqual(float.NegativeInfinity, a.inRevolutions); - } - - [Test] - public void Equality() { - // Test equality operator - Assert.IsTrue(AngleFloat.Degrees(90) == AngleFloat.Degrees(90), "90 == 90"); - Assert.IsFalse(AngleFloat.Degrees(90) == AngleFloat.Degrees(45), "90 == 45"); - Assert.IsTrue(AngleFloat.Degrees(0) == AngleFloat.Degrees(0), "0 == 0"); - Assert.IsTrue(AngleFloat.Degrees(-180) == AngleFloat.Degrees(-180), "-180 == -180"); - - // Test inequality operator - Assert.IsTrue(AngleFloat.Degrees(90) != AngleFloat.Degrees(45), "90 != 45"); - Assert.IsFalse(AngleFloat.Degrees(90) != AngleFloat.Degrees(90), "90 != 90"); - Assert.IsTrue(AngleFloat.Degrees(0) != AngleFloat.Degrees(1), "0 != 1"); - - // Test greater than operator - Assert.IsTrue(AngleFloat.Degrees(90) > AngleFloat.Degrees(45), "90 > 45"); - Assert.IsFalse(AngleFloat.Degrees(45) > AngleFloat.Degrees(90), "45 > 90"); - Assert.IsFalse(AngleFloat.Degrees(90) > AngleFloat.Degrees(90), "90 > 90"); - - // Test greater than or equal operator - Assert.IsTrue(AngleFloat.Degrees(90) >= AngleFloat.Degrees(45), "90 >= 45"); - Assert.IsTrue(AngleFloat.Degrees(90) >= AngleFloat.Degrees(90), "90 >= 90"); - Assert.IsFalse(AngleFloat.Degrees(45) >= AngleFloat.Degrees(90), "45 >= 90"); - - // Test less than operator - Assert.IsTrue(AngleFloat.Degrees(45) < AngleFloat.Degrees(90), "45 < 90"); - Assert.IsFalse(AngleFloat.Degrees(90) < AngleFloat.Degrees(45), "90 < 45"); - Assert.IsFalse(AngleFloat.Degrees(90) < AngleFloat.Degrees(90), "90 < 90"); - - // Test less than or equal operator - Assert.IsTrue(AngleFloat.Degrees(45) <= AngleFloat.Degrees(90), "45 <= 90"); - Assert.IsTrue(AngleFloat.Degrees(90) <= AngleFloat.Degrees(90), "90 <= 90"); - Assert.IsFalse(AngleFloat.Degrees(90) <= AngleFloat.Degrees(45), "90 <= 45"); - } - - // [Test] - // public void Normalize() { - // float r = 0; - - // r = Angle.Normalize(90); - // Assert.AreEqual(r, 90, "Normalize 90"); - - // r = Angle.Normalize(-90); - // Assert.AreEqual(r, -90, "Normalize -90"); - - // r = Angle.Normalize(270); - // Assert.AreEqual(r, -90, "Normalize 270"); - - // r = Angle.Normalize(270 + 360); - // Assert.AreEqual(r, -90, "Normalize 270+360"); - - // r = Angle.Normalize(-270); - // Assert.AreEqual(r, 90, "Normalize -270"); - - // r = Angle.Normalize(-270 - 360); - // Assert.AreEqual(r, 90, "Normalize -270-360"); - - // r = Angle.Normalize(0); - // Assert.AreEqual(r, 0, "Normalize 0"); - - // r = Angle.Normalize(float.PositiveInfinity); - // Assert.AreEqual(r, float.PositiveInfinity, "Normalize INFINITY"); - - // r = Angle.Normalize(float.NegativeInfinity); - // Assert.AreEqual(r, float.NegativeInfinity, "Normalize INFINITY"); - // } - - [Test] - public void Clamp() { - float r = 0; - - r = AngleFloat.Clamp(AngleFloat.Degrees(1), AngleFloat.Degrees(0), AngleFloat.Degrees(2)); - Assert.AreEqual(1, r, "Clamp 1 0 2"); - - r = AngleFloat.Clamp(AngleFloat.Degrees(-1), AngleFloat.Degrees(0), AngleFloat.Degrees(2)); - Assert.AreEqual(0, r, "Clamp -1 0 2"); - - r = AngleFloat.Clamp(AngleFloat.Degrees(3), AngleFloat.Degrees(0), AngleFloat.Degrees(2)); - Assert.AreEqual(2, r, "Clamp 3 0 2"); - - r = AngleFloat.Clamp(AngleFloat.Degrees(1), AngleFloat.Degrees(0), AngleFloat.Degrees(0)); - Assert.AreEqual(0, r, "Clamp 1 0 0"); - - r = AngleFloat.Clamp(AngleFloat.Degrees(0), AngleFloat.Degrees(0), AngleFloat.Degrees(0)); - Assert.AreEqual(0, r, "Clamp 0 0 0"); - - r = AngleFloat.Clamp(AngleFloat.Degrees(0), AngleFloat.Degrees(1), AngleFloat.Degrees(-1)); - Assert.AreEqual(1, r, "Clamp 0 1 -1"); - - r = AngleFloat.Clamp(AngleFloat.Degrees(1), AngleFloat.Degrees(0), AngleFloat.Degrees(float.PositiveInfinity)); - Assert.AreEqual(1, r, "Clamp 1 0 INFINITY"); - - r = AngleFloat.Clamp(AngleFloat.Degrees(1), AngleFloat.Degrees(float.NegativeInfinity), AngleFloat.Degrees(1)); - Assert.AreEqual(1, r, "Clamp 1 -INFINITY 1"); - } - - [Test] - public void Cos() { - // Test zero - Assert.AreEqual(1.0f, AngleFloat.Cos(AngleFloat.Degrees(0)), 1.0E-05F, "Cos(0°)"); - - // Test 90 degrees - Assert.AreEqual(0.0f, AngleFloat.Cos(AngleFloat.Degrees(90)), 1.0E-05F, "Cos(90°)"); - - // Test 180 degrees - Assert.AreEqual(-1.0f, AngleFloat.Cos(AngleFloat.Degrees(180)), 1.0E-05F, "Cos(180°)"); - - // Test 270 degrees - Assert.AreEqual(0.0f, AngleFloat.Cos(AngleFloat.Degrees(270)), 1.0E-05F, "Cos(270°)"); - - // Test 45 degrees - Assert.AreEqual(MathF.Sqrt(2) / 2, AngleFloat.Cos(AngleFloat.Degrees(45)), 1.0E-05F, "Cos(45°)"); - - // Test negative angle - Assert.AreEqual(1.0f, AngleFloat.Cos(AngleFloat.Degrees(-360)), 1.0E-05F, "Cos(-360°)"); - - // Test using radians - Assert.AreEqual(1.0f, AngleFloat.Cos(AngleFloat.Radians(0)), 1.0E-05F, "Cos(0 rad)"); - Assert.AreEqual(0.0f, AngleFloat.Cos(AngleFloat.Radians((float)Math.PI / 2)), 1.0E-05F, "Cos(π/2)"); - Assert.AreEqual(-1.0f, AngleFloat.Cos(AngleFloat.Radians((float)Math.PI)), 1.0E-05F, "Cos(π)"); - } - - [Test] - public void Sin() { - // Test zero - Assert.AreEqual(0.0f, AngleFloat.Sin(AngleFloat.Degrees(0)), 1.0E-05F, "Sin(0°)"); - - // Test 90 degrees - Assert.AreEqual(1.0f, AngleFloat.Sin(AngleFloat.Degrees(90)), 1.0E-05F, "Sin(90°)"); - - // Test 180 degrees - Assert.AreEqual(0.0f, AngleFloat.Sin(AngleFloat.Degrees(180)), 1.0E-05F, "Sin(180°)"); - - // Test 270 degrees - Assert.AreEqual(-1.0f, AngleFloat.Sin(AngleFloat.Degrees(270)), 1.0E-05F, "Sin(270°)"); - - // Test 45 degrees - Assert.AreEqual(MathF.Sqrt(2) / 2, AngleFloat.Sin(AngleFloat.Degrees(45)), 1.0E-05F, "Sin(45°)"); - - // Test negative angle - Assert.AreEqual(0.0f, AngleFloat.Sin(AngleFloat.Degrees(-360)), 1.0E-05F, "Sin(-360°)"); - - // Test using radians - Assert.AreEqual(0.0f, AngleFloat.Sin(AngleFloat.Radians(0)), 1.0E-05F, "Sin(0 rad)"); - Assert.AreEqual(1.0f, AngleFloat.Sin(AngleFloat.Radians((float)Math.PI / 2)), 1.0E-05F, "Sin(π/2)"); - Assert.AreEqual(0.0f, AngleFloat.Sin(AngleFloat.Radians((float)Math.PI)), 1.0E-05F, "Sin(π)"); - } - - [Test] - public void Tan() { - // Test zero - Assert.AreEqual(0.0f, AngleFloat.Tan(AngleFloat.Degrees(0)), 1.0E-05F, "Tan(0°)"); - - // Test 45 degrees - Assert.AreEqual(1.0f, AngleFloat.Tan(AngleFloat.Degrees(45)), 1.0E-05F, "Tan(45°)"); - - // Test -45 degrees - Assert.AreEqual(-1.0f, AngleFloat.Tan(AngleFloat.Degrees(-45)), 1.0E-05F, "Tan(-45°)"); - - // Test using radians - Assert.AreEqual(0.0f, AngleFloat.Tan(AngleFloat.Radians(0)), 1.0E-05F, "Tan(0 rad)"); - Assert.AreEqual(1.0f, AngleFloat.Tan(AngleFloat.Radians((float)Math.PI / 4)), 1.0E-05F, "Tan(π/4)"); - } - - [Test] - public void Acos() { - // Test 1 (0 degrees) - Assert.AreEqual(0.0f, AngleFloat.Acos(1.0f).inRadians, 1.0E-05F, "Acos(1)"); - - // Test 0 (90 degrees or π/2 radians) - Assert.AreEqual((float)Math.PI / 2, AngleFloat.Acos(0.0f).inRadians, 1.0E-05F, "Acos(0)"); - - // Test -1 (-180 degrees or π radians) - Assert.AreEqual((float)-Math.PI, AngleFloat.Acos(-1.0f).inRadians, 1.0E-05F, "Acos(-1)"); - - // Test 0.5 (60 degrees or π/3 radians) - Assert.AreEqual((float)Math.PI / 3, AngleFloat.Acos(0.5f).inRadians, 1.0E-05F, "Acos(0.5)"); - - // Test sqrt(2)/2 (45 degrees or π/4 radians) - Assert.AreEqual((float)Math.PI / 4, AngleFloat.Acos(MathF.Sqrt(2) / 2).inRadians, 1.0E-05F, "Acos(√2/2)"); - } - - [Test] - public void Asin() { - // Test 0 (0 degrees) - Assert.AreEqual(0.0f, AngleFloat.Asin(0.0f).inRadians, 1.0E-05F, "Asin(0)"); - - // Test 1 (90 degrees or π/2 radians) - Assert.AreEqual((float)Math.PI / 2, AngleFloat.Asin(1.0f).inRadians, 1.0E-05F, "Asin(1)"); - - // Test -1 (-90 degrees or -π/2 radians) - Assert.AreEqual(-(float)Math.PI / 2, AngleFloat.Asin(-1.0f).inRadians, 1.0E-05F, "Asin(-1)"); - - // Test 0.5 (30 degrees or π/6 radians) - Assert.AreEqual((float)Math.PI / 6, AngleFloat.Asin(0.5f).inRadians, 1.0E-05F, "Asin(0.5)"); - - // Test sqrt(2)/2 (45 degrees or π/4 radians) - Assert.AreEqual((float)Math.PI / 4, AngleFloat.Asin(MathF.Sqrt(2) / 2).inRadians, 1.0E-05F, "Asin(√2/2)"); - } - - - [Test] - public void Atan() { - // Test zero - Assert.AreEqual(0.0f, AngleFloat.Atan(0.0f).inRadians, 1.0E-05F, "Atan(0)"); - - // Test 1 (45 degrees or π/4 radians) - Assert.AreEqual((float)Math.PI / 4, AngleFloat.Atan(1.0f).inRadians, 1.0E-05F, "Atan(1)"); - - // Test -1 (-45 degrees or -π/4 radians) - Assert.AreEqual(-(float)Math.PI / 4, AngleFloat.Atan(-1.0f).inRadians, 1.0E-05F, "Atan(-1)"); - - // Test sqrt(3) (60 degrees or π/3 radians) - Assert.AreEqual((float)Math.PI / 3, AngleFloat.Atan(MathF.Sqrt(3)).inRadians, 1.0E-05F, "Atan(√3)"); - - // Test 1/sqrt(3) (30 degrees or π/6 radians) - Assert.AreEqual((float)Math.PI / 6, AngleFloat.Atan(1.0f / MathF.Sqrt(3)).inRadians, 1.0E-05F, "Atan(1/√3)"); - - // Test positive infinity - Assert.AreEqual((float)Math.PI / 2, AngleFloat.Atan(float.PositiveInfinity).inRadians, 1.0E-05F, "Atan(+∞)"); - - // Test negative infinity - Assert.AreEqual(-(float)Math.PI / 2, AngleFloat.Atan(float.NegativeInfinity).inRadians, 1.0E-05F, "Atan(-∞)"); - } - - [Test] - public void Atan2() { - // Test basic quadrant I - Assert.AreEqual((float)Math.PI / 4, AngleFloat.Atan2(1.0f, 1.0f).inRadians, 1.0E-05F, "Atan2(1, 1)"); - - // Test quadrant II - Assert.AreEqual(3 * (float)Math.PI / 4, AngleFloat.Atan2(1.0f, -1.0f).inRadians, 1.0E-05F, "Atan2(1, -1)"); - - // Test quadrant III - Assert.AreEqual(-(float)Math.PI * 0.75f, AngleFloat.Atan2(-1.0f, -1.0f).inRadians, 1.0E-05F, "Atan2(-1, -1)"); - - // Test quadrant IV - Assert.AreEqual(-(float)Math.PI / 4, AngleFloat.Atan2(-1.0f, 1.0f).inRadians, 1.0E-05F, "Atan2(-1, 1)"); - - // Test positive x-axis - Assert.AreEqual(0.0f, AngleFloat.Atan2(0.0f, 1.0f).inRadians, 1.0E-05F, "Atan2(0, 1)"); - - // Test positive y-axis - Assert.AreEqual((float)Math.PI / 2, AngleFloat.Atan2(1.0f, 0.0f).inRadians, 1.0E-05F, "Atan2(1, 0)"); - - // Test negative y-axis - Assert.AreEqual(-(float)Math.PI / 2, AngleFloat.Atan2(-1.0f, 0.0f).inRadians, 1.0E-05F, "Atan2(-1, 0)"); - - // Test origin - Assert.AreEqual(0.0f, AngleFloat.Atan2(0.0f, 0.0f).inRadians, 1.0E-05F, "Atan2(0, 0)"); - - // Test with different magnitudes - Assert.AreEqual((float)Math.PI / 3, AngleFloat.Atan2(MathF.Sqrt(3), 1.0f).inRadians, 1.0E-05F, "Atan2(√3, 1)"); - - // Test negative x-axis - Assert.AreEqual((float)-Math.PI, AngleFloat.Atan2(0.0f, -1.0f).inRadians, 1.0E-05F, "Atan2(0, -1)"); - } - - [Test] - public void Multiplication() { - AngleFloat r = AngleFloat.zero; - - // Angle * float - r = AngleFloat.Degrees(90) * 2; - Assert.AreEqual(-180, r.inDegrees, "Multiply 90 * 2"); - - r = AngleFloat.Degrees(45) * 0.5f; - Assert.AreEqual(22.5f, r.inDegrees, "Multiply 45 * 0.5"); - - r = AngleFloat.Degrees(90) * 0; - Assert.AreEqual(0, r.inDegrees, "Multiply 90 * 0"); - - r = AngleFloat.Degrees(-90) * 2; - Assert.AreEqual(-180, r.inDegrees, "Multiply -90 * 2"); - - r = AngleFloat.Degrees(270) * 2; - Assert.AreEqual(-180, r.inDegrees, "Multiply 270 * 2 (normalized)"); - - // float * Angle - r = 2 * AngleFloat.Degrees(90); - Assert.AreEqual(-180, r.inDegrees, "Multiply 2 * 90"); - - r = 0.5f * AngleFloat.Degrees(45); - Assert.AreEqual(22.5, r.inDegrees, "Multiply 0.5 * 45"); - - r = 0 * AngleFloat.Degrees(90); - Assert.AreEqual(0, r.inDegrees, "Multiply 0 * 90"); - - r = 2 * AngleFloat.Degrees(-90); - Assert.AreEqual(-180, r.inDegrees, "Multiply 2 * -90"); - - // Negative factor - r = AngleFloat.Degrees(90) * -1; - Assert.AreEqual(-90, r.inDegrees, "Multiply 90 * -1"); - - r = -1 * AngleFloat.Degrees(90); - Assert.AreEqual(-90, r.inDegrees, "Multiply -1 * 90"); - } - - [Test] - public void MoveTowards() { - AngleFloat r = AngleFloat.zero; - - r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(90), 30); - Assert.AreEqual(30, r.inDegrees, "MoveTowards 0 90 30"); - - r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(90), 90); - Assert.AreEqual(90, r.inDegrees, "MoveTowards 0 90 90"); - - r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(90), 180); - Assert.AreEqual(90, r.inDegrees, "MoveTowards 0 90 180"); - - r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(90), 270); - Assert.AreEqual(90, r.inDegrees, "MoveTowrads 0 90 270"); - - r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(90), -30); - Assert.AreEqual(0, r.inDegrees, "MoveTowards 0 90 -30"); - - r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(-90), -30); - Assert.AreEqual(0, r.inDegrees, "MoveTowards 0 -90 -30"); - - r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(-90), -90); - Assert.AreEqual(0, r.inDegrees, "MoveTowards 0 -90 -90"); - - r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(-90), -180); - Assert.AreEqual(0, r.inDegrees, "MoveTowards 0 -90 -180"); - - r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(-90), -270); - Assert.AreEqual(0, r.inDegrees, "MoveTowrads 0 -90 -270"); - - r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(90), 0); - Assert.AreEqual(0, r.inDegrees, "MoveTowards 0 90 0"); - - r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(0), 0); - Assert.AreEqual(0, r.inDegrees, "MoveTowards 0 0 0"); - - r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(0), 30); - Assert.AreEqual(0, r.inDegrees, "MoveTowrads 0 0 30"); - - r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(90), float.PositiveInfinity); - Assert.AreEqual(90, r.inDegrees, "MoveTowards 0 90 INFINITY"); - - r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(float.PositiveInfinity), 30); - Assert.AreEqual(30, r.inDegrees, "MoveTowrads 0 INFINITY 30"); - - r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(-90), float.NegativeInfinity); - Assert.AreEqual(0, r.inDegrees, "MoveTowards 0 -90 -INFINITY"); - - r = AngleFloat.MoveTowards(AngleFloat.Degrees(0), AngleFloat.Degrees(float.NegativeInfinity), -30); - Assert.AreEqual(0, r.inDegrees, "MoveTowrads 0 -INFINITY -30"); - - } - - [Test] - public void Difference() { - float r = 0; - - r = Angles.Difference(0, 90); - Assert.AreEqual(90, r, "Difference 0 90"); - - r = Angles.Difference(0, -90); - Assert.AreEqual(-90, r, "Difference 0 -90"); - - r = Angles.Difference(0, 270); - Assert.AreEqual(-90, r, "Difference 0 270"); - - r = Angles.Difference(0, -270); - Assert.AreEqual(90, r, "Difference 0 -270"); - - r = Angles.Difference(90, 0); - Assert.AreEqual(-90, r, "Difference 90 0"); - - r = Angles.Difference(-90, 0); - Assert.AreEqual(90, r, "Difference -90 0"); - - r = Angles.Difference(0, 0); - Assert.AreEqual(0, r, "Difference 0 0"); - - r = Angles.Difference(90, 90); - Assert.AreEqual(0, r, "Difference 90 90"); - - r = Angles.Difference(0, float.PositiveInfinity); - Assert.AreEqual(float.PositiveInfinity, r, "Difference 0 INFINITY"); - - r = Angles.Difference(0, float.NegativeInfinity); - Assert.AreEqual(float.NegativeInfinity, r, "Difference 0 -INFINITY"); - - r = Angles.Difference(float.NegativeInfinity, float.PositiveInfinity); - Assert.AreEqual(float.PositiveInfinity, r, "Difference -INFINITY INFINITY"); - } - } - -} -#endif diff --git a/Assets/NanoBrain/LinearAlgebra/test/DirectionTest.cs b/Assets/NanoBrain/LinearAlgebra/test/DirectionTest.cs deleted file mode 100644 index 0eb9882..0000000 --- a/Assets/NanoBrain/LinearAlgebra/test/DirectionTest.cs +++ /dev/null @@ -1,226 +0,0 @@ -#if !UNITY_5_6_OR_NEWER -using System; -using NUnit.Framework; - -namespace LinearAlgebra.Test { - public class DirectionTest { - - [Test] - public void RadiansForward() { - Direction d = Direction.Radians(0, 0); - Assert.AreEqual(0, d.horizontal.inDegrees, 0.0001f); - Assert.AreEqual(0, d.vertical.inDegrees, 0.0001f); - } - - [Test] - public void RadiansUp() { - Direction d = Direction.Radians(0, (float)Math.PI / 2); - Assert.AreEqual(0, d.horizontal.inDegrees, 0.0001f); - Assert.AreEqual(90, d.vertical.inDegrees, 0.0001f); - } - - [Test] - public void RadiansDown() { - Direction d = Direction.Radians(0, -(float)Math.PI / 2); - Assert.AreEqual(0, d.horizontal.inDegrees, 0.0001f); - Assert.AreEqual(-90, d.vertical.inDegrees, 0.0001f); - } - - [Test] - public void RadiansArbitrary() { - Direction d = Direction.Radians((float)Math.PI / 4, (float)Math.PI / 6); - Assert.AreEqual(45, d.horizontal.inDegrees, 0.0001f); - Assert.AreEqual(30, d.vertical.inDegrees, 0.0001f); - } - - [Test] - public void DegreesNormalize1() { - Direction d = Direction.Degrees(112, 91); - Assert.AreEqual(-68, d.horizontal.inDegrees, 0.0001f); - Assert.AreEqual(89, d.vertical.inDegrees, 0.0001f); - } - - [Test] - public void RadiansEquivalentToDegreesConversion() { - Direction d1 = Direction.Radians((float)Math.PI / 3, (float)Math.PI / 4); - Direction d2 = Direction.Degrees(60, 45); - Assert.AreEqual(d1.horizontal.inDegrees, d2.horizontal.inDegrees, 0.0001f); - Assert.AreEqual(d1.vertical.inDegrees, d2.vertical.inDegrees, 0.0001f); - } - - [Test] - public void ToVector3Forward() { - Direction d = Direction.forward; - Vector3Float v = d.ToVector3(); - Assert.AreEqual(0, v.horizontal, 0.0001f); - Assert.AreEqual(0, v.vertical, 0.0001f); - Assert.AreEqual(1, v.depth, 0.0001f); - } - - [Test] - public void ToVector3Up() { - Direction d = Direction.up; - Vector3Float v = d.ToVector3(); - Assert.AreEqual(0, v.horizontal, 0.0001f); - Assert.AreEqual(1, v.vertical, 0.0001f); - Assert.AreEqual(0, v.depth, 0.0001f); - } - - [Test] - public void ToVector3Down() { - Direction d = Direction.down; - Vector3Float v = d.ToVector3(); - Assert.AreEqual(0, v.horizontal, 0.0001f); - Assert.AreEqual(-1, v.vertical, 0.0001f); - Assert.AreEqual(0, v.depth, 0.0001f); - } - - [Test] - public void ToVector3Left() { - Direction d = Direction.left; - Vector3Float v = d.ToVector3(); - Assert.AreEqual(-1, v.horizontal, 0.0001f); - Assert.AreEqual(0, v.vertical, 0.0001f); - Assert.AreEqual(0, v.depth, 0.0001f); - } - - [Test] - public void FromVector3Forward() { - Vector3Float v = new(0, 0, 1); - Direction d = Direction.FromVector3(v); - Assert.AreEqual(0, d.horizontal.inDegrees, 0.0001f); - Assert.AreEqual(0, d.vertical.inDegrees, 0.0001f); - } - - [Test] - public void ToVector3AndBack() { - Direction d1 = Direction.Degrees(45, 30); - Vector3Float v = d1.ToVector3(); - Direction d2 = Direction.FromVector3(v); - Assert.AreEqual(d1.horizontal.inDegrees, d2.horizontal.inDegrees, 0.0001f); - Assert.AreEqual(d1.vertical.inDegrees, d2.vertical.inDegrees, 0.0001f); - } - - [Test] - public void ToVector3AndBack2() { - Direction d1 = Direction.Degrees(-135, 85); - Vector3Float v = d1.ToVector3(); - Direction d2 = Direction.FromVector3(v); - Assert.AreEqual(d1.horizontal.inDegrees, d2.horizontal.inDegrees, 0.0001f); - Assert.AreEqual(d1.vertical.inDegrees, d2.vertical.inDegrees, 0.0001f); - } - - [Test] - public void Compare() { - Direction d1 = Direction.Degrees(45, 135); - Direction d2 = new(AngleFloat.Degrees(45), AngleFloat.Degrees(135)); - bool r; - r = d1 == d2; - Assert.True(r); - Assert.AreEqual(d1, d2); - } - - [Test] - public void NotEqualWithDifferentHorizontal() { - Direction d1 = Direction.Degrees(45, 30); - Direction d2 = Direction.Degrees(90, 30); - Assert.True(d1 != d2); - } - - [Test] - public void NotEqualWithDifferentVertical() { - Direction d1 = Direction.Degrees(45, 30); - Direction d2 = Direction.Degrees(45, 60); - Assert.True(d1 != d2); - } - - [Test] - public void NotEqualWithDifferentBoth() { - Direction d1 = Direction.Degrees(45, 30); - Direction d2 = Direction.Degrees(90, 60); - Assert.True(d1 != d2); - } - - [Test] - public void NotEqualWithSameValues() { - Direction d1 = Direction.Degrees(45, 30); - Direction d2 = Direction.Degrees(45, 30); - Assert.False(d1 != d2); - } - - - [Test] - public void EqualsWithSameValues() { - Direction d1 = Direction.Degrees(45, 30); - Direction d2 = Direction.Degrees(45, 30); - Assert.True(d1.Equals(d2)); - } - - [Test] - public void EqualsWithDifferentHorizontal() { - Direction d1 = Direction.Degrees(45, 30); - Direction d2 = Direction.Degrees(90, 30); - Assert.False(d1.Equals(d2)); - } - - [Test] - public void EqualsWithDifferentVertical() { - Direction d1 = Direction.Degrees(45, 30); - Direction d2 = Direction.Degrees(45, 60); - Assert.False(d1.Equals(d2)); - } - - [Test] - public void EqualsWithDifferentBoth() { - Direction d1 = Direction.Degrees(45, 30); - Direction d2 = Direction.Degrees(90, 60); - Assert.False(d1.Equals(d2)); - } - - [Test] - public void EqualsWithNonDirectionObject() { - Direction d = Direction.Degrees(45, 30); - Assert.False(d.Equals("not a direction")); - } - - [Test] - public void EqualsWithNull() { - Direction d = Direction.Degrees(45, 30); - Assert.False(d.Equals(null)); - } - - [Test] - public void EqualsWithZeros() { - Direction d1 = Direction.forward; - Direction d2 = Direction.Degrees(0, 0); - Assert.True(d1.Equals(d2)); - } - - [Test] - public void HashCode() { - Direction d1 = Direction.Degrees(45, 30); - Direction d2 = Direction.Degrees(45, 30); - Assert.AreEqual(d1.GetHashCode(), d2.GetHashCode()); - - d1 = Direction.Degrees(45, 30); - d2 = Direction.Degrees(90, 30); - Assert.AreNotEqual(d1.GetHashCode(), d2.GetHashCode()); - - d1 = Direction.Degrees(45, 30); - d2 = Direction.Degrees(45, 60); - Assert.AreNotEqual(d1.GetHashCode(), d2.GetHashCode()); - - Direction d = Direction.Degrees(45, 30); - int hash1 = d.GetHashCode(); - int hash2 = d.GetHashCode(); - Assert.AreEqual(hash1, hash2); - - d1 = Direction.forward; - d2 = Direction.Degrees(0, 0); - Assert.AreEqual(d1.GetHashCode(), d2.GetHashCode()); - } - - }; -} -#endif - diff --git a/Assets/NanoBrain/LinearAlgebra/test/LinearAlgebra_Test.csproj b/Assets/NanoBrain/LinearAlgebra/test/LinearAlgebra_Test.csproj deleted file mode 100644 index 5b48e60..0000000 --- a/Assets/NanoBrain/LinearAlgebra/test/LinearAlgebra_Test.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - net8.0 - false - true - - - - - - - - - - - - - diff --git a/Assets/NanoBrain/LinearAlgebra/test/QuaternionTest.cs b/Assets/NanoBrain/LinearAlgebra/test/QuaternionTest.cs deleted file mode 100644 index 9dd5a96..0000000 --- a/Assets/NanoBrain/LinearAlgebra/test/QuaternionTest.cs +++ /dev/null @@ -1,185 +0,0 @@ -#if !UNITY_5_6_OR_NEWER -using NUnit.Framework; - -namespace LinearAlgebra.Test { - - public class QuaternionTest { - - [SetUp] - public void Setup() { - } - - [Test] - public void Normalize() { - Quaternion q1 = new(0, 0, 0, 1); - Quaternion r = Quaternion.identity; - - r = q1.normalized; - Assert.AreEqual(r, q1, "q.normalized 0 0 0 1"); - - r = Quaternion.Normalize(q1); - Assert.AreEqual(r, q1, "q.normalized 0 0 0 1"); - } - - [Test] - public void ToAngles() { - Quaternion q1 = new(0, 0, 0, 1); - Vector3Float v = Vector3Float.zero; - - v = Quaternion.ToAngles(q1); - Assert.AreEqual(v, new Vector3Float(0, 0, 0), "ToAngles 0 0 0 1"); - - q1 = new(1, 0, 0, 0); - v = Quaternion.ToAngles(q1); - Assert.AreEqual(0, v.horizontal, "1 0 0 0 H"); - Assert.AreEqual(180, v.vertical, "1 0 0 0 V"); - Assert.AreEqual(180, v.depth, "1 0 0 0 D"); - - } - - [Test] - public void Multiplication() { - Quaternion q1 = new(0, 0, 0, 1); - Quaternion q2 = new(1, 0, 0, 0); - Quaternion r; - - r = q1 * q2; - Assert.AreEqual(r, new Quaternion(1, 0, 0, 0), "0 0 0 1 * 1 0 0 0 "); - } - - [Test] - public void MultiplicationVector() { - Quaternion q1 = new(0, 0, 0, 1); - Vector3Float v1 = new(0, 1, 0); - Vector3Float r; - - r = q1 * v1; - Assert.AreEqual(r, new Vector3Float(0, 1, 0), "0 0 0 1 * Vector 0 1 0"); - - q1 = new(1, 0, 0, 0); - r = q1 * v1; - Assert.AreEqual(r, new Vector3Float(0, -1, 0), "1 0 0 0 * Vector 0 1 0"); - } - - [Test] - public void Equality() { - Quaternion q1 = new(0, 0, 0, 1); - Quaternion q2 = new(1, 0, 0, 0); - Assert.AreNotEqual(q1, q2, "0 0 0 1 == 1 0 0 0"); - - q2 = new(0, 0, 0, 1); - Assert.AreEqual(q1, q2, "0 0 0 1 == 1 0 0 0"); - } - - [Test, Ignore("ToDo")] - public void Inverse() { } - - [Test, Ignore("ToDo")] - public void LookRotation() { } - - [Test, Ignore("ToDo")] - public void FromToRotation() { } - - [Test, Ignore("ToDo")] - public void RotateTowards() { } - - [Test, Ignore("ToDo")] - public void AngleAxis() { } - - [Test, Ignore("ToDo")] - public void Angle() { } - - [Test, Ignore("ToDo")] - public void Slerp() { } - - [Test, Ignore("ToDo")] - public void SlerpUnclamped() { } - - [Test] - public void Euler() { - Vector3Float v1 = new(0, 0, 0); - Quaternion q; - - q = Quaternion.Euler(v1); - Assert.AreEqual(q, Quaternion.identity, "Euler Vector 0 0 0"); - - q = Quaternion.Euler(0, 0, 0); - Assert.AreEqual(q, Quaternion.identity, "Euler 0 0 0"); - - v1 = new(90, 90, -90); - q = Quaternion.Euler(v1); - Assert.AreEqual(q, new Quaternion(0, 0.707106709F, -0.707106709F, 0), "Euler Vector 90 90 -90"); - - q = Quaternion.Euler(90, 90, -90); - Assert.AreEqual(q, new Quaternion(0, 0.707106709F, -0.707106709F, 0), "Euler 90 90 -90"); - } - - [Test] - public void EulerToAngles() { - Vector3Float v; - Quaternion q; - Quaternion r; - - //v = new(0, 0, 0); - q = Quaternion.Euler(0, 0 , 0); - v = Quaternion.ToAngles(q); - r = Quaternion.Euler(v); - Assert.AreEqual(0, Quaternion.UnsignedAngle(q, r), 10e-2f, "0 0 0"); - - q = Quaternion.Euler(-45, -30, -15); - v = Quaternion.ToAngles(q); - r = Quaternion.Euler(v); - Assert.AreEqual(0, Quaternion.UnsignedAngle(q, r), 10e-2f, "-45, -30, -15"); - - // Gimball lock - // q = Quaternion.Euler(90, 90, -90); - // v = Quaternion.ToAngles(q); - // r = Quaternion.Euler(v); - // Assert.AreEqual(0, Quaternion.UnsignedAngle(q, r), 10e-2f, "0 0 0"); - - } - - [Test] - public void GetAngleAround() { - Vector3Float v1 = new(0, 1, 0); - Quaternion q1 = new(0, 0, 0, 1); - - float f = Quaternion.GetAngleAround(v1, q1); - Assert.AreEqual(f, 0, "GetAngleAround 0 1 0 , 0 0 0 1"); - - q1 = new(0, 0.707106709F, -0.707106709F, 0); - f = Quaternion.GetAngleAround(v1, q1); - Assert.AreEqual(f, 180, "GetAngleAround 0 1 0 , 0 0.7 -0.7 0"); - - v1 = new(0, 0, 0); - f = Quaternion.GetAngleAround(v1, q1); - Assert.IsTrue(float.IsNaN(f), "GetAngleAround 0 0 0 , 0 0.7 -0.7 0"); - } - - [Test] - public void GetRotationAround() { - Vector3Float v1 = new(0, 1, 0); - Quaternion q1 = new(0, 0, 0, 1); - - Quaternion q = Quaternion.GetRotationAround(v1, q1); - Assert.AreEqual(q, new Quaternion(0, 0, 0, 1), "GetRotationAround 0 1 0 , 0 0 0 1"); - - q1 = new(0, 0.707106709F, -0.707106709F, 0); - q = Quaternion.GetRotationAround(v1, q1); - Assert.AreEqual(q, new Quaternion(0, 1, 0, 0), "GetRotationAround 0 1 0 , 0 0.7 -0.7 0"); - - v1 = new(0, 0, 0); - q = Quaternion.GetRotationAround(v1, q1); - bool r = float.IsNaN(q.x) && float.IsNaN(q.y) && float.IsNaN(q.z) && float.IsNaN(q.w); - Assert.IsTrue(r, "GetRotationAround 0 0 0 , 0 0.7 -0.7 0"); - } - - [Test, Ignore("ToDo")] - public void GetSwingTwist() { } - - [Test, Ignore("ToDo")] - public void Dot() { } - - } -} -#endif \ No newline at end of file diff --git a/Assets/NanoBrain/LinearAlgebra/test/SphericalTest.cs b/Assets/NanoBrain/LinearAlgebra/test/SphericalTest.cs deleted file mode 100644 index b28b9d9..0000000 --- a/Assets/NanoBrain/LinearAlgebra/test/SphericalTest.cs +++ /dev/null @@ -1,271 +0,0 @@ -//#if !UNITY_5_6_OR_NEWER -using System; -using System.Collections.Generic; -using NUnit.Framework; - -namespace LinearAlgebra.Test { - public class SphericalTest { - [SetUp] - public void Setup() { - } - - [Test] - public void FromVector3() { -#if UNITY_5_6_OR_NEWER - UnityEngine.Vector3 v = new(0, 0, 1); -#else - Vector3Float v = new(0, 0, 1); -#endif - Spherical s = Spherical.FromVector3(v); - Assert.AreEqual(1.0f, s.distance, "s.distance 0 0 1"); - Assert.AreEqual(0.0f, s.direction.horizontal.inDegrees, "s.hor 0 0 1"); - Assert.AreEqual(0.0f, s.direction.vertical.inDegrees, 1.0E-05F, "s.vert 0 0 1"); - - v = new(0, 1, 0); - s = Spherical.FromVector3(v); - Assert.AreEqual(1.0f, s.distance, "s.distance 0 1 0"); - Assert.AreEqual(0.0f, s.direction.horizontal.inDegrees, "s.hor 0 1 0"); - Assert.AreEqual(90.0f, s.direction.vertical.inDegrees, "s.vert 0 1 0"); - - v = new(1, 0, 0); - s = Spherical.FromVector3(v); - Assert.AreEqual(1.0f, s.distance, "s.distance 1 0 0"); - Assert.AreEqual(90.0f, s.direction.horizontal.inDegrees, "s.hor 1 0 0"); - Assert.AreEqual(0.0f, s.direction.vertical.inDegrees, 1.0E-05F, "s.vert 1 0 0"); - } - - [Test] - public void Addition() { - Spherical v1 = Spherical.Degrees(1, 45, 0); - Spherical v2 = Spherical.zero; - Spherical r = Spherical.zero; - - r = v1 + v2; - Assert.AreEqual(v1.distance, r.distance, 1.0E-05F, "Addition(0,0,0)"); - - r = v1; - r += v2; - Assert.AreEqual(v1.distance, r.distance, 1.0E-05F, "Addition(0,0,0)"); - - v2 = Spherical.Degrees(1, 0, 90); - r = v1 + v2; - Assert.AreEqual(Math.Sqrt(2), r.distance, 1.0E-05F, "Addition(1 0 90)"); - Assert.AreEqual(45.0f, r.direction.horizontal.inDegrees, 1e-5f, "Addition(1 0 90)"); - Assert.AreEqual(45.0f, r.direction.vertical.inDegrees, 1.0E-05F, "Addition(1 0 90)"); - } - - [Test] - public void Average2_IdenticalVectors() { - Direction dir = Direction.Radians(MathF.PI / 4f, MathF.PI / 6f); - Spherical v = new(2.5f, dir); - - Spherical avg = Spherical.Average(v, v); - - Assert.AreEqual(2.5f, avg.distance, 1e-5f); - Assert.AreEqual(dir.horizontal, avg.direction.horizontal); - Assert.AreEqual(dir.vertical, avg.direction.vertical); - } - - [Test] - public void Average2_OppositeUnitVectors() { - // Two opposite vectors: same distance, horizontal opposite (pi apart), same vertical - Spherical v1 = Spherical.Radians(1f, 0f, 0f); - Spherical v2 = Spherical.Radians(1f, MathF.PI, 0f); - Spherical avg = Spherical.Average(v1, v2); - - Assert.AreEqual(0f, avg.distance, 1e-4f); - // When distance is zero, angles may be undefined; allow any angle but ensure near-zero magnitude - } - - [Test] - public void Average2_WeightedByDistance() { - // Two vectors same direction but different distances -> weighted average distance - Direction dir = Direction.Radians(MathF.PI / 3f, MathF.PI / 4f); - Spherical a = new(1f, dir); - Spherical b = new(3f, dir); - Spherical avg = Spherical.Average(a, b); - - // average distance should be (1+3)/2 = 2 - Assert.AreEqual(2f, avg.distance, 1e-5f); - Assert.AreEqual(dir.horizontal.inRadians, avg.direction.horizontal.inRadians, 1e-5f); - Assert.AreEqual(dir.vertical.inRadians, avg.direction.vertical.inRadians, 1e-5f); - } - - [Test] - public void Average2_OppositeButNotExact_NotZero() { - // Nearly opposite but not exact; expect a valid averaged direction and averaged distance - Direction d1 = Direction.Radians(0f, 0f); - Direction d2 = Direction.Radians(MathF.PI - 1e-3f, 0.0f); // slight offset - Spherical v1 = new(2.0f, d1); - Spherical v2 = new(4.0f, d2); - - Spherical avg = Spherical.Average(v1, v2); - - // Distance is arithmetic mean - Assert.AreEqual(3.0f, avg.distance, 1e-5f); - - // Averaged azimuth should be near +pi/2 or -pi/2? we can check it's not NaN and unit-vector properties hold - float ux = MathF.Cos(avg.direction.horizontal.inRadians) * MathF.Cos(avg.direction.vertical.inRadians); - float uy = MathF.Sin(avg.direction.horizontal.inRadians) * MathF.Cos(avg.direction.vertical.inRadians); - float uz = MathF.Sin(avg.direction.vertical.inRadians); - float mag = MathF.Sqrt(ux * ux + uy * uy + uz * uz); - Assert.IsTrue(mag > 0.999f && mag < 1.001f); - - } - - [Test] - public void Average2_BasicAverageDirectionAndDistance() { - // Two different directions not cancelling: expect vector-average result - Direction d1 = Direction.Radians(MathF.PI / 6f, MathF.PI / 12f); // 30°, 15° - Direction d2 = Direction.Radians(MathF.PI / 3f, MathF.PI / 18f); // 60°, 10° - Spherical v1 = new(2.0f, d1); - Spherical v2 = new(4.0f, d2); - - Spherical avg = Spherical.Average(v1, v2); - - // Distance is arithmetic mean - Assert.AreEqual(3.0f, avg.distance, 1e-5f); - - // Check averaged unit-vector equals normalized sum of unit vectors computed here - float a1 = d1.horizontal.inRadians; - float a2 = d2.horizontal.inRadians; - float e1 = d1.vertical.inRadians; - float e2 = d2.vertical.inRadians; - - float cx = MathF.Cos(a1) + MathF.Cos(a2); - float cy = MathF.Sin(a1) + MathF.Sin(a2); - float z1 = MathF.Sin(e1); - float z2 = MathF.Sin(e2); - float cz = z1 + z2; - float mag = MathF.Sqrt(cx * cx + cy * cy + cz * cz); - Assert.IsTrue(mag > 1e-6f); - - float ux = cx / mag; - float uy = cy / mag; - float uz = cz / mag; - - // Reconstruct direction from avg result - float uxAvg = MathF.Cos(avg.direction.horizontal.inRadians) * MathF.Cos(avg.direction.vertical.inRadians); - float uyAvg = MathF.Sin(avg.direction.horizontal.inRadians) * MathF.Cos(avg.direction.vertical.inRadians); - float uzAvg = MathF.Sin(avg.direction.vertical.inRadians); - - Assert.AreEqual(ux, uxAvg, 1e-4f); - Assert.AreEqual(uy, uyAvg, 1e-4f); - Assert.AreEqual(uz, uzAvg, 1e-4f); - } - - [Test] - public void Average_IdenticalVectors() { - var dir = Direction.Radians(MathF.PI / 4f, MathF.PI / 6f); - var v = new Spherical(2.5f, dir); - var list = new List { v, v, v }; - - var avg = Spherical.Average(list); - - Assert.AreEqual(2.5f, avg.distance, 1e-5f); - Assert.AreEqual(dir.horizontal, avg.direction.horizontal); - Assert.AreEqual(dir.vertical, avg.direction.vertical); - } - - [Test] - public void Average_SingleElement() { - Spherical s = Spherical.Radians(1.234f, 0.3f, -0.7f); - Spherical avg = Spherical.Average(new List { s }); - - Assert.AreEqual(s.distance, avg.distance, 1e-5f); - Assert.AreEqual(s.direction.horizontal.inRadians, avg.direction.horizontal.inRadians, 1e-5f); - Assert.AreEqual(s.direction.vertical.inRadians, avg.direction.vertical.inRadians, 1e-5f); - } - - [Test] - public void Average_OppositeUnitVectors() { - // Two opposite vectors: same distance, horizontal opposite (pi apart), same vertical - Spherical v1 = Spherical.Radians(1f, 0f, 0f); - Spherical v2 = Spherical.Radians(1f, MathF.PI, 0f); - Spherical avg = Spherical.Average(new List { v1, v2 }); - - Assert.AreEqual(0f, avg.distance, 1e-4f); - // When distance is zero, angles may be undefined; allow any angle but ensure near-zero magnitude - } - - [Test] - public void Average_WeightedByDistance() { - // Two vectors same direction but different distances -> weighted average distance - Direction dir = Direction.Radians(MathF.PI / 3f, MathF.PI / 4f); - Spherical a = new(1f, dir); - Spherical b = new(3f, dir); - Spherical avg = Spherical.Average(new List { a, b }); - - // average distance should be (1+3)/2 = 2 - Assert.AreEqual(2f, avg.distance, 1e-5f); - Assert.AreEqual(dir.horizontal.inRadians, avg.direction.horizontal.inRadians, 1e-5f); - Assert.AreEqual(dir.vertical.inRadians, avg.direction.vertical.inRadians, 1e-5f); - } - - [Test] - public void Average_AxisSymmetricAroundVertical() { - // Four vectors around azimuth 0, pi/2, pi, 3pi/2 at same elevation (vertical) angle phi - float phi = MathF.PI / 6f; // elevation from horizontal plane - var dirs = new List { - new(1f, Direction.Radians(0f, phi)), - new(1f, Direction.Radians(MathF.PI/2, phi)), - new(1f, Direction.Radians(MathF.PI, phi)), - new(1f, Direction.Radians(3*MathF.PI/2, phi)) - }; - - Spherical avg = Spherical.Average(dirs); - - // rAvg should equal r * sin(elevation) = sin(phi) - Assert.AreEqual(MathF.Sin(phi), avg.distance, 1e-4f); - // vertical angle undefined when horizontal xy components cancel; allow any angle but ensure r matches - } - - [Test] - public void Average_AxisSymmetricAroundVertical2() { - // Four vectors around azimuth 0, pi/2, pi, 3pi/2 at same polar angle from vertical (alpha) - float alpha = MathF.PI / 6f; // polar angle from vertical - float elevation = MathF.PI / 2f - alpha; // convert polar-from-vertical to elevation - var dirs = new List { - new(1f, Direction.Radians(0f, elevation)), - new(1f, Direction.Radians(MathF.PI/2, elevation)), - new(1f, Direction.Radians(MathF.PI, elevation)), - new(1f, Direction.Radians(3*MathF.PI/2, elevation)) - }; - - Spherical avg = Spherical.Average(dirs); - - // rAvg should equal r * sin(elevation) which equals cos(alpha) - Assert.AreEqual(MathF.Cos(alpha), avg.distance, 1e-4f); - } - - [Test] - public void Average_CompareWithVector3() { - // Four vectors around azimuth 0, pi/2, pi, 3pi/2 at same polar angle from vertical (alpha) - float alpha = MathF.PI / 6f; // polar angle from vertical - float elevation = MathF.PI / 2f - alpha; // convert polar-from-vertical to elevation - List dirs = new List { - new(1f, Direction.Radians(0f, elevation)), - new(2f, Direction.Radians(MathF.PI/2, elevation+1)), - new(3f, Direction.Radians(MathF.PI, elevation+2)), - new(4f, Direction.Radians(3*MathF.PI/2, elevation+3)) - }; - - Spherical avg = Spherical.Average(dirs); - -#if UNITY_5_3_OR_NEWER - UnityEngine.Vector3 r = UnityEngine.Vector3.zero; -#else - Vector3Float r = Vector3Float.zero; -#endif - foreach (Spherical dir in dirs) { - r += dir.ToVector3(); - } - r = r / 4; - Spherical avg2 = Spherical.FromVector3(r); - - Assert.AreEqual(avg, avg2); - } - - } -} -//#endif \ No newline at end of file diff --git a/Assets/NanoBrain/LinearAlgebra/test/SwingTwistTest.cs b/Assets/NanoBrain/LinearAlgebra/test/SwingTwistTest.cs deleted file mode 100644 index 5f05a96..0000000 --- a/Assets/NanoBrain/LinearAlgebra/test/SwingTwistTest.cs +++ /dev/null @@ -1,131 +0,0 @@ -#if !UNITY_5_6_OR_NEWER -using NUnit.Framework; - -namespace LinearAlgebra.Test { - - [TestFixture] - public class SwingTwistTest { - - [Test] - public void Degrees_CreatesSwingTwistWithDegreeAngles() { - SwingTwist st = SwingTwist.Degrees(45, 30, 15); - Assert.IsNotNull(st); - Assert.AreEqual(45, st.swing.horizontal.inDegrees, 0.01f); - Assert.AreEqual(30, st.swing.vertical.inDegrees, 0.01f); - Assert.AreEqual(15, st.twist.inDegrees, 0.01f); - } - - [Test] - public void Radians_CreatesSwingTwistWithRadianAngles() { - float pi = (float)System.Math.PI; - SwingTwist st = SwingTwist.Radians(pi / 4, pi / 6, pi / 12); - Assert.IsNotNull(st); - Assert.AreEqual(45, st.swing.horizontal.inDegrees, 0.01f); - Assert.AreEqual(30, st.swing.vertical.inDegrees, 0.01f); - Assert.AreEqual(15, st.twist.inDegrees, 0.01f); - } - - [Test] - public void Zero_CreatesZeroRotation() { - SwingTwist st = SwingTwist.zero; - Assert.AreEqual(0, st.swing.horizontal.inDegrees, 0.01f); - Assert.AreEqual(0, st.swing.vertical.inDegrees, 0.01f); - Assert.AreEqual(0, st.twist.inDegrees, 0.01f); - } - - [Test] - public void QuaternionTest() { - Quaternion q; - SwingTwist s; - Quaternion r; - - q = Quaternion.identity; - s = SwingTwist.FromQuaternion(q); - r = s.ToQuaternion(); - Assert.AreEqual(q, r); - - q = Quaternion.Euler(90, 0, 0); - s = SwingTwist.FromQuaternion(q); - Assert.AreEqual(0, s.swing.horizontal.inDegrees, 10e-2f); - Assert.AreEqual(90, s.swing.vertical.inDegrees, 10e-2f); - Assert.AreEqual(0, s.twist.inDegrees, 0.01f); - r = s.ToQuaternion(); - Assert.AreEqual(0, Quaternion.UnsignedAngle(q, r), 10e-2f); - - q = Quaternion.Euler(0, 90, 0); - s = SwingTwist.FromQuaternion(q); - Assert.AreEqual(90, s.swing.horizontal.inDegrees,10e-2f); - Assert.AreEqual(0, s.swing.vertical.inDegrees, 0.01f); - Assert.AreEqual(0, s.twist.inDegrees, 0.01f); - r = s.ToQuaternion(); - Assert.AreEqual(0, Quaternion.UnsignedAngle(q, r), 10e-2f); - - q = Quaternion.Euler(0, 0, 90); - s = SwingTwist.FromQuaternion(q); - Assert.AreEqual(0, s.swing.horizontal.inDegrees, 0.01f); - Assert.AreEqual(0, s.swing.vertical.inDegrees, 0.01f); - Assert.AreEqual(90, s.twist.inDegrees, 0.01f); - r = s.ToQuaternion(); - Assert.AreEqual(0, Quaternion.UnsignedAngle(q, r), 10e-2f); - - q = Quaternion.Euler(0, 180, 0); - s = SwingTwist.FromQuaternion(q); - Assert.AreEqual(-180, s.swing.horizontal.inDegrees, 0.01f); - Assert.AreEqual(0, s.swing.vertical.inDegrees, 0.01f); - Assert.AreEqual(0, s.twist.inDegrees, 0.01f); - r = s.ToQuaternion(); - Assert.AreEqual(0, Quaternion.UnsignedAngle(q, r), 10e-2f); - - q = Quaternion.Euler(0, 135, 0); - s = SwingTwist.FromQuaternion(q); - Assert.AreEqual(135, s.swing.horizontal.inDegrees, 0.01f); - Assert.AreEqual(0, s.swing.vertical.inDegrees, 0.01f); - Assert.AreEqual(0, s.twist.inDegrees, 0.01f); - r = s.ToQuaternion(); - Assert.AreEqual(0, Quaternion.UnsignedAngle(q, r), 10e-2f); - - q = Quaternion.Euler(60, 45, 30); - s = SwingTwist.FromQuaternion(q); - Assert.AreEqual(45, s.swing.horizontal.inDegrees, 0.01f); - Assert.AreEqual(60, s.swing.vertical.inDegrees, 0.01f); - Assert.AreEqual(30, s.twist.inDegrees, 0.01f); - // r = s.ToQuaternion(); - // Assert.AreEqual(0, Quaternion.UnsignedAngle(q, r), 10e-2f); - - // q = Quaternion.Euler(-45, -30, -15); - // s = SwingTwist.FromQuaternion(q); - // Assert.AreEqual(-30, s.swing.horizontal.inDegrees, 0.01f); - // Assert.AreEqual(-45, s.swing.vertical.inDegrees, 0.01f); - // Assert.AreEqual(-15, s.twist.inDegrees, 0.01f); - // r = s.ToQuaternion(); - // Assert.AreEqual(0, Quaternion.UnsignedAngle(q, r), 10e-2f); - - // q = Quaternion.Euler(180, 180, 180); - // s = SwingTwist.FromQuaternion(q); - // Assert.AreEqual(-180, s.swing.horizontal.inDegrees, 0.01f); - // Assert.AreEqual(-180, s.swing.vertical.inDegrees, 0.01f); - // Assert.AreEqual(-180, s.twist.inDegrees, 0.01f); - // r = s.ToQuaternion(); - // Assert.AreEqual(0, Quaternion.UnsignedAngle(q, r), 10e-2f); - - } - - [Test] - public void ToAngleAxis_ConvertsToSpherical() { - SwingTwist st = SwingTwist.Degrees(45, 30, 15); - Spherical s = st.ToAngleAxis(); - Assert.IsNotNull(s); - } - - [Test] - public void FromAngleAxis_ConvertsFromSpherical() { - Spherical s = new(90, Direction.Degrees(45, 0)); - SwingTwist st = SwingTwist.FromAngleAxis(s); - Assert.IsNotNull(st); - } - - } - -} - -#endif \ No newline at end of file diff --git a/Assets/NanoBrain/LinearAlgebra/test/Vector2FloatTest.cs b/Assets/NanoBrain/LinearAlgebra/test/Vector2FloatTest.cs deleted file mode 100644 index 867765a..0000000 --- a/Assets/NanoBrain/LinearAlgebra/test/Vector2FloatTest.cs +++ /dev/null @@ -1,364 +0,0 @@ -#if !UNITY_5_6_OR_NEWER -using NUnit.Framework; - -namespace LinearAlgebra.Test { - using Vector2 = Vector2Float; - - public class Vector2FloatTest { - - [SetUp] - public void Setup() { - } - - [Test] - public void FromPolar() { - } - - [Test] - public void Equality() { - Vector2 v1 = new(4, 5); - Vector2 v2 = new(1, 2); - - Assert.IsFalse(v1 == v2, "4 5 == 1 2"); - Assert.IsTrue(v1 != v2, "4 5 != 1 2"); - - v2 = new(4, 5); - Assert.IsTrue(v1 == v2, "4 5 == 4 5"); - Assert.IsFalse(v1 != v2, "4 5 != 4 5"); - } - - [Test] - public void Magnitude() { - Vector2 v = new(1, 2); - float m = 0; - m = v.magnitude; - Assert.AreEqual(m, 2.236068F, "v.magnitude 1 2"); - - m = Vector2.MagnitudeOf(v); - Assert.AreEqual(m, 2.236068F, "MagnitudeOf 1 2"); - - v = new(-1, -2); - m = v.magnitude; - Assert.AreEqual(m, 2.236068F, "v.magnitude -1 -2"); - - v = new(0, 0); - m = v.magnitude; - Assert.AreEqual(m, 0, "v.magnitude 0 0"); - } - - [Test] - public void SqrMagnitude() { - Vector2 v = new(1, 2); - float m = 0; - - m = v.sqrMagnitude; - Assert.AreEqual(m, 5, "v.sqrMagnitude 1 2"); - - m = Vector2.SqrMagnitudeOf(v); - Assert.AreEqual(m, 5, "SqrMagnitudeOf 1 2"); - - v = new(-1, -2); - m = v.sqrMagnitude; - Assert.AreEqual(m, 5, "v.sqrMagnitude -1 -2"); - - v = new(0, 0); - m = v.sqrMagnitude; - Assert.AreEqual(m, 0, "v.sqrMagnitude 0 0"); - } - - [Test] - public void Distance() { - Vector2 v1 = new(4, 5); - Vector2 v2 = new(1, 2); - float f = 0; - - f = Vector2.Distance(v1, v2); - Assert.AreEqual(f, 4.24264002f, 1.0E-05F, "Distance(4 5, 1 2)"); - - v2 = new(-1, -2); - f = Vector2.Distance(v1, v2); - Assert.AreEqual(f, 8.602325F, "Distance(4 5, 1 2)"); - - v2 = new(0, 0); - f = Vector2.Distance(v1, v2); - Assert.AreEqual(f, 6.403124F, 1.0E-05F, "Distance(4 5, 1 2)"); - } - - [Test] - public void Normalize() { - Vector2 v = new(0, 3); - Vector2Float r; - - r = v.normalized; - Assert.AreEqual(0, r.horizontal, "normalized 0 3 H"); - Assert.AreEqual(1, r.vertical, "normalized 0 3 V"); - - r = Vector2.Normalize(v); - Assert.AreEqual(0, r.horizontal, "Normalize 0 3 H"); - Assert.AreEqual(1, r.vertical, "Normalize 0 3 V"); - - v = new(0, -3); - r = v.normalized; - Assert.AreEqual(0, r.horizontal, "normalized 0 -3 H"); - Assert.AreEqual(-1, r.vertical, "normalized 0 -3 V"); - - v = new(0, 0); - r = v.normalized; - Assert.AreEqual(0, r.horizontal, "normalized 0 0 H"); - Assert.AreEqual(0, r.vertical, "normalized 0 0 V"); - } - - [Test] - public void Negate() { - Vector2 v = new(4, 5); - Vector2 r; - - r = -v; - Assert.AreEqual(-4, r.horizontal, "- 4 5 H"); - Assert.AreEqual(-5, r.vertical, "- 4 5 V"); - - v = new(-4, -5); - r = -v; - Assert.AreEqual(4, r.horizontal, "- -4 -5 H"); - Assert.AreEqual(5, r.vertical, "- -4 -5 V"); - - v = new(0, 0); - r = -v; - Assert.AreEqual(0, r.horizontal, "- 0 0 H"); - Assert.AreEqual(0, r.vertical, "- 0 0 V"); - } - - [Test] - public void Subtract() { - Vector2 v1 = new(4, 5); - Vector2 v2 = new(1, 2); - Vector2 r = Vector2.zero; - - r = v1 - v2; - Assert.IsTrue(r == new Vector2(3, 3), "4 5 - 1 2"); - - v2 = new(-1, -2); - r = v1 - v2; - Assert.IsTrue(r == new Vector2(5, 7), "4 5 - -1 -2"); - - v2 = new(4, 5); - r = v1 - v2; - Assert.IsTrue(r == new Vector2(0, 0), "4 5 - 4 5"); - r = v1; - r -= v2; - Assert.AreEqual(r, new Vector2(0, 0), "4 5 - 4 5"); - - v2 = new(0, 0); - r = v1 - v2; - Assert.AreEqual(r, new Vector2(4, 5), "4 5 - 0 0"); - r -= v2; - Assert.AreEqual(r, new Vector2(4, 5), "4 5 - 0 0"); - } - - [Test] - public void Addition() { - Vector2 v1 = new(4, 5); - Vector2 v2 = new(1, 2); - Vector2 r = Vector2.zero; - - r = v1 + v2; - Assert.IsTrue(r == new Vector2(5, 7), "4 5 + 1 2"); - - v2 = new(-1, -2); - r = v1 + v2; - Assert.IsTrue(r == new Vector2(3, 3), "4 5 + -1 -2"); - r = v1; - r += v2; - Assert.AreEqual(r, new Vector2(3, 3), "4 5 + -1 -2"); - - v2 = new(0, 0); - r = v1 + v2; - Assert.AreEqual(r, new Vector2(4, 5), "4 5 + 0 0"); - r += v2; - Assert.AreEqual(r, new Vector2(4, 5), "4 5 + 0 0"); - } - - [Test] - public void Scale() { - Vector2 v1 = new(4, 5); - Vector2 v2 = new(1, 2); - Vector2 r; - - r = Vector2.Scale(v1, v2); - Assert.AreEqual(4, r.horizontal, "Scale 4 5 , 1 2 H"); - Assert.AreEqual(10, r.vertical, "Scale 4 5 , 1 2 V"); - - v2 = new(-1, -2); - r = Vector2.Scale(v1, v2); - Assert.AreEqual(-4, r.horizontal, "Scale 4 5 , -1 -2 H"); - Assert.AreEqual(-10, r.vertical, "Scale 4 5 , -1 -2 V"); - - v2 = new(0, 0); - r = Vector2.Scale(v1, v2); - Assert.AreEqual(0, r.horizontal, "Scale 4 5 , 0 0 H"); - Assert.AreEqual(0, r.vertical, "Scale 4 5 , 0 0 V"); - } - - [Test] - public void Multiply() { - Vector2 v1 = new(4, 5); - int f = 3; - Vector2 r; - - r = v1 * f; - Assert.AreEqual(12, r.horizontal, "4 5 * 3 H"); - Assert.AreEqual(15, r.vertical, "4 5 * 3 V"); - - r = f * v1; - Assert.AreEqual(12, r.horizontal, "3 * 4 5 H"); - Assert.AreEqual(15, r.vertical, "3 * 4 5 V"); - - f = -3; - r = v1 * f; - Assert.AreEqual(-12, r.horizontal, "4 5 * -3 H"); - Assert.AreEqual(-15, r.vertical, "4 5 * -3 V"); - - f = 0; - r = v1 * f; - Assert.AreEqual(0, r.horizontal, "4 5 * 0 H"); - Assert.AreEqual(0, r.vertical, "4 5 * 0 V"); - } - - [Test] - public void Divide() { - Vector2 v1 = new(4, 5); - float f = 2; - Vector2 r; - - r = v1 / f; - Assert.AreEqual(2, r.horizontal, "4 5 / 2 H"); - Assert.AreEqual(2.5, r.vertical, "4 5 / 2 V"); - - f = -2; - r = v1 / f; - Assert.AreEqual(-2, r.horizontal, "4 5 / -2 H"); - Assert.AreEqual(-2.5, r.vertical, "4 5 / -2 V"); - - f = 0; - r = v1 / f; - Assert.AreEqual(float.PositiveInfinity, r.horizontal, "4 5 / 0 H"); - Assert.AreEqual(float.PositiveInfinity, r.vertical, "4 5 / 0 V"); - } - - [Test] - public void Dot() { - Vector2 v1 = new(4, 5); - Vector2 v2 = new(1, 2); - float f; - - f = Vector2.Dot(v1, v2); - Assert.AreEqual(14, f, "Dot(4 5, 1 2)"); - - v2 = new(-1, -2); - f = Vector2.Dot(v1, v2); - Assert.AreEqual(-14, f, "Dot(4 5, -1 -2)"); - - v2 = new(0, 0); - f = Vector2.Dot(v1, v2); - Assert.AreEqual(0, f, "Dot(4 5, 0 0)"); - } - - [Test] - public void SignedAngle() { - Vector2 v1 = new(4, 5); - Vector2 v2 = new(1, 2); - float f; - - f = Vector2.SignedAngle(v1, v2); - Assert.AreEqual(-12.094758f, f); - - v2 = new(-1, -2); - f = Vector2.SignedAngle(v1, v2); - Assert.AreEqual(167.905228f, f); - - v2 = new(0, 0); - f = Vector2.SignedAngle(v1, v2); - Assert.AreEqual(0, f); - - v1 = new(0, 1); - v2 = new(1, 0); - f = Vector2.SignedAngle(v1, v2); - Assert.AreEqual(90, f); - - v1 = new(0, 1); - v2 = new(0, -1); - f = Vector2.SignedAngle(v1, v2); - Assert.AreEqual(180, f); - } - - [Test] - public void UnsignedAngle() { - Vector2 v1 = new(4, 5); - Vector2 v2 = new(1, 2); - float f; - - f = Vector2.UnsignedAngle(v1, v2); - Assert.AreEqual(12.094758f, f); - - v2 = new(-1, -2); - f = Vector2.UnsignedAngle(v1, v2); - Assert.AreEqual(167.905228f, f); - - v2 = new(0, 0); - f = Vector2.UnsignedAngle(v1, v2); - Assert.AreEqual(0, f); - - v1 = new(0, 1); - v2 = new(1, 0); - f = Vector2.UnsignedAngle(v1, v2); - Assert.AreEqual(90, f); - - v1 = new(0, 1); - v2 = new(0, -1); - f = Vector2.UnsignedAngle(v1, v2); - Assert.AreEqual(180, f); - } - - [Test] - public void Rotate() { - Vector2 v1 = new(1, 2); - Vector2 r; - - r = Vector2.Rotate(v1, AngleFloat.Degrees(0)); - Assert.AreEqual(0, Vector2.Distance(r, v1)); - - r = Vector2.Rotate(v1, AngleFloat.Degrees(180)); - Assert.AreEqual(0, Vector2.Distance(r, new Vector2(-1, -2)), 1.0e-06); - - r = Vector2.Rotate(v1, AngleFloat.Degrees(-90)); - Assert.AreEqual(0, Vector2.Distance(r, new Vector2(2, -1)), 1.0e-06); - - r = Vector2.Rotate(v1, AngleFloat.Degrees(270)); - Assert.AreEqual(0, Vector2.Distance(r, new Vector2(2, -1)), 1.0e-06); - } - - [Test] - public void Lerp() { - Vector2 v1 = new(4, 5); - Vector2 v2 = new(1, 2); - Vector2 r; - - r = Vector2.Lerp(v1, v2, 0); - Assert.AreEqual(0, Vector2.Distance(r, v1), 0); - - r = Vector2.Lerp(v1, v2, 1); - Assert.AreEqual(0, Vector2.Distance(r, v2), 0); - - r = Vector2.Lerp(v1, v2, 0.5f); - Assert.AreEqual(0, Vector2.Distance(r, new Vector2(2.5f, 3.5f)), 0); - - r = Vector2.Lerp(v1, v2, -1); - Assert.AreEqual(0, Vector2.Distance(r, new Vector2(7, 8)), 0); - - r = Vector2.Lerp(v1, v2, 2); - Assert.AreEqual(0, Vector2.Distance(r, new Vector2(-2, -1)), 0); - } - - } -} -#endif \ No newline at end of file diff --git a/Assets/NanoBrain/LinearAlgebra/test/Vector2IntTest.cs b/Assets/NanoBrain/LinearAlgebra/test/Vector2IntTest.cs deleted file mode 100644 index 3647ca0..0000000 --- a/Assets/NanoBrain/LinearAlgebra/test/Vector2IntTest.cs +++ /dev/null @@ -1,270 +0,0 @@ -#if !UNITY_5_6_OR_NEWER -using NUnit.Framework; - -namespace LinearAlgebra.Test { - using Vector2 = Vector2Int; - - public class Vector2IntTest { - - [SetUp] - public void Setup() { - } - - [Test] - public void FromPolar() { - } - - [Test] - public void Equality() { - Vector2 v1 = new(4, 5); - Vector2 v2 = new(1, 2); - - Assert.IsFalse(v1 == v2, "4 5 == 1 2"); - Assert.IsTrue(v1 != v2, "4 5 != 1 2"); - - v2 = new(4, 5); - Assert.IsTrue(v1 == v2, "4 5 == 4 5"); - Assert.IsFalse(v1 != v2, "4 5 != 4 5"); - } - - [Test] - public void Magnitude() { - Vector2 v = new(1, 2); - float m = 0; - m = v.magnitude; - Assert.AreEqual(m, 2.236068F, "v.magnitude 1 2"); - - m = Vector2.MagnitudeOf(v); - Assert.AreEqual(m, 2.236068F, "MagnitudeOf 1 2"); - - v = new(-1, -2); - m = v.magnitude; - Assert.AreEqual(m, 2.236068F, "v.magnitude -1 -2"); - - v = new(0, 0); - m = v.magnitude; - Assert.AreEqual(m, 0, "v.magnitude 0 0"); - } - - [Test] - public void SqrMagnitude() { - Vector2 v = new(1, 2); - float m = 0; - - m = v.sqrMagnitude; - Assert.AreEqual(m, 5, "v.sqrMagnitude 1 2"); - - m = Vector2.SqrMagnitudeOf(v); - Assert.AreEqual(m, 5, "SqrMagnitudeOf 1 2"); - - v = new(-1, -2); - m = v.sqrMagnitude; - Assert.AreEqual(m, 5, "v.sqrMagnitude -1 -2"); - - v = new(0, 0); - m = v.sqrMagnitude; - Assert.AreEqual(m, 0, "v.sqrMagnitude 0 0"); - } - - [Test] - public void Distance() { - Vector2 v1 = new(4, 5); - Vector2 v2 = new(1, 2); - float f = 0; - - f = Vector2.Distance(v1, v2); - Assert.AreEqual(f, 4.24264002f, 1.0E-05F, "Distance(4 5, 1 2)"); - - v2 = new(-1, -2); - f = Vector2.Distance(v1, v2); - Assert.AreEqual(f, 8.602325F, "Distance(4 5, 1 2)"); - - v2 = new(0, 0); - f = Vector2.Distance(v1, v2); - Assert.AreEqual(f, 6.403124F, 1.0E-05F, "Distance(4 5, 1 2)"); - } - - [Test] - public void Normalize() { - Vector2 v = new(0, 3); - Vector2Float r; - - r = v.normalized; - Assert.AreEqual(0, r.horizontal, "normalized 0 3 H"); - Assert.AreEqual(1, r.vertical, "normalized 0 3 V"); - - r = Vector2.Normalize(v); - Assert.AreEqual(0, r.horizontal, "Normalize 0 3 H"); - Assert.AreEqual(1, r.vertical, "Normalize 0 3 V"); - - v = new(0, -3); - r = v.normalized; - Assert.AreEqual(0, r.horizontal, "normalized 0 -3 H"); - Assert.AreEqual(-1, r.vertical, "normalized 0 -3 V"); - - v = new(0, 0); - r = v.normalized; - Assert.AreEqual(0, r.horizontal, "normalized 0 0 H"); - Assert.AreEqual(0, r.vertical, "normalized 0 0 V"); - } - - [Test] - public void Negate() { - Vector2 v = new(4, 5); - Vector2 r; - - r = -v; - Assert.AreEqual(-4, r.horizontal, "- 4 5 H"); - Assert.AreEqual(-5, r.vertical, "- 4 5 V"); - - v = new(-4, -5); - r = -v; - Assert.AreEqual(4, r.horizontal, "- -4 -5 H"); - Assert.AreEqual(5, r.vertical, "- -4 -5 V"); - - v = new(0, 0); - r = -v; - Assert.AreEqual(0, r.horizontal, "- 0 0 H"); - Assert.AreEqual(0, r.vertical, "- 0 0 V"); - } - - [Test] - public void Subtract() { - Vector2 v1 = new(4, 5); - Vector2 v2 = new(1, 2); - Vector2 r = Vector2.zero; - - r = v1 - v2; - Assert.IsTrue(r == new Vector2(3, 3), "4 5 - 1 2"); - - v2 = new(-1, -2); - r = v1 - v2; - Assert.IsTrue(r == new Vector2(5, 7), "4 5 - -1 -2"); - - v2 = new(4, 5); - r = v1 - v2; - Assert.IsTrue(r == new Vector2(0, 0), "4 5 - 4 5"); - r = v1; - r -= v2; - Assert.AreEqual(r, new Vector2(0, 0), "4 5 - 4 5"); - - v2 = new(0, 0); - r = v1 - v2; - Assert.AreEqual(r, new Vector2(4, 5), "4 5 - 0 0"); - r -= v2; - Assert.AreEqual(r, new Vector2(4, 5), "4 5 - 0 0"); - } - - [Test] - public void Addition() { - Vector2 v1 = new(4, 5); - Vector2 v2 = new(1, 2); - Vector2 r = Vector2.zero; - - r = v1 + v2; - Assert.IsTrue(r == new Vector2(5, 7), "4 5 + 1 2"); - - v2 = new(-1, -2); - r = v1 + v2; - Assert.IsTrue(r == new Vector2(3, 3), "4 5 + -1 -2"); - r = v1; - r += v2; - Assert.AreEqual(r, new Vector2(3, 3), "4 5 + -1 -2"); - - v2 = new(0, 0); - r = v1 + v2; - Assert.AreEqual(r, new Vector2(4, 5), "4 5 + 0 0"); - r += v2; - Assert.AreEqual(r, new Vector2(4, 5), "4 5 + 0 0"); - } - - [Test] - public void Scale() { - Vector2 v1 = new(4, 5); - Vector2 v2 = new(1, 2); - Vector2 r; - - r = Vector2.Scale(v1, v2); - Assert.AreEqual(4, r.horizontal, "Scale 4 5 , 1 2 H"); - Assert.AreEqual(10, r.vertical, "Scale 4 5 , 1 2 V"); - - v2 = new(-1, -2); - r = Vector2.Scale(v1, v2); - Assert.AreEqual(-4, r.horizontal, "Scale 4 5 , -1 -2 H"); - Assert.AreEqual(-10, r.vertical, "Scale 4 5 , -1 -2 V"); - - v2 = new(0, 0); - r = Vector2.Scale(v1, v2); - Assert.AreEqual(0, r.horizontal, "Scale 4 5 , 0 0 H"); - Assert.AreEqual(0, r.vertical, "Scale 4 5 , 0 0 V"); - } - - [Test] - public void Multiply() { - Vector2 v1 = new(4, 5); - int f = 3; - Vector2 r; - - r = v1 * f; - Assert.AreEqual(12, r.horizontal, "4 5 * 3 H"); - Assert.AreEqual(15, r.vertical, "4 5 * 3 V"); - - r = f * v1; - Assert.AreEqual(12, r.horizontal, "3 * 4 5 H"); - Assert.AreEqual(15, r.vertical, "3 * 4 5 V"); - - f = -3; - r = v1 * f; - Assert.AreEqual(-12, r.horizontal, "4 5 * -3 H"); - Assert.AreEqual(-15, r.vertical, "4 5 * -3 V"); - - f = 0; - r = v1 * f; - Assert.AreEqual(0, r.horizontal, "4 5 * 0 H"); - Assert.AreEqual(0, r.vertical, "4 5 * 0 V"); - } - - [Test] - public void Divide() { - Vector2 v1 = new(4, 5); - int f = 2; - Vector2 r; - - r = v1 / f; - Assert.AreEqual(2, r.horizontal, "4 5 / 2 H"); - Assert.AreEqual(2, r.vertical, "4 5 / 2 V"); - - f = -2; - r = v1 / f; - Assert.AreEqual(-2, r.horizontal, "4 5 / -2 H"); - Assert.AreEqual(-2, r.vertical, "4 5 / -2 V"); - - Assert.Throws(() => { - f = 0; - r = v1 / f; - Assert.AreEqual(float.PositiveInfinity, r.horizontal, "4 5 / 0 H"); - Assert.AreEqual(float.PositiveInfinity, r.vertical, "4 5 / 0 V"); - }); - } - - [Test] - public void Dot() { - Vector2 v1 = new(4, 5); - Vector2 v2 = new(1, 2); - int f; - - f = Vector2.Dot(v1, v2); - Assert.AreEqual(14, f, "Dot(4 5, 1 2)"); - - v2 = new(-1, -2); - f = Vector2.Dot(v1, v2); - Assert.AreEqual(-14, f, "Dot(4 5, -1 -2)"); - - v2 = new(0, 0); - f = Vector2.Dot(v1, v2); - Assert.AreEqual(0, f, "Dot(4 5, 0 0)"); - } - - } -} -#endif \ No newline at end of file diff --git a/Assets/NanoBrain/LinearAlgebra/test/Vector3FloatTest.cs b/Assets/NanoBrain/LinearAlgebra/test/Vector3FloatTest.cs deleted file mode 100644 index fd3c2dc..0000000 --- a/Assets/NanoBrain/LinearAlgebra/test/Vector3FloatTest.cs +++ /dev/null @@ -1,581 +0,0 @@ -#if !UNITY_5_6_OR_NEWER -using NUnit.Framework; - -namespace LinearAlgebra.Test { - using Vector3 = Vector3Float; - - public class Vector3FloatTest { - - [Test] - public void FromSpherical() { - Vector3 v = new(0, 0, 1); - Spherical s = Spherical.FromVector3(v); - Vector3 r = Vector3.FromSpherical(s); - - Assert.AreEqual(0, r.horizontal, "0 0 1"); - Assert.AreEqual(0, r.vertical, 1.0e-06, "0 0 1"); - Assert.AreEqual(1, r.depth, "0 0 1"); - - v = new(0, 1, 0); - s = Spherical.FromVector3(v); - r = Vector3.FromSpherical(s); - Assert.AreEqual(0, r.horizontal, "0 0 1"); - Assert.AreEqual(1, r.vertical, "0 0 1"); - Assert.AreEqual(0, r.depth, 1.0e-06, "0 0 1"); - - v = new(1, 0, 0); - s = Spherical.FromVector3(v); - r = Vector3.FromSpherical(s); - Assert.AreEqual(1, r.horizontal, "0 0 1"); - Assert.AreEqual(0, r.vertical, 1.0e-06, "0 0 1"); - Assert.AreEqual(0, r.depth, 1.0e-06, "0 0 1"); - } - - [Test] - public void Magnitude() { - Vector3 v = new(1, 2, 3); - float m = 0; - - m = v.magnitude; - Assert.AreEqual(3.7416575f, m, "magnitude 1 2 3"); - - m = Vector3.MagnitudeOf(v); - Assert.AreEqual(3.7416575f, m, "MagnitudeOf 1 2 3"); - - v = new(-1, -2, -3); - m = v.magnitude; - Assert.AreEqual(3.7416575f, m, "magnitude -1 -2 -3"); - - v = new(0, 0, 0); - m = v.magnitude; - Assert.AreEqual(0, m, "magnitude 0 0 0"); - - // Infinity tests are still missing - } - - [Test] - public void SqrMagnitude() { - Vector3 v = new(1, 2, 3); - float m = 0; - - m = v.sqrMagnitude; - Assert.AreEqual(14, m, "sqrMagnitude 1 2 3"); - - m = Vector3.SqrMagnitudeOf(v); - Assert.AreEqual(14, m, "SqrMagnitudeOf 1 2 3"); - - v = new(-1, -2, -3); - m = v.sqrMagnitude; - Assert.AreEqual(14, m, "sqrMagnitude -1 -2 -3"); - - v = new(0, 0, 0); - m = v.sqrMagnitude; - Assert.AreEqual(0, m, "sqrMagnitude 0 0 0"); - - // Infinity tests are still missing - } - - [Test] - public void Normalize() { - Vector3 v = new(0, 2, 0); - Vector3 r; - - r = v.normalized; - Assert.AreEqual(new Vector3(0, 1, 0), r, "normalized 0 2 0"); - - r = Vector3.Normalize(v); - Assert.AreEqual(new Vector3(0, 1, 0), r, "Normalize 0 2 0"); - - v = new(0, -2, 0); - r = v.normalized; - Assert.AreEqual(new Vector3(0, -1, 0), r, "normalized 0 -2 0"); - v = new(0, 0, 0); - r = v.normalized; - Assert.AreEqual(new Vector3(0, 0, 0), r, "normalized 0 0 0"); - - v = new(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); - r = v.normalized; - Assert.IsTrue(float.IsNaN(r.horizontal), "normalized infinity infinity infinity"); - Assert.IsTrue(float.IsNaN(r.vertical), "normalized infinity infinity infinity"); - Assert.IsTrue(float.IsNaN(r.depth), "normalized infinity infinity infinity"); - - v = new(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); - r = v.normalized; - Assert.IsTrue(float.IsNaN(r.horizontal), "normalized -infinity -infinity -infinity"); - Assert.IsTrue(float.IsNaN(r.vertical), "normalized -infinity -infinity -infinity"); - Assert.IsTrue(float.IsNaN(r.depth), "normalized -infinity -infinity -infinity"); - } - - [Test] - public void Negate() { - Vector3 v = new(4, 5, 6); - Vector3 r; - - r = -v; - Assert.AreEqual(-4, r.horizontal, "- 4 5 6 H"); - Assert.AreEqual(-5, r.vertical, "- 4 5 6 V"); - Assert.AreEqual(-6, r.depth, "- 4 5 6 D"); - - v = new(-4, -5, -6); - r = -v; - Assert.AreEqual(4, r.horizontal, "- -4 -5 -6 H"); - Assert.AreEqual(5, r.vertical, "- -4 -5 -6 V"); - Assert.AreEqual(6, r.depth, "- -4 -5 -6 D"); - - v = new(0, 0, 0); - r = -v; - Assert.AreEqual(new Vector3(0, 0, 0), r, "- 0 0 0"); - Assert.AreEqual(0, r.horizontal, "- 0 0 0 H"); - Assert.AreEqual(0, r.vertical, "- 0 0 0 V"); - Assert.AreEqual(0, r.depth, "- 0 0 0 D"); - - - v = new(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); - r = -v; - Assert.AreEqual(new Vector3(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity), r, "- inifinty infinity infinity"); - - v = new(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); - r = -v; - Assert.AreEqual(new Vector3(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity), r, "- -inifinty -infinity -infinity"); - } - - [Test] - public void Subtract() { - Vector3 v1 = new(4, 5, 6); - Vector3 v2 = new(1, 2, 3); - Vector3 r = Vector3.zero; - - r = v1 - v2; - Assert.IsTrue(r == new Vector3(3, 3, 3), "4 5 6 - 1 2 3"); - - v2 = new(-1, -2, -3); - r = v1 - v2; - Assert.IsTrue(r == new Vector3(5, 7, 9), "4 5 6 - -1 -2 -3"); - - v2 = new(4, 5, 6); - r = v1 - v2; - Assert.IsTrue(r == new Vector3(0, 0, 0), "4 5 6 - 4 5 6"); - r = v1; - r -= v2; - Assert.AreEqual(r, new Vector3(0, 0, 0), "4 5 6 - 4 5 6"); - - v2 = new(0, 0, 0); - r = v1 - v2; - Assert.AreEqual(r, new Vector3(4, 5, 6), "4 5 6 - 0 0 0"); - r -= v2; - Assert.AreEqual(r, new Vector3(4, 5, 6), "4 5 6 - 0 0 0"); - - // Infinity tests are still missing - } - - [Test] - public void Addition() { - Vector3 v1 = new(4, 5, 6); - Vector3 v2 = new(1, 2, 3); - Vector3 r = Vector3.zero; - - r = v1 + v2; - Assert.IsTrue(r == new Vector3(5, 7, 9), "4 5 6 + 1 2 3"); - - v2 = new(-1, -2, -3); - r = v1 + v2; - Assert.IsTrue(r == new Vector3(3, 3, 3), "4 5 6 + -1 -2 -3"); - r = v1; - r += v2; - Assert.AreEqual(r, new Vector3(3, 3, 3), "4 5 6 + -1 -2 -3"); - - v2 = new(0, 0, 0); - r = v1 + v2; - Assert.AreEqual(r, new Vector3(4, 5, 6), "4 5 6 + 0 0 0"); - r += v2; - Assert.AreEqual(r, new Vector3(4, 5, 6), "4 5 6 + 0 0 0"); - - // Infinity tests are still missing - } - - [Test] - public void Scale() { - Vector3 v1 = new(4, 5, 6); - Vector3 v2 = new(1, 2, 3); - Vector3 r; - - r = Vector3.Scale(v1, v2); - Assert.AreEqual(4, r.horizontal, "Scale 4 5 6 , 1 2 3 H"); - Assert.AreEqual(10, r.vertical, "Scale 4 5 6 , 1 2 3 V"); - Assert.AreEqual(18, r.depth, "Scale 4 5 6 , 1 2 3 D"); - - v2 = new(-1, -2, -3); - r = Vector3.Scale(v1, v2); - Assert.AreEqual(-4, r.horizontal, "Scale 4 5 6 , -1 -2 -3 H"); - Assert.AreEqual(-10, r.vertical, "Scale 4 5 6 , -1 -2 -3 V"); - Assert.AreEqual(-18, r.depth, "Scale 4 5 6 , -1 -2 -3 D"); - - v2 = new(0, 0, 0); - r = Vector3.Scale(v1, v2); - Assert.AreEqual(0, r.horizontal, "Scale 4 5 6 , 0 0 0 H"); - Assert.AreEqual(0, r.vertical, "Scale 4 5 6 , 0 0 0 V"); - Assert.AreEqual(0, r.depth, "Scale 4 5 6 , 0 0 0 D"); - - v2 = new(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); - r = Vector3.Scale(v1, v2); - Assert.AreEqual(float.PositiveInfinity, r.horizontal, "Scale 4 5 6 , inf inf inf H"); - Assert.AreEqual(float.PositiveInfinity, r.vertical, "Scale 4 5 6 , inf inf inf V"); - Assert.AreEqual(float.PositiveInfinity, r.depth, "Scale 4 5 6 , inf inf inf D"); - - v2 = new(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); - r = Vector3.Scale(v1, v2); - Assert.AreEqual(float.NegativeInfinity, r.horizontal, "Scale 4 5 6 , -inf -inf -inf H"); - Assert.AreEqual(float.NegativeInfinity, r.vertical, "Scale 4 5 6 , -inf -inf -inf V"); - Assert.AreEqual(float.NegativeInfinity, r.depth, "Scale 4 5 6 , -inf -inf -inf D"); - } - - [Test] - public void Multiply() { - Vector3 v1 = new(4, 5, 6); - float f = 3; - Vector3 r; - - r = v1 * f; - Assert.AreEqual(12, r.horizontal, "4 5 6 * 3 H"); - Assert.AreEqual(15, r.vertical, "4 5 6 * 3 V"); - Assert.AreEqual(18, r.depth, "4 5 6 * 3 D"); - - f = -3; - r = v1 * f; - Assert.AreEqual(-12, r.horizontal, "4 5 6 * -3 H"); - Assert.AreEqual(-15, r.vertical, "4 5 6 * -3 V"); - Assert.AreEqual(-18, r.depth, "4 5 6 * -3 D"); - - f = 0; - r = v1 * f; - Assert.AreEqual(0, r.horizontal, "4 5 6 * 0 H"); - Assert.AreEqual(0, r.vertical, "4 5 6 * 0 V"); - Assert.AreEqual(0, r.depth, "4 5 6 * 0 D"); - - f = float.PositiveInfinity; - r = v1 * f; - Assert.AreEqual(float.PositiveInfinity, r.horizontal, "4 5 6 * inf H"); - Assert.AreEqual(float.PositiveInfinity, r.vertical, "4 5 6 * inf V"); - Assert.AreEqual(float.PositiveInfinity, r.depth, "4 5 6 * inf D"); - - f = float.NegativeInfinity; - r = v1 * f; - Assert.AreEqual(float.NegativeInfinity, r.horizontal, "4 5 6 * -inf H"); - Assert.AreEqual(float.NegativeInfinity, r.vertical, "4 5 6 * -inf V"); - Assert.AreEqual(float.NegativeInfinity, r.depth, "4 5 6 * -inf D"); - } - - [Test] - public void Divide() { - Vector3 v1 = new(4, 5, 6); - float f = 2; - Vector3 r; - - r = v1 / f; - Assert.AreEqual(2, r.horizontal, "4 5 6 / 2 H"); - Assert.AreEqual(2.5, r.vertical, "4 5 6 / 2 V"); - Assert.AreEqual(3, r.depth, "4 5 6 / 2 D"); - - f = -2; - r = v1 / f; - Assert.AreEqual(-2, r.horizontal, "4 5 6 / -2 H"); - Assert.AreEqual(-2.5, r.vertical, "4 5 6 / -2 V"); - Assert.AreEqual(-3, r.depth, "4 5 6 / -2 D"); - - f = 0; - r = v1 / f; - Assert.AreEqual(float.PositiveInfinity, r.horizontal, "4 5 6 / 0 H"); - Assert.AreEqual(float.PositiveInfinity, r.vertical, "4 5 6 / 0 V"); - Assert.AreEqual(float.PositiveInfinity, r.depth, "4 5 6 / 0 D"); - - f = float.PositiveInfinity; - r = v1 / f; - Assert.AreEqual(0, r.horizontal, "4 5 6 / inf H"); - Assert.AreEqual(0, r.vertical, "4 5 6 / inf V"); - Assert.AreEqual(0, r.depth, "4 5 6 / inf D"); - - f = float.NegativeInfinity; - r = v1 / f; - Assert.AreEqual(0, r.horizontal, "4 5 6 / -inf H"); - Assert.AreEqual(0, r.vertical, "4 5 6 / -inf V"); - Assert.AreEqual(0, r.depth, "4 5 6 / -inf D"); - } - - [Test] - public void Dot() { - Vector3 v1 = new(4, 5, 6); - Vector3 v2 = new(1, 2, 3); - float f; - - f = Vector3.Dot(v1, v2); - Assert.AreEqual(32, f, "Dot(4 5 6, 1 2 3)"); - - v2 = new(-1, -2, -3); - f = Vector3.Dot(v1, v2); - Assert.AreEqual(-32, f, "Dot(4 5 6, -1 -2 -3)"); - - v2 = new(0, 0, 0); - f = Vector3.Dot(v1, v2); - Assert.AreEqual(0, f, "Dot(4 5 6, 0 0 0)"); - - v2 = new(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); - f = Vector3.Dot(v1, v2); - Assert.AreEqual(float.PositiveInfinity, f, "Dot(4 5 6, inf inf inf)"); - - v2 = new(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); - f = Vector3.Dot(v1, v2); - Assert.AreEqual(float.NegativeInfinity, f, "Dot(4 5 6, -inf -inf -inf)"); - } - - [Test] - public void Equality() { - Vector3 v1 = new(4, 5, 6); - Vector3 v2 = new(1, 2, 3); - bool r; - - r = v1 == v2; - Assert.IsFalse(r, "4 5 6 == 1 2 3"); - - v2 = new(4, 5, 6); - r = v1 == v2; - Assert.IsTrue(r, "4 5 6 == 4 5 6"); - - v2 = new(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); - r = v1 == v2; - Assert.IsFalse(r, "4 5 6 == inf inf inf"); - - v1 = new(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); - r = v1 == v2; - Assert.IsFalse(r, "-inf -inf -inf == inf inf inf"); - } - - [Test] - public void Distance() { - Vector3 v1 = new(4, 5, 6); - Vector3 v2 = new(1, 2, 3); - float f; - - f = Vector3.Distance(v1, v2); - Assert.AreEqual(5.19615221F, f, "Distance(4 5 6, 1 2 3)"); - - v2 = new(-1, -2, -3); - f = Vector3.Distance(v1, v2); - Assert.AreEqual(12.4498997F, f, "Distance(4 5 6, -1 -2 -3)"); - - v2 = new(0, 0, 0); - f = Vector3.Distance(v1, v2); - Assert.AreEqual(v1.magnitude, f, "Distance(4 5 6, 0 0 0)"); - - v2 = new(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); - f = Vector3.Distance(v1, v2); - Assert.AreEqual(float.PositiveInfinity, f, "Distance(4 5 6, inf inf inf)"); - - v2 = new(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); - f = Vector3.Distance(v1, v2); - Assert.AreEqual(float.PositiveInfinity, f, "Distance(4 5 6, -inf -inf -inf)"); - } - - [Test] - public void Cross() { - Vector3 v1 = new(4, 5, 6); - Vector3 v2 = new(1, 2, 3); - Vector3 r; - - r = Vector3.Cross(v1, v2); - Assert.AreEqual(3, r.horizontal, "Cross(4 5 6, 1 2 3) H"); - Assert.AreEqual(-6, r.vertical, "Cross(4 5 6, 1 2 3) V"); - Assert.AreEqual(3, r.depth, "Cross(4 5 6, 1 2 3) D"); - - v2 = new(-1, -2, -3); - r = Vector3.Cross(v1, v2); - Assert.AreEqual(-3, r.horizontal, "Cross(4 5 6, -1 -2 -3) H"); - Assert.AreEqual(6, r.vertical, "Cross(4 5 6, -1 -2 -3) V"); - Assert.AreEqual(-3, r.depth, "Cross(4 5 6, -1 -2 -3) D"); - - v2 = new(0, 0, 0); - r = Vector3.Cross(v1, v2); - Assert.AreEqual(0, r.horizontal, "Cross(4 5 6, 0 0 0) H"); - Assert.AreEqual(0, r.vertical, "Cross(4 5 6, 0 0 0) V"); - Assert.AreEqual(0, r.depth, "Cross(4 5 6, 0 0 0) D"); - - v2 = new(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); - r = Vector3.Cross(v1, v2); - Assert.IsTrue(float.IsNaN(r.horizontal), "Cross(4 5 6, inf inf inf) H"); - Assert.IsTrue(float.IsNaN(r.vertical), "Cross(4 5 6, inf inf inf) V"); - Assert.IsTrue(float.IsNaN(r.depth), "Cross(4 5 6, inf inf inf) D"); - - v2 = new(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); - r = Vector3.Cross(v1, v2); - Assert.IsTrue(float.IsNaN(r.horizontal), "Cross(4 5 6, -inf -inf -inf) H"); - Assert.IsTrue(float.IsNaN(r.vertical), "Cross(4 5 6, -inf -inf -inf) V"); - Assert.IsTrue(float.IsNaN(r.depth), "Cross(4 5 6, -inf -inf -inf) D"); - } - - [Test] - public void Project() { - Vector3 v1 = new(4, 5, 6); - Vector3 v2 = new(1, 2, 3); - Vector3 r; - - r = Vector3.Project(v1, v2); - Assert.AreEqual(2.28571439F, r.horizontal, "Project(4 5 6, 1 2 3) H"); - Assert.AreEqual(4.57142878F, r.vertical, "Project(4 5 6, 1 2 3) V"); - Assert.AreEqual(6.85714293F, r.depth, "Project(4 5 6, 1 2 3) D"); - - v2 = new(-1, -2, -3); - r = Vector3.Project(v1, v2); - Assert.AreEqual(2.28571439F, r.horizontal, "Project(4 5 6, -1 -2 -3) H"); - Assert.AreEqual(4.57142878F, r.vertical, "Project(4 5 6, -1 -2 -3) V"); - Assert.AreEqual(6.85714293F, r.depth, "Project(4 5 6, -1 -2 -3) D"); - - v2 = new(0, 0, 0); - r = Vector3.Project(v1, v2); - Assert.AreEqual(0, r.horizontal, "Project(4 5 6, 0 0 0) H"); - Assert.AreEqual(0, r.vertical, "Project(4 5 6, 0 0 0) V"); - Assert.AreEqual(0, r.depth, "Project(4 5 6, 0 0 0) D"); - - r = Vector3.Project(v2, v1); - Assert.AreEqual(0, r.horizontal, "Project(0 0 0, 4 5 6) H"); - Assert.AreEqual(0, r.vertical, "Project(0 0 0, 4 5 6) V"); - Assert.AreEqual(0, r.depth, "Project(0 0 0, 4 5 6) D"); - - v2 = new(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); - r = Vector3.Project(v1, v2); - Assert.IsTrue(float.IsNaN(r.horizontal), "Project(4 5 6, inf inf inf) H"); - Assert.IsTrue(float.IsNaN(r.vertical), "Project(4 5 6, inf inf inf) V"); - Assert.IsTrue(float.IsNaN(r.depth), "Project(4 5 6, inf inf inf) D"); - - v2 = new(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); - r = Vector3.Project(v1, v2); - Assert.IsTrue(float.IsNaN(r.horizontal), "Project(4 5 6, -inf -inf -inf) H"); - Assert.IsTrue(float.IsNaN(r.vertical), "Project(4 5 6, -inf -inf -inf) V"); - Assert.IsTrue(float.IsNaN(r.depth), "Project(4 5 6, -inf -inf -inf) D"); - } - - [Test] - public void ProjectOnPlane() { - Vector3 v1 = new(4, 5, 6); - Vector3 v2 = new(1, 2, 3); - Vector3 r; - - r = Vector3.ProjectOnPlane(v1, v2); - Assert.AreEqual(1.71428561F, r.horizontal, "ProjectOnPlane(4 5 6, 1 2 3) H"); - Assert.AreEqual(0.428571224F, r.vertical, "ProjectOnPlane(4 5 6, 1 2 3) V"); - Assert.AreEqual(-0.857142925F, r.depth, "ProjectOnPlane(4 5 6, 1 2 3) D"); - - v2 = new(-1, -2, -3); - r = Vector3.ProjectOnPlane(v1, v2); - Assert.AreEqual(1.71428561F, r.horizontal, "ProjectOnPlane(4 5 6, -1 -2 -3) H"); - Assert.AreEqual(0.428571224F, r.vertical, "ProjectOnPlane(4 5 6, -1 -2 -3) V"); - Assert.AreEqual(-0.857142925F, r.depth, "ProjectOnPlane(4 5 6, -1 -2 -3) D"); - - v2 = new(0, 0, 0); - r = Vector3.ProjectOnPlane(v1, v2); - Assert.AreEqual(4, r.horizontal, "ProjectOnPlane(4 5 6, 0 0 0) H"); - Assert.AreEqual(5, r.vertical, "ProjectOnPlane(4 5 6, 0 0 0) V"); - Assert.AreEqual(6, r.depth, "ProjectOnPlane(4 5 6, 0 0 0) D"); - - r = Vector3.ProjectOnPlane(v2, v1); - Assert.AreEqual(0, r.horizontal, "ProjectOnPlane(0 0 0, 4 5 6) H"); - Assert.AreEqual(0, r.vertical, "ProjectOnPlane(0 0 0, 4 5 6) V"); - Assert.AreEqual(0, r.depth, "ProjectOnPlane(0 0 0, 4 5 6) D"); - - v2 = new(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); - r = Vector3.ProjectOnPlane(v1, v2); - Assert.IsTrue(float.IsNaN(r.horizontal), "ProjectOnPlane(4 5 6, inf inf inf) H"); - Assert.IsTrue(float.IsNaN(r.vertical), "ProjectOnPlane(4 5 6, inf inf inf) V"); - Assert.IsTrue(float.IsNaN(r.depth), "ProjectOnPlane(4 5 6, inf inf inf) D"); - - v2 = new(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); - r = Vector3.ProjectOnPlane(v1, v2); - Assert.IsTrue(float.IsNaN(r.horizontal), "ProjectOnPlane(4 5 6, -inf -inf -inf) H"); - Assert.IsTrue(float.IsNaN(r.vertical), "ProjectOnPlane(4 5 6, -inf -inf -inf) V"); - Assert.IsTrue(float.IsNaN(r.depth), "ProjectOnPlane(4 5 6, -inf -inf -inf) D"); - } - - [Test] - public void UnsignedAngle() { - Vector3 v1 = new(4, 5, 6); - Vector3 v2 = new(1, 2, 3); - AngleFloat a; - - a = Vector3.UnsignedAngle(v1, v2); - Assert.AreEqual(12.9331379F, a.inDegrees, "Angle(4 5 6, 1 2 3)"); - - v2 = new(-1, -2, -3); - a = Vector3.UnsignedAngle(v1, v2); - Assert.AreEqual(167.066849F, a.inDegrees, "Angle(4 5 6, -1 -2 -3)"); - - v2 = new(0, 0, 0); - a = Vector3.UnsignedAngle(v1, v2); - Assert.AreEqual(0, a.inDegrees, "Angle(4 5 6, 0 0 0)"); - - v2 = new(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); - a = Vector3.UnsignedAngle(v1, v2); - Assert.IsTrue(float.IsNaN(a.inDegrees), "Angle(4 5 6, inf inf inf)"); - - v2 = new(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); - a = Vector3.UnsignedAngle(v1, v2); - Assert.IsTrue(float.IsNaN(a.inDegrees), "Angle(4 5 6, inf inf inf)"); - } - - [Test] - public void SignedAngle() { - Vector3 v1 = new(4, 5, 6); - Vector3 v2 = new(1, 2, 3); - Vector3 v3 = new(7, 8, -9); - AngleFloat a; - - a = Vector3.SignedAngle(v1, v2, v3); - Assert.AreEqual(-12.9331379F, a.inDegrees, "SignedAngle(4 5 6, 1 2 3, 7 8 -9)"); - - v2 = new(-1, -2, -3); - a = Vector3.SignedAngle(v1, v2, v3); - Assert.AreEqual(167.066849F, a.inDegrees, "SignedAngle(4 5 6, -1 -2 -3, 7 8 -9)"); - - v2 = new(0, 0, 0); - a = Vector3.SignedAngle(v1, v2, v3); - Assert.AreEqual(0, a.inDegrees, "SignedAngle(4 5 6, 0 0 0, 7 8 -9)"); - - v2 = new(1, 2, 3); - v3 = new(-7, -8, 9); - a = Vector3.SignedAngle(v1, v2, v3); - Assert.AreEqual(12.9331379F, a.inDegrees, "SignedAngle(4 5 6, 1 2 3, -7 -8 9)"); - - v3 = new(0, 0, 0); - a = Vector3.SignedAngle(v1, v2, v3); - Assert.AreEqual(0, a.inDegrees, "SignedAngle(4 5 6, 1 2 3, 0 0 0)"); - - v2 = new(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); - a = Vector3.SignedAngle(v1, v2, v3); - Assert.IsTrue(float.IsNaN(a.inDegrees), "SignedAngle(4 5 6, inf inf inf, 0 0 0)"); - - v2 = new(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); - a = Vector3.SignedAngle(v1, v2, v3); - Assert.IsTrue(float.IsNaN(a.inDegrees), "SignedAngle(4 5 6, -inf -inf -inf, 0 0 0)"); - } - - [Test] - public void Lerp() { - Vector3 v1 = new(4, 5, 6); - Vector3 v2 = new(1, 2, 3); - Vector3 r; - - r = Vector3.Lerp(v1, v2, 0); - Assert.AreEqual(0, Vector3.Distance(r, v1), 0); - - r = Vector3.Lerp(v1, v2, 1); - Assert.AreEqual(0, Vector3.Distance(r, v2), 0); - - r = Vector3.Lerp(v1, v2, 0.5f); - Assert.AreEqual(0, Vector3.Distance(r, new Vector3(2.5f, 3.5f, 4.5f)), 0); - - r = Vector3.Lerp(v1, v2, -1); - Assert.AreEqual(0, Vector3.Distance(r, new Vector3(7, 8, 9)), 0); - - r = Vector3.Lerp(v1, v2, 2); - Assert.AreEqual(0, Vector3.Distance(r, new Vector3(-2, -1, 0)), 0); - } - } -} -#endif \ No newline at end of file diff --git a/Assets/NanoBrain/LinearAlgebra/test/Vector3IntTest.cs b/Assets/NanoBrain/LinearAlgebra/test/Vector3IntTest.cs deleted file mode 100644 index b718178..0000000 --- a/Assets/NanoBrain/LinearAlgebra/test/Vector3IntTest.cs +++ /dev/null @@ -1,349 +0,0 @@ -#if !UNITY_5_6_OR_NEWER -using NUnit.Framework; - -namespace LinearAlgebra.Test { - using Vector3 = Vector3Int; - - public class Vector3IntTest { - - [Test] - public void Equality() { - Vector3 v1 = new(4, 5, 6); - Vector3 v2 = new(1, 2, 3); - - Assert.IsFalse(v1 == v2, "4 5 6 == 1 2 3"); - Assert.IsTrue(v1 != v2, "4 5 6 != 1 2 3"); - - v2 = new(4, 5, 6); - Assert.IsTrue(v1 == v2, "4 5 6 == 4 5 6"); - Assert.IsFalse(v1 != v2, "4 5 6 != 4 5 6"); - } - - [Test] - public void Magnitude() { - Vector3 v = new(1, 2, 3); - float m = 0; - - m = v.magnitude; - Assert.AreEqual(3.7416575f, m, "magnitude 1 2 3"); - - m = Vector3.MagnitudeOf(v); - Assert.AreEqual(3.7416575f, m, "MagnitudeOf 1 2 3"); - - v = new(-1, -2, -3); - m = v.magnitude; - Assert.AreEqual(3.7416575f, m, "magnitude -1 -2 -3"); - - v = new(0, 0, 0); - m = v.magnitude; - Assert.AreEqual(0, m, "magnitude 0 0 0"); - - // Infinity tests are still missing - } - - [Test] - public void SqrMagnitude() { - Vector3 v = new(1, 2, 3); - float m = 0; - - m = v.sqrMagnitude; - Assert.AreEqual(14, m, "sqrMagnitude 1 2 3"); - - m = Vector3.SqrMagnitudeOf(v); - Assert.AreEqual(14, m, "SqrMagnitudeOf 1 2 3"); - - v = new(-1, -2, -3); - m = v.sqrMagnitude; - Assert.AreEqual(14, m, "sqrMagnitude -1 -2 -3"); - - v = new(0, 0, 0); - m = v.sqrMagnitude; - Assert.AreEqual(0, m, "sqrMagnitude 0 0 0"); - - // Infinity tests are still missing - } - - [Test] - public void Distance() { - Vector3 v1 = new(4, 5, 6); - Vector3 v2 = new(1, 2, 3); - float f; - - f = Vector3.Distance(v1, v2); - Assert.AreEqual(5.19615221F, f, "Distance(4 5 6, 1 2 3)"); - - v2 = new(-1, -2, -3); - f = Vector3.Distance(v1, v2); - Assert.AreEqual(12.4498997F, f, "Distance(4 5 6, -1 -2 -3)"); - - v2 = new(0, 0, 0); - f = Vector3.Distance(v1, v2); - Assert.AreEqual(v1.magnitude, f, "Distance(4 5 6, 0 0 0)"); - } - - [Test] - public void Normalize() { - Vector3 v = new(0, 2, 0); - Vector3Float r; - - r = v.normalized; - //Assert.AreEqual(new Vector3(0, 1, 0), r, "normalized 0 2 0"); - Assert.AreEqual(0, r.horizontal, "normalized 0 2 0"); - Assert.AreEqual(1, r.vertical, "normalized 0 2 0"); - Assert.AreEqual(0, r.depth, "normalized 0 2 0"); - - r = Vector3.Normalize(v); - Assert.AreEqual(new Vector3Float(0, 1, 0), r, "Normalize 0 2 0"); - - v = new(0, -2, 0); - r = v.normalized; - Assert.AreEqual(new Vector3Float(0, -1, 0), r, "normalized 0 -2 0"); - v = new(0, 0, 0); - r = v.normalized; - Assert.AreEqual(new Vector3Float(0, 0, 0), r, "normalized 0 0 0"); - } - - [Test] - public void Negate() { - Vector3 v = new(4, 5, 6); - Vector3 r; - - r = -v; - Assert.AreEqual(-4, r.horizontal, "- 4 5 6 H"); - Assert.AreEqual(-5, r.vertical, "- 4 5 6 V"); - Assert.AreEqual(-6, r.depth, "- 4 5 6 D"); - - v = new(-4, -5, -6); - r = -v; - Assert.AreEqual(4, r.horizontal, "- -4 -5 -6 H"); - Assert.AreEqual(5, r.vertical, "- -4 -5 -6 V"); - Assert.AreEqual(6, r.depth, "- -4 -5 -6 D"); - - v = new(0, 0, 0); - r = -v; - Assert.AreEqual(new Vector3(0, 0, 0), r, "- 0 0 0"); - Assert.AreEqual(0, r.horizontal, "- 0 0 0 H"); - Assert.AreEqual(0, r.vertical, "- 0 0 0 V"); - Assert.AreEqual(0, r.depth, "- 0 0 0 D"); - } - - [Test] - public void Subtract() { - Vector3 v1 = new(4, 5, 6); - Vector3 v2 = new(1, 2, 3); - Vector3 r = Vector3.zero; - - r = v1 - v2; - Assert.IsTrue(r == new Vector3(3, 3, 3), "4 5 6 - 1 2 3"); - - v2 = new(-1, -2, -3); - r = v1 - v2; - Assert.IsTrue(r == new Vector3(5, 7, 9), "4 5 6 - -1 -2 -3"); - - v2 = new(4, 5, 6); - r = v1 - v2; - Assert.IsTrue(r == new Vector3(0, 0, 0), "4 5 6 - 4 5 6"); - r = v1; - r -= v2; - Assert.AreEqual(r, new Vector3(0, 0, 0), "4 5 6 - 4 5 6"); - - v2 = new(0, 0, 0); - r = v1 - v2; - Assert.AreEqual(r, new Vector3(4, 5, 6), "4 5 6 - 0 0 0"); - r -= v2; - Assert.AreEqual(r, new Vector3(4, 5, 6), "4 5 6 - 0 0 0"); - - // Infinity tests are still missing - } - - [Test] - public void Addition() { - Vector3 v1 = new(4, 5, 6); - Vector3 v2 = new(1, 2, 3); - Vector3 r = Vector3.zero; - - r = v1 + v2; - Assert.IsTrue(r == new Vector3(5, 7, 9), "4 5 6 + 1 2 3"); - - v2 = new(-1, -2, -3); - r = v1 + v2; - Assert.IsTrue(r == new Vector3(3, 3, 3), "4 5 6 + -1 -2 -3"); - r = v1; - r += v2; - Assert.AreEqual(r, new Vector3(3, 3, 3), "4 5 6 + -1 -2 -3"); - - v2 = new(0, 0, 0); - r = v1 + v2; - Assert.AreEqual(r, new Vector3(4, 5, 6), "4 5 6 + 0 0 0"); - r += v2; - Assert.AreEqual(r, new Vector3(4, 5, 6), "4 5 6 + 0 0 0"); - - // Infinity tests are still missing - } - - [Test] - public void Scale() { - Vector3 v1 = new(4, 5, 6); - Vector3 v2 = new(1, 2, 3); - Vector3 r; - - r = Vector3.Scale(v1, v2); - Assert.AreEqual(4, r.horizontal, "Scale 4 5 6 , 1 2 3 H"); - Assert.AreEqual(10, r.vertical, "Scale 4 5 6 , 1 2 3 V"); - Assert.AreEqual(18, r.depth, "Scale 4 5 6 , 1 2 3 D"); - - v2 = new(-1, -2, -3); - r = Vector3.Scale(v1, v2); - Assert.AreEqual(-4, r.horizontal, "Scale 4 5 6 , -1 -2 -3 H"); - Assert.AreEqual(-10, r.vertical, "Scale 4 5 6 , -1 -2 -3 V"); - Assert.AreEqual(-18, r.depth, "Scale 4 5 6 , -1 -2 -3 D"); - - v2 = new(0, 0, 0); - r = Vector3.Scale(v1, v2); - Assert.AreEqual(0, r.horizontal, "Scale 4 5 6 , 0 0 0 H"); - Assert.AreEqual(0, r.vertical, "Scale 4 5 6 , 0 0 0 V"); - Assert.AreEqual(0, r.depth, "Scale 4 5 6 , 0 0 0 D"); - } - - [Test] - public void Multiply() { - Vector3 v1 = new(4, 5, 6); - int f = 3; - Vector3 r; - - r = v1 * f; - Assert.AreEqual(12, r.horizontal, "4 5 6 * 3 H"); - Assert.AreEqual(15, r.vertical, "4 5 6 * 3 V"); - Assert.AreEqual(18, r.depth, "4 5 6 * 3 D"); - - r = f * v1; - Assert.AreEqual(12, r.horizontal, "3 * 4 5 6 H"); - Assert.AreEqual(15, r.vertical, "3 * 4 5 6 V"); - Assert.AreEqual(18, r.depth, "3 * 4 5 6 D"); - - f = -3; - r = v1 * f; - Assert.AreEqual(-12, r.horizontal, "4 5 6 * -3 H"); - Assert.AreEqual(-15, r.vertical, "4 5 6 * -3 V"); - Assert.AreEqual(-18, r.depth, "4 5 6 * -3 D"); - - f = 0; - r = v1 * f; - Assert.AreEqual(0, r.horizontal, "4 5 6 * 0 H"); - Assert.AreEqual(0, r.vertical, "4 5 6 * 0 V"); - Assert.AreEqual(0, r.depth, "4 5 6 * 0 D"); - } - - [Test] - public void Divide() { - Vector3 v1 = new(4, 5, 6); - int f = 2; - Vector3 r; - - r = v1 / f; - Assert.AreEqual(2, r.horizontal, "4 5 6 / 2 H"); - Assert.AreEqual(2, r.vertical, "4 5 6 / 2 V"); - Assert.AreEqual(3, r.depth, "4 5 6 / 2 D"); - - f = -2; - r = v1 / f; - Assert.AreEqual(-2, r.horizontal, "4 5 6 / -2 H"); - Assert.AreEqual(-2, r.vertical, "4 5 6 / -2 V"); - Assert.AreEqual(-3, r.depth, "4 5 6 / -2 D"); - - Assert.Throws(() => { - f = 0; - r = v1 / f; - }); - } - - [Test] - public void Dot() { - Vector3 v1 = new(4, 5, 6); - Vector3 v2 = new(1, 2, 3); - float f; - - f = Vector3.Dot(v1, v2); - Assert.AreEqual(32, f, "Dot(4 5 6, 1 2 3)"); - - v2 = new(-1, -2, -3); - f = Vector3.Dot(v1, v2); - Assert.AreEqual(-32, f, "Dot(4 5 6, -1 -2 -3)"); - - v2 = new(0, 0, 0); - f = Vector3.Dot(v1, v2); - Assert.AreEqual(0, f, "Dot(4 5 6, 0 0 0)"); - } - - [Test] - public void Cross() { - Vector3 v1 = new(4, 5, 6); - Vector3 v2 = new(1, 2, 3); - Vector3 r; - - r = Vector3.Cross(v1, v2); - Assert.AreEqual(3, r.horizontal, "Cross(4 5 6, 1 2 3) H"); - Assert.AreEqual(-6, r.vertical, "Cross(4 5 6, 1 2 3) V"); - Assert.AreEqual(3, r.depth, "Cross(4 5 6, 1 2 3) D"); - - v2 = new(-1, -2, -3); - r = Vector3.Cross(v1, v2); - Assert.AreEqual(-3, r.horizontal, "Cross(4 5 6, -1 -2 -3) H"); - Assert.AreEqual(6, r.vertical, "Cross(4 5 6, -1 -2 -3) V"); - Assert.AreEqual(-3, r.depth, "Cross(4 5 6, -1 -2 -3) D"); - - v2 = new(0, 0, 0); - r = Vector3.Cross(v1, v2); - Assert.AreEqual(0, r.horizontal, "Cross(4 5 6, 0 0 0) H"); - Assert.AreEqual(0, r.vertical, "Cross(4 5 6, 0 0 0) V"); - Assert.AreEqual(0, r.depth, "Cross(4 5 6, 0 0 0) D"); - } - - [Test] - public void UnsignedAngle() { - Vector3 v1 = new(4, 5, 6); - Vector3 v2 = new(1, 2, 3); - AngleFloat a; - - a = Vector3.UnsignedAngle(v1, v2); - Assert.AreEqual(12.9331379F, a.inDegrees, "Angle(4 5 6, 1 2 3)"); - - v2 = new(-1, -2, -3); - a = Vector3.UnsignedAngle(v1, v2); - Assert.AreEqual(167.066849F, a.inDegrees, "Angle(4 5 6, -1 -2 -3)"); - - v2 = new(0, 0, 0); - a = Vector3.UnsignedAngle(v1, v2); - Assert.AreEqual(0, a.inDegrees, "Angle(4 5 6, 0 0 0)"); - } - - [Test] - public void SignedAngle() { - Vector3 v1 = new(4, 5, 6); - Vector3 v2 = new(1, 2, 3); - Vector3 v3 = new(7, 8, -9); - AngleFloat a; - - a = Vector3.SignedAngle(v1, v2, v3); - Assert.AreEqual(-12.9331379F, a.inDegrees, "SignedAngle(4 5 6, 1 2 3, 7 8 -9)"); - - v2 = new(-1, -2, -3); - a = Vector3.SignedAngle(v1, v2, v3); - Assert.AreEqual(167.066849F, a.inDegrees, "SignedAngle(4 5 6, -1 -2 -3, 7 8 -9)"); - - v2 = new(0, 0, 0); - a = Vector3.SignedAngle(v1, v2, v3); - Assert.AreEqual(0, a.inDegrees, "SignedAngle(4 5 6, 0 0 0, 7 8 -9)"); - - v2 = new(1, 2, 3); - v3 = new(-7, -8, 9); - a = Vector3.SignedAngle(v1, v2, v3); - Assert.AreEqual(12.9331379F, a.inDegrees, "SignedAngle(4 5 6, 1 2 3, -7 -8 9)"); - - v3 = new(0, 0, 0); - a = Vector3.SignedAngle(v1, v2, v3); - Assert.AreEqual(0, a.inDegrees, "SignedAngle(4 5 6, 1 2 3, 0 0 0)"); - } - } -} -#endif \ No newline at end of file diff --git a/Assets/NanoBrain/MemoryCell.cs b/Assets/NanoBrain/MemoryCell.cs deleted file mode 100644 index 6e20a75..0000000 --- a/Assets/NanoBrain/MemoryCell.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System; -using UnityEngine; -using Unity.Mathematics; -using static Unity.Mathematics.math; - -[Serializable] -public class MemoryCell : Neuron { - - public MemoryCell(ClusterPrefab cluster, string name) : base(cluster, name) {} - - #region Parameters - - // Returns the memorized value weighted by time - // return lastValue * (current time - last time) - [SerializeField] - public bool deltaValue = false; - - #endregion Parameters - - #region State - - private float3 _memorizedValue; - private float _memorizedTime; - - public override void UpdateState() { - // A memorycell does not have an activation function - float3 result = new(0, 0, 0); - int n = 0; - - //Applying the weight factgors - foreach (Synapse synapse in this.synapses) { - if (synapse.nucleus == this) { - float deltaTime = Time.time - this.lastTime; - synapse.weight = deltaTime; - } - result += synapse.weight * synapse.nucleus.outputValue; - if (lengthsq(synapse.nucleus.outputValue) != 0) - n++; - } - - if (this.average) - result /= n; - - UpdateResult(result); - } - - public override void UpdateResult(Vector3 result) { - // output value is the previous value - if (this.deltaValue) { - float deltaTime = Time.time - this._memorizedTime; - this._outputValue = this._memorizedValue * deltaTime; - } - else - this._outputValue = this._memorizedValue; - - // Store the result for the next time - this._memorizedValue = result; - this._memorizedTime = Time.time; - - foreach (INucleus receiver in this.receivers) - receiver.UpdateState(); - } - - #endregion State -} diff --git a/Assets/NanoBrain/MemoryCell.cs.meta b/Assets/NanoBrain/MemoryCell.cs.meta deleted file mode 100644 index ef74aba..0000000 --- a/Assets/NanoBrain/MemoryCell.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 29633aa3fe5cd9dcc8d886051f45d4d8 \ No newline at end of file diff --git a/Assets/NanoBrain/NanoBrain-Unity.code-workspace b/Assets/NanoBrain/NanoBrain-Unity.code-workspace deleted file mode 100644 index 5194438..0000000 --- a/Assets/NanoBrain/NanoBrain-Unity.code-workspace +++ /dev/null @@ -1,12 +0,0 @@ -{ - "folders": [ - { - "path": "../.." - }, - { - "name": "LinearAlgebra-csharp", - "path": "LinearAlgebra-csharp" - } - ], - "settings": {} -} \ No newline at end of file diff --git a/Assets/NanoBrain/NanoBrain-Unity.code-workspace.meta b/Assets/NanoBrain/NanoBrain-Unity.code-workspace.meta deleted file mode 100644 index 65bb132..0000000 --- a/Assets/NanoBrain/NanoBrain-Unity.code-workspace.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: cfec45da5945b94d684a763d86b0dcf8 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs deleted file mode 100644 index d4a64f2..0000000 --- a/Assets/NanoBrain/Neuroid.cs +++ /dev/null @@ -1,82 +0,0 @@ -/* -using UnityEngine; -using Unity.Mathematics; -using static Unity.Mathematics.math; - -[System.Serializable] -public class Neuroid : Neuron { - - public bool average = false; - - public Neuroid(Cluster brain, string name) : base(name) { - this.cluster = brain; - if (this.cluster != null) { - this.cluster.nuclei.Add(this); - } - else - Debug.LogError("No neuroid network"); - } - - public Neuroid(string name) : base(name) { } - - public override INucleus Clone() { - Neuroid clone = new(this.name) { - cluster = this.cluster, - array = this.array, - curve = this.curve, - curvePreset = this.curvePreset, - curveMax = this.curveMax, - average = this.average - }; - if (clone.cluster != null) - clone.cluster.nuclei.Add(clone); - - foreach (Synapse synapse in this.synapses) { - Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); - clonedSynapse.weight = synapse.weight; - } - foreach (INucleus receiver in this.receivers) { - clone.AddReceiver(receiver); - } - return clone; - } - - public override void UpdateState() { - float3 sum = new(0, 0, 0); - int n = 0; - - //Applying the weight factgors - foreach (Synapse synapse in this.synapses) { - sum = sum + (synapse.weight * synapse.nucleus.outputValue); - if (lengthsq(synapse.nucleus.outputValue) != 0) - n++; - } - if (average) - sum /= n; - - // Activation function - Vector3 result; - switch (this.curvePreset) { - case CurvePresets.Linear: - result = sum; - break; - case CurvePresets.Sqrt: - result = normalize(sum) * System.MathF.Sqrt(length(sum)); - break; - case CurvePresets.Power: - result = normalize(sum) * System.MathF.Pow(length(sum), 2); - break; - case CurvePresets.Reciprocal: - result = normalize(sum) * (1 / length(sum)); - break; - default: - float activatedValue = this.curve.Evaluate(length(sum)); - result = normalize(sum) * activatedValue; - break; - } - UpdateResult(result); - } - -} - -*/ \ No newline at end of file diff --git a/Assets/NanoBrain/Neuroid.cs.meta b/Assets/NanoBrain/Neuroid.cs.meta deleted file mode 100644 index 1c633f0..0000000 --- a/Assets/NanoBrain/Neuroid.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 771f64aec709af240a39b1d918bbc829 \ No newline at end of file diff --git a/Assets/NanoBrain/Neuron.cs b/Assets/NanoBrain/Neuron.cs deleted file mode 100644 index 099ceab..0000000 --- a/Assets/NanoBrain/Neuron.cs +++ /dev/null @@ -1,321 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using UnityEditor; -using Unity.Mathematics; -using static Unity.Mathematics.math; - -[Serializable] -public class Neuron : INucleus { - - [SerializeField] - protected string _name; - public virtual string name { - get => _name; - set => _name = value; - } - - [SerializeField] - private List _synapses = new(); - public List synapses => _synapses; - - [SerializeReference] - private List _receivers = new(); - public List receivers { - get { return _receivers; } - set { _receivers = value; } - } - - [SerializeReference] - private NucleusArray _array; - public NucleusArray array { - get { return _array; } - set { _array = value; } - } - - #region Serialization - - public enum CurvePresets { - Linear, - Power, - Sqrt, - Reciprocal, - Custom - } - [SerializeField] - private CurvePresets _curvePreset; - public CurvePresets curvePreset { - get { return _curvePreset; } - set { - _curvePreset = value; - this.curve = GenerateCurve(); - } - } - public AnimationCurve curve; - public float curveMax = 1.0f; - - #region Parameters - - public bool average = false; - - #endregion Parameters - - public AnimationCurve GenerateCurve() { - switch (this.curvePreset) { - case CurvePresets.Linear: - this.curveMax = 1; - return Presets.Linear(1); - case CurvePresets.Power: - this.curveMax = 1; - return Presets.Power(2.0f, 1); - case CurvePresets.Sqrt: - this.curveMax = 1; - return Presets.Power(0.5f, 1); - case CurvePresets.Reciprocal: - this.curveMax = 1 / 0.01f * 1; - return Presets.Reciprocal(1); - default: - this.curveMax = 1; - return this.curve; - } - } - - public virtual void Deserialize(Neuron nucleus) { } - - #endregion Serialization - - #region Runtime state (not serialized) - - public ClusterPrefab cluster { get; set; } - - #region Activation - - public static class Presets { - private const int samples = 32; - public static AnimationCurve Linear(float weight) { - return AnimationCurve.Linear(0f, 0f, 1000f, weight * 1000); - } - public static AnimationCurve Power(float exponent, float weight) { - // build keyframes - Keyframe[] keys = new Keyframe[samples]; - for (int i = 0; i < samples; i++) { - float t = i / (float)(samples - 1); - float v = Mathf.Pow(t, exponent) * weight; - keys[i] = new Keyframe(t, v); - } - - AnimationCurve curve = new(keys); - - // set tangent modes for each key to Auto (smooth). Use Linear if you prefer straight segments. - for (int i = 0; i < curve.length; i++) { - AnimationUtility.SetKeyLeftTangentMode(curve, i, AnimationUtility.TangentMode.Auto); - AnimationUtility.SetKeyRightTangentMode(curve, i, AnimationUtility.TangentMode.Auto); - } - - return curve; - } - public static AnimationCurve Reciprocal(float weight) { - int samples = 128; - float xMin = 0.001f; - float xMax = 1; - var keys = new Keyframe[samples]; - for (int i = 0; i < samples; i++) { - float t = i / (float)(samples - 1); - float x = Mathf.Lerp(xMin, xMax, t); - float y = 1f / x * weight; - keys[i] = new Keyframe(x, y); - } - var curve = new AnimationCurve(keys); - for (int i = 0; i < curve.length; i++) { - AnimationUtility.SetKeyLeftTangentMode(curve, i, AnimationUtility.TangentMode.Linear); - AnimationUtility.SetKeyRightTangentMode(curve, i, AnimationUtility.TangentMode.Linear); - } - return curve; - } - } - - #endregion Activation - - protected float3 _outputValue; - public virtual float3 outputValue { - get { return _outputValue; } - set { - this.stale = 0; - // this._isSleeping = false; - _outputValue = value; - } - } - - [NonSerialized] - private int stale = 1000; - - // private bool _isSleeping = false; - // public bool isSleeping => _isSleeping; - public bool isSleeping => lengthsq(this.outputValue) == 0; - public float lastTime { get; private set; } - - public void UpdateNuclei() { - this.stale++; - // this._isSleeping = this.stale > 2; - // if (isSleeping) - if (this.stale > 2) - _outputValue = Vector3.zero; - } - - #endregion Runtime state - - public Neuron(ClusterPrefab parent, string name) { - this.cluster = parent; - this.name = name; - if (this.cluster != null) { - this.cluster.nuclei.Add(this); - } - // else - // Debug.LogError("No neuroid network"); - } - - // public Neuron(string name) { - // this._name = name; - // } - - public virtual IReceptor CloneTo(ClusterPrefab parent) { - Neuron clone = new(parent, this.name) { - array = this.array, - curve = this.curve, - curvePreset = this.curvePreset, - curveMax = this.curveMax, - average = this.average - }; - // if (clone.cluster != null) - // clone.cluster.nuclei.Add(clone); - - foreach (Synapse synapse in this.synapses) { - Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); - clonedSynapse.weight = synapse.weight; - } - foreach (INucleus receiver in this.receivers) { - clone.AddReceiver(receiver); - } - return clone; - } - public virtual IReceptor Clone() { - Neuron clone = new(this.cluster, this.name) { - array = this.array, - curve = this.curve, - curvePreset = this.curvePreset, - curveMax = this.curveMax, - average = this.average - }; - // if (clone.cluster != null) - // clone.cluster.nuclei.Add(clone); - - foreach (Synapse synapse in this.synapses) { - Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); - clonedSynapse.weight = synapse.weight; - } - foreach (INucleus receiver in this.receivers) { - clone.AddReceiver(receiver); - } - return clone; - } - - public virtual void AddReceiver(INucleus receivingNucleus) { - this._receivers.Add(receivingNucleus); - receivingNucleus.AddSynapse(this); - } - - public void RemoveReceiver(INucleus receiverNucleus) { - this._receivers.RemoveAll(receiver => receiver == receiverNucleus); - receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); - } - - public static void Delete(INucleus nucleus) { - foreach (Synapse synapse in nucleus.synapses) { - if (synapse.nucleus is Neuron synapse_nucleus) { - if (synapse_nucleus._receivers.Count > 1) { - // there is another nucleus feeding into this input nucleus - synapse_nucleus._receivers.RemoveAll(r => r == nucleus); - } - else { - // No other links, delete it. - Neuron.Delete(synapse_nucleus); - } - } - } - foreach (INucleus receiver in nucleus.receivers) { - if (receiver != null && receiver.synapses != null) - receiver.synapses.RemoveAll(s => s.nucleus == nucleus); - } - - if (nucleus.cluster != null) { - nucleus.cluster.nuclei.RemoveAll(n => n == nucleus); - nucleus.cluster.GarbageCollection(); - } - } - - public Synapse AddSynapse(IReceptor sendingNucleus) { - Synapse synapse = new(sendingNucleus); - this.synapses.Add(synapse); - return synapse; - } - - public virtual void UpdateState() { - UpdateState(new float3(0, 0, 0)); - } - - public virtual void UpdateState(float3 inputValue) { - float3 sum = inputValue;//new(0, 0, 0); - int n = 0; - - //Applying the weight factgors - foreach (Synapse synapse in this.synapses) { - if (synapse.nucleus == this) { - float deltaTime = Time.time - this.lastTime; - synapse.weight = deltaTime; - } - sum += synapse.weight * synapse.nucleus.outputValue; - // Perhaps synapses should be removed when the output value goes to 0.... - if (lengthsq(synapse.nucleus.outputValue) != 0) - n++; - } - if (this.average && n > 0) - sum /= n; - - // Activation function - Vector3 result; - switch (this.curvePreset) { - case CurvePresets.Linear: - result = sum; - break; - case CurvePresets.Sqrt: - result = normalize(sum) * System.MathF.Sqrt(length(sum)); - break; - case CurvePresets.Power: - result = normalize(sum) * System.MathF.Pow(length(sum), 2); - break; - case CurvePresets.Reciprocal: - result = normalize(sum) * (1 / length(sum)); - break; - default: - float activatedValue = this.curve.Evaluate(length(sum)); - result = normalize(sum) * activatedValue; - break; - } - UpdateResult(result); - } - - public virtual void UpdateResult(Vector3 result) { - // float d = Vector3.Distance(result, this.outputValue); - // if (d < 0.5f) { - // //Debug.Log($"insignificant update: {d}"); - // return; - // } - - this.outputValue = result; - this.lastTime = Time.time; - foreach (INucleus receiver in this.receivers) - receiver.UpdateState(); - - } -} \ No newline at end of file diff --git a/Assets/NanoBrain/Neuron.cs.meta b/Assets/NanoBrain/Neuron.cs.meta deleted file mode 100644 index e520090..0000000 --- a/Assets/NanoBrain/Neuron.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 750748f3f0e7d472fbf88ab02987074c \ No newline at end of file diff --git a/Assets/NanoBrain/NucleusArray.cs b/Assets/NanoBrain/NucleusArray.cs deleted file mode 100644 index 82a3b0e..0000000 --- a/Assets/NanoBrain/NucleusArray.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System.Linq; -using System.Collections.Generic; -using UnityEngine; - -[System.Serializable] -public class NucleusArray { - [SerializeReference] - private INucleus[] _nuclei; - private ClusterPrefab[] _clusters; - public IEnumerable nuclei { - get { - // if (_nuclei == null) - // return _clusters; - // else if (_clusters == null) - return _nuclei; - // else - // return _nuclei.Concat(_clusters); - } - } - public string name; - - public NucleusArray(INucleus nucleus) { - this.name = nucleus.name; - this._nuclei = new INucleus[1]; - this._nuclei[0] = nucleus; - this._clusters = new ClusterPrefab[0]; - } - public NucleusArray(ClusterPrefab cluster) { - this.name = cluster.name; - this._nuclei = new INucleus[0]; - this._clusters = new ClusterPrefab[1]; - this._clusters[0] = cluster; - } - - public void AddNucleus() { - if (this._nuclei.Length == 0) { - Debug.LogError("Empty perceptoid array, cannot add"); - return; - } - int newLength = this._nuclei.Length + 1; - INucleus[] newArray = new INucleus[newLength]; - - for (int i = 0; i < this._nuclei.Length; i++) - newArray[i] = this._nuclei[i]; - if (this._nuclei[0] is INucleus nucleus) - newArray[newLength - 1] = (INucleus) nucleus.Clone(); - - this._nuclei = newArray; - } - - public void RemoveNucleus() { - int newLength = this._nuclei.Length - 1; - if (newLength == 0) { - Debug.LogWarning("Perceptoid array cannot be empty"); - return; - } - INucleus[] newPerceptei = new INucleus[newLength]; - for (int i = 0; i < newLength; i++) - newPerceptei[i] = this._nuclei[i]; - // Delete the last perception - Neuron.Delete(this._nuclei[newLength]); - - this._nuclei = newPerceptei; - } - - -} \ No newline at end of file diff --git a/Assets/NanoBrain/NucleusArray.cs.meta b/Assets/NanoBrain/NucleusArray.cs.meta deleted file mode 100644 index 61e26b7..0000000 --- a/Assets/NanoBrain/NucleusArray.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: f8cac60bd79854595a8571c042f77998 \ No newline at end of file diff --git a/Assets/NanoBrain/Perceptoid.cs b/Assets/NanoBrain/Perceptoid.cs deleted file mode 100644 index 447a3d7..0000000 --- a/Assets/NanoBrain/Perceptoid.cs +++ /dev/null @@ -1,105 +0,0 @@ -/* -using UnityEngine; - -[System.Serializable] -public class Perceptoid : Neuroid { - // A neuroid which has no neurons as input - // But receives value from a receptor - - public NanoBrain brain; - public Receptor receptor; - public string baseName; - - public int thingId; - - //[SerializeField] - // Needs serialization!!!! - [SerializeReference] - public PercepteiArray array; - - #region Serialization - - [SerializeField] - public int thingType; - - public override void Rebuild(NanoBrain brain) { - base.Rebuild(brain); - this.receptor = Receptor.GetReceptor(brain, thingType); - this.receptor.perceptei.Add(this); - if (string.IsNullOrEmpty(this.baseName)) - this.baseName = this.name; - } - - public override void Deserialize(Nucleus nucleus) { - base.Deserialize(nucleus); - - if (nucleus is Perceptoid perceptoid) - this.receptor.thingType = perceptoid.thingType; - - // Point all receivers to this perceptoid instead of the default nucleus - foreach (INucleus receiver in nucleus.receivers) { - foreach (Synapse synapse in receiver.synapses) { - if (synapse.nucleus == nucleus) - synapse.nucleus = this; - } - } - // Point all synapses to this perceptoid instead of the default nucleus - // foreach (Synapse synapse in nucleus.synapses) { - // foreach (INucleus r in synapse.nucleus.receivers) { - // if (r == nucleus) - // this.receiver = this; - // } - // } - // Copying disabled for now - // // Copy all the synapses - // this.synapses = nucleus.synapses; - // // Copy all receivers - // this.receivers = nucleus.receivers; - } - - #endregion Serialization - - public Perceptoid(NanoBrain brain, int thingType, string name = "sensor") : base(name) { - this.brain = brain; - this.cluster = brain.cluster; - if (this.cluster != null) { - brain.perceptei.Add(this); - } - else - Debug.LogError("No neuroid network"); - - this.nucleusType = nameof(Perceptoid); - this.name = name; - this.baseName = name; - this.thingType = thingType; - this.receptor = Receptor.GetReceptor(brain, thingType); - this.receptor.perceptei.Add(this); - this.array = new PercepteiArray(this); - } - - public Perceptoid(PercepteiArray array) : base(array.name) { - this.array = array; - Perceptoid source = array.perceptei[0]; - this.brain = source.brain; - this.cluster = source.cluster; - if (this.brain != null) { - this.brain.perceptei.Add(this); - } - else - Debug.LogError("No neuroid network"); - - this.nucleusType = nameof(Perceptoid); - this.name = source.baseName; - this.baseName = source.baseName; - this.thingType = source.thingType; - this.receptor = Receptor.GetReceptor(this.brain, this.thingType); - this.receptor.perceptei.Add(this); - } - - public override void UpdateState() { - Vector3 result = this.receptor.localPosition; - UpdateResult(result); - } - -} -*/ \ No newline at end of file diff --git a/Assets/NanoBrain/Perceptoid.cs.meta b/Assets/NanoBrain/Perceptoid.cs.meta deleted file mode 100644 index ebac122..0000000 --- a/Assets/NanoBrain/Perceptoid.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 702f634001a21a9d7ae1057c8ce356e9 \ No newline at end of file diff --git a/Assets/NanoBrain/Receptor.cs b/Assets/NanoBrain/Receptor.cs deleted file mode 100644 index 72ef7df..0000000 --- a/Assets/NanoBrain/Receptor.cs +++ /dev/null @@ -1,175 +0,0 @@ -using System.Collections.Generic; -using UnityEngine; -using Unity.Mathematics; -using static Unity.Mathematics.math; - -public class Receptor : IReceptor { - - private ClusterPrefab cluster; - - [SerializeField] - protected string _name; - public virtual string name { - get => _name; - set => _name = value; - } - - public Receptor(ClusterPrefab cluster) { - this.cluster = cluster; - if (cluster != null) - cluster.nuclei.Add(this); - } - - public Receptor(ClusterPrefab cluster, INucleus nucleus) { - this.cluster = cluster; - if (cluster != null) - cluster.nuclei.Add(this); - this.AddReceiver(nucleus); - } - - public static Receptor CreateReceptor(ClusterPrefab cluster, string nucleusName) { - if (cluster == null) - return null; - - Receptor receptor = new(cluster); - foreach (INucleus nucleus in cluster.inputs) { - if (nucleus != null && nucleus.name == nucleusName) { - // Receptor receptor = new(cluster, nucleus); - // return receptor; - receptor.AddReceiver(nucleus); - } - } - if (receptor._receivers.Count == 0) - return null; - else - return receptor; - } - - public virtual IReceptor CloneTo(ClusterPrefab parent) { - Receptor clone = new(parent); - - foreach (INucleus receiver in this.receivers) { - clone.AddReceiver(receiver); - } - - return clone; - } - public virtual IReceptor Clone() { - Receptor clone = new(this.cluster); - - foreach (INucleus receiver in this.receivers) { - clone.AddReceiver(receiver); - } - - return clone; - } - - class Receiver { - public INucleus nucleus; - public int thingId; - public string thingName; - public Receiver(INucleus nucleus, int thingId, string thingName) { - this.nucleus = nucleus; - this.thingId = thingId; - this.thingName = thingName; - } - } - - [SerializeReference] - private List _receivers = new(); - public List receivers { - get { return _receivers; } - set { _receivers = value; } - } - - protected int[] thingIds; // every receiver can handle a thing with this id - - public virtual void AddReceiver(INucleus receivingNucleus) { - this._receivers.Add(receivingNucleus); - receivingNucleus.AddSynapse(this); - } - - public void RemoveReceiver(INucleus receiverNucleus) { - this._receivers.RemoveAll(receiver => receiver == receiverNucleus); - receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); - } - - private int stale = 1000; - - private bool _isSleeping = false; - public bool isSleeping => _isSleeping; - - public Vector3 localPosition { - set { - this.stale = 0; - this._isSleeping = false; - this._outputValue = value; - - } - } - public float distanceResolution = 0.1f; - public float directionResolution = 5; - - private float3 _outputValue; - public float3 outputValue { - get { return this._outputValue; } - set { - this.stale = 0; - this._isSleeping = false; - this._outputValue = value; - } - } - - public virtual void ProcessStimulus(int thingId, Vector3 newLocalPositionVector, string thingName = null) { - this.localPosition = newLocalPositionVector; - - thingIds ??= new int[this._receivers.Count]; - - int receiverIx = 0; - INucleus selectedReceiver = null; - int selectedReceiverIx = 0; - foreach (INucleus receiver in this.receivers) { - if (thingIds[receiverIx] == thingId) { - // We found an existing receiver for this thing - selectedReceiver = receiver; - selectedReceiverIx = receiverIx; - // Do not look any further - break; - } - else if (receiver.isSleeping) { - // A sleeping receiver is not active and can therefore always be used - selectedReceiver = receiver; - selectedReceiverIx = receiverIx; - // Look further because we may find an existing receiver for this thing - } - else if (selectedReceiver == null) { - // If we haven't found a receiver yet, just start by taking the first - selectedReceiver = receiver; - selectedReceiverIx = receiverIx; - } - else if (selectedReceiver.isSleeping == false) { - // If no existing or sleeping receiver is found, we look for - // the receiver with the furthest/least interesting stimulus - if (length(receiver.outputValue) < length(selectedReceiver.outputValue)) { - // Debug.Log($"{selectedReceiver.name}[{selectedReceiverIx}] {length(selectedReceiver.outputValue)}" + - // $" {receiver.name}[{receiverIx}] {length(receiver.outputValue)} "); - selectedReceiver = receiver; - selectedReceiverIx = receiverIx; - } - } - receiverIx++; - } - // Debug.Log($"Receiver {selectedReceiver.name}[{selectedReceiverIx}] for thing {thingId}"); - thingIds[selectedReceiverIx] = thingId; - // if (thingName != null) - // selectedReceiver.nucleus.name = selectedReceiver.nucleus.baseName + " " + thingName; - selectedReceiver.UpdateState(); - } - - public void UpdateNuclei() { - this.stale++; - this._isSleeping = this.stale > 2; - if (isSleeping) - this._outputValue = Vector3.zero; - } -} \ No newline at end of file diff --git a/Assets/NanoBrain/Receptor.cs.meta b/Assets/NanoBrain/Receptor.cs.meta deleted file mode 100644 index 56793ae..0000000 --- a/Assets/NanoBrain/Receptor.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: cfb9734aebc3ab85aacf87d26fb92e55 \ No newline at end of file diff --git a/Assets/NanoBrain/Scene.meta b/Assets/NanoBrain/Scene.meta deleted file mode 100644 index d71b5e5..0000000 --- a/Assets/NanoBrain/Scene.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: bfd7dadd61c0891d8a94db0196e61a8a -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/NanoBrain/Scene/TestScene.unity b/Assets/NanoBrain/Scene/TestScene.unity deleted file mode 100644 index 401756e..0000000 --- a/Assets/NanoBrain/Scene/TestScene.unity +++ /dev/null @@ -1,487 +0,0 @@ -%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: 10 - 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: 0 - m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} - m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 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_UseRadianceAmbientProbe: 0 ---- !u!157 &3 -LightmapSettings: - m_ObjectHideFlags: 0 - serializedVersion: 13 - m_BakeOnSceneLoad: 0 - m_GISettings: - serializedVersion: 2 - m_BounceScale: 1 - m_IndirectOutputScale: 1 - m_AlbedoBoost: 1 - m_EnvironmentLightingMode: 0 - m_EnableBakedLightmaps: 1 - 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_ReflectionCompression: 2 - m_MixedBakeMode: 2 - m_BakeBackend: 2 - 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: 1 - m_PVRFilteringGaussRadiusAO: 1 - m_PVRFilteringAtrousPositionSigmaDirect: 0.5 - m_PVRFilteringAtrousPositionSigmaIndirect: 2 - m_PVRFilteringAtrousPositionSigmaAO: 1 - m_ExportTrainingData: 0 - m_TrainingDataDestination: TrainingData - m_LightProbeSampleCountMultiplier: 4 - m_LightingDataAsset: {fileID: 20201, guid: 0000000000000000f000000000000000, type: 0} - m_LightingSettings: {fileID: 0} ---- !u!196 &4 -NavMeshSettings: - serializedVersion: 2 - m_ObjectHideFlags: 0 - m_BuildSettings: - serializedVersion: 3 - 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 - buildHeightMesh: 0 - maxJobWorkers: 0 - preserveTilesOutsideBounds: 0 - debug: - m_Flags: 0 - m_NavMeshData: {fileID: 0} ---- !u!1001 &551770709 -PrefabInstance: - m_ObjectHideFlags: 0 - serializedVersion: 2 - m_Modification: - serializedVersion: 3 - m_TransformParent: {fileID: 0} - m_Modifications: - - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} - propertyPath: m_LocalPosition.x - value: 0.71 - objectReference: {fileID: 0} - - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} - propertyPath: m_LocalPosition.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} - propertyPath: m_LocalPosition.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} - propertyPath: m_LocalRotation.w - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} - propertyPath: m_LocalRotation.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} - propertyPath: m_LocalRotation.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} - propertyPath: m_LocalRotation.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} - propertyPath: m_LocalEulerAnglesHint.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} - propertyPath: m_LocalEulerAnglesHint.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} - propertyPath: m_LocalEulerAnglesHint.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7761516481062093763, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} - propertyPath: m_Name - value: Boid2 - objectReference: {fileID: 0} - m_RemovedComponents: [] - m_RemovedGameObjects: [] - m_AddedGameObjects: [] - m_AddedComponents: [] - m_SourcePrefab: {fileID: 100100000, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} ---- !u!1 &968074744 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 968074747} - - component: {fileID: 968074746} - - component: {fileID: 968074745} - 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 &968074745 -AudioListener: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 968074744} - m_Enabled: 1 ---- !u!20 &968074746 -Camera: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 968074744} - 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_Iso: 200 - m_ShutterSpeed: 0.005 - m_Aperture: 16 - m_FocusDistance: 10 - m_FocalLength: 50 - m_BladeCount: 5 - m_Curvature: {x: 2, y: 11} - m_BarrelClipping: 0.25 - m_Anamorphism: 0 - m_SensorSize: {x: 36, y: 24} - m_LensShift: {x: 0, y: 0} - 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: 0 - 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 &968074747 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 968074744} - serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 1, z: -10} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &1342149740 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1342149742} - - component: {fileID: 1342149741} - m_Layer: 0 - m_Name: SwamControl - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &1342149741 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1342149740} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 0464906885ae3494f8fd0314719fb2db, type: 3} - m_Name: - m_EditorClassIdentifier: Assembly-CSharp::SwarmControl - speed: 0.5 - inertia: 0.1 - alignmentForce: 0 - cohesionForce: 1 - separationForce: 1 - avoidanceForce: 5 - separationDistance: 0.5 - perceptionDistance: 1 - spaceSize: {x: 10, y: 10, z: 10} - boundaryWidth: {x: 1, y: 1, z: 1} ---- !u!4 &1342149742 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1342149740} - serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: -1.00377, y: -1.02283, z: 0.72231} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &2011285159 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 2011285161} - - component: {fileID: 2011285160} - m_Layer: 0 - m_Name: Directional Light - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!108 &2011285160 -Light: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2011285159} - m_Enabled: 1 - serializedVersion: 12 - m_Type: 1 - m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} - m_Intensity: 1 - m_Range: 10 - m_SpotAngle: 30 - m_InnerSpotAngle: 21.80208 - m_CookieSize2D: {x: 0.5, y: 0.5} - m_Shadows: - m_Type: 2 - m_Resolution: -1 - m_CustomResolution: -1 - m_Strength: 1 - m_Bias: 0.05 - m_NormalBias: 0.4 - m_NearPlane: 0.2 - m_CullingMatrixOverride: - e00: 1 - e01: 0 - e02: 0 - e03: 0 - e10: 0 - e11: 1 - e12: 0 - e13: 0 - e20: 0 - e21: 0 - e22: 1 - e23: 0 - e30: 0 - e31: 0 - e32: 0 - e33: 1 - m_UseCullingMatrixOverride: 0 - m_Cookie: {fileID: 0} - m_DrawHalo: 0 - m_Flare: {fileID: 0} - m_RenderMode: 0 - m_CullingMask: - serializedVersion: 2 - m_Bits: 4294967295 - m_RenderingLayerMask: 1 - m_Lightmapping: 4 - m_LightShadowCasterMode: 0 - m_AreaSize: {x: 1, y: 1} - m_BounceIntensity: 1 - m_ColorTemperature: 6570 - m_UseColorTemperature: 0 - m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} - m_UseBoundingSphereOverride: 0 - m_UseViewFrustumForShadowCasterCull: 1 - m_ForceVisible: 0 - m_ShadowRadius: 0 - m_ShadowAngle: 0 - m_LightUnit: 1 - m_LuxAtDistance: 1 - m_EnableSpotReflector: 1 ---- !u!4 &2011285161 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2011285159} - serializedVersion: 2 - m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} - m_LocalPosition: {x: 0, y: 3, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} ---- !u!1001 &4573752827112804207 -PrefabInstance: - m_ObjectHideFlags: 0 - serializedVersion: 2 - m_Modification: - serializedVersion: 3 - m_TransformParent: {fileID: 0} - m_Modifications: - - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} - propertyPath: m_LocalPosition.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} - propertyPath: m_LocalPosition.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} - propertyPath: m_LocalPosition.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} - propertyPath: m_LocalRotation.w - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} - propertyPath: m_LocalRotation.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} - propertyPath: m_LocalRotation.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} - propertyPath: m_LocalRotation.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} - propertyPath: m_LocalEulerAnglesHint.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} - propertyPath: m_LocalEulerAnglesHint.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7761516481062093762, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} - propertyPath: m_LocalEulerAnglesHint.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7761516481062093763, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} - propertyPath: m_Name - value: Boid1 - objectReference: {fileID: 0} - m_RemovedComponents: [] - m_RemovedGameObjects: [] - m_AddedGameObjects: [] - m_AddedComponents: [] - m_SourcePrefab: {fileID: 100100000, guid: 6860355b30724b5ddb35781dcaf3b57e, type: 3} ---- !u!1660057539 &9223372036854775807 -SceneRoots: - m_ObjectHideFlags: 0 - m_Roots: - - {fileID: 968074747} - - {fileID: 2011285161} - - {fileID: 4573752827112804207} - - {fileID: 551770709} - - {fileID: 1342149742} diff --git a/Assets/NanoBrain/Scene/TestScene.unity.meta b/Assets/NanoBrain/Scene/TestScene.unity.meta deleted file mode 100644 index 676153c..0000000 --- a/Assets/NanoBrain/Scene/TestScene.unity.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 1070383882ed0f5379a3b34e8ccb1f75 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/NanoBrain/Synapse.cs b/Assets/NanoBrain/Synapse.cs deleted file mode 100644 index e7c8116..0000000 --- a/Assets/NanoBrain/Synapse.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using UnityEngine; - -[Serializable] -public class Synapse { - // Support access to cluster of basic nucleus - //public IReceptor nucleus => basicNucleus; - - - //[SerializeReference] - //public Cluster cluster; - - [SerializeReference] - public IReceptor nucleus; - - public float weight; - - public Synapse(IReceptor nucleus, float weight = 1.0f) { - this.nucleus = nucleus; - this.weight = weight; - } -} \ No newline at end of file diff --git a/Assets/NanoBrain/Synapse.cs.meta b/Assets/NanoBrain/Synapse.cs.meta deleted file mode 100644 index e62612c..0000000 --- a/Assets/NanoBrain/Synapse.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 334a58eafccd60cbdb32f719e9e861c6 \ No newline at end of file diff --git a/Assets/NanoBrain/Velocity.asset b/Assets/NanoBrain/Velocity.asset deleted file mode 100644 index 521ba9b..0000000 --- a/Assets/NanoBrain/Velocity.asset +++ /dev/null @@ -1,108 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3} - m_Name: Velocity - m_EditorClassIdentifier: Assembly-CSharp::Cluster - nuclei: - - rid: 2243601403683012671 - - rid: 2243601403683012676 - references: - version: 2 - RefIds: - - rid: -2 - type: {class: , ns: , asm: } - - rid: 2243601403683012671 - type: {class: Neuron, ns: , asm: Assembly-CSharp} - data: - _name: Output - _synapses: - - nucleus: - rid: -2 - weight: 1 - _receivers: [] - _array: - rid: 2243601403683012672 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 1 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1000 - value: 1000 - inSlope: 1 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - - rid: 2243601403683012672 - type: {class: NucleusArray, ns: , asm: Assembly-CSharp} - data: - _nuclei: - - rid: 2243601403683012671 - name: Output - - rid: 2243601403683012676 - type: {class: Neuron, ns: , asm: Assembly-CSharp} - data: - _name: Position - _synapses: [] - _receivers: - - rid: 2243601403683012671 - _array: - rid: 2243601403683012677 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 1 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1000 - value: 1000 - inSlope: 1 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - - rid: 2243601403683012677 - type: {class: NucleusArray, ns: , asm: Assembly-CSharp} - data: - _nuclei: - - rid: 2243601403683012676 - name: New neuron diff --git a/Assets/NanoBrain/Velocity.asset.meta b/Assets/NanoBrain/Velocity.asset.meta deleted file mode 100644 index 07ecb98..0000000 --- a/Assets/NanoBrain/Velocity.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: dd622ac7ed09e70ea8edac595047ac82 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/NanoBrain/VisualEditor.meta b/Assets/NanoBrain/VisualEditor.meta deleted file mode 100644 index d012778..0000000 --- a/Assets/NanoBrain/VisualEditor.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 62a58c801eda0c9eab7a49fb1d0840cb -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/NanoBrain/VisualEditor/Editor.meta b/Assets/NanoBrain/VisualEditor/Editor.meta deleted file mode 100644 index c068f8e..0000000 --- a/Assets/NanoBrain/VisualEditor/Editor.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: e47ea55fc051fcdcb8ae6197d1105cc0 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/NanoBrain/VisualEditor/Editor/BrainPickerWindow.cs b/Assets/NanoBrain/VisualEditor/Editor/BrainPickerWindow.cs deleted file mode 100644 index 3a536df..0000000 --- a/Assets/NanoBrain/VisualEditor/Editor/BrainPickerWindow.cs +++ /dev/null @@ -1,66 +0,0 @@ -using UnityEditor; -using UnityEngine; -using System; -using System.Linq; - -public class BrainPickerWindow : EditorWindow { - private Vector2 scroll; - private ClusterPrefab[] items = new ClusterPrefab[0]; - private Action onPicked; - private string search = ""; - - public static void ShowPicker(Action onPicked, string title = "Select Cluster") { - var w = CreateInstance(); - w.titleContent = new GUIContent(title); - w.minSize = new Vector2(360, 320); - w.onPicked = onPicked; - w.RefreshList(); - w.ShowModalUtility(); // modal dialog - } - - private void OnEnable() => RefreshList(); - - private void RefreshList() { - var guids = AssetDatabase.FindAssets("t:Cluster"); - items = guids - .Select(g => AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(g))) - .Where(b => b != null) - .OrderBy(b => b.name) - .ToArray(); - } - - private void OnGUI() { - EditorGUILayout.Space(); - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.LabelField("Choose Cluster:", EditorStyles.boldLabel); - if (GUILayout.Button("Refresh", GUILayout.Width(80))) RefreshList(); - GUILayout.FlexibleSpace(); - EditorGUILayout.EndHorizontal(); - - EditorGUILayout.Space(); - search = EditorGUILayout.TextField(search); - - EditorGUILayout.Space(); - scroll = EditorGUILayout.BeginScrollView(scroll); - foreach (var it in items) { - if (!string.IsNullOrEmpty(search) && it.name.IndexOf(search, StringComparison.OrdinalIgnoreCase) < 0) - continue; - - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.LabelField(EditorGUIUtility.ObjectContent(it, typeof(ClusterPrefab)), GUILayout.Height(20)); - if (GUILayout.Button("Select", GUILayout.Width(70))) { - onPicked?.Invoke(it); - Close(); - return; - } - EditorGUILayout.EndHorizontal(); - } - EditorGUILayout.EndScrollView(); - - EditorGUILayout.Space(); - EditorGUILayout.BeginHorizontal(); - if (GUILayout.Button("Cancel")) { onPicked?.Invoke(null); Close(); } - GUILayout.FlexibleSpace(); - EditorGUILayout.EndHorizontal(); - } -} diff --git a/Assets/NanoBrain/VisualEditor/Editor/BrainPickerWindow.cs.meta b/Assets/NanoBrain/VisualEditor/Editor/BrainPickerWindow.cs.meta deleted file mode 100644 index b2de114..0000000 --- a/Assets/NanoBrain/VisualEditor/Editor/BrainPickerWindow.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 9197e2d322d23b5798ab4aef729815b0 \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs deleted file mode 100644 index 94273dd..0000000 --- a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs +++ /dev/null @@ -1,728 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using UnityEditor; - -using UnityEngine; -using UnityEngine.UIElements; -using Unity.Mathematics; -using static Unity.Mathematics.math; - -[CustomEditor(typeof(ClusterPrefab))] -public class ClusterInspector : Editor { - protected static VisualElement mainContainer; - protected static VisualElement inspectorContainer; - - protected bool breakOnWake = false; - - #region Start - - public override VisualElement CreateInspectorGUI() { - ClusterPrefab cluster = target as ClusterPrefab; - - serializedObject.Update(); - - VisualElement root = new(); - //root.style.flexDirection = FlexDirection.Row; // side-by-side layout - //root.style.flexGrow = 1; - //root.style.minHeight = 600; - root.style.paddingLeft = 0; - root.style.paddingRight = 0; - root.style.paddingTop = 0; - root.style.paddingBottom = 0; - - root.styleSheets.Add(Resources.Load("GraphStyles")); - - mainContainer = new() { - // name = "main", - style = { - // flexDirection = FlexDirection.Row, - // flexGrow = 1, - height = 450, - } - }; - GraphView graph = new(); - graph.style.flexGrow = 1; - - inspectorContainer = new VisualElement { - // name = "inspector" - }; - - mainContainer.Add(graph); - mainContainer.Add(inspectorContainer); - root.Add(mainContainer); - - // Run once for initial state (use resolved style width if available) - float initialWidth = root.layout.width > 0 ? root.layout.width : root.contentRect.width; - UpdateLayout(initialWidth); - - // React to size changes of root (or parent if appropriate) - root.RegisterCallback(evt => { - UpdateLayout(evt.newRect.width); - }); - - if (cluster != null) { - cluster.EnsureInitialization(); - graph.SetGraph(null, cluster, cluster.output, inspectorContainer); - } - else - Debug.LogWarning(" No brain!"); - - serializedObject.ApplyModifiedProperties(); - return root; - } - - public class GraphView : VisualElement { - ClusterPrefab cluster; - SerializedObject serializedBrain; - INucleus currentNucleus; - GameObject gameObject; - private List layers = new(); - private readonly Dictionary neuroidPositions = new(); - private bool expandArray = false; - - //Vector2 pan = Vector2.zero; - //float zoom = 1f; - //bool draggingCanvas = false; - //Vector2 lastMouse; - ClusterWrapper currentWrapper; - - public GraphView() { - name = "content"; - style.flexGrow = 1; - - IMGUIContainer imguiContainer = new(OnIMGUI); - imguiContainer.style.position = Position.Absolute; - imguiContainer.style.left = 0; imguiContainer.style.top = 0; - imguiContainer.style.right = 0; imguiContainer.style.bottom = 0; - imguiContainer.pickingMode = PickingMode.Position; - imguiContainer.focusable = true; - Add(imguiContainer); - - //RegisterCallback(OnWheel); - // RegisterCallback(OnMouseDown); - // RegisterCallback(OnMouseMove); - // RegisterCallback(OnMouseUp); - - // Subscribe when added to panel (editor UI ready) - RegisterCallback(evt => Subscribe()); - RegisterCallback(evt => Unsubscribe()); - } - - - bool subscribed = false; - void Subscribe() { - if (subscribed) return; - SceneView.duringSceneGui += OnSceneGUI; - subscribed = true; - SceneView.RepaintAll(); - } - - void Unsubscribe() { - if (!subscribed) return; - SceneView.duringSceneGui -= OnSceneGUI; - subscribed = false; - } - - public void SetGraph(GameObject gameObject, ClusterPrefab brain, INucleus nucleus, VisualElement inspectorContainer) { - this.gameObject = gameObject; - this.cluster = brain; - if (Application.isPlaying == false) - this.serializedBrain = new SerializedObject(brain); - this.currentNucleus = nucleus; - Rebuild(inspectorContainer); - } - - void Rebuild(VisualElement inspectorContainer) { - BuildLayers(); - - if (this.currentNucleus == null) { - inspectorContainer.Clear(); - return; - } - - if (currentWrapper != null) - DestroyImmediate(currentWrapper); - currentWrapper = CreateInstance().Init(this.currentNucleus, cluster); - DrawInspector(inspectorContainer); - } - - private void BuildLayers() { - // A temporary list to track what's been added to layers - this.layers = new(); - int layerIx = 0; - - INucleus selectedNucleus = this.currentNucleus; - if (selectedNucleus == null) - return; - NeuroidLayer currentLayer = new() { ix = layerIx }; - - if (selectedNucleus.receivers != null) { - foreach (INucleus receiver in selectedNucleus.receivers) { - INucleus outputNeuroid = receiver; - if (outputNeuroid != null) { - AddToLayer(currentLayer, outputNeuroid); - // Debug.Log($"layer {layerIx} nucleus {outputNeuroid.name}"); - } - } - } - if (currentLayer.neuroids.Count > 0) { - this.layers.Add(currentLayer); - layerIx++; - currentLayer = new() { ix = layerIx }; - } - - AddToLayer(currentLayer, selectedNucleus); - this.layers.Add(currentLayer); - // Debug.Log($"layer {layerIx} nucleus {selectedNucleus.name}"); - - layerIx++; - currentLayer = new() { ix = layerIx }; - - if (selectedNucleus.synapses != null) { - foreach (Synapse synapse in selectedNucleus.synapses) { - IReceptor input = synapse.nucleus; - AddToLayer(currentLayer, input); - // Debug.Log($"layer {layerIx} nucleus {input.name}"); - } - } - if (currentLayer.neuroids.Count > 0) { - this.layers.Add(currentLayer); - } - } - - private void AddToLayer(NeuroidLayer layer, IReceptor nucleus) { - if (nucleus == null) - return; - layer.neuroids.Add(nucleus); - //nucleus.layerIx = layer.ix; - // Store its position - Vector2Int neuroidPosition = new(layer.ix, layer.neuroids.Count - 1); - neuroidPositions[nucleus] = neuroidPosition; - - } - - - public void OnIMGUI() { - if (currentNucleus == null) - return; - - if (Application.isPlaying == false) - serializedBrain.Update(); - - Handles.BeginGUI(); - DrawGraph(); - Handles.EndGUI(); - - } - - private void DrawGraph() { - float size = 20; - Vector3 position = new(150, 210, 0); - - DrawReceivers(this.currentNucleus, position, size); - DrawSynapses(this.currentNucleus, position, size); - - // Draw selected Nucleus - if (expandArray) { - float maxValue = 0; - foreach (INucleus nucleus in this.currentNucleus.array.nuclei) { - float value = length(nucleus.outputValue); - if (value > maxValue) - maxValue = value; - } - - float spacing = 400f / this.currentNucleus.array.nuclei.Count(); - float margin = 10 + spacing / 2; - float xMin = 150 - size; - float xMax = 150 + size; - float yMin = 10 + margin - size / 2; - float yMax = 400 - margin + size; - Vector3[] verts = new Vector3[4] { - new(xMin, yMin, 0), - new(xMax, yMin, 0), - new(xMax, yMax, 0), - new(xMin, yMax, 0) - }; - Handles.color = Color.black; - Handles.DrawAAConvexPolygon(verts); - int row = 0; - foreach (INucleus nucleus in this.currentNucleus.array.nuclei) { - Vector3 pos = new(150, margin + row * spacing, 0.0f); - Handles.color = Color.white; - //Handles.DrawLine(parentPos, pos); - - Handles.color = Color.white; - Handles.DrawSolidDisc(pos, Vector3.forward, size + 2); - DrawNucleus(nucleus, pos, maxValue, size); - row++; - } - GUIStyle style = new(EditorStyles.label) { - alignment = TextAnchor.UpperCenter, - normal = { textColor = Color.white }, - fontStyle = FontStyle.Bold, - }; - Vector3 labelPos = new Vector3(150, yMax, 0) - Vector3.down * (size + 10); // below disc along up axis - Handles.Label(labelPos, this.currentNucleus.name, style); - } - else { - Handles.color = Color.white; - Handles.DrawSolidDisc(position, Vector3.forward, size + 2); - DrawNucleus(this.currentNucleus, position, length(this.currentNucleus.outputValue), 20); - } - } - - private void DrawReceivers(INucleus nucleus, Vector3 parentPos, float size) { - int nodeCount = nucleus.receivers.Count(); - - // Determine the maximum value in this layer - // This is used to 'scale' the output value colors of the nuclei - float maxValue = 0; - foreach (INucleus receiver in nucleus.receivers) { - if (receiver is Neuron neuroid) { - float value = length(neuroid.outputValue); - if (value > maxValue) - maxValue = value; - } - } - - // Determine the spacing of the nuclei in the layer - float spacing = 400f / nodeCount; - float margin = 10 + spacing / 2; - - int row = 0; - foreach (INucleus receiver in nucleus.receivers) { - INucleus receiverNucleus = receiver; - if (receiverNucleus == null) - continue; - - Vector3 pos = new(50, margin + row * spacing, 0.0f); - Handles.color = Color.white; - Handles.DrawLine(parentPos, pos); - - DrawNucleus(receiverNucleus, pos, maxValue, size); - row++; - } - } - - private void DrawSynapses(INucleus nucleus, Vector3 parentPos, float size) { - int nodeCount = nucleus.synapses.Count; - - // Determine the maximum value in this layer - // This is used to 'scale' the output value colors of the nuclei - float maxValue = 0; - int neuronCount = 0; - List drawnArrays = new(); - foreach (Synapse synapse in nucleus.synapses) { - if (synapse.nucleus is Neuron neuroid) { - if (drawnArrays.Contains(neuroid.array)) - continue; - drawnArrays.Add(neuroid.array); - - } - float value = length(synapse.nucleus.outputValue) * synapse.weight; - // Debug.Log($"{synapse.nucleus.name}: {value} {length(synapse.nucleus.outputValue)} {synapse.weight}"); - if (value > maxValue) - maxValue = value; - neuronCount++; - } - - // Determine the spacing of the nuclei in the layer - float spacing = 400f / neuronCount; - float margin = 10 + spacing / 2; - - int row = 0; - drawnArrays = new(); - foreach (Synapse synapse in nucleus.synapses) { - if (synapse.nucleus is Neuron neuron) { - if (drawnArrays.Contains(neuron.array)) - continue; - drawnArrays.Add(neuron.array); - } - Vector3 pos = new(250, margin + row * spacing, 0.0f); - Handles.color = Color.white; - Handles.DrawLine(parentPos, pos); - if (synapse.nucleus != null) { - Color color = Color.black; - if (synapse.nucleus.isSleeping) - color = Color.darkRed; - else if (Application.isPlaying) { - float brightness = length(synapse.nucleus.outputValue) * synapse.weight / maxValue; - color = new Color(brightness, brightness, brightness, 1f); - } - DrawNucleus(synapse.nucleus, pos, maxValue, size, color); - } - row++; - } - } - - private void DrawNucleus(IReceptor nucleus, Vector3 position, float maxValue, float size) { - Color color; - if (nucleus.isSleeping) - color = Color.darkRed; - else { - if (Application.isPlaying) { - float brightness = length(nucleus.outputValue) / maxValue; - color = new Color(brightness, brightness, brightness, 1f); - } - else - color = Color.black; - } - DrawNucleus(nucleus, position, maxValue, size, color); - } - - private void DrawNucleus(IReceptor nucleus, Vector3 position, float maxValue, float size, Color color) { - if (nucleus is MemoryCell memory) { - Handles.color = Color.white; - Handles.DrawWireDisc(position + Vector3.right * 10, Vector3.forward, size); - } - - Handles.color = color; - Handles.DrawSolidDisc(position, Vector3.forward, size); - - Handles.color = Color.white; - // Position the label in front of the disc - Vector3 labelPosition = position + (Vector3.forward * 0.1f); - - GUIStyle style = new(EditorStyles.label) { - alignment = TextAnchor.MiddleCenter, - normal = { textColor = Color.white }, - fontStyle = FontStyle.Bold, - }; - if (nucleus is INucleus neuron) { - if (neuron.array == null || neuron.array.nuclei == null || neuron.array.nuclei.Count() == 0) - neuron.array = new NucleusArray(neuron); - - if ((!expandArray || neuron.array.nuclei.First() != this.currentNucleus) && neuron.array.nuclei.Count() > 1) { - Handles.Label(labelPosition, neuron.array.nuclei.Count().ToString(), style); - } - if (expandArray && neuron.array.nuclei.First() == this.currentNucleus) { - int arrayIx = 0; - foreach (INucleus n in neuron.array.nuclei) { - if (n == neuron) - break; - arrayIx++; - } - Handles.Label(labelPosition, $"[{arrayIx}]", style); - } - else { - style.alignment = TextAnchor.UpperCenter; - Vector3 labelPos = position - Vector3.down * (size + 10f); // below disc along up axis - Handles.Label(labelPos, nucleus.name, style); - } - - if (nucleus is Cluster cluster) { - Handles.color = Color.white; - Handles.DrawWireDisc(position, Vector3.forward, size + 10); - } - } - else { - style.alignment = TextAnchor.UpperCenter; - Vector3 labelPos = position - Vector3.down * (size + 10); // below disc along up axis - Handles.Label(labelPos, nucleus.name, style); - } - - Rect neuronRect = new(position.x - size, position.y - size, size * 2, size * 2); - int id = GUIUtility.GetControlID(FocusType.Passive); - Event e = Event.current; - EventType et = e.GetTypeForControl(id); - if (e != null && neuronRect.Contains(e.mousePosition)) { - // Process Hover - HandleMouseHover(nucleus, neuronRect); - // Process click - if (e.type == EventType.MouseDown && e.button == 0) { - // Consume the event so the scene doesn't also handle it - e.Use(); - HandleClicked(nucleus); - } - } - } - - private void HandleMouseHover(IReceptor nucleus, Rect rect) { - GUIContent tooltip; - if (nucleus is INucleus n) { - tooltip = new( - $"{nucleus.name}" + - $"\nsynapse count {n.synapses.Count}" + - $"\nValue: {nucleus.outputValue}"); - } - else { - tooltip = new( - $"{nucleus.name}" + - $"\nValue: {nucleus.outputValue}"); - } - - Vector2 mousePosition = Event.current.mousePosition; - - // Display tooltip with some offset - Vector2 tooltipSize = GUI.skin.box.CalcSize(tooltip); - Rect tooltipRect = new Rect(mousePosition.x + 10, mousePosition.y + 10, tooltipSize.x, tooltipSize.y); - - GUI.Box(tooltipRect, tooltip); - } - - private void HandleClicked(IReceptor nucleus) { - if (nucleus == this.currentNucleus) { - if (nucleus is INucleus n) { - expandArray = !expandArray; - return; - } - } - else if (nucleus is INucleus n) { - this.currentNucleus = n; - BuildLayers(); - } - } - - void DrawInspector(VisualElement inspectorContainer) { - if (inspectorContainer == null) - return; - - inspectorContainer.Clear(); - if (this.currentNucleus == null) - return; - - // create a SerializedObject wrapper so Unity inspector controls work (and Undo) - SerializedObject so = new(currentWrapper); - IMGUIContainer container = new(() => { - if (so.targetObject == null) - return; - so.Update(); - - if (this.currentNucleus == null) - return; - - this.currentNucleus.name = EditorGUILayout.TextField(this.currentNucleus.name); - if (this.currentNucleus is Neuron neuroid) { - if (this.currentNucleus is MemoryCell memory) { - } - else { - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.LabelField("Activation Curve", GUILayout.Width(150)); - if (neuroid.curveMax > 0) - EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, 0, 1, neuroid.curveMax)); - else - EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, neuroid.curveMax, 1, -neuroid.curveMax)); - neuroid.curvePreset = (Neuron.CurvePresets)EditorGUILayout.EnumPopup(neuroid.curvePreset, GUILayout.Width(100)); - EditorGUILayout.EndHorizontal(); - } - - if (neuroid.array == null || neuroid.array.nuclei == null || neuroid.array.nuclei.Count() == 0) - neuroid.array = new NucleusArray(neuroid); - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.IntField("Array size", neuroid.array.nuclei.Count()); - if (GUILayout.Button("Add")) - neuroid.array.AddNucleus(); - if (GUILayout.Button("Del")) - neuroid.array.RemoveNucleus(); - EditorGUILayout.EndHorizontal(); - } - - if (Application.isPlaying) - EditorGUILayout.FloatField("Output", length(this.currentNucleus.outputValue)); - else - EditorGUILayout.LabelField(" "); - - if (this.currentNucleus.synapses.Count > 0) { - EditorGUILayout.LabelField("Synapses"); - Synapse[] synapses = this.currentNucleus.synapses.ToArray(); - foreach (Synapse synapse in synapses) { - if (synapse.nucleus != null) { - EditorGUILayout.Space(); - - //EditorGUI.BeginDisabledGroup(synapse.nucleus.isSleeping); - if (Application.isPlaying) - EditorGUILayout.FloatField(synapse.nucleus.name, length(synapse.nucleus.outputValue) * synapse.weight); - else { - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.LabelField(synapse.nucleus.name); - if (GUILayout.Button("Disconnect")) - synapse.nucleus.RemoveReceiver(this.currentNucleus); - EditorGUILayout.EndHorizontal(); - } - - EditorGUI.indentLevel++; - synapse.weight = EditorGUILayout.FloatField("Weight", synapse.weight); - EditorGUI.indentLevel--; - //EditorGUI.EndDisabledGroup(); - } - } - } - - EditorGUILayout.Space(); - - ConnectNucleus(this.cluster, this.currentNucleus); - if (GUILayout.Button("Add Input Neuron")) - AddInputNeuron(this.currentNucleus); - if (GUILayout.Button("Add Input MemoryCell")) - AddInputMemoryCell(this.currentNucleus); - if (GUILayout.Button("Add Input Cluster")) - AddCluster(this.currentNucleus); - - EditorGUILayout.Space(); - - if (GUILayout.Button("Delete this neuron")) - DeleteNeuron(this.currentNucleus); - - if (this.currentNucleus is Cluster subCluster) { - if (GUILayout.Button("Edit Cluster")) - EditCluster(subCluster); - } - - // if (this.gameObject != null) { - // Vector3 worldVector = this.gameObject.transform.TransformVector(this.currentNucleus.outputValue); - // //Debug.DrawRay(this.gameObject.transform.position, worldVector, Color.yellow); - // Handles.color = Color.yellow; - // Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); - // } - }); - - inspectorContainer.Add(container); - } - - void OnSceneGUI(SceneView sceneView) { - if (this.gameObject != null) { - Vector3 worldVector = this.gameObject.transform.TransformVector(this.currentNucleus.outputValue); - Handles.color = Color.yellow; - Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); - } - } - - protected virtual void AddInputNeuron(INucleus nucleus) { - Neuron newNeuroid = new(this.cluster, "New neuron"); - newNeuroid.AddReceiver(nucleus); - this.currentNucleus = newNeuroid; - BuildLayers(); - } - - protected virtual void DeleteNeuron(INucleus nucleus) { - if (nucleus == null) - return; - if (nucleus.cluster != null) - this.currentNucleus = nucleus.cluster.output; - foreach (INucleus receiver in nucleus.receivers) { - if (receiver != null) { - this.currentNucleus = receiver; - break; - } - } - Neuron.Delete(nucleus); - BuildLayers(); - } - - protected virtual void AddInputMemoryCell(INucleus nucleus) { - MemoryCell newMemory = new(this.cluster, "New memory cell"); - newMemory.AddReceiver(nucleus); - this.currentNucleus = newMemory; - BuildLayers(); - } - - protected virtual void AddCluster(INucleus nucleus) { - BrainPickerWindow.ShowPicker(brain => OnClusterPicked(nucleus, brain), "Select Cluster"); - } - - private void OnClusterPicked(INucleus nucleus, ClusterPrefab subCluster) { - Cluster subclusterInstance = new(this.cluster, subCluster); - //this.cluster.AddSubCluster(subclusterInstance); - //this.cluster.nuclei.Add(subclusterInstance); - subclusterInstance.AddReceiver(nucleus); - } - - private void EditCluster(Cluster subCluster) { - //var currentActiveObject = Selection.activeObject; - Selection.activeObject = subCluster.prefab; - EditorGUIUtility.PingObject(subCluster.prefab); - var editor = Editor.CreateEditor(subCluster.prefab); - //Selection.activeObject = currentActiveObject; - } - - // Connect to another nucleus in the same cluster - protected virtual void ConnectNucleus(ClusterPrefab cluster, INucleus nucleus) { - if (cluster == null) - return; - - IEnumerable synapseNuclei = this.currentNucleus.synapses.Select(synapse => synapse.nucleus != null ? synapse.nucleus.name : ""); - //IEnumerable perceptei = this.currentNucleus.brain.perceptei.Select(i => i.name).Except(synapseNuclei); - IEnumerable nuclei = cluster.nuclei.Select(i => i.name).Except(synapseNuclei); - //string[] names = perceptei.Concat(nuclei).ToArray(); - string[] names = nuclei.ToArray(); - int selectedIndex = -1; - selectedIndex = EditorGUILayout.Popup("Connect to", selectedIndex, names); - if (selectedIndex >= 0) { - // if (selectedIndex < perceptei.Count()) { - // Nucleus n = this.currentNucleus.brain.perceptei[selectedIndex]; - // n.AddReceiver(this.currentNucleus); - // } - // else { - // Nucleus n = this.currentNucleus.brain.nuclei[selectedIndex - perceptei.Count()]; - // n.AddReceiver(this.currentNucleus); - // } - IReceptor receptor = cluster.nuclei[selectedIndex]; - receptor.AddReceiver(this.currentNucleus); - } - } - - protected virtual void DisconnectNucleus(Neuron nucleus) { - if (this.currentNucleus.cluster == null) - return; - string[] names = this.currentNucleus.synapses.Select(synapse => synapse.nucleus.name).ToArray(); - int selectedIndex = -1; - selectedIndex = EditorGUILayout.Popup("Disconnect from", selectedIndex, names); - //if (selectedIndex >= 0 && selectedIndex < this.currentNucleus.brain.perceptei.Count) { - if (selectedIndex >= 0 && selectedIndex < this.currentNucleus.cluster.nuclei.Count) { - Synapse synapse = this.currentNucleus.synapses[selectedIndex]; - synapse.nucleus.RemoveReceiver(this.currentNucleus); - } - } - } - - #endregion Start - - #region Update - - private void UpdateLayout(float containerWidth) { - if (containerWidth > 600f) { - mainContainer.style.flexDirection = FlexDirection.Row; - inspectorContainer.style.width = 300; // fixed sidebar width - inspectorContainer.style.flexGrow = 0; - } - else { - mainContainer.style.flexDirection = FlexDirection.Column; - inspectorContainer.style.width = Length.Percent(100); // full width below - inspectorContainer.style.flexDirection = FlexDirection.Column; - inspectorContainer.style.flexGrow = 1; // can set 0 or keep as needed - } - } - - #endregion Update -} - -public class NeuroidLayer { - public int ix = 0; - public List neuroids = new(); -} - -public class ClusterWrapper : ScriptableObject { - // expose fields that map to GraphNode - //public string title; - public Vector2 position; - INucleus node; - ClusterPrefab graph; // needed to write back and mark dirty - - public ClusterWrapper Init(INucleus node, ClusterPrefab graphAsset) { - this.node = node; - this.graph = graphAsset; - //this.title = " A " + node.name; - //position = node.position; - return this; - } - void OnValidate() { - if (node != null) { - //node.name = title; - //node.position = position; -#if UNITY_EDITOR - if (graph != null) - UnityEditor.EditorUtility.SetDirty(graph); -#endif - } - } -} \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs.meta b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs.meta deleted file mode 100644 index a1a18f5..0000000 --- a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 1fc1fb7db9f7ad54a87d31313e7f457d \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs deleted file mode 100644 index 253993a..0000000 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs +++ /dev/null @@ -1,129 +0,0 @@ -using UnityEditor; -using UnityEditor.UIElements; -using UnityEngine; -using UnityEngine.UIElements; - -[CustomEditor(typeof(NanoBrainComponent))] -public class NanoBrainComponent_Editor : Editor { - protected static VisualElement mainContainer; - protected static VisualElement inspectorContainer; - - protected NanoBrainComponent component; - private SerializedProperty brainProp; - - ClusterInspector.GraphView board; - - public void OnEnable() { - component = target as NanoBrainComponent; - - if (Application.isPlaying == false) - brainProp = serializedObject.FindProperty(nameof(NanoBrainComponent.defaultBrain)); - - } - - public override VisualElement CreateInspectorGUI() { - //NanoBrainComponent component = target as NanoBrainComponent; - ClusterPrefab brain = Application.isPlaying ? component.brain : component.defaultBrain; - - if (Application.isPlaying == false) - serializedObject.Update(); - - - VisualElement root = new(); - root.style.flexDirection = FlexDirection.Column; // side-by-side layout - root.style.flexGrow = 1; - root.style.minHeight = 600; - root.style.paddingLeft = 0; - root.style.paddingRight = 0; - root.style.paddingTop = 0; - root.style.paddingBottom = 0; - - root.styleSheets.Add(Resources.Load("GraphStyles")); - - if (Application.isPlaying == false) { - PropertyField brainField = new(brainProp) { - label = "Nano Brain" - }; - root.Add(brainField); - } - - mainContainer = new() { - name = "main", - style = { - flexDirection = FlexDirection.Row, - flexGrow = 1, - minHeight = 500, - } - }; - board = new ClusterInspector.GraphView(); - board.style.flexGrow = 1; - mainContainer.Add(board); - - inspectorContainer = new VisualElement { - name = "inspector", - style = { - width = 400, - } - }; - - mainContainer.Add(inspectorContainer); - root.Add(mainContainer); - - // Run once for initial state (use resolved style width if available) - float initialWidth = root.layout.width > 0 ? root.layout.width : root.contentRect.width; - UpdateLayout(initialWidth); - - // React to size changes of root (or parent if appropriate) - root.RegisterCallback(evt => { - UpdateLayout(evt.newRect.width); - }); - - if (brain != null && board != null) - board.SetGraph(component.gameObject, brain, brain.output, inspectorContainer); - // else - // Debug.LogWarning(" No brain!"); - - if (Application.isPlaying == false) - serializedObject.ApplyModifiedProperties(); - return root; - } - - // void OnSceneGUI() { - // if (Application.isPlaying && board != null) - // board.OnIMGUI(); - // } - - void OnSceneGui(SceneView sv) { - if (Application.isPlaying == false) - return; - // May need some throttling here... - if (board != null) { - Debug.Log("."); - board.OnIMGUI(); - } - - // EditorApplication.delayCall = UpdateInspectorUI; - } - - void UpdateInspectorUI() { - if (board != null) { - Debug.Log("."); - board.OnIMGUI(); - } - } - - private void UpdateLayout(float containerWidth) { - if (containerWidth > 800f) { - mainContainer.style.flexDirection = FlexDirection.Row; - inspectorContainer.style.width = 400; // fixed sidebar width - inspectorContainer.style.flexGrow = 0; - } - else { - mainContainer.style.flexDirection = FlexDirection.Column; - inspectorContainer.style.width = Length.Percent(100); // full width below - inspectorContainer.style.flexDirection = FlexDirection.Column; - inspectorContainer.style.flexGrow = 1; // can set 0 or keep as needed - } - } - -} \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs.meta b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs.meta deleted file mode 100644 index eaf830b..0000000 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: f05072314d39990639a2dbf99f322664 \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs deleted file mode 100644 index 230bfa1..0000000 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs +++ /dev/null @@ -1,511 +0,0 @@ -/* -using UnityEditor; -using UnityEngine; -using UnityEngine.UIElements; -using UnityEditor.Callbacks; -using System.Linq; -using System.Collections.Generic; - -public class NucleusLayer { - public int ix = 0; - public List neuroids = new(); -} - -public class NanoBrainEditor : EditorWindow { - public NanoBrain brain; - - public static VisualElement inspectorContainer; - - [MenuItem("Window/NanoBrain Editor")] - public static void ShowWindow() { - GetWindow("NanoBrain Editor"); - } - - public static void Open(NanoBrain asset) { - NanoBrainEditor editor = GetWindow("NanoBrain Editor"); - editor.brain = asset; - editor.Show(); - } - - GraphBoardView board; - - private void OnEnable() { - OnFocus(); - } - private void OnFocus() { - if (brain == null) { - // brain = CreateInstance(); - // EditorUtility.SetDirty(brain); - return; - } - - VisualElement root = rootVisualElement; - root.Clear(); - root.styleSheets.Add(Resources.Load("GraphStyles")); - - VisualElement main = new() { - name = "main", - style = { - flexDirection = FlexDirection.Row, - flexGrow = 1 - } - }; - board = new GraphBoardView(); - board.style.flexGrow = 1; - inspectorContainer = new VisualElement { - name = "inspector", - style = { - width = 400 - } - }; - - main.Add(board); - main.Add(inspectorContainer); - root.Add(main); - - board.SetGraph(brain, brain.root); - - } - -} - -public class GraphBoardView : VisualElement { - NanoBrain brain; - SerializedObject serializedBrain; - Nucleus currentNucleus; - private List layers = new(); - private Dictionary neuroidPositions = new(); - - Vector2 pan = Vector2.zero; - //float zoom = 1f; - bool draggingCanvas = false; - Vector2 lastMouse; - GraphNodeWrapper currentWrapper; - - public GraphBoardView() { - name = "content"; - style.flexGrow = 1; - - IMGUIContainer imguiContainer = new(OnIMGUI); - imguiContainer.style.position = Position.Absolute; - imguiContainer.style.left = 0; imguiContainer.style.top = 0; - imguiContainer.style.right = 0; imguiContainer.style.bottom = 0; - imguiContainer.pickingMode = PickingMode.Position; - imguiContainer.focusable = true; - Add(imguiContainer); - - //RegisterCallback(OnWheel); - RegisterCallback(OnMouseDown); - RegisterCallback(OnMouseMove); - RegisterCallback(OnMouseUp); - } - - public void SetGraph(NanoBrain brain, Nucleus nucleus) { - this.brain = brain; - this.serializedBrain = new SerializedObject(brain); - this.currentNucleus = nucleus; - Rebuild(); - } - - void Rebuild() { - BuildLayers(); - - if (currentNucleus == null) { - NanoBrainEditor.inspectorContainer.Clear(); - return; - } - - if (currentWrapper != null) - Object.DestroyImmediate(currentWrapper); - currentWrapper = ScriptableObject.CreateInstance().Init(currentNucleus, brain); - DrawInspector(); - } - - private void BuildLayers() { - // A temporary list to track what's been added to layers - this.layers = new(); - int layerIx = 0; - - Nucleus selectedNucleus = this.currentNucleus; - if (selectedNucleus == null) - return; - NeuroidLayer currentLayer = new() { ix = layerIx }; - - //foreach (Nucleus outputNeuroid in selectedNucleus.receivers) { - foreach (Receiver receiver in selectedNucleus.receivers) { - Nucleus outputNeuroid = receiver.nucleus; - if (outputNeuroid != null) { - AddToLayer(currentLayer, outputNeuroid); - // Debug.Log($"layer {layerIx} nucleus {outputNeuroid.name}"); - } - } - if (currentLayer.neuroids.Count > 0) { - this.layers.Add(currentLayer); - layerIx++; - currentLayer = new() { ix = layerIx }; - } - - AddToLayer(currentLayer, selectedNucleus); - this.layers.Add(currentLayer); - // Debug.Log($"layer {layerIx} nucleus {selectedNucleus.name}"); - - layerIx++; - currentLayer = new() { ix = layerIx }; - - //foreach (Nucleus input in selectedNucleus.synapses.Keys) { - foreach (Synapse synapse in selectedNucleus.synapses) { - Nucleus input = synapse.nucleus; - AddToLayer(currentLayer, input); - // Debug.Log($"layer {layerIx} nucleus {input.name}"); - } - if (currentLayer.neuroids.Count > 0) { - this.layers.Add(currentLayer); - } - } - - private void AddToLayer(NeuroidLayer layer, Nucleus nucleus) { - if (nucleus == null) - return; - layer.neuroids.Add(nucleus); - nucleus.layerIx = layer.ix; - // Store its position - Vector2Int neuroidPosition = new(layer.ix, layer.neuroids.Count - 1); - neuroidPositions[nucleus] = neuroidPosition; - - } - - // basic pan/zoom handling - // void OnWheel(WheelEvent e) { - // if (e.ctrlKey) { - // float delta = -e.delta.y * 0.001f; - // zoom = Mathf.Clamp(zoom + delta, 0.25f, 2f); - // content.transform.rotation = Quaternion.identity; // keep transform accessible - // content.transform.scale = new Vector3(zoom, zoom, 1); - // e.StopPropagation(); - // } - // else { - // pan += e.delta; - // content.style.left = pan.x; - // content.style.top = pan.y; - // } - // } - - void OnMouseDown(MouseDownEvent e) { - if (e.button == 2) { draggingCanvas = true; lastMouse = e.mousePosition; e.StopPropagation(); } - } - void OnMouseMove(MouseMoveEvent e) { - if (draggingCanvas) { - var delta = e.mousePosition - lastMouse; - pan += delta; - //content.style.left = pan.x; - //content.style.top = pan.y; - lastMouse = e.mousePosition; - } - } - void OnMouseUp(MouseUpEvent e) { if (e.button == 2) draggingCanvas = false; } - - void OnIMGUI() { - if (currentNucleus == null) - return; - - serializedBrain.Update(); - - Handles.BeginGUI(); - foreach (NeuroidLayer layer in layers) - DrawLayer(layer); - Handles.EndGUI(); - - } - - private void DrawLayer(NeuroidLayer layer) { - int nodeCount = layer.neuroids.Count; - float maxValue = 0; - foreach (Nucleus nucleus in layer.neuroids) { - if (nucleus is Neuroid neuroid) { - float value = neuroid.outputValue.magnitude; - if (value > maxValue) - maxValue = value; - } - } - float spacing = 400f / nodeCount; - float margin = 10 + spacing / 2; - foreach (Nucleus layerNucleus in layer.neuroids) { - Vector2Int layerNeuroidPos = this.neuroidPositions[layerNucleus]; - Vector3 parentPos = new(100 + layerNeuroidPos.x * 100, margin + layerNeuroidPos.y * spacing, 0.1f); - - //int i = 0; - float inputSpacing = 400f / layerNucleus.synapses.Count; - float inputMargin = 10 + inputSpacing / 2; - // int minStale = 10000; - //foreach ((Nucleus nucleus, float weight) in layerNucleus.synapses) { - foreach (Synapse synapse in layerNucleus.synapses) { - Nucleus nucleus = synapse.nucleus; - if (nucleus != null) { - float weight = synapse.weight; - if (this.neuroidPositions.ContainsKey(nucleus)) { - Vector2Int inputNeuroidPos = this.neuroidPositions[nucleus]; - if (inputNeuroidPos.x == layerNeuroidPos.x + 1) { - Vector3 pos = new(100 + inputNeuroidPos.x * 100, inputMargin + inputNeuroidPos.y * inputSpacing, 0.0f); - - float brightness = weight / 10.0f; - Handles.color = new Color(brightness, brightness, brightness); - Handles.DrawLine(parentPos, pos); - } - } - // if (nucleus is Neuroid neuroid && neuroid.stale < minStale) - // minStale = neuroid.stale; - } - } - - // if (layerNucleus.synapses.Count > 0 && minStale > 2 && layerNucleus.stale < 3) - // Debug.LogWarning($"Strange {minStale} is big duing update"); - - - float size = 20; - if (layerNucleus.isSleeping) - Handles.color = Color.darkRed; - else { - float brightness = layerNucleus.outputValue.magnitude / maxValue; - Handles.color = new Color(brightness, brightness, brightness); - } - Handles.DrawSolidDisc(parentPos, Vector3.forward, size); - Vector3 labelPos = parentPos - Vector3.down * (size + 0.2f); // below disc along up axis - GUIStyle style = new GUIStyle(EditorStyles.label) { - alignment = TextAnchor.UpperCenter, - normal = { textColor = Color.white }, - fontStyle = FontStyle.Bold - }; - Handles.Label(labelPos, layerNucleus.name, style); - - Rect neuronRect = new(parentPos.x - size, parentPos.y - size, size * 2, size * 2); - int id = GUIUtility.GetControlID(FocusType.Passive); - Event e = Event.current; - EventType et = e.GetTypeForControl(id); - if (e != null && neuronRect.Contains(e.mousePosition)) { - // Process Hover - HandleMouseHover(layerNucleus, neuronRect); - // Process click - // Debug.Log($"{et} {e.type}"); - if (e.type == EventType.MouseDown && e.button == 0) { - // Consume the event so the scene doesn't also handle it - e.Use(); - HandleDiscClicked(layerNucleus); - } - } - } - } - - private void HandleMouseHover(Nucleus neuroid, Rect rect) { - GUIContent tooltip; - // if (neuroid is SensoryNeuroid sensoryNeuroid) { - // tooltip = new( - // $"{sensoryNeuroid.name}" + - // $"\nThing {sensoryNeuroid.receptor.thingType}" + - // $"\nValue: {neuroid.outputValue}"); - // } - // else { - tooltip = new( - $"{neuroid.name}" + - $"\nsynapse count {neuroid.synapses.Count}" + - $"\nValue: {neuroid.outputValue}"); - // } - - Vector2 mousePosition = Event.current.mousePosition; - - // Display tooltip with some offset - Vector2 tooltipSize = GUI.skin.box.CalcSize(tooltip); - Rect tooltipRect = new Rect(mousePosition.x + 10, mousePosition.y + 10, tooltipSize.x, tooltipSize.y); - - GUI.Box(tooltipRect, tooltip); - } - - private void HandleDiscClicked(Nucleus nucleus) { - this.currentNucleus = nucleus; - BuildLayers(); - } - - - void DrawInspector() { - if (NanoBrainEditor.inspectorContainer == null) - return; - - NanoBrainEditor.inspectorContainer.Clear(); - if (this.currentNucleus == null) - return; - - // create a SerializedObject wrapper so Unity inspector controls work (and Undo) - SerializedObject so = new SerializedObject(currentWrapper); - IMGUIContainer container = new IMGUIContainer(() => { - so.Update(); - currentNucleus.name = EditorGUILayout.TextField(currentNucleus.name); - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.LabelField("Output Value", GUILayout.Width(100)); - EditorGUILayout.Vector3Field(GUIContent.none, currentNucleus.outputValue); - EditorGUILayout.EndHorizontal(); - if (currentNucleus.synapses.Count > 0) { - EditorGUILayout.LabelField("Synapses"); - EditorGUI.indentLevel++; - - //List nuclei = currentNucleus.synapses.Keys.ToList(); - // foreach (Nucleus nucleus in nuclei) { - foreach (Synapse synapse in currentNucleus.synapses) { - EditorGUI.BeginDisabledGroup(synapse.nucleus.isSleeping); - - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.LabelField(synapse.nucleus.name, GUILayout.Width(120)); - EditorGUI.indentLevel--; - EditorGUILayout.LabelField("Weight", GUILayout.Width(45)); - // float weight = currentNucleus.synapses[nucleus]; - // currentNucleus.synapses[nucleus] = EditorGUILayout.FloatField(weight, GUILayout.Width(40)); - synapse.weight = EditorGUILayout.FloatField(synapse.weight, GUILayout.Width(40)); - EditorGUI.indentLevel++; - EditorGUILayout.Vector3Field(GUIContent.none, synapse.nucleus.outputValue, GUILayout.Width(180)); - EditorGUILayout.EndHorizontal(); - - EditorGUI.EndDisabledGroup(); - } - EditorGUI.indentLevel--; - } - if (GUILayout.Button("Add Neuron")) - AddInputNeuron(currentNucleus); - - }); - - NanoBrainEditor.inspectorContainer.Add(container); - } - - protected virtual void AddInputNeuron(Nucleus receiver) { - Neuroid newNeuroid = new(brain, "New neuron"); - newNeuroid.AddReceiver(receiver); - Rebuild(); - } - - private Vector3 NodePosition(Nucleus nucleus, int layerNodeCount = 1) { - if (this.neuroidPositions.ContainsKey(nucleus)) { - Vector2Int nucleusPos = this.neuroidPositions[nucleus]; - return NodePosition(nucleusPos, layerNodeCount); - } - else { - return Vector3.zero; - } - } - private Vector3 NodePosition(Vector2Int location, int layerNodeCount = 1) { - float spacing = 400f / layerNodeCount; - float margin = 10 + spacing / 2; - float size = 20; - Vector3 parentPos = new(100 + location.x * 100 - size, margin + location.y * spacing - size, 0.1f); - return parentPos; - } - - - // public void CreateEdge(string fromId, string toId) { - // if (fromId == toId) return; - // Undo.RecordObject(graph, "Create Edge"); - // graph.edges.Add(new GraphEdge { fromNodeId = fromId, toNodeId = toId }); - // EditorUtility.SetDirty(graph); - // Rebuild(); - // } -} - - -public class NodeView : VisualElement { - Nucleus data; - GraphBoardView board; - Label titleLabel; - //bool dragging = false; - Vector2 localDragStart; - - public NodeView(Nucleus node, GraphBoardView boardView) { - data = node; - board = boardView; - name = "node"; - style.width = 20; //node.size.x; - style.height = 20; //node.size.y; - - titleLabel = new Label(node.name) { name = "title" }; - Add(titleLabel); - - // ports - // var outPort = new Button(() => StartEdgeDrag(true)) { text = "◀", name = "out" }; - // var inPort = new Button(() => StartEdgeDrag(false)) { text = "▶", name = "in" }; - // Add(outPort); - // Add(inPort); - - RegisterCallback(OnMouseDown); - // RegisterCallback(OnMouseMove); - RegisterCallback(OnMouseUp); - //RegisterCallback(e => dragging = false); - } - - // void StartEdgeDrag(bool isOutput) { - // // simplified: on first click store source; on second click on target port call board.CreateEdge - // if (EdgeDragState.active == null) EdgeDragState.active = new EdgeDragState { fromNode = data, fromIsOutput = isOutput }; - // else { - // var src = EdgeDragState.active.fromNode; - // if (src != null && src.id != data.id) board.CreateEdge(src.id, data.id); - // EdgeDragState.active = null; - // } - // } - - void OnMouseDown(MouseDownEvent e) { - if (e.button == 0 && e.target == this) { - //dragging = true; - localDragStart = e.mousePosition; - e.StopPropagation(); - } - } - // void OnMouseMove(MouseMoveEvent e) { - // if (!dragging) return; - // var delta = e.mousePosition - localDragStart; - // var worldPos = new Vector2(layout.x + delta.x, layout.y + delta.y); - // style.left = worldPos.x; - // style.top = worldPos.y; - // // commit on every move - // board.UpdateNodePosition(data, worldPos); - // } - void OnMouseUp(MouseUpEvent e) { - //dragging = false; - } -} - - -public class GraphNodeWrapper : ScriptableObject { - // expose fields that map to GraphNode - public string title; - public Vector2 position; - Nucleus node; - NanoBrain graph; // needed to write back and mark dirty - - public GraphNodeWrapper Init(Nucleus node, NanoBrain graphAsset) { - this.node = node; - this.graph = graphAsset; - this.title = " A " + node.name; - //position = node.position; - return this; - } - void OnValidate() { - if (node != null) { - node.name = title; - //node.position = position; -#if UNITY_EDITOR - if (graph != null) - UnityEditor.EditorUtility.SetDirty(graph); -#endif - } - } -} -//static class EdgeDragState { public static EdgeDragState active; public GraphNode fromNode; public bool fromIsOutput; } - -public static class OpenAssetHandler { - // Called when an asset is double-clicked or opened. - [OnOpenAsset] - public static bool OpenMyScriptableObject(int instanceID, int line) { - NanoBrain obj = EditorUtility.EntityIdToObject(instanceID) as NanoBrain; - if (obj != null) { - NanoBrainEditor.Open(obj); - return true; // handled - } - return false; // let Unity open normally - } -} -*/ \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs.meta b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs.meta deleted file mode 100644 index 99dedcd..0000000 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainEditor.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: c57f78e25f0e55b96a50fd5592b26317 \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs deleted file mode 100644 index 447fa70..0000000 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs +++ /dev/null @@ -1,645 +0,0 @@ -/* -using System.Collections.Generic; -using System.Linq; -using UnityEditor; - -using UnityEngine; -using UnityEngine.UIElements; - -[CustomEditor(typeof(NanoBrain))] -public class NanoBrainInspector : Editor { - protected static VisualElement mainContainer; - protected static VisualElement inspectorContainer; - - protected bool breakOnWake = false; - - #region Start - - public override VisualElement CreateInspectorGUI() { - NanoBrain brain = target as NanoBrain; - - serializedObject.Update(); - - VisualElement root = new(); - //root.style.flexDirection = FlexDirection.Row; // side-by-side layout - //root.style.flexGrow = 1; - //root.style.minHeight = 600; - root.style.paddingLeft = 0; - root.style.paddingRight = 0; - root.style.paddingTop = 0; - root.style.paddingBottom = 0; - - root.styleSheets.Add(Resources.Load("GraphStyles")); - - mainContainer = new() { - // name = "main", - style = { - // flexDirection = FlexDirection.Row, - // flexGrow = 1, - height = 450, - } - }; - GraphView graph = new(); - graph.style.flexGrow = 1; - - inspectorContainer = new VisualElement { - // name = "inspector" - }; - - mainContainer.Add(graph); - mainContainer.Add(inspectorContainer); - root.Add(mainContainer); - - // Run once for initial state (use resolved style width if available) - float initialWidth = root.layout.width > 0 ? root.layout.width : root.contentRect.width; - UpdateLayout(initialWidth); - - // React to size changes of root (or parent if appropriate) - root.RegisterCallback(evt => { - UpdateLayout(evt.newRect.width); - }); - - if (brain != null) - graph.SetGraph(null, brain, brain.output, inspectorContainer); - else - Debug.LogWarning(" No brain!"); - - serializedObject.ApplyModifiedProperties(); - return root; - } - - public class GraphView : VisualElement { - NanoBrain brain; - SerializedObject serializedBrain; - INucleus currentNucleus; - GameObject gameObject; - private List layers = new(); - private readonly Dictionary neuroidPositions = new(); - - Vector2 pan = Vector2.zero; - //float zoom = 1f; - bool draggingCanvas = false; - Vector2 lastMouse; - GraphNodeWrapper currentWrapper; - - public GraphView() { - name = "content"; - style.flexGrow = 1; - - IMGUIContainer imguiContainer = new(OnIMGUI); - imguiContainer.style.position = Position.Absolute; - imguiContainer.style.left = 0; imguiContainer.style.top = 0; - imguiContainer.style.right = 0; imguiContainer.style.bottom = 0; - imguiContainer.pickingMode = PickingMode.Position; - imguiContainer.focusable = true; - Add(imguiContainer); - - //RegisterCallback(OnWheel); - RegisterCallback(OnMouseDown); - RegisterCallback(OnMouseMove); - RegisterCallback(OnMouseUp); - } - - public void SetGraph(GameObject gameObject, NanoBrain brain, Nucleus nucleus, VisualElement inspectorContainer) { - this.gameObject = gameObject; - this.brain = brain; - if (Application.isPlaying == false) - this.serializedBrain = new SerializedObject(brain); - this.currentNucleus = nucleus; - Rebuild(inspectorContainer); - } - - void Rebuild(VisualElement inspectorContainer) { - BuildLayers(); - - if (this.currentNucleus == null) { - inspectorContainer.Clear(); - return; - } - - if (currentWrapper != null) - DestroyImmediate(currentWrapper); - currentWrapper = CreateInstance().Init(this.currentNucleus, brain); - DrawInspector(inspectorContainer); - } - - private void BuildLayers() { - // A temporary list to track what's been added to layers - this.layers = new(); - int layerIx = 0; - - INucleus selectedNucleus = this.currentNucleus; - if (selectedNucleus == null) - return; - NeuroidLayer currentLayer = new() { ix = layerIx }; - - if (selectedNucleus.receivers != null) { - foreach (INucleus receiver in selectedNucleus.receivers) { - INucleus outputNeuroid = receiver; - if (outputNeuroid != null) { - AddToLayer(currentLayer, outputNeuroid); - // Debug.Log($"layer {layerIx} nucleus {outputNeuroid.name}"); - } - } - } - if (currentLayer.neuroids.Count > 0) { - this.layers.Add(currentLayer); - layerIx++; - currentLayer = new() { ix = layerIx }; - } - - AddToLayer(currentLayer, selectedNucleus); - this.layers.Add(currentLayer); - // Debug.Log($"layer {layerIx} nucleus {selectedNucleus.name}"); - - layerIx++; - currentLayer = new() { ix = layerIx }; - - if (selectedNucleus.synapses != null) { - foreach (Synapse synapse in selectedNucleus.synapses) { - IReceptor input = synapse.nucleus; - AddToLayer(currentLayer, input); - // Debug.Log($"layer {layerIx} nucleus {input.name}"); - } - } - if (currentLayer.neuroids.Count > 0) { - this.layers.Add(currentLayer); - } - } - - private void AddToLayer(NeuroidLayer layer, IReceptor nucleus) { - if (nucleus == null) - return; - layer.neuroids.Add(nucleus); - //nucleus.layerIx = layer.ix; - // Store its position - Vector2Int neuroidPosition = new(layer.ix, layer.neuroids.Count - 1); - neuroidPositions[nucleus] = neuroidPosition; - - } - - void OnMouseDown(MouseDownEvent e) { - if (e.button == 2) { draggingCanvas = true; lastMouse = e.mousePosition; e.StopPropagation(); } - } - void OnMouseMove(MouseMoveEvent e) { - if (draggingCanvas) { - var delta = e.mousePosition - lastMouse; - pan += delta; - //content.style.left = pan.x; - //content.style.top = pan.y; - lastMouse = e.mousePosition; - } - } - void OnMouseUp(MouseUpEvent e) { if (e.button == 2) draggingCanvas = false; } - - void OnIMGUI() { - if (currentNucleus == null) - return; - - if (Application.isPlaying == false) - serializedBrain.Update(); - - Handles.BeginGUI(); - DrawGraph(); - Handles.EndGUI(); - - } - - private void DrawGraph() { - float size = 20; - Vector3 position = new(150, 210, 0); - - DrawReceivers(this.currentNucleus, position, size); - DrawSynapses(this.currentNucleus, position, size); - - // Draw selected Nucleus - Handles.color = Color.white; - Handles.DrawSolidDisc(position, Vector3.forward, size + 2); - DrawNucleus(this.currentNucleus, position, this.currentNucleus.outputValue.magnitude, 20); - } - - private void DrawReceivers(INucleus nucleus, Vector3 parentPos, float size) { - int nodeCount = nucleus.receivers.Count; - - // Determine the maximum value in this layer - // This is used to 'scale' the output value colors of the nuclei - float maxValue = 0; - foreach (INucleus receiver in nucleus.receivers) { - if (receiver is Neuroid neuroid) { - float value = neuroid.outputValue.magnitude; - if (value > maxValue) - maxValue = value; - } - } - - // Determine the spacing of the nuclei in the layer - float spacing = 400f / nodeCount; - float margin = 10 + spacing / 2; - - int row = 0; - foreach (INucleus receiver in nucleus.receivers) { - INucleus receiverNucleus = receiver; - if (receiverNucleus == null) - continue; - - Vector3 pos = new(50, margin + row * spacing, 0.0f); - Handles.color = Color.white; - Handles.DrawLine(parentPos, pos); - - DrawNucleus(receiverNucleus, pos, maxValue, size); - row++; - } - } - - private void DrawSynapses(INucleus nucleus, Vector3 parentPos, float size) { - int nodeCount = nucleus.synapses.Count; - - // Determine the maximum value in this layer - // This is used to 'scale' the output value colors of the nuclei - float maxValue = 0; - foreach (Synapse receiver in nucleus.synapses) { - if (receiver.nucleus is Neuroid neuroid) { - float value = neuroid.outputValue.magnitude; - if (value > maxValue) - maxValue = value; - } - } - - // Determine the spacing of the nuclei in the layer - float spacing = 400f / nodeCount; - float margin = 10 + spacing / 2; - - int row = 0; - List drawnArrays = new(); - foreach (Synapse synapse in nucleus.synapses) { - Vector3 pos = new(250, margin + row * spacing, 0.0f); - Handles.color = Color.white; - Handles.DrawLine(parentPos, pos); - // if (synapse.nucleus is Perceptoid perceptoid && perceptoid.array != null) { - // // if (drawnArrays.Contains(perceptoid.array)) - // // // We already drawn this array - // // continue; - - // drawnArrays.Add(perceptoid.array); - // DrawArray(perceptoid.array, pos, size); - // } - // else { - - DrawNucleus(synapse.nucleus, pos, maxValue, size); - row++; - // } - } - } - - private void DrawNucleus(IReceptor nucleus, Vector3 position, float maxValue, float size) { - if (nucleus.isSleeping) - Handles.color = Color.darkRed; - else { - if (Application.isPlaying) { - float brightness = nucleus.outputValue.magnitude / maxValue; - Handles.color = new Color(brightness, brightness, brightness, 1f); - } - else - Handles.color = Color.black; - } - Handles.DrawSolidDisc(position, Vector3.forward, size); - - Handles.color = Color.white; - // Position the label in front of the disc - Vector3 labelPosition = position + (Vector3.forward * 0.1f); - - GUIStyle style = new(EditorStyles.label) { - alignment = TextAnchor.MiddleCenter, - normal = { textColor = Color.white }, - fontStyle = FontStyle.Bold, - }; - if (nucleus is Perceptoid perceptoid) { - if (perceptoid.array == null || perceptoid.array.perceptei == null || perceptoid.array.perceptei.Length == 0) - perceptoid.array = new PercepteiArray(perceptoid); - - if (perceptoid.array.perceptei.Length > 1) { - Handles.Label(labelPosition, perceptoid.array.perceptei.Length.ToString(), style); - } - } - - style.alignment = TextAnchor.UpperCenter; - Vector3 labelPos = position - Vector3.down * (size + 0.2f); // below disc along up axis - Handles.Label(labelPos, nucleus.name, style); - - Rect neuronRect = new(position.x - size, position.y - size, size * 2, size * 2); - int id = GUIUtility.GetControlID(FocusType.Passive); - Event e = Event.current; - EventType et = e.GetTypeForControl(id); - if (e != null && neuronRect.Contains(e.mousePosition)) { - // Process Hover - HandleMouseHover(nucleus, neuronRect); - // Process click - if (e.type == EventType.MouseDown && e.button == 0) { - // Consume the event so the scene doesn't also handle it - e.Use(); - HandleClicked(nucleus); - } - } - } - - private void DrawArray(PercepteiArray array, Vector3 position, float size) { - Vector3 offset = new(size / 4, size / 4, 0); - Handles.color = Color.black; - Handles.DrawSolidDisc(position, Vector3.forward, size); - - GUIStyle style = new(EditorStyles.label) { - alignment = TextAnchor.UpperCenter, - normal = { textColor = Color.white }, - fontStyle = FontStyle.Bold - }; - Handles.Label(position, array.perceptei.Length.ToString(), style); - Vector3 labelPos = position - Vector3.down * (size + 0.2f); // below disc along up axis - Handles.Label(labelPos, array.name, style); - - // To do: add HandleClick (see above) to expand the array - } - - private void HandleMouseHover(IReceptor nucleus, Rect rect) { - GUIContent tooltip; - if (nucleus is Perceptoid perceptoid) { - if (perceptoid.receptor != null) { - tooltip = new( - $"{perceptoid.name}" + - // $"\nType {perceptoid.receptor.thingType}" + - $" Thing {perceptoid.thingId}" + - $"\nValue: {nucleus.outputValue}"); - } - else { - tooltip = new( - $"{perceptoid.name}" + - $"\nThing {perceptoid.thingId}" + - $"\nValue: {nucleus.outputValue}"); - } - } - else if (nucleus is INucleus n) { - tooltip = new( - $"{nucleus.name}" + - $"\nsynapse count {n.synapses.Count}" + - $"\nValue: {nucleus.outputValue}"); - } - else { - tooltip = new( - $"{nucleus.name}" + - $"\nValue: {nucleus.outputValue}"); - } - - Vector2 mousePosition = Event.current.mousePosition; - - // Display tooltip with some offset - Vector2 tooltipSize = GUI.skin.box.CalcSize(tooltip); - Rect tooltipRect = new Rect(mousePosition.x + 10, mousePosition.y + 10, tooltipSize.x, tooltipSize.y); - - GUI.Box(tooltipRect, tooltip); - } - - private void HandleClicked(IReceptor nucleus) { - if (nucleus is INucleus n) { - this.currentNucleus = n; - BuildLayers(); - } - } - - void DrawInspector(VisualElement inspectorContainer) { - if (inspectorContainer == null) - return; - - inspectorContainer.Clear(); - if (this.currentNucleus == null) - return; - - // create a SerializedObject wrapper so Unity inspector controls work (and Undo) - SerializedObject so = new(currentWrapper); - IMGUIContainer container = new(() => { - if (so.targetObject == null) - return; - so.Update(); - - if (this.currentNucleus == null) - return; - - this.currentNucleus.name = EditorGUILayout.TextField(this.currentNucleus.name); - if (this.currentNucleus is Perceptoid perceptoid) { - // perceptoid.receptor.thingType = EditorGUILayout.IntField("Thing Type", perceptoid.receptor.thingType); - - if (perceptoid.array == null || perceptoid.array.perceptei == null || perceptoid.array.perceptei.Length == 0) - perceptoid.array = new PercepteiArray(perceptoid); - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.IntField("Array size", perceptoid.array.perceptei.Length); - if (GUILayout.Button("Add")) - perceptoid.array.AddPerceptoid(); - if (GUILayout.Button("Del")) - perceptoid.array.RemovePerceptoid(); - EditorGUILayout.EndHorizontal(); - } - else if (this.currentNucleus is Neuroid neuroid) { - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.LabelField("Activation Curve", GUILayout.Width(150)); - if (neuroid.curveMax > 0) - EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, 0, 1, neuroid.curveMax)); - else - EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, neuroid.curveMax, 1, -neuroid.curveMax)); - neuroid.curvePreset = (Neuroid.CurvePresets)EditorGUILayout.EnumPopup(neuroid.curvePreset, GUILayout.Width(100)); - EditorGUILayout.EndHorizontal(); - } - - if (Application.isPlaying) - EditorGUILayout.FloatField("Output", this.currentNucleus.outputValue.magnitude); - else - EditorGUILayout.LabelField(" "); - - if (this.currentNucleus.synapses.Count > 0) { - Synapse[] synapses = this.currentNucleus.synapses.ToArray(); - foreach (Synapse synapse in synapses) { - if (synapse.nucleus != null) { - EditorGUILayout.Space(); - - EditorGUI.BeginDisabledGroup(synapse.nucleus.isSleeping); - if (Application.isPlaying) - EditorGUILayout.FloatField(synapse.nucleus.name, synapse.nucleus.outputValue.magnitude * synapse.weight); - else { - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.LabelField(synapse.nucleus.name); - // if (synapse.nucleus is Perceptoid perceptoid) { - // if (perceptoid.array == null || perceptoid.array.perceptei == null || perceptoid.array.perceptei.Length == 0) { - // perceptoid.array = new PercepteiArray(perceptoid); - // } - // EditorGUILayout.IntField(perceptoid.array.perceptei.Length); - // if (GUILayout.Button("Add")) - // perceptoid.array.AddPerceptoid(); - // } - if (GUILayout.Button("Disconnect")) - synapse.nucleus.RemoveReceiver(this.currentNucleus); - EditorGUILayout.EndHorizontal(); - } - - EditorGUI.indentLevel++; - synapse.weight = EditorGUILayout.FloatField("Weight", synapse.weight); - EditorGUI.indentLevel--; - EditorGUI.EndDisabledGroup(); - } - } - } - - EditorGUILayout.Space(); - - ConnectNucleus(this.currentNucleus); - if (GUILayout.Button("Add Input Neuron")) - AddInputNeuron(this.currentNucleus); - if (GUILayout.Button("Add Input Perceptoid")) - AddPerceptoid(this.currentNucleus); - if (GUILayout.Button("Add Input Cluster")) - AddCluster(this.currentNucleus); - - EditorGUILayout.Space(); - - if (GUILayout.Button("Delete this neuron")) - DeleteNeuron(this.currentNucleus); - - //DisconnectNucleus(this.currentNucleus); - - if (this.gameObject != null) { - Vector3 worldVector = this.gameObject.transform.TransformVector(this.currentNucleus.outputValue); - Debug.DrawRay(this.gameObject.transform.position, worldVector, Color.yellow); - } - }); - - inspectorContainer.Add(container); - } - - protected virtual void AddInputNeuron(INucleus nucleus) { - Neuroid newNeuroid = new(this.brain.cluster, "New neuron"); - newNeuroid.AddReceiver(nucleus); - this.currentNucleus = newNeuroid; - BuildLayers(); - } - - protected virtual void DeleteNeuron(INucleus nucleus) { - if (nucleus == null) - return; - if (nucleus.cluster != null) - this.currentNucleus = nucleus.cluster.output; - foreach (INucleus receiver in nucleus.receivers) { - if (receiver != null) { - this.currentNucleus = receiver; - break; - } - } - Nucleus.Delete(nucleus); - BuildLayers(); - } - - protected virtual void AddPerceptoid(INucleus nucleus) { - Perceptoid newPerceptoid = new(this.brain, 0, "New Perceptoid"); - newPerceptoid.AddReceiver(nucleus); - this.currentNucleus = newPerceptoid; - BuildLayers(); - } - - protected virtual void AddCluster(INucleus nucleus) { - BrainPickerWindow.ShowPicker(brain => OnClusterPicked(nucleus, brain), "Select Cluster"); - } - - private void OnClusterPicked(INucleus nucleus, NanoBrain brain) { - NanoBrain brainInstance = Instantiate(brain); - brainInstance.AddReceiver(nucleus); - } - - protected virtual void ConnectNucleus(INucleus nucleus) { - if (this.currentNucleus.cluster == null) - return; - - IEnumerable synapseNuclei = this.currentNucleus.synapses.Select(synapse => synapse.nucleus.name); - //IEnumerable perceptei = this.currentNucleus.brain.perceptei.Select(i => i.name).Except(synapseNuclei); - IEnumerable nuclei = this.currentNucleus.cluster.nuclei.Select(i => i.name).Except(synapseNuclei); - //string[] names = perceptei.Concat(nuclei).ToArray(); - string[] names = nuclei.ToArray(); - int selectedIndex = -1; - selectedIndex = EditorGUILayout.Popup("Connect to", selectedIndex, names); - if (selectedIndex >= 0) { - // if (selectedIndex < perceptei.Count()) { - // Nucleus n = this.currentNucleus.brain.perceptei[selectedIndex]; - // n.AddReceiver(this.currentNucleus); - // } - // else { - // Nucleus n = this.currentNucleus.brain.nuclei[selectedIndex - perceptei.Count()]; - // n.AddReceiver(this.currentNucleus); - // } - INucleus n = this.currentNucleus.cluster.nuclei[selectedIndex]; - n.AddReceiver(this.currentNucleus); - } - } - - protected virtual void DisconnectNucleus(Nucleus nucleus) { - if (this.currentNucleus.cluster == null) - return; - string[] names = this.currentNucleus.synapses.Select(synapse => synapse.nucleus.name).ToArray(); - int selectedIndex = -1; - selectedIndex = EditorGUILayout.Popup("Disconnect from", selectedIndex, names); - //if (selectedIndex >= 0 && selectedIndex < this.currentNucleus.brain.perceptei.Count) { - if (selectedIndex >= 0 && selectedIndex < this.currentNucleus.cluster.nuclei.Count) { - Synapse synapse = this.currentNucleus.synapses[selectedIndex]; - synapse.nucleus.RemoveReceiver(this.currentNucleus); - } - } - } - - #endregion Start - - #region Update - - private void UpdateLayout(float containerWidth) { - if (containerWidth > 600f) { - mainContainer.style.flexDirection = FlexDirection.Row; - inspectorContainer.style.width = 300; // fixed sidebar width - inspectorContainer.style.flexGrow = 0; - } - else { - mainContainer.style.flexDirection = FlexDirection.Column; - inspectorContainer.style.width = Length.Percent(100); // full width below - inspectorContainer.style.flexDirection = FlexDirection.Column; - inspectorContainer.style.flexGrow = 1; // can set 0 or keep as needed - } - } - - #endregion Update -} - -/* -public class NeuroidLayer { - public int ix = 0; - public List neuroids = new(); -} -*/ - -/* -public class GraphNodeWrapper : ScriptableObject { - // expose fields that map to GraphNode - //public string title; - public Vector2 position; - INucleus node; - NanoBrain graph; // needed to write back and mark dirty - - public GraphNodeWrapper Init(INucleus node, NanoBrain graphAsset) { - this.node = node; - this.graph = graphAsset; - //this.title = " A " + node.name; - //position = node.position; - return this; - } - void OnValidate() { - if (node != null) { - //node.name = title; - //node.position = position; -#if UNITY_EDITOR - if (graph != null) - UnityEditor.EditorUtility.SetDirty(graph); -#endif - } - } -} -*/ \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs.meta b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs.meta deleted file mode 100644 index e71178e..0000000 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainInspector.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: c96ad47c3d4498640b52630789e38573 \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/NanoBrain.cs b/Assets/NanoBrain/VisualEditor/NanoBrain.cs deleted file mode 100644 index d786da6..0000000 --- a/Assets/NanoBrain/VisualEditor/NanoBrain.cs +++ /dev/null @@ -1,102 +0,0 @@ -/* -using System; -using System.Collections.Generic; -using UnityEngine; - -[CreateAssetMenu(menuName = "Passer/NanoBrain")] -public class NanoBrain : ScriptableObject, ISerializationCallbackReceiver { - public List nuclei = new(); - public List perceptei = new(); - public List receptors = new(); - - - // This is probably always the first element in the nuclei list... - [System.NonSerialized] - public Nucleus output; - public int rootId; - - public NanoBrain() { - // this.cluster = new(); - // this.output = new Neuroid(this.cluster, "Root"); - } - - public Cluster cluster; - - public void AddReceiver(INucleus receiver) { - output.AddReceiver(receiver); - } - - public Neuroid AddNeuron(string name) { - Neuroid neuroid = new(this.cluster, name); - return neuroid; - } - - public void UpdateNuclei() { - foreach (Nucleus nucleus in nuclei) - nucleus.IncreaseAge(); - foreach (Perceptoid perception in perceptei) - perception.IncreaseAge(); - } - - public void OnBeforeSerialize() { - if (output != null) { - this.rootId = output.id; - } - } - public void OnAfterDeserialize() { - try { - foreach (Nucleus nucleus in this.nuclei.ToArray()) { - if (this.rootId == nucleus.id) - this.output = nucleus; - nucleus.Rebuild(this); - } - - foreach (Perceptoid perceptoid in this.perceptei.ToArray()) - perceptoid.Rebuild(this); - } - catch (System.Exception) { } - if (this.cluster != null) - this.cluster.GarbageCollection(); - } - - - public void GarbageCollection() { - HashSet visitedNuclei = new(); - MarkNuclei(visitedNuclei, this.output); - //Debug.Log($"Garbage collection found {visitedNuclei.Count} Nuclei"); - this.nuclei.RemoveAll(nucleus => visitedNuclei.Contains(nucleus) == false); - this.perceptei.RemoveAll(perceptoid => visitedNuclei.Contains(perceptoid) == false); - } - - public void MarkNuclei(HashSet visitedNuclei, INucleus nucleus) { - if (nucleus is null) - return; - - if (nucleus.brain == null) - nucleus.brain = this; - - visitedNuclei.Add(nucleus); - if (nucleus.synapses != null) { - HashSet visitedSynapses = new(); - foreach (Synapse synapse in nucleus.synapses) { - if (synapse != null && synapse.nucleus != null) { - visitedSynapses.Add(synapse); - MarkNuclei(visitedNuclei, synapse.nucleus); - } - } - nucleus.synapses.RemoveAll(synapse => visitedSynapses.Contains(synapse) == false); - } - if (nucleus.receivers != null) { - HashSet visitedReceivers = new(); - foreach (Receiver receiver in nucleus.receivers) { - if (receiver != null && receiver.nucleus != null) { - visitedReceivers.Add(receiver); - visitedNuclei.Add(receiver.nucleus); - } - } - nucleus.receivers.RemoveAll(receiver => visitedReceivers.Contains(receiver) == false); - } - } - -} -*/ \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/NanoBrain.cs.meta b/Assets/NanoBrain/VisualEditor/NanoBrain.cs.meta deleted file mode 100644 index 40e85f2..0000000 --- a/Assets/NanoBrain/VisualEditor/NanoBrain.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 36081359186edfec998d891a1feeb17b \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs b/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs deleted file mode 100644 index 56c9159..0000000 --- a/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs +++ /dev/null @@ -1,35 +0,0 @@ -using UnityEngine; - -public class NanoBrainComponent : MonoBehaviour { - public ClusterPrefab defaultBrain; - private ClusterPrefab brainInstance; - - public INucleus root => brainInstance.output; - public ClusterPrefab brain { - get { - if (brainInstance == null && defaultBrain != null) { - brainInstance = Instantiate(defaultBrain); - brainInstance.name = defaultBrain.name + " (Instance)"; - - SwarmControl sc = FindFirstObjectByType(); - if (sc != null) { - UpdateWeight(brainInstance, "Avoidance", sc.avoidanceForce); - UpdateWeight(brainInstance, "Cohesion", sc.cohesionForce); - UpdateWeight(brainInstance, "Separation", sc.separationForce); - UpdateWeight(brainInstance, "Alignment", sc.alignmentForce); - } - } - return brainInstance; - } - } - - public static void UpdateWeight(ClusterPrefab brain, string name, float weight) { - INucleus root = brain.output; - foreach (Synapse synapse in root.synapses) { - if (synapse.nucleus.name == name) { - synapse.weight = weight; - } - } - } - -} \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs.meta b/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs.meta deleted file mode 100644 index 1666c60..0000000 --- a/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 92f34a5e4027a1dc39efd8ce63cf6aba \ No newline at end of file diff --git a/Assets/NanoBrain/VisualEditor/Resources.meta b/Assets/NanoBrain/VisualEditor/Resources.meta deleted file mode 100644 index e9c19e4..0000000 --- a/Assets/NanoBrain/VisualEditor/Resources.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 7b61a93fc9332d2adae74fe4abe92d53 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/NanoBrain/VisualEditor/Resources/GraphStyles.uss b/Assets/NanoBrain/VisualEditor/Resources/GraphStyles.uss deleted file mode 100644 index 79bafe8..0000000 --- a/Assets/NanoBrain/VisualEditor/Resources/GraphStyles.uss +++ /dev/null @@ -1,12 +0,0 @@ -#content { - background-color: #2b2b2b; -} -#inspector { - border-left-width: 1px; - border-left-color: #000; - padding: 3px; -} -#title { - -unity-font-style: bold; - color: white; - } diff --git a/Assets/NanoBrain/VisualEditor/Resources/GraphStyles.uss.meta b/Assets/NanoBrain/VisualEditor/Resources/GraphStyles.uss.meta deleted file mode 100644 index 2546c45..0000000 --- a/Assets/NanoBrain/VisualEditor/Resources/GraphStyles.uss.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 28268b644fa8f3948851b25e41f5b03b -ScriptedImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 2 - userData: - assetBundleName: - assetBundleVariant: - script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} - disableValidation: 0 From 92c301b85010f4e689ac0470d85e3e282af11b2d Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 29 Jan 2026 09:11:09 +0100 Subject: [PATCH 088/179] Cleanup --- Assembly-CSharp-Editor.csproj | 6 ------ Assembly-CSharp.csproj | 38 ----------------------------------- Assets/NanoBrain.meta | 8 -------- 3 files changed, 52 deletions(-) delete mode 100644 Assets/NanoBrain.meta diff --git a/Assembly-CSharp-Editor.csproj b/Assembly-CSharp-Editor.csproj index 36cc367..5f0adfe 100644 --- a/Assembly-CSharp-Editor.csproj +++ b/Assembly-CSharp-Editor.csproj @@ -49,13 +49,7 @@ - - - - - - diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index cd3cc27..8232055 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -49,48 +49,10 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Assets/NanoBrain.meta b/Assets/NanoBrain.meta deleted file mode 100644 index f63dc81..0000000 --- a/Assets/NanoBrain.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 235b4d678b27ec7458f2b47a618b5355 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: From 5aedb30d3623f9c43982e6523a47e8652b8fcf36 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 29 Jan 2026 11:30:33 +0100 Subject: [PATCH 089/179] It runs without errors (not working functionaltiy yet) --- Cluster.cs | 16 ++++- ClusterPrefab.cs | 6 ++ Receptor.cs | 16 ++--- Velocity.asset | 62 +++---------------- Velocity.asset.meta | 2 +- VisualEditor/Editor/BrainPickerWindow.cs | 6 +- VisualEditor/Editor/ClusterInspector.cs | 2 +- .../Editor/NanoBrainComponent_Editor.cs | 2 +- VisualEditor/NanoBrainComponent.cs | 10 +-- 9 files changed, 46 insertions(+), 76 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index 44f68ed..255dc66 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -7,7 +7,8 @@ using static Unity.Mathematics.math; [System.Serializable] public class Cluster : INucleus { // The ScriptableObject asset from which the runtime object has been created - public readonly ClusterPrefab prefab; + [SerializeField] + public ClusterPrefab prefab; public ClusterPrefab cluster { get; set; } @@ -18,9 +19,18 @@ public class Cluster : INucleus { set => _name = value; } + public Cluster(ClusterPrefab prefab) { + this.prefab = UnityEngine.Object.Instantiate(prefab); + this.name = prefab.name; + this.cluster = null; + if (this.cluster != null) + this.cluster.nuclei.Add(this); + } + // Hmm, a cluster instance can never be part of a scriptable object...(Cluster) public Cluster(ClusterPrefab parent, ClusterPrefab prefab) { - this.prefab = prefab; + this.prefab = prefab.Clone(); //UnityEngine.Object.Instantiate(prefab); + this.name = prefab.name; this.cluster = parent; if (this.cluster != null) this.cluster.nuclei.Add(this); @@ -46,6 +56,8 @@ public class Cluster : INucleus { return clone; } + public INucleus output => prefab.output; + // Not sure if this belongs here... [SerializeReference] private NucleusArray _array; diff --git a/ClusterPrefab.cs b/ClusterPrefab.cs index db65b70..151cba5 100644 --- a/ClusterPrefab.cs +++ b/ClusterPrefab.cs @@ -33,6 +33,12 @@ public class ClusterPrefab : ScriptableObject { } } + public virtual ClusterPrefab Clone() { + ClusterPrefab clone = Instantiate(this); + return clone; + } + + // Call this function to ensure that there is at least one nucleus // This is an invariant and should be ensured before the nucleus is used // because output requires it. diff --git a/Receptor.cs b/Receptor.cs index 72ef7df..74053dd 100644 --- a/Receptor.cs +++ b/Receptor.cs @@ -5,7 +5,7 @@ using static Unity.Mathematics.math; public class Receptor : IReceptor { - private ClusterPrefab cluster; + private Cluster cluster; [SerializeField] protected string _name; @@ -14,25 +14,25 @@ public class Receptor : IReceptor { set => _name = value; } - public Receptor(ClusterPrefab cluster) { + public Receptor(Cluster cluster) { this.cluster = cluster; if (cluster != null) - cluster.nuclei.Add(this); + cluster.prefab.nuclei.Add(this); } - public Receptor(ClusterPrefab cluster, INucleus nucleus) { + public Receptor(Cluster cluster, INucleus nucleus) { this.cluster = cluster; if (cluster != null) - cluster.nuclei.Add(this); + cluster.prefab.nuclei.Add(this); this.AddReceiver(nucleus); } - public static Receptor CreateReceptor(ClusterPrefab cluster, string nucleusName) { + public static Receptor CreateReceptor(Cluster cluster, string nucleusName) { if (cluster == null) return null; Receptor receptor = new(cluster); - foreach (INucleus nucleus in cluster.inputs) { + foreach (INucleus nucleus in cluster.prefab.inputs) { if (nucleus != null && nucleus.name == nucleusName) { // Receptor receptor = new(cluster, nucleus); // return receptor; @@ -45,7 +45,7 @@ public class Receptor : IReceptor { return receptor; } - public virtual IReceptor CloneTo(ClusterPrefab parent) { + public virtual IReceptor CloneTo(Cluster parent) { Receptor clone = new(parent); foreach (INucleus receiver in this.receivers) { diff --git a/Velocity.asset b/Velocity.asset index 521ba9b..1528d43 100644 --- a/Velocity.asset +++ b/Velocity.asset @@ -11,26 +11,20 @@ MonoBehaviour: m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3} m_Name: Velocity - m_EditorClassIdentifier: Assembly-CSharp::Cluster + m_EditorClassIdentifier: Assembly-CSharp::ClusterPrefab nuclei: - - rid: 2243601403683012671 - - rid: 2243601403683012676 + - rid: 2243601420268863545 references: version: 2 RefIds: - - rid: -2 - type: {class: , ns: , asm: } - - rid: 2243601403683012671 + - rid: 2243601420268863545 type: {class: Neuron, ns: , asm: Assembly-CSharp} data: _name: Output - _synapses: - - nucleus: - rid: -2 - weight: 1 + _synapses: [] _receivers: [] _array: - rid: 2243601403683012672 + rid: 2243601420268863546 _curvePreset: 0 curve: serializedVersion: 2 @@ -58,51 +52,9 @@ MonoBehaviour: m_RotationOrder: 4 curveMax: 1 average: 0 - - rid: 2243601403683012672 + - rid: 2243601420268863546 type: {class: NucleusArray, ns: , asm: Assembly-CSharp} data: _nuclei: - - rid: 2243601403683012671 + - rid: 2243601420268863545 name: Output - - rid: 2243601403683012676 - type: {class: Neuron, ns: , asm: Assembly-CSharp} - data: - _name: Position - _synapses: [] - _receivers: - - rid: 2243601403683012671 - _array: - rid: 2243601403683012677 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 1 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1000 - value: 1000 - inSlope: 1 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - - rid: 2243601403683012677 - type: {class: NucleusArray, ns: , asm: Assembly-CSharp} - data: - _nuclei: - - rid: 2243601403683012676 - name: New neuron diff --git a/Velocity.asset.meta b/Velocity.asset.meta index 07ecb98..38684df 100644 --- a/Velocity.asset.meta +++ b/Velocity.asset.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: dd622ac7ed09e70ea8edac595047ac82 +guid: c61aecac62c26de4aaefb2612bcc9a5d NativeFormatImporter: externalObjects: {} mainObjectFileID: 11400000 diff --git a/VisualEditor/Editor/BrainPickerWindow.cs b/VisualEditor/Editor/BrainPickerWindow.cs index 3a536df..503bd10 100644 --- a/VisualEditor/Editor/BrainPickerWindow.cs +++ b/VisualEditor/Editor/BrainPickerWindow.cs @@ -3,14 +3,14 @@ using UnityEngine; using System; using System.Linq; -public class BrainPickerWindow : EditorWindow { +public class ClusterPickerWindow : EditorWindow { private Vector2 scroll; private ClusterPrefab[] items = new ClusterPrefab[0]; private Action onPicked; private string search = ""; public static void ShowPicker(Action onPicked, string title = "Select Cluster") { - var w = CreateInstance(); + var w = CreateInstance(); w.titleContent = new GUIContent(title); w.minSize = new Vector2(360, 320); w.onPicked = onPicked; @@ -21,7 +21,7 @@ public class BrainPickerWindow : EditorWindow { private void OnEnable() => RefreshList(); private void RefreshList() { - var guids = AssetDatabase.FindAssets("t:Cluster"); + var guids = AssetDatabase.FindAssets("t:ClusterPrefab"); items = guids .Select(g => AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(g))) .Where(b => b != null) diff --git a/VisualEditor/Editor/ClusterInspector.cs b/VisualEditor/Editor/ClusterInspector.cs index 94273dd..413b87f 100644 --- a/VisualEditor/Editor/ClusterInspector.cs +++ b/VisualEditor/Editor/ClusterInspector.cs @@ -617,7 +617,7 @@ public class ClusterInspector : Editor { } protected virtual void AddCluster(INucleus nucleus) { - BrainPickerWindow.ShowPicker(brain => OnClusterPicked(nucleus, brain), "Select Cluster"); + ClusterPickerWindow.ShowPicker(brain => OnClusterPicked(nucleus, brain), "Select Cluster"); } private void OnClusterPicked(INucleus nucleus, ClusterPrefab subCluster) { diff --git a/VisualEditor/Editor/NanoBrainComponent_Editor.cs b/VisualEditor/Editor/NanoBrainComponent_Editor.cs index 253993a..6e60376 100644 --- a/VisualEditor/Editor/NanoBrainComponent_Editor.cs +++ b/VisualEditor/Editor/NanoBrainComponent_Editor.cs @@ -23,7 +23,7 @@ public class NanoBrainComponent_Editor : Editor { public override VisualElement CreateInspectorGUI() { //NanoBrainComponent component = target as NanoBrainComponent; - ClusterPrefab brain = Application.isPlaying ? component.brain : component.defaultBrain; + ClusterPrefab brain = Application.isPlaying ? component.brain.prefab : component.defaultBrain; if (Application.isPlaying == false) serializedObject.Update(); diff --git a/VisualEditor/NanoBrainComponent.cs b/VisualEditor/NanoBrainComponent.cs index 56c9159..d5b39c9 100644 --- a/VisualEditor/NanoBrainComponent.cs +++ b/VisualEditor/NanoBrainComponent.cs @@ -2,13 +2,13 @@ using UnityEngine; public class NanoBrainComponent : MonoBehaviour { public ClusterPrefab defaultBrain; - private ClusterPrefab brainInstance; + private Cluster brainInstance; - public INucleus root => brainInstance.output; - public ClusterPrefab brain { + //public INucleus root => brainInstance.output; + public Cluster brain { get { if (brainInstance == null && defaultBrain != null) { - brainInstance = Instantiate(defaultBrain); + brainInstance = new Cluster(defaultBrain); //Instantiate(defaultBrain); brainInstance.name = defaultBrain.name + " (Instance)"; SwarmControl sc = FindFirstObjectByType(); @@ -23,7 +23,7 @@ public class NanoBrainComponent : MonoBehaviour { } } - public static void UpdateWeight(ClusterPrefab brain, string name, float weight) { + public static void UpdateWeight(Cluster brain, string name, float weight) { INucleus root = brain.output; foreach (Synapse synapse in root.synapses) { if (synapse.nucleus.name == name) { From d754457a147b63961ada73505495d9b7eccdd24d Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 29 Jan 2026 11:48:49 +0100 Subject: [PATCH 090/179] The subcluster is producing (wrong) results --- Cluster.cs | 14 ++++++++++++++ ClusterPrefab.cs | 7 +++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index 255dc66..7c77590 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -193,8 +193,22 @@ public class Cluster : INucleus { // This does not work because the prefab nucleus does not have a state this.prefab.inputs[0].UpdateState(sum); + //this._outputValue = this.output.outputValue; + UpdateResult(this.output.outputValue); } + public virtual void UpdateResult(Vector3 result) { + // float d = Vector3.Distance(result, this.outputValue); + // if (d < 0.5f) { + // //Debug.Log($"insignificant update: {d}"); + // return; + // } + + this.outputValue = result; + foreach (INucleus receiver in this.receivers) + receiver.UpdateState(); + } + public void UpdateNuclei() { this.stale++; if (this.stale > 2) diff --git a/ClusterPrefab.cs b/ClusterPrefab.cs index 151cba5..5786820 100644 --- a/ClusterPrefab.cs +++ b/ClusterPrefab.cs @@ -25,8 +25,11 @@ public class ClusterPrefab : ScriptableObject { if (this._inputs == null) { this._inputs = new(); foreach (IReceptor receptor in this.nuclei) { - if (receptor is INucleus nucleus) - this._inputs.Add(nucleus); + if (receptor is INucleus nucleus) { + // inputs have no incoming synapses yet. + if (nucleus.synapses.Count == 0) + this._inputs.Add(nucleus); + } } } return this._inputs; From b60fc19d96f6cc82b0dc5d995dc3ea61a790930c Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 29 Jan 2026 12:31:23 +0100 Subject: [PATCH 091/179] Simplyfying --- MemoryCell.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/MemoryCell.cs b/MemoryCell.cs index 6e20a75..fe81c1c 100644 --- a/MemoryCell.cs +++ b/MemoryCell.cs @@ -12,8 +12,8 @@ public class MemoryCell : Neuron { // Returns the memorized value weighted by time // return lastValue * (current time - last time) - [SerializeField] - public bool deltaValue = false; + // [SerializeField] + // public bool deltaValue = false; #endregion Parameters @@ -46,12 +46,12 @@ public class MemoryCell : Neuron { public override void UpdateResult(Vector3 result) { // output value is the previous value - if (this.deltaValue) { - float deltaTime = Time.time - this._memorizedTime; - this._outputValue = this._memorizedValue * deltaTime; - } - else - this._outputValue = this._memorizedValue; + // if (this.deltaValue) { + // float deltaTime = Time.time - this._memorizedTime; + // this._outputValue = this._memorizedValue * deltaTime; + // } + //else + this.outputValue = this._memorizedValue; // Store the result for the next time this._memorizedValue = result; From 5cb9e788a4f418b4d8c9e16139d2187e1a978b40 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 29 Jan 2026 17:41:55 +0100 Subject: [PATCH 092/179] Cluster no longer clones ClusterPrefab --- Cluster.cs | 214 +++++++++++------- ClusterPrefab.cs | 57 ++++- INucleus.cs | 4 +- Neuron.cs | 38 +++- Receptor.cs | 33 ++- Velocity.asset | 10 +- VisualEditor/Editor/ClusterInspector.cs | 15 +- .../Editor/NanoBrainComponent_Editor.cs | 6 +- VisualEditor/NanoBrainComponent.cs | 1 + 9 files changed, 262 insertions(+), 116 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index 7c77590..fc8f88f 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -7,38 +7,31 @@ using static Unity.Mathematics.math; [System.Serializable] public class Cluster : INucleus { // The ScriptableObject asset from which the runtime object has been created - [SerializeField] - public ClusterPrefab prefab; + public ClusterPrefab storedPrefab; + //public ClusterPrefab prefab; - public ClusterPrefab cluster { get; set; } - - [SerializeField] - protected string _name; - public virtual string name { - get => _name; - set => _name = value; + public Cluster() { + } + public Cluster(Cluster parent) { + this.parent = parent; } public Cluster(ClusterPrefab prefab) { - this.prefab = UnityEngine.Object.Instantiate(prefab); + this.storedPrefab = prefab; + //this.prefab = prefab.Clone(); this.name = prefab.name; this.cluster = null; if (this.cluster != null) - this.cluster.nuclei.Add(this); + this.cluster.nuclei.Add(this); } - // Hmm, a cluster instance can never be part of a scriptable object...(Cluster) - public Cluster(ClusterPrefab parent, ClusterPrefab prefab) { - this.prefab = prefab.Clone(); //UnityEngine.Object.Instantiate(prefab); - this.name = prefab.name; + public Cluster(ClusterPrefab parent, ClusterPrefab realPrefab) { + this.storedPrefab = realPrefab; + //this.prefab = realPrefab.Clone(); + this.name = realPrefab.name; this.cluster = parent; if (this.cluster != null) this.cluster.nuclei.Add(this); - - // foreach (IReceptor nucleus in this.prefab.nuclei) { - // IReceptor clone = nucleus.CloneTo(null); - // this.dynamicNuclei.Add(clone); - // } } public virtual IReceptor Clone() { @@ -56,7 +49,112 @@ public class Cluster : INucleus { return clone; } - public INucleus output => prefab.output; + // public IReceptor CloneTo(ClusterPrefab parent) { + // Cluster clone = new(parent, this.prefab); + // return clone; + // } + + public IReceptor ShallowCloneTo(Cluster parent) { + Cluster clone = new(parent); + return clone; + } + + // public IReceptor ShallowCloneTo(ClusterPrefab parent) { + // Cluster clone = new(parent, this.prefab); + // return clone; + // } + + // Deep clone a nucleus with its connections + public virtual Cluster InstantiatePrefab(ClusterPrefab prefab) { + Cluster clone = new Cluster { + nuclei = new() + }; + + IReceptor[] nucleiArray = this.nuclei.ToArray(); + // first clone the nuclei without their connections + foreach (IReceptor nucleus in this.nuclei) + nucleus.ShallowCloneTo(clone); + IReceptor[] clonedNuclei = clone.nuclei.ToArray(); + + // Now clone the connections + for (int nucleusIx = 0; nucleusIx < nucleiArray.Length; nucleusIx++) { + IReceptor receptor = nucleiArray[nucleusIx]; + IReceptor clonedReceptor = clonedNuclei[nucleusIx]; + if (clonedReceptor == null) + continue; + + // Copy the synapses + if (receptor is INucleus nucleus) { + foreach (Synapse synapse in nucleus.synapses) { + if (clonedReceptor is not INucleus clonedNucleus) + continue; + + int ix = GetNucleusIndex(nucleiArray, synapse.nucleus); + if (ix < 0) + continue; + IReceptor clonedSynapseNucleus = clonedNuclei[ix]; + if (clonedSynapseNucleus == null) + continue; + + clonedNucleus.AddSynapse(clonedSynapseNucleus, synapse.weight); + } + } + // Copy the receivers + foreach (INucleus receiver in nucleiArray[nucleusIx].receivers) { + int ix = GetNucleusIndex(nucleiArray, receiver); + if (ix < 0) + continue; + + if (clonedNuclei[ix] is not INucleus clonedReceiver) + continue; + + clonedReceptor.AddReceiver(clonedReceiver); + } + } + + return clone; + } + + private int GetNucleusIndex(IReceptor[] nucleiArray, IReceptor nucleus) { + for (int i = 0; i < nucleiArray.Length; i++) { + if (nucleus == nucleiArray[i]) + return i; + } + return -1; + } + + public ClusterPrefab cluster { get; set; } + public Cluster parent { get; set; } + + [SerializeReference] + public List nuclei = new(); + + [SerializeField] + protected string _name; + public virtual string name { + get => _name; + set => _name = value; + } + + public List _inputs = null; + public virtual List inputs { + get { + if (this._inputs == null) { + this._inputs = new(); + foreach (IReceptor receptor in this.nuclei) { + if (receptor is INucleus nucleus) { + // inputs have no incoming synapses yet. + if (nucleus.synapses.Count == 0) + this._inputs.Add(nucleus); + } + } + } + return this._inputs; + } + } + + //public INucleus output => prefab.output; + public virtual INucleus output => this.nuclei[0] as INucleus; // Not sure if this belongs here... [SerializeReference] @@ -68,27 +166,14 @@ public class Cluster : INucleus { #region Synapses - // class ClusterSynapse : Synapse { - // public IReceptor receptor; - // public ClusterSynapse(IReceptor nucleus, INucleus receptor, float weight = 1.0f) : base(nucleus, weight) { - // this.receptor = receptor; - // } - // } [SerializeField] private List _synapses = new(); public List synapses => _synapses; - public Synapse AddSynapse(IReceptor sendingNucleus) { - Synapse synapse = new(sendingNucleus); //, this.prefab.inputs[0]); + public Synapse AddSynapse(IReceptor sendingNucleus, float weight = 1.0f) { + Synapse synapse = new(sendingNucleus, weight); //, this.prefab.inputs[0]); this._synapses.Add(synapse); return synapse; - // else { - // INucleus receptor = (INucleus)this.prefab.nuclei.Find(nucleus => nucleus is INucleus n && nucleus.name == nucleusName); - // ClusterSynapse synapse = new(sendingNucleus, receptor); - // receptor.AddSynapse(sendingNucleus); - // } - // // Add synapse to which neuron? - // return null; } // Does this even exist already? @@ -117,48 +202,6 @@ public class Cluster : INucleus { receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); } - // public void AddReceiver(INucleus receivingNucleus) { - // int newLength = this._receivers.Count + 1; - // INucleus[] newReceivers = new INucleus[newLength]; - - // // Copy the existing receivers - // for (int ix = 0; ix < this._receivers.Count; ix++) - // newReceivers[ix] = this._receivers[ix]; - // // Add the new receivers - // newReceivers[this._receivers.Count] = receivingNucleus; - // // Replace the receivers with the new receivers - // this._receivers = new(newReceivers); - - // receivingNucleus.AddSynapse(this); - // } - - // public void RemoveReceiver(INucleus receivingNucleus) { - // Debug.Log("Clusterinstance. remote receiver"); - // int newLength = this._receivers.Count - 1; - // if (newLength < 0) - // // Array was empty, so we cannot remove anything - // return; - - // INucleus[] newReceivers = new INucleus[newLength]; - - // int newIx = 0; - // // Copy all receivers except receivingNucleus - // for (int ix = 0; ix < this._receivers.Count; ix++) { - // if (this._receivers[ix] == receivingNucleus) - // // skip the receiver we want to remote - // continue; - - // if (newIx >= newLength) - // // We want to copy more elements than expected - // // the receivingNucleus is not found - // // and the original array is returned - // return; - // newReceivers[newIx] = this._receivers[ix]; - // newIx++; - // } - // this._receivers = new(newReceivers); - // } - #endregion Receivers #region Runtime @@ -190,10 +233,10 @@ public class Cluster : INucleus { foreach (Synapse synapse in this.synapses) { sum += synapse.weight * synapse.nucleus.outputValue; } - - // This does not work because the prefab nucleus does not have a state - this.prefab.inputs[0].UpdateState(sum); - //this._outputValue = this.output.outputValue; + + //this.prefab.inputs[0].UpdateState(sum); + this.inputs[0].UpdateState(sum); + UpdateResult(this.output.outputValue); } @@ -208,13 +251,14 @@ public class Cluster : INucleus { foreach (INucleus receiver in this.receivers) receiver.UpdateState(); } - + public void UpdateNuclei() { this.stale++; - if (this.stale > 2) + if (this.stale > 2) _outputValue = Vector3.zero; - foreach (IReceptor nucleus in this.prefab.nuclei) + //foreach (IReceptor nucleus in this.prefab.nuclei) + foreach (IReceptor nucleus in this.nuclei) nucleus.UpdateNuclei(); } diff --git a/ClusterPrefab.cs b/ClusterPrefab.cs index 5786820..1beb6b2 100644 --- a/ClusterPrefab.cs +++ b/ClusterPrefab.cs @@ -36,12 +36,67 @@ public class ClusterPrefab : ScriptableObject { } } +/* + // Deep clone a nucleus with its connections public virtual ClusterPrefab Clone() { ClusterPrefab clone = Instantiate(this); + clone.nuclei = new(); + // foreach (IReceptor nucleus in this.nuclei) + // nucleus.CloneTo(clone); + + IReceptor[] nucleiArray = this.nuclei.ToArray(); + // first clone the nuclei without their connections + foreach (IReceptor nucleus in this.nuclei) + nucleus.ShallowCloneTo(clone); + IReceptor[] clonedNuclei = clone.nuclei.ToArray(); + + // Now clone the connections + for (int nucleusIx = 0; nucleusIx < nucleiArray.Length; nucleusIx++) { + IReceptor receptor = nucleiArray[nucleusIx]; + IReceptor clonedReceptor = clonedNuclei[nucleusIx]; + if (clonedReceptor == null) + continue; + + // Copy the synapses + if (receptor is INucleus nucleus) { + foreach (Synapse synapse in nucleus.synapses) { + if (clonedReceptor is not INucleus clonedNucleus) + continue; + + int ix = GetNucleusIndex(nucleiArray, synapse.nucleus); + if (ix < 0) + continue; + IReceptor clonedSynapseNucleus = clonedNuclei[ix]; + if (clonedSynapseNucleus == null) + continue; + + clonedNucleus.AddSynapse(clonedSynapseNucleus, synapse.weight); + } + } + // Copy the receivers + foreach (INucleus receiver in nucleiArray[nucleusIx].receivers) { + int ix = GetNucleusIndex(nucleiArray, receiver); + if (ix < 0) + continue; + + if (clonedNuclei[ix] is not INucleus clonedReceiver) + continue; + + clonedReceptor.AddReceiver(clonedReceiver); + } + } + return clone; } - + private int GetNucleusIndex(IReceptor[] nucleiArray, IReceptor nucleus) { + for (int i = 0; i < nucleiArray.Length; i++) { + if (nucleus == nucleiArray[i]) + return i; + } + return -1; + } +*/ // Call this function to ensure that there is at least one nucleus // This is an invariant and should be ensured before the nucleus is used // because output requires it. diff --git a/INucleus.cs b/INucleus.cs index f7272f3..cd4ba50 100644 --- a/INucleus.cs +++ b/INucleus.cs @@ -10,7 +10,7 @@ public interface INucleus : IReceptor { // Senders public List synapses { get; } - public Synapse AddSynapse(IReceptor sender); + public Synapse AddSynapse(IReceptor sender, float weight = 1.0f); public NucleusArray array { get; set; } @@ -48,6 +48,8 @@ public interface IReceptor { #endregion dynamic + //public IReceptor ShallowCloneTo(ClusterPrefab parent); + public IReceptor ShallowCloneTo(Cluster parent); //public IReceptor CloneTo(ClusterPrefab parent); public IReceptor Clone(); } diff --git a/Neuron.cs b/Neuron.cs index 099ceab..26443d0 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -88,6 +88,7 @@ public class Neuron : INucleus { #region Runtime state (not serialized) public ClusterPrefab cluster { get; set; } + public Cluster parent { get; set; } #region Activation @@ -159,12 +160,19 @@ public class Neuron : INucleus { this.stale++; // this._isSleeping = this.stale > 2; // if (isSleeping) - if (this.stale > 2) + if (this.stale > 2) _outputValue = Vector3.zero; } #endregion Runtime state + public Neuron(Cluster parent, string name) { + this.parent = parent; + this.name = name; + if (this.cluster != null) { + this.cluster.nuclei.Add(this); + } + } public Neuron(ClusterPrefab parent, string name) { this.cluster = parent; this.name = name; @@ -179,6 +187,28 @@ public class Neuron : INucleus { // this._name = name; // } + // this clone the nucleus without the synapses and receivers + public virtual IReceptor ShallowCloneTo(Cluster newParent) { + Neuron clone = new(newParent, this.name) { + array = this.array, + curve = this.curve, + curvePreset = this.curvePreset, + curveMax = this.curveMax, + average = this.average + }; + return clone; + } + public virtual IReceptor ShallowCloneTo(ClusterPrefab newParent) { + Neuron clone = new(newParent, this.name) { + array = this.array, + curve = this.curve, + curvePreset = this.curvePreset, + curveMax = this.curveMax, + average = this.average + }; + return clone; + } + public virtual IReceptor CloneTo(ClusterPrefab parent) { Neuron clone = new(parent, this.name) { array = this.array, @@ -187,8 +217,6 @@ public class Neuron : INucleus { curveMax = this.curveMax, average = this.average }; - // if (clone.cluster != null) - // clone.cluster.nuclei.Add(clone); foreach (Synapse synapse in this.synapses) { Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); @@ -254,8 +282,8 @@ public class Neuron : INucleus { } } - public Synapse AddSynapse(IReceptor sendingNucleus) { - Synapse synapse = new(sendingNucleus); + public Synapse AddSynapse(IReceptor sendingNucleus, float weight = 1.0f) { + Synapse synapse = new(sendingNucleus, weight); this.synapses.Add(synapse); return synapse; } diff --git a/Receptor.cs b/Receptor.cs index 74053dd..8d9c81e 100644 --- a/Receptor.cs +++ b/Receptor.cs @@ -1,11 +1,14 @@ +using System; using System.Collections.Generic; using UnityEngine; using Unity.Mathematics; using static Unity.Mathematics.math; +[Serializable] public class Receptor : IReceptor { - private Cluster cluster; + private ClusterPrefab cluster; + private Cluster parent; [SerializeField] protected string _name; @@ -14,16 +17,21 @@ public class Receptor : IReceptor { set => _name = value; } - public Receptor(Cluster cluster) { + public Receptor(Cluster parent) { + this.parent = parent; + if (parent != null) + parent.nuclei.Add(this); + } + public Receptor(ClusterPrefab cluster) { this.cluster = cluster; if (cluster != null) - cluster.prefab.nuclei.Add(this); + cluster.nuclei.Add(this); } - public Receptor(Cluster cluster, INucleus nucleus) { + public Receptor(ClusterPrefab cluster, INucleus nucleus) { this.cluster = cluster; if (cluster != null) - cluster.prefab.nuclei.Add(this); + cluster.nuclei.Add(this); this.AddReceiver(nucleus); } @@ -31,8 +39,10 @@ public class Receptor : IReceptor { if (cluster == null) return null; + //Receptor receptor = new(cluster.prefab); Receptor receptor = new(cluster); - foreach (INucleus nucleus in cluster.prefab.inputs) { + //foreach (INucleus nucleus in cluster.prefab.inputs) { + foreach (INucleus nucleus in cluster.inputs) { if (nucleus != null && nucleus.name == nucleusName) { // Receptor receptor = new(cluster, nucleus); // return receptor; @@ -45,7 +55,16 @@ public class Receptor : IReceptor { return receptor; } - public virtual IReceptor CloneTo(Cluster parent) { + public virtual IReceptor ShallowCloneTo(Cluster parent) { + Receptor clone = new(parent); + return clone; + } + public virtual IReceptor ShallowCloneTo(ClusterPrefab parent) { + Receptor clone = new(parent); + return clone; + } + + public virtual IReceptor CloneTo(ClusterPrefab parent) { Receptor clone = new(parent); foreach (INucleus receiver in this.receivers) { diff --git a/Velocity.asset b/Velocity.asset index 1528d43..aad36ea 100644 --- a/Velocity.asset +++ b/Velocity.asset @@ -13,18 +13,18 @@ MonoBehaviour: m_Name: Velocity m_EditorClassIdentifier: Assembly-CSharp::ClusterPrefab nuclei: - - rid: 2243601420268863545 + - rid: 2243601425629446539 references: version: 2 RefIds: - - rid: 2243601420268863545 + - rid: 2243601425629446539 type: {class: Neuron, ns: , asm: Assembly-CSharp} data: _name: Output _synapses: [] _receivers: [] _array: - rid: 2243601420268863546 + rid: 2243601425629446540 _curvePreset: 0 curve: serializedVersion: 2 @@ -52,9 +52,9 @@ MonoBehaviour: m_RotationOrder: 4 curveMax: 1 average: 0 - - rid: 2243601420268863546 + - rid: 2243601425629446540 type: {class: NucleusArray, ns: , asm: Assembly-CSharp} data: _nuclei: - - rid: 2243601420268863545 + - rid: 2243601425629446539 name: Output diff --git a/VisualEditor/Editor/ClusterInspector.cs b/VisualEditor/Editor/ClusterInspector.cs index 413b87f..6e2022a 100644 --- a/VisualEditor/Editor/ClusterInspector.cs +++ b/VisualEditor/Editor/ClusterInspector.cs @@ -620,19 +620,16 @@ public class ClusterInspector : Editor { ClusterPickerWindow.ShowPicker(brain => OnClusterPicked(nucleus, brain), "Select Cluster"); } - private void OnClusterPicked(INucleus nucleus, ClusterPrefab subCluster) { - Cluster subclusterInstance = new(this.cluster, subCluster); - //this.cluster.AddSubCluster(subclusterInstance); - //this.cluster.nuclei.Add(subclusterInstance); + private void OnClusterPicked(INucleus nucleus, ClusterPrefab prefab) { + Cluster subclusterInstance = new(this.cluster, prefab); subclusterInstance.AddReceiver(nucleus); } private void EditCluster(Cluster subCluster) { - //var currentActiveObject = Selection.activeObject; - Selection.activeObject = subCluster.prefab; - EditorGUIUtility.PingObject(subCluster.prefab); - var editor = Editor.CreateEditor(subCluster.prefab); - //Selection.activeObject = currentActiveObject; + // May be used with storedPrefab... + Selection.activeObject = subCluster.storedPrefab; + EditorGUIUtility.PingObject(subCluster.storedPrefab); + var editor = Editor.CreateEditor(subCluster.storedPrefab); } // Connect to another nucleus in the same cluster diff --git a/VisualEditor/Editor/NanoBrainComponent_Editor.cs b/VisualEditor/Editor/NanoBrainComponent_Editor.cs index 6e60376..8b15fe6 100644 --- a/VisualEditor/Editor/NanoBrainComponent_Editor.cs +++ b/VisualEditor/Editor/NanoBrainComponent_Editor.cs @@ -22,8 +22,8 @@ public class NanoBrainComponent_Editor : Editor { } public override VisualElement CreateInspectorGUI() { - //NanoBrainComponent component = target as NanoBrainComponent; - ClusterPrefab brain = Application.isPlaying ? component.brain.prefab : component.defaultBrain; + //ClusterPrefab brain = Application.isPlaying ? component.brain.prefab : component.defaultBrain; + Cluster brain = component.brain; if (Application.isPlaying == false) serializedObject.Update(); @@ -79,7 +79,7 @@ public class NanoBrainComponent_Editor : Editor { }); if (brain != null && board != null) - board.SetGraph(component.gameObject, brain, brain.output, inspectorContainer); + board.SetGraph(component.gameObject, brain.storedPrefab, brain.output, inspectorContainer); // else // Debug.LogWarning(" No brain!"); diff --git a/VisualEditor/NanoBrainComponent.cs b/VisualEditor/NanoBrainComponent.cs index d5b39c9..5ed427f 100644 --- a/VisualEditor/NanoBrainComponent.cs +++ b/VisualEditor/NanoBrainComponent.cs @@ -1,6 +1,7 @@ using UnityEngine; public class NanoBrainComponent : MonoBehaviour { + [SerializeField] public ClusterPrefab defaultBrain; private Cluster brainInstance; From 728ef1767cd9d9f92d701afb66ee2fcf96c1e19f Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Fri, 30 Jan 2026 10:10:37 +0100 Subject: [PATCH 093/179] Each boid now has its own brain (but output is still not correct) --- Cluster.cs | 207 +++++++++++++++++------- Neuron.cs | 4 +- Receptor.cs | 5 +- VisualEditor/Editor/ClusterInspector.cs | 3 + VisualEditor/NanoBrainComponent.cs | 6 +- 5 files changed, 161 insertions(+), 64 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index fc8f88f..6bc11aa 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -7,22 +7,61 @@ using static Unity.Mathematics.math; [System.Serializable] public class Cluster : INucleus { // The ScriptableObject asset from which the runtime object has been created + + [SerializeField] + protected string _name; + public virtual string name { + get => _name; + set => _name = value; + } + public ClusterPrefab storedPrefab; //public ClusterPrefab prefab; - public Cluster() { - } - public Cluster(Cluster parent) { + // public Cluster() { + // } + public Cluster(Cluster parent, ClusterPrefab realPrefab) { + this.storedPrefab = realPrefab; this.parent = parent; + this.parent?.nuclei.Add(this); + + ClonePrefab(); } - public Cluster(ClusterPrefab prefab) { - this.storedPrefab = prefab; + public Cluster(ClusterPrefab realPrefab) { + this.storedPrefab = realPrefab; //this.prefab = prefab.Clone(); - this.name = prefab.name; + this.name = realPrefab.name; this.cluster = null; if (this.cluster != null) this.cluster.nuclei.Add(this); + + ClonePrefab(); + // IReceptor[] nucleiArray = this.storedPrefab.nuclei.ToArray(); + // // first clone the nuclei without their connections + // foreach (IReceptor nucleus in this.storedPrefab.nuclei) + // nucleus.ShallowCloneTo(this); + // IReceptor[] clonedNuclei = this.nuclei.ToArray(); + + // // Now clone the connections + // for (int nucleusIx = 0; nucleusIx < nucleiArray.Length; nucleusIx++) { + // //IReceptor receptor = nucleiArray[nucleusIx]; + // IReceptor clonedReceptor = clonedNuclei[nucleusIx]; + // if (clonedReceptor == null) + // continue; + + // // Copy the receivers, which will also create the synapses + // foreach (INucleus receiver in nucleiArray[nucleusIx].receivers) { + // int ix = GetNucleusIndex(nucleiArray, receiver); + // if (ix < 0) + // continue; + + // if (clonedNuclei[ix] is not INucleus clonedReceiver) + // continue; + + // clonedReceptor.AddReceiver(clonedReceiver); + // } + // } } public Cluster(ClusterPrefab parent, ClusterPrefab realPrefab) { @@ -32,6 +71,61 @@ public class Cluster : INucleus { this.cluster = parent; if (this.cluster != null) this.cluster.nuclei.Add(this); + + ClonePrefab(); + // IReceptor[] nucleiArray = this.storedPrefab.nuclei.ToArray(); + // // first clone the nuclei without their connections + // foreach (IReceptor nucleus in this.storedPrefab.nuclei) + // nucleus.ShallowCloneTo(this); + // IReceptor[] clonedNuclei = this.nuclei.ToArray(); + + // // Now clone the connections + // for (int nucleusIx = 0; nucleusIx < nucleiArray.Length; nucleusIx++) { + // IReceptor receptor = nucleiArray[nucleusIx]; + // IReceptor clonedReceptor = clonedNuclei[nucleusIx]; + // if (clonedReceptor == null) + // continue; + + // // Copy the receivers, which will also create the synapses + // foreach (INucleus receiver in nucleiArray[nucleusIx].receivers) { + // int ix = GetNucleusIndex(nucleiArray, receiver); + // if (ix < 0) + // continue; + + // if (clonedNuclei[ix] is not INucleus clonedReceiver) + // continue; + + // clonedReceptor.AddReceiver(clonedReceiver); + // } + // } + } + + private void ClonePrefab() { + IReceptor[] nucleiArray = this.storedPrefab.nuclei.ToArray(); + // first clone the nuclei without their connections + foreach (IReceptor nucleus in this.storedPrefab.nuclei) + nucleus.ShallowCloneTo(this); + IReceptor[] clonedNuclei = this.nuclei.ToArray(); + + // Now clone the connections + for (int nucleusIx = 0; nucleusIx < nucleiArray.Length; nucleusIx++) { + IReceptor receptor = nucleiArray[nucleusIx]; + IReceptor clonedReceptor = clonedNuclei[nucleusIx]; + if (clonedReceptor == null) + continue; + + // Copy the receivers, which will also create the synapses + foreach (INucleus receiver in nucleiArray[nucleusIx].receivers) { + int ix = GetNucleusIndex(nucleiArray, receiver); + if (ix < 0) + continue; + + if (clonedNuclei[ix] is not INucleus clonedReceiver) + continue; + + clonedReceptor.AddReceiver(clonedReceiver); + } + } } public virtual IReceptor Clone() { @@ -55,7 +149,9 @@ public class Cluster : INucleus { // } public IReceptor ShallowCloneTo(Cluster parent) { - Cluster clone = new(parent); + Cluster clone = new(parent, this.storedPrefab) { + name = this.name, + }; return clone; } @@ -65,55 +161,55 @@ public class Cluster : INucleus { // } // Deep clone a nucleus with its connections - public virtual Cluster InstantiatePrefab(ClusterPrefab prefab) { - Cluster clone = new Cluster { - nuclei = new() - }; + // public virtual Cluster InstantiatePrefab(ClusterPrefab prefab) { + // Cluster clone = new Cluster { + // nuclei = new() + // }; - IReceptor[] nucleiArray = this.nuclei.ToArray(); - // first clone the nuclei without their connections - foreach (IReceptor nucleus in this.nuclei) - nucleus.ShallowCloneTo(clone); - IReceptor[] clonedNuclei = clone.nuclei.ToArray(); + // IReceptor[] nucleiArray = this.nuclei.ToArray(); + // // first clone the nuclei without their connections + // foreach (IReceptor nucleus in this.nuclei) + // nucleus.ShallowCloneTo(clone); + // IReceptor[] clonedNuclei = clone.nuclei.ToArray(); - // Now clone the connections - for (int nucleusIx = 0; nucleusIx < nucleiArray.Length; nucleusIx++) { - IReceptor receptor = nucleiArray[nucleusIx]; - IReceptor clonedReceptor = clonedNuclei[nucleusIx]; - if (clonedReceptor == null) - continue; + // // Now clone the connections + // for (int nucleusIx = 0; nucleusIx < nucleiArray.Length; nucleusIx++) { + // IReceptor receptor = nucleiArray[nucleusIx]; + // IReceptor clonedReceptor = clonedNuclei[nucleusIx]; + // if (clonedReceptor == null) + // continue; - // Copy the synapses - if (receptor is INucleus nucleus) { - foreach (Synapse synapse in nucleus.synapses) { - if (clonedReceptor is not INucleus clonedNucleus) - continue; + // // Copy the synapses + // if (receptor is INucleus nucleus) { + // foreach (Synapse synapse in nucleus.synapses) { + // if (clonedReceptor is not INucleus clonedNucleus) + // continue; - int ix = GetNucleusIndex(nucleiArray, synapse.nucleus); - if (ix < 0) - continue; - IReceptor clonedSynapseNucleus = clonedNuclei[ix]; - if (clonedSynapseNucleus == null) - continue; + // int ix = GetNucleusIndex(nucleiArray, synapse.nucleus); + // if (ix < 0) + // continue; + // IReceptor clonedSynapseNucleus = clonedNuclei[ix]; + // if (clonedSynapseNucleus == null) + // continue; - clonedNucleus.AddSynapse(clonedSynapseNucleus, synapse.weight); - } - } - // Copy the receivers - foreach (INucleus receiver in nucleiArray[nucleusIx].receivers) { - int ix = GetNucleusIndex(nucleiArray, receiver); - if (ix < 0) - continue; + // clonedNucleus.AddSynapse(clonedSynapseNucleus, synapse.weight); + // } + // } + // // Copy the receivers + // foreach (INucleus receiver in nucleiArray[nucleusIx].receivers) { + // int ix = GetNucleusIndex(nucleiArray, receiver); + // if (ix < 0) + // continue; - if (clonedNuclei[ix] is not INucleus clonedReceiver) - continue; + // if (clonedNuclei[ix] is not INucleus clonedReceiver) + // continue; - clonedReceptor.AddReceiver(clonedReceiver); - } - } + // clonedReceptor.AddReceiver(clonedReceiver); + // } + // } - return clone; - } + // return clone; + // } private int GetNucleusIndex(IReceptor[] nucleiArray, IReceptor nucleus) { for (int i = 0; i < nucleiArray.Length; i++) { @@ -129,13 +225,6 @@ public class Cluster : INucleus { [SerializeReference] public List nuclei = new(); - [SerializeField] - protected string _name; - public virtual string name { - get => _name; - set => _name = value; - } - public List _inputs = null; public virtual List inputs { get { @@ -154,7 +243,13 @@ public class Cluster : INucleus { } //public INucleus output => prefab.output; - public virtual INucleus output => this.nuclei[0] as INucleus; + public virtual INucleus output {//=> this.nuclei[0] as INucleus; + get { + if (this.nuclei.Count > 0) + return this.nuclei[0] as INucleus; + return null; + } + } // Not sure if this belongs here... [SerializeReference] diff --git a/Neuron.cs b/Neuron.cs index 26443d0..9c153ef 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -169,9 +169,7 @@ public class Neuron : INucleus { public Neuron(Cluster parent, string name) { this.parent = parent; this.name = name; - if (this.cluster != null) { - this.cluster.nuclei.Add(this); - } + this.parent?.nuclei.Add(this); } public Neuron(ClusterPrefab parent, string name) { this.cluster = parent; diff --git a/Receptor.cs b/Receptor.cs index 8d9c81e..0baec36 100644 --- a/Receptor.cs +++ b/Receptor.cs @@ -4,7 +4,6 @@ using UnityEngine; using Unity.Mathematics; using static Unity.Mathematics.math; -[Serializable] public class Receptor : IReceptor { private ClusterPrefab cluster; @@ -141,7 +140,9 @@ public class Receptor : IReceptor { public virtual void ProcessStimulus(int thingId, Vector3 newLocalPositionVector, string thingName = null) { this.localPosition = newLocalPositionVector; - + if (this._receivers == null) + return; + thingIds ??= new int[this._receivers.Count]; int receiverIx = 0; diff --git a/VisualEditor/Editor/ClusterInspector.cs b/VisualEditor/Editor/ClusterInspector.cs index 6e2022a..a8c2922 100644 --- a/VisualEditor/Editor/ClusterInspector.cs +++ b/VisualEditor/Editor/ClusterInspector.cs @@ -623,6 +623,9 @@ public class ClusterInspector : Editor { private void OnClusterPicked(INucleus nucleus, ClusterPrefab prefab) { Cluster subclusterInstance = new(this.cluster, prefab); subclusterInstance.AddReceiver(nucleus); + // This does not work somehow + // this.currentNucleus = subclusterInstance; + // BuildLayers(); } private void EditCluster(Cluster subCluster) { diff --git a/VisualEditor/NanoBrainComponent.cs b/VisualEditor/NanoBrainComponent.cs index 5ed427f..d32c4ce 100644 --- a/VisualEditor/NanoBrainComponent.cs +++ b/VisualEditor/NanoBrainComponent.cs @@ -1,11 +1,11 @@ +using System; using UnityEngine; public class NanoBrainComponent : MonoBehaviour { - [SerializeField] public ClusterPrefab defaultBrain; + + [NonSerialized] private Cluster brainInstance; - - //public INucleus root => brainInstance.output; public Cluster brain { get { if (brainInstance == null && defaultBrain != null) { From 8a414816e51ab5d5aed3c220cfb51e0a342ad2e9 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Fri, 30 Jan 2026 11:05:00 +0100 Subject: [PATCH 094/179] subcluster seems to work --- Cluster.cs | 21 +++++++++++++++------ INucleus.cs | 2 +- Neuron.cs | 10 ++++------ Receptor.cs | 6 +++--- 4 files changed, 23 insertions(+), 16 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index 6bc11aa..9d92c1c 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -110,12 +110,12 @@ public class Cluster : INucleus { // Now clone the connections for (int nucleusIx = 0; nucleusIx < nucleiArray.Length; nucleusIx++) { IReceptor receptor = nucleiArray[nucleusIx]; - IReceptor clonedReceptor = clonedNuclei[nucleusIx]; - if (clonedReceptor == null) + IReceptor clonedSender = clonedNuclei[nucleusIx]; + if (clonedSender == null) continue; // Copy the receivers, which will also create the synapses - foreach (INucleus receiver in nucleiArray[nucleusIx].receivers) { + foreach (INucleus receiver in receptor.receivers) { int ix = GetNucleusIndex(nucleiArray, receiver); if (ix < 0) continue; @@ -123,7 +123,16 @@ public class Cluster : INucleus { if (clonedNuclei[ix] is not INucleus clonedReceiver) continue; - clonedReceptor.AddReceiver(clonedReceiver); + // Find the synapse for the weight + float weight = 1; + foreach (Synapse synapse in receiver.synapses) { + if (synapse.nucleus == receptor) { + weight = synapse.weight; + break; + } + } + + clonedSender.AddReceiver(clonedReceiver, weight); } } } @@ -287,9 +296,9 @@ public class Cluster : INucleus { set { _receivers = value; } } - public virtual void AddReceiver(INucleus receivingNucleus) { + public virtual void AddReceiver(INucleus receivingNucleus, float weight = 1) { this._receivers.Add(receivingNucleus); - receivingNucleus.AddSynapse(this); + receivingNucleus.AddSynapse(this, weight); } public void RemoveReceiver(INucleus receiverNucleus) { diff --git a/INucleus.cs b/INucleus.cs index cd4ba50..13590a1 100644 --- a/INucleus.cs +++ b/INucleus.cs @@ -33,7 +33,7 @@ public interface IReceptor { // Receivers public List receivers { get; set; } - public void AddReceiver(INucleus receiver); + public void AddReceiver(INucleus receiver, float weight = 1); public void RemoveReceiver(INucleus receiverNucleus); #endregion static diff --git a/Neuron.cs b/Neuron.cs index 9c153ef..db67206 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -181,10 +181,6 @@ public class Neuron : INucleus { // Debug.LogError("No neuroid network"); } - // public Neuron(string name) { - // this._name = name; - // } - // this clone the nucleus without the synapses and receivers public virtual IReceptor ShallowCloneTo(Cluster newParent) { Neuron clone = new(newParent, this.name) { @@ -246,9 +242,9 @@ public class Neuron : INucleus { return clone; } - public virtual void AddReceiver(INucleus receivingNucleus) { + public virtual void AddReceiver(INucleus receivingNucleus, float weight = 1) { this._receivers.Add(receivingNucleus); - receivingNucleus.AddSynapse(this); + receivingNucleus.AddSynapse(this, weight); } public void RemoveReceiver(INucleus receiverNucleus) { @@ -294,6 +290,7 @@ public class Neuron : INucleus { float3 sum = inputValue;//new(0, 0, 0); int n = 0; + Debug.Log($"{this.parent.name}.{this.name}: {inputValue}"); //Applying the weight factgors foreach (Synapse synapse in this.synapses) { if (synapse.nucleus == this) { @@ -301,6 +298,7 @@ public class Neuron : INucleus { synapse.weight = deltaTime; } sum += synapse.weight * synapse.nucleus.outputValue; + Debug.Log($" {synapse.weight} * {synapse.nucleus.outputValue}"); // Perhaps synapses should be removed when the output value goes to 0.... if (lengthsq(synapse.nucleus.outputValue) != 0) n++; diff --git a/Receptor.cs b/Receptor.cs index 0baec36..d7321bc 100644 --- a/Receptor.cs +++ b/Receptor.cs @@ -102,9 +102,9 @@ public class Receptor : IReceptor { protected int[] thingIds; // every receiver can handle a thing with this id - public virtual void AddReceiver(INucleus receivingNucleus) { + public virtual void AddReceiver(INucleus receivingNucleus, float weight = 1) { this._receivers.Add(receivingNucleus); - receivingNucleus.AddSynapse(this); + receivingNucleus.AddSynapse(this, weight); } public void RemoveReceiver(INucleus receiverNucleus) { @@ -142,7 +142,7 @@ public class Receptor : IReceptor { this.localPosition = newLocalPositionVector; if (this._receivers == null) return; - + thingIds ??= new int[this._receivers.Count]; int receiverIx = 0; From 9ae3607911addc045be52b3ce7e25a2c59fb82d1 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Fri, 30 Jan 2026 11:33:52 +0100 Subject: [PATCH 095/179] Cleanup --- Cluster.cs | 181 +---------------------------------------------- ClusterPrefab.cs | 68 ------------------ INucleus.cs | 2 - Neuron.cs | 9 ++- Receptor.cs | 4 -- 5 files changed, 8 insertions(+), 256 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index 9d92c1c..d5cd988 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -4,7 +4,7 @@ using UnityEngine; using Unity.Mathematics; using static Unity.Mathematics.math; -[System.Serializable] +[Serializable] public class Cluster : INucleus { // The ScriptableObject asset from which the runtime object has been created @@ -16,10 +16,7 @@ public class Cluster : INucleus { } public ClusterPrefab storedPrefab; - //public ClusterPrefab prefab; - // public Cluster() { - // } public Cluster(Cluster parent, ClusterPrefab realPrefab) { this.storedPrefab = realPrefab; this.parent = parent; @@ -30,38 +27,12 @@ public class Cluster : INucleus { public Cluster(ClusterPrefab realPrefab) { this.storedPrefab = realPrefab; - //this.prefab = prefab.Clone(); this.name = realPrefab.name; this.cluster = null; if (this.cluster != null) this.cluster.nuclei.Add(this); ClonePrefab(); - // IReceptor[] nucleiArray = this.storedPrefab.nuclei.ToArray(); - // // first clone the nuclei without their connections - // foreach (IReceptor nucleus in this.storedPrefab.nuclei) - // nucleus.ShallowCloneTo(this); - // IReceptor[] clonedNuclei = this.nuclei.ToArray(); - - // // Now clone the connections - // for (int nucleusIx = 0; nucleusIx < nucleiArray.Length; nucleusIx++) { - // //IReceptor receptor = nucleiArray[nucleusIx]; - // IReceptor clonedReceptor = clonedNuclei[nucleusIx]; - // if (clonedReceptor == null) - // continue; - - // // Copy the receivers, which will also create the synapses - // foreach (INucleus receiver in nucleiArray[nucleusIx].receivers) { - // int ix = GetNucleusIndex(nucleiArray, receiver); - // if (ix < 0) - // continue; - - // if (clonedNuclei[ix] is not INucleus clonedReceiver) - // continue; - - // clonedReceptor.AddReceiver(clonedReceiver); - // } - // } } public Cluster(ClusterPrefab parent, ClusterPrefab realPrefab) { @@ -73,31 +44,6 @@ public class Cluster : INucleus { this.cluster.nuclei.Add(this); ClonePrefab(); - // IReceptor[] nucleiArray = this.storedPrefab.nuclei.ToArray(); - // // first clone the nuclei without their connections - // foreach (IReceptor nucleus in this.storedPrefab.nuclei) - // nucleus.ShallowCloneTo(this); - // IReceptor[] clonedNuclei = this.nuclei.ToArray(); - - // // Now clone the connections - // for (int nucleusIx = 0; nucleusIx < nucleiArray.Length; nucleusIx++) { - // IReceptor receptor = nucleiArray[nucleusIx]; - // IReceptor clonedReceptor = clonedNuclei[nucleusIx]; - // if (clonedReceptor == null) - // continue; - - // // Copy the receivers, which will also create the synapses - // foreach (INucleus receiver in nucleiArray[nucleusIx].receivers) { - // int ix = GetNucleusIndex(nucleiArray, receiver); - // if (ix < 0) - // continue; - - // if (clonedNuclei[ix] is not INucleus clonedReceiver) - // continue; - - // clonedReceptor.AddReceiver(clonedReceiver); - // } - // } } private void ClonePrefab() { @@ -152,11 +98,6 @@ public class Cluster : INucleus { return clone; } - // public IReceptor CloneTo(ClusterPrefab parent) { - // Cluster clone = new(parent, this.prefab); - // return clone; - // } - public IReceptor ShallowCloneTo(Cluster parent) { Cluster clone = new(parent, this.storedPrefab) { name = this.name, @@ -164,62 +105,6 @@ public class Cluster : INucleus { return clone; } - // public IReceptor ShallowCloneTo(ClusterPrefab parent) { - // Cluster clone = new(parent, this.prefab); - // return clone; - // } - - // Deep clone a nucleus with its connections - // public virtual Cluster InstantiatePrefab(ClusterPrefab prefab) { - // Cluster clone = new Cluster { - // nuclei = new() - // }; - - // IReceptor[] nucleiArray = this.nuclei.ToArray(); - // // first clone the nuclei without their connections - // foreach (IReceptor nucleus in this.nuclei) - // nucleus.ShallowCloneTo(clone); - // IReceptor[] clonedNuclei = clone.nuclei.ToArray(); - - // // Now clone the connections - // for (int nucleusIx = 0; nucleusIx < nucleiArray.Length; nucleusIx++) { - // IReceptor receptor = nucleiArray[nucleusIx]; - // IReceptor clonedReceptor = clonedNuclei[nucleusIx]; - // if (clonedReceptor == null) - // continue; - - // // Copy the synapses - // if (receptor is INucleus nucleus) { - // foreach (Synapse synapse in nucleus.synapses) { - // if (clonedReceptor is not INucleus clonedNucleus) - // continue; - - // int ix = GetNucleusIndex(nucleiArray, synapse.nucleus); - // if (ix < 0) - // continue; - // IReceptor clonedSynapseNucleus = clonedNuclei[ix]; - // if (clonedSynapseNucleus == null) - // continue; - - // clonedNucleus.AddSynapse(clonedSynapseNucleus, synapse.weight); - // } - // } - // // Copy the receivers - // foreach (INucleus receiver in nucleiArray[nucleusIx].receivers) { - // int ix = GetNucleusIndex(nucleiArray, receiver); - // if (ix < 0) - // continue; - - // if (clonedNuclei[ix] is not INucleus clonedReceiver) - // continue; - - // clonedReceptor.AddReceiver(clonedReceiver); - // } - // } - - // return clone; - // } - private int GetNucleusIndex(IReceptor[] nucleiArray, IReceptor nucleus) { for (int i = 0; i < nucleiArray.Length; i++) { if (nucleus == nucleiArray[i]) @@ -251,7 +136,6 @@ public class Cluster : INucleus { } } - //public INucleus output => prefab.output; public virtual INucleus output {//=> this.nuclei[0] as INucleus; get { if (this.nuclei.Count > 0) @@ -275,7 +159,7 @@ public class Cluster : INucleus { public List synapses => _synapses; public Synapse AddSynapse(IReceptor sendingNucleus, float weight = 1.0f) { - Synapse synapse = new(sendingNucleus, weight); //, this.prefab.inputs[0]); + Synapse synapse = new(sendingNucleus, weight); this._synapses.Add(synapse); return synapse; } @@ -369,65 +253,4 @@ public class Cluster : INucleus { #endregion Update #endregion Runtime - - /* - [SerializeField] - private List _dynamicNuclei; - public List dynamicNuclei {// = new(); - get { - if (_dynamicNuclei == null) { - this._dynamicNuclei = new(); - foreach (IReceptor nucleus in this.prefab.nuclei) { - IReceptor clone = nucleus.CloneTo(null); - this._dynamicNuclei.Add(clone); - } - } - return this._dynamicNuclei; - } - } - - public List _inputs = null; - public List inputs { - get { - this._inputs = new(); - if (this.dynamicNuclei != null) { - foreach (IReceptor receptor in this.dynamicNuclei) { - if (receptor is INucleus nucleus) - this._inputs.Add(nucleus); - } - } - return this._inputs; - } - } - - public INucleus output => this.dynamicNuclei[0] as INucleus; - - public float3 outputValue => this.output.outputValue; - - - public IReceptor CloneTo(ClusterPrefab parent) { - Cluster clone = new(parent, this.prefab); - return clone; - } - public IReceptor Clone() { - Cluster clone = new(this.cluster, this.prefab); - return clone; - } - - #region Properties - - public string name { - get { return prefab.name; } - set { prefab.name = value; } - } - - public bool isSleeping => lengthsq(this.outputValue) == 0; - - public NucleusArray array { get; set; } - - #endregion Properties - - - */ - } diff --git a/ClusterPrefab.cs b/ClusterPrefab.cs index 1beb6b2..f4fdd3f 100644 --- a/ClusterPrefab.cs +++ b/ClusterPrefab.cs @@ -4,18 +4,11 @@ using UnityEngine; [CreateAssetMenu(menuName = "Passer/Cluster")] public class ClusterPrefab : ScriptableObject { - //public virtual Cluster cluster {get;set;} - // The ScriptableObject asset from which the runtime object has been created - //public Cluster asset; [SerializeReference] public List nuclei = new(); - // public List subClusters = new(); - // public void AddSubCluster(ClusterInstance subCluster) { - // this.nuclei.Add(subCluster); - // } public virtual INucleus output => this.nuclei[0] as INucleus; @@ -36,67 +29,6 @@ public class ClusterPrefab : ScriptableObject { } } -/* - // Deep clone a nucleus with its connections - public virtual ClusterPrefab Clone() { - ClusterPrefab clone = Instantiate(this); - clone.nuclei = new(); - // foreach (IReceptor nucleus in this.nuclei) - // nucleus.CloneTo(clone); - - IReceptor[] nucleiArray = this.nuclei.ToArray(); - // first clone the nuclei without their connections - foreach (IReceptor nucleus in this.nuclei) - nucleus.ShallowCloneTo(clone); - IReceptor[] clonedNuclei = clone.nuclei.ToArray(); - - // Now clone the connections - for (int nucleusIx = 0; nucleusIx < nucleiArray.Length; nucleusIx++) { - IReceptor receptor = nucleiArray[nucleusIx]; - IReceptor clonedReceptor = clonedNuclei[nucleusIx]; - if (clonedReceptor == null) - continue; - - // Copy the synapses - if (receptor is INucleus nucleus) { - foreach (Synapse synapse in nucleus.synapses) { - if (clonedReceptor is not INucleus clonedNucleus) - continue; - - int ix = GetNucleusIndex(nucleiArray, synapse.nucleus); - if (ix < 0) - continue; - IReceptor clonedSynapseNucleus = clonedNuclei[ix]; - if (clonedSynapseNucleus == null) - continue; - - clonedNucleus.AddSynapse(clonedSynapseNucleus, synapse.weight); - } - } - // Copy the receivers - foreach (INucleus receiver in nucleiArray[nucleusIx].receivers) { - int ix = GetNucleusIndex(nucleiArray, receiver); - if (ix < 0) - continue; - - if (clonedNuclei[ix] is not INucleus clonedReceiver) - continue; - - clonedReceptor.AddReceiver(clonedReceiver); - } - } - - return clone; - } - - private int GetNucleusIndex(IReceptor[] nucleiArray, IReceptor nucleus) { - for (int i = 0; i < nucleiArray.Length; i++) { - if (nucleus == nucleiArray[i]) - return i; - } - return -1; - } -*/ // Call this function to ensure that there is at least one nucleus // This is an invariant and should be ensured before the nucleus is used // because output requires it. diff --git a/INucleus.cs b/INucleus.cs index 13590a1..0835c52 100644 --- a/INucleus.cs +++ b/INucleus.cs @@ -48,9 +48,7 @@ public interface IReceptor { #endregion dynamic - //public IReceptor ShallowCloneTo(ClusterPrefab parent); public IReceptor ShallowCloneTo(Cluster parent); - //public IReceptor CloneTo(ClusterPrefab parent); public IReceptor Clone(); } diff --git a/Neuron.cs b/Neuron.cs index db67206..d4444b6 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -287,10 +287,9 @@ public class Neuron : INucleus { } public virtual void UpdateState(float3 inputValue) { - float3 sum = inputValue;//new(0, 0, 0); + float3 sum = inputValue; int n = 0; - Debug.Log($"{this.parent.name}.{this.name}: {inputValue}"); //Applying the weight factgors foreach (Synapse synapse in this.synapses) { if (synapse.nucleus == this) { @@ -298,7 +297,7 @@ public class Neuron : INucleus { synapse.weight = deltaTime; } sum += synapse.weight * synapse.nucleus.outputValue; - Debug.Log($" {synapse.weight} * {synapse.nucleus.outputValue}"); + // Perhaps synapses should be removed when the output value goes to 0.... if (lengthsq(synapse.nucleus.outputValue) != 0) n++; @@ -337,6 +336,10 @@ public class Neuron : INucleus { // } this.outputValue = result; + if (lengthsq(outputValue) != 0) { + Debug.Log($"{this.parent.name}.{this.name}: {this.outputValue}"); + } + this.lastTime = Time.time; foreach (INucleus receiver in this.receivers) receiver.UpdateState(); diff --git a/Receptor.cs b/Receptor.cs index d7321bc..24bf9a7 100644 --- a/Receptor.cs +++ b/Receptor.cs @@ -38,13 +38,9 @@ public class Receptor : IReceptor { if (cluster == null) return null; - //Receptor receptor = new(cluster.prefab); Receptor receptor = new(cluster); - //foreach (INucleus nucleus in cluster.prefab.inputs) { foreach (INucleus nucleus in cluster.inputs) { if (nucleus != null && nucleus.name == nucleusName) { - // Receptor receptor = new(cluster, nucleus); - // return receptor; receptor.AddReceiver(nucleus); } } From b4f8e5a4d8afba777fbe78b4e6db0cd5698e56a9 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Fri, 30 Jan 2026 12:05:44 +0100 Subject: [PATCH 096/179] Add topological evaluation order --- Cluster.cs | 88 ++++++++++++++----- MemoryCell.cs | 4 - Neuron.cs | 6 -- VisualEditor/Editor/ClusterInspector.cs | 8 +- .../Editor/NanoBrainComponent_Editor.cs | 2 +- 5 files changed, 73 insertions(+), 35 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index d5cd988..e581690 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -15,41 +15,45 @@ public class Cluster : INucleus { set => _name = value; } - public ClusterPrefab storedPrefab; + #region Init + + public Cluster(ClusterPrefab prefab, Cluster parent) { + this.prefab = prefab; + this.name = prefab.name; - public Cluster(Cluster parent, ClusterPrefab realPrefab) { - this.storedPrefab = realPrefab; this.parent = parent; this.parent?.nuclei.Add(this); ClonePrefab(); + this.sortedNuclei = TopologicalSort(this.nuclei); } - public Cluster(ClusterPrefab realPrefab) { - this.storedPrefab = realPrefab; - this.name = realPrefab.name; - this.cluster = null; - if (this.cluster != null) - this.cluster.nuclei.Add(this); - - ClonePrefab(); - } - - public Cluster(ClusterPrefab parent, ClusterPrefab realPrefab) { - this.storedPrefab = realPrefab; - //this.prefab = realPrefab.Clone(); - this.name = realPrefab.name; + public Cluster(ClusterPrefab prefab, ClusterPrefab parent = null) { + this.prefab = prefab; + this.name = prefab.name; this.cluster = parent; + if (this.cluster != null) this.cluster.nuclei.Add(this); ClonePrefab(); + this.sortedNuclei = TopologicalSort(this.nuclei); } + // public Cluster(ClusterPrefab parent, ClusterPrefab realPrefab) { + // this.prefab = realPrefab; + // this.name = realPrefab.name; + // this.cluster = parent; + // if (this.cluster != null) + // this.cluster.nuclei.Add(this); + + // ClonePrefab(); + // } + private void ClonePrefab() { - IReceptor[] nucleiArray = this.storedPrefab.nuclei.ToArray(); + IReceptor[] nucleiArray = this.prefab.nuclei.ToArray(); // first clone the nuclei without their connections - foreach (IReceptor nucleus in this.storedPrefab.nuclei) + foreach (IReceptor nucleus in this.prefab.nuclei) nucleus.ShallowCloneTo(this); IReceptor[] clonedNuclei = this.nuclei.ToArray(); @@ -83,6 +87,43 @@ public class Cluster : INucleus { } } + // Sort the nuclei in a correct evaluation order + private List TopologicalSort(List nodes) { + Dictionary inDegree = new(); + foreach (IReceptor node in nodes) + inDegree[node] = 0; // Initialize in-degree to zero + + // Calculate in-degrees + foreach (IReceptor node in nodes) { + foreach (INucleus receiver in node.receivers) + inDegree[receiver]++; + } + + Queue queue = new(); + foreach (IReceptor node in nodes) { + if (inDegree[node] == 0) // Nodes with no dependencies + queue.Enqueue(node); + } + + List sortedOrder = new(); + while (queue.Count > 0) { + IReceptor current = queue.Dequeue(); + sortedOrder.Add(current); // Process the node + + foreach (INucleus receiver in current.receivers) { + inDegree[receiver]--; + if (inDegree[receiver] == 0) // If all dependencies resolved + queue.Enqueue(receiver); + } + } + + // Check for cycles in the graph + if (sortedOrder.Count != nodes.Count) + throw new InvalidOperationException("Graph is not a DAG; a cycle exists."); + + return sortedOrder; + } + public virtual IReceptor Clone() { Neuron clone = new(this.cluster, this.name) { array = this.array, @@ -99,7 +140,7 @@ public class Cluster : INucleus { } public IReceptor ShallowCloneTo(Cluster parent) { - Cluster clone = new(parent, this.storedPrefab) { + Cluster clone = new(this.prefab, parent) { name = this.name, }; return clone; @@ -113,11 +154,18 @@ public class Cluster : INucleus { return -1; } + #endregion Init + + public ClusterPrefab prefab; + public ClusterPrefab cluster { get; set; } public Cluster parent { get; set; } [SerializeReference] public List nuclei = new(); + // the nuclei sorted using topological sorting + // to ensure that the cluster is computer in the right order + public List sortedNuclei; public List _inputs = null; public virtual List inputs { diff --git a/MemoryCell.cs b/MemoryCell.cs index fe81c1c..1e35ace 100644 --- a/MemoryCell.cs +++ b/MemoryCell.cs @@ -29,10 +29,6 @@ public class MemoryCell : Neuron { //Applying the weight factgors foreach (Synapse synapse in this.synapses) { - if (synapse.nucleus == this) { - float deltaTime = Time.time - this.lastTime; - synapse.weight = deltaTime; - } result += synapse.weight * synapse.nucleus.outputValue; if (lengthsq(synapse.nucleus.outputValue) != 0) n++; diff --git a/Neuron.cs b/Neuron.cs index d4444b6..92cda57 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -154,7 +154,6 @@ public class Neuron : INucleus { // private bool _isSleeping = false; // public bool isSleeping => _isSleeping; public bool isSleeping => lengthsq(this.outputValue) == 0; - public float lastTime { get; private set; } public void UpdateNuclei() { this.stale++; @@ -292,10 +291,6 @@ public class Neuron : INucleus { //Applying the weight factgors foreach (Synapse synapse in this.synapses) { - if (synapse.nucleus == this) { - float deltaTime = Time.time - this.lastTime; - synapse.weight = deltaTime; - } sum += synapse.weight * synapse.nucleus.outputValue; // Perhaps synapses should be removed when the output value goes to 0.... @@ -340,7 +335,6 @@ public class Neuron : INucleus { Debug.Log($"{this.parent.name}.{this.name}: {this.outputValue}"); } - this.lastTime = Time.time; foreach (INucleus receiver in this.receivers) receiver.UpdateState(); diff --git a/VisualEditor/Editor/ClusterInspector.cs b/VisualEditor/Editor/ClusterInspector.cs index a8c2922..8e8d4df 100644 --- a/VisualEditor/Editor/ClusterInspector.cs +++ b/VisualEditor/Editor/ClusterInspector.cs @@ -621,7 +621,7 @@ public class ClusterInspector : Editor { } private void OnClusterPicked(INucleus nucleus, ClusterPrefab prefab) { - Cluster subclusterInstance = new(this.cluster, prefab); + Cluster subclusterInstance = new(prefab, this.cluster); subclusterInstance.AddReceiver(nucleus); // This does not work somehow // this.currentNucleus = subclusterInstance; @@ -630,9 +630,9 @@ public class ClusterInspector : Editor { private void EditCluster(Cluster subCluster) { // May be used with storedPrefab... - Selection.activeObject = subCluster.storedPrefab; - EditorGUIUtility.PingObject(subCluster.storedPrefab); - var editor = Editor.CreateEditor(subCluster.storedPrefab); + Selection.activeObject = subCluster.prefab; + EditorGUIUtility.PingObject(subCluster.prefab); + var editor = Editor.CreateEditor(subCluster.prefab); } // Connect to another nucleus in the same cluster diff --git a/VisualEditor/Editor/NanoBrainComponent_Editor.cs b/VisualEditor/Editor/NanoBrainComponent_Editor.cs index 8b15fe6..4d4b54b 100644 --- a/VisualEditor/Editor/NanoBrainComponent_Editor.cs +++ b/VisualEditor/Editor/NanoBrainComponent_Editor.cs @@ -79,7 +79,7 @@ public class NanoBrainComponent_Editor : Editor { }); if (brain != null && board != null) - board.SetGraph(component.gameObject, brain.storedPrefab, brain.output, inspectorContainer); + board.SetGraph(component.gameObject, brain.prefab, brain.output, inspectorContainer); // else // Debug.LogWarning(" No brain!"); From 91c4500b0a1288dc674dc4a89b675b344aa861e6 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Fri, 30 Jan 2026 12:46:29 +0100 Subject: [PATCH 097/179] Fixed the evaluation order --- Cluster.cs | 35 +++++++++++++++++++++++++----- INucleus.cs | 3 ++- MemoryCell.cs | 59 +++++++++++++++++++++++++++++++++++++++------------ Neuron.cs | 44 +++++++++++++++++++++++++++++++++++++- 4 files changed, 121 insertions(+), 20 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index e581690..130f0e2 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -262,20 +262,45 @@ public class Cluster : INucleus { UpdateState(new float3(0, 0, 0)); } - public void UpdateState(float3 inputValue) { - float3 sum = inputValue; // new(0, 0, 0); + public void UpdateState(float3 bias) { + float3 sum = bias; // new(0, 0, 0); - //Applying the weight factgors + //Applying the weight factors foreach (Synapse synapse in this.synapses) { sum += synapse.weight * synapse.nucleus.outputValue; } - //this.prefab.inputs[0].UpdateState(sum); - this.inputs[0].UpdateState(sum); + //this.inputs[0].UpdateState(sum); + this.inputs[0].UpdateStateIsolated(sum); + foreach (IReceptor receptor in this.sortedNuclei) { + if (receptor is INucleus nucleus && nucleus != this.inputs[0]) + nucleus.UpdateStateIsolated(); + } UpdateResult(this.output.outputValue); } + public void UpdateStateIsolated() { + float3 bias = new(0,0,0); + UpdateStateIsolated(bias); + } + public void UpdateStateIsolated(float3 bias) { + float3 sum = bias; // new(0, 0, 0); + + //Applying the weight factors + foreach (Synapse synapse in this.synapses) { + sum += synapse.weight * synapse.nucleus.outputValue; + } + + //this.inputs[0].UpdateState(sum); + this.inputs[0].UpdateStateIsolated(sum); + foreach (IReceptor receptor in this.sortedNuclei) { + if (receptor is INucleus nucleus && nucleus != this.inputs[0]) + nucleus.UpdateStateIsolated(); + } + this.outputValue = this.output.outputValue; + } + public virtual void UpdateResult(Vector3 result) { // float d = Vector3.Distance(result, this.outputValue); // if (d < 0.5f) { diff --git a/INucleus.cs b/INucleus.cs index 0835c52..324896d 100644 --- a/INucleus.cs +++ b/INucleus.cs @@ -20,7 +20,8 @@ public interface INucleus : IReceptor { public void UpdateState(); public void UpdateState(float3 inputValue); - + public void UpdateStateIsolated(); + public void UpdateStateIsolated(float3 inputValue); #endregion dynamic state } diff --git a/MemoryCell.cs b/MemoryCell.cs index 1e35ace..307ac77 100644 --- a/MemoryCell.cs +++ b/MemoryCell.cs @@ -4,27 +4,34 @@ using Unity.Mathematics; using static Unity.Mathematics.math; [Serializable] -public class MemoryCell : Neuron { +public class MemoryCell : Neuron, INucleus { - public MemoryCell(ClusterPrefab cluster, string name) : base(cluster, name) {} + public MemoryCell(ClusterPrefab cluster, string name) : base(cluster, name) { } + public MemoryCell(Cluster parent, string name) : base(parent, name) { } + // this.parent = parent; + // this.name = name; + // this.parent?.nuclei.Add(this); + // } - #region Parameters - - // Returns the memorized value weighted by time - // return lastValue * (current time - last time) - // [SerializeField] - // public bool deltaValue = false; - - #endregion Parameters + public override IReceptor ShallowCloneTo(Cluster newParent) { + MemoryCell clone = new(newParent, this.name) { + array = this.array, + curve = this.curve, + curvePreset = this.curvePreset, + curveMax = this.curveMax, + average = this.average + }; + return clone; + } #region State private float3 _memorizedValue; private float _memorizedTime; - public override void UpdateState() { + public override void UpdateState(float3 bias) { // A memorycell does not have an activation function - float3 result = new(0, 0, 0); + float3 result = bias; int n = 0; //Applying the weight factgors @@ -40,6 +47,32 @@ public class MemoryCell : Neuron { UpdateResult(result); } + public override void UpdateStateIsolated() { + float3 bias = new(0, 0, 0); + UpdateStateIsolated(bias); + } + public override void UpdateStateIsolated(float3 bias) { + // A memorycell does not have an activation function + float3 result = bias; + int n = 0; + + //Applying the weight factgors + foreach (Synapse synapse in this.synapses) { + result += synapse.weight * synapse.nucleus.outputValue; + if (lengthsq(synapse.nucleus.outputValue) != 0) + n++; + } + + if (this.average) + result /= n; + + this.outputValue = this._memorizedValue; + + // Store the result for the next time + this._memorizedValue = result; + this._memorizedTime = Time.time; + } + public override void UpdateResult(Vector3 result) { // output value is the previous value // if (this.deltaValue) { @@ -47,7 +80,7 @@ public class MemoryCell : Neuron { // this._outputValue = this._memorizedValue * deltaTime; // } //else - this.outputValue = this._memorizedValue; + this.outputValue = this._memorizedValue; // Store the result for the next time this._memorizedValue = result; diff --git a/Neuron.cs b/Neuron.cs index 92cda57..c622de8 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -282,7 +282,8 @@ public class Neuron : INucleus { } public virtual void UpdateState() { - UpdateState(new float3(0, 0, 0)); + //UpdateState(new float3(0, 0, 0)); + this.parent?.UpdateState(); } public virtual void UpdateState(float3 inputValue) { @@ -323,6 +324,47 @@ public class Neuron : INucleus { UpdateResult(result); } + public virtual void UpdateStateIsolated() { + UpdateStateIsolated(new float3(0, 0, 0)); + } + public virtual void UpdateStateIsolated(float3 bias) { + float3 sum = bias; + int n = 0; + + //Applying the weight factgors + foreach (Synapse synapse in this.synapses) { + sum += synapse.weight * synapse.nucleus.outputValue; + + // Perhaps synapses should be removed when the output value goes to 0.... + if (lengthsq(synapse.nucleus.outputValue) != 0) + n++; + } + if (this.average && n > 0) + sum /= n; + + // Activation function + Vector3 result; + switch (this.curvePreset) { + case CurvePresets.Linear: + result = sum; + break; + case CurvePresets.Sqrt: + result = normalize(sum) * System.MathF.Sqrt(length(sum)); + break; + case CurvePresets.Power: + result = normalize(sum) * System.MathF.Pow(length(sum), 2); + break; + case CurvePresets.Reciprocal: + result = normalize(sum) * (1 / length(sum)); + break; + default: + float activatedValue = this.curve.Evaluate(length(sum)); + result = normalize(sum) * activatedValue; + break; + } + this.outputValue = result; + } + public virtual void UpdateResult(Vector3 result) { // float d = Vector3.Distance(result, this.outputValue); // if (d < 0.5f) { From aab6f59934f901affad3162879dd20fc23cbcd5f Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Fri, 30 Jan 2026 15:49:45 +0100 Subject: [PATCH 098/179] Resetup swarming --- Neuron.cs | 11 +++++++---- VisualEditor/NanoBrainComponent.cs | 27 +++++++++++++++------------ 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/Neuron.cs b/Neuron.cs index c622de8..5af285a 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -343,7 +343,7 @@ public class Neuron : INucleus { sum /= n; // Activation function - Vector3 result; + float3 result = Vector3.zero; switch (this.curvePreset) { case CurvePresets.Linear: result = sum; @@ -354,9 +354,12 @@ public class Neuron : INucleus { case CurvePresets.Power: result = normalize(sum) * System.MathF.Pow(length(sum), 2); break; - case CurvePresets.Reciprocal: - result = normalize(sum) * (1 / length(sum)); - break; + case CurvePresets.Reciprocal: { + float magnitude = length(sum); + if (magnitude > 0) + result = normalize(sum) * (1 / magnitude); + break; + } default: float activatedValue = this.curve.Evaluate(length(sum)); result = normalize(sum) * activatedValue; diff --git a/VisualEditor/NanoBrainComponent.cs b/VisualEditor/NanoBrainComponent.cs index d32c4ce..59314c2 100644 --- a/VisualEditor/NanoBrainComponent.cs +++ b/VisualEditor/NanoBrainComponent.cs @@ -3,22 +3,22 @@ using UnityEngine; public class NanoBrainComponent : MonoBehaviour { public ClusterPrefab defaultBrain; - + [NonSerialized] private Cluster brainInstance; public Cluster brain { get { if (brainInstance == null && defaultBrain != null) { - brainInstance = new Cluster(defaultBrain); //Instantiate(defaultBrain); - brainInstance.name = defaultBrain.name + " (Instance)"; - - SwarmControl sc = FindFirstObjectByType(); - if (sc != null) { - UpdateWeight(brainInstance, "Avoidance", sc.avoidanceForce); - UpdateWeight(brainInstance, "Cohesion", sc.cohesionForce); - UpdateWeight(brainInstance, "Separation", sc.separationForce); - UpdateWeight(brainInstance, "Alignment", sc.alignmentForce); - } + brainInstance = new Cluster(defaultBrain) { + name = defaultBrain.name + " (Instance)" + }; + } + SwarmControl sc = FindFirstObjectByType(); + if (sc != null) { + UpdateWeight(brainInstance, "Containment", sc.containmentForce); + UpdateWeight(brainInstance, "Cohesion", sc.cohesionForce); + UpdateWeight(brainInstance, "Separation", sc.separationForce); + UpdateWeight(brainInstance, "Alignment", sc.alignmentForce); } return brainInstance; } @@ -28,7 +28,10 @@ public class NanoBrainComponent : MonoBehaviour { INucleus root = brain.output; foreach (Synapse synapse in root.synapses) { if (synapse.nucleus.name == name) { - synapse.weight = weight; + if (synapse.weight != weight) { + synapse.weight = weight; + // Debug.Log($"Updated weight for {name}"); + } } } } From 811ddd1761d9193f3667ade652b8c545d316c9f2 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 4 Feb 2026 09:44:34 +0100 Subject: [PATCH 099/179] Add selector neuron --- Neuron.cs | 30 +- .../{TestScene.unity => TestScene Boid.unity} | 0 Scene/TestScene Boid.unity.meta | 7 + Scene/TestScene Experiment.unity | 365 ++++++++++ ...y.meta => TestScene Experiment.unity.meta} | 0 Scripts.meta | 8 + Scripts/Experimental.meta | 8 + Scripts/Experimental/SelectorBrain.cs | 23 + Scripts/Experimental/SelectorBrain.cs.meta | 2 + Selector.asset | 138 ++++ Selector.asset.meta | 8 + Selector.cs | 49 ++ Selector.cs.meta | 2 + VisualEditor/Editor/NanoBrainEditor.cs | 511 -------------- VisualEditor/Editor/NanoBrainEditor.cs.meta | 2 - VisualEditor/Editor/NanoBrainInspector.cs | 645 ------------------ .../Editor/NanoBrainInspector.cs.meta | 2 - ...omponent_Editor.cs => NanoBrain_Editor.cs} | 8 +- ...ditor.cs.meta => NanoBrain_Editor.cs.meta} | 0 VisualEditor/NanoBrain.cs | 118 +--- VisualEditor/NanoBrain.cs.meta | 2 +- VisualEditor/NanoBrainComponent.cs | 39 -- VisualEditor/NanoBrainComponent.cs.meta | 2 - 23 files changed, 657 insertions(+), 1312 deletions(-) rename Scene/{TestScene.unity => TestScene Boid.unity} (100%) create mode 100644 Scene/TestScene Boid.unity.meta create mode 100644 Scene/TestScene Experiment.unity rename Scene/{TestScene.unity.meta => TestScene Experiment.unity.meta} (100%) create mode 100644 Scripts.meta create mode 100644 Scripts/Experimental.meta create mode 100644 Scripts/Experimental/SelectorBrain.cs create mode 100644 Scripts/Experimental/SelectorBrain.cs.meta create mode 100644 Selector.asset create mode 100644 Selector.asset.meta create mode 100644 Selector.cs create mode 100644 Selector.cs.meta delete mode 100644 VisualEditor/Editor/NanoBrainEditor.cs delete mode 100644 VisualEditor/Editor/NanoBrainEditor.cs.meta delete mode 100644 VisualEditor/Editor/NanoBrainInspector.cs delete mode 100644 VisualEditor/Editor/NanoBrainInspector.cs.meta rename VisualEditor/Editor/{NanoBrainComponent_Editor.cs => NanoBrain_Editor.cs} (92%) rename VisualEditor/Editor/{NanoBrainComponent_Editor.cs.meta => NanoBrain_Editor.cs.meta} (100%) delete mode 100644 VisualEditor/NanoBrainComponent.cs delete mode 100644 VisualEditor/NanoBrainComponent.cs.meta diff --git a/Neuron.cs b/Neuron.cs index 5af285a..d6b50c0 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -9,6 +9,21 @@ using static Unity.Mathematics.math; [Serializable] public class Neuron : INucleus { + public Neuron(Cluster parent, string name) { + this.parent = parent; + this.name = name; + this.parent?.nuclei.Add(this); + } + public Neuron(ClusterPrefab parent, string name) { + this.cluster = parent; + this.name = name; + if (this.cluster != null) { + this.cluster.nuclei.Add(this); + } + // else + // Debug.LogError("No neuroid network"); + } + [SerializeField] protected string _name; public virtual string name { @@ -165,21 +180,6 @@ public class Neuron : INucleus { #endregion Runtime state - public Neuron(Cluster parent, string name) { - this.parent = parent; - this.name = name; - this.parent?.nuclei.Add(this); - } - public Neuron(ClusterPrefab parent, string name) { - this.cluster = parent; - this.name = name; - if (this.cluster != null) { - this.cluster.nuclei.Add(this); - } - // else - // Debug.LogError("No neuroid network"); - } - // this clone the nucleus without the synapses and receivers public virtual IReceptor ShallowCloneTo(Cluster newParent) { Neuron clone = new(newParent, this.name) { diff --git a/Scene/TestScene.unity b/Scene/TestScene Boid.unity similarity index 100% rename from Scene/TestScene.unity rename to Scene/TestScene Boid.unity diff --git a/Scene/TestScene Boid.unity.meta b/Scene/TestScene Boid.unity.meta new file mode 100644 index 0000000..81fe061 --- /dev/null +++ b/Scene/TestScene Boid.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 4f343147e37db9eeda3e98058c553c92 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scene/TestScene Experiment.unity b/Scene/TestScene Experiment.unity new file mode 100644 index 0000000..ac54ba4 --- /dev/null +++ b/Scene/TestScene Experiment.unity @@ -0,0 +1,365 @@ +%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: 10 + 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: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 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_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 13 + m_BakeOnSceneLoad: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + 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_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 2 + 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: 1 + m_PVRFilteringGaussRadiusAO: 1 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 20201, guid: 0000000000000000f000000000000000, type: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 3 + 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 + buildHeightMesh: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &388118692 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 388118694} + - component: {fileID: 388118693} + m_Layer: 0 + m_Name: GameObject + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &388118693 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 388118692} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9051408e82b511584998506096af4bf0, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::SelectorBrain + defaultBrain: {fileID: 11400000, guid: d5b3a22d9bb7d13aeb3174077125967b, type: 2} + input1: {x: 0, y: 0, z: 1} + input2: {x: 0, y: -2, z: 0} + output: {x: 0, y: 0, z: 0} +--- !u!4 &388118694 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 388118692} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -2.01476, y: -0, z: 0.65362} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &968074744 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 968074747} + - component: {fileID: 968074746} + - component: {fileID: 968074745} + 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 &968074745 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 968074744} + m_Enabled: 1 +--- !u!20 &968074746 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 968074744} + 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_Iso: 200 + m_ShutterSpeed: 0.005 + m_Aperture: 16 + m_FocusDistance: 10 + m_FocalLength: 50 + m_BladeCount: 5 + m_Curvature: {x: 2, y: 11} + m_BarrelClipping: 0.25 + m_Anamorphism: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + 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: 0 + 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 &968074747 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 968074744} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &2011285159 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2011285161} + - component: {fileID: 2011285160} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &2011285160 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2011285159} + m_Enabled: 1 + serializedVersion: 12 + m_Type: 1 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize2D: {x: 0.5, y: 0.5} + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ForceVisible: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 + m_LightUnit: 1 + m_LuxAtDistance: 1 + m_EnableSpotReflector: 1 +--- !u!4 &2011285161 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2011285159} + serializedVersion: 2 + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1660057539 &9223372036854775807 +SceneRoots: + m_ObjectHideFlags: 0 + m_Roots: + - {fileID: 968074747} + - {fileID: 2011285161} + - {fileID: 388118694} diff --git a/Scene/TestScene.unity.meta b/Scene/TestScene Experiment.unity.meta similarity index 100% rename from Scene/TestScene.unity.meta rename to Scene/TestScene Experiment.unity.meta diff --git a/Scripts.meta b/Scripts.meta new file mode 100644 index 0000000..6083b0e --- /dev/null +++ b/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 363b69b84de0e4b729794c10e7c40ab5 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Experimental.meta b/Scripts/Experimental.meta new file mode 100644 index 0000000..7c7ad14 --- /dev/null +++ b/Scripts/Experimental.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2c1e3956a0b70ae6b8d09fb467b73621 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Experimental/SelectorBrain.cs b/Scripts/Experimental/SelectorBrain.cs new file mode 100644 index 0000000..a08dc46 --- /dev/null +++ b/Scripts/Experimental/SelectorBrain.cs @@ -0,0 +1,23 @@ +using UnityEngine; + +public class SelectorBrain : NanoBrain { + public Vector3 input1; + public Vector3 input2; + public Vector3 output; + + public Receptor receptor1; + public Receptor receptor2; + + protected void Awake() { + receptor1 = Receptor.CreateReceptor(this.brain, "Input 1"); + receptor2 = Receptor.CreateReceptor(this.brain, "Input 2"); + } + + protected void Update() { + receptor1.ProcessStimulus(0, input1); + receptor2.ProcessStimulus(1, input2); + output = this.brain.outputValue; + + this.brain.UpdateNuclei(); + } +} \ No newline at end of file diff --git a/Scripts/Experimental/SelectorBrain.cs.meta b/Scripts/Experimental/SelectorBrain.cs.meta new file mode 100644 index 0000000..ef88825 --- /dev/null +++ b/Scripts/Experimental/SelectorBrain.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 9051408e82b511584998506096af4bf0 \ No newline at end of file diff --git a/Selector.asset b/Selector.asset new file mode 100644 index 0000000..8221c64 --- /dev/null +++ b/Selector.asset @@ -0,0 +1,138 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3} + m_Name: Selector + m_EditorClassIdentifier: Assembly-CSharp::ClusterPrefab + nuclei: + - rid: 5479437130421501952 + - rid: 5479437130421501954 + - rid: 5479437130421501956 + references: + version: 2 + RefIds: + - rid: 5479437130421501952 + type: {class: Neuron, ns: , asm: Assembly-CSharp} + data: + _name: Output + _synapses: + - nucleus: + rid: 5479437130421501954 + weight: 0.1 + - nucleus: + rid: 5479437130421501956 + weight: 0.9 + _receivers: [] + _array: + rid: 5479437130421501953 + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1000 + value: 1000 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 1 + - rid: 5479437130421501953 + type: {class: NucleusArray, ns: , asm: Assembly-CSharp} + data: + _nuclei: + - rid: 5479437130421501952 + name: Output + - rid: 5479437130421501954 + type: {class: Neuron, ns: , asm: Assembly-CSharp} + data: + _name: Input + _synapses: [] + _receivers: + - rid: 5479437130421501952 + - rid: 5479437130421501956 + _array: + rid: 5479437130421501955 + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1000 + value: 1000 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + - rid: 5479437130421501955 + type: {class: NucleusArray, ns: , asm: Assembly-CSharp} + data: + _nuclei: + - rid: 5479437130421501954 + name: New neuron + - rid: 5479437130421501956 + type: {class: MemoryCell, ns: , asm: Assembly-CSharp} + data: + _name: Previous Input + _synapses: + - nucleus: + rid: 5479437130421501954 + weight: 1 + _receivers: + - rid: 5479437130421501952 + _array: + rid: 5479437130421501957 + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + average: 0 + - rid: 5479437130421501957 + type: {class: NucleusArray, ns: , asm: Assembly-CSharp} + data: + _nuclei: + - rid: 5479437130421501956 + name: New memory cell diff --git a/Selector.asset.meta b/Selector.asset.meta new file mode 100644 index 0000000..2365967 --- /dev/null +++ b/Selector.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d5b3a22d9bb7d13aeb3174077125967b +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Selector.cs b/Selector.cs new file mode 100644 index 0000000..01a2411 --- /dev/null +++ b/Selector.cs @@ -0,0 +1,49 @@ +using Unity.Mathematics; +using static Unity.Mathematics.math; + +public class Selector : Neuron { + public Selector(Cluster parent, string name) : base(parent, name) { } + + public override void UpdateStateIsolated(float3 bias) { + float3 max = bias; + float maxSqrLength = lengthsq(max); + + //Applying the weight factors + foreach (Synapse synapse in this.synapses) { + float3 input = synapse.weight * synapse.nucleus.outputValue; + + float inputSqrlength = lengthsq(input); + if (inputSqrlength > maxSqrLength) { + max = input; + maxSqrLength = inputSqrlength; + } + } + + // Activation function + float3 result; + switch (this.curvePreset) { + case CurvePresets.Linear: + result = max; + break; + case CurvePresets.Sqrt: + result = normalize(max) * System.MathF.Sqrt(length(max)); + break; + case CurvePresets.Power: + result = normalize(max) * System.MathF.Pow(length(max), 2); + break; + case CurvePresets.Reciprocal: { + float magnitude = length(max); + if (magnitude > 0) + result = normalize(max) * (1 / magnitude); + else + result = float3(0, 0, 0); + break; + } + default: + float activatedValue = this.curve.Evaluate(length(max)); + result = normalize(max) * activatedValue; + break; + } + this.outputValue = result; + } +} \ No newline at end of file diff --git a/Selector.cs.meta b/Selector.cs.meta new file mode 100644 index 0000000..1273f83 --- /dev/null +++ b/Selector.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 4218c2f3f15af944db0eadd6e1500d17 \ No newline at end of file diff --git a/VisualEditor/Editor/NanoBrainEditor.cs b/VisualEditor/Editor/NanoBrainEditor.cs deleted file mode 100644 index 230bfa1..0000000 --- a/VisualEditor/Editor/NanoBrainEditor.cs +++ /dev/null @@ -1,511 +0,0 @@ -/* -using UnityEditor; -using UnityEngine; -using UnityEngine.UIElements; -using UnityEditor.Callbacks; -using System.Linq; -using System.Collections.Generic; - -public class NucleusLayer { - public int ix = 0; - public List neuroids = new(); -} - -public class NanoBrainEditor : EditorWindow { - public NanoBrain brain; - - public static VisualElement inspectorContainer; - - [MenuItem("Window/NanoBrain Editor")] - public static void ShowWindow() { - GetWindow("NanoBrain Editor"); - } - - public static void Open(NanoBrain asset) { - NanoBrainEditor editor = GetWindow("NanoBrain Editor"); - editor.brain = asset; - editor.Show(); - } - - GraphBoardView board; - - private void OnEnable() { - OnFocus(); - } - private void OnFocus() { - if (brain == null) { - // brain = CreateInstance(); - // EditorUtility.SetDirty(brain); - return; - } - - VisualElement root = rootVisualElement; - root.Clear(); - root.styleSheets.Add(Resources.Load("GraphStyles")); - - VisualElement main = new() { - name = "main", - style = { - flexDirection = FlexDirection.Row, - flexGrow = 1 - } - }; - board = new GraphBoardView(); - board.style.flexGrow = 1; - inspectorContainer = new VisualElement { - name = "inspector", - style = { - width = 400 - } - }; - - main.Add(board); - main.Add(inspectorContainer); - root.Add(main); - - board.SetGraph(brain, brain.root); - - } - -} - -public class GraphBoardView : VisualElement { - NanoBrain brain; - SerializedObject serializedBrain; - Nucleus currentNucleus; - private List layers = new(); - private Dictionary neuroidPositions = new(); - - Vector2 pan = Vector2.zero; - //float zoom = 1f; - bool draggingCanvas = false; - Vector2 lastMouse; - GraphNodeWrapper currentWrapper; - - public GraphBoardView() { - name = "content"; - style.flexGrow = 1; - - IMGUIContainer imguiContainer = new(OnIMGUI); - imguiContainer.style.position = Position.Absolute; - imguiContainer.style.left = 0; imguiContainer.style.top = 0; - imguiContainer.style.right = 0; imguiContainer.style.bottom = 0; - imguiContainer.pickingMode = PickingMode.Position; - imguiContainer.focusable = true; - Add(imguiContainer); - - //RegisterCallback(OnWheel); - RegisterCallback(OnMouseDown); - RegisterCallback(OnMouseMove); - RegisterCallback(OnMouseUp); - } - - public void SetGraph(NanoBrain brain, Nucleus nucleus) { - this.brain = brain; - this.serializedBrain = new SerializedObject(brain); - this.currentNucleus = nucleus; - Rebuild(); - } - - void Rebuild() { - BuildLayers(); - - if (currentNucleus == null) { - NanoBrainEditor.inspectorContainer.Clear(); - return; - } - - if (currentWrapper != null) - Object.DestroyImmediate(currentWrapper); - currentWrapper = ScriptableObject.CreateInstance().Init(currentNucleus, brain); - DrawInspector(); - } - - private void BuildLayers() { - // A temporary list to track what's been added to layers - this.layers = new(); - int layerIx = 0; - - Nucleus selectedNucleus = this.currentNucleus; - if (selectedNucleus == null) - return; - NeuroidLayer currentLayer = new() { ix = layerIx }; - - //foreach (Nucleus outputNeuroid in selectedNucleus.receivers) { - foreach (Receiver receiver in selectedNucleus.receivers) { - Nucleus outputNeuroid = receiver.nucleus; - if (outputNeuroid != null) { - AddToLayer(currentLayer, outputNeuroid); - // Debug.Log($"layer {layerIx} nucleus {outputNeuroid.name}"); - } - } - if (currentLayer.neuroids.Count > 0) { - this.layers.Add(currentLayer); - layerIx++; - currentLayer = new() { ix = layerIx }; - } - - AddToLayer(currentLayer, selectedNucleus); - this.layers.Add(currentLayer); - // Debug.Log($"layer {layerIx} nucleus {selectedNucleus.name}"); - - layerIx++; - currentLayer = new() { ix = layerIx }; - - //foreach (Nucleus input in selectedNucleus.synapses.Keys) { - foreach (Synapse synapse in selectedNucleus.synapses) { - Nucleus input = synapse.nucleus; - AddToLayer(currentLayer, input); - // Debug.Log($"layer {layerIx} nucleus {input.name}"); - } - if (currentLayer.neuroids.Count > 0) { - this.layers.Add(currentLayer); - } - } - - private void AddToLayer(NeuroidLayer layer, Nucleus nucleus) { - if (nucleus == null) - return; - layer.neuroids.Add(nucleus); - nucleus.layerIx = layer.ix; - // Store its position - Vector2Int neuroidPosition = new(layer.ix, layer.neuroids.Count - 1); - neuroidPositions[nucleus] = neuroidPosition; - - } - - // basic pan/zoom handling - // void OnWheel(WheelEvent e) { - // if (e.ctrlKey) { - // float delta = -e.delta.y * 0.001f; - // zoom = Mathf.Clamp(zoom + delta, 0.25f, 2f); - // content.transform.rotation = Quaternion.identity; // keep transform accessible - // content.transform.scale = new Vector3(zoom, zoom, 1); - // e.StopPropagation(); - // } - // else { - // pan += e.delta; - // content.style.left = pan.x; - // content.style.top = pan.y; - // } - // } - - void OnMouseDown(MouseDownEvent e) { - if (e.button == 2) { draggingCanvas = true; lastMouse = e.mousePosition; e.StopPropagation(); } - } - void OnMouseMove(MouseMoveEvent e) { - if (draggingCanvas) { - var delta = e.mousePosition - lastMouse; - pan += delta; - //content.style.left = pan.x; - //content.style.top = pan.y; - lastMouse = e.mousePosition; - } - } - void OnMouseUp(MouseUpEvent e) { if (e.button == 2) draggingCanvas = false; } - - void OnIMGUI() { - if (currentNucleus == null) - return; - - serializedBrain.Update(); - - Handles.BeginGUI(); - foreach (NeuroidLayer layer in layers) - DrawLayer(layer); - Handles.EndGUI(); - - } - - private void DrawLayer(NeuroidLayer layer) { - int nodeCount = layer.neuroids.Count; - float maxValue = 0; - foreach (Nucleus nucleus in layer.neuroids) { - if (nucleus is Neuroid neuroid) { - float value = neuroid.outputValue.magnitude; - if (value > maxValue) - maxValue = value; - } - } - float spacing = 400f / nodeCount; - float margin = 10 + spacing / 2; - foreach (Nucleus layerNucleus in layer.neuroids) { - Vector2Int layerNeuroidPos = this.neuroidPositions[layerNucleus]; - Vector3 parentPos = new(100 + layerNeuroidPos.x * 100, margin + layerNeuroidPos.y * spacing, 0.1f); - - //int i = 0; - float inputSpacing = 400f / layerNucleus.synapses.Count; - float inputMargin = 10 + inputSpacing / 2; - // int minStale = 10000; - //foreach ((Nucleus nucleus, float weight) in layerNucleus.synapses) { - foreach (Synapse synapse in layerNucleus.synapses) { - Nucleus nucleus = synapse.nucleus; - if (nucleus != null) { - float weight = synapse.weight; - if (this.neuroidPositions.ContainsKey(nucleus)) { - Vector2Int inputNeuroidPos = this.neuroidPositions[nucleus]; - if (inputNeuroidPos.x == layerNeuroidPos.x + 1) { - Vector3 pos = new(100 + inputNeuroidPos.x * 100, inputMargin + inputNeuroidPos.y * inputSpacing, 0.0f); - - float brightness = weight / 10.0f; - Handles.color = new Color(brightness, brightness, brightness); - Handles.DrawLine(parentPos, pos); - } - } - // if (nucleus is Neuroid neuroid && neuroid.stale < minStale) - // minStale = neuroid.stale; - } - } - - // if (layerNucleus.synapses.Count > 0 && minStale > 2 && layerNucleus.stale < 3) - // Debug.LogWarning($"Strange {minStale} is big duing update"); - - - float size = 20; - if (layerNucleus.isSleeping) - Handles.color = Color.darkRed; - else { - float brightness = layerNucleus.outputValue.magnitude / maxValue; - Handles.color = new Color(brightness, brightness, brightness); - } - Handles.DrawSolidDisc(parentPos, Vector3.forward, size); - Vector3 labelPos = parentPos - Vector3.down * (size + 0.2f); // below disc along up axis - GUIStyle style = new GUIStyle(EditorStyles.label) { - alignment = TextAnchor.UpperCenter, - normal = { textColor = Color.white }, - fontStyle = FontStyle.Bold - }; - Handles.Label(labelPos, layerNucleus.name, style); - - Rect neuronRect = new(parentPos.x - size, parentPos.y - size, size * 2, size * 2); - int id = GUIUtility.GetControlID(FocusType.Passive); - Event e = Event.current; - EventType et = e.GetTypeForControl(id); - if (e != null && neuronRect.Contains(e.mousePosition)) { - // Process Hover - HandleMouseHover(layerNucleus, neuronRect); - // Process click - // Debug.Log($"{et} {e.type}"); - if (e.type == EventType.MouseDown && e.button == 0) { - // Consume the event so the scene doesn't also handle it - e.Use(); - HandleDiscClicked(layerNucleus); - } - } - } - } - - private void HandleMouseHover(Nucleus neuroid, Rect rect) { - GUIContent tooltip; - // if (neuroid is SensoryNeuroid sensoryNeuroid) { - // tooltip = new( - // $"{sensoryNeuroid.name}" + - // $"\nThing {sensoryNeuroid.receptor.thingType}" + - // $"\nValue: {neuroid.outputValue}"); - // } - // else { - tooltip = new( - $"{neuroid.name}" + - $"\nsynapse count {neuroid.synapses.Count}" + - $"\nValue: {neuroid.outputValue}"); - // } - - Vector2 mousePosition = Event.current.mousePosition; - - // Display tooltip with some offset - Vector2 tooltipSize = GUI.skin.box.CalcSize(tooltip); - Rect tooltipRect = new Rect(mousePosition.x + 10, mousePosition.y + 10, tooltipSize.x, tooltipSize.y); - - GUI.Box(tooltipRect, tooltip); - } - - private void HandleDiscClicked(Nucleus nucleus) { - this.currentNucleus = nucleus; - BuildLayers(); - } - - - void DrawInspector() { - if (NanoBrainEditor.inspectorContainer == null) - return; - - NanoBrainEditor.inspectorContainer.Clear(); - if (this.currentNucleus == null) - return; - - // create a SerializedObject wrapper so Unity inspector controls work (and Undo) - SerializedObject so = new SerializedObject(currentWrapper); - IMGUIContainer container = new IMGUIContainer(() => { - so.Update(); - currentNucleus.name = EditorGUILayout.TextField(currentNucleus.name); - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.LabelField("Output Value", GUILayout.Width(100)); - EditorGUILayout.Vector3Field(GUIContent.none, currentNucleus.outputValue); - EditorGUILayout.EndHorizontal(); - if (currentNucleus.synapses.Count > 0) { - EditorGUILayout.LabelField("Synapses"); - EditorGUI.indentLevel++; - - //List nuclei = currentNucleus.synapses.Keys.ToList(); - // foreach (Nucleus nucleus in nuclei) { - foreach (Synapse synapse in currentNucleus.synapses) { - EditorGUI.BeginDisabledGroup(synapse.nucleus.isSleeping); - - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.LabelField(synapse.nucleus.name, GUILayout.Width(120)); - EditorGUI.indentLevel--; - EditorGUILayout.LabelField("Weight", GUILayout.Width(45)); - // float weight = currentNucleus.synapses[nucleus]; - // currentNucleus.synapses[nucleus] = EditorGUILayout.FloatField(weight, GUILayout.Width(40)); - synapse.weight = EditorGUILayout.FloatField(synapse.weight, GUILayout.Width(40)); - EditorGUI.indentLevel++; - EditorGUILayout.Vector3Field(GUIContent.none, synapse.nucleus.outputValue, GUILayout.Width(180)); - EditorGUILayout.EndHorizontal(); - - EditorGUI.EndDisabledGroup(); - } - EditorGUI.indentLevel--; - } - if (GUILayout.Button("Add Neuron")) - AddInputNeuron(currentNucleus); - - }); - - NanoBrainEditor.inspectorContainer.Add(container); - } - - protected virtual void AddInputNeuron(Nucleus receiver) { - Neuroid newNeuroid = new(brain, "New neuron"); - newNeuroid.AddReceiver(receiver); - Rebuild(); - } - - private Vector3 NodePosition(Nucleus nucleus, int layerNodeCount = 1) { - if (this.neuroidPositions.ContainsKey(nucleus)) { - Vector2Int nucleusPos = this.neuroidPositions[nucleus]; - return NodePosition(nucleusPos, layerNodeCount); - } - else { - return Vector3.zero; - } - } - private Vector3 NodePosition(Vector2Int location, int layerNodeCount = 1) { - float spacing = 400f / layerNodeCount; - float margin = 10 + spacing / 2; - float size = 20; - Vector3 parentPos = new(100 + location.x * 100 - size, margin + location.y * spacing - size, 0.1f); - return parentPos; - } - - - // public void CreateEdge(string fromId, string toId) { - // if (fromId == toId) return; - // Undo.RecordObject(graph, "Create Edge"); - // graph.edges.Add(new GraphEdge { fromNodeId = fromId, toNodeId = toId }); - // EditorUtility.SetDirty(graph); - // Rebuild(); - // } -} - - -public class NodeView : VisualElement { - Nucleus data; - GraphBoardView board; - Label titleLabel; - //bool dragging = false; - Vector2 localDragStart; - - public NodeView(Nucleus node, GraphBoardView boardView) { - data = node; - board = boardView; - name = "node"; - style.width = 20; //node.size.x; - style.height = 20; //node.size.y; - - titleLabel = new Label(node.name) { name = "title" }; - Add(titleLabel); - - // ports - // var outPort = new Button(() => StartEdgeDrag(true)) { text = "◀", name = "out" }; - // var inPort = new Button(() => StartEdgeDrag(false)) { text = "▶", name = "in" }; - // Add(outPort); - // Add(inPort); - - RegisterCallback(OnMouseDown); - // RegisterCallback(OnMouseMove); - RegisterCallback(OnMouseUp); - //RegisterCallback(e => dragging = false); - } - - // void StartEdgeDrag(bool isOutput) { - // // simplified: on first click store source; on second click on target port call board.CreateEdge - // if (EdgeDragState.active == null) EdgeDragState.active = new EdgeDragState { fromNode = data, fromIsOutput = isOutput }; - // else { - // var src = EdgeDragState.active.fromNode; - // if (src != null && src.id != data.id) board.CreateEdge(src.id, data.id); - // EdgeDragState.active = null; - // } - // } - - void OnMouseDown(MouseDownEvent e) { - if (e.button == 0 && e.target == this) { - //dragging = true; - localDragStart = e.mousePosition; - e.StopPropagation(); - } - } - // void OnMouseMove(MouseMoveEvent e) { - // if (!dragging) return; - // var delta = e.mousePosition - localDragStart; - // var worldPos = new Vector2(layout.x + delta.x, layout.y + delta.y); - // style.left = worldPos.x; - // style.top = worldPos.y; - // // commit on every move - // board.UpdateNodePosition(data, worldPos); - // } - void OnMouseUp(MouseUpEvent e) { - //dragging = false; - } -} - - -public class GraphNodeWrapper : ScriptableObject { - // expose fields that map to GraphNode - public string title; - public Vector2 position; - Nucleus node; - NanoBrain graph; // needed to write back and mark dirty - - public GraphNodeWrapper Init(Nucleus node, NanoBrain graphAsset) { - this.node = node; - this.graph = graphAsset; - this.title = " A " + node.name; - //position = node.position; - return this; - } - void OnValidate() { - if (node != null) { - node.name = title; - //node.position = position; -#if UNITY_EDITOR - if (graph != null) - UnityEditor.EditorUtility.SetDirty(graph); -#endif - } - } -} -//static class EdgeDragState { public static EdgeDragState active; public GraphNode fromNode; public bool fromIsOutput; } - -public static class OpenAssetHandler { - // Called when an asset is double-clicked or opened. - [OnOpenAsset] - public static bool OpenMyScriptableObject(int instanceID, int line) { - NanoBrain obj = EditorUtility.EntityIdToObject(instanceID) as NanoBrain; - if (obj != null) { - NanoBrainEditor.Open(obj); - return true; // handled - } - return false; // let Unity open normally - } -} -*/ \ No newline at end of file diff --git a/VisualEditor/Editor/NanoBrainEditor.cs.meta b/VisualEditor/Editor/NanoBrainEditor.cs.meta deleted file mode 100644 index 99dedcd..0000000 --- a/VisualEditor/Editor/NanoBrainEditor.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: c57f78e25f0e55b96a50fd5592b26317 \ No newline at end of file diff --git a/VisualEditor/Editor/NanoBrainInspector.cs b/VisualEditor/Editor/NanoBrainInspector.cs deleted file mode 100644 index 447fa70..0000000 --- a/VisualEditor/Editor/NanoBrainInspector.cs +++ /dev/null @@ -1,645 +0,0 @@ -/* -using System.Collections.Generic; -using System.Linq; -using UnityEditor; - -using UnityEngine; -using UnityEngine.UIElements; - -[CustomEditor(typeof(NanoBrain))] -public class NanoBrainInspector : Editor { - protected static VisualElement mainContainer; - protected static VisualElement inspectorContainer; - - protected bool breakOnWake = false; - - #region Start - - public override VisualElement CreateInspectorGUI() { - NanoBrain brain = target as NanoBrain; - - serializedObject.Update(); - - VisualElement root = new(); - //root.style.flexDirection = FlexDirection.Row; // side-by-side layout - //root.style.flexGrow = 1; - //root.style.minHeight = 600; - root.style.paddingLeft = 0; - root.style.paddingRight = 0; - root.style.paddingTop = 0; - root.style.paddingBottom = 0; - - root.styleSheets.Add(Resources.Load("GraphStyles")); - - mainContainer = new() { - // name = "main", - style = { - // flexDirection = FlexDirection.Row, - // flexGrow = 1, - height = 450, - } - }; - GraphView graph = new(); - graph.style.flexGrow = 1; - - inspectorContainer = new VisualElement { - // name = "inspector" - }; - - mainContainer.Add(graph); - mainContainer.Add(inspectorContainer); - root.Add(mainContainer); - - // Run once for initial state (use resolved style width if available) - float initialWidth = root.layout.width > 0 ? root.layout.width : root.contentRect.width; - UpdateLayout(initialWidth); - - // React to size changes of root (or parent if appropriate) - root.RegisterCallback(evt => { - UpdateLayout(evt.newRect.width); - }); - - if (brain != null) - graph.SetGraph(null, brain, brain.output, inspectorContainer); - else - Debug.LogWarning(" No brain!"); - - serializedObject.ApplyModifiedProperties(); - return root; - } - - public class GraphView : VisualElement { - NanoBrain brain; - SerializedObject serializedBrain; - INucleus currentNucleus; - GameObject gameObject; - private List layers = new(); - private readonly Dictionary neuroidPositions = new(); - - Vector2 pan = Vector2.zero; - //float zoom = 1f; - bool draggingCanvas = false; - Vector2 lastMouse; - GraphNodeWrapper currentWrapper; - - public GraphView() { - name = "content"; - style.flexGrow = 1; - - IMGUIContainer imguiContainer = new(OnIMGUI); - imguiContainer.style.position = Position.Absolute; - imguiContainer.style.left = 0; imguiContainer.style.top = 0; - imguiContainer.style.right = 0; imguiContainer.style.bottom = 0; - imguiContainer.pickingMode = PickingMode.Position; - imguiContainer.focusable = true; - Add(imguiContainer); - - //RegisterCallback(OnWheel); - RegisterCallback(OnMouseDown); - RegisterCallback(OnMouseMove); - RegisterCallback(OnMouseUp); - } - - public void SetGraph(GameObject gameObject, NanoBrain brain, Nucleus nucleus, VisualElement inspectorContainer) { - this.gameObject = gameObject; - this.brain = brain; - if (Application.isPlaying == false) - this.serializedBrain = new SerializedObject(brain); - this.currentNucleus = nucleus; - Rebuild(inspectorContainer); - } - - void Rebuild(VisualElement inspectorContainer) { - BuildLayers(); - - if (this.currentNucleus == null) { - inspectorContainer.Clear(); - return; - } - - if (currentWrapper != null) - DestroyImmediate(currentWrapper); - currentWrapper = CreateInstance().Init(this.currentNucleus, brain); - DrawInspector(inspectorContainer); - } - - private void BuildLayers() { - // A temporary list to track what's been added to layers - this.layers = new(); - int layerIx = 0; - - INucleus selectedNucleus = this.currentNucleus; - if (selectedNucleus == null) - return; - NeuroidLayer currentLayer = new() { ix = layerIx }; - - if (selectedNucleus.receivers != null) { - foreach (INucleus receiver in selectedNucleus.receivers) { - INucleus outputNeuroid = receiver; - if (outputNeuroid != null) { - AddToLayer(currentLayer, outputNeuroid); - // Debug.Log($"layer {layerIx} nucleus {outputNeuroid.name}"); - } - } - } - if (currentLayer.neuroids.Count > 0) { - this.layers.Add(currentLayer); - layerIx++; - currentLayer = new() { ix = layerIx }; - } - - AddToLayer(currentLayer, selectedNucleus); - this.layers.Add(currentLayer); - // Debug.Log($"layer {layerIx} nucleus {selectedNucleus.name}"); - - layerIx++; - currentLayer = new() { ix = layerIx }; - - if (selectedNucleus.synapses != null) { - foreach (Synapse synapse in selectedNucleus.synapses) { - IReceptor input = synapse.nucleus; - AddToLayer(currentLayer, input); - // Debug.Log($"layer {layerIx} nucleus {input.name}"); - } - } - if (currentLayer.neuroids.Count > 0) { - this.layers.Add(currentLayer); - } - } - - private void AddToLayer(NeuroidLayer layer, IReceptor nucleus) { - if (nucleus == null) - return; - layer.neuroids.Add(nucleus); - //nucleus.layerIx = layer.ix; - // Store its position - Vector2Int neuroidPosition = new(layer.ix, layer.neuroids.Count - 1); - neuroidPositions[nucleus] = neuroidPosition; - - } - - void OnMouseDown(MouseDownEvent e) { - if (e.button == 2) { draggingCanvas = true; lastMouse = e.mousePosition; e.StopPropagation(); } - } - void OnMouseMove(MouseMoveEvent e) { - if (draggingCanvas) { - var delta = e.mousePosition - lastMouse; - pan += delta; - //content.style.left = pan.x; - //content.style.top = pan.y; - lastMouse = e.mousePosition; - } - } - void OnMouseUp(MouseUpEvent e) { if (e.button == 2) draggingCanvas = false; } - - void OnIMGUI() { - if (currentNucleus == null) - return; - - if (Application.isPlaying == false) - serializedBrain.Update(); - - Handles.BeginGUI(); - DrawGraph(); - Handles.EndGUI(); - - } - - private void DrawGraph() { - float size = 20; - Vector3 position = new(150, 210, 0); - - DrawReceivers(this.currentNucleus, position, size); - DrawSynapses(this.currentNucleus, position, size); - - // Draw selected Nucleus - Handles.color = Color.white; - Handles.DrawSolidDisc(position, Vector3.forward, size + 2); - DrawNucleus(this.currentNucleus, position, this.currentNucleus.outputValue.magnitude, 20); - } - - private void DrawReceivers(INucleus nucleus, Vector3 parentPos, float size) { - int nodeCount = nucleus.receivers.Count; - - // Determine the maximum value in this layer - // This is used to 'scale' the output value colors of the nuclei - float maxValue = 0; - foreach (INucleus receiver in nucleus.receivers) { - if (receiver is Neuroid neuroid) { - float value = neuroid.outputValue.magnitude; - if (value > maxValue) - maxValue = value; - } - } - - // Determine the spacing of the nuclei in the layer - float spacing = 400f / nodeCount; - float margin = 10 + spacing / 2; - - int row = 0; - foreach (INucleus receiver in nucleus.receivers) { - INucleus receiverNucleus = receiver; - if (receiverNucleus == null) - continue; - - Vector3 pos = new(50, margin + row * spacing, 0.0f); - Handles.color = Color.white; - Handles.DrawLine(parentPos, pos); - - DrawNucleus(receiverNucleus, pos, maxValue, size); - row++; - } - } - - private void DrawSynapses(INucleus nucleus, Vector3 parentPos, float size) { - int nodeCount = nucleus.synapses.Count; - - // Determine the maximum value in this layer - // This is used to 'scale' the output value colors of the nuclei - float maxValue = 0; - foreach (Synapse receiver in nucleus.synapses) { - if (receiver.nucleus is Neuroid neuroid) { - float value = neuroid.outputValue.magnitude; - if (value > maxValue) - maxValue = value; - } - } - - // Determine the spacing of the nuclei in the layer - float spacing = 400f / nodeCount; - float margin = 10 + spacing / 2; - - int row = 0; - List drawnArrays = new(); - foreach (Synapse synapse in nucleus.synapses) { - Vector3 pos = new(250, margin + row * spacing, 0.0f); - Handles.color = Color.white; - Handles.DrawLine(parentPos, pos); - // if (synapse.nucleus is Perceptoid perceptoid && perceptoid.array != null) { - // // if (drawnArrays.Contains(perceptoid.array)) - // // // We already drawn this array - // // continue; - - // drawnArrays.Add(perceptoid.array); - // DrawArray(perceptoid.array, pos, size); - // } - // else { - - DrawNucleus(synapse.nucleus, pos, maxValue, size); - row++; - // } - } - } - - private void DrawNucleus(IReceptor nucleus, Vector3 position, float maxValue, float size) { - if (nucleus.isSleeping) - Handles.color = Color.darkRed; - else { - if (Application.isPlaying) { - float brightness = nucleus.outputValue.magnitude / maxValue; - Handles.color = new Color(brightness, brightness, brightness, 1f); - } - else - Handles.color = Color.black; - } - Handles.DrawSolidDisc(position, Vector3.forward, size); - - Handles.color = Color.white; - // Position the label in front of the disc - Vector3 labelPosition = position + (Vector3.forward * 0.1f); - - GUIStyle style = new(EditorStyles.label) { - alignment = TextAnchor.MiddleCenter, - normal = { textColor = Color.white }, - fontStyle = FontStyle.Bold, - }; - if (nucleus is Perceptoid perceptoid) { - if (perceptoid.array == null || perceptoid.array.perceptei == null || perceptoid.array.perceptei.Length == 0) - perceptoid.array = new PercepteiArray(perceptoid); - - if (perceptoid.array.perceptei.Length > 1) { - Handles.Label(labelPosition, perceptoid.array.perceptei.Length.ToString(), style); - } - } - - style.alignment = TextAnchor.UpperCenter; - Vector3 labelPos = position - Vector3.down * (size + 0.2f); // below disc along up axis - Handles.Label(labelPos, nucleus.name, style); - - Rect neuronRect = new(position.x - size, position.y - size, size * 2, size * 2); - int id = GUIUtility.GetControlID(FocusType.Passive); - Event e = Event.current; - EventType et = e.GetTypeForControl(id); - if (e != null && neuronRect.Contains(e.mousePosition)) { - // Process Hover - HandleMouseHover(nucleus, neuronRect); - // Process click - if (e.type == EventType.MouseDown && e.button == 0) { - // Consume the event so the scene doesn't also handle it - e.Use(); - HandleClicked(nucleus); - } - } - } - - private void DrawArray(PercepteiArray array, Vector3 position, float size) { - Vector3 offset = new(size / 4, size / 4, 0); - Handles.color = Color.black; - Handles.DrawSolidDisc(position, Vector3.forward, size); - - GUIStyle style = new(EditorStyles.label) { - alignment = TextAnchor.UpperCenter, - normal = { textColor = Color.white }, - fontStyle = FontStyle.Bold - }; - Handles.Label(position, array.perceptei.Length.ToString(), style); - Vector3 labelPos = position - Vector3.down * (size + 0.2f); // below disc along up axis - Handles.Label(labelPos, array.name, style); - - // To do: add HandleClick (see above) to expand the array - } - - private void HandleMouseHover(IReceptor nucleus, Rect rect) { - GUIContent tooltip; - if (nucleus is Perceptoid perceptoid) { - if (perceptoid.receptor != null) { - tooltip = new( - $"{perceptoid.name}" + - // $"\nType {perceptoid.receptor.thingType}" + - $" Thing {perceptoid.thingId}" + - $"\nValue: {nucleus.outputValue}"); - } - else { - tooltip = new( - $"{perceptoid.name}" + - $"\nThing {perceptoid.thingId}" + - $"\nValue: {nucleus.outputValue}"); - } - } - else if (nucleus is INucleus n) { - tooltip = new( - $"{nucleus.name}" + - $"\nsynapse count {n.synapses.Count}" + - $"\nValue: {nucleus.outputValue}"); - } - else { - tooltip = new( - $"{nucleus.name}" + - $"\nValue: {nucleus.outputValue}"); - } - - Vector2 mousePosition = Event.current.mousePosition; - - // Display tooltip with some offset - Vector2 tooltipSize = GUI.skin.box.CalcSize(tooltip); - Rect tooltipRect = new Rect(mousePosition.x + 10, mousePosition.y + 10, tooltipSize.x, tooltipSize.y); - - GUI.Box(tooltipRect, tooltip); - } - - private void HandleClicked(IReceptor nucleus) { - if (nucleus is INucleus n) { - this.currentNucleus = n; - BuildLayers(); - } - } - - void DrawInspector(VisualElement inspectorContainer) { - if (inspectorContainer == null) - return; - - inspectorContainer.Clear(); - if (this.currentNucleus == null) - return; - - // create a SerializedObject wrapper so Unity inspector controls work (and Undo) - SerializedObject so = new(currentWrapper); - IMGUIContainer container = new(() => { - if (so.targetObject == null) - return; - so.Update(); - - if (this.currentNucleus == null) - return; - - this.currentNucleus.name = EditorGUILayout.TextField(this.currentNucleus.name); - if (this.currentNucleus is Perceptoid perceptoid) { - // perceptoid.receptor.thingType = EditorGUILayout.IntField("Thing Type", perceptoid.receptor.thingType); - - if (perceptoid.array == null || perceptoid.array.perceptei == null || perceptoid.array.perceptei.Length == 0) - perceptoid.array = new PercepteiArray(perceptoid); - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.IntField("Array size", perceptoid.array.perceptei.Length); - if (GUILayout.Button("Add")) - perceptoid.array.AddPerceptoid(); - if (GUILayout.Button("Del")) - perceptoid.array.RemovePerceptoid(); - EditorGUILayout.EndHorizontal(); - } - else if (this.currentNucleus is Neuroid neuroid) { - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.LabelField("Activation Curve", GUILayout.Width(150)); - if (neuroid.curveMax > 0) - EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, 0, 1, neuroid.curveMax)); - else - EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, neuroid.curveMax, 1, -neuroid.curveMax)); - neuroid.curvePreset = (Neuroid.CurvePresets)EditorGUILayout.EnumPopup(neuroid.curvePreset, GUILayout.Width(100)); - EditorGUILayout.EndHorizontal(); - } - - if (Application.isPlaying) - EditorGUILayout.FloatField("Output", this.currentNucleus.outputValue.magnitude); - else - EditorGUILayout.LabelField(" "); - - if (this.currentNucleus.synapses.Count > 0) { - Synapse[] synapses = this.currentNucleus.synapses.ToArray(); - foreach (Synapse synapse in synapses) { - if (synapse.nucleus != null) { - EditorGUILayout.Space(); - - EditorGUI.BeginDisabledGroup(synapse.nucleus.isSleeping); - if (Application.isPlaying) - EditorGUILayout.FloatField(synapse.nucleus.name, synapse.nucleus.outputValue.magnitude * synapse.weight); - else { - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.LabelField(synapse.nucleus.name); - // if (synapse.nucleus is Perceptoid perceptoid) { - // if (perceptoid.array == null || perceptoid.array.perceptei == null || perceptoid.array.perceptei.Length == 0) { - // perceptoid.array = new PercepteiArray(perceptoid); - // } - // EditorGUILayout.IntField(perceptoid.array.perceptei.Length); - // if (GUILayout.Button("Add")) - // perceptoid.array.AddPerceptoid(); - // } - if (GUILayout.Button("Disconnect")) - synapse.nucleus.RemoveReceiver(this.currentNucleus); - EditorGUILayout.EndHorizontal(); - } - - EditorGUI.indentLevel++; - synapse.weight = EditorGUILayout.FloatField("Weight", synapse.weight); - EditorGUI.indentLevel--; - EditorGUI.EndDisabledGroup(); - } - } - } - - EditorGUILayout.Space(); - - ConnectNucleus(this.currentNucleus); - if (GUILayout.Button("Add Input Neuron")) - AddInputNeuron(this.currentNucleus); - if (GUILayout.Button("Add Input Perceptoid")) - AddPerceptoid(this.currentNucleus); - if (GUILayout.Button("Add Input Cluster")) - AddCluster(this.currentNucleus); - - EditorGUILayout.Space(); - - if (GUILayout.Button("Delete this neuron")) - DeleteNeuron(this.currentNucleus); - - //DisconnectNucleus(this.currentNucleus); - - if (this.gameObject != null) { - Vector3 worldVector = this.gameObject.transform.TransformVector(this.currentNucleus.outputValue); - Debug.DrawRay(this.gameObject.transform.position, worldVector, Color.yellow); - } - }); - - inspectorContainer.Add(container); - } - - protected virtual void AddInputNeuron(INucleus nucleus) { - Neuroid newNeuroid = new(this.brain.cluster, "New neuron"); - newNeuroid.AddReceiver(nucleus); - this.currentNucleus = newNeuroid; - BuildLayers(); - } - - protected virtual void DeleteNeuron(INucleus nucleus) { - if (nucleus == null) - return; - if (nucleus.cluster != null) - this.currentNucleus = nucleus.cluster.output; - foreach (INucleus receiver in nucleus.receivers) { - if (receiver != null) { - this.currentNucleus = receiver; - break; - } - } - Nucleus.Delete(nucleus); - BuildLayers(); - } - - protected virtual void AddPerceptoid(INucleus nucleus) { - Perceptoid newPerceptoid = new(this.brain, 0, "New Perceptoid"); - newPerceptoid.AddReceiver(nucleus); - this.currentNucleus = newPerceptoid; - BuildLayers(); - } - - protected virtual void AddCluster(INucleus nucleus) { - BrainPickerWindow.ShowPicker(brain => OnClusterPicked(nucleus, brain), "Select Cluster"); - } - - private void OnClusterPicked(INucleus nucleus, NanoBrain brain) { - NanoBrain brainInstance = Instantiate(brain); - brainInstance.AddReceiver(nucleus); - } - - protected virtual void ConnectNucleus(INucleus nucleus) { - if (this.currentNucleus.cluster == null) - return; - - IEnumerable synapseNuclei = this.currentNucleus.synapses.Select(synapse => synapse.nucleus.name); - //IEnumerable perceptei = this.currentNucleus.brain.perceptei.Select(i => i.name).Except(synapseNuclei); - IEnumerable nuclei = this.currentNucleus.cluster.nuclei.Select(i => i.name).Except(synapseNuclei); - //string[] names = perceptei.Concat(nuclei).ToArray(); - string[] names = nuclei.ToArray(); - int selectedIndex = -1; - selectedIndex = EditorGUILayout.Popup("Connect to", selectedIndex, names); - if (selectedIndex >= 0) { - // if (selectedIndex < perceptei.Count()) { - // Nucleus n = this.currentNucleus.brain.perceptei[selectedIndex]; - // n.AddReceiver(this.currentNucleus); - // } - // else { - // Nucleus n = this.currentNucleus.brain.nuclei[selectedIndex - perceptei.Count()]; - // n.AddReceiver(this.currentNucleus); - // } - INucleus n = this.currentNucleus.cluster.nuclei[selectedIndex]; - n.AddReceiver(this.currentNucleus); - } - } - - protected virtual void DisconnectNucleus(Nucleus nucleus) { - if (this.currentNucleus.cluster == null) - return; - string[] names = this.currentNucleus.synapses.Select(synapse => synapse.nucleus.name).ToArray(); - int selectedIndex = -1; - selectedIndex = EditorGUILayout.Popup("Disconnect from", selectedIndex, names); - //if (selectedIndex >= 0 && selectedIndex < this.currentNucleus.brain.perceptei.Count) { - if (selectedIndex >= 0 && selectedIndex < this.currentNucleus.cluster.nuclei.Count) { - Synapse synapse = this.currentNucleus.synapses[selectedIndex]; - synapse.nucleus.RemoveReceiver(this.currentNucleus); - } - } - } - - #endregion Start - - #region Update - - private void UpdateLayout(float containerWidth) { - if (containerWidth > 600f) { - mainContainer.style.flexDirection = FlexDirection.Row; - inspectorContainer.style.width = 300; // fixed sidebar width - inspectorContainer.style.flexGrow = 0; - } - else { - mainContainer.style.flexDirection = FlexDirection.Column; - inspectorContainer.style.width = Length.Percent(100); // full width below - inspectorContainer.style.flexDirection = FlexDirection.Column; - inspectorContainer.style.flexGrow = 1; // can set 0 or keep as needed - } - } - - #endregion Update -} - -/* -public class NeuroidLayer { - public int ix = 0; - public List neuroids = new(); -} -*/ - -/* -public class GraphNodeWrapper : ScriptableObject { - // expose fields that map to GraphNode - //public string title; - public Vector2 position; - INucleus node; - NanoBrain graph; // needed to write back and mark dirty - - public GraphNodeWrapper Init(INucleus node, NanoBrain graphAsset) { - this.node = node; - this.graph = graphAsset; - //this.title = " A " + node.name; - //position = node.position; - return this; - } - void OnValidate() { - if (node != null) { - //node.name = title; - //node.position = position; -#if UNITY_EDITOR - if (graph != null) - UnityEditor.EditorUtility.SetDirty(graph); -#endif - } - } -} -*/ \ No newline at end of file diff --git a/VisualEditor/Editor/NanoBrainInspector.cs.meta b/VisualEditor/Editor/NanoBrainInspector.cs.meta deleted file mode 100644 index e71178e..0000000 --- a/VisualEditor/Editor/NanoBrainInspector.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: c96ad47c3d4498640b52630789e38573 \ No newline at end of file diff --git a/VisualEditor/Editor/NanoBrainComponent_Editor.cs b/VisualEditor/Editor/NanoBrain_Editor.cs similarity index 92% rename from VisualEditor/Editor/NanoBrainComponent_Editor.cs rename to VisualEditor/Editor/NanoBrain_Editor.cs index 4d4b54b..2710e62 100644 --- a/VisualEditor/Editor/NanoBrainComponent_Editor.cs +++ b/VisualEditor/Editor/NanoBrain_Editor.cs @@ -3,21 +3,21 @@ using UnityEditor.UIElements; using UnityEngine; using UnityEngine.UIElements; -[CustomEditor(typeof(NanoBrainComponent))] +[CustomEditor(typeof(NanoBrain))] public class NanoBrainComponent_Editor : Editor { protected static VisualElement mainContainer; protected static VisualElement inspectorContainer; - protected NanoBrainComponent component; + protected NanoBrain component; private SerializedProperty brainProp; ClusterInspector.GraphView board; public void OnEnable() { - component = target as NanoBrainComponent; + component = target as NanoBrain; if (Application.isPlaying == false) - brainProp = serializedObject.FindProperty(nameof(NanoBrainComponent.defaultBrain)); + brainProp = serializedObject.FindProperty(nameof(NanoBrain.defaultBrain)); } diff --git a/VisualEditor/Editor/NanoBrainComponent_Editor.cs.meta b/VisualEditor/Editor/NanoBrain_Editor.cs.meta similarity index 100% rename from VisualEditor/Editor/NanoBrainComponent_Editor.cs.meta rename to VisualEditor/Editor/NanoBrain_Editor.cs.meta diff --git a/VisualEditor/NanoBrain.cs b/VisualEditor/NanoBrain.cs index d786da6..e368369 100644 --- a/VisualEditor/NanoBrain.cs +++ b/VisualEditor/NanoBrain.cs @@ -1,102 +1,38 @@ -/* using System; -using System.Collections.Generic; using UnityEngine; -[CreateAssetMenu(menuName = "Passer/NanoBrain")] -public class NanoBrain : ScriptableObject, ISerializationCallbackReceiver { - public List nuclei = new(); - public List perceptei = new(); - public List receptors = new(); +public class NanoBrain : MonoBehaviour { + public ClusterPrefab defaultBrain; - - // This is probably always the first element in the nuclei list... - [System.NonSerialized] - public Nucleus output; - public int rootId; - - public NanoBrain() { - // this.cluster = new(); - // this.output = new Neuroid(this.cluster, "Root"); - } - - public Cluster cluster; - - public void AddReceiver(INucleus receiver) { - output.AddReceiver(receiver); - } - - public Neuroid AddNeuron(string name) { - Neuroid neuroid = new(this.cluster, name); - return neuroid; - } - - public void UpdateNuclei() { - foreach (Nucleus nucleus in nuclei) - nucleus.IncreaseAge(); - foreach (Perceptoid perception in perceptei) - perception.IncreaseAge(); - } - - public void OnBeforeSerialize() { - if (output != null) { - this.rootId = output.id; - } - } - public void OnAfterDeserialize() { - try { - foreach (Nucleus nucleus in this.nuclei.ToArray()) { - if (this.rootId == nucleus.id) - this.output = nucleus; - nucleus.Rebuild(this); + [NonSerialized] + private Cluster brainInstance; + public Cluster brain { + get { + if (brainInstance == null && defaultBrain != null) { + brainInstance = new Cluster(defaultBrain) { + name = defaultBrain.name + " (Instance)" + }; } - - foreach (Perceptoid perceptoid in this.perceptei.ToArray()) - perceptoid.Rebuild(this); + SwarmControl sc = FindFirstObjectByType(); + if (sc != null) { + UpdateWeight(brainInstance, "Containment", sc.containmentForce); + UpdateWeight(brainInstance, "Cohesion", sc.cohesionForce); + UpdateWeight(brainInstance, "Separation", sc.separationForce); + UpdateWeight(brainInstance, "Alignment", sc.alignmentForce); + } + return brainInstance; } - catch (System.Exception) { } - if (this.cluster != null) - this.cluster.GarbageCollection(); } - - public void GarbageCollection() { - HashSet visitedNuclei = new(); - MarkNuclei(visitedNuclei, this.output); - //Debug.Log($"Garbage collection found {visitedNuclei.Count} Nuclei"); - this.nuclei.RemoveAll(nucleus => visitedNuclei.Contains(nucleus) == false); - this.perceptei.RemoveAll(perceptoid => visitedNuclei.Contains(perceptoid) == false); - } - - public void MarkNuclei(HashSet visitedNuclei, INucleus nucleus) { - if (nucleus is null) - return; - - if (nucleus.brain == null) - nucleus.brain = this; - - visitedNuclei.Add(nucleus); - if (nucleus.synapses != null) { - HashSet visitedSynapses = new(); - foreach (Synapse synapse in nucleus.synapses) { - if (synapse != null && synapse.nucleus != null) { - visitedSynapses.Add(synapse); - MarkNuclei(visitedNuclei, synapse.nucleus); - } + public static void UpdateWeight(Cluster brain, string name, float weight) { + INucleus root = brain.output; + foreach (Synapse synapse in root.synapses) { + if (synapse.nucleus.name == name) { + if (synapse.weight != weight) { + synapse.weight = weight; + // Debug.Log($"Updated weight for {name}"); } - nucleus.synapses.RemoveAll(synapse => visitedSynapses.Contains(synapse) == false); - } - if (nucleus.receivers != null) { - HashSet visitedReceivers = new(); - foreach (Receiver receiver in nucleus.receivers) { - if (receiver != null && receiver.nucleus != null) { - visitedReceivers.Add(receiver); - visitedNuclei.Add(receiver.nucleus); - } - } - nucleus.receivers.RemoveAll(receiver => visitedReceivers.Contains(receiver) == false); } } - -} -*/ \ No newline at end of file + } +} \ No newline at end of file diff --git a/VisualEditor/NanoBrain.cs.meta b/VisualEditor/NanoBrain.cs.meta index 40e85f2..1666c60 100644 --- a/VisualEditor/NanoBrain.cs.meta +++ b/VisualEditor/NanoBrain.cs.meta @@ -1,2 +1,2 @@ fileFormatVersion: 2 -guid: 36081359186edfec998d891a1feeb17b \ No newline at end of file +guid: 92f34a5e4027a1dc39efd8ce63cf6aba \ No newline at end of file diff --git a/VisualEditor/NanoBrainComponent.cs b/VisualEditor/NanoBrainComponent.cs deleted file mode 100644 index 59314c2..0000000 --- a/VisualEditor/NanoBrainComponent.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using UnityEngine; - -public class NanoBrainComponent : MonoBehaviour { - public ClusterPrefab defaultBrain; - - [NonSerialized] - private Cluster brainInstance; - public Cluster brain { - get { - if (brainInstance == null && defaultBrain != null) { - brainInstance = new Cluster(defaultBrain) { - name = defaultBrain.name + " (Instance)" - }; - } - SwarmControl sc = FindFirstObjectByType(); - if (sc != null) { - UpdateWeight(brainInstance, "Containment", sc.containmentForce); - UpdateWeight(brainInstance, "Cohesion", sc.cohesionForce); - UpdateWeight(brainInstance, "Separation", sc.separationForce); - UpdateWeight(brainInstance, "Alignment", sc.alignmentForce); - } - return brainInstance; - } - } - - public static void UpdateWeight(Cluster brain, string name, float weight) { - INucleus root = brain.output; - foreach (Synapse synapse in root.synapses) { - if (synapse.nucleus.name == name) { - if (synapse.weight != weight) { - synapse.weight = weight; - // Debug.Log($"Updated weight for {name}"); - } - } - } - } - -} \ No newline at end of file diff --git a/VisualEditor/NanoBrainComponent.cs.meta b/VisualEditor/NanoBrainComponent.cs.meta deleted file mode 100644 index 1666c60..0000000 --- a/VisualEditor/NanoBrainComponent.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 92f34a5e4027a1dc39efd8ce63cf6aba \ No newline at end of file From 25cd5aefd08b66d34dd278c165d7da672f06cb56 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 4 Feb 2026 09:46:15 +0100 Subject: [PATCH 100/179] Cleanup --- {VisualEditor/Editor => Editor}/BrainPickerWindow.cs | 0 {VisualEditor/Editor => Editor}/BrainPickerWindow.cs.meta | 0 {VisualEditor/Editor => Editor}/ClusterInspector.cs | 0 {VisualEditor/Editor => Editor}/ClusterInspector.cs.meta | 0 {VisualEditor/Editor => Editor}/NanoBrain_Editor.cs | 0 {VisualEditor/Editor => Editor}/NanoBrain_Editor.cs.meta | 0 {VisualEditor => Editor}/Resources.meta | 0 {VisualEditor => Editor}/Resources/GraphStyles.uss | 0 {VisualEditor => Editor}/Resources/GraphStyles.uss.meta | 0 VisualEditor/NanoBrain.cs => NanoBrain.cs | 0 VisualEditor/NanoBrain.cs.meta => NanoBrain.cs.meta | 0 VisualEditor.meta | 8 -------- VisualEditor/Editor.meta | 8 -------- 13 files changed, 16 deletions(-) rename {VisualEditor/Editor => Editor}/BrainPickerWindow.cs (100%) rename {VisualEditor/Editor => Editor}/BrainPickerWindow.cs.meta (100%) rename {VisualEditor/Editor => Editor}/ClusterInspector.cs (100%) rename {VisualEditor/Editor => Editor}/ClusterInspector.cs.meta (100%) rename {VisualEditor/Editor => Editor}/NanoBrain_Editor.cs (100%) rename {VisualEditor/Editor => Editor}/NanoBrain_Editor.cs.meta (100%) rename {VisualEditor => Editor}/Resources.meta (100%) rename {VisualEditor => Editor}/Resources/GraphStyles.uss (100%) rename {VisualEditor => Editor}/Resources/GraphStyles.uss.meta (100%) rename VisualEditor/NanoBrain.cs => NanoBrain.cs (100%) rename VisualEditor/NanoBrain.cs.meta => NanoBrain.cs.meta (100%) delete mode 100644 VisualEditor.meta delete mode 100644 VisualEditor/Editor.meta diff --git a/VisualEditor/Editor/BrainPickerWindow.cs b/Editor/BrainPickerWindow.cs similarity index 100% rename from VisualEditor/Editor/BrainPickerWindow.cs rename to Editor/BrainPickerWindow.cs diff --git a/VisualEditor/Editor/BrainPickerWindow.cs.meta b/Editor/BrainPickerWindow.cs.meta similarity index 100% rename from VisualEditor/Editor/BrainPickerWindow.cs.meta rename to Editor/BrainPickerWindow.cs.meta diff --git a/VisualEditor/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs similarity index 100% rename from VisualEditor/Editor/ClusterInspector.cs rename to Editor/ClusterInspector.cs diff --git a/VisualEditor/Editor/ClusterInspector.cs.meta b/Editor/ClusterInspector.cs.meta similarity index 100% rename from VisualEditor/Editor/ClusterInspector.cs.meta rename to Editor/ClusterInspector.cs.meta diff --git a/VisualEditor/Editor/NanoBrain_Editor.cs b/Editor/NanoBrain_Editor.cs similarity index 100% rename from VisualEditor/Editor/NanoBrain_Editor.cs rename to Editor/NanoBrain_Editor.cs diff --git a/VisualEditor/Editor/NanoBrain_Editor.cs.meta b/Editor/NanoBrain_Editor.cs.meta similarity index 100% rename from VisualEditor/Editor/NanoBrain_Editor.cs.meta rename to Editor/NanoBrain_Editor.cs.meta diff --git a/VisualEditor/Resources.meta b/Editor/Resources.meta similarity index 100% rename from VisualEditor/Resources.meta rename to Editor/Resources.meta diff --git a/VisualEditor/Resources/GraphStyles.uss b/Editor/Resources/GraphStyles.uss similarity index 100% rename from VisualEditor/Resources/GraphStyles.uss rename to Editor/Resources/GraphStyles.uss diff --git a/VisualEditor/Resources/GraphStyles.uss.meta b/Editor/Resources/GraphStyles.uss.meta similarity index 100% rename from VisualEditor/Resources/GraphStyles.uss.meta rename to Editor/Resources/GraphStyles.uss.meta diff --git a/VisualEditor/NanoBrain.cs b/NanoBrain.cs similarity index 100% rename from VisualEditor/NanoBrain.cs rename to NanoBrain.cs diff --git a/VisualEditor/NanoBrain.cs.meta b/NanoBrain.cs.meta similarity index 100% rename from VisualEditor/NanoBrain.cs.meta rename to NanoBrain.cs.meta diff --git a/VisualEditor.meta b/VisualEditor.meta deleted file mode 100644 index d012778..0000000 --- a/VisualEditor.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 62a58c801eda0c9eab7a49fb1d0840cb -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/VisualEditor/Editor.meta b/VisualEditor/Editor.meta deleted file mode 100644 index c068f8e..0000000 --- a/VisualEditor/Editor.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: e47ea55fc051fcdcb8ae6197d1105cc0 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: From c290b62637aa43cd5ecaf4641eb5dac8fcfa1cbb Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 4 Feb 2026 11:19:19 +0100 Subject: [PATCH 101/179] Selector is working --- Cluster.cs | 54 +++++------ Editor/ClusterInspector.cs | 35 ++++++- INucleus.cs | 5 +- MemoryCell.cs | 56 +++++------ Neuron.cs | 130 ++++++++++---------------- Receptor.cs | 2 +- Scripts/Experimental/SelectorBrain.cs | 4 +- Selector.cs | 16 +++- 8 files changed, 161 insertions(+), 141 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index 130f0e2..6afd6aa 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -258,27 +258,27 @@ public class Cluster : INucleus { #region Update - public virtual void UpdateState() { - UpdateState(new float3(0, 0, 0)); - } + // public virtual void UpdateState() { + // UpdateState(new float3(0, 0, 0)); + // } - public void UpdateState(float3 bias) { - float3 sum = bias; // new(0, 0, 0); + // public void UpdateState(float3 bias) { + // float3 sum = bias; // new(0, 0, 0); - //Applying the weight factors - foreach (Synapse synapse in this.synapses) { - sum += synapse.weight * synapse.nucleus.outputValue; - } + // //Applying the weight factors + // foreach (Synapse synapse in this.synapses) { + // sum += synapse.weight * synapse.nucleus.outputValue; + // } - //this.inputs[0].UpdateState(sum); - this.inputs[0].UpdateStateIsolated(sum); - foreach (IReceptor receptor in this.sortedNuclei) { - if (receptor is INucleus nucleus && nucleus != this.inputs[0]) - nucleus.UpdateStateIsolated(); - } + // //this.inputs[0].UpdateState(sum); + // this.inputs[0].UpdateStateIsolated(sum); + // foreach (IReceptor receptor in this.sortedNuclei) { + // if (receptor is INucleus nucleus && nucleus != this.inputs[0]) + // nucleus.UpdateStateIsolated(); + // } - UpdateResult(this.output.outputValue); - } + // UpdateResult(this.output.outputValue); + // } public void UpdateStateIsolated() { float3 bias = new(0,0,0); @@ -301,17 +301,17 @@ public class Cluster : INucleus { this.outputValue = this.output.outputValue; } - public virtual void UpdateResult(Vector3 result) { - // float d = Vector3.Distance(result, this.outputValue); - // if (d < 0.5f) { - // //Debug.Log($"insignificant update: {d}"); - // return; - // } + // public virtual void UpdateResult(Vector3 result) { + // // float d = Vector3.Distance(result, this.outputValue); + // // if (d < 0.5f) { + // // //Debug.Log($"insignificant update: {d}"); + // // return; + // // } - this.outputValue = result; - foreach (INucleus receiver in this.receivers) - receiver.UpdateState(); - } + // this.outputValue = result; + // foreach (INucleus receiver in this.receivers) + // receiver.UpdateState(); + // } public void UpdateNuclei() { this.stale++; diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 8e8d4df..6d774c1 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -473,6 +473,7 @@ public class ClusterInspector : Editor { } } + private int selectedInputType = 0; void DrawInspector(VisualElement inspectorContainer) { if (inspectorContainer == null) return; @@ -491,7 +492,7 @@ public class ClusterInspector : Editor { if (this.currentNucleus == null) return; - this.currentNucleus.name = EditorGUILayout.TextField(this.currentNucleus.name); + this.currentNucleus.name = EditorGUILayout.TextField(this.currentNucleus.GetType().ToString(), this.currentNucleus.name); if (this.currentNucleus is Neuron neuroid) { if (this.currentNucleus is MemoryCell memory) { } @@ -551,6 +552,14 @@ public class ClusterInspector : Editor { EditorGUILayout.Space(); ConnectNucleus(this.cluster, this.currentNucleus); + + EditorGUILayout.BeginHorizontal(); + if (GUILayout.Button("Add Input")) + AddInput(selectedInputType, this.currentNucleus); + string[] options = { "Neuron", "MemoryCell", "Selector", "Cluster" }; + selectedInputType = EditorGUILayout.Popup(selectedInputType, options); + EditorGUILayout.EndHorizontal(); + if (GUILayout.Button("Add Input Neuron")) AddInputNeuron(this.currentNucleus); if (GUILayout.Button("Add Input MemoryCell")) @@ -587,6 +596,23 @@ public class ClusterInspector : Editor { } } + protected virtual void AddInput(int selectedInputType, INucleus nucleus) { + switch (selectedInputType) { + case 0: // Neuron + AddInputNeuron(nucleus); + break; + case 1: // MemoryCell + AddInputMemoryCell(nucleus); + break; + case 2: // Selector + AddSelectorInput(nucleus); + break; + case 3: // Cluster + AddCluster(nucleus); + break; + } + } + protected virtual void AddInputNeuron(INucleus nucleus) { Neuron newNeuroid = new(this.cluster, "New neuron"); newNeuroid.AddReceiver(nucleus); @@ -609,6 +635,13 @@ public class ClusterInspector : Editor { BuildLayers(); } + protected void AddSelectorInput(INucleus nucleus) { + Selector newSelector = new(this.cluster, "New Selector"); + newSelector.AddReceiver(nucleus); + this.currentNucleus = newSelector; + BuildLayers(); + } + protected virtual void AddInputMemoryCell(INucleus nucleus) { MemoryCell newMemory = new(this.cluster, "New memory cell"); newMemory.AddReceiver(nucleus); diff --git a/INucleus.cs b/INucleus.cs index 324896d..195e9da 100644 --- a/INucleus.cs +++ b/INucleus.cs @@ -7,6 +7,7 @@ public interface INucleus : IReceptor { // Cluster public ClusterPrefab cluster { get; } + public Cluster parent { get; } // Senders public List synapses { get; } @@ -18,8 +19,8 @@ public interface INucleus : IReceptor { #region dynamic state - public void UpdateState(); - public void UpdateState(float3 inputValue); + // public void UpdateState(); + // public void UpdateState(float3 inputValue); public void UpdateStateIsolated(); public void UpdateStateIsolated(float3 inputValue); diff --git a/MemoryCell.cs b/MemoryCell.cs index 307ac77..643b039 100644 --- a/MemoryCell.cs +++ b/MemoryCell.cs @@ -29,23 +29,23 @@ public class MemoryCell : Neuron, INucleus { private float3 _memorizedValue; private float _memorizedTime; - public override void UpdateState(float3 bias) { - // A memorycell does not have an activation function - float3 result = bias; - int n = 0; + // public override void UpdateState(float3 bias) { + // // A memorycell does not have an activation function + // float3 result = bias; + // int n = 0; - //Applying the weight factgors - foreach (Synapse synapse in this.synapses) { - result += synapse.weight * synapse.nucleus.outputValue; - if (lengthsq(synapse.nucleus.outputValue) != 0) - n++; - } + // //Applying the weight factgors + // foreach (Synapse synapse in this.synapses) { + // result += synapse.weight * synapse.nucleus.outputValue; + // if (lengthsq(synapse.nucleus.outputValue) != 0) + // n++; + // } - if (this.average) - result /= n; + // if (this.average) + // result /= n; - UpdateResult(result); - } + // UpdateResult(result); + // } public override void UpdateStateIsolated() { float3 bias = new(0, 0, 0); @@ -73,22 +73,22 @@ public class MemoryCell : Neuron, INucleus { this._memorizedTime = Time.time; } - public override void UpdateResult(Vector3 result) { - // output value is the previous value - // if (this.deltaValue) { - // float deltaTime = Time.time - this._memorizedTime; - // this._outputValue = this._memorizedValue * deltaTime; - // } - //else - this.outputValue = this._memorizedValue; + // public override void UpdateResult(Vector3 result) { + // // output value is the previous value + // // if (this.deltaValue) { + // // float deltaTime = Time.time - this._memorizedTime; + // // this._outputValue = this._memorizedValue * deltaTime; + // // } + // //else + // this.outputValue = this._memorizedValue; - // Store the result for the next time - this._memorizedValue = result; - this._memorizedTime = Time.time; + // // Store the result for the next time + // this._memorizedValue = result; + // this._memorizedTime = Time.time; - foreach (INucleus receiver in this.receivers) - receiver.UpdateState(); - } + // foreach (INucleus receiver in this.receivers) + // receiver.UpdateState(); + // } #endregion State } diff --git a/Neuron.cs b/Neuron.cs index d6b50c0..270f830 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -191,35 +191,7 @@ public class Neuron : INucleus { }; return clone; } - public virtual IReceptor ShallowCloneTo(ClusterPrefab newParent) { - Neuron clone = new(newParent, this.name) { - array = this.array, - curve = this.curve, - curvePreset = this.curvePreset, - curveMax = this.curveMax, - average = this.average - }; - return clone; - } - public virtual IReceptor CloneTo(ClusterPrefab parent) { - Neuron clone = new(parent, this.name) { - array = this.array, - curve = this.curve, - curvePreset = this.curvePreset, - curveMax = this.curveMax, - average = this.average - }; - - foreach (Synapse synapse in this.synapses) { - Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); - clonedSynapse.weight = synapse.weight; - } - foreach (INucleus receiver in this.receivers) { - clone.AddReceiver(receiver); - } - return clone; - } public virtual IReceptor Clone() { Neuron clone = new(this.cluster, this.name) { array = this.array, @@ -281,48 +253,48 @@ public class Neuron : INucleus { return synapse; } - public virtual void UpdateState() { - //UpdateState(new float3(0, 0, 0)); - this.parent?.UpdateState(); - } + // public virtual void UpdateState() { + // //UpdateState(new float3(0, 0, 0)); + // this.parent?.UpdateState(); + // } - public virtual void UpdateState(float3 inputValue) { - float3 sum = inputValue; - int n = 0; + // public virtual void UpdateState(float3 inputValue) { + // float3 sum = inputValue; + // int n = 0; - //Applying the weight factgors - foreach (Synapse synapse in this.synapses) { - sum += synapse.weight * synapse.nucleus.outputValue; + // //Applying the weight factgors + // foreach (Synapse synapse in this.synapses) { + // sum += synapse.weight * synapse.nucleus.outputValue; - // Perhaps synapses should be removed when the output value goes to 0.... - if (lengthsq(synapse.nucleus.outputValue) != 0) - n++; - } - if (this.average && n > 0) - sum /= n; + // // Perhaps synapses should be removed when the output value goes to 0.... + // if (lengthsq(synapse.nucleus.outputValue) != 0) + // n++; + // } + // if (this.average && n > 0) + // sum /= n; - // Activation function - Vector3 result; - switch (this.curvePreset) { - case CurvePresets.Linear: - result = sum; - break; - case CurvePresets.Sqrt: - result = normalize(sum) * System.MathF.Sqrt(length(sum)); - break; - case CurvePresets.Power: - result = normalize(sum) * System.MathF.Pow(length(sum), 2); - break; - case CurvePresets.Reciprocal: - result = normalize(sum) * (1 / length(sum)); - break; - default: - float activatedValue = this.curve.Evaluate(length(sum)); - result = normalize(sum) * activatedValue; - break; - } - UpdateResult(result); - } + // // Activation function + // Vector3 result; + // switch (this.curvePreset) { + // case CurvePresets.Linear: + // result = sum; + // break; + // case CurvePresets.Sqrt: + // result = normalize(sum) * System.MathF.Sqrt(length(sum)); + // break; + // case CurvePresets.Power: + // result = normalize(sum) * System.MathF.Pow(length(sum), 2); + // break; + // case CurvePresets.Reciprocal: + // result = normalize(sum) * (1 / length(sum)); + // break; + // default: + // float activatedValue = this.curve.Evaluate(length(sum)); + // result = normalize(sum) * activatedValue; + // break; + // } + // UpdateResult(result); + // } public virtual void UpdateStateIsolated() { UpdateStateIsolated(new float3(0, 0, 0)); @@ -368,20 +340,20 @@ public class Neuron : INucleus { this.outputValue = result; } - public virtual void UpdateResult(Vector3 result) { - // float d = Vector3.Distance(result, this.outputValue); - // if (d < 0.5f) { - // //Debug.Log($"insignificant update: {d}"); - // return; - // } + // public virtual void UpdateResult(Vector3 result) { + // // float d = Vector3.Distance(result, this.outputValue); + // // if (d < 0.5f) { + // // //Debug.Log($"insignificant update: {d}"); + // // return; + // // } - this.outputValue = result; - if (lengthsq(outputValue) != 0) { - Debug.Log($"{this.parent.name}.{this.name}: {this.outputValue}"); - } + // this.outputValue = result; + // if (lengthsq(outputValue) != 0) { + // Debug.Log($"{this.parent.name}.{this.name}: {this.outputValue}"); + // } - foreach (INucleus receiver in this.receivers) - receiver.UpdateState(); + // foreach (INucleus receiver in this.receivers) + // receiver.UpdateState(); - } + // } } \ No newline at end of file diff --git a/Receptor.cs b/Receptor.cs index 24bf9a7..7ad1982 100644 --- a/Receptor.cs +++ b/Receptor.cs @@ -179,7 +179,7 @@ public class Receptor : IReceptor { thingIds[selectedReceiverIx] = thingId; // if (thingName != null) // selectedReceiver.nucleus.name = selectedReceiver.nucleus.baseName + " " + thingName; - selectedReceiver.UpdateState(); + selectedReceiver.parent.UpdateStateIsolated(); } public void UpdateNuclei() { diff --git a/Scripts/Experimental/SelectorBrain.cs b/Scripts/Experimental/SelectorBrain.cs index a08dc46..8b40798 100644 --- a/Scripts/Experimental/SelectorBrain.cs +++ b/Scripts/Experimental/SelectorBrain.cs @@ -9,8 +9,8 @@ public class SelectorBrain : NanoBrain { public Receptor receptor2; protected void Awake() { - receptor1 = Receptor.CreateReceptor(this.brain, "Input 1"); - receptor2 = Receptor.CreateReceptor(this.brain, "Input 2"); + receptor1 = Receptor.CreateReceptor(this.brain, "Selector"); + receptor2 = Receptor.CreateReceptor(this.brain, "Selector"); } protected void Update() { diff --git a/Selector.cs b/Selector.cs index 01a2411..cb8a2ec 100644 --- a/Selector.cs +++ b/Selector.cs @@ -1,8 +1,22 @@ +using System; using Unity.Mathematics; using static Unity.Mathematics.math; +[Serializable] public class Selector : Neuron { public Selector(Cluster parent, string name) : base(parent, name) { } + public Selector(ClusterPrefab parent, string name) : base(parent, name) {} + + public override IReceptor ShallowCloneTo(Cluster newParent) { + Selector clone = new(newParent, this.name) { + array = this.array, + curve = this.curve, + curvePreset = this.curvePreset, + curveMax = this.curveMax, + average = this.average + }; + return clone; + } public override void UpdateStateIsolated(float3 bias) { float3 max = bias; @@ -11,7 +25,7 @@ public class Selector : Neuron { //Applying the weight factors foreach (Synapse synapse in this.synapses) { float3 input = synapse.weight * synapse.nucleus.outputValue; - + float inputSqrlength = lengthsq(input); if (inputSqrlength > maxSqrLength) { max = input; From 08f9f3a3b1bb2c7e10a9c8bbbd58071f5bb95152 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 4 Feb 2026 11:53:53 +0100 Subject: [PATCH 102/179] Added initial Ant scene setup --- Selector.asset | 52 ++++++++++---------------------------------------- 1 file changed, 10 insertions(+), 42 deletions(-) diff --git a/Selector.asset b/Selector.asset index 8221c64..a1bfc0c 100644 --- a/Selector.asset +++ b/Selector.asset @@ -14,8 +14,7 @@ MonoBehaviour: m_EditorClassIdentifier: Assembly-CSharp::ClusterPrefab nuclei: - rid: 5479437130421501952 - - rid: 5479437130421501954 - - rid: 5479437130421501956 + - rid: 5479437186280456251 references: version: 2 RefIds: @@ -25,11 +24,8 @@ MonoBehaviour: _name: Output _synapses: - nucleus: - rid: 5479437130421501954 - weight: 0.1 - - nucleus: - rid: 5479437130421501956 - weight: 0.9 + rid: 5479437186280456251 + weight: 1 _receivers: [] _array: rid: 5479437130421501953 @@ -66,16 +62,15 @@ MonoBehaviour: _nuclei: - rid: 5479437130421501952 name: Output - - rid: 5479437130421501954 - type: {class: Neuron, ns: , asm: Assembly-CSharp} + - rid: 5479437186280456251 + type: {class: Selector, ns: , asm: Assembly-CSharp} data: - _name: Input + _name: Selector _synapses: [] _receivers: - rid: 5479437130421501952 - - rid: 5479437130421501956 _array: - rid: 5479437130421501955 + rid: 5479437186280456252 _curvePreset: 0 curve: serializedVersion: 2 @@ -103,36 +98,9 @@ MonoBehaviour: m_RotationOrder: 4 curveMax: 1 average: 0 - - rid: 5479437130421501955 + - rid: 5479437186280456252 type: {class: NucleusArray, ns: , asm: Assembly-CSharp} data: _nuclei: - - rid: 5479437130421501954 - name: New neuron - - rid: 5479437130421501956 - type: {class: MemoryCell, ns: , asm: Assembly-CSharp} - data: - _name: Previous Input - _synapses: - - nucleus: - rid: 5479437130421501954 - weight: 1 - _receivers: - - rid: 5479437130421501952 - _array: - rid: 5479437130421501957 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: [] - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - - rid: 5479437130421501957 - type: {class: NucleusArray, ns: , asm: Assembly-CSharp} - data: - _nuclei: - - rid: 5479437130421501956 - name: New memory cell + - rid: 5479437186280456251 + name: New Selector From 5982c8acfec240d846d5f56cb85e89d72b02da0e Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 4 Feb 2026 12:52:56 +0100 Subject: [PATCH 103/179] Added initial pheromone smell --- Editor/ClusterInspector.cs | 47 ++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 6d774c1..222fd91 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -492,7 +492,20 @@ public class ClusterInspector : Editor { if (this.currentNucleus == null) return; - this.currentNucleus.name = EditorGUILayout.TextField(this.currentNucleus.GetType().ToString(), this.currentNucleus.name); + GUIStyle headerStyle = new GUIStyle(EditorStyles.boldLabel) { + alignment = TextAnchor.MiddleLeft, + margin = new RectOffset(10, 0, 4, 4) + }; + //GUI.backgroundColor = EditorGUIUtility.isProSkin ? new Color(0.15f, 0.15f, 0.15f) : new Color(0.85f, 0.85f, 0.85f); + //GUILayout.BeginVertical("box"); + GUIStyle boldTextFieldStyle = new GUIStyle(EditorStyles.textField) { + fontStyle = FontStyle.Bold + }; + + GUILayout.Label(this.currentNucleus.GetType().ToString(), headerStyle); + //GUILayout.EndVertical(); + //GUI.backgroundColor = Color.white; // Reset background color + this.currentNucleus.name = EditorGUILayout.TextField(this.currentNucleus.name, boldTextFieldStyle); if (this.currentNucleus is Neuron neuroid) { if (this.currentNucleus is MemoryCell memory) { } @@ -554,18 +567,18 @@ public class ClusterInspector : Editor { ConnectNucleus(this.cluster, this.currentNucleus); EditorGUILayout.BeginHorizontal(); - if (GUILayout.Button("Add Input")) - AddInput(selectedInputType, this.currentNucleus); string[] options = { "Neuron", "MemoryCell", "Selector", "Cluster" }; selectedInputType = EditorGUILayout.Popup(selectedInputType, options); + if (GUILayout.Button("Add Input")) + AddInput(selectedInputType, this.currentNucleus); EditorGUILayout.EndHorizontal(); - if (GUILayout.Button("Add Input Neuron")) - AddInputNeuron(this.currentNucleus); - if (GUILayout.Button("Add Input MemoryCell")) - AddInputMemoryCell(this.currentNucleus); - if (GUILayout.Button("Add Input Cluster")) - AddCluster(this.currentNucleus); + // if (GUILayout.Button("Add Input Neuron")) + // AddInputNeuron(this.currentNucleus); + // if (GUILayout.Button("Add Input MemoryCell")) + // AddInputMemoryCell(this.currentNucleus); + // if (GUILayout.Button("Add Input Cluster")) + // AddCluster(this.currentNucleus); EditorGUILayout.Space(); @@ -599,17 +612,17 @@ public class ClusterInspector : Editor { protected virtual void AddInput(int selectedInputType, INucleus nucleus) { switch (selectedInputType) { case 0: // Neuron - AddInputNeuron(nucleus); - break; + AddInputNeuron(nucleus); + break; case 1: // MemoryCell - AddInputMemoryCell(nucleus); - break; + AddInputMemoryCell(nucleus); + break; case 2: // Selector - AddSelectorInput(nucleus); - break; + AddSelectorInput(nucleus); + break; case 3: // Cluster - AddCluster(nucleus); - break; + AddCluster(nucleus); + break; } } From 60e2b3e33fc77f58f3082bfdccc2c6b0a09c9c03 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 4 Feb 2026 15:38:18 +0100 Subject: [PATCH 104/179] Cleanup --- Editor/ClusterInspector.cs | 44 +++++++-------------- Editor/NanoBrain_Editor.cs | 49 ++++++++++++----------- Receptor.cs | 80 +++++++++++++++++++++++--------------- 3 files changed, 87 insertions(+), 86 deletions(-) diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 222fd91..69b1d25 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -22,9 +22,6 @@ public class ClusterInspector : Editor { serializedObject.Update(); VisualElement root = new(); - //root.style.flexDirection = FlexDirection.Row; // side-by-side layout - //root.style.flexGrow = 1; - //root.style.minHeight = 600; root.style.paddingLeft = 0; root.style.paddingRight = 0; root.style.paddingTop = 0; @@ -33,11 +30,8 @@ public class ClusterInspector : Editor { root.styleSheets.Add(Resources.Load("GraphStyles")); mainContainer = new() { - // name = "main", style = { - // flexDirection = FlexDirection.Row, - // flexGrow = 1, - height = 450, + height = 450 } }; GraphView graph = new(); @@ -80,10 +74,6 @@ public class ClusterInspector : Editor { private readonly Dictionary neuroidPositions = new(); private bool expandArray = false; - //Vector2 pan = Vector2.zero; - //float zoom = 1f; - //bool draggingCanvas = false; - //Vector2 lastMouse; ClusterWrapper currentWrapper; public GraphView() { @@ -98,11 +88,6 @@ public class ClusterInspector : Editor { imguiContainer.focusable = true; Add(imguiContainer); - //RegisterCallback(OnWheel); - // RegisterCallback(OnMouseDown); - // RegisterCallback(OnMouseMove); - // RegisterCallback(OnMouseUp); - // Subscribe when added to panel (editor UI ready) RegisterCallback(evt => Subscribe()); RegisterCallback(evt => Unsubscribe()); @@ -249,9 +234,7 @@ public class ClusterInspector : Editor { foreach (INucleus nucleus in this.currentNucleus.array.nuclei) { Vector3 pos = new(150, margin + row * spacing, 0.0f); Handles.color = Color.white; - //Handles.DrawLine(parentPos, pos); - - Handles.color = Color.white; + // The selected nucleus highlight ring Handles.DrawSolidDisc(pos, Vector3.forward, size + 2); DrawNucleus(nucleus, pos, maxValue, size); row++; @@ -266,6 +249,7 @@ public class ClusterInspector : Editor { } else { Handles.color = Color.white; + // The selected nucleus highlight ring Handles.DrawSolidDisc(position, Vector3.forward, size + 2); DrawNucleus(this.currentNucleus, position, length(this.currentNucleus.outputValue), 20); } @@ -726,17 +710,17 @@ public class ClusterInspector : Editor { #region Update private void UpdateLayout(float containerWidth) { - if (containerWidth > 600f) { - mainContainer.style.flexDirection = FlexDirection.Row; - inspectorContainer.style.width = 300; // fixed sidebar width - inspectorContainer.style.flexGrow = 0; - } - else { - mainContainer.style.flexDirection = FlexDirection.Column; - inspectorContainer.style.width = Length.Percent(100); // full width below - inspectorContainer.style.flexDirection = FlexDirection.Column; - inspectorContainer.style.flexGrow = 1; // can set 0 or keep as needed - } + // if (containerWidth > 600f) { + mainContainer.style.flexDirection = FlexDirection.Row; + inspectorContainer.style.width = 300; // fixed sidebar width + inspectorContainer.style.flexGrow = 0; + // } + // else { + // mainContainer.style.flexDirection = FlexDirection.Column; + // inspectorContainer.style.width = Length.Percent(100); // full width below + // inspectorContainer.style.flexDirection = FlexDirection.Column; + // inspectorContainer.style.flexGrow = 1; // can set 0 or keep as needed + // } } #endregion Update diff --git a/Editor/NanoBrain_Editor.cs b/Editor/NanoBrain_Editor.cs index 2710e62..f4cd22b 100644 --- a/Editor/NanoBrain_Editor.cs +++ b/Editor/NanoBrain_Editor.cs @@ -22,7 +22,6 @@ public class NanoBrainComponent_Editor : Editor { } public override VisualElement CreateInspectorGUI() { - //ClusterPrefab brain = Application.isPlaying ? component.brain.prefab : component.defaultBrain; Cluster brain = component.brain; if (Application.isPlaying == false) @@ -93,37 +92,37 @@ public class NanoBrainComponent_Editor : Editor { // board.OnIMGUI(); // } - void OnSceneGui(SceneView sv) { - if (Application.isPlaying == false) - return; - // May need some throttling here... - if (board != null) { - Debug.Log("."); - board.OnIMGUI(); - } + // void OnSceneGui(SceneView sv) { + // if (Application.isPlaying == false) + // return; + // // May need some throttling here... + // if (board != null) { + // Debug.Log("."); + // board.OnIMGUI(); + // } - // EditorApplication.delayCall = UpdateInspectorUI; - } + // // EditorApplication.delayCall = UpdateInspectorUI; + // } - void UpdateInspectorUI() { - if (board != null) { - Debug.Log("."); - board.OnIMGUI(); - } - } + // void UpdateInspectorUI() { + // if (board != null) { + // Debug.Log("."); + // board.OnIMGUI(); + // } + // } private void UpdateLayout(float containerWidth) { - if (containerWidth > 800f) { + // if (containerWidth > 800f) { mainContainer.style.flexDirection = FlexDirection.Row; inspectorContainer.style.width = 400; // fixed sidebar width inspectorContainer.style.flexGrow = 0; - } - else { - mainContainer.style.flexDirection = FlexDirection.Column; - inspectorContainer.style.width = Length.Percent(100); // full width below - inspectorContainer.style.flexDirection = FlexDirection.Column; - inspectorContainer.style.flexGrow = 1; // can set 0 or keep as needed - } + // } + // else { + // mainContainer.style.flexDirection = FlexDirection.Column; + // inspectorContainer.style.width = Length.Percent(100); // full width below + // inspectorContainer.style.flexDirection = FlexDirection.Column; + // inspectorContainer.style.flexGrow = 1; // can set 0 or keep as needed + // } } } \ No newline at end of file diff --git a/Receptor.cs b/Receptor.cs index 7ad1982..c7b544b 100644 --- a/Receptor.cs +++ b/Receptor.cs @@ -27,47 +27,60 @@ public class Receptor : IReceptor { cluster.nuclei.Add(this); } - public Receptor(ClusterPrefab cluster, INucleus nucleus) { - this.cluster = cluster; - if (cluster != null) - cluster.nuclei.Add(this); - this.AddReceiver(nucleus); - } + // public Receptor(ClusterPrefab cluster, INucleus nucleus) { + // this.cluster = cluster; + // if (cluster != null) + // cluster.nuclei.Add(this); + // this.AddReceiver(nucleus); + // } + public Receptor(Cluster parent, string name, string nucleusName) { + this.parent = parent ?? throw new ArgumentNullException(nameof(parent), "Parent cannot be null."); - public static Receptor CreateReceptor(Cluster cluster, string nucleusName) { - if (cluster == null) - return null; - - Receptor receptor = new(cluster); - foreach (INucleus nucleus in cluster.inputs) { + this.name = name; + this.parent.nuclei.Add(this); + foreach (INucleus nucleus in parent.inputs) { if (nucleus != null && nucleus.name == nucleusName) { - receptor.AddReceiver(nucleus); + this.AddReceiver(nucleus); } } - if (receptor._receivers.Count == 0) - return null; - else - return receptor; + } + + [Obsolete("This method is deprecated. Use Receptor() constructor instead.")] + public static Receptor CreateReceptor(Cluster cluster, string nucleusName) { + return new Receptor(cluster, "Receptor", nucleusName); + // if (cluster == null) + // return null; + + // Receptor receptor = new(cluster); + // foreach (INucleus nucleus in cluster.inputs) { + // if (nucleus != null && nucleus.name == nucleusName) { + // receptor.AddReceiver(nucleus); + // } + // } + // if (receptor._receivers.Count == 0) + // return null; + // else + // return receptor; } public virtual IReceptor ShallowCloneTo(Cluster parent) { Receptor clone = new(parent); return clone; } - public virtual IReceptor ShallowCloneTo(ClusterPrefab parent) { - Receptor clone = new(parent); - return clone; - } + // public virtual IReceptor ShallowCloneTo(ClusterPrefab parent) { + // Receptor clone = new(parent); + // return clone; + // } - public virtual IReceptor CloneTo(ClusterPrefab parent) { - Receptor clone = new(parent); + // public virtual IReceptor CloneTo(ClusterPrefab parent) { + // Receptor clone = new(parent); - foreach (INucleus receiver in this.receivers) { - clone.AddReceiver(receiver); - } + // foreach (INucleus receiver in this.receivers) { + // clone.AddReceiver(receiver); + // } - return clone; - } + // return clone; + // } public virtual IReceptor Clone() { Receptor clone = new(this.cluster); @@ -175,10 +188,15 @@ public class Receptor : IReceptor { } receiverIx++; } - // Debug.Log($"Receiver {selectedReceiver.name}[{selectedReceiverIx}] for thing {thingId}"); + Debug.Log($"Receiver {selectedReceiver.name}[{selectedReceiverIx}] for thing {thingId}"); thingIds[selectedReceiverIx] = thingId; - // if (thingName != null) - // selectedReceiver.nucleus.name = selectedReceiver.nucleus.baseName + " " + thingName; + if (thingName != null) { + string baseName = selectedReceiver.name; + int colonPos = selectedReceiver.name.IndexOf(":"); + if (colonPos > 0) + baseName = selectedReceiver.name.Substring(0, colonPos); + selectedReceiver.name = baseName + ": " + thingName; + } selectedReceiver.parent.UpdateStateIsolated(); } From 3cc5f56f61b892f2be19a72d99ecba0719ff80d3 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 4 Feb 2026 17:42:16 +0100 Subject: [PATCH 105/179] WIP: cloning of nucleusarrays is not working yet --- Cluster.cs | 48 ++++++++++++++++++++++++++++++-------- Editor/ClusterInspector.cs | 23 +++++++++++------- NanoBrain.cs | 19 +++++++++------ Neuron.cs | 2 +- NucleusArray.cs | 33 +++++++++++++------------- Receptor.cs | 10 +++++--- 6 files changed, 89 insertions(+), 46 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index 6afd6aa..5f85b04 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using UnityEngine; using Unity.Mathematics; using static Unity.Mathematics.math; @@ -51,22 +52,22 @@ public class Cluster : INucleus { // } private void ClonePrefab() { - IReceptor[] nucleiArray = this.prefab.nuclei.ToArray(); + IReceptor[] nuclei = this.prefab.nuclei.ToArray(); // first clone the nuclei without their connections foreach (IReceptor nucleus in this.prefab.nuclei) nucleus.ShallowCloneTo(this); IReceptor[] clonedNuclei = this.nuclei.ToArray(); // Now clone the connections - for (int nucleusIx = 0; nucleusIx < nucleiArray.Length; nucleusIx++) { - IReceptor receptor = nucleiArray[nucleusIx]; + for (int nucleusIx = 0; nucleusIx < nuclei.Length; nucleusIx++) { + IReceptor receptor = nuclei[nucleusIx]; IReceptor clonedSender = clonedNuclei[nucleusIx]; if (clonedSender == null) continue; // Copy the receivers, which will also create the synapses foreach (INucleus receiver in receptor.receivers) { - int ix = GetNucleusIndex(nucleiArray, receiver); + int ix = GetNucleusIndex(nuclei, receiver); if (ix < 0) continue; @@ -75,15 +76,42 @@ public class Cluster : INucleus { // Find the synapse for the weight float weight = 1; + NucleusArray nucleusArray = null; foreach (Synapse synapse in receiver.synapses) { - if (synapse.nucleus == receptor) { + if (synapse.nucleus == receptor) weight = synapse.weight; - break; + if (synapse.nucleus is INucleus synapseNucleus) { + if (synapseNucleus.array != null && synapseNucleus.array.nuclei.Length > 0) { + if (nucleusArray == null) { + // copy the array + nucleusArray = new NucleusArray(synapseNucleus.array.nuclei.Length, "array"); + for (int arrayIx = 0; arrayIx < synapseNucleus.array.nuclei.Length; arrayIx++) { + IReceptor arrayNucleus = synapseNucleus.array.nuclei[arrayIx]; + int ix2 = GetNucleusIndex(nuclei, arrayNucleus); + nucleusArray.nuclei[arrayIx] = clonedNuclei[ix2]; + } + } + synapseNucleus.array = nucleusArray; + } } } clonedSender.AddReceiver(clonedReceiver, weight); } + + // if (receptor is INucleus nucleus) { + // if (clonedSender is not INucleus clonedNucleus) { + // Debug.LogError("INucleus clone is not an INucleus!"); + // continue; + // } + // clonedNucleus.array = new NucleusArray(nucleus.array._nuclei.Length, "array"); + // for (int arrayIx = 0; arrayIx < nucleus.array._nuclei.Length; arrayIx++) { + // //foreach (INucleus arrayNucleus in nucleus.array.nuclei) { + // IReceptor arrayNucleus = nucleus.array._nuclei[arrayIx]; + // int ix = GetNucleusIndex(nuclei, arrayNucleus); + // clonedNucleus.array._nuclei[arrayIx] = clonedNuclei[ix]; + // } + // } } } @@ -96,13 +124,13 @@ public class Cluster : INucleus { // Calculate in-degrees foreach (IReceptor node in nodes) { foreach (INucleus receiver in node.receivers) - inDegree[receiver]++; + inDegree[receiver]++; } Queue queue = new(); foreach (IReceptor node in nodes) { if (inDegree[node] == 0) // Nodes with no dependencies - queue.Enqueue(node); + queue.Enqueue(node); } List sortedOrder = new(); @@ -119,7 +147,7 @@ public class Cluster : INucleus { // Check for cycles in the graph if (sortedOrder.Count != nodes.Count) - throw new InvalidOperationException("Graph is not a DAG; a cycle exists."); + throw new InvalidOperationException("Graph is not a DAG; a cycle exists."); return sortedOrder; } @@ -281,7 +309,7 @@ public class Cluster : INucleus { // } public void UpdateStateIsolated() { - float3 bias = new(0,0,0); + float3 bias = new(0, 0, 0); UpdateStateIsolated(bias); } public void UpdateStateIsolated(float3 bias) { diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 69b1d25..0d84576 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -210,7 +210,7 @@ public class ClusterInspector : Editor { // Draw selected Nucleus if (expandArray) { float maxValue = 0; - foreach (INucleus nucleus in this.currentNucleus.array.nuclei) { + foreach (IReceptor nucleus in this.currentNucleus.array.nuclei) { float value = length(nucleus.outputValue); if (value > maxValue) maxValue = value; @@ -231,7 +231,7 @@ public class ClusterInspector : Editor { Handles.color = Color.black; Handles.DrawAAConvexPolygon(verts); int row = 0; - foreach (INucleus nucleus in this.currentNucleus.array.nuclei) { + foreach (IReceptor nucleus in this.currentNucleus.array.nuclei) { Vector3 pos = new(150, margin + row * spacing, 0.0f); Handles.color = Color.white; // The selected nucleus highlight ring @@ -239,13 +239,13 @@ public class ClusterInspector : Editor { DrawNucleus(nucleus, pos, maxValue, size); row++; } - GUIStyle style = new(EditorStyles.label) { - alignment = TextAnchor.UpperCenter, - normal = { textColor = Color.white }, - fontStyle = FontStyle.Bold, - }; - Vector3 labelPos = new Vector3(150, yMax, 0) - Vector3.down * (size + 10); // below disc along up axis - Handles.Label(labelPos, this.currentNucleus.name, style); + // GUIStyle style = new(EditorStyles.label) { + // alignment = TextAnchor.UpperCenter, + // normal = { textColor = Color.white }, + // fontStyle = FontStyle.Bold, + // }; + // Vector3 labelPos = new Vector3(150, yMax, 0) - Vector3.down * (size + 25); // below disc along up axis + // Handles.Label(labelPos, this.currentNucleus.name, style); } else { Handles.color = Color.white; @@ -274,7 +274,12 @@ public class ClusterInspector : Editor { float margin = 10 + spacing / 2; int row = 0; + List drawnArrays = new(); foreach (INucleus receiver in nucleus.receivers) { + if (drawnArrays.Contains(receiver.array)) + continue; + drawnArrays.Add(receiver.array); + INucleus receiverNucleus = receiver; if (receiverNucleus == null) continue; diff --git a/NanoBrain.cs b/NanoBrain.cs index e368369..5fc7643 100644 --- a/NanoBrain.cs +++ b/NanoBrain.cs @@ -13,17 +13,22 @@ public class NanoBrain : MonoBehaviour { name = defaultBrain.name + " (Instance)" }; } - SwarmControl sc = FindFirstObjectByType(); - if (sc != null) { - UpdateWeight(brainInstance, "Containment", sc.containmentForce); - UpdateWeight(brainInstance, "Cohesion", sc.cohesionForce); - UpdateWeight(brainInstance, "Separation", sc.separationForce); - UpdateWeight(brainInstance, "Alignment", sc.alignmentForce); - } + // SwarmControl sc = FindFirstObjectByType(); + // if (sc != null) { + // UpdateWeight(brainInstance, "Containment", sc.containmentForce); + // UpdateWeight(brainInstance, "Cohesion", sc.cohesionForce); + // UpdateWeight(brainInstance, "Separation", sc.separationForce); + // UpdateWeight(brainInstance, "Alignment", sc.alignmentForce); + // } return brainInstance; } } + // public void Awake() { + // brainInstance = new Cluster(defaultBrain); + // } + + public static void UpdateWeight(Cluster brain, string name, float weight) { INucleus root = brain.output; foreach (Synapse synapse in root.synapses) { diff --git a/Neuron.cs b/Neuron.cs index 270f830..6e33f4a 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -183,7 +183,7 @@ public class Neuron : INucleus { // this clone the nucleus without the synapses and receivers public virtual IReceptor ShallowCloneTo(Cluster newParent) { Neuron clone = new(newParent, this.name) { - array = this.array, + array = null, curve = this.curve, curvePreset = this.curvePreset, curveMax = this.curveMax, diff --git a/NucleusArray.cs b/NucleusArray.cs index 82a3b0e..bcccf49 100644 --- a/NucleusArray.cs +++ b/NucleusArray.cs @@ -5,16 +5,11 @@ using UnityEngine; [System.Serializable] public class NucleusArray { [SerializeReference] - private INucleus[] _nuclei; - private ClusterPrefab[] _clusters; - public IEnumerable nuclei { + private IReceptor[] _nuclei; + //private ClusterPrefab[] _clusters; + public IReceptor[] nuclei { get { - // if (_nuclei == null) - // return _clusters; - // else if (_clusters == null) - return _nuclei; - // else - // return _nuclei.Concat(_clusters); + return _nuclei; } } public string name; @@ -23,14 +18,19 @@ public class NucleusArray { this.name = nucleus.name; this._nuclei = new INucleus[1]; this._nuclei[0] = nucleus; - this._clusters = new ClusterPrefab[0]; + //this._clusters = new ClusterPrefab[0]; } public NucleusArray(ClusterPrefab cluster) { this.name = cluster.name; this._nuclei = new INucleus[0]; - this._clusters = new ClusterPrefab[1]; - this._clusters[0] = cluster; + // this._clusters = new ClusterPrefab[1]; + // this._clusters[0] = cluster; } + public NucleusArray(int size, string name) { + this.name = name; + this._nuclei = new INucleus[size]; + } + public void AddNucleus() { if (this._nuclei.Length == 0) { @@ -38,12 +38,12 @@ public class NucleusArray { return; } int newLength = this._nuclei.Length + 1; - INucleus[] newArray = new INucleus[newLength]; + IReceptor[] newArray = new INucleus[newLength]; for (int i = 0; i < this._nuclei.Length; i++) newArray[i] = this._nuclei[i]; if (this._nuclei[0] is INucleus nucleus) - newArray[newLength - 1] = (INucleus) nucleus.Clone(); + newArray[newLength - 1] = (INucleus)nucleus.Clone(); this._nuclei = newArray; } @@ -54,11 +54,12 @@ public class NucleusArray { Debug.LogWarning("Perceptoid array cannot be empty"); return; } - INucleus[] newPerceptei = new INucleus[newLength]; + IReceptor[] newPerceptei = new INucleus[newLength]; for (int i = 0; i < newLength; i++) newPerceptei[i] = this._nuclei[i]; // Delete the last perception - Neuron.Delete(this._nuclei[newLength]); + if (this._nuclei[newLength] is INucleus nucleus) + Neuron.Delete(nucleus); //this._nuclei[newLength]); this._nuclei = newPerceptei; } diff --git a/Receptor.cs b/Receptor.cs index c7b544b..cf99794 100644 --- a/Receptor.cs +++ b/Receptor.cs @@ -6,8 +6,6 @@ using static Unity.Mathematics.math; public class Receptor : IReceptor { - private ClusterPrefab cluster; - private Cluster parent; [SerializeField] protected string _name; @@ -63,6 +61,9 @@ public class Receptor : IReceptor { // return receptor; } + private ClusterPrefab cluster; + private Cluster parent; + public virtual IReceptor ShallowCloneTo(Cluster parent) { Receptor clone = new(parent); return clone; @@ -188,7 +189,9 @@ public class Receptor : IReceptor { } receiverIx++; } - Debug.Log($"Receiver {selectedReceiver.name}[{selectedReceiverIx}] for thing {thingId}"); + if (selectedReceiverIx >= thingIds.Length) + return; + thingIds[selectedReceiverIx] = thingId; if (thingName != null) { string baseName = selectedReceiver.name; @@ -197,6 +200,7 @@ public class Receptor : IReceptor { baseName = selectedReceiver.name.Substring(0, colonPos); selectedReceiver.name = baseName + ": " + thingName; } + Debug.Log($"Receiver {selectedReceiver.name}[{selectedReceiverIx}] for thing {thingId}"); selectedReceiver.parent.UpdateStateIsolated(); } From 16f0c3d3bf5c09fcd9fa9cd1e50d848984690f31 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 5 Feb 2026 12:16:37 +0100 Subject: [PATCH 106/179] NucleusArray cloning seems to work --- Cluster.cs | 86 +++++++++++++---- Neuron.cs | 128 +++++++++++++------------- Nucleus.cs | 105 +++++++++++++++++++++ Nucleus.cs.meta | 2 + Scripts/Experimental/SelectorBrain.cs | 4 +- 5 files changed, 241 insertions(+), 84 deletions(-) create mode 100644 Nucleus.cs create mode 100644 Nucleus.cs.meta diff --git a/Cluster.cs b/Cluster.cs index 5f85b04..3d601db 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -61,8 +61,8 @@ public class Cluster : INucleus { // Now clone the connections for (int nucleusIx = 0; nucleusIx < nuclei.Length; nucleusIx++) { IReceptor receptor = nuclei[nucleusIx]; - IReceptor clonedSender = clonedNuclei[nucleusIx]; - if (clonedSender == null) + IReceptor clonedReceptor = clonedNuclei[nucleusIx]; + if (clonedReceptor == null) continue; // Copy the receivers, which will also create the synapses @@ -76,27 +76,49 @@ public class Cluster : INucleus { // Find the synapse for the weight float weight = 1; - NucleusArray nucleusArray = null; + //NucleusArray clonedNucleusArray = null; foreach (Synapse synapse in receiver.synapses) { + // Find the weight for this synapse if (synapse.nucleus == receptor) weight = synapse.weight; - if (synapse.nucleus is INucleus synapseNucleus) { - if (synapseNucleus.array != null && synapseNucleus.array.nuclei.Length > 0) { - if (nucleusArray == null) { - // copy the array - nucleusArray = new NucleusArray(synapseNucleus.array.nuclei.Length, "array"); - for (int arrayIx = 0; arrayIx < synapseNucleus.array.nuclei.Length; arrayIx++) { - IReceptor arrayNucleus = synapseNucleus.array.nuclei[arrayIx]; - int ix2 = GetNucleusIndex(nuclei, arrayNucleus); - nucleusArray.nuclei[arrayIx] = clonedNuclei[ix2]; - } - } - synapseNucleus.array = nucleusArray; - } - } + + // if (synapse.nucleus is INucleus synapseNucleus) { + // if (synapseNucleus.array != null && synapseNucleus.array.nuclei.Length > 0) { + // Debug.Log("Clone: Nucleus array"); + // if (clonedNucleusArray == null) { + // // copy the array + // clonedNucleusArray = new NucleusArray(synapseNucleus.array.nuclei.Length, "array"); + // for (int arrayIx = 0; arrayIx < synapseNucleus.array.nuclei.Length; arrayIx++) { + // IReceptor arrayNucleus = synapseNucleus.array.nuclei[arrayIx]; + // int ix2 = GetNucleusIndex(nuclei, arrayNucleus); + // clonedNucleusArray.nuclei[arrayIx] = clonedNuclei[ix2]; + // } + // } + // synapseNucleus.array = clonedNucleusArray; + // } + // } } - clonedSender.AddReceiver(clonedReceiver, weight); + clonedReceptor.AddReceiver(clonedReceiver, weight); + // Nucleus clonedNucleus = clonedReceptor as Nucleus; + // if (clonedNucleus is not null) { + // Synapse clonedSynapse = clonedNucleus.GetSynapse(clonedReceiver); + // if (clonedSynapse.nucleus is INucleus synapseNucleus) { + // if (synapseNucleus.array != null && synapseNucleus.array.nuclei.Length > 0) { + // Debug.Log("Clone: Nucleus array"); + // if (clonedNucleusArray == null) { + // // copy the array + // clonedNucleusArray = new NucleusArray(synapseNucleus.array.nuclei.Length, "array"); + // for (int arrayIx = 0; arrayIx < synapseNucleus.array.nuclei.Length; arrayIx++) { + // IReceptor arrayNucleus = synapseNucleus.array.nuclei[arrayIx]; + // int ix2 = GetNucleusIndex(nuclei, arrayNucleus); + // clonedNucleusArray.nuclei[arrayIx] = clonedNuclei[ix2]; + // } + // } + // synapseNucleus.array = clonedNucleusArray; + // } + // } + // } } // if (receptor is INucleus nucleus) { @@ -113,6 +135,34 @@ public class Cluster : INucleus { // } // } } + for (int nucleusIx = 0; nucleusIx < nuclei.Length; nucleusIx++) { + IReceptor prefabReceptor = nuclei[nucleusIx]; + if (prefabReceptor is not INucleus prefabNucleus) + continue; + + if (prefabNucleus.array == null || prefabNucleus.array.nuclei == null || prefabNucleus.array.nuclei.Length == 0) + continue; + + INucleus clonedNucleus = clonedNuclei[nucleusIx] as INucleus; + if (prefabNucleus == prefabNucleus.array.nuclei[0]) { + // We clone the array only for the first entry + NucleusArray clonedArray = new(prefabNucleus.array.nuclei.Length, "array"); + int arrayIx = 0; + foreach (IReceptor prefabArrayNucleus in prefabNucleus.array.nuclei) { + int arrayNucleusIx = GetNucleusIndex(nuclei, prefabArrayNucleus); + IReceptor clonedArrayNucleus = clonedNuclei[arrayNucleusIx]; + clonedArray.nuclei[arrayIx] = clonedArrayNucleus; + arrayIx++; + } + clonedNucleus.array = clonedArray; + } + else { + // The others will refer to the array created for the first nucleus in the array + int firstNucleusIx = GetNucleusIndex(nuclei, prefabNucleus.array.nuclei[0]); + INucleus clonedFirstNucleus = clonedNuclei[firstNucleusIx] as INucleus; + clonedNucleus.array = clonedFirstNucleus.array; + } + } } // Sort the nuclei in a correct evaluation order diff --git a/Neuron.cs b/Neuron.cs index 6e33f4a..742817c 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -7,7 +7,7 @@ using Unity.Mathematics; using static Unity.Mathematics.math; [Serializable] -public class Neuron : INucleus { +public class Neuron : Nucleus, INucleus { public Neuron(Cluster parent, string name) { this.parent = parent; @@ -24,30 +24,30 @@ public class Neuron : INucleus { // Debug.LogError("No neuroid network"); } - [SerializeField] - protected string _name; - public virtual string name { - get => _name; - set => _name = value; - } + // [SerializeField] + // protected string _name; + // public virtual string name { + // get => _name; + // set => _name = value; + // } - [SerializeField] - private List _synapses = new(); - public List synapses => _synapses; + // [SerializeField] + // private List _synapses = new(); + // public List synapses => _synapses; - [SerializeReference] - private List _receivers = new(); - public List receivers { - get { return _receivers; } - set { _receivers = value; } - } + // [SerializeReference] + // private List _receivers = new(); + // public List receivers { + // get { return _receivers; } + // set { _receivers = value; } + // } - [SerializeReference] - private NucleusArray _array; - public NucleusArray array { - get { return _array; } - set { _array = value; } - } + // [SerializeReference] + // private NucleusArray _array; + // public NucleusArray array { + // get { return _array; } + // set { _array = value; } + // } #region Serialization @@ -102,8 +102,8 @@ public class Neuron : INucleus { #region Runtime state (not serialized) - public ClusterPrefab cluster { get; set; } - public Cluster parent { get; set; } + // public ClusterPrefab cluster { get; set; } + // public Cluster parent { get; set; } #region Activation @@ -153,35 +153,35 @@ public class Neuron : INucleus { #endregion Activation - protected float3 _outputValue; - public virtual float3 outputValue { - get { return _outputValue; } - set { - this.stale = 0; - // this._isSleeping = false; - _outputValue = value; - } - } + // protected float3 _outputValue; + // public virtual float3 outputValue { + // get { return _outputValue; } + // set { + // this.stale = 0; + // // this._isSleeping = false; + // _outputValue = value; + // } + // } - [NonSerialized] - private int stale = 1000; + // [NonSerialized] + // private int stale = 1000; // private bool _isSleeping = false; // public bool isSleeping => _isSleeping; - public bool isSleeping => lengthsq(this.outputValue) == 0; + // public bool isSleeping => lengthsq(this.outputValue) == 0; - public void UpdateNuclei() { - this.stale++; - // this._isSleeping = this.stale > 2; - // if (isSleeping) - if (this.stale > 2) - _outputValue = Vector3.zero; - } + // public void UpdateNuclei() { + // this.stale++; + // // this._isSleeping = this.stale > 2; + // // if (isSleeping) + // if (this.stale > 2) + // _outputValue = Vector3.zero; + // } #endregion Runtime state // this clone the nucleus without the synapses and receivers - public virtual IReceptor ShallowCloneTo(Cluster newParent) { + public override IReceptor ShallowCloneTo(Cluster newParent) { Neuron clone = new(newParent, this.name) { array = null, curve = this.curve, @@ -192,7 +192,7 @@ public class Neuron : INucleus { return clone; } - public virtual IReceptor Clone() { + public override IReceptor Clone() { Neuron clone = new(this.cluster, this.name) { array = this.array, curve = this.curve, @@ -213,22 +213,22 @@ public class Neuron : INucleus { return clone; } - public virtual void AddReceiver(INucleus receivingNucleus, float weight = 1) { - this._receivers.Add(receivingNucleus); - receivingNucleus.AddSynapse(this, weight); - } + // public virtual void AddReceiver(INucleus receivingNucleus, float weight = 1) { + // this._receivers.Add(receivingNucleus); + // receivingNucleus.AddSynapse(this, weight); + // } - public void RemoveReceiver(INucleus receiverNucleus) { - this._receivers.RemoveAll(receiver => receiver == receiverNucleus); - receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); - } + // public void RemoveReceiver(INucleus receiverNucleus) { + // this._receivers.RemoveAll(receiver => receiver == receiverNucleus); + // receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); + // } public static void Delete(INucleus nucleus) { foreach (Synapse synapse in nucleus.synapses) { if (synapse.nucleus is Neuron synapse_nucleus) { - if (synapse_nucleus._receivers.Count > 1) { + if (synapse_nucleus.receivers.Count > 1) { // there is another nucleus feeding into this input nucleus - synapse_nucleus._receivers.RemoveAll(r => r == nucleus); + synapse_nucleus.receivers.RemoveAll(r => r == nucleus); } else { // No other links, delete it. @@ -247,11 +247,11 @@ public class Neuron : INucleus { } } - public Synapse AddSynapse(IReceptor sendingNucleus, float weight = 1.0f) { - Synapse synapse = new(sendingNucleus, weight); - this.synapses.Add(synapse); - return synapse; - } + // public Synapse AddSynapse(IReceptor sendingNucleus, float weight = 1.0f) { + // Synapse synapse = new(sendingNucleus, weight); + // this.synapses.Add(synapse); + // return synapse; + // } // public virtual void UpdateState() { // //UpdateState(new float3(0, 0, 0)); @@ -296,10 +296,10 @@ public class Neuron : INucleus { // UpdateResult(result); // } - public virtual void UpdateStateIsolated() { - UpdateStateIsolated(new float3(0, 0, 0)); - } - public virtual void UpdateStateIsolated(float3 bias) { + // public virtual void UpdateStateIsolated() { + // UpdateStateIsolated(new float3(0, 0, 0)); + // } + public override void UpdateStateIsolated(float3 bias) { float3 sum = bias; int n = 0; diff --git a/Nucleus.cs b/Nucleus.cs new file mode 100644 index 0000000..f7ac9ac --- /dev/null +++ b/Nucleus.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using Unity.Mathematics; +using static Unity.Mathematics.math; + +public abstract class Nucleus : IReceptor { + [SerializeField] + protected string _name; + public virtual string name { + get => _name; + set => _name = value; + } + + //[Obsolete] + public ClusterPrefab cluster { get; set; } + public Cluster parent { get; set; } + + protected float3 _outputValue; + public virtual float3 outputValue { + get { return _outputValue; } + set { + this.stale = 0; + // this._isSleeping = false; + _outputValue = value; + } + } + + public bool isSleeping => lengthsq(this.outputValue) == 0; + [NonSerialized] + private int stale = 1000; + + // Cannot clone an abstract nucleus... + public virtual IReceptor ShallowCloneTo(Cluster parent) { return null; } + // Cannot clone an abstract nucleus... + public virtual IReceptor Clone() { return null; } + + #region Synapses + + [SerializeField] + private List _synapses = new(); + public List synapses => _synapses; + + public Synapse AddSynapse(IReceptor sendingNucleus, float weight = 1.0f) { + Synapse synapse = new(sendingNucleus, weight); + this.synapses.Add(synapse); + return synapse; + } + + public Synapse GetSynapse(INucleus sender) { + foreach (Synapse synapse in this.synapses) + if (synapse.nucleus == sender) + return synapse; + return null; + } + + #endregion Synapses + + #region Receivers + + [SerializeReference] + private List _receivers = new(); + public List receivers { + get { return _receivers; } + set { _receivers = value; } + } + + public virtual void AddReceiver(INucleus receivingNucleus, float weight = 1) { + this._receivers.Add(receivingNucleus); + receivingNucleus.AddSynapse(this, weight); + } + + public void RemoveReceiver(INucleus receiverNucleus) { + this._receivers.RemoveAll(receiver => receiver == receiverNucleus); + receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); + } + + + #endregion Receivers + + [SerializeReference] + private NucleusArray _array; + public NucleusArray array { + get { return _array; } + set { _array = value; } + } + + #region Update + + public virtual void UpdateStateIsolated() { + UpdateStateIsolated(new float3(0, 0, 0)); + } + + public virtual void UpdateStateIsolated(float3 bias) { + } + + public void UpdateNuclei() { + this.stale++; + if (this.stale > 2) + _outputValue = Vector3.zero; + } + + #endregion Update + +} \ No newline at end of file diff --git a/Nucleus.cs.meta b/Nucleus.cs.meta new file mode 100644 index 0000000..08b3cf8 --- /dev/null +++ b/Nucleus.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 4310eea6ab77628b085387a226c1c386 \ No newline at end of file diff --git a/Scripts/Experimental/SelectorBrain.cs b/Scripts/Experimental/SelectorBrain.cs index 8b40798..7ea01b6 100644 --- a/Scripts/Experimental/SelectorBrain.cs +++ b/Scripts/Experimental/SelectorBrain.cs @@ -9,8 +9,8 @@ public class SelectorBrain : NanoBrain { public Receptor receptor2; protected void Awake() { - receptor1 = Receptor.CreateReceptor(this.brain, "Selector"); - receptor2 = Receptor.CreateReceptor(this.brain, "Selector"); + receptor1 = new Receptor(this.brain, "Receptor", "Selector"); + receptor2 = new Receptor(this.brain, "Receptor", "Selector"); } protected void Update() { From b73b28146cad3818ffa2324e9808da5c7d723add Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 5 Feb 2026 12:52:13 +0100 Subject: [PATCH 107/179] WIP: all array elements share the same receptor (value) --- Cluster.cs | 56 ++++---------------------------------- Editor/ClusterInspector.cs | 4 +-- Receptor.cs | 51 ++-------------------------------- 3 files changed, 10 insertions(+), 101 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index 3d601db..82faa5d 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -76,65 +76,19 @@ public class Cluster : INucleus { // Find the synapse for the weight float weight = 1; - //NucleusArray clonedNucleusArray = null; foreach (Synapse synapse in receiver.synapses) { // Find the weight for this synapse - if (synapse.nucleus == receptor) + if (synapse.nucleus == receptor) { weight = synapse.weight; - - // if (synapse.nucleus is INucleus synapseNucleus) { - // if (synapseNucleus.array != null && synapseNucleus.array.nuclei.Length > 0) { - // Debug.Log("Clone: Nucleus array"); - // if (clonedNucleusArray == null) { - // // copy the array - // clonedNucleusArray = new NucleusArray(synapseNucleus.array.nuclei.Length, "array"); - // for (int arrayIx = 0; arrayIx < synapseNucleus.array.nuclei.Length; arrayIx++) { - // IReceptor arrayNucleus = synapseNucleus.array.nuclei[arrayIx]; - // int ix2 = GetNucleusIndex(nuclei, arrayNucleus); - // clonedNucleusArray.nuclei[arrayIx] = clonedNuclei[ix2]; - // } - // } - // synapseNucleus.array = clonedNucleusArray; - // } - // } + break; + } } clonedReceptor.AddReceiver(clonedReceiver, weight); - // Nucleus clonedNucleus = clonedReceptor as Nucleus; - // if (clonedNucleus is not null) { - // Synapse clonedSynapse = clonedNucleus.GetSynapse(clonedReceiver); - // if (clonedSynapse.nucleus is INucleus synapseNucleus) { - // if (synapseNucleus.array != null && synapseNucleus.array.nuclei.Length > 0) { - // Debug.Log("Clone: Nucleus array"); - // if (clonedNucleusArray == null) { - // // copy the array - // clonedNucleusArray = new NucleusArray(synapseNucleus.array.nuclei.Length, "array"); - // for (int arrayIx = 0; arrayIx < synapseNucleus.array.nuclei.Length; arrayIx++) { - // IReceptor arrayNucleus = synapseNucleus.array.nuclei[arrayIx]; - // int ix2 = GetNucleusIndex(nuclei, arrayNucleus); - // clonedNucleusArray.nuclei[arrayIx] = clonedNuclei[ix2]; - // } - // } - // synapseNucleus.array = clonedNucleusArray; - // } - // } - // } } - - // if (receptor is INucleus nucleus) { - // if (clonedSender is not INucleus clonedNucleus) { - // Debug.LogError("INucleus clone is not an INucleus!"); - // continue; - // } - // clonedNucleus.array = new NucleusArray(nucleus.array._nuclei.Length, "array"); - // for (int arrayIx = 0; arrayIx < nucleus.array._nuclei.Length; arrayIx++) { - // //foreach (INucleus arrayNucleus in nucleus.array.nuclei) { - // IReceptor arrayNucleus = nucleus.array._nuclei[arrayIx]; - // int ix = GetNucleusIndex(nuclei, arrayNucleus); - // clonedNucleus.array._nuclei[arrayIx] = clonedNuclei[ix]; - // } - // } } + + // Copy nucleus arrays for (int nucleusIx = 0; nucleusIx < nuclei.Length; nucleusIx++) { IReceptor prefabReceptor = nuclei[nucleusIx]; if (prefabReceptor is not INucleus prefabNucleus) diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 0d84576..c805b8e 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -432,12 +432,12 @@ public class ClusterInspector : Editor { tooltip = new( $"{nucleus.name}" + $"\nsynapse count {n.synapses.Count}" + - $"\nValue: {nucleus.outputValue}"); + $"\nValue: {length(nucleus.outputValue)}"); } else { tooltip = new( $"{nucleus.name}" + - $"\nValue: {nucleus.outputValue}"); + $"\nValue: {length(nucleus.outputValue)}"); } Vector2 mousePosition = Event.current.mousePosition; diff --git a/Receptor.cs b/Receptor.cs index cf99794..ad6d526 100644 --- a/Receptor.cs +++ b/Receptor.cs @@ -25,12 +25,6 @@ public class Receptor : IReceptor { cluster.nuclei.Add(this); } - // public Receptor(ClusterPrefab cluster, INucleus nucleus) { - // this.cluster = cluster; - // if (cluster != null) - // cluster.nuclei.Add(this); - // this.AddReceiver(nucleus); - // } public Receptor(Cluster parent, string name, string nucleusName) { this.parent = parent ?? throw new ArgumentNullException(nameof(parent), "Parent cannot be null."); @@ -43,24 +37,6 @@ public class Receptor : IReceptor { } } - [Obsolete("This method is deprecated. Use Receptor() constructor instead.")] - public static Receptor CreateReceptor(Cluster cluster, string nucleusName) { - return new Receptor(cluster, "Receptor", nucleusName); - // if (cluster == null) - // return null; - - // Receptor receptor = new(cluster); - // foreach (INucleus nucleus in cluster.inputs) { - // if (nucleus != null && nucleus.name == nucleusName) { - // receptor.AddReceiver(nucleus); - // } - // } - // if (receptor._receivers.Count == 0) - // return null; - // else - // return receptor; - } - private ClusterPrefab cluster; private Cluster parent; @@ -68,20 +44,7 @@ public class Receptor : IReceptor { Receptor clone = new(parent); return clone; } - // public virtual IReceptor ShallowCloneTo(ClusterPrefab parent) { - // Receptor clone = new(parent); - // return clone; - // } - // public virtual IReceptor CloneTo(ClusterPrefab parent) { - // Receptor clone = new(parent); - - // foreach (INucleus receiver in this.receivers) { - // clone.AddReceiver(receiver); - // } - - // return clone; - // } public virtual IReceptor Clone() { Receptor clone = new(this.cluster); @@ -127,16 +90,8 @@ public class Receptor : IReceptor { private bool _isSleeping = false; public bool isSleeping => _isSleeping; - public Vector3 localPosition { - set { - this.stale = 0; - this._isSleeping = false; - this._outputValue = value; - - } - } - public float distanceResolution = 0.1f; - public float directionResolution = 5; + // public float distanceResolution = 0.1f; + // public float directionResolution = 5; private float3 _outputValue; public float3 outputValue { @@ -149,7 +104,7 @@ public class Receptor : IReceptor { } public virtual void ProcessStimulus(int thingId, Vector3 newLocalPositionVector, string thingName = null) { - this.localPosition = newLocalPositionVector; + this.outputValue = newLocalPositionVector; if (this._receivers == null) return; From 0258ef11979cf5e1650ac09cc834a4a571c387c3 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 5 Feb 2026 16:38:42 +0100 Subject: [PATCH 108/179] receptorarray is working --- Cluster.cs | 40 +++++++++++------- Editor/ClusterInspector.cs | 17 ++++---- Neuron.cs | 25 ++++++++--- Nucleus.cs | 13 ++++-- NucleusArray.cs | 59 ++++++++++++++++++++++++-- Receptor.cs | 17 ++------ ReceptorArray.cs | 85 ++++++++++++++++++++++++++++++++++++++ ReceptorArray.cs.meta | 2 + 8 files changed, 209 insertions(+), 49 deletions(-) create mode 100644 ReceptorArray.cs create mode 100644 ReceptorArray.cs.meta diff --git a/Cluster.cs b/Cluster.cs index 82faa5d..a1bfca2 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -41,16 +41,6 @@ public class Cluster : INucleus { this.sortedNuclei = TopologicalSort(this.nuclei); } - // public Cluster(ClusterPrefab parent, ClusterPrefab realPrefab) { - // this.prefab = realPrefab; - // this.name = realPrefab.name; - // this.cluster = parent; - // if (this.cluster != null) - // this.cluster.nuclei.Add(this); - - // ClonePrefab(); - // } - private void ClonePrefab() { IReceptor[] nuclei = this.prefab.nuclei.ToArray(); // first clone the nuclei without their connections @@ -157,7 +147,8 @@ public class Cluster : INucleus { } public virtual IReceptor Clone() { - Neuron clone = new(this.cluster, this.name) { + //Neuron clone = new(this.cluster, this.name) { + Neuron clone = new(this.parent, this.name) { array = this.array, }; @@ -232,6 +223,18 @@ public class Cluster : INucleus { set { _array = value; } } + public bool TryGetNucleus(string nucleusName, out Nucleus foundNucleus) { + foreach (IReceptor receptor in this.nuclei) { + if (receptor is Nucleus nucleus) + if (nucleus.name == nucleusName) { + foundNucleus = nucleus; + return true; + } + } + foundNucleus = null; + return false; + } + #region Synapses [SerializeField] @@ -321,16 +324,23 @@ public class Cluster : INucleus { //Applying the weight factors foreach (Synapse synapse in this.synapses) { - sum += synapse.weight * synapse.nucleus.outputValue; + if (lengthsq(synapse.nucleus.outputValue) > 0) { + sum += synapse.weight * synapse.nucleus.outputValue; + this.stale = 0; + } } //this.inputs[0].UpdateState(sum); this.inputs[0].UpdateStateIsolated(sum); foreach (IReceptor receptor in this.sortedNuclei) { - if (receptor is INucleus nucleus && nucleus != this.inputs[0]) - nucleus.UpdateStateIsolated(); + if (receptor is INucleus nucleus && nucleus != this.inputs[0]) { + //if (nucleus.isSleeping == false) + nucleus.UpdateStateIsolated(); + } } this.outputValue = this.output.outputValue; + + UpdateNuclei(); } // public virtual void UpdateResult(Vector3 result) { @@ -347,7 +357,7 @@ public class Cluster : INucleus { public void UpdateNuclei() { this.stale++; - if (this.stale > 2) + if (this.stale > 5) _outputValue = Vector3.zero; //foreach (IReceptor nucleus in this.prefab.nuclei) diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index c805b8e..b642079 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -428,17 +428,17 @@ public class ClusterInspector : Editor { private void HandleMouseHover(IReceptor nucleus, Rect rect) { GUIContent tooltip; - if (nucleus is INucleus n) { - tooltip = new( - $"{nucleus.name}" + - $"\nsynapse count {n.synapses.Count}" + - $"\nValue: {length(nucleus.outputValue)}"); - } - else { + // if (nucleus is INucleus n) { + // tooltip = new( + // $"{nucleus.name}" + + // //$"\nsynapse count {n.synapses.Count}" + + // $"\nValue: {length(nucleus.outputValue)}"); + // } + // else { tooltip = new( $"{nucleus.name}" + $"\nValue: {length(nucleus.outputValue)}"); - } + // } Vector2 mousePosition = Event.current.mousePosition; @@ -616,6 +616,7 @@ public class ClusterInspector : Editor { } protected virtual void AddInputNeuron(INucleus nucleus) { + //Neuron newNeuroid = new(this.cluster, "New neuron"); Neuron newNeuroid = new(this.cluster, "New neuron"); newNeuroid.AddReceiver(nucleus); this.currentNucleus = newNeuroid; diff --git a/Neuron.cs b/Neuron.cs index 742817c..2d29e3f 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -193,7 +193,8 @@ public class Neuron : Nucleus, INucleus { } public override IReceptor Clone() { - Neuron clone = new(this.cluster, this.name) { + //Neuron clone = new(this.cluster, this.name) { + Neuron clone = new(this.parent, this.name) { array = this.array, curve = this.curve, curvePreset = this.curvePreset, @@ -299,8 +300,10 @@ public class Neuron : Nucleus, INucleus { // public virtual void UpdateStateIsolated() { // UpdateStateIsolated(new float3(0, 0, 0)); // } - public override void UpdateStateIsolated(float3 bias) { - float3 sum = bias; + + public float3 bias = float3(0, 0, 0); + public override void UpdateStateIsolated(float3 bias_unused) { + float3 sum = this.bias; int n = 0; //Applying the weight factgors @@ -308,8 +311,10 @@ public class Neuron : Nucleus, INucleus { sum += synapse.weight * synapse.nucleus.outputValue; // Perhaps synapses should be removed when the output value goes to 0.... - if (lengthsq(synapse.nucleus.outputValue) != 0) + if (lengthsq(synapse.nucleus.outputValue) != 0) { n++; + this.stale = 0; + } } if (this.average && n > 0) sum /= n; @@ -337,7 +342,17 @@ public class Neuron : Nucleus, INucleus { result = normalize(sum) * activatedValue; break; } - this.outputValue = result; + if (this.stale > 5) + this.outputValue = new float3(0,0,0); + else + this.outputValue = result; + } + + public virtual void ProcessStimulus(Vector3 inputValue, string thingName = null) { + //this.outputValue = inputValue; + this.stale = 0; + Debug.Log($"{this.name} processed stimulus"); + this.bias = inputValue; } // public virtual void UpdateResult(Vector3 result) { diff --git a/Nucleus.cs b/Nucleus.cs index f7ac9ac..1d71fbe 100644 --- a/Nucleus.cs +++ b/Nucleus.cs @@ -20,7 +20,8 @@ public abstract class Nucleus : IReceptor { public virtual float3 outputValue { get { return _outputValue; } set { - this.stale = 0; + //Debug.Log($"{this.name}: stale is reset, was: {this.stale}"); + //this.stale = 0; // this._isSleeping = false; _outputValue = value; } @@ -28,7 +29,7 @@ public abstract class Nucleus : IReceptor { public bool isSleeping => lengthsq(this.outputValue) == 0; [NonSerialized] - private int stale = 1000; + public int stale = 1000; // Cannot clone an abstract nucleus... public virtual IReceptor ShallowCloneTo(Cluster parent) { return null; } @@ -96,8 +97,14 @@ public abstract class Nucleus : IReceptor { public void UpdateNuclei() { this.stale++; - if (this.stale > 2) + if (this.stale > 5) { + //Debug.Log($"{this.name} goes to sleep, stale = {this.stale}"); _outputValue = Vector3.zero; + } + } + + public void ProcessStimulus(int thingId, Vector3 inputValue, string thingName = null) { + this.array.ProcessStimulus(thingId, inputValue, thingName); } #endregion Update diff --git a/NucleusArray.cs b/NucleusArray.cs index bcccf49..b16ad97 100644 --- a/NucleusArray.cs +++ b/NucleusArray.cs @@ -6,7 +6,6 @@ using UnityEngine; public class NucleusArray { [SerializeReference] private IReceptor[] _nuclei; - //private ClusterPrefab[] _clusters; public IReceptor[] nuclei { get { return _nuclei; @@ -18,13 +17,10 @@ public class NucleusArray { this.name = nucleus.name; this._nuclei = new INucleus[1]; this._nuclei[0] = nucleus; - //this._clusters = new ClusterPrefab[0]; } public NucleusArray(ClusterPrefab cluster) { this.name = cluster.name; this._nuclei = new INucleus[0]; - // this._clusters = new ClusterPrefab[1]; - // this._clusters[0] = cluster; } public NucleusArray(int size, string name) { this.name = name; @@ -64,5 +60,60 @@ public class NucleusArray { this._nuclei = newPerceptei; } + public Dictionary thingReceivers = new(); + + public virtual void ProcessStimulus(int thingId, Vector3 inputValue, string thingName = null) { + CleanupReceivers(); + if (!thingReceivers.TryGetValue(thingId, out INucleus selectedReceiver)) { + Debug.Log($"No receiver found for {thingId}"); + foreach (IReceptor receptor in this.nuclei) { + if (receptor is not INucleus receiver) + continue; + + if (thingReceivers.ContainsValue(receiver) == false) { + // receiver is not used yet + Debug.Log($"{thingId} -> {receiver.name}"); + thingReceivers.Add(thingId, receiver); + selectedReceiver = receiver; + break; + } + } + } + + if (thingName != null) { + string baseName = selectedReceiver.name; + int colonPos = selectedReceiver.name.IndexOf(":"); + if (colonPos > 0) + baseName = selectedReceiver.name[..colonPos]; + selectedReceiver.name = baseName + ": " + thingName; + } + + if (selectedReceiver is Neuron selectedNucleus) + selectedNucleus.ProcessStimulus(inputValue); + selectedReceiver.parent.UpdateStateIsolated(); + } + + private void CleanupReceivers() { + // Remove a thing-receiver connection when the nucleus is inactive + List receiversToRemove = new(); + foreach (KeyValuePair item in thingReceivers) { + if (item.Value.isSleeping) { + Nucleus n = item.Value as Nucleus; + Debug.Log($"{item.Value.name} is sleeping, stale = {n.stale}"); + receiversToRemove.Add(item.Key); + } + } + foreach (int thingId in receiversToRemove) { + INucleus selectedReceiver = thingReceivers[thingId]; + + thingReceivers.Remove(thingId); + Debug.Log($"Cleanup receiver for {thingId}"); + + int colonPos = selectedReceiver.name.IndexOf(":"); + if (colonPos > 0) + selectedReceiver.name = selectedReceiver.name[..colonPos]; + + } + } } \ No newline at end of file diff --git a/Receptor.cs b/Receptor.cs index ad6d526..16d2ded 100644 --- a/Receptor.cs +++ b/Receptor.cs @@ -6,7 +6,6 @@ using static Unity.Mathematics.math; public class Receptor : IReceptor { - [SerializeField] protected string _name; public virtual string name { @@ -16,13 +15,7 @@ public class Receptor : IReceptor { public Receptor(Cluster parent) { this.parent = parent; - if (parent != null) - parent.nuclei.Add(this); - } - public Receptor(ClusterPrefab cluster) { - this.cluster = cluster; - if (cluster != null) - cluster.nuclei.Add(this); + parent?.nuclei.Add(this); } public Receptor(Cluster parent, string name, string nucleusName) { @@ -37,8 +30,7 @@ public class Receptor : IReceptor { } } - private ClusterPrefab cluster; - private Cluster parent; + private readonly Cluster parent; public virtual IReceptor ShallowCloneTo(Cluster parent) { Receptor clone = new(parent); @@ -46,7 +38,7 @@ public class Receptor : IReceptor { } public virtual IReceptor Clone() { - Receptor clone = new(this.cluster); + Receptor clone = new(this.parent); foreach (INucleus receiver in this.receivers) { clone.AddReceiver(receiver); @@ -90,9 +82,6 @@ public class Receptor : IReceptor { private bool _isSleeping = false; public bool isSleeping => _isSleeping; - // public float distanceResolution = 0.1f; - // public float directionResolution = 5; - private float3 _outputValue; public float3 outputValue { get { return this._outputValue; } diff --git a/ReceptorArray.cs b/ReceptorArray.cs new file mode 100644 index 0000000..fed0b3a --- /dev/null +++ b/ReceptorArray.cs @@ -0,0 +1,85 @@ +using System.Collections.Generic; +using UnityEngine; + +public class ReceptorArray { + public string name; + + public Cluster parent { get; set; } + + public NucleusArray nuclei; + public int size => nuclei.nuclei.Length; + + public Dictionary thingReceivers = new(); + + public ReceptorArray(Cluster parent, NucleusArray nuclei) { + this.parent = parent; + this.nuclei = nuclei; + } + + public virtual void ProcessStimulus(int thingId, Vector3 newLocalPositionVector, string thingName = null) { + if (!thingReceivers.TryGetValue(thingId, out INucleus selectedReceiver)) { + foreach (IReceptor receptor in this.nuclei.nuclei) { + if (receptor is not INucleus receiver) + continue; + if (thingReceivers.ContainsValue(receiver)) + continue; + // receiver is not used yet + thingReceivers.Add(thingId, receiver); + selectedReceiver = receiver; + } + } + //selectedReceiver.outputValue = newLocalPositionVector; + + + /* + int receiverIx = 0; + INucleus selectedReceiver = null; + int selectedReceiverIx = 0; + foreach (INucleus receiver in this.receivers) { + if (thingIds[receiverIx] == thingId) { + // We found an existing receiver for this thing + selectedReceiver = receiver; + selectedReceiverIx = receiverIx; + // Do not look any further + break; + } + else if (receiver.isSleeping) { + // A sleeping receiver is not active and can therefore always be used + selectedReceiver = receiver; + selectedReceiverIx = receiverIx; + // Look further because we may find an existing receiver for this thing + } + else if (selectedReceiver == null) { + // If we haven't found a receiver yet, just start by taking the first + selectedReceiver = receiver; + selectedReceiverIx = receiverIx; + } + else if (selectedReceiver.isSleeping == false) { + // If no existing or sleeping receiver is found, we look for + // the receiver with the furthest/least interesting stimulus + if (length(receiver.outputValue) < length(selectedReceiver.outputValue)) { + // Debug.Log($"{selectedReceiver.name}[{selectedReceiverIx}] {length(selectedReceiver.outputValue)}" + + // $" {receiver.name}[{receiverIx}] {length(receiver.outputValue)} "); + selectedReceiver = receiver; + selectedReceiverIx = receiverIx; + } + } + receiverIx++; + } + if (selectedReceiverIx >= thingIds.Length) + return; + + thingIds[selectedReceiverIx] = thingId; + if (thingName != null) { + string baseName = selectedReceiver.name; + int colonPos = selectedReceiver.name.IndexOf(":"); + if (colonPos > 0) + baseName = selectedReceiver.name.Substring(0, colonPos); + selectedReceiver.name = baseName + ": " + thingName; + } + Debug.Log($"Receiver {selectedReceiver.name}[{selectedReceiverIx}] for thing {thingId}"); + selectedReceiver.parent.UpdateStateIsolated(); + */ + } + +} \ No newline at end of file diff --git a/ReceptorArray.cs.meta b/ReceptorArray.cs.meta new file mode 100644 index 0000000..4a0e23a --- /dev/null +++ b/ReceptorArray.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 9e915c8563642f23891b20522b3589cf \ No newline at end of file From 0d268edd6dfef1b9606efee1f4132b1dbbc280bf Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 5 Feb 2026 16:55:12 +0100 Subject: [PATCH 109/179] Disabled Receptor --- Cluster.cs | 51 +++++++------ ClusterPrefab.cs | 6 +- Editor/ClusterInspector.cs | 12 ++-- INucleus.cs | 7 +- Nucleus.cs | 4 +- Receptor.cs | 4 +- ReceptorArray.cs | 100 +++++++++++++------------- Scripts/Experimental/SelectorBrain.cs | 12 ++-- Synapse.cs | 11 +-- 9 files changed, 107 insertions(+), 100 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index a1bfca2..5cacf3b 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -42,22 +42,22 @@ public class Cluster : INucleus { } private void ClonePrefab() { - IReceptor[] nuclei = this.prefab.nuclei.ToArray(); + INucleus[] prefabNuclei = this.prefab.nuclei.ToArray(); // first clone the nuclei without their connections - foreach (IReceptor nucleus in this.prefab.nuclei) + foreach (INucleus nucleus in this.prefab.nuclei) nucleus.ShallowCloneTo(this); - IReceptor[] clonedNuclei = this.nuclei.ToArray(); + INucleus[] clonedNuclei = this.nuclei.ToArray(); // Now clone the connections - for (int nucleusIx = 0; nucleusIx < nuclei.Length; nucleusIx++) { - IReceptor receptor = nuclei[nucleusIx]; - IReceptor clonedReceptor = clonedNuclei[nucleusIx]; + for (int nucleusIx = 0; nucleusIx < prefabNuclei.Length; nucleusIx++) { + INucleus receptor = prefabNuclei[nucleusIx]; + INucleus clonedReceptor = clonedNuclei[nucleusIx]; if (clonedReceptor == null) continue; // Copy the receivers, which will also create the synapses foreach (INucleus receiver in receptor.receivers) { - int ix = GetNucleusIndex(nuclei, receiver); + int ix = GetNucleusIndex(prefabNuclei, receiver); if (ix < 0) continue; @@ -79,8 +79,8 @@ public class Cluster : INucleus { } // Copy nucleus arrays - for (int nucleusIx = 0; nucleusIx < nuclei.Length; nucleusIx++) { - IReceptor prefabReceptor = nuclei[nucleusIx]; + for (int nucleusIx = 0; nucleusIx < prefabNuclei.Length; nucleusIx++) { + IReceptor prefabReceptor = prefabNuclei[nucleusIx]; if (prefabReceptor is not INucleus prefabNucleus) continue; @@ -93,7 +93,7 @@ public class Cluster : INucleus { NucleusArray clonedArray = new(prefabNucleus.array.nuclei.Length, "array"); int arrayIx = 0; foreach (IReceptor prefabArrayNucleus in prefabNucleus.array.nuclei) { - int arrayNucleusIx = GetNucleusIndex(nuclei, prefabArrayNucleus); + int arrayNucleusIx = GetNucleusIndex(prefabNuclei, prefabArrayNucleus); IReceptor clonedArrayNucleus = clonedNuclei[arrayNucleusIx]; clonedArray.nuclei[arrayIx] = clonedArrayNucleus; arrayIx++; @@ -102,7 +102,7 @@ public class Cluster : INucleus { } else { // The others will refer to the array created for the first nucleus in the array - int firstNucleusIx = GetNucleusIndex(nuclei, prefabNucleus.array.nuclei[0]); + int firstNucleusIx = GetNucleusIndex(prefabNuclei, prefabNucleus.array.nuclei[0]); INucleus clonedFirstNucleus = clonedNuclei[firstNucleusIx] as INucleus; clonedNucleus.array = clonedFirstNucleus.array; } @@ -110,26 +110,26 @@ public class Cluster : INucleus { } // Sort the nuclei in a correct evaluation order - private List TopologicalSort(List nodes) { + private List TopologicalSort(List nodes) { Dictionary inDegree = new(); foreach (IReceptor node in nodes) inDegree[node] = 0; // Initialize in-degree to zero // Calculate in-degrees - foreach (IReceptor node in nodes) { + foreach (INucleus node in nodes) { foreach (INucleus receiver in node.receivers) inDegree[receiver]++; } - Queue queue = new(); - foreach (IReceptor node in nodes) { + Queue queue = new(); + foreach (INucleus node in nodes) { if (inDegree[node] == 0) // Nodes with no dependencies queue.Enqueue(node); } List sortedOrder = new(); while (queue.Count > 0) { - IReceptor current = queue.Dequeue(); + INucleus current = queue.Dequeue(); sortedOrder.Add(current); // Process the node foreach (INucleus receiver in current.receivers) { @@ -185,7 +185,7 @@ public class Cluster : INucleus { public Cluster parent { get; set; } [SerializeReference] - public List nuclei = new(); + public List nuclei = new(); // the nuclei sorted using topological sorting // to ensure that the cluster is computer in the right order public List sortedNuclei; @@ -235,13 +235,22 @@ public class Cluster : INucleus { return false; } + public Nucleus GetNucleus(string nucleusName) { + foreach (IReceptor receptor in this.nuclei) { + if (receptor is Nucleus nucleus) + if (nucleus.name == nucleusName) + return nucleus; + } + return null; + } + #region Synapses [SerializeField] private List _synapses = new(); public List synapses => _synapses; - public Synapse AddSynapse(IReceptor sendingNucleus, float weight = 1.0f) { + public Synapse AddSynapse(INucleus sendingNucleus, float weight = 1.0f) { Synapse synapse = new(sendingNucleus, weight); this._synapses.Add(synapse); return synapse; @@ -335,7 +344,7 @@ public class Cluster : INucleus { foreach (IReceptor receptor in this.sortedNuclei) { if (receptor is INucleus nucleus && nucleus != this.inputs[0]) { //if (nucleus.isSleeping == false) - nucleus.UpdateStateIsolated(); + nucleus.UpdateStateIsolated(); } } this.outputValue = this.output.outputValue; @@ -357,11 +366,11 @@ public class Cluster : INucleus { public void UpdateNuclei() { this.stale++; - if (this.stale > 5) + if (this.stale > 5) _outputValue = Vector3.zero; //foreach (IReceptor nucleus in this.prefab.nuclei) - foreach (IReceptor nucleus in this.nuclei) + foreach (INucleus nucleus in this.nuclei) nucleus.UpdateNuclei(); } diff --git a/ClusterPrefab.cs b/ClusterPrefab.cs index f4fdd3f..5116e81 100644 --- a/ClusterPrefab.cs +++ b/ClusterPrefab.cs @@ -7,7 +7,7 @@ public class ClusterPrefab : ScriptableObject { // The ScriptableObject asset from which the runtime object has been created [SerializeReference] - public List nuclei = new(); + public List nuclei = new(); public virtual INucleus output => this.nuclei[0] as INucleus; @@ -33,7 +33,7 @@ public class ClusterPrefab : ScriptableObject { // This is an invariant and should be ensured before the nucleus is used // because output requires it. public void EnsureInitialization() { - nuclei ??= new List(); + nuclei ??= new List(); if (nuclei.Count == 0) new Neuron(this, "Output"); // Every cluster should have at least 1 neuron } @@ -74,7 +74,7 @@ public class ClusterPrefab : ScriptableObject { } public virtual void UpdateNuclei() { - foreach (IReceptor nucleus in this.nuclei) + foreach (INucleus nucleus in this.nuclei) nucleus.UpdateNuclei(); } } \ No newline at end of file diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index b642079..e3020cd 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -210,7 +210,7 @@ public class ClusterInspector : Editor { // Draw selected Nucleus if (expandArray) { float maxValue = 0; - foreach (IReceptor nucleus in this.currentNucleus.array.nuclei) { + foreach (INucleus nucleus in this.currentNucleus.array.nuclei) { float value = length(nucleus.outputValue); if (value > maxValue) maxValue = value; @@ -231,7 +231,7 @@ public class ClusterInspector : Editor { Handles.color = Color.black; Handles.DrawAAConvexPolygon(verts); int row = 0; - foreach (IReceptor nucleus in this.currentNucleus.array.nuclei) { + foreach (INucleus nucleus in this.currentNucleus.array.nuclei) { Vector3 pos = new(150, margin + row * spacing, 0.0f); Handles.color = Color.white; // The selected nucleus highlight ring @@ -344,7 +344,7 @@ public class ClusterInspector : Editor { } } - private void DrawNucleus(IReceptor nucleus, Vector3 position, float maxValue, float size) { + private void DrawNucleus(INucleus nucleus, Vector3 position, float maxValue, float size) { Color color; if (nucleus.isSleeping) color = Color.darkRed; @@ -359,7 +359,7 @@ public class ClusterInspector : Editor { DrawNucleus(nucleus, position, maxValue, size, color); } - private void DrawNucleus(IReceptor nucleus, Vector3 position, float maxValue, float size, Color color) { + private void DrawNucleus(INucleus nucleus, Vector3 position, float maxValue, float size, Color color) { if (nucleus is MemoryCell memory) { Handles.color = Color.white; Handles.DrawWireDisc(position + Vector3.right * 10, Vector3.forward, size); @@ -426,7 +426,7 @@ public class ClusterInspector : Editor { } } - private void HandleMouseHover(IReceptor nucleus, Rect rect) { + private void HandleMouseHover(INucleus nucleus, Rect rect) { GUIContent tooltip; // if (nucleus is INucleus n) { // tooltip = new( @@ -692,7 +692,7 @@ public class ClusterInspector : Editor { // Nucleus n = this.currentNucleus.brain.nuclei[selectedIndex - perceptei.Count()]; // n.AddReceiver(this.currentNucleus); // } - IReceptor receptor = cluster.nuclei[selectedIndex]; + INucleus receptor = cluster.nuclei[selectedIndex]; receptor.AddReceiver(this.currentNucleus); } } diff --git a/INucleus.cs b/INucleus.cs index 195e9da..7e0f2ee 100644 --- a/INucleus.cs +++ b/INucleus.cs @@ -11,7 +11,7 @@ public interface INucleus : IReceptor { // Senders public List synapses { get; } - public Synapse AddSynapse(IReceptor sender, float weight = 1.0f); + public Synapse AddSynapse(INucleus sender, float weight = 1.0f); public NucleusArray array { get; set; } @@ -25,9 +25,7 @@ public interface INucleus : IReceptor { public void UpdateStateIsolated(float3 inputValue); #endregion dynamic state -} -public interface IReceptor { #region static public string name { get; set; } @@ -54,3 +52,6 @@ public interface IReceptor { public IReceptor Clone(); } +public interface IReceptor { +} + diff --git a/Nucleus.cs b/Nucleus.cs index 1d71fbe..605a16d 100644 --- a/Nucleus.cs +++ b/Nucleus.cs @@ -4,7 +4,7 @@ using UnityEngine; using Unity.Mathematics; using static Unity.Mathematics.math; -public abstract class Nucleus : IReceptor { +public abstract class Nucleus : INucleus { [SerializeField] protected string _name; public virtual string name { @@ -42,7 +42,7 @@ public abstract class Nucleus : IReceptor { private List _synapses = new(); public List synapses => _synapses; - public Synapse AddSynapse(IReceptor sendingNucleus, float weight = 1.0f) { + public Synapse AddSynapse(INucleus sendingNucleus, float weight = 1.0f) { Synapse synapse = new(sendingNucleus, weight); this.synapses.Add(synapse); return synapse; diff --git a/Receptor.cs b/Receptor.cs index 16d2ded..71a1d0a 100644 --- a/Receptor.cs +++ b/Receptor.cs @@ -1,3 +1,4 @@ +/* using System; using System.Collections.Generic; using UnityEngine; @@ -154,4 +155,5 @@ public class Receptor : IReceptor { if (isSleeping) this._outputValue = Vector3.zero; } -} \ No newline at end of file +} +*/ \ No newline at end of file diff --git a/ReceptorArray.cs b/ReceptorArray.cs index fed0b3a..70afe30 100644 --- a/ReceptorArray.cs +++ b/ReceptorArray.cs @@ -1,3 +1,4 @@ +/* using System.Collections.Generic; using UnityEngine; @@ -31,55 +32,56 @@ public class ReceptorArray { //selectedReceiver.outputValue = newLocalPositionVector; - /* - int receiverIx = 0; - INucleus selectedReceiver = null; - int selectedReceiverIx = 0; - foreach (INucleus receiver in this.receivers) { - if (thingIds[receiverIx] == thingId) { - // We found an existing receiver for this thing - selectedReceiver = receiver; - selectedReceiverIx = receiverIx; - // Do not look any further - break; - } - else if (receiver.isSleeping) { - // A sleeping receiver is not active and can therefore always be used - selectedReceiver = receiver; - selectedReceiverIx = receiverIx; - // Look further because we may find an existing receiver for this thing - } - else if (selectedReceiver == null) { - // If we haven't found a receiver yet, just start by taking the first - selectedReceiver = receiver; - selectedReceiverIx = receiverIx; - } - else if (selectedReceiver.isSleeping == false) { - // If no existing or sleeping receiver is found, we look for - // the receiver with the furthest/least interesting stimulus - if (length(receiver.outputValue) < length(selectedReceiver.outputValue)) { - // Debug.Log($"{selectedReceiver.name}[{selectedReceiverIx}] {length(selectedReceiver.outputValue)}" + - // $" {receiver.name}[{receiverIx}] {length(receiver.outputValue)} "); - selectedReceiver = receiver; - selectedReceiverIx = receiverIx; - } - } - receiverIx++; - } - if (selectedReceiverIx >= thingIds.Length) - return; + + // int receiverIx = 0; + // INucleus selectedReceiver = null; + // int selectedReceiverIx = 0; + // foreach (INucleus receiver in this.receivers) { + // if (thingIds[receiverIx] == thingId) { + // // We found an existing receiver for this thing + // selectedReceiver = receiver; + // selectedReceiverIx = receiverIx; + // // Do not look any further + // break; + // } + // else if (receiver.isSleeping) { + // // A sleeping receiver is not active and can therefore always be used + // selectedReceiver = receiver; + // selectedReceiverIx = receiverIx; + // // Look further because we may find an existing receiver for this thing + // } + // else if (selectedReceiver == null) { + // // If we haven't found a receiver yet, just start by taking the first + // selectedReceiver = receiver; + // selectedReceiverIx = receiverIx; + // } + // else if (selectedReceiver.isSleeping == false) { + // // If no existing or sleeping receiver is found, we look for + // // the receiver with the furthest/least interesting stimulus + // if (length(receiver.outputValue) < length(selectedReceiver.outputValue)) { + // // Debug.Log($"{selectedReceiver.name}[{selectedReceiverIx}] {length(selectedReceiver.outputValue)}" + + // // $" {receiver.name}[{receiverIx}] {length(receiver.outputValue)} "); + // selectedReceiver = receiver; + // selectedReceiverIx = receiverIx; + // } + // } + // receiverIx++; + // } + // if (selectedReceiverIx >= thingIds.Length) + // return; - thingIds[selectedReceiverIx] = thingId; - if (thingName != null) { - string baseName = selectedReceiver.name; - int colonPos = selectedReceiver.name.IndexOf(":"); - if (colonPos > 0) - baseName = selectedReceiver.name.Substring(0, colonPos); - selectedReceiver.name = baseName + ": " + thingName; - } - Debug.Log($"Receiver {selectedReceiver.name}[{selectedReceiverIx}] for thing {thingId}"); - selectedReceiver.parent.UpdateStateIsolated(); - */ + // thingIds[selectedReceiverIx] = thingId; + // if (thingName != null) { + // string baseName = selectedReceiver.name; + // int colonPos = selectedReceiver.name.IndexOf(":"); + // if (colonPos > 0) + // baseName = selectedReceiver.name.Substring(0, colonPos); + // selectedReceiver.name = baseName + ": " + thingName; + // } + // Debug.Log($"Receiver {selectedReceiver.name}[{selectedReceiverIx}] for thing {thingId}"); + // selectedReceiver.parent.UpdateStateIsolated(); + } -} \ No newline at end of file +} +*/ \ No newline at end of file diff --git a/Scripts/Experimental/SelectorBrain.cs b/Scripts/Experimental/SelectorBrain.cs index 7ea01b6..b5a6c79 100644 --- a/Scripts/Experimental/SelectorBrain.cs +++ b/Scripts/Experimental/SelectorBrain.cs @@ -5,17 +5,17 @@ public class SelectorBrain : NanoBrain { public Vector3 input2; public Vector3 output; - public Receptor receptor1; - public Receptor receptor2; + public Nucleus receptor; + //public Nucleus receptor2; protected void Awake() { - receptor1 = new Receptor(this.brain, "Receptor", "Selector"); - receptor2 = new Receptor(this.brain, "Receptor", "Selector"); + receptor = this.brain.GetNucleus("Selector"); + //receptor2 = this.brain.GetNucleus("Selector"); } protected void Update() { - receptor1.ProcessStimulus(0, input1); - receptor2.ProcessStimulus(1, input2); + receptor.ProcessStimulus(0, input1); + receptor.ProcessStimulus(1, input2); output = this.brain.outputValue; this.brain.UpdateNuclei(); diff --git a/Synapse.cs b/Synapse.cs index e7c8116..b56f241 100644 --- a/Synapse.cs +++ b/Synapse.cs @@ -3,19 +3,12 @@ using UnityEngine; [Serializable] public class Synapse { - // Support access to cluster of basic nucleus - //public IReceptor nucleus => basicNucleus; - - - //[SerializeReference] - //public Cluster cluster; - [SerializeReference] - public IReceptor nucleus; + public INucleus nucleus; public float weight; - public Synapse(IReceptor nucleus, float weight = 1.0f) { + public Synapse(INucleus nucleus, float weight = 1.0f) { this.nucleus = nucleus; this.weight = weight; } From d48475b48300ed4a066f7bfa6d74242980d2fc8a Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 5 Feb 2026 17:00:26 +0100 Subject: [PATCH 110/179] Removed IReceptor --- Cluster.cs | 30 +++++++++++++++--------------- ClusterPrefab.cs | 2 +- Editor/ClusterInspector.cs | 10 +++++----- INucleus.cs | 10 +++++----- MemoryCell.cs | 2 +- Neuron.cs | 4 ++-- Nucleus.cs | 4 ++-- NucleusArray.cs | 10 +++++----- Selector.cs | 2 +- 9 files changed, 37 insertions(+), 37 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index 5cacf3b..780b71a 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -80,7 +80,7 @@ public class Cluster : INucleus { // Copy nucleus arrays for (int nucleusIx = 0; nucleusIx < prefabNuclei.Length; nucleusIx++) { - IReceptor prefabReceptor = prefabNuclei[nucleusIx]; + INucleus prefabReceptor = prefabNuclei[nucleusIx]; if (prefabReceptor is not INucleus prefabNucleus) continue; @@ -92,9 +92,9 @@ public class Cluster : INucleus { // We clone the array only for the first entry NucleusArray clonedArray = new(prefabNucleus.array.nuclei.Length, "array"); int arrayIx = 0; - foreach (IReceptor prefabArrayNucleus in prefabNucleus.array.nuclei) { + foreach (INucleus prefabArrayNucleus in prefabNucleus.array.nuclei) { int arrayNucleusIx = GetNucleusIndex(prefabNuclei, prefabArrayNucleus); - IReceptor clonedArrayNucleus = clonedNuclei[arrayNucleusIx]; + INucleus clonedArrayNucleus = clonedNuclei[arrayNucleusIx]; clonedArray.nuclei[arrayIx] = clonedArrayNucleus; arrayIx++; } @@ -110,9 +110,9 @@ public class Cluster : INucleus { } // Sort the nuclei in a correct evaluation order - private List TopologicalSort(List nodes) { - Dictionary inDegree = new(); - foreach (IReceptor node in nodes) + private List TopologicalSort(List nodes) { + Dictionary inDegree = new(); + foreach (INucleus node in nodes) inDegree[node] = 0; // Initialize in-degree to zero // Calculate in-degrees @@ -127,7 +127,7 @@ public class Cluster : INucleus { queue.Enqueue(node); } - List sortedOrder = new(); + List sortedOrder = new(); while (queue.Count > 0) { INucleus current = queue.Dequeue(); sortedOrder.Add(current); // Process the node @@ -146,7 +146,7 @@ public class Cluster : INucleus { return sortedOrder; } - public virtual IReceptor Clone() { + public virtual INucleus Clone() { //Neuron clone = new(this.cluster, this.name) { Neuron clone = new(this.parent, this.name) { array = this.array, @@ -162,14 +162,14 @@ public class Cluster : INucleus { return clone; } - public IReceptor ShallowCloneTo(Cluster parent) { + public INucleus ShallowCloneTo(Cluster parent) { Cluster clone = new(this.prefab, parent) { name = this.name, }; return clone; } - private int GetNucleusIndex(IReceptor[] nucleiArray, IReceptor nucleus) { + private int GetNucleusIndex(INucleus[] nucleiArray, INucleus nucleus) { for (int i = 0; i < nucleiArray.Length; i++) { if (nucleus == nucleiArray[i]) return i; @@ -188,14 +188,14 @@ public class Cluster : INucleus { public List nuclei = new(); // the nuclei sorted using topological sorting // to ensure that the cluster is computer in the right order - public List sortedNuclei; + public List sortedNuclei; public List _inputs = null; public virtual List inputs { get { if (this._inputs == null) { this._inputs = new(); - foreach (IReceptor receptor in this.nuclei) { + foreach (INucleus receptor in this.nuclei) { if (receptor is INucleus nucleus) { // inputs have no incoming synapses yet. if (nucleus.synapses.Count == 0) @@ -224,7 +224,7 @@ public class Cluster : INucleus { } public bool TryGetNucleus(string nucleusName, out Nucleus foundNucleus) { - foreach (IReceptor receptor in this.nuclei) { + foreach (INucleus receptor in this.nuclei) { if (receptor is Nucleus nucleus) if (nucleus.name == nucleusName) { foundNucleus = nucleus; @@ -236,7 +236,7 @@ public class Cluster : INucleus { } public Nucleus GetNucleus(string nucleusName) { - foreach (IReceptor receptor in this.nuclei) { + foreach (INucleus receptor in this.nuclei) { if (receptor is Nucleus nucleus) if (nucleus.name == nucleusName) return nucleus; @@ -341,7 +341,7 @@ public class Cluster : INucleus { //this.inputs[0].UpdateState(sum); this.inputs[0].UpdateStateIsolated(sum); - foreach (IReceptor receptor in this.sortedNuclei) { + foreach (INucleus receptor in this.sortedNuclei) { if (receptor is INucleus nucleus && nucleus != this.inputs[0]) { //if (nucleus.isSleeping == false) nucleus.UpdateStateIsolated(); diff --git a/ClusterPrefab.cs b/ClusterPrefab.cs index 5116e81..694efaf 100644 --- a/ClusterPrefab.cs +++ b/ClusterPrefab.cs @@ -17,7 +17,7 @@ public class ClusterPrefab : ScriptableObject { get { if (this._inputs == null) { this._inputs = new(); - foreach (IReceptor receptor in this.nuclei) { + foreach (INucleus receptor in this.nuclei) { if (receptor is INucleus nucleus) { // inputs have no incoming synapses yet. if (nucleus.synapses.Count == 0) diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index e3020cd..333f8a5 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -71,7 +71,7 @@ public class ClusterInspector : Editor { INucleus currentNucleus; GameObject gameObject; private List layers = new(); - private readonly Dictionary neuroidPositions = new(); + private readonly Dictionary neuroidPositions = new(); private bool expandArray = false; ClusterWrapper currentWrapper; @@ -165,7 +165,7 @@ public class ClusterInspector : Editor { if (selectedNucleus.synapses != null) { foreach (Synapse synapse in selectedNucleus.synapses) { - IReceptor input = synapse.nucleus; + INucleus input = synapse.nucleus; AddToLayer(currentLayer, input); // Debug.Log($"layer {layerIx} nucleus {input.name}"); } @@ -175,7 +175,7 @@ public class ClusterInspector : Editor { } } - private void AddToLayer(NeuroidLayer layer, IReceptor nucleus) { + private void AddToLayer(NeuroidLayer layer, INucleus nucleus) { if (nucleus == null) return; layer.neuroids.Add(nucleus); @@ -449,7 +449,7 @@ public class ClusterInspector : Editor { GUI.Box(tooltipRect, tooltip); } - private void HandleClicked(IReceptor nucleus) { + private void HandleClicked(INucleus nucleus) { if (nucleus == this.currentNucleus) { if (nucleus is INucleus n) { expandArray = !expandArray; @@ -734,7 +734,7 @@ public class ClusterInspector : Editor { public class NeuroidLayer { public int ix = 0; - public List neuroids = new(); + public List neuroids = new(); } public class ClusterWrapper : ScriptableObject { diff --git a/INucleus.cs b/INucleus.cs index 7e0f2ee..4869d33 100644 --- a/INucleus.cs +++ b/INucleus.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using Unity.Mathematics; -public interface INucleus : IReceptor { +public interface INucleus { #region static struct @@ -48,10 +48,10 @@ public interface INucleus : IReceptor { #endregion dynamic - public IReceptor ShallowCloneTo(Cluster parent); - public IReceptor Clone(); + public INucleus ShallowCloneTo(Cluster parent); + public INucleus Clone(); } -public interface IReceptor { -} +// public interface IReceptor { +// } diff --git a/MemoryCell.cs b/MemoryCell.cs index 643b039..3397bff 100644 --- a/MemoryCell.cs +++ b/MemoryCell.cs @@ -13,7 +13,7 @@ public class MemoryCell : Neuron, INucleus { // this.parent?.nuclei.Add(this); // } - public override IReceptor ShallowCloneTo(Cluster newParent) { + public override INucleus ShallowCloneTo(Cluster newParent) { MemoryCell clone = new(newParent, this.name) { array = this.array, curve = this.curve, diff --git a/Neuron.cs b/Neuron.cs index 2d29e3f..ca6ee25 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -181,7 +181,7 @@ public class Neuron : Nucleus, INucleus { #endregion Runtime state // this clone the nucleus without the synapses and receivers - public override IReceptor ShallowCloneTo(Cluster newParent) { + public override INucleus ShallowCloneTo(Cluster newParent) { Neuron clone = new(newParent, this.name) { array = null, curve = this.curve, @@ -192,7 +192,7 @@ public class Neuron : Nucleus, INucleus { return clone; } - public override IReceptor Clone() { + public override INucleus Clone() { //Neuron clone = new(this.cluster, this.name) { Neuron clone = new(this.parent, this.name) { array = this.array, diff --git a/Nucleus.cs b/Nucleus.cs index 605a16d..7511710 100644 --- a/Nucleus.cs +++ b/Nucleus.cs @@ -32,9 +32,9 @@ public abstract class Nucleus : INucleus { public int stale = 1000; // Cannot clone an abstract nucleus... - public virtual IReceptor ShallowCloneTo(Cluster parent) { return null; } + public virtual INucleus ShallowCloneTo(Cluster parent) { return null; } // Cannot clone an abstract nucleus... - public virtual IReceptor Clone() { return null; } + public virtual INucleus Clone() { return null; } #region Synapses diff --git a/NucleusArray.cs b/NucleusArray.cs index b16ad97..36d2417 100644 --- a/NucleusArray.cs +++ b/NucleusArray.cs @@ -5,8 +5,8 @@ using UnityEngine; [System.Serializable] public class NucleusArray { [SerializeReference] - private IReceptor[] _nuclei; - public IReceptor[] nuclei { + private INucleus[] _nuclei; + public INucleus[] nuclei { get { return _nuclei; } @@ -34,7 +34,7 @@ public class NucleusArray { return; } int newLength = this._nuclei.Length + 1; - IReceptor[] newArray = new INucleus[newLength]; + INucleus[] newArray = new INucleus[newLength]; for (int i = 0; i < this._nuclei.Length; i++) newArray[i] = this._nuclei[i]; @@ -50,7 +50,7 @@ public class NucleusArray { Debug.LogWarning("Perceptoid array cannot be empty"); return; } - IReceptor[] newPerceptei = new INucleus[newLength]; + INucleus[] newPerceptei = new INucleus[newLength]; for (int i = 0; i < newLength; i++) newPerceptei[i] = this._nuclei[i]; // Delete the last perception @@ -67,7 +67,7 @@ public class NucleusArray { CleanupReceivers(); if (!thingReceivers.TryGetValue(thingId, out INucleus selectedReceiver)) { Debug.Log($"No receiver found for {thingId}"); - foreach (IReceptor receptor in this.nuclei) { + foreach (INucleus receptor in this.nuclei) { if (receptor is not INucleus receiver) continue; diff --git a/Selector.cs b/Selector.cs index cb8a2ec..8cfe378 100644 --- a/Selector.cs +++ b/Selector.cs @@ -7,7 +7,7 @@ public class Selector : Neuron { public Selector(Cluster parent, string name) : base(parent, name) { } public Selector(ClusterPrefab parent, string name) : base(parent, name) {} - public override IReceptor ShallowCloneTo(Cluster newParent) { + public override INucleus ShallowCloneTo(Cluster newParent) { Selector clone = new(newParent, this.name) { array = this.array, curve = this.curve, From 351f242f2e62b43cffff1851105ff39f10fc3b31 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 5 Feb 2026 17:03:56 +0100 Subject: [PATCH 111/179] Switching from INucleus to Nucleus --- Cluster.cs | 108 +++++++++++++++++++++++++------------------------- MemoryCell.cs | 2 +- Neuron.cs | 4 +- Nucleus.cs | 2 +- 4 files changed, 58 insertions(+), 58 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index 780b71a..f1a0d74 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -6,15 +6,15 @@ using Unity.Mathematics; using static Unity.Mathematics.math; [Serializable] -public class Cluster : INucleus { +public class Cluster : Nucleus { // The ScriptableObject asset from which the runtime object has been created - [SerializeField] - protected string _name; - public virtual string name { - get => _name; - set => _name = value; - } + // [SerializeField] + // protected string _name; + // public virtual string name { + // get => _name; + // set => _name = value; + // } #region Init @@ -146,7 +146,7 @@ public class Cluster : INucleus { return sortedOrder; } - public virtual INucleus Clone() { + public override INucleus Clone() { //Neuron clone = new(this.cluster, this.name) { Neuron clone = new(this.parent, this.name) { array = this.array, @@ -162,7 +162,7 @@ public class Cluster : INucleus { return clone; } - public INucleus ShallowCloneTo(Cluster parent) { + public override INucleus ShallowCloneTo(Cluster parent) { Cluster clone = new(this.prefab, parent) { name = this.name, }; @@ -181,8 +181,8 @@ public class Cluster : INucleus { public ClusterPrefab prefab; - public ClusterPrefab cluster { get; set; } - public Cluster parent { get; set; } + // public ClusterPrefab cluster { get; set; } + // public Cluster parent { get; set; } [SerializeReference] public List nuclei = new(); @@ -216,12 +216,12 @@ public class Cluster : INucleus { } // Not sure if this belongs here... - [SerializeReference] - private NucleusArray _array; - public NucleusArray array { - get { return _array; } - set { _array = value; } - } + // [SerializeReference] + // private NucleusArray _array; + // public NucleusArray array { + // get { return _array; } + // set { _array = value; } + // } public bool TryGetNucleus(string nucleusName, out Nucleus foundNucleus) { foreach (INucleus receptor in this.nuclei) { @@ -246,15 +246,15 @@ public class Cluster : INucleus { #region Synapses - [SerializeField] - private List _synapses = new(); - public List synapses => _synapses; + // [SerializeField] + // private List _synapses = new(); + // public List synapses => _synapses; - public Synapse AddSynapse(INucleus sendingNucleus, float weight = 1.0f) { - Synapse synapse = new(sendingNucleus, weight); - this._synapses.Add(synapse); - return synapse; - } + // public Synapse AddSynapse(INucleus sendingNucleus, float weight = 1.0f) { + // Synapse synapse = new(sendingNucleus, weight); + // this._synapses.Add(synapse); + // return synapse; + // } // Does this even exist already? public void RemoveSynapse() { @@ -265,40 +265,40 @@ public class Cluster : INucleus { #region Receivers - [SerializeReference] - private List _receivers = new(); - public List receivers { - get { return _receivers; } - set { _receivers = value; } - } + // [SerializeReference] + // private List _receivers = new(); + // public List receivers { + // get { return _receivers; } + // set { _receivers = value; } + // } - public virtual void AddReceiver(INucleus receivingNucleus, float weight = 1) { - this._receivers.Add(receivingNucleus); - receivingNucleus.AddSynapse(this, weight); - } + // public virtual void AddReceiver(INucleus receivingNucleus, float weight = 1) { + // this._receivers.Add(receivingNucleus); + // receivingNucleus.AddSynapse(this, weight); + // } - public void RemoveReceiver(INucleus receiverNucleus) { - this._receivers.RemoveAll(receiver => receiver == receiverNucleus); - receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); - } + // public void RemoveReceiver(INucleus receiverNucleus) { + // this._receivers.RemoveAll(receiver => receiver == receiverNucleus); + // receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); + // } #endregion Receivers #region Runtime - [NonSerialized] - private int stale = 1000; - public bool isSleeping => lengthsq(this.outputValue) == 0; + // [NonSerialized] + // private int stale = 1000; + // public bool isSleeping => lengthsq(this.outputValue) == 0; - [NonSerialized] - protected float3 _outputValue; - public virtual float3 outputValue { - get { return _outputValue; } - set { - this.stale = 0; - _outputValue = value; - } - } + // [NonSerialized] + // protected float3 _outputValue; + // public virtual float3 outputValue { + // get { return _outputValue; } + // set { + // this.stale = 0; + // _outputValue = value; + // } + // } #region Update @@ -324,11 +324,11 @@ public class Cluster : INucleus { // UpdateResult(this.output.outputValue); // } - public void UpdateStateIsolated() { + public override void UpdateStateIsolated() { float3 bias = new(0, 0, 0); UpdateStateIsolated(bias); } - public void UpdateStateIsolated(float3 bias) { + public override void UpdateStateIsolated(float3 bias) { float3 sum = bias; // new(0, 0, 0); //Applying the weight factors @@ -364,7 +364,7 @@ public class Cluster : INucleus { // receiver.UpdateState(); // } - public void UpdateNuclei() { + public override void UpdateNuclei() { this.stale++; if (this.stale > 5) _outputValue = Vector3.zero; diff --git a/MemoryCell.cs b/MemoryCell.cs index 3397bff..ab45440 100644 --- a/MemoryCell.cs +++ b/MemoryCell.cs @@ -4,7 +4,7 @@ using Unity.Mathematics; using static Unity.Mathematics.math; [Serializable] -public class MemoryCell : Neuron, INucleus { +public class MemoryCell : Neuron { public MemoryCell(ClusterPrefab cluster, string name) : base(cluster, name) { } public MemoryCell(Cluster parent, string name) : base(parent, name) { } diff --git a/Neuron.cs b/Neuron.cs index ca6ee25..ba861a0 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -7,7 +7,7 @@ using Unity.Mathematics; using static Unity.Mathematics.math; [Serializable] -public class Neuron : Nucleus, INucleus { +public class Neuron : Nucleus { public Neuron(Cluster parent, string name) { this.parent = parent; @@ -351,7 +351,7 @@ public class Neuron : Nucleus, INucleus { public virtual void ProcessStimulus(Vector3 inputValue, string thingName = null) { //this.outputValue = inputValue; this.stale = 0; - Debug.Log($"{this.name} processed stimulus"); + //Debug.Log($"{this.name} processed stimulus"); this.bias = inputValue; } diff --git a/Nucleus.cs b/Nucleus.cs index 7511710..f3621c0 100644 --- a/Nucleus.cs +++ b/Nucleus.cs @@ -95,7 +95,7 @@ public abstract class Nucleus : INucleus { public virtual void UpdateStateIsolated(float3 bias) { } - public void UpdateNuclei() { + public virtual void UpdateNuclei() { this.stale++; if (this.stale > 5) { //Debug.Log($"{this.name} goes to sleep, stale = {this.stale}"); From 1e5a19c1ab31ec78b11356f44610009f85353ed8 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 5 Feb 2026 17:32:01 +0100 Subject: [PATCH 112/179] Removed the use of INucleus --- Cluster.cs | 94 +++++------ ClusterPrefab.cs | 30 ++-- Editor/ClusterInspector.cs | 74 ++++----- Editor/NeuroidWindow.cs | 302 ----------------------------------- Editor/NeuroidWindow.cs.meta | 2 - INucleus.cs | 18 ++- MemoryCell.cs | 2 +- NanoBrain.cs | 2 +- Neuron.cs | 14 +- Nucleus.cs | 21 ++- NucleusArray.cs | 34 ++-- Selector.cs | 2 +- Synapse.cs | 4 +- 13 files changed, 148 insertions(+), 451 deletions(-) delete mode 100644 Editor/NeuroidWindow.cs delete mode 100644 Editor/NeuroidWindow.cs.meta diff --git a/Cluster.cs b/Cluster.cs index f1a0d74..351176e 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -42,26 +42,26 @@ public class Cluster : Nucleus { } private void ClonePrefab() { - INucleus[] prefabNuclei = this.prefab.nuclei.ToArray(); + Nucleus[] prefabNuclei = this.prefab.nuclei.ToArray(); // first clone the nuclei without their connections - foreach (INucleus nucleus in this.prefab.nuclei) + foreach (Nucleus nucleus in this.prefab.nuclei) nucleus.ShallowCloneTo(this); - INucleus[] clonedNuclei = this.nuclei.ToArray(); + Nucleus[] clonedNuclei = this.nuclei.ToArray(); // Now clone the connections for (int nucleusIx = 0; nucleusIx < prefabNuclei.Length; nucleusIx++) { - INucleus receptor = prefabNuclei[nucleusIx]; - INucleus clonedReceptor = clonedNuclei[nucleusIx]; + Nucleus receptor = prefabNuclei[nucleusIx]; + Nucleus clonedReceptor = clonedNuclei[nucleusIx]; if (clonedReceptor == null) continue; // Copy the receivers, which will also create the synapses - foreach (INucleus receiver in receptor.receivers) { + foreach (Nucleus receiver in receptor.receivers) { int ix = GetNucleusIndex(prefabNuclei, receiver); if (ix < 0) continue; - if (clonedNuclei[ix] is not INucleus clonedReceiver) + if (clonedNuclei[ix] is not Nucleus clonedReceiver) continue; // Find the synapse for the weight @@ -80,21 +80,21 @@ public class Cluster : Nucleus { // Copy nucleus arrays for (int nucleusIx = 0; nucleusIx < prefabNuclei.Length; nucleusIx++) { - INucleus prefabReceptor = prefabNuclei[nucleusIx]; - if (prefabReceptor is not INucleus prefabNucleus) + Nucleus prefabReceptor = prefabNuclei[nucleusIx]; + if (prefabReceptor is not Nucleus prefabNucleus) continue; if (prefabNucleus.array == null || prefabNucleus.array.nuclei == null || prefabNucleus.array.nuclei.Length == 0) continue; - INucleus clonedNucleus = clonedNuclei[nucleusIx] as INucleus; + Nucleus clonedNucleus = clonedNuclei[nucleusIx] as Nucleus; if (prefabNucleus == prefabNucleus.array.nuclei[0]) { // We clone the array only for the first entry NucleusArray clonedArray = new(prefabNucleus.array.nuclei.Length, "array"); int arrayIx = 0; - foreach (INucleus prefabArrayNucleus in prefabNucleus.array.nuclei) { + foreach (Nucleus prefabArrayNucleus in prefabNucleus.array.nuclei) { int arrayNucleusIx = GetNucleusIndex(prefabNuclei, prefabArrayNucleus); - INucleus clonedArrayNucleus = clonedNuclei[arrayNucleusIx]; + Nucleus clonedArrayNucleus = clonedNuclei[arrayNucleusIx]; clonedArray.nuclei[arrayIx] = clonedArrayNucleus; arrayIx++; } @@ -103,36 +103,36 @@ public class Cluster : Nucleus { else { // The others will refer to the array created for the first nucleus in the array int firstNucleusIx = GetNucleusIndex(prefabNuclei, prefabNucleus.array.nuclei[0]); - INucleus clonedFirstNucleus = clonedNuclei[firstNucleusIx] as INucleus; + Nucleus clonedFirstNucleus = clonedNuclei[firstNucleusIx] as Nucleus; clonedNucleus.array = clonedFirstNucleus.array; } } } // Sort the nuclei in a correct evaluation order - private List TopologicalSort(List nodes) { - Dictionary inDegree = new(); - foreach (INucleus node in nodes) + private List TopologicalSort(List nodes) { + Dictionary inDegree = new(); + foreach (Nucleus node in nodes) inDegree[node] = 0; // Initialize in-degree to zero // Calculate in-degrees - foreach (INucleus node in nodes) { - foreach (INucleus receiver in node.receivers) + foreach (Nucleus node in nodes) { + foreach (Nucleus receiver in node.receivers) inDegree[receiver]++; } - Queue queue = new(); - foreach (INucleus node in nodes) { + Queue queue = new(); + foreach (Nucleus node in nodes) { if (inDegree[node] == 0) // Nodes with no dependencies queue.Enqueue(node); } - List sortedOrder = new(); + List sortedOrder = new(); while (queue.Count > 0) { - INucleus current = queue.Dequeue(); + Nucleus current = queue.Dequeue(); sortedOrder.Add(current); // Process the node - foreach (INucleus receiver in current.receivers) { + foreach (Nucleus receiver in current.receivers) { inDegree[receiver]--; if (inDegree[receiver] == 0) // If all dependencies resolved queue.Enqueue(receiver); @@ -146,7 +146,7 @@ public class Cluster : Nucleus { return sortedOrder; } - public override INucleus Clone() { + public override Nucleus Clone() { //Neuron clone = new(this.cluster, this.name) { Neuron clone = new(this.parent, this.name) { array = this.array, @@ -156,20 +156,20 @@ public class Cluster : Nucleus { Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); clonedSynapse.weight = synapse.weight; } - foreach (INucleus receiver in this.receivers) { + foreach (Nucleus receiver in this.receivers) { clone.AddReceiver(receiver); } return clone; } - public override INucleus ShallowCloneTo(Cluster parent) { + public override Nucleus ShallowCloneTo(Cluster parent) { Cluster clone = new(this.prefab, parent) { name = this.name, }; return clone; } - private int GetNucleusIndex(INucleus[] nucleiArray, INucleus nucleus) { + private int GetNucleusIndex(Nucleus[] nucleiArray, Nucleus nucleus) { for (int i = 0; i < nucleiArray.Length; i++) { if (nucleus == nucleiArray[i]) return i; @@ -185,18 +185,18 @@ public class Cluster : Nucleus { // public Cluster parent { get; set; } [SerializeReference] - public List nuclei = new(); + public List nuclei = new(); // the nuclei sorted using topological sorting // to ensure that the cluster is computer in the right order - public List sortedNuclei; + public List sortedNuclei; - public List _inputs = null; - public virtual List inputs { + public List _inputs = null; + public virtual List inputs { get { if (this._inputs == null) { this._inputs = new(); - foreach (INucleus receptor in this.nuclei) { - if (receptor is INucleus nucleus) { + foreach (Nucleus receptor in this.nuclei) { + if (receptor is Nucleus nucleus) { // inputs have no incoming synapses yet. if (nucleus.synapses.Count == 0) this._inputs.Add(nucleus); @@ -207,10 +207,10 @@ public class Cluster : Nucleus { } } - public virtual INucleus output {//=> this.nuclei[0] as INucleus; + public virtual Nucleus output {//=> this.nuclei[0] as Nucleus; get { if (this.nuclei.Count > 0) - return this.nuclei[0] as INucleus; + return this.nuclei[0]; return null; } } @@ -224,7 +224,7 @@ public class Cluster : Nucleus { // } public bool TryGetNucleus(string nucleusName, out Nucleus foundNucleus) { - foreach (INucleus receptor in this.nuclei) { + foreach (Nucleus receptor in this.nuclei) { if (receptor is Nucleus nucleus) if (nucleus.name == nucleusName) { foundNucleus = nucleus; @@ -236,7 +236,7 @@ public class Cluster : Nucleus { } public Nucleus GetNucleus(string nucleusName) { - foreach (INucleus receptor in this.nuclei) { + foreach (Nucleus receptor in this.nuclei) { if (receptor is Nucleus nucleus) if (nucleus.name == nucleusName) return nucleus; @@ -250,7 +250,7 @@ public class Cluster : Nucleus { // private List _synapses = new(); // public List synapses => _synapses; - // public Synapse AddSynapse(INucleus sendingNucleus, float weight = 1.0f) { + // public Synapse AddSynapse(Nucleus sendingNucleus, float weight = 1.0f) { // Synapse synapse = new(sendingNucleus, weight); // this._synapses.Add(synapse); // return synapse; @@ -266,18 +266,18 @@ public class Cluster : Nucleus { #region Receivers // [SerializeReference] - // private List _receivers = new(); - // public List receivers { + // private List _receivers = new(); + // public List receivers { // get { return _receivers; } // set { _receivers = value; } // } - // public virtual void AddReceiver(INucleus receivingNucleus, float weight = 1) { + // public virtual void AddReceiver(Nucleus receivingNucleus, float weight = 1) { // this._receivers.Add(receivingNucleus); // receivingNucleus.AddSynapse(this, weight); // } - // public void RemoveReceiver(INucleus receiverNucleus) { + // public void RemoveReceiver(Nucleus receiverNucleus) { // this._receivers.RemoveAll(receiver => receiver == receiverNucleus); // receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); // } @@ -317,7 +317,7 @@ public class Cluster : Nucleus { // //this.inputs[0].UpdateState(sum); // this.inputs[0].UpdateStateIsolated(sum); // foreach (IReceptor receptor in this.sortedNuclei) { - // if (receptor is INucleus nucleus && nucleus != this.inputs[0]) + // if (receptor is Nucleus nucleus && nucleus != this.inputs[0]) // nucleus.UpdateStateIsolated(); // } @@ -341,8 +341,8 @@ public class Cluster : Nucleus { //this.inputs[0].UpdateState(sum); this.inputs[0].UpdateStateIsolated(sum); - foreach (INucleus receptor in this.sortedNuclei) { - if (receptor is INucleus nucleus && nucleus != this.inputs[0]) { + foreach (Nucleus receptor in this.sortedNuclei) { + if (receptor is Nucleus nucleus && nucleus != this.inputs[0]) { //if (nucleus.isSleeping == false) nucleus.UpdateStateIsolated(); } @@ -360,7 +360,7 @@ public class Cluster : Nucleus { // // } // this.outputValue = result; - // foreach (INucleus receiver in this.receivers) + // foreach (Nucleus receiver in this.receivers) // receiver.UpdateState(); // } @@ -370,7 +370,7 @@ public class Cluster : Nucleus { _outputValue = Vector3.zero; //foreach (IReceptor nucleus in this.prefab.nuclei) - foreach (INucleus nucleus in this.nuclei) + foreach (Nucleus nucleus in this.nuclei) nucleus.UpdateNuclei(); } diff --git a/ClusterPrefab.cs b/ClusterPrefab.cs index 694efaf..5a390e8 100644 --- a/ClusterPrefab.cs +++ b/ClusterPrefab.cs @@ -3,22 +3,22 @@ using UnityEngine; [CreateAssetMenu(menuName = "Passer/Cluster")] public class ClusterPrefab : ScriptableObject { - // The ScriptableObject asset from which the runtime object has been created + public string hello = "hello"; [SerializeReference] - public List nuclei = new(); + public List nuclei = new(); - public virtual INucleus output => this.nuclei[0] as INucleus; + public virtual Nucleus output => this.nuclei[0] as Nucleus; - public List _inputs = null; - public virtual List inputs { + public List _inputs = null; + public virtual List inputs { get { if (this._inputs == null) { this._inputs = new(); - foreach (INucleus receptor in this.nuclei) { - if (receptor is INucleus nucleus) { + foreach (Nucleus receptor in this.nuclei) { + if (receptor is Nucleus nucleus) { // inputs have no incoming synapses yet. if (nucleus.synapses.Count == 0) this._inputs.Add(nucleus); @@ -33,19 +33,19 @@ public class ClusterPrefab : ScriptableObject { // This is an invariant and should be ensured before the nucleus is used // because output requires it. public void EnsureInitialization() { - nuclei ??= new List(); + nuclei ??= new List(); if (nuclei.Count == 0) new Neuron(this, "Output"); // Every cluster should have at least 1 neuron } public void GarbageCollection() { - HashSet visitedNuclei = new(); + HashSet visitedNuclei = new(); MarkNuclei(visitedNuclei, this.output); //Debug.Log($"Garbage collection found {visitedNuclei.Count} Nuclei"); - this.nuclei.RemoveAll(nucleus => nucleus is INucleus n && visitedNuclei.Contains(n) == false); + this.nuclei.RemoveAll(nucleus => nucleus is Nucleus n && visitedNuclei.Contains(n) == false); } - public void MarkNuclei(HashSet visitedNuclei, INucleus nucleus) { + public void MarkNuclei(HashSet visitedNuclei, Nucleus nucleus) { if (nucleus is null) return; @@ -55,15 +55,15 @@ public class ClusterPrefab : ScriptableObject { foreach (Synapse synapse in nucleus.synapses) { if (synapse != null && synapse.nucleus != null) { visitedSynapses.Add(synapse); - if (synapse.nucleus is INucleus synapse_nucleus) + if (synapse.nucleus is Nucleus synapse_nucleus) MarkNuclei(visitedNuclei, synapse_nucleus); } } nucleus.synapses.RemoveAll(synapse => visitedSynapses.Contains(synapse) == false); } if (nucleus.receivers != null) { - HashSet visitedReceivers = new(); - foreach (INucleus receiver in nucleus.receivers) { + HashSet visitedReceivers = new(); + foreach (Nucleus receiver in nucleus.receivers) { if (receiver != null && receiver != null) { visitedReceivers.Add(receiver); visitedNuclei.Add(receiver); @@ -74,7 +74,7 @@ public class ClusterPrefab : ScriptableObject { } public virtual void UpdateNuclei() { - foreach (INucleus nucleus in this.nuclei) + foreach (Nucleus nucleus in this.nuclei) nucleus.UpdateNuclei(); } } \ No newline at end of file diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 333f8a5..45950e1 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -68,10 +68,10 @@ public class ClusterInspector : Editor { public class GraphView : VisualElement { ClusterPrefab cluster; SerializedObject serializedBrain; - INucleus currentNucleus; + Nucleus currentNucleus; GameObject gameObject; private List layers = new(); - private readonly Dictionary neuroidPositions = new(); + private readonly Dictionary neuroidPositions = new(); private bool expandArray = false; ClusterWrapper currentWrapper; @@ -108,7 +108,7 @@ public class ClusterInspector : Editor { subscribed = false; } - public void SetGraph(GameObject gameObject, ClusterPrefab brain, INucleus nucleus, VisualElement inspectorContainer) { + public void SetGraph(GameObject gameObject, ClusterPrefab brain, Nucleus nucleus, VisualElement inspectorContainer) { this.gameObject = gameObject; this.cluster = brain; if (Application.isPlaying == false) @@ -136,14 +136,14 @@ public class ClusterInspector : Editor { this.layers = new(); int layerIx = 0; - INucleus selectedNucleus = this.currentNucleus; + Nucleus selectedNucleus = this.currentNucleus; if (selectedNucleus == null) return; NeuroidLayer currentLayer = new() { ix = layerIx }; if (selectedNucleus.receivers != null) { - foreach (INucleus receiver in selectedNucleus.receivers) { - INucleus outputNeuroid = receiver; + foreach (Nucleus receiver in selectedNucleus.receivers) { + Nucleus outputNeuroid = receiver; if (outputNeuroid != null) { AddToLayer(currentLayer, outputNeuroid); // Debug.Log($"layer {layerIx} nucleus {outputNeuroid.name}"); @@ -165,7 +165,7 @@ public class ClusterInspector : Editor { if (selectedNucleus.synapses != null) { foreach (Synapse synapse in selectedNucleus.synapses) { - INucleus input = synapse.nucleus; + Nucleus input = synapse.nucleus; AddToLayer(currentLayer, input); // Debug.Log($"layer {layerIx} nucleus {input.name}"); } @@ -175,7 +175,7 @@ public class ClusterInspector : Editor { } } - private void AddToLayer(NeuroidLayer layer, INucleus nucleus) { + private void AddToLayer(NeuroidLayer layer, Nucleus nucleus) { if (nucleus == null) return; layer.neuroids.Add(nucleus); @@ -210,7 +210,7 @@ public class ClusterInspector : Editor { // Draw selected Nucleus if (expandArray) { float maxValue = 0; - foreach (INucleus nucleus in this.currentNucleus.array.nuclei) { + foreach (Nucleus nucleus in this.currentNucleus.array.nuclei) { float value = length(nucleus.outputValue); if (value > maxValue) maxValue = value; @@ -231,7 +231,7 @@ public class ClusterInspector : Editor { Handles.color = Color.black; Handles.DrawAAConvexPolygon(verts); int row = 0; - foreach (INucleus nucleus in this.currentNucleus.array.nuclei) { + foreach (Nucleus nucleus in this.currentNucleus.array.nuclei) { Vector3 pos = new(150, margin + row * spacing, 0.0f); Handles.color = Color.white; // The selected nucleus highlight ring @@ -255,13 +255,13 @@ public class ClusterInspector : Editor { } } - private void DrawReceivers(INucleus nucleus, Vector3 parentPos, float size) { + private void DrawReceivers(Nucleus nucleus, Vector3 parentPos, float size) { int nodeCount = nucleus.receivers.Count(); // Determine the maximum value in this layer // This is used to 'scale' the output value colors of the nuclei float maxValue = 0; - foreach (INucleus receiver in nucleus.receivers) { + foreach (Nucleus receiver in nucleus.receivers) { if (receiver is Neuron neuroid) { float value = length(neuroid.outputValue); if (value > maxValue) @@ -275,12 +275,12 @@ public class ClusterInspector : Editor { int row = 0; List drawnArrays = new(); - foreach (INucleus receiver in nucleus.receivers) { + foreach (Nucleus receiver in nucleus.receivers) { if (drawnArrays.Contains(receiver.array)) continue; drawnArrays.Add(receiver.array); - INucleus receiverNucleus = receiver; + Nucleus receiverNucleus = receiver; if (receiverNucleus == null) continue; @@ -293,7 +293,7 @@ public class ClusterInspector : Editor { } } - private void DrawSynapses(INucleus nucleus, Vector3 parentPos, float size) { + private void DrawSynapses(Nucleus nucleus, Vector3 parentPos, float size) { int nodeCount = nucleus.synapses.Count; // Determine the maximum value in this layer @@ -344,7 +344,7 @@ public class ClusterInspector : Editor { } } - private void DrawNucleus(INucleus nucleus, Vector3 position, float maxValue, float size) { + private void DrawNucleus(Nucleus nucleus, Vector3 position, float maxValue, float size) { Color color; if (nucleus.isSleeping) color = Color.darkRed; @@ -359,7 +359,7 @@ public class ClusterInspector : Editor { DrawNucleus(nucleus, position, maxValue, size, color); } - private void DrawNucleus(INucleus nucleus, Vector3 position, float maxValue, float size, Color color) { + private void DrawNucleus(Nucleus nucleus, Vector3 position, float maxValue, float size, Color color) { if (nucleus is MemoryCell memory) { Handles.color = Color.white; Handles.DrawWireDisc(position + Vector3.right * 10, Vector3.forward, size); @@ -377,7 +377,7 @@ public class ClusterInspector : Editor { normal = { textColor = Color.white }, fontStyle = FontStyle.Bold, }; - if (nucleus is INucleus neuron) { + if (nucleus is Nucleus neuron) { if (neuron.array == null || neuron.array.nuclei == null || neuron.array.nuclei.Count() == 0) neuron.array = new NucleusArray(neuron); @@ -386,7 +386,7 @@ public class ClusterInspector : Editor { } if (expandArray && neuron.array.nuclei.First() == this.currentNucleus) { int arrayIx = 0; - foreach (INucleus n in neuron.array.nuclei) { + foreach (Nucleus n in neuron.array.nuclei) { if (n == neuron) break; arrayIx++; @@ -426,9 +426,9 @@ public class ClusterInspector : Editor { } } - private void HandleMouseHover(INucleus nucleus, Rect rect) { + private void HandleMouseHover(Nucleus nucleus, Rect rect) { GUIContent tooltip; - // if (nucleus is INucleus n) { + // if (nucleus is Nucleus n) { // tooltip = new( // $"{nucleus.name}" + // //$"\nsynapse count {n.synapses.Count}" + @@ -449,14 +449,14 @@ public class ClusterInspector : Editor { GUI.Box(tooltipRect, tooltip); } - private void HandleClicked(INucleus nucleus) { + private void HandleClicked(Nucleus nucleus) { if (nucleus == this.currentNucleus) { - if (nucleus is INucleus n) { + if (nucleus is Nucleus n) { expandArray = !expandArray; return; } } - else if (nucleus is INucleus n) { + else if (nucleus is Nucleus n) { this.currentNucleus = n; BuildLayers(); } @@ -598,7 +598,7 @@ public class ClusterInspector : Editor { } } - protected virtual void AddInput(int selectedInputType, INucleus nucleus) { + protected virtual void AddInput(int selectedInputType, Nucleus nucleus) { switch (selectedInputType) { case 0: // Neuron AddInputNeuron(nucleus); @@ -615,7 +615,7 @@ public class ClusterInspector : Editor { } } - protected virtual void AddInputNeuron(INucleus nucleus) { + protected virtual void AddInputNeuron(Nucleus nucleus) { //Neuron newNeuroid = new(this.cluster, "New neuron"); Neuron newNeuroid = new(this.cluster, "New neuron"); newNeuroid.AddReceiver(nucleus); @@ -623,12 +623,12 @@ public class ClusterInspector : Editor { BuildLayers(); } - protected virtual void DeleteNeuron(INucleus nucleus) { + protected virtual void DeleteNeuron(Nucleus nucleus) { if (nucleus == null) return; if (nucleus.cluster != null) this.currentNucleus = nucleus.cluster.output; - foreach (INucleus receiver in nucleus.receivers) { + foreach (Nucleus receiver in nucleus.receivers) { if (receiver != null) { this.currentNucleus = receiver; break; @@ -638,25 +638,25 @@ public class ClusterInspector : Editor { BuildLayers(); } - protected void AddSelectorInput(INucleus nucleus) { + protected void AddSelectorInput(Nucleus nucleus) { Selector newSelector = new(this.cluster, "New Selector"); newSelector.AddReceiver(nucleus); this.currentNucleus = newSelector; BuildLayers(); } - protected virtual void AddInputMemoryCell(INucleus nucleus) { + protected virtual void AddInputMemoryCell(Nucleus nucleus) { MemoryCell newMemory = new(this.cluster, "New memory cell"); newMemory.AddReceiver(nucleus); this.currentNucleus = newMemory; BuildLayers(); } - protected virtual void AddCluster(INucleus nucleus) { + protected virtual void AddCluster(Nucleus nucleus) { ClusterPickerWindow.ShowPicker(brain => OnClusterPicked(nucleus, brain), "Select Cluster"); } - private void OnClusterPicked(INucleus nucleus, ClusterPrefab prefab) { + private void OnClusterPicked(Nucleus nucleus, ClusterPrefab prefab) { Cluster subclusterInstance = new(prefab, this.cluster); subclusterInstance.AddReceiver(nucleus); // This does not work somehow @@ -672,7 +672,7 @@ public class ClusterInspector : Editor { } // Connect to another nucleus in the same cluster - protected virtual void ConnectNucleus(ClusterPrefab cluster, INucleus nucleus) { + protected virtual void ConnectNucleus(ClusterPrefab cluster, Nucleus nucleus) { if (cluster == null) return; @@ -692,7 +692,7 @@ public class ClusterInspector : Editor { // Nucleus n = this.currentNucleus.brain.nuclei[selectedIndex - perceptei.Count()]; // n.AddReceiver(this.currentNucleus); // } - INucleus receptor = cluster.nuclei[selectedIndex]; + Nucleus receptor = cluster.nuclei[selectedIndex]; receptor.AddReceiver(this.currentNucleus); } } @@ -734,17 +734,17 @@ public class ClusterInspector : Editor { public class NeuroidLayer { public int ix = 0; - public List neuroids = new(); + public List neuroids = new(); } public class ClusterWrapper : ScriptableObject { // expose fields that map to GraphNode //public string title; public Vector2 position; - INucleus node; + Nucleus node; ClusterPrefab graph; // needed to write back and mark dirty - public ClusterWrapper Init(INucleus node, ClusterPrefab graphAsset) { + public ClusterWrapper Init(Nucleus node, ClusterPrefab graphAsset) { this.node = node; this.graph = graphAsset; //this.title = " A " + node.name; diff --git a/Editor/NeuroidWindow.cs b/Editor/NeuroidWindow.cs deleted file mode 100644 index 187df35..0000000 --- a/Editor/NeuroidWindow.cs +++ /dev/null @@ -1,302 +0,0 @@ -/* -using UnityEditor; -using UnityEngine; -using System.Linq; -using System.Collections.Generic; - -public class NeuroidLayer { - public int ix = 0; - public List neuroids = new(); -} - -public class GraphEditorWindow : EditorWindow { - private Nucleus currentNucleus; - private List allNeuroids; - private Dictionary neuroidPositions = new(); - - private List layers = new(); - - private void OnEnable() { - EditorApplication.update += EditorUpdate; - Selection.selectionChanged += OnSelectionChange; - SelectNeuron(); - } - - private void AddToLayer(NeuroidLayer layer, Nucleus nucleus) { - layer.neuroids.Add(nucleus); - nucleus.layerIx = layer.ix; - // Store its position - Vector2Int neuroidPosition = new(layer.ix, layer.neuroids.Count - 1); - neuroidPositions[nucleus] = neuroidPosition; - - } - - private void BuildLayers() { - // A temporary list to track what's been added to layers - this.layers = new(); - int layerIx = 0; - - Nucleus selectedNucleus = this.currentNucleus; - if (selectedNucleus == null) - return; - NeuroidLayer currentLayer = new() { ix = layerIx }; - - //foreach (Nucleus outputNeuroid in selectedNucleus.receivers) { - foreach (Receiver receiver in selectedNucleus.receivers) { - Nucleus outputNeuroid = receiver.nucleus; - if (outputNeuroid != null) { - AddToLayer(currentLayer, outputNeuroid); - Debug.Log($"layer {layerIx} nucleus {outputNeuroid.name}"); - } - } - if (currentLayer.neuroids.Count > 0) { - this.layers.Add(currentLayer); - layerIx++; - currentLayer = new() { ix = layerIx }; - } - - AddToLayer(currentLayer, selectedNucleus); - this.layers.Add(currentLayer); - Debug.Log($"layer {layerIx} nucleus {selectedNucleus.name}"); - - layerIx++; - currentLayer = new() { ix = layerIx }; - - int six = 0; - // foreach (Synapse synapse in selectedNucleus.synapses.Values) { - // Debug.Log($"Synapse {six}"); - // Nucleus input = synapse.neuroid; - //foreach ((Nucleus input, Synapse synapse) in selectedNucleus.synapses) { - //foreach ((Nucleus input, float weight) in selectedNucleus.synapses) { - foreach (Synapse synapse in selectedNucleus.synapses) { - Nucleus input = synapse.nucleus; - if (input != null) { - AddToLayer(currentLayer, input); - Debug.Log($"layer {layerIx} nucleus {input.name}"); - } - six++; - } - if (currentLayer.neuroids.Count > 0) { - this.layers.Add(currentLayer); - } - } - - private void BuildLayers_old(List neuroids) { - if (neuroids == null) - return; - - // A temporary list to track what's been added to layers - this.layers = new(); - HashSet neuronVisited = new(); - int layerIx = 0; - - // While there are unvisited neuroid - while (neuroids.Any(neuroid => !neuronVisited.Contains(neuroid))) { - // Create the next layer - NeuroidLayer currentLayer = new() { ix = layerIx }; - int neuroidIx = 0; - - foreach (Neuroid neuroid in neuroids) { - // Skip neurons we already processed - if (neuronVisited.Contains(neuroid)) - continue; - - // if (neuroid.IsStale()) { - // Debug.Log($"neuron {neuroid.name} is stale {neuroid.stale}"); - // neuronVisited.Add(neuroid); - // continue; - // } - - // If the output neuroid is visited - // Note: this does not yet work for multiple outputs yet (see the use of First()) - // if (neuroid.receivers.Count == 0 // make sure the root neuroids are processed directly - // || (neuronVisited.Contains(neuroid.receivers.First()) && neuroid.receivers.First().layerIx == layerIx - 1)) { - if (neuroid.receivers.Count == 0 // make sure the root neuroids are processed directly - || (neuronVisited.Contains(neuroid.receivers.First().nucleus) && neuroid.receivers.First().nucleus.layerIx == layerIx - 1)) { - // Add it to the next layer - currentLayer.neuroids.Add(neuroid); - neuroid.layerIx = layerIx; - // Register it as visited - neuronVisited.Add(neuroid); - // Store its position - Vector2Int neuroidPosition = new(layerIx, neuroidIx); - neuroidPositions[neuroid] = neuroidPosition; - neuroidIx++; - Debug.Log($"Layer {layerIx} neuron {neuroidIx} name {neuroid.name}"); - } - } - - if (currentLayer.neuroids.Count > 0) { - this.layers.Add(currentLayer); - layerIx++; - } - } - } - - private void OnDisable() { - EditorApplication.update -= EditorUpdate; - Selection.selectionChanged -= OnSelectionChange; - } - - private void OnSelectionChange() { - SelectNeuron(); - Repaint(); - } - - private void EditorUpdate() { - if (EditorApplication.isPlaying) - Repaint(); - } - - private void OnGUI() { - GUILayout.Label("Graph Visualizer", EditorStyles.boldLabel); - - DrawGraph(); - } - - private void DrawGraph() { - if (currentNucleus == null) - return; - - foreach (NeuroidLayer layer in layers) - DrawLayer(layer); - } - - private void DrawLayer(NeuroidLayer layer) { - int column = layer.ix * 100; - int nodeCount = layer.neuroids.Count; - float maxValue = 0; - foreach (Nucleus nucleus in layer.neuroids) { - if (nucleus is Neuroid neuroid) { - float value = neuroid.outputValue.magnitude; - if (value > maxValue) - maxValue = value; - } - } - float spacing = 400f / nodeCount; - float margin = 100 + spacing / 2; - foreach (Nucleus layerNucleus in layer.neuroids) { - if (layerNucleus is Neuroid layerNeuroid) { - Vector2Int layerNeuroidPos = this.neuroidPositions[layerNeuroid]; - Vector3 parentPos = new(100 + layerNeuroidPos.x * 100, margin + layerNeuroidPos.y * spacing, 0.1f); - - int i = 0; - float inputSpacing = 400f / layerNeuroid.synapses.Count; - float inputMargin = 100 + inputSpacing / 2; - // foreach (Synapse synapse in layerNeuroid.synapses.Values) { - // if (synapse.neuroid != null) { - // if (this.neuroidPositions.ContainsKey(synapse.neuroid)) { - - // Vector2Int inputNeuroidPos = this.neuroidPositions[synapse.neuroid]; - //foreach ((Nucleus neuroid, Synapse synapse) in layerNeuroid.synapses) { - //foreach ((Nucleus neuroid, float weight) in layerNeuroid.synapses) { - foreach (Synapse synapse in layerNeuroid.synapses) { - Nucleus neuroid = synapse.nucleus; - float weight = synapse.weight; - if (neuroid != null) { - if (this.neuroidPositions.ContainsKey(neuroid)) { - Vector2Int inputNeuroidPos = this.neuroidPositions[neuroid]; - if (inputNeuroidPos.x == layerNeuroidPos.x + 1) { - Vector3 pos = new(100 + inputNeuroidPos.x * 100, inputMargin + inputNeuroidPos.y * inputSpacing, 0.0f); - - //float brightness = synapse.weight / 10.0f; - float brightness = weight / 10.0f; - Handles.color = new Color(brightness, brightness, brightness); - Handles.DrawLine(parentPos, pos); - } - } - } - } - - float size = 20; - if (layerNeuroid.isSleeping) - Handles.color = Color.black; - else { - float brightness = layerNeuroid.outputValue.magnitude / maxValue; - Handles.color = new Color(brightness, brightness, brightness); - } - Handles.DrawSolidDisc(parentPos, Vector3.forward, size); - Vector3 labelPos = parentPos - Vector3.down * (size + 0.2f); // below disc along up axis - GUIStyle style = new GUIStyle(EditorStyles.label) { - alignment = TextAnchor.UpperCenter, - normal = { textColor = Color.white }, - fontStyle = FontStyle.Bold - }; - Handles.Label(labelPos, layerNeuroid.name, style); - - Rect neuronRect = new(parentPos.x - size, parentPos.y - size, size * 2, size * 2); - Event e = Event.current; - if (e != null && neuronRect.Contains(e.mousePosition)) { - HandleMouseHover(layerNeuroid, neuronRect); - // Process click - if (e.type == EventType.MouseDown && e.button == 0) { - // Consume the event so the scene doesn't also handle it - e.Use(); - HandleDiscClicked(layerNeuroid); - } - } - i++; - } - } - } - - private void HandleMouseHover(Neuroid neuroid, Rect rect) { - GUIContent tooltip; - // if (neuroid is SensoryNeuroid sensoryNeuroid) { - // tooltip = new( - // $"{sensoryNeuroid.name}" + - // $"\nThing {sensoryNeuroid.receptor.thingType}" + - // $"\nValue: {neuroid.outputValue}"); - // } - // else { - tooltip = new( - $"{neuroid.name}" + - $"\nsynapse count {neuroid.synapses.Count}" + - $"\nValue: {neuroid.outputValue}"); - // } - - Vector2 mousePosition = Event.current.mousePosition; - - // Display tooltip with some offset - Vector2 tooltipSize = GUI.skin.box.CalcSize(tooltip); - Rect tooltipRect = new Rect(mousePosition.x + 10, mousePosition.y + 10, tooltipSize.x, tooltipSize.y); - - GUI.Box(tooltipRect, tooltip); - } - - private void HandleDiscClicked(Nucleus nucleus) { - this.currentNucleus = nucleus; - BuildLayers(); - } - - // Update node colors based on selected GameObjects - private void SelectNeuron() { - GameObject[] selectedObjects = Selection.gameObjects; - if (selectedObjects.Length == 0) - return; - - GameObject selectedObject = selectedObjects[0]; - Boid boid = selectedObject.GetComponent(); - if (boid == null) - return; - - // Nucleus neuroid = boid.behaviour; - // this.currentNucleus = neuroid; - // if (neuroid == null) - // this.allNeuroids = new(); - // else - // this.allNeuroids = neuroid.brain.neuroids; - - - // Debug.Log($"Neuroncount = {this.allNeuroids.Count}"); - // BuildLayers(); - // Debug.Log($"Layercount = {this.layers.Count}"); - - } - - [MenuItem("Window/Neuroid Visualizer")] - public static void ShowWindow() { - GetWindow("Neuroid Visualizer"); - } -} -*/ \ No newline at end of file diff --git a/Editor/NeuroidWindow.cs.meta b/Editor/NeuroidWindow.cs.meta deleted file mode 100644 index a8a1aa1..0000000 --- a/Editor/NeuroidWindow.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 26e68838038ea5243ae57bc81f4db8a8 \ No newline at end of file diff --git a/INucleus.cs b/INucleus.cs index 4869d33..17199fc 100644 --- a/INucleus.cs +++ b/INucleus.cs @@ -1,3 +1,4 @@ +/* using System.Collections.Generic; using Unity.Mathematics; @@ -11,7 +12,7 @@ public interface INucleus { // Senders public List synapses { get; } - public Synapse AddSynapse(INucleus sender, float weight = 1.0f); + public Synapse AddSynapse(Nucleus sender, float weight = 1.0f); public NucleusArray array { get; set; } @@ -21,8 +22,8 @@ public interface INucleus { // public void UpdateState(); // public void UpdateState(float3 inputValue); - public void UpdateStateIsolated(); - public void UpdateStateIsolated(float3 inputValue); + // public void UpdateStateIsolated(); + // public void UpdateStateIsolated(float3 inputValue); #endregion dynamic state @@ -31,10 +32,10 @@ public interface INucleus { public string name { get; set; } // Receivers - public List receivers { get; set; } + // public List receivers { get; set; } - public void AddReceiver(INucleus receiver, float weight = 1); - public void RemoveReceiver(INucleus receiverNucleus); + // public void AddReceiver(Nucleus receiver, float weight = 1); + // public void RemoveReceiver(Nucleus receiverNucleus); #endregion static @@ -48,10 +49,11 @@ public interface INucleus { #endregion dynamic - public INucleus ShallowCloneTo(Cluster parent); - public INucleus Clone(); + // public INucleus ShallowCloneTo(Cluster parent); + // public INucleus Clone(); } // public interface IReceptor { // } +*/ \ No newline at end of file diff --git a/MemoryCell.cs b/MemoryCell.cs index ab45440..5341220 100644 --- a/MemoryCell.cs +++ b/MemoryCell.cs @@ -13,7 +13,7 @@ public class MemoryCell : Neuron { // this.parent?.nuclei.Add(this); // } - public override INucleus ShallowCloneTo(Cluster newParent) { + public override Nucleus ShallowCloneTo(Cluster newParent) { MemoryCell clone = new(newParent, this.name) { array = this.array, curve = this.curve, diff --git a/NanoBrain.cs b/NanoBrain.cs index 5fc7643..930c6a1 100644 --- a/NanoBrain.cs +++ b/NanoBrain.cs @@ -30,7 +30,7 @@ public class NanoBrain : MonoBehaviour { public static void UpdateWeight(Cluster brain, string name, float weight) { - INucleus root = brain.output; + Nucleus root = brain.output; foreach (Synapse synapse in root.synapses) { if (synapse.nucleus.name == name) { if (synapse.weight != weight) { diff --git a/Neuron.cs b/Neuron.cs index ba861a0..41b41e8 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -181,7 +181,7 @@ public class Neuron : Nucleus { #endregion Runtime state // this clone the nucleus without the synapses and receivers - public override INucleus ShallowCloneTo(Cluster newParent) { + public override Nucleus ShallowCloneTo(Cluster newParent) { Neuron clone = new(newParent, this.name) { array = null, curve = this.curve, @@ -192,9 +192,9 @@ public class Neuron : Nucleus { return clone; } - public override INucleus Clone() { - //Neuron clone = new(this.cluster, this.name) { - Neuron clone = new(this.parent, this.name) { + public override Nucleus Clone() { + Neuron clone = new(this.cluster, this.name) { + //Neuron clone = new(this.parent, this.name) { array = this.array, curve = this.curve, curvePreset = this.curvePreset, @@ -208,7 +208,7 @@ public class Neuron : Nucleus { Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); clonedSynapse.weight = synapse.weight; } - foreach (INucleus receiver in this.receivers) { + foreach (Nucleus receiver in this.receivers) { clone.AddReceiver(receiver); } return clone; @@ -224,7 +224,7 @@ public class Neuron : Nucleus { // receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); // } - public static void Delete(INucleus nucleus) { + public static void Delete(Nucleus nucleus) { foreach (Synapse synapse in nucleus.synapses) { if (synapse.nucleus is Neuron synapse_nucleus) { if (synapse_nucleus.receivers.Count > 1) { @@ -237,7 +237,7 @@ public class Neuron : Nucleus { } } } - foreach (INucleus receiver in nucleus.receivers) { + foreach (Nucleus receiver in nucleus.receivers) { if (receiver != null && receiver.synapses != null) receiver.synapses.RemoveAll(s => s.nucleus == nucleus); } diff --git a/Nucleus.cs b/Nucleus.cs index f3621c0..9847a68 100644 --- a/Nucleus.cs +++ b/Nucleus.cs @@ -4,7 +4,8 @@ using UnityEngine; using Unity.Mathematics; using static Unity.Mathematics.math; -public abstract class Nucleus : INucleus { +[Serializable] +public abstract class Nucleus { [SerializeField] protected string _name; public virtual string name { @@ -31,10 +32,8 @@ public abstract class Nucleus : INucleus { [NonSerialized] public int stale = 1000; - // Cannot clone an abstract nucleus... - public virtual INucleus ShallowCloneTo(Cluster parent) { return null; } - // Cannot clone an abstract nucleus... - public virtual INucleus Clone() { return null; } + public abstract Nucleus ShallowCloneTo(Cluster parent); + public abstract Nucleus Clone(); #region Synapses @@ -42,13 +41,13 @@ public abstract class Nucleus : INucleus { private List _synapses = new(); public List synapses => _synapses; - public Synapse AddSynapse(INucleus sendingNucleus, float weight = 1.0f) { + public Synapse AddSynapse(Nucleus sendingNucleus, float weight = 1.0f) { Synapse synapse = new(sendingNucleus, weight); this.synapses.Add(synapse); return synapse; } - public Synapse GetSynapse(INucleus sender) { + public Synapse GetSynapse(Nucleus sender) { foreach (Synapse synapse in this.synapses) if (synapse.nucleus == sender) return synapse; @@ -60,18 +59,18 @@ public abstract class Nucleus : INucleus { #region Receivers [SerializeReference] - private List _receivers = new(); - public List receivers { + private List _receivers = new(); + public List receivers { get { return _receivers; } set { _receivers = value; } } - public virtual void AddReceiver(INucleus receivingNucleus, float weight = 1) { + public virtual void AddReceiver(Nucleus receivingNucleus, float weight = 1) { this._receivers.Add(receivingNucleus); receivingNucleus.AddSynapse(this, weight); } - public void RemoveReceiver(INucleus receiverNucleus) { + public void RemoveReceiver(Nucleus receiverNucleus) { this._receivers.RemoveAll(receiver => receiver == receiverNucleus); receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); } diff --git a/NucleusArray.cs b/NucleusArray.cs index 36d2417..af9bd63 100644 --- a/NucleusArray.cs +++ b/NucleusArray.cs @@ -5,26 +5,26 @@ using UnityEngine; [System.Serializable] public class NucleusArray { [SerializeReference] - private INucleus[] _nuclei; - public INucleus[] nuclei { + private Nucleus[] _nuclei; + public Nucleus[] nuclei { get { return _nuclei; } } public string name; - public NucleusArray(INucleus nucleus) { + public NucleusArray(Nucleus nucleus) { this.name = nucleus.name; - this._nuclei = new INucleus[1]; + this._nuclei = new Nucleus[1]; this._nuclei[0] = nucleus; } public NucleusArray(ClusterPrefab cluster) { this.name = cluster.name; - this._nuclei = new INucleus[0]; + this._nuclei = new Nucleus[0]; } public NucleusArray(int size, string name) { this.name = name; - this._nuclei = new INucleus[size]; + this._nuclei = new Nucleus[size]; } @@ -34,12 +34,12 @@ public class NucleusArray { return; } int newLength = this._nuclei.Length + 1; - INucleus[] newArray = new INucleus[newLength]; + Nucleus[] newArray = new Nucleus[newLength]; for (int i = 0; i < this._nuclei.Length; i++) newArray[i] = this._nuclei[i]; - if (this._nuclei[0] is INucleus nucleus) - newArray[newLength - 1] = (INucleus)nucleus.Clone(); + if (this._nuclei[0] is Nucleus nucleus) + newArray[newLength - 1] = nucleus.Clone(); this._nuclei = newArray; } @@ -50,25 +50,25 @@ public class NucleusArray { Debug.LogWarning("Perceptoid array cannot be empty"); return; } - INucleus[] newPerceptei = new INucleus[newLength]; + Nucleus[] newPerceptei = new Nucleus[newLength]; for (int i = 0; i < newLength; i++) newPerceptei[i] = this._nuclei[i]; // Delete the last perception - if (this._nuclei[newLength] is INucleus nucleus) + if (this._nuclei[newLength] is Nucleus nucleus) Neuron.Delete(nucleus); //this._nuclei[newLength]); this._nuclei = newPerceptei; } - public Dictionary thingReceivers = new(); + public Dictionary thingReceivers = new(); public virtual void ProcessStimulus(int thingId, Vector3 inputValue, string thingName = null) { CleanupReceivers(); - if (!thingReceivers.TryGetValue(thingId, out INucleus selectedReceiver)) { + if (!thingReceivers.TryGetValue(thingId, out Nucleus selectedReceiver)) { Debug.Log($"No receiver found for {thingId}"); - foreach (INucleus receptor in this.nuclei) { - if (receptor is not INucleus receiver) + foreach (Nucleus receptor in this.nuclei) { + if (receptor is not Nucleus receiver) continue; if (thingReceivers.ContainsValue(receiver) == false) { @@ -97,7 +97,7 @@ public class NucleusArray { private void CleanupReceivers() { // Remove a thing-receiver connection when the nucleus is inactive List receiversToRemove = new(); - foreach (KeyValuePair item in thingReceivers) { + foreach (KeyValuePair item in thingReceivers) { if (item.Value.isSleeping) { Nucleus n = item.Value as Nucleus; Debug.Log($"{item.Value.name} is sleeping, stale = {n.stale}"); @@ -105,7 +105,7 @@ public class NucleusArray { } } foreach (int thingId in receiversToRemove) { - INucleus selectedReceiver = thingReceivers[thingId]; + Nucleus selectedReceiver = thingReceivers[thingId]; thingReceivers.Remove(thingId); Debug.Log($"Cleanup receiver for {thingId}"); diff --git a/Selector.cs b/Selector.cs index 8cfe378..d4893fe 100644 --- a/Selector.cs +++ b/Selector.cs @@ -7,7 +7,7 @@ public class Selector : Neuron { public Selector(Cluster parent, string name) : base(parent, name) { } public Selector(ClusterPrefab parent, string name) : base(parent, name) {} - public override INucleus ShallowCloneTo(Cluster newParent) { + public override Nucleus ShallowCloneTo(Cluster newParent) { Selector clone = new(newParent, this.name) { array = this.array, curve = this.curve, diff --git a/Synapse.cs b/Synapse.cs index b56f241..53a7a51 100644 --- a/Synapse.cs +++ b/Synapse.cs @@ -4,11 +4,11 @@ using UnityEngine; [Serializable] public class Synapse { [SerializeReference] - public INucleus nucleus; + public Nucleus nucleus; public float weight; - public Synapse(INucleus nucleus, float weight = 1.0f) { + public Synapse(Nucleus nucleus, float weight = 1.0f) { this.nucleus = nucleus; this.weight = weight; } From 00dea149f3f15e71a15e600b19c0f14b7b507a15 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 5 Feb 2026 17:38:10 +0100 Subject: [PATCH 113/179] Cleanup --- Cluster.cs | 117 +------------------------------- Editor/NanoBrain_Editor.cs | 24 ------- INucleus.cs | 59 ---------------- INucleus.cs.meta | 2 - MemoryCell.cs | 39 ----------- NanoBrain.cs | 12 ---- Neuron.cs | 133 ------------------------------------- 7 files changed, 2 insertions(+), 384 deletions(-) delete mode 100644 INucleus.cs delete mode 100644 INucleus.cs.meta diff --git a/Cluster.cs b/Cluster.cs index 351176e..9d29581 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -7,14 +7,6 @@ using static Unity.Mathematics.math; [Serializable] public class Cluster : Nucleus { - // The ScriptableObject asset from which the runtime object has been created - - // [SerializeField] - // protected string _name; - // public virtual string name { - // get => _name; - // set => _name = value; - // } #region Init @@ -181,8 +173,6 @@ public class Cluster : Nucleus { public ClusterPrefab prefab; - // public ClusterPrefab cluster { get; set; } - // public Cluster parent { get; set; } [SerializeReference] public List nuclei = new(); @@ -215,14 +205,6 @@ public class Cluster : Nucleus { } } - // Not sure if this belongs here... - // [SerializeReference] - // private NucleusArray _array; - // public NucleusArray array { - // get { return _array; } - // set { _array = value; } - // } - public bool TryGetNucleus(string nucleusName, out Nucleus foundNucleus) { foreach (Nucleus receptor in this.nuclei) { if (receptor is Nucleus nucleus) @@ -244,92 +226,14 @@ public class Cluster : Nucleus { return null; } - #region Synapses - - // [SerializeField] - // private List _synapses = new(); - // public List synapses => _synapses; - - // public Synapse AddSynapse(Nucleus sendingNucleus, float weight = 1.0f) { - // Synapse synapse = new(sendingNucleus, weight); - // this._synapses.Add(synapse); - // return synapse; - // } - - // Does this even exist already? - public void RemoveSynapse() { - - } - - #endregion Synapses - - #region Receivers - - // [SerializeReference] - // private List _receivers = new(); - // public List receivers { - // get { return _receivers; } - // set { _receivers = value; } - // } - - // public virtual void AddReceiver(Nucleus receivingNucleus, float weight = 1) { - // this._receivers.Add(receivingNucleus); - // receivingNucleus.AddSynapse(this, weight); - // } - - // public void RemoveReceiver(Nucleus receiverNucleus) { - // this._receivers.RemoveAll(receiver => receiver == receiverNucleus); - // receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); - // } - - #endregion Receivers - - #region Runtime - - // [NonSerialized] - // private int stale = 1000; - // public bool isSleeping => lengthsq(this.outputValue) == 0; - - // [NonSerialized] - // protected float3 _outputValue; - // public virtual float3 outputValue { - // get { return _outputValue; } - // set { - // this.stale = 0; - // _outputValue = value; - // } - // } - #region Update - // public virtual void UpdateState() { - // UpdateState(new float3(0, 0, 0)); - // } - - // public void UpdateState(float3 bias) { - // float3 sum = bias; // new(0, 0, 0); - - // //Applying the weight factors - // foreach (Synapse synapse in this.synapses) { - // sum += synapse.weight * synapse.nucleus.outputValue; - // } - - // //this.inputs[0].UpdateState(sum); - // this.inputs[0].UpdateStateIsolated(sum); - // foreach (IReceptor receptor in this.sortedNuclei) { - // if (receptor is Nucleus nucleus && nucleus != this.inputs[0]) - // nucleus.UpdateStateIsolated(); - // } - - // UpdateResult(this.output.outputValue); - // } - public override void UpdateStateIsolated() { float3 bias = new(0, 0, 0); UpdateStateIsolated(bias); } public override void UpdateStateIsolated(float3 bias) { - float3 sum = bias; // new(0, 0, 0); + float3 sum = bias; //Applying the weight factors foreach (Synapse synapse in this.synapses) { @@ -339,42 +243,25 @@ public class Cluster : Nucleus { } } - //this.inputs[0].UpdateState(sum); this.inputs[0].UpdateStateIsolated(sum); foreach (Nucleus receptor in this.sortedNuclei) { - if (receptor is Nucleus nucleus && nucleus != this.inputs[0]) { - //if (nucleus.isSleeping == false) + if (receptor is Nucleus nucleus && nucleus != this.inputs[0]) nucleus.UpdateStateIsolated(); - } } this.outputValue = this.output.outputValue; UpdateNuclei(); } - // public virtual void UpdateResult(Vector3 result) { - // // float d = Vector3.Distance(result, this.outputValue); - // // if (d < 0.5f) { - // // //Debug.Log($"insignificant update: {d}"); - // // return; - // // } - - // this.outputValue = result; - // foreach (Nucleus receiver in this.receivers) - // receiver.UpdateState(); - // } - public override void UpdateNuclei() { this.stale++; if (this.stale > 5) _outputValue = Vector3.zero; - //foreach (IReceptor nucleus in this.prefab.nuclei) foreach (Nucleus nucleus in this.nuclei) nucleus.UpdateNuclei(); } #endregion Update - #endregion Runtime } diff --git a/Editor/NanoBrain_Editor.cs b/Editor/NanoBrain_Editor.cs index f4cd22b..646f384 100644 --- a/Editor/NanoBrain_Editor.cs +++ b/Editor/NanoBrain_Editor.cs @@ -87,30 +87,6 @@ public class NanoBrainComponent_Editor : Editor { return root; } - // void OnSceneGUI() { - // if (Application.isPlaying && board != null) - // board.OnIMGUI(); - // } - - // void OnSceneGui(SceneView sv) { - // if (Application.isPlaying == false) - // return; - // // May need some throttling here... - // if (board != null) { - // Debug.Log("."); - // board.OnIMGUI(); - // } - - // // EditorApplication.delayCall = UpdateInspectorUI; - // } - - // void UpdateInspectorUI() { - // if (board != null) { - // Debug.Log("."); - // board.OnIMGUI(); - // } - // } - private void UpdateLayout(float containerWidth) { // if (containerWidth > 800f) { mainContainer.style.flexDirection = FlexDirection.Row; diff --git a/INucleus.cs b/INucleus.cs deleted file mode 100644 index 17199fc..0000000 --- a/INucleus.cs +++ /dev/null @@ -1,59 +0,0 @@ -/* -using System.Collections.Generic; -using Unity.Mathematics; - -public interface INucleus { - - #region static struct - - // Cluster - public ClusterPrefab cluster { get; } - public Cluster parent { get; } - - // Senders - public List synapses { get; } - public Synapse AddSynapse(Nucleus sender, float weight = 1.0f); - - public NucleusArray array { get; set; } - - #endregion static struct - - #region dynamic state - - // public void UpdateState(); - // public void UpdateState(float3 inputValue); - // public void UpdateStateIsolated(); - // public void UpdateStateIsolated(float3 inputValue); - - #endregion dynamic state - - #region static - - public string name { get; set; } - - // Receivers - // public List receivers { get; set; } - - // public void AddReceiver(Nucleus receiver, float weight = 1); - // public void RemoveReceiver(Nucleus receiverNucleus); - - #endregion static - - #region dynamic - - // float3 to prepare for SIMD - public float3 outputValue { get; } - - public void UpdateNuclei(); - public bool isSleeping { get; } - - #endregion dynamic - - // public INucleus ShallowCloneTo(Cluster parent); - // public INucleus Clone(); -} - -// public interface IReceptor { -// } - -*/ \ No newline at end of file diff --git a/INucleus.cs.meta b/INucleus.cs.meta deleted file mode 100644 index aed95bb..0000000 --- a/INucleus.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 6a8a0e8965cea660abff254cab8a4723 \ No newline at end of file diff --git a/MemoryCell.cs b/MemoryCell.cs index 5341220..7da9ed1 100644 --- a/MemoryCell.cs +++ b/MemoryCell.cs @@ -8,10 +8,6 @@ public class MemoryCell : Neuron { public MemoryCell(ClusterPrefab cluster, string name) : base(cluster, name) { } public MemoryCell(Cluster parent, string name) : base(parent, name) { } - // this.parent = parent; - // this.name = name; - // this.parent?.nuclei.Add(this); - // } public override Nucleus ShallowCloneTo(Cluster newParent) { MemoryCell clone = new(newParent, this.name) { @@ -29,24 +25,6 @@ public class MemoryCell : Neuron { private float3 _memorizedValue; private float _memorizedTime; - // public override void UpdateState(float3 bias) { - // // A memorycell does not have an activation function - // float3 result = bias; - // int n = 0; - - // //Applying the weight factgors - // foreach (Synapse synapse in this.synapses) { - // result += synapse.weight * synapse.nucleus.outputValue; - // if (lengthsq(synapse.nucleus.outputValue) != 0) - // n++; - // } - - // if (this.average) - // result /= n; - - // UpdateResult(result); - // } - public override void UpdateStateIsolated() { float3 bias = new(0, 0, 0); UpdateStateIsolated(bias); @@ -73,22 +51,5 @@ public class MemoryCell : Neuron { this._memorizedTime = Time.time; } - // public override void UpdateResult(Vector3 result) { - // // output value is the previous value - // // if (this.deltaValue) { - // // float deltaTime = Time.time - this._memorizedTime; - // // this._outputValue = this._memorizedValue * deltaTime; - // // } - // //else - // this.outputValue = this._memorizedValue; - - // // Store the result for the next time - // this._memorizedValue = result; - // this._memorizedTime = Time.time; - - // foreach (INucleus receiver in this.receivers) - // receiver.UpdateState(); - // } - #endregion State } diff --git a/NanoBrain.cs b/NanoBrain.cs index 930c6a1..3e3ee21 100644 --- a/NanoBrain.cs +++ b/NanoBrain.cs @@ -13,22 +13,10 @@ public class NanoBrain : MonoBehaviour { name = defaultBrain.name + " (Instance)" }; } - // SwarmControl sc = FindFirstObjectByType(); - // if (sc != null) { - // UpdateWeight(brainInstance, "Containment", sc.containmentForce); - // UpdateWeight(brainInstance, "Cohesion", sc.cohesionForce); - // UpdateWeight(brainInstance, "Separation", sc.separationForce); - // UpdateWeight(brainInstance, "Alignment", sc.alignmentForce); - // } return brainInstance; } } - // public void Awake() { - // brainInstance = new Cluster(defaultBrain); - // } - - public static void UpdateWeight(Cluster brain, string name, float weight) { Nucleus root = brain.output; foreach (Synapse synapse in root.synapses) { diff --git a/Neuron.cs b/Neuron.cs index 41b41e8..aa62c72 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -24,31 +24,6 @@ public class Neuron : Nucleus { // Debug.LogError("No neuroid network"); } - // [SerializeField] - // protected string _name; - // public virtual string name { - // get => _name; - // set => _name = value; - // } - - // [SerializeField] - // private List _synapses = new(); - // public List synapses => _synapses; - - // [SerializeReference] - // private List _receivers = new(); - // public List receivers { - // get { return _receivers; } - // set { _receivers = value; } - // } - - // [SerializeReference] - // private NucleusArray _array; - // public NucleusArray array { - // get { return _array; } - // set { _array = value; } - // } - #region Serialization public enum CurvePresets { @@ -102,9 +77,6 @@ public class Neuron : Nucleus { #region Runtime state (not serialized) - // public ClusterPrefab cluster { get; set; } - // public Cluster parent { get; set; } - #region Activation public static class Presets { @@ -153,31 +125,6 @@ public class Neuron : Nucleus { #endregion Activation - // protected float3 _outputValue; - // public virtual float3 outputValue { - // get { return _outputValue; } - // set { - // this.stale = 0; - // // this._isSleeping = false; - // _outputValue = value; - // } - // } - - // [NonSerialized] - // private int stale = 1000; - - // private bool _isSleeping = false; - // public bool isSleeping => _isSleeping; - // public bool isSleeping => lengthsq(this.outputValue) == 0; - - // public void UpdateNuclei() { - // this.stale++; - // // this._isSleeping = this.stale > 2; - // // if (isSleeping) - // if (this.stale > 2) - // _outputValue = Vector3.zero; - // } - #endregion Runtime state // this clone the nucleus without the synapses and receivers @@ -214,16 +161,6 @@ public class Neuron : Nucleus { return clone; } - // public virtual void AddReceiver(INucleus receivingNucleus, float weight = 1) { - // this._receivers.Add(receivingNucleus); - // receivingNucleus.AddSynapse(this, weight); - // } - - // public void RemoveReceiver(INucleus receiverNucleus) { - // this._receivers.RemoveAll(receiver => receiver == receiverNucleus); - // receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); - // } - public static void Delete(Nucleus nucleus) { foreach (Synapse synapse in nucleus.synapses) { if (synapse.nucleus is Neuron synapse_nucleus) { @@ -248,59 +185,6 @@ public class Neuron : Nucleus { } } - // public Synapse AddSynapse(IReceptor sendingNucleus, float weight = 1.0f) { - // Synapse synapse = new(sendingNucleus, weight); - // this.synapses.Add(synapse); - // return synapse; - // } - - // public virtual void UpdateState() { - // //UpdateState(new float3(0, 0, 0)); - // this.parent?.UpdateState(); - // } - - // public virtual void UpdateState(float3 inputValue) { - // float3 sum = inputValue; - // int n = 0; - - // //Applying the weight factgors - // foreach (Synapse synapse in this.synapses) { - // sum += synapse.weight * synapse.nucleus.outputValue; - - // // Perhaps synapses should be removed when the output value goes to 0.... - // if (lengthsq(synapse.nucleus.outputValue) != 0) - // n++; - // } - // if (this.average && n > 0) - // sum /= n; - - // // Activation function - // Vector3 result; - // switch (this.curvePreset) { - // case CurvePresets.Linear: - // result = sum; - // break; - // case CurvePresets.Sqrt: - // result = normalize(sum) * System.MathF.Sqrt(length(sum)); - // break; - // case CurvePresets.Power: - // result = normalize(sum) * System.MathF.Pow(length(sum), 2); - // break; - // case CurvePresets.Reciprocal: - // result = normalize(sum) * (1 / length(sum)); - // break; - // default: - // float activatedValue = this.curve.Evaluate(length(sum)); - // result = normalize(sum) * activatedValue; - // break; - // } - // UpdateResult(result); - // } - - // public virtual void UpdateStateIsolated() { - // UpdateStateIsolated(new float3(0, 0, 0)); - // } - public float3 bias = float3(0, 0, 0); public override void UpdateStateIsolated(float3 bias_unused) { float3 sum = this.bias; @@ -354,21 +238,4 @@ public class Neuron : Nucleus { //Debug.Log($"{this.name} processed stimulus"); this.bias = inputValue; } - - // public virtual void UpdateResult(Vector3 result) { - // // float d = Vector3.Distance(result, this.outputValue); - // // if (d < 0.5f) { - // // //Debug.Log($"insignificant update: {d}"); - // // return; - // // } - - // this.outputValue = result; - // if (lengthsq(outputValue) != 0) { - // Debug.Log($"{this.parent.name}.{this.name}: {this.outputValue}"); - // } - - // foreach (INucleus receiver in this.receivers) - // receiver.UpdateState(); - - // } } \ No newline at end of file From 8eb1cbea1ac243904e093088bdf8b02d486bbf5e Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Fri, 6 Feb 2026 12:17:42 +0100 Subject: [PATCH 114/179] Fix brain prefab cloning --- Cluster.cs | 6 +++--- Editor/ClusterInspector.cs | 24 ++++++++++-------------- Nucleus.cs | 5 +++-- 3 files changed, 16 insertions(+), 19 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index 9d29581..e2a9fae 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -42,13 +42,13 @@ public class Cluster : Nucleus { // Now clone the connections for (int nucleusIx = 0; nucleusIx < prefabNuclei.Length; nucleusIx++) { - Nucleus receptor = prefabNuclei[nucleusIx]; + Nucleus prefabNucleus = prefabNuclei[nucleusIx]; Nucleus clonedReceptor = clonedNuclei[nucleusIx]; if (clonedReceptor == null) continue; // Copy the receivers, which will also create the synapses - foreach (Nucleus receiver in receptor.receivers) { + foreach (Nucleus receiver in prefabNucleus.receivers) { int ix = GetNucleusIndex(prefabNuclei, receiver); if (ix < 0) continue; @@ -60,7 +60,7 @@ public class Cluster : Nucleus { float weight = 1; foreach (Synapse synapse in receiver.synapses) { // Find the weight for this synapse - if (synapse.nucleus == receptor) { + if (synapse.nucleus == prefabNucleus) { weight = synapse.weight; break; } diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 45950e1..541134f 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -676,23 +676,19 @@ public class ClusterInspector : Editor { if (cluster == null) return; - IEnumerable synapseNuclei = this.currentNucleus.synapses.Select(synapse => synapse.nucleus != null ? synapse.nucleus.name : ""); - //IEnumerable perceptei = this.currentNucleus.brain.perceptei.Select(i => i.name).Except(synapseNuclei); - IEnumerable nuclei = cluster.nuclei.Select(i => i.name).Except(synapseNuclei); - //string[] names = perceptei.Concat(nuclei).ToArray(); - string[] names = nuclei.ToArray(); + IEnumerable synapseNuclei = this.currentNucleus.synapses + .Where(synapse => synapse.nucleus != null) + .Select(synapse => synapse.nucleus); + + IEnumerable nuclei = cluster.nuclei + .Except(synapseNuclei); + IEnumerable nucleiNames = nuclei.Select(n => n.name); + + string[] names = nucleiNames.ToArray(); int selectedIndex = -1; selectedIndex = EditorGUILayout.Popup("Connect to", selectedIndex, names); if (selectedIndex >= 0) { - // if (selectedIndex < perceptei.Count()) { - // Nucleus n = this.currentNucleus.brain.perceptei[selectedIndex]; - // n.AddReceiver(this.currentNucleus); - // } - // else { - // Nucleus n = this.currentNucleus.brain.nuclei[selectedIndex - perceptei.Count()]; - // n.AddReceiver(this.currentNucleus); - // } - Nucleus receptor = cluster.nuclei[selectedIndex]; + Nucleus receptor = nuclei.ElementAt(selectedIndex); receptor.AddReceiver(this.currentNucleus); } } diff --git a/Nucleus.cs b/Nucleus.cs index 9847a68..8652637 100644 --- a/Nucleus.cs +++ b/Nucleus.cs @@ -91,8 +91,9 @@ public abstract class Nucleus { UpdateStateIsolated(new float3(0, 0, 0)); } - public virtual void UpdateStateIsolated(float3 bias) { - } + public abstract void UpdateStateIsolated(float3 bias); + // public virtual void UpdateStateIsolated(float3 bias) { + // } public virtual void UpdateNuclei() { this.stale++; From 7fffa6dbe510478b11f314e2d921331bc3d8ccb3 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Fri, 6 Feb 2026 15:12:34 +0100 Subject: [PATCH 115/179] Added ants nest --- Editor/ClusterInspector.cs | 23 ++++++++++------------- NucleusArray.cs | 10 +++++----- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 541134f..47721a5 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -279,7 +279,7 @@ public class ClusterInspector : Editor { if (drawnArrays.Contains(receiver.array)) continue; drawnArrays.Add(receiver.array); - + Nucleus receiverNucleus = receiver; if (receiverNucleus == null) continue; @@ -396,7 +396,12 @@ public class ClusterInspector : Editor { else { style.alignment = TextAnchor.UpperCenter; Vector3 labelPos = position - Vector3.down * (size + 10f); // below disc along up axis - Handles.Label(labelPos, nucleus.name, style); + int colonPos = nucleus.name.IndexOf(":"); + if (colonPos > 0) { + string baseName = nucleus.name[..colonPos]; + Handles.Label(labelPos, baseName, style); + } else + Handles.Label(labelPos, nucleus.name, style); } if (nucleus is Cluster cluster) { @@ -428,17 +433,9 @@ public class ClusterInspector : Editor { private void HandleMouseHover(Nucleus nucleus, Rect rect) { GUIContent tooltip; - // if (nucleus is Nucleus n) { - // tooltip = new( - // $"{nucleus.name}" + - // //$"\nsynapse count {n.synapses.Count}" + - // $"\nValue: {length(nucleus.outputValue)}"); - // } - // else { - tooltip = new( - $"{nucleus.name}" + - $"\nValue: {length(nucleus.outputValue)}"); - // } + tooltip = new( + $"{nucleus.name}" + + $"\nValue: {length(nucleus.outputValue)}"); Vector2 mousePosition = Event.current.mousePosition; diff --git a/NucleusArray.cs b/NucleusArray.cs index af9bd63..543718d 100644 --- a/NucleusArray.cs +++ b/NucleusArray.cs @@ -66,20 +66,22 @@ public class NucleusArray { public virtual void ProcessStimulus(int thingId, Vector3 inputValue, string thingName = null) { CleanupReceivers(); if (!thingReceivers.TryGetValue(thingId, out Nucleus selectedReceiver)) { - Debug.Log($"No receiver found for {thingId}"); + // Debug.Log($"No receiver found for {thingId}"); foreach (Nucleus receptor in this.nuclei) { if (receptor is not Nucleus receiver) continue; if (thingReceivers.ContainsValue(receiver) == false) { // receiver is not used yet - Debug.Log($"{thingId} -> {receiver.name}"); + // Debug.Log($"{thingId} -> {receiver.name}"); thingReceivers.Add(thingId, receiver); selectedReceiver = receiver; break; } } } + if (selectedReceiver == null) + return; if (thingName != null) { string baseName = selectedReceiver.name; @@ -99,8 +101,7 @@ public class NucleusArray { List receiversToRemove = new(); foreach (KeyValuePair item in thingReceivers) { if (item.Value.isSleeping) { - Nucleus n = item.Value as Nucleus; - Debug.Log($"{item.Value.name} is sleeping, stale = {n.stale}"); + //Nucleus n = item.Value as Nucleus; receiversToRemove.Add(item.Key); } } @@ -108,7 +109,6 @@ public class NucleusArray { Nucleus selectedReceiver = thingReceivers[thingId]; thingReceivers.Remove(thingId); - Debug.Log($"Cleanup receiver for {thingId}"); int colonPos = selectedReceiver.name.IndexOf(":"); if (colonPos > 0) From 790deab7c6e08c7c663b6b25061915ae6d9ddbb2 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Fri, 6 Feb 2026 17:31:58 +0100 Subject: [PATCH 116/179] Add output nucleus selection --- Editor/ClusterInspector.cs | 122 +++++++++++++++++++++++++++---------- Editor/NanoBrain_Editor.cs | 111 ++++++++++++++++----------------- Nucleus.cs | 1 + 3 files changed, 145 insertions(+), 89 deletions(-) diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 47721a5..6ebb721 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -18,10 +18,56 @@ public class ClusterInspector : Editor { public override VisualElement CreateInspectorGUI() { ClusterPrefab cluster = target as ClusterPrefab; + if (cluster != null) + cluster.EnsureInitialization(); serializedObject.Update(); VisualElement root = new(); + //GraphView graph = + CreateInspector(root, cluster); + // root.style.paddingLeft = 0; + // root.style.paddingRight = 0; + // root.style.paddingTop = 0; + // root.style.paddingBottom = 0; + + // root.styleSheets.Add(Resources.Load("GraphStyles")); + + // mainContainer = new() { + // style = { + // height = 450 + // } + // }; + // GraphView graph = new(); + // graph.style.flexGrow = 1; + + // inspectorContainer = new VisualElement { + // name = "inspector" + // }; + + // mainContainer.Add(graph); + // mainContainer.Add(inspectorContainer); + // root.Add(mainContainer); + + // // Run once for initial state (use resolved style width if available) + // float initialWidth = root.layout.width > 0 ? root.layout.width : root.contentRect.width; + // UpdateLayout(initialWidth); + + // // React to size changes of root (or parent if appropriate) + // root.RegisterCallback(evt => { + // UpdateLayout(evt.newRect.width); + // }); + + //graph.SetGraph(null, cluster, cluster.output, inspectorContainer); + + // else + // Debug.LogWarning(" No brain!"); + + serializedObject.ApplyModifiedProperties(); + return root; + } + + public static GraphView CreateInspector(VisualElement root, ClusterPrefab cluster) { root.style.paddingLeft = 0; root.style.paddingRight = 0; root.style.paddingTop = 0; @@ -29,16 +75,23 @@ public class ClusterInspector : Editor { root.styleSheets.Add(Resources.Load("GraphStyles")); + // does the main container have added value? + // is just is like the root mainContainer = new() { style = { - height = 450 + height = 450, + flexDirection = FlexDirection.Row } }; GraphView graph = new(); graph.style.flexGrow = 1; inspectorContainer = new VisualElement { - // name = "inspector" + name = "inspector", + style = { + width = 300, + flexGrow = 0 + } }; mainContainer.Add(graph); @@ -47,24 +100,33 @@ public class ClusterInspector : Editor { // Run once for initial state (use resolved style width if available) float initialWidth = root.layout.width > 0 ? root.layout.width : root.contentRect.width; - UpdateLayout(initialWidth); + //UpdateLayout(initialWidth); // React to size changes of root (or parent if appropriate) - root.RegisterCallback(evt => { - UpdateLayout(evt.newRect.width); - }); + // root.RegisterCallback(evt => { + // UpdateLayout(evt.newRect.width); + // }); - if (cluster != null) { - cluster.EnsureInitialization(); - graph.SetGraph(null, cluster, cluster.output, inspectorContainer); - } - else - Debug.LogWarning(" No brain!"); + graph.SetGraph(null, cluster, cluster.output, inspectorContainer); - serializedObject.ApplyModifiedProperties(); - return root; + return graph; } + private static void UpdateLayout(float containerWidth) { + // if (containerWidth > 600f) { + // mainContainer.style.flexDirection = FlexDirection.Row; + // inspectorContainer.style.width = 300; // fixed sidebar width + // inspectorContainer.style.flexGrow = 0; + // } + // else { + // mainContainer.style.flexDirection = FlexDirection.Column; + // inspectorContainer.style.width = Length.Percent(100); // full width below + // inspectorContainer.style.flexDirection = FlexDirection.Column; + // inspectorContainer.style.flexGrow = 1; // can set 0 or keep as needed + // } + } + + public class GraphView : VisualElement { ClusterPrefab cluster; SerializedObject serializedBrain; @@ -76,6 +138,12 @@ public class ClusterInspector : Editor { ClusterWrapper currentWrapper; + public enum OutputNodes { + Output, + Output2, + Output3 + } + public GraphView() { name = "content"; style.flexGrow = 1; @@ -88,11 +156,17 @@ public class ClusterInspector : Editor { imguiContainer.focusable = true; Add(imguiContainer); + PopupField enumField = new(System.Enum.GetValues(typeof(OutputNodes)).Cast().ToList(), OutputNodes.Output); + enumField.RegisterValueChangedCallback(evt => OnOutputChanged(evt.newValue)); + Add(enumField); + // Subscribe when added to panel (editor UI ready) RegisterCallback(evt => Subscribe()); RegisterCallback(evt => Unsubscribe()); } + void OnOutputChanged(OutputNodes output) { + } bool subscribed = false; void Subscribe() { @@ -400,7 +474,8 @@ public class ClusterInspector : Editor { if (colonPos > 0) { string baseName = nucleus.name[..colonPos]; Handles.Label(labelPos, baseName, style); - } else + } + else Handles.Label(labelPos, nucleus.name, style); } @@ -706,23 +781,6 @@ public class ClusterInspector : Editor { #endregion Start - #region Update - - private void UpdateLayout(float containerWidth) { - // if (containerWidth > 600f) { - mainContainer.style.flexDirection = FlexDirection.Row; - inspectorContainer.style.width = 300; // fixed sidebar width - inspectorContainer.style.flexGrow = 0; - // } - // else { - // mainContainer.style.flexDirection = FlexDirection.Column; - // inspectorContainer.style.width = Length.Percent(100); // full width below - // inspectorContainer.style.flexDirection = FlexDirection.Column; - // inspectorContainer.style.flexGrow = 1; // can set 0 or keep as needed - // } - } - - #endregion Update } public class NeuroidLayer { diff --git a/Editor/NanoBrain_Editor.cs b/Editor/NanoBrain_Editor.cs index 646f384..3f4888a 100644 --- a/Editor/NanoBrain_Editor.cs +++ b/Editor/NanoBrain_Editor.cs @@ -11,14 +11,14 @@ public class NanoBrainComponent_Editor : Editor { protected NanoBrain component; private SerializedProperty brainProp; - ClusterInspector.GraphView board; + ClusterInspector.GraphView board; public void OnEnable() { component = target as NanoBrain; if (Application.isPlaying == false) brainProp = serializedObject.FindProperty(nameof(NanoBrain.defaultBrain)); - + } public override VisualElement CreateInspectorGUI() { @@ -29,56 +29,53 @@ public class NanoBrainComponent_Editor : Editor { VisualElement root = new(); - root.style.flexDirection = FlexDirection.Column; // side-by-side layout - root.style.flexGrow = 1; - root.style.minHeight = 600; - root.style.paddingLeft = 0; - root.style.paddingRight = 0; - root.style.paddingTop = 0; - root.style.paddingBottom = 0; + //ClusterInspector.GraphView board = + ClusterInspector.CreateInspector(root, brain.prefab); + // root.style.paddingLeft = 0; + // root.style.paddingRight = 0; + // root.style.paddingTop = 0; + // root.style.paddingBottom = 0; - root.styleSheets.Add(Resources.Load("GraphStyles")); + // root.styleSheets.Add(Resources.Load("GraphStyles")); - if (Application.isPlaying == false) { - PropertyField brainField = new(brainProp) { - label = "Nano Brain" - }; - root.Add(brainField); - } + // if (Application.isPlaying == false) { + // PropertyField brainField = new(brainProp) { + // label = "Nano Brain" + // }; + // root.Add(brainField); + // } - mainContainer = new() { - name = "main", - style = { - flexDirection = FlexDirection.Row, - flexGrow = 1, - minHeight = 500, - } - }; - board = new ClusterInspector.GraphView(); - board.style.flexGrow = 1; - mainContainer.Add(board); + // mainContainer = new() { + // name = "main", + // style = { + // height = 450, + // } + // }; + // board = new ClusterInspector.GraphView(); + // board.style.flexGrow = 1; + // mainContainer.Add(board); - inspectorContainer = new VisualElement { - name = "inspector", - style = { - width = 400, - } - }; + // inspectorContainer = new VisualElement { + // name = "inspector" + // // style = { + // // width = 400, + // // } + // }; - mainContainer.Add(inspectorContainer); - root.Add(mainContainer); + // mainContainer.Add(inspectorContainer); + // root.Add(mainContainer); - // Run once for initial state (use resolved style width if available) - float initialWidth = root.layout.width > 0 ? root.layout.width : root.contentRect.width; - UpdateLayout(initialWidth); + // // Run once for initial state (use resolved style width if available) + // float initialWidth = root.layout.width > 0 ? root.layout.width : root.contentRect.width; + // UpdateLayout(initialWidth); - // React to size changes of root (or parent if appropriate) - root.RegisterCallback(evt => { - UpdateLayout(evt.newRect.width); - }); + // // React to size changes of root (or parent if appropriate) + // root.RegisterCallback(evt => { + // UpdateLayout(evt.newRect.width); + // }); - if (brain != null && board != null) - board.SetGraph(component.gameObject, brain.prefab, brain.output, inspectorContainer); + // if (brain != null && board != null) + // board.SetGraph(component.gameObject, brain.prefab, brain.output, inspectorContainer); // else // Debug.LogWarning(" No brain!"); @@ -87,18 +84,18 @@ public class NanoBrainComponent_Editor : Editor { return root; } - private void UpdateLayout(float containerWidth) { - // if (containerWidth > 800f) { - mainContainer.style.flexDirection = FlexDirection.Row; - inspectorContainer.style.width = 400; // fixed sidebar width - inspectorContainer.style.flexGrow = 0; - // } - // else { - // mainContainer.style.flexDirection = FlexDirection.Column; - // inspectorContainer.style.width = Length.Percent(100); // full width below - // inspectorContainer.style.flexDirection = FlexDirection.Column; - // inspectorContainer.style.flexGrow = 1; // can set 0 or keep as needed - // } - } + // private void UpdateLayout(float containerWidth) { + // // if (containerWidth > 800f) { + // mainContainer.style.flexDirection = FlexDirection.Row; + // inspectorContainer.style.width = 300; // fixed sidebar width + // inspectorContainer.style.flexGrow = 0; + // // } + // // else { + // // mainContainer.style.flexDirection = FlexDirection.Column; + // // inspectorContainer.style.width = Length.Percent(100); // full width below + // // inspectorContainer.style.flexDirection = FlexDirection.Column; + // // inspectorContainer.style.flexGrow = 1; // can set 0 or keep as needed + // // } + // } } \ No newline at end of file diff --git a/Nucleus.cs b/Nucleus.cs index 8652637..247ffad 100644 --- a/Nucleus.cs +++ b/Nucleus.cs @@ -27,6 +27,7 @@ public abstract class Nucleus { _outputValue = value; } } + public bool isFiring => length(_outputValue) > 0.5f; public bool isSleeping => lengthsq(this.outputValue) == 0; [NonSerialized] From 278b861a84dc13f945c44f4fb957a355a6204397 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Fri, 6 Feb 2026 17:33:07 +0100 Subject: [PATCH 117/179] Cleanup --- Editor/ClusterInspector.cs | 60 ----------------------------------- Editor/NanoBrain_Editor.cs | 64 -------------------------------------- 2 files changed, 124 deletions(-) diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 6ebb721..972c955 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -24,44 +24,7 @@ public class ClusterInspector : Editor { serializedObject.Update(); VisualElement root = new(); - //GraphView graph = CreateInspector(root, cluster); - // root.style.paddingLeft = 0; - // root.style.paddingRight = 0; - // root.style.paddingTop = 0; - // root.style.paddingBottom = 0; - - // root.styleSheets.Add(Resources.Load("GraphStyles")); - - // mainContainer = new() { - // style = { - // height = 450 - // } - // }; - // GraphView graph = new(); - // graph.style.flexGrow = 1; - - // inspectorContainer = new VisualElement { - // name = "inspector" - // }; - - // mainContainer.Add(graph); - // mainContainer.Add(inspectorContainer); - // root.Add(mainContainer); - - // // Run once for initial state (use resolved style width if available) - // float initialWidth = root.layout.width > 0 ? root.layout.width : root.contentRect.width; - // UpdateLayout(initialWidth); - - // // React to size changes of root (or parent if appropriate) - // root.RegisterCallback(evt => { - // UpdateLayout(evt.newRect.width); - // }); - - //graph.SetGraph(null, cluster, cluster.output, inspectorContainer); - - // else - // Debug.LogWarning(" No brain!"); serializedObject.ApplyModifiedProperties(); return root; @@ -98,34 +61,11 @@ public class ClusterInspector : Editor { mainContainer.Add(inspectorContainer); root.Add(mainContainer); - // Run once for initial state (use resolved style width if available) - float initialWidth = root.layout.width > 0 ? root.layout.width : root.contentRect.width; - //UpdateLayout(initialWidth); - - // React to size changes of root (or parent if appropriate) - // root.RegisterCallback(evt => { - // UpdateLayout(evt.newRect.width); - // }); - graph.SetGraph(null, cluster, cluster.output, inspectorContainer); return graph; } - private static void UpdateLayout(float containerWidth) { - // if (containerWidth > 600f) { - // mainContainer.style.flexDirection = FlexDirection.Row; - // inspectorContainer.style.width = 300; // fixed sidebar width - // inspectorContainer.style.flexGrow = 0; - // } - // else { - // mainContainer.style.flexDirection = FlexDirection.Column; - // inspectorContainer.style.width = Length.Percent(100); // full width below - // inspectorContainer.style.flexDirection = FlexDirection.Column; - // inspectorContainer.style.flexGrow = 1; // can set 0 or keep as needed - // } - } - public class GraphView : VisualElement { ClusterPrefab cluster; diff --git a/Editor/NanoBrain_Editor.cs b/Editor/NanoBrain_Editor.cs index 3f4888a..658c02c 100644 --- a/Editor/NanoBrain_Editor.cs +++ b/Editor/NanoBrain_Editor.cs @@ -1,5 +1,4 @@ using UnityEditor; -using UnityEditor.UIElements; using UnityEngine; using UnityEngine.UIElements; @@ -18,7 +17,6 @@ public class NanoBrainComponent_Editor : Editor { if (Application.isPlaying == false) brainProp = serializedObject.FindProperty(nameof(NanoBrain.defaultBrain)); - } public override VisualElement CreateInspectorGUI() { @@ -29,73 +27,11 @@ public class NanoBrainComponent_Editor : Editor { VisualElement root = new(); - //ClusterInspector.GraphView board = ClusterInspector.CreateInspector(root, brain.prefab); - // root.style.paddingLeft = 0; - // root.style.paddingRight = 0; - // root.style.paddingTop = 0; - // root.style.paddingBottom = 0; - - // root.styleSheets.Add(Resources.Load("GraphStyles")); - - // if (Application.isPlaying == false) { - // PropertyField brainField = new(brainProp) { - // label = "Nano Brain" - // }; - // root.Add(brainField); - // } - - // mainContainer = new() { - // name = "main", - // style = { - // height = 450, - // } - // }; - // board = new ClusterInspector.GraphView(); - // board.style.flexGrow = 1; - // mainContainer.Add(board); - - // inspectorContainer = new VisualElement { - // name = "inspector" - // // style = { - // // width = 400, - // // } - // }; - - // mainContainer.Add(inspectorContainer); - // root.Add(mainContainer); - - // // Run once for initial state (use resolved style width if available) - // float initialWidth = root.layout.width > 0 ? root.layout.width : root.contentRect.width; - // UpdateLayout(initialWidth); - - // // React to size changes of root (or parent if appropriate) - // root.RegisterCallback(evt => { - // UpdateLayout(evt.newRect.width); - // }); - - // if (brain != null && board != null) - // board.SetGraph(component.gameObject, brain.prefab, brain.output, inspectorContainer); - // else - // Debug.LogWarning(" No brain!"); if (Application.isPlaying == false) serializedObject.ApplyModifiedProperties(); return root; } - // private void UpdateLayout(float containerWidth) { - // // if (containerWidth > 800f) { - // mainContainer.style.flexDirection = FlexDirection.Row; - // inspectorContainer.style.width = 300; // fixed sidebar width - // inspectorContainer.style.flexGrow = 0; - // // } - // // else { - // // mainContainer.style.flexDirection = FlexDirection.Column; - // // inspectorContainer.style.width = Length.Percent(100); // full width below - // // inspectorContainer.style.flexDirection = FlexDirection.Column; - // // inspectorContainer.style.flexGrow = 1; // can set 0 or keep as needed - // // } - // } - } \ No newline at end of file From 2cae7a6c41e68e80ae73c3cef521c6c7b0e751be Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Fri, 6 Feb 2026 18:06:36 +0100 Subject: [PATCH 118/179] initial multiple output support --- Cluster.cs | 24 +++++++++---- ClusterPrefab.cs | 23 +++++++++++++ Editor/ClusterInspector.cs | 70 +++++++++++++++++++++++++------------- 3 files changed, 88 insertions(+), 29 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index e2a9fae..e9eeb18 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -185,12 +185,10 @@ public class Cluster : Nucleus { get { if (this._inputs == null) { this._inputs = new(); - foreach (Nucleus receptor in this.nuclei) { - if (receptor is Nucleus nucleus) { - // inputs have no incoming synapses yet. - if (nucleus.synapses.Count == 0) - this._inputs.Add(nucleus); - } + foreach (Nucleus nucleus in this.nuclei) { + // inputs have no synapses + if (nucleus.synapses.Count == 0) + this._inputs.Add(nucleus); } } return this._inputs; @@ -204,6 +202,20 @@ public class Cluster : Nucleus { return null; } } + public List _outputs = null; + public List outputs { + get { + if (this._outputs == null) { + this._outputs = new(); + foreach (Nucleus nucleus in this.nuclei) { + // outputs have not receivers + if (nucleus.receivers.Count == 0) + this._outputs.Add(nucleus); + } + } + return this._outputs; + } + } public bool TryGetNucleus(string nucleusName, out Nucleus foundNucleus) { foreach (Nucleus receptor in this.nuclei) { diff --git a/ClusterPrefab.cs b/ClusterPrefab.cs index 5a390e8..ad98aac 100644 --- a/ClusterPrefab.cs +++ b/ClusterPrefab.cs @@ -28,6 +28,29 @@ public class ClusterPrefab : ScriptableObject { return this._inputs; } } + private List _outputs = null; + public List outputs { + get { + if (this._outputs == null) + RefreshOutputs(); + return this._outputs; + } + } + public void RefreshOutputs() { + this._outputs = new(); + foreach (Nucleus nucleus in this.nuclei) { + if (nucleus.receivers.Count == 0) + this._outputs.Add(nucleus); + } + } + + public Nucleus GetNucleus(string nucleusName) { + foreach (Nucleus nucleus in this.nuclei) { + if (nucleus.name == nucleusName) + return nucleus; + } + return null; + } // Call this function to ensure that there is at least one nucleus // This is an invariant and should be ensured before the nucleus is used diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 972c955..e1928f9 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -46,7 +46,7 @@ public class ClusterInspector : Editor { flexDirection = FlexDirection.Row } }; - GraphView graph = new(); + GraphView graph = new(cluster); graph.style.flexGrow = 1; inspectorContainer = new VisualElement { @@ -61,14 +61,14 @@ public class ClusterInspector : Editor { mainContainer.Add(inspectorContainer); root.Add(mainContainer); - graph.SetGraph(null, cluster, cluster.output, inspectorContainer); + graph.SetGraph(null, cluster.output, inspectorContainer); return graph; } public class GraphView : VisualElement { - ClusterPrefab cluster; + readonly ClusterPrefab cluster; SerializedObject serializedBrain; Nucleus currentNucleus; GameObject gameObject; @@ -77,35 +77,59 @@ public class ClusterInspector : Editor { private bool expandArray = false; ClusterWrapper currentWrapper; + PopupField outputsField; - public enum OutputNodes { - Output, - Output2, - Output3 - } + public GraphView(ClusterPrefab prefab) { + this.cluster = prefab; - public GraphView() { name = "content"; style.flexGrow = 1; - IMGUIContainer imguiContainer = new(OnIMGUI); - imguiContainer.style.position = Position.Absolute; - imguiContainer.style.left = 0; imguiContainer.style.top = 0; - imguiContainer.style.right = 0; imguiContainer.style.bottom = 0; - imguiContainer.pickingMode = PickingMode.Position; - imguiContainer.focusable = true; - Add(imguiContainer); + IMGUIContainer graphContainer = new(OnIMGUI); + graphContainer.style.position = Position.Absolute; + graphContainer.style.left = 0; graphContainer.style.top = 0; + graphContainer.style.right = 0; graphContainer.style.bottom = 0; + graphContainer.pickingMode = PickingMode.Position; + graphContainer.focusable = true; + Add(graphContainer); - PopupField enumField = new(System.Enum.GetValues(typeof(OutputNodes)).Cast().ToList(), OutputNodes.Output); - enumField.RegisterValueChangedCallback(evt => OnOutputChanged(evt.newValue)); - Add(enumField); + VisualElement outputContainer = new() { + style = { + flexDirection = FlexDirection.Row, + alignItems = Align.Center, + } + }; + + List names = this.cluster.outputs.Select(output => output.name).ToList(); + outputsField = new(names, names.First()) { + style = { flexGrow = 1 } + }; + outputsField.RegisterValueChangedCallback(evt => OnOutputChanged(evt.newValue)); + outputContainer.Add(outputsField); + + Button addButton = new(() => OnAddClusterOutput()) { + text = "Add" + }; + outputContainer.Add(addButton); + + Add(outputContainer); // Subscribe when added to panel (editor UI ready) RegisterCallback(evt => Subscribe()); RegisterCallback(evt => Unsubscribe()); } - void OnOutputChanged(OutputNodes output) { + void OnOutputChanged(string outputName) { + this.currentNucleus = this.cluster.GetNucleus(outputName); + } + + void OnAddClusterOutput() { + Nucleus newOutput = new Neuron(this.cluster, "Output 2"); + + outputsField.choices = this.cluster.outputs.Select(output => output.name).ToList(); + outputsField.value = newOutput.name; + + this.currentNucleus = newOutput; } bool subscribed = false; @@ -122,11 +146,11 @@ public class ClusterInspector : Editor { subscribed = false; } - public void SetGraph(GameObject gameObject, ClusterPrefab brain, Nucleus nucleus, VisualElement inspectorContainer) { + public void SetGraph(GameObject gameObject, Nucleus nucleus, VisualElement inspectorContainer) { this.gameObject = gameObject; - this.cluster = brain; + //this.cluster = brain; if (Application.isPlaying == false) - this.serializedBrain = new SerializedObject(brain); + this.serializedBrain = new SerializedObject(this.cluster); this.currentNucleus = nucleus; Rebuild(inspectorContainer); } From 7bcd4a6cf1d9b3c5844492e1ee45e440179195db Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 9 Feb 2026 09:22:31 +0100 Subject: [PATCH 119/179] ant and mouth share the same brain --- Cluster.cs | 8 ++++++-- Editor/ClusterInspector.cs | 2 +- Neuron.cs | 4 ++-- Nucleus.cs | 2 +- NucleusArray.cs | 4 ++-- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index e9eeb18..e94417b 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -86,8 +86,12 @@ public class Cluster : Nucleus { int arrayIx = 0; foreach (Nucleus prefabArrayNucleus in prefabNucleus.array.nuclei) { int arrayNucleusIx = GetNucleusIndex(prefabNuclei, prefabArrayNucleus); + if (arrayNucleusIx >= 0) { Nucleus clonedArrayNucleus = clonedNuclei[arrayNucleusIx]; clonedArray.nuclei[arrayIx] = clonedArrayNucleus; + } else { + Debug.LogError($" Could not find prefab nuclues {prefabNucleus.name} in the clones"); + } arrayIx++; } clonedNucleus.array = clonedArray; @@ -138,9 +142,9 @@ public class Cluster : Nucleus { return sortedOrder; } - public override Nucleus Clone() { + public override Nucleus Clone(ClusterPrefab prefab) { //Neuron clone = new(this.cluster, this.name) { - Neuron clone = new(this.parent, this.name) { + Neuron clone = new(prefab, this.name) { array = this.array, }; diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index e1928f9..1fa78ee 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -550,7 +550,7 @@ public class ClusterInspector : Editor { EditorGUILayout.BeginHorizontal(); EditorGUILayout.IntField("Array size", neuroid.array.nuclei.Count()); if (GUILayout.Button("Add")) - neuroid.array.AddNucleus(); + neuroid.array.AddNucleus(this.cluster); if (GUILayout.Button("Del")) neuroid.array.RemoveNucleus(); EditorGUILayout.EndHorizontal(); diff --git a/Neuron.cs b/Neuron.cs index aa62c72..4b86845 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -139,8 +139,8 @@ public class Neuron : Nucleus { return clone; } - public override Nucleus Clone() { - Neuron clone = new(this.cluster, this.name) { + public override Nucleus Clone(ClusterPrefab prefab) { + Neuron clone = new(prefab, this.name) { //Neuron clone = new(this.parent, this.name) { array = this.array, curve = this.curve, diff --git a/Nucleus.cs b/Nucleus.cs index 247ffad..25bebb1 100644 --- a/Nucleus.cs +++ b/Nucleus.cs @@ -34,7 +34,7 @@ public abstract class Nucleus { public int stale = 1000; public abstract Nucleus ShallowCloneTo(Cluster parent); - public abstract Nucleus Clone(); + public abstract Nucleus Clone(ClusterPrefab prefab); #region Synapses diff --git a/NucleusArray.cs b/NucleusArray.cs index 543718d..368aac3 100644 --- a/NucleusArray.cs +++ b/NucleusArray.cs @@ -28,7 +28,7 @@ public class NucleusArray { } - public void AddNucleus() { + public void AddNucleus(ClusterPrefab prefab) { if (this._nuclei.Length == 0) { Debug.LogError("Empty perceptoid array, cannot add"); return; @@ -39,7 +39,7 @@ public class NucleusArray { for (int i = 0; i < this._nuclei.Length; i++) newArray[i] = this._nuclei[i]; if (this._nuclei[0] is Nucleus nucleus) - newArray[newLength - 1] = nucleus.Clone(); + newArray[newLength - 1] = nucleus.Clone(prefab); this._nuclei = newArray; } From e8471683d6923598998c8e21725c6a7d248752b6 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 9 Feb 2026 09:53:33 +0100 Subject: [PATCH 120/179] Inspector cleanup --- Editor/ClusterInspector.cs | 87 ++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 46 deletions(-) diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 1fa78ee..2290d71 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -498,7 +498,8 @@ public class ClusterInspector : Editor { } } - private int selectedInputType = 0; + //private int selectedInputType = 0; + private bool showSynapses = true; void DrawInspector(VisualElement inspectorContainer) { if (inspectorContainer == null) return; @@ -517,19 +518,15 @@ public class ClusterInspector : Editor { if (this.currentNucleus == null) return; - GUIStyle headerStyle = new GUIStyle(EditorStyles.boldLabel) { + GUIStyle headerStyle = new(EditorStyles.boldLabel) { alignment = TextAnchor.MiddleLeft, margin = new RectOffset(10, 0, 4, 4) }; - //GUI.backgroundColor = EditorGUIUtility.isProSkin ? new Color(0.15f, 0.15f, 0.15f) : new Color(0.85f, 0.85f, 0.85f); - //GUILayout.BeginVertical("box"); - GUIStyle boldTextFieldStyle = new GUIStyle(EditorStyles.textField) { + GUIStyle boldTextFieldStyle = new(EditorStyles.textField) { fontStyle = FontStyle.Bold }; GUILayout.Label(this.currentNucleus.GetType().ToString(), headerStyle); - //GUILayout.EndVertical(); - //GUI.backgroundColor = Color.white; // Reset background color this.currentNucleus.name = EditorGUILayout.TextField(this.currentNucleus.name, boldTextFieldStyle); if (this.currentNucleus is Neuron neuroid) { if (this.currentNucleus is MemoryCell memory) { @@ -561,49 +558,36 @@ public class ClusterInspector : Editor { else EditorGUILayout.LabelField(" "); - if (this.currentNucleus.synapses.Count > 0) { - EditorGUILayout.LabelField("Synapses"); - Synapse[] synapses = this.currentNucleus.synapses.ToArray(); - foreach (Synapse synapse in synapses) { - if (synapse.nucleus != null) { - EditorGUILayout.Space(); + showSynapses = EditorGUILayout.BeginFoldoutHeaderGroup(showSynapses, "Synapses"); + if (showSynapses) { + ConnectNucleus(this.cluster, this.currentNucleus); + AddSynapse(this.cluster, this.currentNucleus); - //EditorGUI.BeginDisabledGroup(synapse.nucleus.isSleeping); - if (Application.isPlaying) - EditorGUILayout.FloatField(synapse.nucleus.name, length(synapse.nucleus.outputValue) * synapse.weight); - else { - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.LabelField(synapse.nucleus.name); - if (GUILayout.Button("Disconnect")) - synapse.nucleus.RemoveReceiver(this.currentNucleus); - EditorGUILayout.EndHorizontal(); + if (this.currentNucleus.synapses.Count > 0) { + Synapse[] synapses = this.currentNucleus.synapses.ToArray(); + foreach (Synapse synapse in synapses) { + if (synapse.nucleus != null) { + EditorGUILayout.Space(); + + //EditorGUI.BeginDisabledGroup(synapse.nucleus.isSleeping); + if (Application.isPlaying) + EditorGUILayout.FloatField(synapse.nucleus.name, length(synapse.nucleus.outputValue) * synapse.weight); + else { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField(synapse.nucleus.name); + if (GUILayout.Button("Disconnect")) + synapse.nucleus.RemoveReceiver(this.currentNucleus); + EditorGUILayout.EndHorizontal(); + } + + EditorGUI.indentLevel++; + synapse.weight = EditorGUILayout.FloatField("Weight", synapse.weight); + EditorGUI.indentLevel--; } - - EditorGUI.indentLevel++; - synapse.weight = EditorGUILayout.FloatField("Weight", synapse.weight); - EditorGUI.indentLevel--; - //EditorGUI.EndDisabledGroup(); } } } - - EditorGUILayout.Space(); - - ConnectNucleus(this.cluster, this.currentNucleus); - - EditorGUILayout.BeginHorizontal(); - string[] options = { "Neuron", "MemoryCell", "Selector", "Cluster" }; - selectedInputType = EditorGUILayout.Popup(selectedInputType, options); - if (GUILayout.Button("Add Input")) - AddInput(selectedInputType, this.currentNucleus); - EditorGUILayout.EndHorizontal(); - - // if (GUILayout.Button("Add Input Neuron")) - // AddInputNeuron(this.currentNucleus); - // if (GUILayout.Button("Add Input MemoryCell")) - // AddInputMemoryCell(this.currentNucleus); - // if (GUILayout.Button("Add Input Cluster")) - // AddCluster(this.currentNucleus); + EditorGUILayout.EndFoldoutHeaderGroup(); EditorGUILayout.Space(); @@ -722,13 +706,24 @@ public class ClusterInspector : Editor { string[] names = nucleiNames.ToArray(); int selectedIndex = -1; - selectedIndex = EditorGUILayout.Popup("Connect to", selectedIndex, names); + selectedIndex = EditorGUILayout.Popup("Connect", selectedIndex, names); if (selectedIndex >= 0) { Nucleus receptor = nuclei.ElementAt(selectedIndex); receptor.AddReceiver(this.currentNucleus); } } + protected virtual void AddSynapse(ClusterPrefab cluster, Nucleus nucleus) { + if (cluster == null) + return; + + string[] options = { "Neuron", "MemoryCell", "Selector", "Cluster" }; + int selectedInputType = -1; + selectedInputType = EditorGUILayout.Popup("Add", selectedInputType, options); + if (selectedInputType >= 0) + AddInput(selectedInputType, this.currentNucleus); + } + protected virtual void DisconnectNucleus(Neuron nucleus) { if (this.currentNucleus.cluster == null) return; From 9db7de16ea497ed9e469497675b5bc82c6e88b57 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 9 Feb 2026 11:32:25 +0100 Subject: [PATCH 121/179] Basic pheromone placement --- Editor/ClusterInspector.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 2290d71..436861e 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -498,8 +498,8 @@ public class ClusterInspector : Editor { } } - //private int selectedInputType = 0; private bool showSynapses = true; + protected bool breakOnWake = false; void DrawInspector(VisualElement inspectorContainer) { if (inspectorContainer == null) return; @@ -605,11 +605,19 @@ public class ClusterInspector : Editor { // Handles.color = Color.yellow; // Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); // } + + EditorGUILayout.Space(); + breakOnWake = EditorGUILayout.Toggle("Break on wake", breakOnWake); + if (breakOnWake) { + if (this.currentNucleus.isSleeping == false) + Debug.Break(); + } }); inspectorContainer.Add(container); } + void OnSceneGUI(SceneView sceneView) { if (this.gameObject != null) { Vector3 worldVector = this.gameObject.transform.TransformVector(this.currentNucleus.outputValue); From f5ed87f9e9409ba0b2b8b9bd86adf0bf3715d1d1 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 9 Feb 2026 11:49:58 +0100 Subject: [PATCH 122/179] home & food pheromones --- Editor/ClusterInspector.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 436861e..0e3f10c 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -124,7 +124,7 @@ public class ClusterInspector : Editor { } void OnAddClusterOutput() { - Nucleus newOutput = new Neuron(this.cluster, "Output 2"); + Nucleus newOutput = new Neuron(this.cluster, "New Output"); outputsField.choices = this.cluster.outputs.Select(output => output.name).ToList(); outputsField.value = newOutput.name; From 1e2726ecd46f76abbf94cb9f4ceb706d191ca664 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 9 Feb 2026 13:04:14 +0100 Subject: [PATCH 123/179] Foraging is working, but not correct yet --- Cluster.cs | 2 +- Editor/ClusterInspector.cs | 54 ++++++++++++++++++-------------------- Editor/NanoBrain_Editor.cs | 2 +- Neuron.cs | 2 +- Nucleus.cs | 3 ++- 5 files changed, 31 insertions(+), 32 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index e94417b..1868d91 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -271,7 +271,7 @@ public class Cluster : Nucleus { public override void UpdateNuclei() { this.stale++; - if (this.stale > 5) + if (this.stale > staleValueForSleep) _outputValue = Vector3.zero; foreach (Nucleus nucleus in this.nuclei) diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 0e3f10c..d4712bc 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -17,20 +17,20 @@ public class ClusterInspector : Editor { #region Start public override VisualElement CreateInspectorGUI() { - ClusterPrefab cluster = target as ClusterPrefab; - if (cluster != null) - cluster.EnsureInitialization(); + ClusterPrefab prefab = target as ClusterPrefab; + if (prefab != null) + prefab.EnsureInitialization(); serializedObject.Update(); VisualElement root = new(); - CreateInspector(root, cluster); + CreateInspector(root, prefab, prefab.output); serializedObject.ApplyModifiedProperties(); return root; } - public static GraphView CreateInspector(VisualElement root, ClusterPrefab cluster) { + public static GraphView CreateInspector(VisualElement root, ClusterPrefab cluster, Nucleus output) { root.style.paddingLeft = 0; root.style.paddingRight = 0; root.style.paddingTop = 0; @@ -61,14 +61,14 @@ public class ClusterInspector : Editor { mainContainer.Add(inspectorContainer); root.Add(mainContainer); - graph.SetGraph(null, cluster.output, inspectorContainer); + graph.SetGraph(null, output, inspectorContainer); return graph; } public class GraphView : VisualElement { - readonly ClusterPrefab cluster; + readonly ClusterPrefab prefab; SerializedObject serializedBrain; Nucleus currentNucleus; GameObject gameObject; @@ -80,7 +80,7 @@ public class ClusterInspector : Editor { PopupField outputsField; public GraphView(ClusterPrefab prefab) { - this.cluster = prefab; + this.prefab = prefab; name = "content"; style.flexGrow = 1; @@ -100,7 +100,7 @@ public class ClusterInspector : Editor { } }; - List names = this.cluster.outputs.Select(output => output.name).ToList(); + List names = this.prefab.outputs.Select(output => output.name).ToList(); outputsField = new(names, names.First()) { style = { flexGrow = 1 } }; @@ -120,13 +120,18 @@ public class ClusterInspector : Editor { } void OnOutputChanged(string outputName) { - this.currentNucleus = this.cluster.GetNucleus(outputName); + if (this.currentNucleus.parent != null) + // Get nucleus in the parent instance + this.currentNucleus = this.currentNucleus.parent.GetNucleus(outputName); + else + // Get nucleus in the prefab + this.currentNucleus = this.prefab.GetNucleus(outputName); } void OnAddClusterOutput() { - Nucleus newOutput = new Neuron(this.cluster, "New Output"); + Nucleus newOutput = new Neuron(this.prefab, "New Output"); - outputsField.choices = this.cluster.outputs.Select(output => output.name).ToList(); + outputsField.choices = this.prefab.outputs.Select(output => output.name).ToList(); outputsField.value = newOutput.name; this.currentNucleus = newOutput; @@ -150,7 +155,7 @@ public class ClusterInspector : Editor { this.gameObject = gameObject; //this.cluster = brain; if (Application.isPlaying == false) - this.serializedBrain = new SerializedObject(this.cluster); + this.serializedBrain = new SerializedObject(this.prefab); this.currentNucleus = nucleus; Rebuild(inspectorContainer); } @@ -165,7 +170,7 @@ public class ClusterInspector : Editor { if (currentWrapper != null) DestroyImmediate(currentWrapper); - currentWrapper = CreateInstance().Init(this.currentNucleus, cluster); + currentWrapper = CreateInstance().Init(this.currentNucleus, prefab); DrawInspector(inspectorContainer); } @@ -277,13 +282,6 @@ public class ClusterInspector : Editor { DrawNucleus(nucleus, pos, maxValue, size); row++; } - // GUIStyle style = new(EditorStyles.label) { - // alignment = TextAnchor.UpperCenter, - // normal = { textColor = Color.white }, - // fontStyle = FontStyle.Bold, - // }; - // Vector3 labelPos = new Vector3(150, yMax, 0) - Vector3.down * (size + 25); // below disc along up axis - // Handles.Label(labelPos, this.currentNucleus.name, style); } else { Handles.color = Color.white; @@ -547,7 +545,7 @@ public class ClusterInspector : Editor { EditorGUILayout.BeginHorizontal(); EditorGUILayout.IntField("Array size", neuroid.array.nuclei.Count()); if (GUILayout.Button("Add")) - neuroid.array.AddNucleus(this.cluster); + neuroid.array.AddNucleus(this.prefab); if (GUILayout.Button("Del")) neuroid.array.RemoveNucleus(); EditorGUILayout.EndHorizontal(); @@ -560,8 +558,8 @@ public class ClusterInspector : Editor { showSynapses = EditorGUILayout.BeginFoldoutHeaderGroup(showSynapses, "Synapses"); if (showSynapses) { - ConnectNucleus(this.cluster, this.currentNucleus); - AddSynapse(this.cluster, this.currentNucleus); + ConnectNucleus(this.prefab, this.currentNucleus); + AddSynapse(this.prefab, this.currentNucleus); if (this.currentNucleus.synapses.Count > 0) { Synapse[] synapses = this.currentNucleus.synapses.ToArray(); @@ -645,7 +643,7 @@ public class ClusterInspector : Editor { protected virtual void AddInputNeuron(Nucleus nucleus) { //Neuron newNeuroid = new(this.cluster, "New neuron"); - Neuron newNeuroid = new(this.cluster, "New neuron"); + Neuron newNeuroid = new(this.prefab, "New neuron"); newNeuroid.AddReceiver(nucleus); this.currentNucleus = newNeuroid; BuildLayers(); @@ -667,14 +665,14 @@ public class ClusterInspector : Editor { } protected void AddSelectorInput(Nucleus nucleus) { - Selector newSelector = new(this.cluster, "New Selector"); + Selector newSelector = new(this.prefab, "New Selector"); newSelector.AddReceiver(nucleus); this.currentNucleus = newSelector; BuildLayers(); } protected virtual void AddInputMemoryCell(Nucleus nucleus) { - MemoryCell newMemory = new(this.cluster, "New memory cell"); + MemoryCell newMemory = new(this.prefab, "New memory cell"); newMemory.AddReceiver(nucleus); this.currentNucleus = newMemory; BuildLayers(); @@ -685,7 +683,7 @@ public class ClusterInspector : Editor { } private void OnClusterPicked(Nucleus nucleus, ClusterPrefab prefab) { - Cluster subclusterInstance = new(prefab, this.cluster); + Cluster subclusterInstance = new(prefab, this.prefab); subclusterInstance.AddReceiver(nucleus); // This does not work somehow // this.currentNucleus = subclusterInstance; diff --git a/Editor/NanoBrain_Editor.cs b/Editor/NanoBrain_Editor.cs index 658c02c..138c901 100644 --- a/Editor/NanoBrain_Editor.cs +++ b/Editor/NanoBrain_Editor.cs @@ -27,7 +27,7 @@ public class NanoBrainComponent_Editor : Editor { VisualElement root = new(); - ClusterInspector.CreateInspector(root, brain.prefab); + ClusterInspector.CreateInspector(root, brain.prefab, brain.output); if (Application.isPlaying == false) serializedObject.ApplyModifiedProperties(); diff --git a/Neuron.cs b/Neuron.cs index 4b86845..a7b56fe 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -226,7 +226,7 @@ public class Neuron : Nucleus { result = normalize(sum) * activatedValue; break; } - if (this.stale > 5) + if (this.stale > staleValueForSleep) this.outputValue = new float3(0,0,0); else this.outputValue = result; diff --git a/Nucleus.cs b/Nucleus.cs index 25bebb1..ff61523 100644 --- a/Nucleus.cs +++ b/Nucleus.cs @@ -32,6 +32,7 @@ public abstract class Nucleus { public bool isSleeping => lengthsq(this.outputValue) == 0; [NonSerialized] public int stale = 1000; + public readonly int staleValueForSleep = 20; public abstract Nucleus ShallowCloneTo(Cluster parent); public abstract Nucleus Clone(ClusterPrefab prefab); @@ -98,7 +99,7 @@ public abstract class Nucleus { public virtual void UpdateNuclei() { this.stale++; - if (this.stale > 5) { + if (this.stale > staleValueForSleep) { //Debug.Log($"{this.name} goes to sleep, stale = {this.stale}"); _outputValue = Vector3.zero; } From c2dc2720b0410642f94e886df089151607cf2f3c Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 9 Feb 2026 16:04:07 +0100 Subject: [PATCH 124/179] Improved foraging --- ClusterPrefab.cs | 4 ++- Editor/ClusterInspector.cs | 2 +- NucleusArray.cs | 68 ++++++++++++++++++++++++++++---------- 3 files changed, 54 insertions(+), 20 deletions(-) diff --git a/ClusterPrefab.cs b/ClusterPrefab.cs index ad98aac..2fc6867 100644 --- a/ClusterPrefab.cs +++ b/ClusterPrefab.cs @@ -63,7 +63,9 @@ public class ClusterPrefab : ScriptableObject { public void GarbageCollection() { HashSet visitedNuclei = new(); - MarkNuclei(visitedNuclei, this.output); + foreach (Nucleus output in this.outputs) + MarkNuclei(visitedNuclei, output); + //MarkNuclei(visitedNuclei, this.output); //Debug.Log($"Garbage collection found {visitedNuclei.Count} Nuclei"); this.nuclei.RemoveAll(nucleus => nucleus is Nucleus n && visitedNuclei.Contains(n) == false); } diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index d4712bc..4018cc9 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -130,7 +130,7 @@ public class ClusterInspector : Editor { void OnAddClusterOutput() { Nucleus newOutput = new Neuron(this.prefab, "New Output"); - + this.prefab.RefreshOutputs(); outputsField.choices = this.prefab.outputs.Select(output => output.name).ToList(); outputsField.value = newOutput.name; diff --git a/NucleusArray.cs b/NucleusArray.cs index 368aac3..89ae516 100644 --- a/NucleusArray.cs +++ b/NucleusArray.cs @@ -1,6 +1,8 @@ using System.Linq; using System.Collections.Generic; using UnityEngine; +using Unity.Mathematics; +using static Unity.Mathematics.math; [System.Serializable] public class NucleusArray { @@ -63,25 +65,57 @@ public class NucleusArray { public Dictionary thingReceivers = new(); - public virtual void ProcessStimulus(int thingId, Vector3 inputValue, string thingName = null) { - CleanupReceivers(); - if (!thingReceivers.TryGetValue(thingId, out Nucleus selectedReceiver)) { - // Debug.Log($"No receiver found for {thingId}"); - foreach (Nucleus receptor in this.nuclei) { - if (receptor is not Nucleus receiver) - continue; - - if (thingReceivers.ContainsValue(receiver) == false) { - // receiver is not used yet - // Debug.Log($"{thingId} -> {receiver.name}"); - thingReceivers.Add(thingId, receiver); + private Nucleus FindReceiver(int thingId, float3 inputValue) { + // No existing nucleus for this thing + float inputMagnitude = length(inputValue); + Nucleus selectedReceiver = null; + float selectedMagnitude = 0; + foreach (Nucleus receiver in this.nuclei) { + if (thingReceivers.ContainsValue(receiver) == false) { + // We found an unusued receiver + thingReceivers.Add(thingId, receiver); + return receiver; + } + else if (receiver.isSleeping) { + // A sleeping receiver is not active and can therefore always be used + thingReceivers.Add(thingId, receiver); + return receiver; + } + else if (selectedReceiver == null) { + // If we haven't found a receiver yet, just start by taking the first + selectedReceiver = receiver; + selectedMagnitude = length(selectedReceiver.outputValue); + } + // Look for the receiver with the lowest magnitude + else { + float magnitude = length(receiver.outputValue); + + if (magnitude < inputMagnitude && length(receiver.outputValue) < selectedMagnitude) { selectedReceiver = receiver; - break; + selectedMagnitude = length(selectedReceiver.outputValue); } } } + if (selectedReceiver != null) { + // Replace the receiver + // Find the thingId current associated with the receiver + int keyToRemove = thingReceivers.FirstOrDefault(r => r.Value.Equals(selectedReceiver)).Key; + if (keyToRemove != 0 || thingReceivers.ContainsKey(keyToRemove)) + thingReceivers.Remove(keyToRemove); + // And add the new association + thingReceivers.Add(thingId, selectedReceiver); + } + return selectedReceiver; + } + + public virtual void ProcessStimulus(int thingId, Vector3 inputValue, string thingName = null) { + CleanupReceivers(); + if (!thingReceivers.TryGetValue(thingId, out Nucleus selectedReceiver)) { + // No existing nucleus for this thing + selectedReceiver = FindReceiver(thingId, inputValue); + } if (selectedReceiver == null) - return; + return; if (thingName != null) { string baseName = selectedReceiver.name; @@ -100,10 +134,8 @@ public class NucleusArray { // Remove a thing-receiver connection when the nucleus is inactive List receiversToRemove = new(); foreach (KeyValuePair item in thingReceivers) { - if (item.Value.isSleeping) { - //Nucleus n = item.Value as Nucleus; - receiversToRemove.Add(item.Key); - } + if (item.Value.isSleeping) + receiversToRemove.Add(item.Key); } foreach (int thingId in receiversToRemove) { Nucleus selectedReceiver = thingReceivers[thingId]; From a95c685e1e5e134bb967a398ab14e94964332d33 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 9 Feb 2026 16:55:22 +0100 Subject: [PATCH 125/179] HasFood is now up/down --- Cluster.cs | 2 +- MemoryCell.cs | 2 +- Neuron.cs | 2 +- Nucleus.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index 1868d91..de9b6d0 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -249,7 +249,7 @@ public class Cluster : Nucleus { UpdateStateIsolated(bias); } public override void UpdateStateIsolated(float3 bias) { - float3 sum = bias; + Vector3 sum = bias; //Applying the weight factors foreach (Synapse synapse in this.synapses) { diff --git a/MemoryCell.cs b/MemoryCell.cs index 7da9ed1..dd69652 100644 --- a/MemoryCell.cs +++ b/MemoryCell.cs @@ -31,7 +31,7 @@ public class MemoryCell : Neuron { } public override void UpdateStateIsolated(float3 bias) { // A memorycell does not have an activation function - float3 result = bias; + Vector3 result = bias; int n = 0; //Applying the weight factgors diff --git a/Neuron.cs b/Neuron.cs index a7b56fe..3992323 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -187,7 +187,7 @@ public class Neuron : Nucleus { public float3 bias = float3(0, 0, 0); public override void UpdateStateIsolated(float3 bias_unused) { - float3 sum = this.bias; + Vector3 sum = this.bias; int n = 0; //Applying the weight factgors diff --git a/Nucleus.cs b/Nucleus.cs index ff61523..dcc30dd 100644 --- a/Nucleus.cs +++ b/Nucleus.cs @@ -18,7 +18,7 @@ public abstract class Nucleus { public Cluster parent { get; set; } protected float3 _outputValue; - public virtual float3 outputValue { + public virtual Vector3 outputValue { get { return _outputValue; } set { //Debug.Log($"{this.name}: stale is reset, was: {this.stale}"); From 76c5372089c24416873d6586820dfb945aa0f9c4 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 9 Feb 2026 17:49:19 +0100 Subject: [PATCH 126/179] WIp pheromone selection in brain --- Cluster.cs | 5 ++ Editor/ClusterInspector.cs | 112 +++++++++++++++++++++++++++---------- Neuron.cs | 3 +- Nucleus.cs | 17 +++--- 4 files changed, 99 insertions(+), 38 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index de9b6d0..d65656a 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -19,6 +19,9 @@ public class Cluster : Nucleus { ClonePrefab(); this.sortedNuclei = TopologicalSort(this.nuclei); + // Does not work because we have nuclei with the same names in an nucleusArray + // 'Pheromone steering' + //this.nucleiDict = nuclei.ToDictionary(nucleus => nucleus.name); } public Cluster(ClusterPrefab prefab, ClusterPrefab parent = null) { @@ -31,6 +34,7 @@ public class Cluster : Nucleus { ClonePrefab(); this.sortedNuclei = TopologicalSort(this.nuclei); + //this.nucleiDict = nuclei.ToDictionary(nucleus => nucleus.name); } private void ClonePrefab() { @@ -183,6 +187,7 @@ public class Cluster : Nucleus { // the nuclei sorted using topological sorting // to ensure that the cluster is computer in the right order public List sortedNuclei; + //public Dictionary nucleiDict = new(); public List _inputs = null; public virtual List inputs { diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 4018cc9..4d4d941 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -497,6 +497,7 @@ public class ClusterInspector : Editor { } private bool showSynapses = true; + private bool showActivation = true; protected bool breakOnWake = false; void DrawInspector(VisualElement inspectorContainer) { if (inspectorContainer == null) @@ -525,34 +526,43 @@ public class ClusterInspector : Editor { }; GUILayout.Label(this.currentNucleus.GetType().ToString(), headerStyle); - this.currentNucleus.name = EditorGUILayout.TextField(this.currentNucleus.name, boldTextFieldStyle); - if (this.currentNucleus is Neuron neuroid) { - if (this.currentNucleus is MemoryCell memory) { - } - else { - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.LabelField("Activation Curve", GUILayout.Width(150)); - if (neuroid.curveMax > 0) - EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, 0, 1, neuroid.curveMax)); - else - EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, neuroid.curveMax, 1, -neuroid.curveMax)); - neuroid.curvePreset = (Neuron.CurvePresets)EditorGUILayout.EnumPopup(neuroid.curvePreset, GUILayout.Width(100)); - EditorGUILayout.EndHorizontal(); - } - - if (neuroid.array == null || neuroid.array.nuclei == null || neuroid.array.nuclei.Count() == 0) - neuroid.array = new NucleusArray(neuroid); - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.IntField("Array size", neuroid.array.nuclei.Count()); - if (GUILayout.Button("Add")) - neuroid.array.AddNucleus(this.prefab); - if (GUILayout.Button("Del")) - neuroid.array.RemoveNucleus(); - EditorGUILayout.EndHorizontal(); + string newName = EditorGUILayout.TextField(this.currentNucleus.name, boldTextFieldStyle); + if (newName != this.currentNucleus.name) { + this.currentNucleus.name = newName; + this.prefab.RefreshOutputs(); + outputsField.choices = this.prefab.outputs.Select(output => output.name).ToList(); + //outputsField.value = newName; } + //if (this.currentNucleus is Neuron neuron) { + // if (this.currentNucleus is MemoryCell memory) { + // } + // else { + // EditorGUILayout.BeginHorizontal(); + // EditorGUILayout.LabelField("Activation Curve", GUILayout.Width(150)); + // if (neuron.curveMax > 0) + // EditorGUILayout.CurveField(neuron.curve, Color.cyan, new Rect(0, 0, 1, neuron.curveMax)); + // else + // EditorGUILayout.CurveField(neuron.curve, Color.cyan, new Rect(0, neuron.curveMax, 1, -neuron.curveMax)); + // neuron.curvePreset = (Neuron.CurvePresets)EditorGUILayout.EnumPopup(neuron.curvePreset, GUILayout.Width(100)); + // EditorGUILayout.EndHorizontal(); + // } - if (Application.isPlaying) - EditorGUILayout.FloatField("Output", length(this.currentNucleus.outputValue)); + // if (neuron.array == null || neuron.array.nuclei == null || neuron.array.nuclei.Count() == 0) + // neuron.array = new NucleusArray(neuron); + // EditorGUILayout.BeginHorizontal(); + // EditorGUILayout.IntField("Array size", neuron.array.nuclei.Count()); + // if (GUILayout.Button("Add")) + // neuron.array.AddNucleus(this.prefab); + // if (GUILayout.Button("Del")) + // neuron.array.RemoveNucleus(); + // EditorGUILayout.EndHorizontal(); + //} + + + if (Application.isPlaying) { + GUIContent nameLabel = new("Output", this.currentNucleus.outputValue.ToString()); + EditorGUILayout.FloatField(nameLabel, length(this.currentNucleus.outputValue)); + } else EditorGUILayout.LabelField(" "); @@ -561,16 +571,29 @@ public class ClusterInspector : Editor { ConnectNucleus(this.prefab, this.currentNucleus); AddSynapse(this.prefab, this.currentNucleus); + this.currentNucleus.bias = EditorGUILayout.Vector3Field("Bias", this.currentNucleus.bias); + + NucleusArray array = null; if (this.currentNucleus.synapses.Count > 0) { Synapse[] synapses = this.currentNucleus.synapses.ToArray(); foreach (Synapse synapse in synapses) { if (synapse.nucleus != null) { + if (array != null) { + if (array.nuclei.Contains(synapse.nucleus)) + continue; + } + else { + if (synapse.nucleus.array != null && synapse.nucleus.array.nuclei.Length > 1) + array = synapse.nucleus.array; + } + EditorGUILayout.Space(); - //EditorGUI.BeginDisabledGroup(synapse.nucleus.isSleeping); - if (Application.isPlaying) - EditorGUILayout.FloatField(synapse.nucleus.name, length(synapse.nucleus.outputValue) * synapse.weight); - else { + if (Application.isPlaying) { + Vector3 value = synapse.nucleus.outputValue * synapse.weight; + GUIContent synapseValueLabel = new(synapse.nucleus.name, synapse.nucleus.outputValue.ToString()); + EditorGUILayout.FloatField(synapseValueLabel, length(synapse.nucleus.outputValue)); + } else { EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField(synapse.nucleus.name); if (GUILayout.Button("Disconnect")) @@ -588,6 +611,35 @@ public class ClusterInspector : Editor { EditorGUILayout.EndFoldoutHeaderGroup(); EditorGUILayout.Space(); + showActivation = EditorGUILayout.BeginFoldoutHeaderGroup(showActivation, "Activation"); + if (showActivation) { + + if (this.currentNucleus is Neuron neuron) { + if (this.currentNucleus is not MemoryCell memory) { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Activation Curve", GUILayout.Width(150)); + if (neuron.curveMax > 0) + EditorGUILayout.CurveField(neuron.curve, Color.cyan, new Rect(0, 0, 1, neuron.curveMax)); + else + EditorGUILayout.CurveField(neuron.curve, Color.cyan, new Rect(0, neuron.curveMax, 1, -neuron.curveMax)); + neuron.curvePreset = (Neuron.CurvePresets)EditorGUILayout.EnumPopup(neuron.curvePreset, GUILayout.Width(100)); + EditorGUILayout.EndHorizontal(); + } + if (neuron.array == null || neuron.array.nuclei == null || neuron.array.nuclei.Count() == 0) + neuron.array = new NucleusArray(neuron); + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.IntField("Array size", neuron.array.nuclei.Count()); + if (GUILayout.Button("Add")) + neuron.array.AddNucleus(this.prefab); + if (GUILayout.Button("Del")) + neuron.array.RemoveNucleus(); + EditorGUILayout.EndHorizontal(); + } + + EditorGUILayout.Space(); + } + EditorGUILayout.EndFoldoutHeaderGroup(); + if (GUILayout.Button("Delete this neuron")) DeleteNeuron(this.currentNucleus); diff --git a/Neuron.cs b/Neuron.cs index 3992323..c6c8221 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -131,6 +131,7 @@ public class Neuron : Nucleus { public override Nucleus ShallowCloneTo(Cluster newParent) { Neuron clone = new(newParent, this.name) { array = null, + bias = this.bias, curve = this.curve, curvePreset = this.curvePreset, curveMax = this.curveMax, @@ -185,7 +186,7 @@ public class Neuron : Nucleus { } } - public float3 bias = float3(0, 0, 0); + //public float3 bias = float3(0, 0, 0); public override void UpdateStateIsolated(float3 bias_unused) { Vector3 sum = this.bias; int n = 0; diff --git a/Nucleus.cs b/Nucleus.cs index dcc30dd..fe5eae4 100644 --- a/Nucleus.cs +++ b/Nucleus.cs @@ -6,13 +6,14 @@ using static Unity.Mathematics.math; [Serializable] public abstract class Nucleus { - [SerializeField] - protected string _name; - public virtual string name { - get => _name; - set => _name = value; - } - + // [SerializeField] + // protected string _name; + // public virtual string name { + // get => _name; + // set => _name = value; + // } + public string name; + //[Obsolete] public ClusterPrefab cluster { get; set; } public Cluster parent { get; set; } @@ -39,6 +40,8 @@ public abstract class Nucleus { #region Synapses + public Vector3 bias = Vector3.zero; + [SerializeField] private List _synapses = new(); public List synapses => _synapses; From fd7359acd09c009afb877346d9e224c1a2911f8b Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Tue, 10 Feb 2026 10:08:35 +0100 Subject: [PATCH 127/179] Physics ant --- Editor/ClusterInspector.cs | 10 ++++++---- Editor/NanoBrain_Editor.cs | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 4d4d941..5f81101 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -24,13 +24,13 @@ public class ClusterInspector : Editor { serializedObject.Update(); VisualElement root = new(); - CreateInspector(root, prefab, prefab.output); + CreateInspector(root, prefab, prefab.output, null); serializedObject.ApplyModifiedProperties(); return root; } - public static GraphView CreateInspector(VisualElement root, ClusterPrefab cluster, Nucleus output) { + public static GraphView CreateInspector(VisualElement root, ClusterPrefab cluster, Nucleus output, GameObject gameObject) { root.style.paddingLeft = 0; root.style.paddingRight = 0; root.style.paddingTop = 0; @@ -61,7 +61,7 @@ public class ClusterInspector : Editor { mainContainer.Add(inspectorContainer); root.Add(mainContainer); - graph.SetGraph(null, output, inspectorContainer); + graph.SetGraph(gameObject, output, inspectorContainer); return graph; } @@ -593,7 +593,8 @@ public class ClusterInspector : Editor { Vector3 value = synapse.nucleus.outputValue * synapse.weight; GUIContent synapseValueLabel = new(synapse.nucleus.name, synapse.nucleus.outputValue.ToString()); EditorGUILayout.FloatField(synapseValueLabel, length(synapse.nucleus.outputValue)); - } else { + } + else { EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField(synapse.nucleus.name); if (GUILayout.Button("Disconnect")) @@ -671,6 +672,7 @@ public class ClusterInspector : Editor { void OnSceneGUI(SceneView sceneView) { if (this.gameObject != null) { Vector3 worldVector = this.gameObject.transform.TransformVector(this.currentNucleus.outputValue); + // worldVector = worldVector.normalized; Handles.color = Color.yellow; Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); } diff --git a/Editor/NanoBrain_Editor.cs b/Editor/NanoBrain_Editor.cs index 138c901..319dc2b 100644 --- a/Editor/NanoBrain_Editor.cs +++ b/Editor/NanoBrain_Editor.cs @@ -27,7 +27,7 @@ public class NanoBrainComponent_Editor : Editor { VisualElement root = new(); - ClusterInspector.CreateInspector(root, brain.prefab, brain.output); + ClusterInspector.CreateInspector(root, brain.prefab, brain.output, component.gameObject); if (Application.isPlaying == false) serializedObject.ApplyModifiedProperties(); From 6f67def8e6305c6ed3b622e018754c14412e03ec Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Tue, 10 Feb 2026 11:47:49 +0100 Subject: [PATCH 128/179] Pulsar neuron and firing actions --- Editor/ClusterInspector.cs | 53 ++++++++++++++++++++++------ Neuron.cs | 72 ++++++++++++++++++++++++-------------- Nucleus.cs | 18 ++++++---- Pulsar.cs | 54 ++++++++++++++++++++++++++++ Pulsar.cs.meta | 2 ++ 5 files changed, 155 insertions(+), 44 deletions(-) create mode 100644 Pulsar.cs create mode 100644 Pulsar.cs.meta diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 5f81101..c675e7b 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -678,24 +678,46 @@ public class ClusterInspector : Editor { } } + protected virtual void AddInput(Nucleus.Type selectedType, Nucleus nucleus) { + switch (selectedType) { + case Nucleus.Type.Neuron: + AddNeuronInput(nucleus); + break; + case Nucleus.Type.MemoryCell: + AddMemoryCellInput(nucleus); + break; + case Nucleus.Type.Selector: + AddSelectorInput(nucleus); + break; + case Nucleus.Type.Cluster: + AddClusterInput(nucleus); + break; + case Nucleus.Type.Pulsar: + AddPulsarInput(nucleus); + break; + default: + break; + } + } + protected virtual void AddInput(int selectedInputType, Nucleus nucleus) { switch (selectedInputType) { case 0: // Neuron - AddInputNeuron(nucleus); + AddNeuronInput(nucleus); break; case 1: // MemoryCell - AddInputMemoryCell(nucleus); + AddMemoryCellInput(nucleus); break; case 2: // Selector AddSelectorInput(nucleus); break; case 3: // Cluster - AddCluster(nucleus); + AddClusterInput(nucleus); break; } } - protected virtual void AddInputNeuron(Nucleus nucleus) { + protected virtual void AddNeuronInput(Nucleus nucleus) { //Neuron newNeuroid = new(this.cluster, "New neuron"); Neuron newNeuroid = new(this.prefab, "New neuron"); newNeuroid.AddReceiver(nucleus); @@ -725,14 +747,21 @@ public class ClusterInspector : Editor { BuildLayers(); } - protected virtual void AddInputMemoryCell(Nucleus nucleus) { + protected void AddPulsarInput(Nucleus nucleus) { + Pulsar newPulsar = new(this.prefab, "New Pulsar"); + newPulsar.AddReceiver(nucleus); + this.currentNucleus = newPulsar; + BuildLayers(); + } + + protected virtual void AddMemoryCellInput(Nucleus nucleus) { MemoryCell newMemory = new(this.prefab, "New memory cell"); newMemory.AddReceiver(nucleus); this.currentNucleus = newMemory; BuildLayers(); } - protected virtual void AddCluster(Nucleus nucleus) { + protected virtual void AddClusterInput(Nucleus nucleus) { ClusterPickerWindow.ShowPicker(brain => OnClusterPicked(nucleus, brain), "Select Cluster"); } @@ -777,11 +806,13 @@ public class ClusterInspector : Editor { if (cluster == null) return; - string[] options = { "Neuron", "MemoryCell", "Selector", "Cluster" }; - int selectedInputType = -1; - selectedInputType = EditorGUILayout.Popup("Add", selectedInputType, options); - if (selectedInputType >= 0) - AddInput(selectedInputType, this.currentNucleus); + //string[] options = { "Neuron", "MemoryCell", "Selector", "Cluster" }; + //int selectedInputType = -1; + //selectedInputType = EditorGUILayout.Popup("Add", selectedInputType, options); + //if (selectedInputType >= 0) + Nucleus.Type selectedType = (Nucleus.Type)EditorGUILayout.EnumPopup("Add", Nucleus.Type.None); + if (selectedType != Nucleus.Type.None) + AddInput(selectedType, this.currentNucleus); } protected virtual void DisconnectNucleus(Neuron nucleus) { diff --git a/Neuron.cs b/Neuron.cs index c6c8221..bc6bccd 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -129,29 +129,33 @@ public class Neuron : Nucleus { // this clone the nucleus without the synapses and receivers public override Nucleus ShallowCloneTo(Cluster newParent) { - Neuron clone = new(newParent, this.name) { - array = null, - bias = this.bias, - curve = this.curve, - curvePreset = this.curvePreset, - curveMax = this.curveMax, - average = this.average - }; + Neuron clone = new(newParent, this.name); + // { + // array = null, + // bias = this.bias, + // curve = this.curve, + // curvePreset = this.curvePreset, + // curveMax = this.curveMax, + // average = this.average + // }; + CloneFields(clone); return clone; } public override Nucleus Clone(ClusterPrefab prefab) { - Neuron clone = new(prefab, this.name) { - //Neuron clone = new(this.parent, this.name) { - array = this.array, - curve = this.curve, - curvePreset = this.curvePreset, - curveMax = this.curveMax, - average = this.average - }; + Neuron clone = new(prefab, this.name); + // { + // //Neuron clone = new(this.parent, this.name) { + // array = this.array, + // curve = this.curve, + // curvePreset = this.curvePreset, + // curveMax = this.curveMax, + // average = this.average + // }; // if (clone.cluster != null) // clone.cluster.nuclei.Add(clone); + CloneFields(clone); foreach (Synapse synapse in this.synapses) { Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); clonedSynapse.weight = synapse.weight; @@ -162,6 +166,15 @@ public class Neuron : Nucleus { return clone; } + protected virtual void CloneFields(Neuron clone) { + clone.array = null; + clone.bias = this.bias; + clone.curve = this.curve; + clone.curvePreset = this.curvePreset; + clone.curveMax = this.curveMax; + clone.average = this.average; + } + public static void Delete(Nucleus nucleus) { foreach (Synapse synapse in nucleus.synapses) { if (synapse.nucleus is Neuron synapse_nucleus) { @@ -205,32 +218,37 @@ public class Neuron : Nucleus { sum /= n; // Activation function + float3 result = Activation(sum); + if (this.stale > staleValueForSleep) + this.outputValue = new float3(0, 0, 0); + else + this.outputValue = result; + } + + protected float3 Activation(float3 input) { float3 result = Vector3.zero; switch (this.curvePreset) { case CurvePresets.Linear: - result = sum; + result = input; break; case CurvePresets.Sqrt: - result = normalize(sum) * System.MathF.Sqrt(length(sum)); + result = normalize(input) * System.MathF.Sqrt(length(input)); break; case CurvePresets.Power: - result = normalize(sum) * System.MathF.Pow(length(sum), 2); + result = normalize(input) * System.MathF.Pow(length(input), 2); break; case CurvePresets.Reciprocal: { - float magnitude = length(sum); + float magnitude = length(input); if (magnitude > 0) - result = normalize(sum) * (1 / magnitude); + result = normalize(input) * (1 / magnitude); break; } default: - float activatedValue = this.curve.Evaluate(length(sum)); - result = normalize(sum) * activatedValue; + float activatedValue = this.curve.Evaluate(length(input)); + result = normalize(input) * activatedValue; break; } - if (this.stale > staleValueForSleep) - this.outputValue = new float3(0,0,0); - else - this.outputValue = result; + return result; } public virtual void ProcessStimulus(Vector3 inputValue, string thingName = null) { diff --git a/Nucleus.cs b/Nucleus.cs index fe5eae4..a72b5dc 100644 --- a/Nucleus.cs +++ b/Nucleus.cs @@ -6,12 +6,6 @@ using static Unity.Mathematics.math; [Serializable] public abstract class Nucleus { - // [SerializeField] - // protected string _name; - // public virtual string name { - // get => _name; - // set => _name = value; - // } public string name; //[Obsolete] @@ -26,9 +20,12 @@ public abstract class Nucleus { //this.stale = 0; // this._isSleeping = false; _outputValue = value; + if (this.isFiring) + WhenFiring?.Invoke(); } } public bool isFiring => length(_outputValue) > 0.5f; + public Action WhenFiring; public bool isSleeping => lengthsq(this.outputValue) == 0; [NonSerialized] @@ -38,6 +35,15 @@ public abstract class Nucleus { public abstract Nucleus ShallowCloneTo(Cluster parent); public abstract Nucleus Clone(ClusterPrefab prefab); + public enum Type { + None, + Neuron, + MemoryCell, + Selector, + Cluster, + Pulsar + } + #region Synapses public Vector3 bias = Vector3.zero; diff --git a/Pulsar.cs b/Pulsar.cs new file mode 100644 index 0000000..889406c --- /dev/null +++ b/Pulsar.cs @@ -0,0 +1,54 @@ +using System; +using Unity.Mathematics; + +/// +/// The Pulsar represents a type of neuron that operates based on +/// the product of its weighted inputs rather than the traditional summation. +/// Drawing inspiration from the concept of pulsars in astrophysics +/// —highly magnetized rotating neutron stars that emit beams of radiation— +/// the Pulsar could symbolize dynamic, focused output based on the interaction of multiple factors. +/// +/// Multiplicative Functionality: +/// Instead of summing inputs, the Pulsar takes the weighted product of its inputs. +/// This means that all inputs must be active (non-zero) for the neuron to "pulse" or activate. +/// Output Behavior: +/// The output could amplify or diminish depending on the magnitude of the inputs. +/// The product would be sensitive to small values, +/// which means that even a small input could significantly lower the overall output if multiplied. +/// Activation Mechanism: +/// The activation function can further refine the output from the product result. +/// For instance, a certain threshold could be used to determine if a pulse occurs. +/// Modeling Complex Interactions: +/// The Pulsar could be particularly beneficial for modeling situations where interactions multiply rather than add. +/// This is useful in fields such as economics (e.g., compound growth models), +/// biology (e.g., interaction of hormones), and machine learning where multiplicative relationships exist. +[Serializable] +public class Pulsar : Neuron { + public Pulsar(Cluster parent, string name) : base(parent, name) { + // To prevent mistakes, bias one (instead of zero for standard neurons) + this.bias = new float3(1, 1, 1); + } + public Pulsar(ClusterPrefab parent, string name) : base(parent, name) { + // To prevent mistakes, bias one (instead of zero for standard neurons) + this.bias = new float3(1, 1, 1); + } + + public override Nucleus ShallowCloneTo(Cluster newParent) { + Pulsar clone = new(newParent, this.name); + CloneFields(clone); + return clone; + } + + public override void UpdateStateIsolated(float3 _bias) { + float3 product = this.bias; + + //Applying the weight factors + foreach (Synapse synapse in this.synapses) { + float3 input = synapse.weight * synapse.nucleus.outputValue; + product *= input; + } + + // Activation function + this.outputValue = Activation(product); + } +} \ No newline at end of file diff --git a/Pulsar.cs.meta b/Pulsar.cs.meta new file mode 100644 index 0000000..e73f7db --- /dev/null +++ b/Pulsar.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 46bd155173053a01585411c3e07f85d4 \ No newline at end of file From d562c7192b3e0a4f330e7dc4e256ff58bf05f853 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Tue, 10 Feb 2026 12:55:25 +0100 Subject: [PATCH 129/179] Simplify/improve UpdateStateIsolated --- Cluster.cs | 22 +++++++++------------- Editor/NanoBrain_Editor.cs | 9 +++++++++ MemoryCell.cs | 12 ++++++------ Neuron.cs | 2 +- Nucleus.cs | 8 ++++---- Pulsar.cs | 2 +- Selector.cs | 4 ++-- 7 files changed, 32 insertions(+), 27 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index d65656a..3aa1945 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -91,9 +91,10 @@ public class Cluster : Nucleus { foreach (Nucleus prefabArrayNucleus in prefabNucleus.array.nuclei) { int arrayNucleusIx = GetNucleusIndex(prefabNuclei, prefabArrayNucleus); if (arrayNucleusIx >= 0) { - Nucleus clonedArrayNucleus = clonedNuclei[arrayNucleusIx]; - clonedArray.nuclei[arrayIx] = clonedArrayNucleus; - } else { + Nucleus clonedArrayNucleus = clonedNuclei[arrayNucleusIx]; + clonedArray.nuclei[arrayIx] = clonedArrayNucleus; + } + else { Debug.LogError($" Could not find prefab nuclues {prefabNucleus.name} in the clones"); } arrayIx++; @@ -250,11 +251,7 @@ public class Cluster : Nucleus { #region Update public override void UpdateStateIsolated() { - float3 bias = new(0, 0, 0); - UpdateStateIsolated(bias); - } - public override void UpdateStateIsolated(float3 bias) { - Vector3 sum = bias; + Vector3 sum = this.bias; //Applying the weight factors foreach (Synapse synapse in this.synapses) { @@ -264,12 +261,11 @@ public class Cluster : Nucleus { } } - this.inputs[0].UpdateStateIsolated(sum); - foreach (Nucleus receptor in this.sortedNuclei) { - if (receptor is Nucleus nucleus && nucleus != this.inputs[0]) - nucleus.UpdateStateIsolated(); - } + foreach (Nucleus nucleus in this.sortedNuclei) + nucleus.UpdateStateIsolated(); + this.outputValue = this.output.outputValue; + this.stale = 0; UpdateNuclei(); } diff --git a/Editor/NanoBrain_Editor.cs b/Editor/NanoBrain_Editor.cs index 319dc2b..6c37746 100644 --- a/Editor/NanoBrain_Editor.cs +++ b/Editor/NanoBrain_Editor.cs @@ -1,4 +1,6 @@ using UnityEditor; +using UnityEditor.UIElements; + using UnityEngine; using UnityEngine.UIElements; @@ -27,6 +29,13 @@ public class NanoBrainComponent_Editor : Editor { VisualElement root = new(); + if (Application.isPlaying == false) { + PropertyField brainField = new(brainProp) { + label = "Nano Brain" + }; + root.Add(brainField); + } + ClusterInspector.CreateInspector(root, brain.prefab, brain.output, component.gameObject); if (Application.isPlaying == false) diff --git a/MemoryCell.cs b/MemoryCell.cs index dd69652..796c6d8 100644 --- a/MemoryCell.cs +++ b/MemoryCell.cs @@ -25,13 +25,13 @@ public class MemoryCell : Neuron { private float3 _memorizedValue; private float _memorizedTime; - public override void UpdateStateIsolated() { - float3 bias = new(0, 0, 0); - UpdateStateIsolated(bias); - } - public override void UpdateStateIsolated(float3 bias) { + // public override void UpdateStateIsolated() { + // float3 bias = new(0, 0, 0); + // UpdateStateIsolated(bias); + // } + public override void UpdateStateIsolated() { //float3 bias) { // A memorycell does not have an activation function - Vector3 result = bias; + Vector3 result = this.bias; int n = 0; //Applying the weight factgors diff --git a/Neuron.cs b/Neuron.cs index bc6bccd..2022a78 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -200,7 +200,7 @@ public class Neuron : Nucleus { } //public float3 bias = float3(0, 0, 0); - public override void UpdateStateIsolated(float3 bias_unused) { + public override void UpdateStateIsolated() { //float3 bias_unused) { Vector3 sum = this.bias; int n = 0; diff --git a/Nucleus.cs b/Nucleus.cs index a72b5dc..baef87e 100644 --- a/Nucleus.cs +++ b/Nucleus.cs @@ -98,11 +98,11 @@ public abstract class Nucleus { #region Update - public virtual void UpdateStateIsolated() { - UpdateStateIsolated(new float3(0, 0, 0)); - } + public abstract void UpdateStateIsolated(); + // UpdateStateIsolated(new float3(0, 0, 0)); + // } - public abstract void UpdateStateIsolated(float3 bias); + //public abstract void UpdateStateIsolated(float3 bias); // public virtual void UpdateStateIsolated(float3 bias) { // } diff --git a/Pulsar.cs b/Pulsar.cs index 889406c..d4f4104 100644 --- a/Pulsar.cs +++ b/Pulsar.cs @@ -39,7 +39,7 @@ public class Pulsar : Neuron { return clone; } - public override void UpdateStateIsolated(float3 _bias) { + public override void UpdateStateIsolated() { //float3 _bias) { float3 product = this.bias; //Applying the weight factors diff --git a/Selector.cs b/Selector.cs index d4893fe..ed7fae4 100644 --- a/Selector.cs +++ b/Selector.cs @@ -18,8 +18,8 @@ public class Selector : Neuron { return clone; } - public override void UpdateStateIsolated(float3 bias) { - float3 max = bias; + public override void UpdateStateIsolated() { //float3 bias) { + float3 max = this.bias; float maxSqrLength = lengthsq(max); //Applying the weight factors From c011e0465062c134dbfeeda998d2e8060c2506f2 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Tue, 10 Feb 2026 15:02:24 +0100 Subject: [PATCH 130/179] Add static memory option --- Editor/ClusterInspector.cs | 105 ++++++++++++++----------------------- MemoryCell.cs | 49 +++++++++++------ Nucleus.cs | 8 +-- 3 files changed, 74 insertions(+), 88 deletions(-) diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index c675e7b..e90ba23 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -396,7 +396,7 @@ public class ClusterInspector : Editor { } private void DrawNucleus(Nucleus nucleus, Vector3 position, float maxValue, float size, Color color) { - if (nucleus is MemoryCell memory) { + if (nucleus is MemoryCell) { Handles.color = Color.white; Handles.DrawWireDisc(position + Vector3.right * 10, Vector3.forward, size); } @@ -413,17 +413,17 @@ public class ClusterInspector : Editor { normal = { textColor = Color.white }, fontStyle = FontStyle.Bold, }; - if (nucleus is Nucleus neuron) { - if (neuron.array == null || neuron.array.nuclei == null || neuron.array.nuclei.Count() == 0) - neuron.array = new NucleusArray(neuron); + //if (nucleus is Nucleus neuron) { + if (nucleus.array == null || nucleus.array.nuclei == null || nucleus.array.nuclei.Count() == 0) + nucleus.array = new NucleusArray(nucleus); - if ((!expandArray || neuron.array.nuclei.First() != this.currentNucleus) && neuron.array.nuclei.Count() > 1) { - Handles.Label(labelPosition, neuron.array.nuclei.Count().ToString(), style); + if ((!expandArray || nucleus.array.nuclei.First() != this.currentNucleus) && nucleus.array.nuclei.Count() > 1) { + Handles.Label(labelPosition, nucleus.array.nuclei.Count().ToString(), style); } - if (expandArray && neuron.array.nuclei.First() == this.currentNucleus) { + if (expandArray && nucleus.array.nuclei.First() == this.currentNucleus) { int arrayIx = 0; - foreach (Nucleus n in neuron.array.nuclei) { - if (n == neuron) + foreach (Nucleus n in nucleus.array.nuclei) { + if (n == nucleus) break; arrayIx++; } @@ -441,17 +441,18 @@ public class ClusterInspector : Editor { Handles.Label(labelPos, nucleus.name, style); } - if (nucleus is Cluster cluster) { + if (nucleus is Cluster) { Handles.color = Color.white; Handles.DrawWireDisc(position, Vector3.forward, size + 10); } - } - else { - style.alignment = TextAnchor.UpperCenter; - Vector3 labelPos = position - Vector3.down * (size + 10); // below disc along up axis - Handles.Label(labelPos, nucleus.name, style); - } + // } + // else { + // style.alignment = TextAnchor.UpperCenter; + // Vector3 labelPos = position - Vector3.down * (size + 10); // below disc along up axis + // Handles.Label(labelPos, nucleus.name, style); + // } + // Tooltip Rect neuronRect = new(position.x - size, position.y - size, size * 2, size * 2); int id = GUIUtility.GetControlID(FocusType.Passive); Event e = Event.current; @@ -533,31 +534,6 @@ public class ClusterInspector : Editor { outputsField.choices = this.prefab.outputs.Select(output => output.name).ToList(); //outputsField.value = newName; } - //if (this.currentNucleus is Neuron neuron) { - // if (this.currentNucleus is MemoryCell memory) { - // } - // else { - // EditorGUILayout.BeginHorizontal(); - // EditorGUILayout.LabelField("Activation Curve", GUILayout.Width(150)); - // if (neuron.curveMax > 0) - // EditorGUILayout.CurveField(neuron.curve, Color.cyan, new Rect(0, 0, 1, neuron.curveMax)); - // else - // EditorGUILayout.CurveField(neuron.curve, Color.cyan, new Rect(0, neuron.curveMax, 1, -neuron.curveMax)); - // neuron.curvePreset = (Neuron.CurvePresets)EditorGUILayout.EnumPopup(neuron.curvePreset, GUILayout.Width(100)); - // EditorGUILayout.EndHorizontal(); - // } - - // if (neuron.array == null || neuron.array.nuclei == null || neuron.array.nuclei.Count() == 0) - // neuron.array = new NucleusArray(neuron); - // EditorGUILayout.BeginHorizontal(); - // EditorGUILayout.IntField("Array size", neuron.array.nuclei.Count()); - // if (GUILayout.Button("Add")) - // neuron.array.AddNucleus(this.prefab); - // if (GUILayout.Button("Del")) - // neuron.array.RemoveNucleus(); - // EditorGUILayout.EndHorizontal(); - //} - if (Application.isPlaying) { GUIContent nameLabel = new("Output", this.currentNucleus.outputValue.ToString()); @@ -566,6 +542,12 @@ public class ClusterInspector : Editor { else EditorGUILayout.LabelField(" "); + if (this.currentNucleus is MemoryCell memory) { + memory.staticMemory = EditorGUILayout.Toggle("Static Memory", memory.staticMemory); + } + + // Synapses + showSynapses = EditorGUILayout.BeginFoldoutHeaderGroup(showSynapses, "Synapses"); if (showSynapses) { ConnectNucleus(this.prefab, this.currentNucleus); @@ -616,7 +598,7 @@ public class ClusterInspector : Editor { if (showActivation) { if (this.currentNucleus is Neuron neuron) { - if (this.currentNucleus is not MemoryCell memory) { + if (this.currentNucleus is not MemoryCell) { EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Activation Curve", GUILayout.Width(150)); if (neuron.curveMax > 0) @@ -650,13 +632,6 @@ public class ClusterInspector : Editor { EditCluster(subCluster); } - // if (this.gameObject != null) { - // Vector3 worldVector = this.gameObject.transform.TransformVector(this.currentNucleus.outputValue); - // //Debug.DrawRay(this.gameObject.transform.position, worldVector, Color.yellow); - // Handles.color = Color.yellow; - // Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); - // } - EditorGUILayout.Space(); breakOnWake = EditorGUILayout.Toggle("Break on wake", breakOnWake); if (breakOnWake) { @@ -700,22 +675,22 @@ public class ClusterInspector : Editor { } } - protected virtual void AddInput(int selectedInputType, Nucleus nucleus) { - switch (selectedInputType) { - case 0: // Neuron - AddNeuronInput(nucleus); - break; - case 1: // MemoryCell - AddMemoryCellInput(nucleus); - break; - case 2: // Selector - AddSelectorInput(nucleus); - break; - case 3: // Cluster - AddClusterInput(nucleus); - break; - } - } + // protected virtual void AddInput(int selectedInputType, Nucleus nucleus) { + // switch (selectedInputType) { + // case 0: // Neuron + // AddNeuronInput(nucleus); + // break; + // case 1: // MemoryCell + // AddMemoryCellInput(nucleus); + // break; + // case 2: // Selector + // AddSelectorInput(nucleus); + // break; + // case 3: // Cluster + // AddClusterInput(nucleus); + // break; + // } + // } protected virtual void AddNeuronInput(Nucleus nucleus) { //Neuron newNeuroid = new(this.cluster, "New neuron"); diff --git a/MemoryCell.cs b/MemoryCell.cs index 796c6d8..5eb13d6 100644 --- a/MemoryCell.cs +++ b/MemoryCell.cs @@ -9,27 +9,30 @@ public class MemoryCell : Neuron { public MemoryCell(ClusterPrefab cluster, string name) : base(cluster, name) { } public MemoryCell(Cluster parent, string name) : base(parent, name) { } + public bool staticMemory = false; + public override bool isSleeping { + get { + if (staticMemory) + return false; + + return base.isSleeping; + } + } + public override Nucleus ShallowCloneTo(Cluster newParent) { - MemoryCell clone = new(newParent, this.name) { - array = this.array, - curve = this.curve, - curvePreset = this.curvePreset, - curveMax = this.curveMax, - average = this.average - }; + MemoryCell clone = new(newParent, this.name); + CloneFields(clone); + clone.staticMemory = this.staticMemory; return clone; } #region State - private float3 _memorizedValue; - private float _memorizedTime; + private bool initialized = false; - // public override void UpdateStateIsolated() { - // float3 bias = new(0, 0, 0); - // UpdateStateIsolated(bias); - // } - public override void UpdateStateIsolated() { //float3 bias) { + private float3 _memorizedValue; + + public override void UpdateStateIsolated() { // A memorycell does not have an activation function Vector3 result = this.bias; int n = 0; @@ -44,11 +47,25 @@ public class MemoryCell : Neuron { if (this.average) result /= n; - this.outputValue = this._memorizedValue; + if (initialized) + // Output the previous, memorized value + this.outputValue = this._memorizedValue; + else { + // The first time, the result is directly set in output + this.outputValue = result; + this.initialized = true; + } // Store the result for the next time this._memorizedValue = result; - this._memorizedTime = Time.time; + } + + public override void UpdateNuclei() { + if (staticMemory) + // Static memory does not get stale or go to sleep + return; + + base.UpdateNuclei(); } #endregion State diff --git a/Nucleus.cs b/Nucleus.cs index baef87e..01d2a80 100644 --- a/Nucleus.cs +++ b/Nucleus.cs @@ -27,7 +27,7 @@ public abstract class Nucleus { public bool isFiring => length(_outputValue) > 0.5f; public Action WhenFiring; - public bool isSleeping => lengthsq(this.outputValue) == 0; + public virtual bool isSleeping => lengthsq(this.outputValue) == 0; [NonSerialized] public int stale = 1000; public readonly int staleValueForSleep = 20; @@ -99,12 +99,6 @@ public abstract class Nucleus { #region Update public abstract void UpdateStateIsolated(); - // UpdateStateIsolated(new float3(0, 0, 0)); - // } - - //public abstract void UpdateStateIsolated(float3 bias); - // public virtual void UpdateStateIsolated(float3 bias) { - // } public virtual void UpdateNuclei() { this.stale++; From 360346eeacd5b7c69a071402e5a83482a567bb87 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Tue, 10 Feb 2026 17:34:03 +0100 Subject: [PATCH 131/179] Fix multiple pheromone placement --- Cluster.cs | 125 +++++++++++++++++++++++++++++++++++-- Editor/ClusterInspector.cs | 4 ++ Nucleus.cs | 4 ++ NucleusArray.cs | 3 +- 4 files changed, 131 insertions(+), 5 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index 3aa1945..61e2897 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -18,6 +18,7 @@ public class Cluster : Nucleus { this.parent?.nuclei.Add(this); ClonePrefab(); + _ = this.inputs; this.sortedNuclei = TopologicalSort(this.nuclei); // Does not work because we have nuclei with the same names in an nucleusArray // 'Pheromone steering' @@ -33,6 +34,7 @@ public class Cluster : Nucleus { this.cluster.nuclei.Add(this); ClonePrefab(); + _ = this.inputs; this.sortedNuclei = TopologicalSort(this.nuclei); //this.nucleiDict = nuclei.ToDictionary(nucleus => nucleus.name); } @@ -127,6 +129,7 @@ public class Cluster : Nucleus { if (inDegree[node] == 0) // Nodes with no dependencies queue.Enqueue(node); } + // The queue basically stores all input nuclei? List sortedOrder = new(); while (queue.Count > 0) { @@ -200,11 +203,107 @@ public class Cluster : Nucleus { if (nucleus.synapses.Count == 0) this._inputs.Add(nucleus); } + ComputeOrders(); } return this._inputs; } } + public Dictionary> computeOrders = new(); + private void ComputeOrders() { + foreach (Nucleus input in this._inputs) { + computeOrders[input] = TopologicalSort2(input); + } + } + + private List TopologicalSort2(Nucleus startNode) { + Dictionary inDegree = new Dictionary(); + HashSet visited = new HashSet(); + + // Initialize in-degrees and mark all nodes as unvisited + foreach (Nucleus node in this.nuclei) { + inDegree[node] = 0; + } + + // Calculate in-degrees for all nodes reachable from the start node + Queue queue = new Queue(); + queue.Enqueue(startNode); + visited.Add(startNode); + + while (queue.Count > 0) { + Nucleus current = queue.Dequeue(); + foreach (Nucleus receiver in current.receivers) { + if (!visited.Contains(receiver)) { + visited.Add(receiver); + queue.Enqueue(receiver); + } + inDegree[receiver]++; + } + } + + // Perform topological sort on all reachable nodes + queue.Clear(); + foreach (var node in visited) { + if (inDegree[node] == 0) { + queue.Enqueue(node); + } + } + + List sortedOrder = new List(); + while (queue.Count > 0) { + Nucleus current = queue.Dequeue(); + sortedOrder.Add(current); // Process the node + + foreach (Nucleus receiver in current.receivers) { + if (visited.Contains(receiver)) { + inDegree[receiver]--; + if (inDegree[receiver] == 0) // If all dependencies resolved + queue.Enqueue(receiver); + } + } + } + + // Check for cycles in the graph + if (sortedOrder.Count != visited.Count) + throw new InvalidOperationException("Graph is not a DAG; a cycle exists."); + + return sortedOrder; + } + + private List TopologicalSort3(Nucleus startNode) { + Dictionary inDegree = new(); + foreach (Nucleus node in this.nuclei) + inDegree[node] = 0; // Initialize in-degree to zero + + // Calculate in-degrees + foreach (Nucleus node in this.nuclei) { + foreach (Nucleus receiver in node.receivers) + inDegree[receiver]++; + } + + Queue queue = new(); + queue.Enqueue(startNode); + + List sortedOrder = new(); + while (queue.Count > 0) { + Nucleus current = queue.Dequeue(); + sortedOrder.Add(current); // Process the node + + foreach (Nucleus receiver in current.receivers) { + inDegree[receiver]--; + if (inDegree[receiver] == 0) // If all dependencies resolved + queue.Enqueue(receiver); + } + } + + Debug.Log($"Compute order for {startNode.name} length = {sortedOrder.Count}"); + // Check for cycles in the graph + // if (sortedOrder.Count != this.nuclei.Count) + // throw new InvalidOperationException("Graph is not a DAG; a cycle exists."); + + return sortedOrder; + } + public virtual Nucleus output {//=> this.nuclei[0] as Nucleus; get { if (this.nuclei.Count > 0) @@ -250,6 +349,24 @@ public class Cluster : Nucleus { #region Update + public void UpdateFromNucleus(Nucleus startNucleus) { + // no bias+synapse input state calculation for now... + + List computeOrder = this.computeOrders[startNucleus]; + if (startNucleus.trace) + Debug.Log($"Update from {startNucleus.name}"); + foreach (Nucleus nucleus in computeOrder) { + nucleus.UpdateStateIsolated(); + if (startNucleus.trace) + Debug.Log($" {nucleus.name} = {nucleus.outputValue}"); + } + + this.outputValue = this.output.outputValue; + this.stale = 0; + + UpdateNuclei(); + } + public override void UpdateStateIsolated() { Vector3 sum = this.bias; @@ -263,7 +380,7 @@ public class Cluster : Nucleus { foreach (Nucleus nucleus in this.sortedNuclei) nucleus.UpdateStateIsolated(); - + this.outputValue = this.output.outputValue; this.stale = 0; @@ -271,9 +388,9 @@ public class Cluster : Nucleus { } public override void UpdateNuclei() { - this.stale++; - if (this.stale > staleValueForSleep) - _outputValue = Vector3.zero; + // this.stale++; + // if (this.stale > staleValueForSleep) + // _outputValue = Vector3.zero; foreach (Nucleus nucleus in this.nuclei) nucleus.UpdateNuclei(); diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index e90ba23..1710cb7 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -500,6 +500,7 @@ public class ClusterInspector : Editor { private bool showSynapses = true; private bool showActivation = true; protected bool breakOnWake = false; + protected bool trace = false; void DrawInspector(VisualElement inspectorContainer) { if (inspectorContainer == null) return; @@ -638,6 +639,9 @@ public class ClusterInspector : Editor { if (this.currentNucleus.isSleeping == false) Debug.Break(); } + trace = EditorGUILayout.Toggle("Trace", trace); + this.currentNucleus.trace = trace; + }); inspectorContainer.Add(container); diff --git a/Nucleus.cs b/Nucleus.cs index 01d2a80..b4defa4 100644 --- a/Nucleus.cs +++ b/Nucleus.cs @@ -31,6 +31,7 @@ public abstract class Nucleus { [NonSerialized] public int stale = 1000; public readonly int staleValueForSleep = 20; + public bool trace = false; public abstract Nucleus ShallowCloneTo(Cluster parent); public abstract Nucleus Clone(ClusterPrefab prefab); @@ -101,6 +102,9 @@ public abstract class Nucleus { public abstract void UpdateStateIsolated(); public virtual void UpdateNuclei() { + if (this.array == null || this.array.nuclei == null || this.array.nuclei.Length <= 1) + return; + this.stale++; if (this.stale > staleValueForSleep) { //Debug.Log($"{this.name} goes to sleep, stale = {this.stale}"); diff --git a/NucleusArray.cs b/NucleusArray.cs index 89ae516..b41aa68 100644 --- a/NucleusArray.cs +++ b/NucleusArray.cs @@ -127,7 +127,8 @@ public class NucleusArray { if (selectedReceiver is Neuron selectedNucleus) selectedNucleus.ProcessStimulus(inputValue); - selectedReceiver.parent.UpdateStateIsolated(); + //selectedReceiver.parent.UpdateStateIsolated(); + selectedReceiver.parent.UpdateFromNucleus(selectedReceiver); } private void CleanupReceivers() { From ed0a95b4d8a5af7fc362504373b0e8092d57a7d9 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Tue, 10 Feb 2026 17:43:40 +0100 Subject: [PATCH 132/179] Cleanup --- Cluster.cs | 4 ---- Neuron.cs | 25 ++----------------------- Nucleus.cs | 2 -- NucleusArray.cs | 3 +-- Pulsar.cs | 2 +- 5 files changed, 4 insertions(+), 32 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index 61e2897..a05f20b 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -388,10 +388,6 @@ public class Cluster : Nucleus { } public override void UpdateNuclei() { - // this.stale++; - // if (this.stale > staleValueForSleep) - // _outputValue = Vector3.zero; - foreach (Nucleus nucleus in this.nuclei) nucleus.UpdateNuclei(); } diff --git a/Neuron.cs b/Neuron.cs index 2022a78..4c7d0eb 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -130,31 +130,12 @@ public class Neuron : Nucleus { // this clone the nucleus without the synapses and receivers public override Nucleus ShallowCloneTo(Cluster newParent) { Neuron clone = new(newParent, this.name); - // { - // array = null, - // bias = this.bias, - // curve = this.curve, - // curvePreset = this.curvePreset, - // curveMax = this.curveMax, - // average = this.average - // }; CloneFields(clone); return clone; } public override Nucleus Clone(ClusterPrefab prefab) { Neuron clone = new(prefab, this.name); - // { - // //Neuron clone = new(this.parent, this.name) { - // array = this.array, - // curve = this.curve, - // curvePreset = this.curvePreset, - // curveMax = this.curveMax, - // average = this.average - // }; - // if (clone.cluster != null) - // clone.cluster.nuclei.Add(clone); - CloneFields(clone); foreach (Synapse synapse in this.synapses) { Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); @@ -199,8 +180,7 @@ public class Neuron : Nucleus { } } - //public float3 bias = float3(0, 0, 0); - public override void UpdateStateIsolated() { //float3 bias_unused) { + public override void UpdateStateIsolated() { Vector3 sum = this.bias; int n = 0; @@ -252,9 +232,8 @@ public class Neuron : Nucleus { } public virtual void ProcessStimulus(Vector3 inputValue, string thingName = null) { - //this.outputValue = inputValue; this.stale = 0; - //Debug.Log($"{this.name} processed stimulus"); this.bias = inputValue; + this.parent.UpdateFromNucleus(this); } } \ No newline at end of file diff --git a/Nucleus.cs b/Nucleus.cs index b4defa4..64d1fe4 100644 --- a/Nucleus.cs +++ b/Nucleus.cs @@ -16,9 +16,7 @@ public abstract class Nucleus { public virtual Vector3 outputValue { get { return _outputValue; } set { - //Debug.Log($"{this.name}: stale is reset, was: {this.stale}"); //this.stale = 0; - // this._isSleeping = false; _outputValue = value; if (this.isFiring) WhenFiring?.Invoke(); diff --git a/NucleusArray.cs b/NucleusArray.cs index b41aa68..c4141b4 100644 --- a/NucleusArray.cs +++ b/NucleusArray.cs @@ -127,8 +127,7 @@ public class NucleusArray { if (selectedReceiver is Neuron selectedNucleus) selectedNucleus.ProcessStimulus(inputValue); - //selectedReceiver.parent.UpdateStateIsolated(); - selectedReceiver.parent.UpdateFromNucleus(selectedReceiver); + //selectedReceiver.parent.UpdateFromNucleus(selectedReceiver); } private void CleanupReceivers() { diff --git a/Pulsar.cs b/Pulsar.cs index d4f4104..88e6251 100644 --- a/Pulsar.cs +++ b/Pulsar.cs @@ -39,7 +39,7 @@ public class Pulsar : Neuron { return clone; } - public override void UpdateStateIsolated() { //float3 _bias) { + public override void UpdateStateIsolated() { float3 product = this.bias; //Applying the weight factors From 8c8d5a5a66d22910e0fac4007d43f1ae42c7aece Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 11 Feb 2026 09:45:21 +0100 Subject: [PATCH 133/179] using neuron types --- ClusterPrefab.cs | 1 - Editor/ClusterInspector.cs | 72 ++++++++++++++++++++++---------------- Neuron.cs | 67 +++++++++++++++++++++++++---------- 3 files changed, 91 insertions(+), 49 deletions(-) diff --git a/ClusterPrefab.cs b/ClusterPrefab.cs index 2fc6867..0839d42 100644 --- a/ClusterPrefab.cs +++ b/ClusterPrefab.cs @@ -4,7 +4,6 @@ using UnityEngine; [CreateAssetMenu(menuName = "Passer/Cluster")] public class ClusterPrefab : ScriptableObject { // The ScriptableObject asset from which the runtime object has been created - public string hello = "hello"; [SerializeReference] public List nuclei = new(); diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 1710cb7..b8b787d 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -77,7 +77,7 @@ public class ClusterInspector : Editor { private bool expandArray = false; ClusterWrapper currentWrapper; - PopupField outputsField; + readonly PopupField outputsField; public GraphView(ClusterPrefab prefab) { this.prefab = prefab; @@ -414,37 +414,37 @@ public class ClusterInspector : Editor { fontStyle = FontStyle.Bold, }; //if (nucleus is Nucleus neuron) { - if (nucleus.array == null || nucleus.array.nuclei == null || nucleus.array.nuclei.Count() == 0) - nucleus.array = new NucleusArray(nucleus); + if (nucleus.array == null || nucleus.array.nuclei == null || nucleus.array.nuclei.Count() == 0) + nucleus.array = new NucleusArray(nucleus); - if ((!expandArray || nucleus.array.nuclei.First() != this.currentNucleus) && nucleus.array.nuclei.Count() > 1) { - Handles.Label(labelPosition, nucleus.array.nuclei.Count().ToString(), style); + if ((!expandArray || nucleus.array.nuclei.First() != this.currentNucleus) && nucleus.array.nuclei.Count() > 1) { + Handles.Label(labelPosition, nucleus.array.nuclei.Count().ToString(), style); + } + if (expandArray && nucleus.array.nuclei.First() == this.currentNucleus) { + int arrayIx = 0; + foreach (Nucleus n in nucleus.array.nuclei) { + if (n == nucleus) + break; + arrayIx++; } - if (expandArray && nucleus.array.nuclei.First() == this.currentNucleus) { - int arrayIx = 0; - foreach (Nucleus n in nucleus.array.nuclei) { - if (n == nucleus) - break; - arrayIx++; - } - Handles.Label(labelPosition, $"[{arrayIx}]", style); - } - else { - style.alignment = TextAnchor.UpperCenter; - Vector3 labelPos = position - Vector3.down * (size + 10f); // below disc along up axis - int colonPos = nucleus.name.IndexOf(":"); - if (colonPos > 0) { - string baseName = nucleus.name[..colonPos]; - Handles.Label(labelPos, baseName, style); - } - else - Handles.Label(labelPos, nucleus.name, style); + Handles.Label(labelPosition, $"[{arrayIx}]", style); + } + else { + style.alignment = TextAnchor.UpperCenter; + Vector3 labelPos = position - Vector3.down * (size + 10f); // below disc along up axis + int colonPos = nucleus.name.IndexOf(":"); + if (colonPos > 0) { + string baseName = nucleus.name[..colonPos]; + Handles.Label(labelPos, baseName, style); } + else + Handles.Label(labelPos, nucleus.name, style); + } - if (nucleus is Cluster) { - Handles.color = Color.white; - Handles.DrawWireDisc(position, Vector3.forward, size + 10); - } + if (nucleus is Cluster) { + Handles.color = Color.white; + Handles.DrawWireDisc(position, Vector3.forward, size + 10); + } // } // else { // style.alignment = TextAnchor.UpperCenter; @@ -528,6 +528,9 @@ public class ClusterInspector : Editor { }; GUILayout.Label(this.currentNucleus.GetType().ToString(), headerStyle); + if (this.currentNucleus is Neuron neuron1) { + neuron1.type = (Nucleus.Type)EditorGUILayout.EnumPopup(neuron1.type); + } string newName = EditorGUILayout.TextField(this.currentNucleus.name, boldTextFieldStyle); if (newName != this.currentNucleus.name) { this.currentNucleus.name = newName; @@ -707,15 +710,24 @@ public class ClusterInspector : Editor { protected virtual void DeleteNeuron(Nucleus nucleus) { if (nucleus == null) return; - if (nucleus.cluster != null) - this.currentNucleus = nucleus.cluster.output; + foreach (Nucleus receiver in nucleus.receivers) { if (receiver != null) { this.currentNucleus = receiver; break; } } + this.prefab.nuclei.Remove(nucleus); + + if (outputsField.value == nucleus.name) { + this.prefab.RefreshOutputs(); + outputsField.choices = this.prefab.outputs.Select(output => output.name).ToList(); + outputsField.index = 0; + } + Neuron.Delete(nucleus); + + this.currentNucleus = this.prefab.output; BuildLayers(); } diff --git a/Neuron.cs b/Neuron.cs index 4c7d0eb..2b74465 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -26,6 +26,8 @@ public class Neuron : Nucleus { #region Serialization + public Type type = Type.Neuron; + public enum CurvePresets { Linear, Power, @@ -150,6 +152,7 @@ public class Neuron : Nucleus { protected virtual void CloneFields(Neuron clone) { clone.array = null; clone.bias = this.bias; + clone.type = this.type; clone.curve = this.curve; clone.curvePreset = this.curvePreset; clone.curveMax = this.curveMax; @@ -181,28 +184,55 @@ public class Neuron : Nucleus { } public override void UpdateStateIsolated() { - Vector3 sum = this.bias; - int n = 0; + switch (this.type) { + case Type.Neuron: + UpdateSum(); + break; + case Type.Pulsar: + UpdateProduct(); + break; + default: + UpdateSum(); + break; + } + // Vector3 sum = this.bias; + // int n = 0; - //Applying the weight factgors - foreach (Synapse synapse in this.synapses) { + // //Applying the weight factgors + // foreach (Synapse synapse in this.synapses) { + // sum += synapse.weight * synapse.nucleus.outputValue; + + // // Perhaps synapses should be removed when the output value goes to 0.... + // if (lengthsq(synapse.nucleus.outputValue) != 0) { + // n++; + // this.stale = 0; + // } + // } + // if (this.average && n > 0) + // sum /= n; + + // // Activation function + // float3 result = Activation(sum); + // if (this.stale > staleValueForSleep) + // this.outputValue = new float3(0, 0, 0); + // else + // this.outputValue = result; + } + + public void UpdateSum() { + Vector3 sum = this.bias; + foreach (Synapse synapse in this.synapses) sum += synapse.weight * synapse.nucleus.outputValue; - // Perhaps synapses should be removed when the output value goes to 0.... - if (lengthsq(synapse.nucleus.outputValue) != 0) { - n++; - this.stale = 0; - } - } - if (this.average && n > 0) - sum /= n; + this.outputValue = Activation(sum); + } - // Activation function - float3 result = Activation(sum); - if (this.stale > staleValueForSleep) - this.outputValue = new float3(0, 0, 0); - else - this.outputValue = result; + public void UpdateProduct() { + float3 product = this.bias; + foreach (Synapse synapse in this.synapses) + product *= synapse.weight * synapse.nucleus.outputValue; + + this.outputValue = Activation(product); } protected float3 Activation(float3 input) { @@ -236,4 +266,5 @@ public class Neuron : Nucleus { this.bias = inputValue; this.parent.UpdateFromNucleus(this); } + } \ No newline at end of file From c1bf54a1cc5be55b73389ee96ab5830d11117d95 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 11 Feb 2026 11:49:03 +0100 Subject: [PATCH 134/179] Improve persisting changes --- Editor/ClusterInspector.cs | 365 ++++++++++++++++++++----------------- Neuron.cs | 71 ++++++-- 2 files changed, 253 insertions(+), 183 deletions(-) diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index b8b787d..b52cba9 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -18,9 +18,17 @@ public class ClusterInspector : Editor { public override VisualElement CreateInspectorGUI() { ClusterPrefab prefab = target as ClusterPrefab; + + string path = AssetDatabase.GetAssetPath(prefab); // or known path + Debug.Log($"{path}"); + ClusterPrefab currentWrapper = AssetDatabase.LoadAssetAtPath(path); + if (currentWrapper == null) + Debug.LogError("CreateInspectorGUI: Cluster Prefab is not found on disk"); + if (prefab != null) prefab.EnsureInitialization(); + serializedObject.Update(); VisualElement root = new(); @@ -76,7 +84,7 @@ public class ClusterInspector : Editor { private readonly Dictionary neuroidPositions = new(); private bool expandArray = false; - ClusterWrapper currentWrapper; + ClusterPrefab prefabAsset; readonly PopupField outputsField; public GraphView(ClusterPrefab prefab) { @@ -168,9 +176,20 @@ public class ClusterInspector : Editor { return; } - if (currentWrapper != null) - DestroyImmediate(currentWrapper); - currentWrapper = CreateInstance().Init(this.currentNucleus, prefab); + // if (currentWrapper != null) + // DestroyImmediate(currentWrapper); + // currentWrapper = CreateInstance().Init(this.currentNucleus, prefab); + + string path = AssetDatabase.GetAssetPath(this.prefab); // or known path + this.prefabAsset = AssetDatabase.LoadAssetAtPath(path); + if (this.prefabAsset == null) { + // create and save if it doesn't exist + this.prefabAsset = CreateInstance(); + // AssetDatabase.CreateAsset(currentWrapper, "Assets/ClusterPrefab.asset"); + // AssetDatabase.SaveAssets(); + Debug.LogError("Cluster Prefab is not found on disk"); + } + //currentWrapper.Init(this.currentNucleus, prefab); DrawInspector(inspectorContainer); } @@ -510,146 +529,164 @@ public class ClusterInspector : Editor { return; // create a SerializedObject wrapper so Unity inspector controls work (and Undo) - SerializedObject so = new(currentWrapper); - IMGUIContainer container = new(() => { - if (so.targetObject == null) - return; - so.Update(); - - if (this.currentNucleus == null) - return; - - GUIStyle headerStyle = new(EditorStyles.boldLabel) { - alignment = TextAnchor.MiddleLeft, - margin = new RectOffset(10, 0, 4, 4) - }; - GUIStyle boldTextFieldStyle = new(EditorStyles.textField) { - fontStyle = FontStyle.Bold - }; - - GUILayout.Label(this.currentNucleus.GetType().ToString(), headerStyle); - if (this.currentNucleus is Neuron neuron1) { - neuron1.type = (Nucleus.Type)EditorGUILayout.EnumPopup(neuron1.type); - } - string newName = EditorGUILayout.TextField(this.currentNucleus.name, boldTextFieldStyle); - if (newName != this.currentNucleus.name) { - this.currentNucleus.name = newName; - this.prefab.RefreshOutputs(); - outputsField.choices = this.prefab.outputs.Select(output => output.name).ToList(); - //outputsField.value = newName; - } - - if (Application.isPlaying) { - GUIContent nameLabel = new("Output", this.currentNucleus.outputValue.ToString()); - EditorGUILayout.FloatField(nameLabel, length(this.currentNucleus.outputValue)); - } - else - EditorGUILayout.LabelField(" "); - - if (this.currentNucleus is MemoryCell memory) { - memory.staticMemory = EditorGUILayout.Toggle("Static Memory", memory.staticMemory); - } - - // Synapses - - showSynapses = EditorGUILayout.BeginFoldoutHeaderGroup(showSynapses, "Synapses"); - if (showSynapses) { - ConnectNucleus(this.prefab, this.currentNucleus); - AddSynapse(this.prefab, this.currentNucleus); - - this.currentNucleus.bias = EditorGUILayout.Vector3Field("Bias", this.currentNucleus.bias); - - NucleusArray array = null; - if (this.currentNucleus.synapses.Count > 0) { - Synapse[] synapses = this.currentNucleus.synapses.ToArray(); - foreach (Synapse synapse in synapses) { - if (synapse.nucleus != null) { - if (array != null) { - if (array.nuclei.Contains(synapse.nucleus)) - continue; - } - else { - if (synapse.nucleus.array != null && synapse.nucleus.array.nuclei.Length > 1) - array = synapse.nucleus.array; - } - - EditorGUILayout.Space(); - - if (Application.isPlaying) { - Vector3 value = synapse.nucleus.outputValue * synapse.weight; - GUIContent synapseValueLabel = new(synapse.nucleus.name, synapse.nucleus.outputValue.ToString()); - EditorGUILayout.FloatField(synapseValueLabel, length(synapse.nucleus.outputValue)); - } - else { - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.LabelField(synapse.nucleus.name); - if (GUILayout.Button("Disconnect")) - synapse.nucleus.RemoveReceiver(this.currentNucleus); - EditorGUILayout.EndHorizontal(); - } - - EditorGUI.indentLevel++; - synapse.weight = EditorGUILayout.FloatField("Weight", synapse.weight); - EditorGUI.indentLevel--; - } - } - } - } - EditorGUILayout.EndFoldoutHeaderGroup(); - - EditorGUILayout.Space(); - showActivation = EditorGUILayout.BeginFoldoutHeaderGroup(showActivation, "Activation"); - if (showActivation) { - - if (this.currentNucleus is Neuron neuron) { - if (this.currentNucleus is not MemoryCell) { - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.LabelField("Activation Curve", GUILayout.Width(150)); - if (neuron.curveMax > 0) - EditorGUILayout.CurveField(neuron.curve, Color.cyan, new Rect(0, 0, 1, neuron.curveMax)); - else - EditorGUILayout.CurveField(neuron.curve, Color.cyan, new Rect(0, neuron.curveMax, 1, -neuron.curveMax)); - neuron.curvePreset = (Neuron.CurvePresets)EditorGUILayout.EnumPopup(neuron.curvePreset, GUILayout.Width(100)); - EditorGUILayout.EndHorizontal(); - } - if (neuron.array == null || neuron.array.nuclei == null || neuron.array.nuclei.Count() == 0) - neuron.array = new NucleusArray(neuron); - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.IntField("Array size", neuron.array.nuclei.Count()); - if (GUILayout.Button("Add")) - neuron.array.AddNucleus(this.prefab); - if (GUILayout.Button("Del")) - neuron.array.RemoveNucleus(); - EditorGUILayout.EndHorizontal(); - } - - EditorGUILayout.Space(); - } - EditorGUILayout.EndFoldoutHeaderGroup(); - - - if (GUILayout.Button("Delete this neuron")) - DeleteNeuron(this.currentNucleus); - - if (this.currentNucleus is Cluster subCluster) { - if (GUILayout.Button("Edit Cluster")) - EditCluster(subCluster); - } - - EditorGUILayout.Space(); - breakOnWake = EditorGUILayout.Toggle("Break on wake", breakOnWake); - if (breakOnWake) { - if (this.currentNucleus.isSleeping == false) - Debug.Break(); - } - trace = EditorGUILayout.Toggle("Trace", trace); - this.currentNucleus.trace = trace; - - }); + SerializedObject so = new(prefabAsset); + IMGUIContainer container = new(() => InspectorHandler(so)); inspectorContainer.Add(container); } + void InspectorHandler(SerializedObject serializedObject) { + bool anythingChanged = false; + + if (serializedObject == null || serializedObject.targetObject == null) + return; + + if (this.currentNucleus == null) + return; + + serializedObject.Update(); + + GUIStyle headerStyle = new(EditorStyles.boldLabel) { + alignment = TextAnchor.MiddleLeft, + margin = new RectOffset(10, 0, 4, 4) + }; + GUIStyle boldTextFieldStyle = new(EditorStyles.textField) { + fontStyle = FontStyle.Bold + }; + + GUILayout.Label(this.currentNucleus.GetType().ToString(), headerStyle); + string newName = EditorGUILayout.TextField(this.currentNucleus.name, boldTextFieldStyle); + if (newName != this.currentNucleus.name) { + this.currentNucleus.name = newName; + this.prefab.RefreshOutputs(); + outputsField.choices = this.prefab.outputs.Select(output => output.name).ToList(); + //outputsField.value = newName; + } + + if (Application.isPlaying) { + GUIContent nameLabel = new("Output", this.currentNucleus.outputValue.ToString()); + EditorGUILayout.FloatField(nameLabel, length(this.currentNucleus.outputValue)); + } + else + EditorGUILayout.LabelField(" "); + + if (this.currentNucleus is MemoryCell memory) { + memory.staticMemory = EditorGUILayout.Toggle("Static Memory", memory.staticMemory); + } + + // Synapses + + showSynapses = EditorGUILayout.BeginFoldoutHeaderGroup(showSynapses, "Synapses"); + if (showSynapses) { + + ConnectNucleus(this.prefab, this.currentNucleus); + AddSynapse(this.prefab, this.currentNucleus); + EditorGUILayout.Space(); + + if (this.currentNucleus is Neuron neuron2) + neuron2.combinator = (Neuron.CombinatorType)EditorGUILayout.EnumPopup("Combinator", neuron2.combinator); + + this.currentNucleus.bias = EditorGUILayout.Vector3Field("Bias", this.currentNucleus.bias); + + NucleusArray array = null; + if (this.currentNucleus.synapses.Count > 0) { + Synapse[] synapses = this.currentNucleus.synapses.ToArray(); + foreach (Synapse synapse in synapses) { + if (synapse.nucleus != null) { + if (array != null) { + if (array.nuclei.Contains(synapse.nucleus)) + continue; + } + else { + if (synapse.nucleus.array != null && synapse.nucleus.array.nuclei.Length > 1) + array = synapse.nucleus.array; + } + + EditorGUILayout.Space(); + + if (Application.isPlaying) { + Vector3 value = synapse.nucleus.outputValue * synapse.weight; + GUIContent synapseValueLabel = new(synapse.nucleus.name, synapse.nucleus.outputValue.ToString()); + EditorGUILayout.FloatField(synapseValueLabel, length(synapse.nucleus.outputValue)); + } + else { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField(synapse.nucleus.name); + if (GUILayout.Button("Disconnect")) + synapse.nucleus.RemoveReceiver(this.currentNucleus); + EditorGUILayout.EndHorizontal(); + } + + EditorGUI.indentLevel++; + synapse.weight = EditorGUILayout.FloatField("Weight", synapse.weight); + EditorGUI.indentLevel--; + } + } + } + } + EditorGUILayout.EndFoldoutHeaderGroup(); + + // Activation + + EditorGUILayout.Space(); + showActivation = EditorGUILayout.BeginFoldoutHeaderGroup(showActivation, "Activation"); + if (showActivation) { + if (this.currentNucleus is Neuron neuron) { + if (this.currentNucleus is not MemoryCell) { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Activation Curve", GUILayout.Width(150)); + if (neuron.curveMax > 0) + EditorGUILayout.CurveField(neuron.curve, Color.cyan, new Rect(0, 0, 1, neuron.curveMax)); + else + EditorGUILayout.CurveField(neuron.curve, Color.cyan, new Rect(0, neuron.curveMax, 1, -neuron.curveMax)); + neuron.curvePreset = (Neuron.CurvePresets)EditorGUILayout.EnumPopup(neuron.curvePreset, GUILayout.Width(100)); + EditorGUILayout.EndHorizontal(); + } + if (neuron.array == null || neuron.array.nuclei == null || neuron.array.nuclei.Count() == 0) + neuron.array = new NucleusArray(neuron); + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.IntField("Array size", neuron.array.nuclei.Count()); + if (GUILayout.Button("Add")) { + Undo.RecordObject(prefabAsset, "Array add " + prefabAsset.name); + neuron.array.AddNucleus(this.prefab); + anythingChanged = true; + } + if (GUILayout.Button("Del")) { + Undo.RecordObject(prefabAsset, "Array delete " + prefabAsset.name); + neuron.array.RemoveNucleus(); + anythingChanged = true; + } + EditorGUILayout.EndHorizontal(); + } + + EditorGUILayout.Space(); + } + EditorGUILayout.EndFoldoutHeaderGroup(); + + + if (GUILayout.Button("Delete this neuron")) + DeleteNeuron(this.currentNucleus); + + if (this.currentNucleus is Cluster subCluster) { + if (GUILayout.Button("Edit Cluster")) + EditCluster(subCluster); + } + + EditorGUILayout.Space(); + breakOnWake = EditorGUILayout.Toggle("Break on wake", breakOnWake); + if (breakOnWake) { + if (this.currentNucleus.isSleeping == false) + Debug.Break(); + } + trace = EditorGUILayout.Toggle("Trace", trace); + this.currentNucleus.trace = trace; + + serializedObject.ApplyModifiedProperties(); + if (anythingChanged) { + EditorUtility.SetDirty(prefabAsset); + AssetDatabase.SaveAssets(); + } + } void OnSceneGUI(SceneView sceneView) { if (this.gameObject != null) { @@ -829,28 +866,28 @@ public class NeuroidLayer { public List neuroids = new(); } -public class ClusterWrapper : ScriptableObject { - // expose fields that map to GraphNode - //public string title; - public Vector2 position; - Nucleus node; - ClusterPrefab graph; // needed to write back and mark dirty +// public class ClusterWrapper : ScriptableObject { +// // expose fields that map to GraphNode +// //public string title; +// public Vector2 position; +// Nucleus node; +// ClusterPrefab graph; // needed to write back and mark dirty - public ClusterWrapper Init(Nucleus node, ClusterPrefab graphAsset) { - this.node = node; - this.graph = graphAsset; - //this.title = " A " + node.name; - //position = node.position; - return this; - } - void OnValidate() { - if (node != null) { - //node.name = title; - //node.position = position; -#if UNITY_EDITOR - if (graph != null) - UnityEditor.EditorUtility.SetDirty(graph); -#endif - } - } -} \ No newline at end of file +// public ClusterWrapper Init(Nucleus node, ClusterPrefab graphAsset) { +// this.node = node; +// this.graph = graphAsset; +// //this.title = " A " + node.name; +// //position = node.position; +// return this; +// } +// void OnValidate() { +// if (node != null) { +// //node.name = title; +// //node.position = position; +// #if UNITY_EDITOR +// if (graph != null) +// UnityEditor.EditorUtility.SetDirty(graph); +// #endif +// } +// } +// } \ No newline at end of file diff --git a/Neuron.cs b/Neuron.cs index 2b74465..53865d4 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -26,7 +26,13 @@ public class Neuron : Nucleus { #region Serialization - public Type type = Type.Neuron; + //public Type type = Type.Neuron; + public enum CombinatorType { + Sum, + Product, + Max + } + public CombinatorType combinator = CombinatorType.Sum; public enum CurvePresets { Linear, @@ -150,9 +156,9 @@ public class Neuron : Nucleus { } protected virtual void CloneFields(Neuron clone) { - clone.array = null; + clone.array = this.array; clone.bias = this.bias; - clone.type = this.type; + clone.combinator = this.combinator; clone.curve = this.curve; clone.curvePreset = this.curvePreset; clone.curveMax = this.curveMax; @@ -184,17 +190,19 @@ public class Neuron : Nucleus { } public override void UpdateStateIsolated() { - switch (this.type) { - case Type.Neuron: - UpdateSum(); - break; - case Type.Pulsar: - UpdateProduct(); - break; - default: - UpdateSum(); - break; - } + float3 result = CombinatorAction(); + this.outputValue = Activation(result); + // switch (this.type) { + // case Type.Neuron: + // UpdateSum(); + // break; + // case Type.Pulsar: + // UpdateProduct(); + // break; + // default: + // UpdateSum(); + // break; + // } // Vector3 sum = this.bias; // int n = 0; @@ -219,20 +227,45 @@ public class Neuron : Nucleus { // this.outputValue = result; } - public void UpdateSum() { + private Func CombinatorAction => combinator switch { + CombinatorType.Sum => UpdateSum, + CombinatorType.Product => UpdateProduct, + CombinatorType.Max => UpdateMax, + _ => UpdateSum + }; + + + public float3 UpdateSum() { Vector3 sum = this.bias; foreach (Synapse synapse in this.synapses) sum += synapse.weight * synapse.nucleus.outputValue; - - this.outputValue = Activation(sum); + return sum; + //this.outputValue = Activation(sum); } - public void UpdateProduct() { + public float3 UpdateProduct() { float3 product = this.bias; foreach (Synapse synapse in this.synapses) product *= synapse.weight * synapse.nucleus.outputValue; + return product; + //this.outputValue = Activation(product); + } - this.outputValue = Activation(product); + public float3 UpdateMax() { + float3 max = this.bias; + float maxSqrLength = lengthsq(max); + + //Applying the weight factors + foreach (Synapse synapse in this.synapses) { + float3 input = synapse.weight * synapse.nucleus.outputValue; + + float inputSqrlength = lengthsq(input); + if (inputSqrlength > maxSqrLength) { + max = input; + maxSqrLength = inputSqrlength; + } + } + return max; } protected float3 Activation(float3 input) { From f40d1ea4ae800a2d34c6cd37e33eb954fd1ca35f Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 11 Feb 2026 12:42:13 +0100 Subject: [PATCH 135/179] Fixes --- Editor/ClusterInspector.cs | 64 ++++++++++---------------------------- Neuron.cs | 9 +++--- NucleusArray.cs | 8 ++--- 3 files changed, 24 insertions(+), 57 deletions(-) diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index b52cba9..6d94ed5 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -19,16 +19,15 @@ public class ClusterInspector : Editor { public override VisualElement CreateInspectorGUI() { ClusterPrefab prefab = target as ClusterPrefab; - string path = AssetDatabase.GetAssetPath(prefab); // or known path - Debug.Log($"{path}"); - ClusterPrefab currentWrapper = AssetDatabase.LoadAssetAtPath(path); - if (currentWrapper == null) - Debug.LogError("CreateInspectorGUI: Cluster Prefab is not found on disk"); + // string path = AssetDatabase.GetAssetPath(prefab); // or known path + // Debug.Log($"{path}"); + // ClusterPrefab currentWrapper = AssetDatabase.LoadAssetAtPath(path); + // if (currentWrapper == null) + // Debug.LogError("CreateInspectorGUI: Cluster Prefab is not found on disk"); if (prefab != null) prefab.EnsureInitialization(); - serializedObject.Update(); VisualElement root = new(); @@ -176,20 +175,13 @@ public class ClusterInspector : Editor { return; } - // if (currentWrapper != null) - // DestroyImmediate(currentWrapper); - // currentWrapper = CreateInstance().Init(this.currentNucleus, prefab); - string path = AssetDatabase.GetAssetPath(this.prefab); // or known path this.prefabAsset = AssetDatabase.LoadAssetAtPath(path); if (this.prefabAsset == null) { - // create and save if it doesn't exist + // create in memory save if it doesn't exist this.prefabAsset = CreateInstance(); - // AssetDatabase.CreateAsset(currentWrapper, "Assets/ClusterPrefab.asset"); - // AssetDatabase.SaveAssets(); Debug.LogError("Cluster Prefab is not found on disk"); } - //currentWrapper.Init(this.currentNucleus, prefab); DrawInspector(inspectorContainer); } @@ -579,7 +571,7 @@ public class ClusterInspector : Editor { showSynapses = EditorGUILayout.BeginFoldoutHeaderGroup(showSynapses, "Synapses"); if (showSynapses) { - ConnectNucleus(this.prefab, this.currentNucleus); + anythingChanged = ConnectNucleus(this.prefab, this.currentNucleus); AddSynapse(this.prefab, this.currentNucleus); EditorGUILayout.Space(); @@ -627,7 +619,7 @@ public class ClusterInspector : Editor { EditorGUILayout.EndFoldoutHeaderGroup(); // Activation - + EditorGUILayout.Space(); showActivation = EditorGUILayout.BeginFoldoutHeaderGroup(showActivation, "Activation"); if (showActivation) { @@ -809,9 +801,9 @@ public class ClusterInspector : Editor { } // Connect to another nucleus in the same cluster - protected virtual void ConnectNucleus(ClusterPrefab cluster, Nucleus nucleus) { + protected virtual bool ConnectNucleus(ClusterPrefab cluster, Nucleus nucleus) { if (cluster == null) - return; + return false; IEnumerable synapseNuclei = this.currentNucleus.synapses .Where(synapse => synapse.nucleus != null) @@ -824,10 +816,12 @@ public class ClusterInspector : Editor { string[] names = nucleiNames.ToArray(); int selectedIndex = -1; selectedIndex = EditorGUILayout.Popup("Connect", selectedIndex, names); - if (selectedIndex >= 0) { - Nucleus receptor = nuclei.ElementAt(selectedIndex); - receptor.AddReceiver(this.currentNucleus); - } + if (selectedIndex < 0) + return false; + + Nucleus receptor = nuclei.ElementAt(selectedIndex); + receptor.AddReceiver(this.currentNucleus); + return true; } protected virtual void AddSynapse(ClusterPrefab cluster, Nucleus nucleus) { @@ -865,29 +859,3 @@ public class NeuroidLayer { public int ix = 0; public List neuroids = new(); } - -// public class ClusterWrapper : ScriptableObject { -// // expose fields that map to GraphNode -// //public string title; -// public Vector2 position; -// Nucleus node; -// ClusterPrefab graph; // needed to write back and mark dirty - -// public ClusterWrapper Init(Nucleus node, ClusterPrefab graphAsset) { -// this.node = node; -// this.graph = graphAsset; -// //this.title = " A " + node.name; -// //position = node.position; -// return this; -// } -// void OnValidate() { -// if (node != null) { -// //node.name = title; -// //node.position = position; -// #if UNITY_EDITOR -// if (graph != null) -// UnityEditor.EditorUtility.SetDirty(graph); -// #endif -// } -// } -// } \ No newline at end of file diff --git a/Neuron.cs b/Neuron.cs index 53865d4..089a862 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -17,11 +17,10 @@ public class Neuron : Nucleus { public Neuron(ClusterPrefab parent, string name) { this.cluster = parent; this.name = name; - if (this.cluster != null) { - this.cluster.nuclei.Add(this); - } - // else - // Debug.LogError("No neuroid network"); + if (this.cluster != null) + this.cluster.nuclei.Add(this); + else + Debug.LogError("No prefab when adding neuron to prefab"); } #region Serialization diff --git a/NucleusArray.cs b/NucleusArray.cs index c4141b4..30c77be 100644 --- a/NucleusArray.cs +++ b/NucleusArray.cs @@ -13,19 +13,19 @@ public class NucleusArray { return _nuclei; } } - public string name; + //public string name; public NucleusArray(Nucleus nucleus) { - this.name = nucleus.name; + //this.name = nucleus.name; this._nuclei = new Nucleus[1]; this._nuclei[0] = nucleus; } public NucleusArray(ClusterPrefab cluster) { - this.name = cluster.name; + //this.name = cluster.name; this._nuclei = new Nucleus[0]; } public NucleusArray(int size, string name) { - this.name = name; + //this.name = name; this._nuclei = new Nucleus[size]; } From 2af597fbdbbb214d63f277d7973dbb60436c681a Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 11 Feb 2026 15:05:11 +0100 Subject: [PATCH 136/179] improved pheromone steering --- Editor/ClusterInspector.cs | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 6d94ed5..9728495 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -572,13 +572,18 @@ public class ClusterInspector : Editor { if (showSynapses) { anythingChanged = ConnectNucleus(this.prefab, this.currentNucleus); - AddSynapse(this.prefab, this.currentNucleus); + anythingChanged = AddSynapse(this.prefab, this.currentNucleus); EditorGUILayout.Space(); - if (this.currentNucleus is Neuron neuron2) - neuron2.combinator = (Neuron.CombinatorType)EditorGUILayout.EnumPopup("Combinator", neuron2.combinator); + if (this.currentNucleus is Neuron neuron2) { + Neuron.CombinatorType newCombinator = (Neuron.CombinatorType)EditorGUILayout.EnumPopup("Combinator", neuron2.combinator); + anythingChanged |= newCombinator != neuron2.combinator; + neuron2.combinator = newCombinator; + } - this.currentNucleus.bias = EditorGUILayout.Vector3Field("Bias", this.currentNucleus.bias); + Vector3 newBias = EditorGUILayout.Vector3Field("Bias", this.currentNucleus.bias); + anythingChanged |= newBias != this.currentNucleus.bias; + this.currentNucleus.bias = newBias; NucleusArray array = null; if (this.currentNucleus.synapses.Count > 0) { @@ -682,10 +687,11 @@ public class ClusterInspector : Editor { void OnSceneGUI(SceneView sceneView) { if (this.gameObject != null) { - Vector3 worldVector = this.gameObject.transform.TransformVector(this.currentNucleus.outputValue); - // worldVector = worldVector.normalized; - Handles.color = Color.yellow; - Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); + foreach (Nucleus nucleus in this.currentNucleus.array.nuclei) { + Vector3 worldVector = this.gameObject.transform.TransformVector(nucleus.outputValue); + Handles.color = Color.yellow; + Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); + } } } @@ -824,17 +830,16 @@ public class ClusterInspector : Editor { return true; } - protected virtual void AddSynapse(ClusterPrefab cluster, Nucleus nucleus) { + protected virtual bool AddSynapse(ClusterPrefab cluster, Nucleus nucleus) { if (cluster == null) - return; + return false; - //string[] options = { "Neuron", "MemoryCell", "Selector", "Cluster" }; - //int selectedInputType = -1; - //selectedInputType = EditorGUILayout.Popup("Add", selectedInputType, options); - //if (selectedInputType >= 0) Nucleus.Type selectedType = (Nucleus.Type)EditorGUILayout.EnumPopup("Add", Nucleus.Type.None); - if (selectedType != Nucleus.Type.None) - AddInput(selectedType, this.currentNucleus); + if (selectedType == Nucleus.Type.None) + return false; + + AddInput(selectedType, this.currentNucleus); + return true; } protected virtual void DisconnectNucleus(Neuron nucleus) { From dbf24b458a6b71cba1c34bc4052dc960ae0d303e Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 11 Feb 2026 15:59:26 +0100 Subject: [PATCH 137/179] Improve smell --- Editor/ClusterInspector.cs | 4 +++- Neuron.cs | 7 ++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 9728495..bd0e313 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -636,7 +636,9 @@ public class ClusterInspector : Editor { EditorGUILayout.CurveField(neuron.curve, Color.cyan, new Rect(0, 0, 1, neuron.curveMax)); else EditorGUILayout.CurveField(neuron.curve, Color.cyan, new Rect(0, neuron.curveMax, 1, -neuron.curveMax)); - neuron.curvePreset = (Neuron.CurvePresets)EditorGUILayout.EnumPopup(neuron.curvePreset, GUILayout.Width(100)); + Neuron.CurvePresets newPreset = (Neuron.CurvePresets)EditorGUILayout.EnumPopup(neuron.curvePreset, GUILayout.Width(100)); + anythingChanged |= newPreset != neuron.curvePreset; + neuron.curvePreset = newPreset; EditorGUILayout.EndHorizontal(); } if (neuron.array == null || neuron.array.nuclei == null || neuron.array.nuclei.Count() == 0) diff --git a/Neuron.cs b/Neuron.cs index 089a862..45d5729 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -41,10 +41,14 @@ public class Neuron : Nucleus { Custom } [SerializeField] - private CurvePresets _curvePreset; + public CurvePresets _curvePreset; public CurvePresets curvePreset { get { return _curvePreset; } set { + foreach (Neuron nucleus in array.nuclei.Cast()) { + nucleus._curvePreset = value; + nucleus.curve = GenerateCurve(); + } _curvePreset = value; this.curve = GenerateCurve(); } @@ -160,6 +164,7 @@ public class Neuron : Nucleus { clone.combinator = this.combinator; clone.curve = this.curve; clone.curvePreset = this.curvePreset; + Debug.Log($"clone preset {clone.name} = {clone.curvePreset}"); clone.curveMax = this.curveMax; clone.average = this.average; } From 42bc32c7345bdcf797e961e467453fd7c77d2152 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 11 Feb 2026 17:03:37 +0100 Subject: [PATCH 138/179] food/home steering in brain, not optimal yet --- Neuron.cs | 10 ++++++---- NucleusArray.cs | 4 ---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/Neuron.cs b/Neuron.cs index 45d5729..400359e 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -18,7 +18,7 @@ public class Neuron : Nucleus { this.cluster = parent; this.name = name; if (this.cluster != null) - this.cluster.nuclei.Add(this); + this.cluster.nuclei.Add(this); else Debug.LogError("No prefab when adding neuron to prefab"); } @@ -45,9 +45,11 @@ public class Neuron : Nucleus { public CurvePresets curvePreset { get { return _curvePreset; } set { - foreach (Neuron nucleus in array.nuclei.Cast()) { - nucleus._curvePreset = value; - nucleus.curve = GenerateCurve(); + if (this.array != null && this.array.nuclei != null) { + foreach (Neuron nucleus in this.array.nuclei.Cast()) { + nucleus._curvePreset = value; + nucleus.curve = GenerateCurve(); + } } _curvePreset = value; this.curve = GenerateCurve(); diff --git a/NucleusArray.cs b/NucleusArray.cs index 30c77be..5ff9876 100644 --- a/NucleusArray.cs +++ b/NucleusArray.cs @@ -13,19 +13,15 @@ public class NucleusArray { return _nuclei; } } - //public string name; public NucleusArray(Nucleus nucleus) { - //this.name = nucleus.name; this._nuclei = new Nucleus[1]; this._nuclei[0] = nucleus; } public NucleusArray(ClusterPrefab cluster) { - //this.name = cluster.name; this._nuclei = new Nucleus[0]; } public NucleusArray(int size, string name) { - //this.name = name; this._nuclei = new Nucleus[size]; } From a62d1cc5d98e8b4362d1b6c5b5fb3c63cdab4ff5 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 11 Feb 2026 17:22:20 +0100 Subject: [PATCH 139/179] Cleanup --- MemoryCell.cs | 13 +---- Neuron.cs | 139 +++++++++++++++++++------------------------------- Pulsar.cs | 2 +- Selector.cs | 1 - 4 files changed, 55 insertions(+), 100 deletions(-) diff --git a/MemoryCell.cs b/MemoryCell.cs index 5eb13d6..e531922 100644 --- a/MemoryCell.cs +++ b/MemoryCell.cs @@ -34,18 +34,7 @@ public class MemoryCell : Neuron { public override void UpdateStateIsolated() { // A memorycell does not have an activation function - Vector3 result = this.bias; - int n = 0; - - //Applying the weight factgors - foreach (Synapse synapse in this.synapses) { - result += synapse.weight * synapse.nucleus.outputValue; - if (lengthsq(synapse.nucleus.outputValue) != 0) - n++; - } - - if (this.average) - result /= n; + float3 result = Combinator(); if (initialized) // Output the previous, memorized value diff --git a/Neuron.cs b/Neuron.cs index 400359e..0a58257 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -58,12 +58,6 @@ public class Neuron : Nucleus { public AnimationCurve curve; public float curveMax = 1.0f; - #region Parameters - - public bool average = false; - - #endregion Parameters - public AnimationCurve GenerateCurve() { switch (this.curvePreset) { case CurvePresets.Linear: @@ -84,14 +78,6 @@ public class Neuron : Nucleus { } } - public virtual void Deserialize(Neuron nucleus) { } - - #endregion Serialization - - #region Runtime state (not serialized) - - #region Activation - public static class Presets { private const int samples = 32; public static AnimationCurve Linear(float weight) { @@ -136,9 +122,7 @@ public class Neuron : Nucleus { } } - #endregion Activation - - #endregion Runtime state + #endregion Serialization // this clone the nucleus without the synapses and receivers public override Nucleus ShallowCloneTo(Cluster newParent) { @@ -166,9 +150,7 @@ public class Neuron : Nucleus { clone.combinator = this.combinator; clone.curve = this.curve; clone.curvePreset = this.curvePreset; - Debug.Log($"clone preset {clone.name} = {clone.curvePreset}"); clone.curveMax = this.curveMax; - clone.average = this.average; } public static void Delete(Nucleus nucleus) { @@ -196,52 +178,20 @@ public class Neuron : Nucleus { } public override void UpdateStateIsolated() { - float3 result = CombinatorAction(); - this.outputValue = Activation(result); - // switch (this.type) { - // case Type.Neuron: - // UpdateSum(); - // break; - // case Type.Pulsar: - // UpdateProduct(); - // break; - // default: - // UpdateSum(); - // break; - // } - // Vector3 sum = this.bias; - // int n = 0; - - // //Applying the weight factgors - // foreach (Synapse synapse in this.synapses) { - // sum += synapse.weight * synapse.nucleus.outputValue; - - // // Perhaps synapses should be removed when the output value goes to 0.... - // if (lengthsq(synapse.nucleus.outputValue) != 0) { - // n++; - // this.stale = 0; - // } - // } - // if (this.average && n > 0) - // sum /= n; - - // // Activation function - // float3 result = Activation(sum); - // if (this.stale > staleValueForSleep) - // this.outputValue = new float3(0, 0, 0); - // else - // this.outputValue = result; + float3 result = Combinator(); + this.outputValue = Activator(result); } - private Func CombinatorAction => combinator switch { - CombinatorType.Sum => UpdateSum, - CombinatorType.Product => UpdateProduct, - CombinatorType.Max => UpdateMax, - _ => UpdateSum + #region Combinator + + protected Func Combinator => combinator switch { + CombinatorType.Sum => CombinatorSum, + CombinatorType.Product => CombinatorProduct, + CombinatorType.Max => CombinatorMax, + _ => CombinatorSum }; - - public float3 UpdateSum() { + public float3 CombinatorSum() { Vector3 sum = this.bias; foreach (Synapse synapse in this.synapses) sum += synapse.weight * synapse.nucleus.outputValue; @@ -249,7 +199,7 @@ public class Neuron : Nucleus { //this.outputValue = Activation(sum); } - public float3 UpdateProduct() { + public float3 CombinatorProduct() { float3 product = this.bias; foreach (Synapse synapse in this.synapses) product *= synapse.weight * synapse.nucleus.outputValue; @@ -257,7 +207,7 @@ public class Neuron : Nucleus { //this.outputValue = Activation(product); } - public float3 UpdateMax() { + public float3 CombinatorMax() { float3 max = this.bias; float maxSqrLength = lengthsq(max); @@ -274,32 +224,49 @@ public class Neuron : Nucleus { return max; } - protected float3 Activation(float3 input) { - float3 result = Vector3.zero; - switch (this.curvePreset) { - case CurvePresets.Linear: - result = input; - break; - case CurvePresets.Sqrt: - result = normalize(input) * System.MathF.Sqrt(length(input)); - break; - case CurvePresets.Power: - result = normalize(input) * System.MathF.Pow(length(input), 2); - break; - case CurvePresets.Reciprocal: { - float magnitude = length(input); - if (magnitude > 0) - result = normalize(input) * (1 / magnitude); - break; - } - default: - float activatedValue = this.curve.Evaluate(length(input)); - result = normalize(input) * activatedValue; - break; - } + #endregion Combinator + + #region Activator + + protected Func Activator => this.curvePreset switch { + CurvePresets.Linear => ActivatorLinear, + CurvePresets.Sqrt => ActivatorSqrt, + CurvePresets.Power => ActivatorPower, + CurvePresets.Reciprocal => ActivatorReciprocal, + _ => ActivatorCustom + }; + + protected float3 ActivatorLinear(float3 input) { + return input; + } + + protected float3 ActivatorSqrt(float3 input) { + float3 result = normalize(input) * System.MathF.Sqrt(length(input)); return result; } + protected float3 ActivatorPower(float3 input) { + float3 result = normalize(input) * System.MathF.Pow(length(input), 2); + return result; + } + + protected float3 ActivatorReciprocal(float3 input) { + float magnitude = length(input); + if (magnitude == 0) + return new float3(0, 0, 0); + + float3 result = normalize(input) * (1 / magnitude); + return result; + } + + protected float3 ActivatorCustom(float3 input) { + float activatedValue = this.curve.Evaluate(length(input)); + float3 result = normalize(input) * activatedValue; + return result; + } + + #endregion Activator + public virtual void ProcessStimulus(Vector3 inputValue, string thingName = null) { this.stale = 0; this.bias = inputValue; diff --git a/Pulsar.cs b/Pulsar.cs index 88e6251..8e2cc54 100644 --- a/Pulsar.cs +++ b/Pulsar.cs @@ -49,6 +49,6 @@ public class Pulsar : Neuron { } // Activation function - this.outputValue = Activation(product); + this.outputValue = Activator(product); } } \ No newline at end of file diff --git a/Selector.cs b/Selector.cs index ed7fae4..6364053 100644 --- a/Selector.cs +++ b/Selector.cs @@ -13,7 +13,6 @@ public class Selector : Neuron { curve = this.curve, curvePreset = this.curvePreset, curveMax = this.curveMax, - average = this.average }; return clone; } From 79e300a6b5dc41b10a25e121dc3f4df76b7168eb Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 12 Feb 2026 11:19:40 +0100 Subject: [PATCH 140/179] Add complete brain viewer --- ClusterPrefab.cs | 10 + Editor/BrainEditorWindow.cs | 363 ++++++++++++++++++++++++++++ Editor/BrainEditorWindow.cs.meta | 2 + Editor/DAGWindow.cs | 393 +++++++++++++++++++++++++++++++ Editor/DAGWindow.cs.meta | 2 + 5 files changed, 770 insertions(+) create mode 100644 Editor/BrainEditorWindow.cs create mode 100644 Editor/BrainEditorWindow.cs.meta create mode 100644 Editor/DAGWindow.cs create mode 100644 Editor/DAGWindow.cs.meta diff --git a/ClusterPrefab.cs b/ClusterPrefab.cs index 0839d42..e58e6c6 100644 --- a/ClusterPrefab.cs +++ b/ClusterPrefab.cs @@ -101,4 +101,14 @@ public class ClusterPrefab : ScriptableObject { foreach (Nucleus nucleus in this.nuclei) nucleus.UpdateNuclei(); } + + public int GetNucleusIndex(Nucleus receiver) { + int ix = 0; + foreach (Nucleus nucleus in this.nuclei) { + if (receiver == nucleus) + return ix; + ix++; + } + return -1; + } } \ No newline at end of file diff --git a/Editor/BrainEditorWindow.cs b/Editor/BrainEditorWindow.cs new file mode 100644 index 0000000..aa4e292 --- /dev/null +++ b/Editor/BrainEditorWindow.cs @@ -0,0 +1,363 @@ +using UnityEngine; +using UnityEditor; +using System.Collections.Generic; +using System.Linq; + +// Simple DAG data model +[System.Serializable] +public class DagNode { + public int id; + public string title; + public Vector2 position; + public float radius = 20f; // circle radius +} + +[System.Serializable] +public class DagEdge { + public int fromId; + public int toId; +} + +public class BrainEditorWindow : EditorWindow { + readonly List nodes = new(); + readonly List edges = new(); + + Vector2 pan = Vector2.zero; + float zoom = 1.0f; + const float minZoom = 0.5f; + const float maxZoom = 2.0f; + + // Vector2 dragStart; + // bool draggingNode = false; + // int draggingNodeId = -1; + + private readonly System.Type acceptedType = typeof(ClusterPrefab); + + [MenuItem("Window/Brain Viewer")] + public static void ShowWindow() { + var w = GetWindow("Brain Viewer"); + w.minSize = new Vector2(500, 300); + } + + void OnEnable() { + // if (nodes.Count == 0) + // CreateSampleGraph(); + + + // Register callback so window updates when selection changes + Selection.selectionChanged += OnSelectionChanged; + RefreshSelection(); + ComputeLeftToRightLayout(); + } + + private void OnDisable() { + Selection.selectionChanged -= OnSelectionChanged; + } + + private void OnSelectionChanged() { + RefreshSelection(); + ComputeLeftToRightLayout(); + Repaint(); + } + + private void RefreshSelection() { + ClusterPrefab prefab = Selection.activeObject as ClusterPrefab; + if (prefab != null && acceptedType.IsAssignableFrom(prefab.GetType())) { + GenerateGraph(prefab); + } + } + + private void GenerateGraph(ClusterPrefab prefab) { + nodes.Clear(); + edges.Clear(); + + int ix = 0; + foreach (Nucleus nucleus in prefab.nuclei) { + nodes.Add(new DagNode() { id = ix, title = nucleus.name }); + foreach (Nucleus receiver in nucleus.receivers) { + int receiverIx = prefab.GetNucleusIndex(receiver); + edges.Add(new DagEdge() { fromId = ix, toId = receiverIx }); + } + ix++; + } + } + + + // void CreateSampleGraph() { + // nodes.Clear(); + // edges.Clear(); + + // nodes.Add(new DagNode() { id = 0, title = "In1" }); + // nodes.Add(new DagNode() { id = 1, title = "In2" }); + // nodes.Add(new DagNode() { id = 2, title = "A" }); + // nodes.Add(new DagNode() { id = 3, title = "B" }); + // nodes.Add(new DagNode() { id = 4, title = "C" }); + // nodes.Add(new DagNode() { id = 5, title = "Out1" }); + // nodes.Add(new DagNode() { id = 6, title = "Out2" }); + + // edges.Add(new DagEdge() { fromId = 0, toId = 2 }); + // edges.Add(new DagEdge() { fromId = 1, toId = 2 }); + // edges.Add(new DagEdge() { fromId = 2, toId = 3 }); + // edges.Add(new DagEdge() { fromId = 2, toId = 4 }); + // edges.Add(new DagEdge() { fromId = 3, toId = 5 }); + // edges.Add(new DagEdge() { fromId = 4, toId = 6 }); + // } + + void OnGUI() { + HandleInput(); + + Rect rect = new(0, 0, position.width, position.height); + EditorGUI.DrawRect(rect, new Color(0.11f, 0.11f, 0.11f)); + + // compute window center + Vector2 windowCenter = new(position.width / 2f, position.height / 2f); + + // compute graph bounds center (in graph space) + Rect bounds = GetGraphBounds(); + Vector2 graphCenter = bounds.center; + + // compute autoPan that recenters the graph (does not modify node positions) + Vector2 autoPan = -graphCenter; // moves graph center to origin + // total translation = windowCenter + autoPan + user pan + Matrix4x4 oldMatrix = GUI.matrix; + GUI.matrix = Matrix4x4.TRS(windowCenter + autoPan + pan, Quaternion.identity, Vector3.one * zoom) * + Matrix4x4.TRS(-windowCenter, Quaternion.identity, Vector3.one); + + + // Draw edges first + foreach (DagEdge e in edges) { + DagNode from = GetNodeById(e.fromId); + DagNode to = GetNodeById(e.toId); + if (from == null || to == null) continue; + DrawEdgeCircleNodes(from, to); + } + + // Draw nodes (circles) + foreach (DagNode n in nodes) + DrawNucleus(n); + + GUI.matrix = oldMatrix; + + // Footer toolbar + GUILayout.FlexibleSpace(); + EditorGUILayout.BeginHorizontal(EditorStyles.toolbar); + if (GUILayout.Button("Fit", EditorStyles.toolbarButton)) FitToView(); + if (GUILayout.Button("Layout LR", EditorStyles.toolbarButton)) ComputeLeftToRightLayout(); + EditorGUILayout.EndHorizontal(); + } + + void HandleInput() { + Event e = Event.current; + + // Zoom with scroll + if (e.type == EventType.ScrollWheel) { + float oldZoom = zoom; + float delta = -e.delta.y * 0.01f; + zoom = Mathf.Clamp(zoom + delta, minZoom, maxZoom); + Vector2 mouse = e.mousePosition; + pan += (mouse - new Vector2(position.width / 2, position.height / 2)) * (1 - zoom / oldZoom); + e.Use(); + } + + // Pan with middle or right+ctrl drag + if (e.type == EventType.MouseDrag && (e.button == 2 || (e.button == 1 && e.control))) { + pan += e.delta; + e.Use(); + } + } + + DagNode GetNodeById(int id) => nodes.FirstOrDefault(x => x.id == id); + List GetIncomingEdges(DagNode node) { + List incoming = new(); + foreach (DagEdge e in edges) { + if (e.toId == node.id) + incoming.Add(e); + } + return incoming; + } + List GetOutgoingEdges(DagNode node) { + List outgoing = new(); + foreach (DagEdge e in edges) { + if (e.fromId == node.id) + outgoing.Add(e); + } + return outgoing; + } + + void DrawNucleus(DagNode n) { + Vector3 position = n.position; + + Handles.color = Color.white * 0.9f; + Handles.DrawSolidDisc(n.position, Vector3.forward, n.radius); + + if (GetIncomingEdges(n).Count == 0) + DrawArrowHead(n.position - new Vector2(n.radius + 10, 0), n.position - new Vector2(n.radius + 5, 0), 10f/zoom, 12f/zoom, Color.white); + if (GetOutgoingEdges(n).Count == 0) + DrawArrowHead(n.position + new Vector2(n.radius + 10, 0), n.position + new Vector2(n.radius + 15, 0), 10f/zoom, 12f/zoom, Color.white); + + Handles.color = Color.white; + GUIStyle style = new(EditorStyles.label) { + alignment = TextAnchor.UpperCenter, + normal = { textColor = Color.white }, + fontStyle = FontStyle.Bold, + }; + Vector3 labelPos = position - Vector3.down * (n.radius + 10f); // below disc along up axis + Handles.Label(labelPos, n.title, style); + } + + void DrawEdgeCircleNodes(DagNode from, DagNode to) { + Vector2 a = from.position; + Vector2 b = to.position; + if (a == b) return; + + Handles.color = Color.white * 0.9f; + Handles.DrawLine(from.position, to.position); + + // Vector2 dir = (b - a).normalized; + // Vector2 start = a + dir * from.radius; + // Vector2 end = b - dir * to.radius; + + //DrawArrowHead(end - dir * 2f, end, 10f / zoom, 12f / zoom, Color.white); + + } + + void DrawArrowHead(Vector2 from, Vector2 to, float headWidth, float headLength, Color color) { + Vector2 dir = (to - from).normalized; + if (dir == Vector2.zero) return; + Vector2 right = new Vector2(-dir.y, dir.x); + + Vector3 p1 = to; + Vector3 p2 = to - dir * headLength + right * headWidth * 0.5f; + Vector3 p3 = to - dir * headLength - right * headWidth * 0.5f; + + Handles.color = color; + Handles.DrawAAConvexPolygon(p1, p2, p3); + } + + // Left-to-right layered layout (sources on the left, sinks on the right) + void ComputeLeftToRightLayout() { + // build adjacency and indegree + var adj = nodes.ToDictionary(n => n.id, n => new List()); + var indeg = nodes.ToDictionary(n => n.id, n => 0); + foreach (var e in edges) { + if (!adj.ContainsKey(e.fromId) || !adj.ContainsKey(e.toId)) continue; + adj[e.fromId].Add(e.toId); + indeg[e.toId]++; + } + + // Kahn's algorithm to compute topological layers (horizontal layers) + Dictionary layer = new(); + Queue q = new(indeg.Where(kv => kv.Value == 0).Select(kv => kv.Key)); + foreach (var id in q) layer[id] = 0; + + while (q.Count > 0) { + int u = q.Dequeue(); + int l = layer[u]; + foreach (var v in adj[u]) { + // prefer placing v at least one layer after u + if (!layer.ContainsKey(v) || layer[v] < l + 1) layer[v] = l + 1; + indeg[v]--; + if (indeg[v] == 0) q.Enqueue(v); + } + } + + // Any unreachable nodes -> assign next layers + int maxLayer = layer.Count > 0 ? layer.Values.Max() : 0; + foreach (var n in nodes) { + if (!layer.ContainsKey(n.id)) { + maxLayer++; + layer[n.id] = maxLayer; + } + } + + // Group nodes by layer (left to right) + var layers = layer.GroupBy(kv => kv.Value).OrderBy(g => g.Key).Select(g => g.Select(x => x.Key).ToList()).ToList(); + + // Layout parameters (horizontal spacing drives left->right) + float hSpacing = 150f; + float vSpacing = 100f; + + // Place nodes: x increases with layer index, y spaced within layer + for (int li = 0; li < layers.Count; li++) { + var lst = layers[li]; + float totalHeight = (lst.Count - 1) * vSpacing; + for (int i = 0; i < lst.Count; i++) { + int id = lst[i]; + var n = GetNodeById(id); + if (n == null) continue; + float x = hSpacing + li * hSpacing; + float y = 400 - totalHeight / 2f + i * vSpacing; + // Debug.Log($"({li}, {i}) -> {x}, {y}"); + n.position = new Vector2(x, y); + } + } + + Repaint(); + } + + void FitToView() { + if (nodes.Count == 0) return; + // compute bounds including radii + Rect bounds = new Rect(nodes[0].position - Vector2.one * nodes[0].radius, Vector2.one * nodes[0].radius * 2f); + foreach (var n in nodes) + bounds = RectUnion(bounds, new Rect(n.position - Vector2.one * n.radius, Vector2.one * n.radius * 2f)); + + // center graph at origin (0,0) then set pan so it appears centered in window + Vector2 graphCenter = bounds.center; + // move nodes so center is at origin + for (int i = 0; i < nodes.Count; i++) + nodes[i].position -= graphCenter; + + // reset pan/zoom so centered + pan = Vector2.zero; + zoom = 1.0f; + Repaint(); + } + + + static Rect RectUnion(Rect a, Rect b) { + float xMin = Mathf.Min(a.xMin, b.xMin); + float xMax = Mathf.Max(a.xMax, b.xMax); + float yMin = Mathf.Min(a.yMin, b.yMin); + float yMax = Mathf.Max(a.yMax, b.yMax); + return Rect.MinMaxRect(xMin, yMin, xMax, yMax); + } + + Vector2 ScreenToGraph_old(Vector2 screenPos) { + Vector2 origin = new Vector2(position.width / 2, position.height / 2); + // invert the GUI.matrix transform (approx for current simple transforms) + return (screenPos - (origin + pan)) / zoom + origin * (1 - 1 / zoom); + } + Vector2 ScreenToGraph(Vector2 screenPos) { + Vector2 windowCenter = new Vector2(position.width / 2f, position.height / 2f); + Rect bounds = GetGraphBounds(); + Vector2 graphCenter = bounds.center; + Vector2 autoPan = -graphCenter; + // inverse of: screen -> translate by -(windowCenter+autoPan+pan), scale by 1/zoom, translate by windowCenter + return (screenPos - (windowCenter + autoPan + pan)) / zoom + windowCenter; + } + + + Rect GetGraphBounds() { + if (nodes == null || nodes.Count == 0) return new Rect(Vector2.zero, Vector2.one); + Rect bounds = new( + nodes[0].position - Vector2.one * nodes[0].radius, + 2f * nodes[0].radius * Vector2.one); + foreach (var n in nodes) + bounds = RectUnion(bounds, + new Rect(n.position - Vector2.one * n.radius, 2f * n.radius * Vector2.one)); + return bounds; + } + + + + int HitTestNode(Vector2 graphPos) { + // returns node id under point or -1 + for (int i = nodes.Count - 1; i >= 0; i--) { + var n = nodes[i]; + if ((graphPos - n.position).sqrMagnitude <= n.radius * n.radius) return n.id; + } + return -1; + } + +} diff --git a/Editor/BrainEditorWindow.cs.meta b/Editor/BrainEditorWindow.cs.meta new file mode 100644 index 0000000..5d8b61f --- /dev/null +++ b/Editor/BrainEditorWindow.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f041740900808273ab006e7d276a78e9 diff --git a/Editor/DAGWindow.cs b/Editor/DAGWindow.cs new file mode 100644 index 0000000..aaf5aa3 --- /dev/null +++ b/Editor/DAGWindow.cs @@ -0,0 +1,393 @@ + +using UnityEngine; +using UnityEditor; +using System.Collections.Generic; +using System.Linq; + +// Simple DAG data model +// [System.Serializable] +// public class DagNode +// { +// public int id; +// public string title; +// public Vector2 position; +// public float radius = 36f; // circle radius +// } + +// [System.Serializable] +// public class DagEdge +// { +// public int fromId; +// public int toId; +// } + +public class DAGEditorWindow : EditorWindow +{ + List nodes = new List(); + List edges = new List(); + + Vector2 pan = Vector2.zero; + float zoom = 1.0f; + const float minZoom = 0.5f; + const float maxZoom = 2.0f; + + GUIStyle labelStyle; + int selectedNodeId = -1; + + Vector2 dragStart; + bool draggingNode = false; + int draggingNodeId = -1; + + [MenuItem("Window/DAG Viewer (LR, Circles)")] + public static void ShowWindow() + { + var w = GetWindow("DAG Viewer (LR)"); + w.minSize = new Vector2(500, 300); + } + + void OnEnable() + { + labelStyle = new GUIStyle(EditorStyles.label); + labelStyle.alignment = TextAnchor.MiddleCenter; + labelStyle.normal.textColor = Color.white; + labelStyle.fontStyle = FontStyle.Bold; + + if (nodes.Count == 0) + CreateSampleGraph(); + + ComputeLeftToRightLayout(); + } + + void CreateSampleGraph() + { + nodes.Clear(); + edges.Clear(); + + nodes.Add(new DagNode() { id = 0, title = "In1" }); + nodes.Add(new DagNode() { id = 1, title = "In2" }); + nodes.Add(new DagNode() { id = 2, title = "A" }); + nodes.Add(new DagNode() { id = 3, title = "B" }); + nodes.Add(new DagNode() { id = 4, title = "C" }); + nodes.Add(new DagNode() { id = 5, title = "Out1" }); + nodes.Add(new DagNode() { id = 6, title = "Out2" }); + + edges.Add(new DagEdge() { fromId = 0, toId = 2 }); + edges.Add(new DagEdge() { fromId = 1, toId = 2 }); + edges.Add(new DagEdge() { fromId = 2, toId = 3 }); + edges.Add(new DagEdge() { fromId = 2, toId = 4 }); + edges.Add(new DagEdge() { fromId = 3, toId = 5 }); + edges.Add(new DagEdge() { fromId = 4, toId = 6 }); + } + + void OnGUI() + { + HandleInput(); + + Rect rect = new Rect(0, 0, position.width, position.height); + EditorGUI.DrawRect(rect, new Color(0.11f, 0.11f, 0.11f)); + + Matrix4x4 oldMatrix = GUI.matrix; + Vector2 origin = new Vector2(position.width / 2, position.height / 2); + GUI.matrix = Matrix4x4.TRS(origin + pan, Quaternion.identity, Vector3.one * zoom) * + Matrix4x4.TRS(-origin, Quaternion.identity, Vector3.one); + + // Draw edges first + foreach (var e in edges) + { + var from = GetNodeById(e.fromId); + var to = GetNodeById(e.toId); + if (from == null || to == null) continue; + DrawEdgeCircleNodes(from, to); + } + + // Draw nodes (circles) + foreach (var n in nodes) + { + DrawNodeCircle(n); + } + + GUI.matrix = oldMatrix; + + // Footer toolbar + GUILayout.FlexibleSpace(); + EditorGUILayout.BeginHorizontal(EditorStyles.toolbar); + if (GUILayout.Button("Fit", EditorStyles.toolbarButton)) FitToView(); + if (GUILayout.Button("Layout LR", EditorStyles.toolbarButton)) ComputeLeftToRightLayout(); + if (GUILayout.Button("Add Node", EditorStyles.toolbarButton)) + { + AddNode("N" + nodes.Count); + ComputeLeftToRightLayout(); + } + if (GUILayout.Button("Add Edge (selected->new)", EditorStyles.toolbarButton)) + { + if (selectedNodeId != -1) + { + var newNode = AddNode("N" + nodes.Count); + edges.Add(new DagEdge() { fromId = selectedNodeId, toId = newNode.id }); + ComputeLeftToRightLayout(); + } + } + EditorGUILayout.EndHorizontal(); + } + + void HandleInput() + { + Event e = Event.current; + + // Zoom with scroll + if (e.type == EventType.ScrollWheel) + { + float oldZoom = zoom; + float delta = -e.delta.y * 0.01f; + zoom = Mathf.Clamp(zoom + delta, minZoom, maxZoom); + Vector2 mouse = e.mousePosition; + pan += (mouse - new Vector2(position.width / 2, position.height / 2)) * (1 - zoom / oldZoom); + e.Use(); + } + + // Pan with middle or right+ctrl drag + if (e.type == EventType.MouseDrag && (e.button == 2 || (e.button == 1 && e.control))) + { + pan += e.delta; + e.Use(); + } + + // Node dragging & selection (convert mouse to graph space) + Vector2 graphMouse = ScreenToGraph(e.mousePosition); + if (e.type == EventType.MouseDown && e.button == 0) + { + int hit = HitTestNode(graphMouse); + if (hit != -1) + { + selectedNodeId = hit; + draggingNode = true; + draggingNodeId = hit; + dragStart = graphMouse; + e.Use(); + } + else + { + selectedNodeId = -1; + } + } + + if (draggingNode && draggingNodeId != -1) + { + if (e.type == EventType.MouseDrag && e.button == 0) + { + Vector2 graphDelta = e.delta / zoom; + var n = GetNodeById(draggingNodeId); + if (n != null) + { + n.position += graphDelta; + Repaint(); + e.Use(); + } + } + if (e.type == EventType.MouseUp && e.button == 0) + { + draggingNode = false; + draggingNodeId = -1; + e.Use(); + } + } + } + + DagNode AddNode(string title) + { + int nextId = nodes.Count > 0 ? nodes.Max(n => n.id) + 1 : 0; + var n = new DagNode() { id = nextId, title = title, position = Vector2.zero }; + nodes.Add(n); + return n; + } + + DagNode GetNodeById(int id) => nodes.FirstOrDefault(x => x.id == id); + + void DrawNodeCircle(DagNode n) + { + Vector2 center = n.position; + float r = n.radius; + Rect nodeRect = new Rect(center.x - r, center.y - r, r * 2, r * 2); + + // circle background + Color bg = (n.id == selectedNodeId) ? new Color(0.15f, 0.5f, 0.9f) : new Color(0.2f, 0.2f, 0.2f); + EditorGUI.DrawRect(nodeRect, bg); + + // anti-aliased circle outline + Handles.color = Color.white * 0.9f; + Handles.DrawAAPolyLine(3f / zoom, GetCircleOutlinePoints(center, r, 48).ToArray()); + + // label + Vector2 labelPos = center - new Vector2(0, 8); + GUI.Label(new Rect(labelPos.x - r, labelPos.y - 8, r * 2, 18), n.title, labelStyle); + } + + List GetCircleOutlinePoints(Vector2 center, float radius, int segments) + { + var pts = new List(segments + 1); + for (int i = 0; i <= segments; i++) + { + float a = (float)i / segments * Mathf.PI * 2f; + pts.Add(new Vector3(center.x + Mathf.Cos(a) * radius, center.y + Mathf.Sin(a) * radius, 0)); + } + return pts; + } + + void DrawEdgeCircleNodes(DagNode from, DagNode to) + { + Vector2 a = from.position; + Vector2 b = to.position; + if (a == b) return; + + // Compute edge line that starts/ends at circle circumferences + Vector2 dir = (b - a).normalized; + Vector2 start = a + dir * from.radius; + Vector2 end = b - dir * to.radius; + + // Use a simple curved line: start -> control -> end (bezier) + Vector2 control = new Vector2((start.x + end.x) / 2f, (start.y + end.y) / 2f); + // Slight vertical offset to separate overlapping lines based on node ids + float offset = ((from.id * 7 + to.id * 11) % 7 - 3) * 6f / zoom; + control += new Vector2(0, offset); + + Handles.color = Color.white * 0.9f; + Handles.DrawAAPolyLine(3f / zoom, 20, GetBezierPoints(start, control, end, 24).ToArray()); + + // Arrow at end pointing towards 'b' + DrawArrowHead(end - dir * 2f, end, 10f / zoom, 12f / zoom, Color.white); + } + + List GetBezierPoints(Vector2 p0, Vector2 p1, Vector2 p2, int seg) + { + var pts = new List(seg + 1); + for (int i = 0; i <= seg; i++) + { + float t = (float)i / seg; + Vector2 p = (1 - t) * (1 - t) * p0 + 2 * (1 - t) * t * p1 + t * t * p2; + pts.Add(new Vector3(p.x, p.y, 0)); + } + return pts; + } + + void DrawArrowHead(Vector2 from, Vector2 to, float headWidth, float headLength, Color color) + { + Vector2 dir = (to - from).normalized; + if (dir == Vector2.zero) return; + Vector2 right = new Vector2(-dir.y, dir.x); + + Vector3 p1 = to; + Vector3 p2 = to - dir * headLength + right * headWidth * 0.5f; + Vector3 p3 = to - dir * headLength - right * headWidth * 0.5f; + + Handles.color = color; + Handles.DrawAAConvexPolygon(p1, p2, p3); + } + + // Left-to-right layered layout (sources on the left, sinks on the right) + void ComputeLeftToRightLayout() + { + // build adjacency and indegree + var adj = nodes.ToDictionary(n => n.id, n => new List()); + var indeg = nodes.ToDictionary(n => n.id, n => 0); + foreach (var e in edges) + { + if (!adj.ContainsKey(e.fromId) || !adj.ContainsKey(e.toId)) continue; + adj[e.fromId].Add(e.toId); + indeg[e.toId]++; + } + + // Kahn's algorithm to compute topological layers (horizontal layers) + Dictionary layer = new Dictionary(); + Queue q = new Queue(indeg.Where(kv => kv.Value == 0).Select(kv => kv.Key)); + foreach (var id in q) layer[id] = 0; + + while (q.Count > 0) + { + int u = q.Dequeue(); + int l = layer[u]; + foreach (var v in adj[u]) + { + // prefer placing v at least one layer after u + if (!layer.ContainsKey(v) || layer[v] < l + 1) layer[v] = l + 1; + indeg[v]--; + if (indeg[v] == 0) q.Enqueue(v); + } + } + + // Any unreachable nodes -> assign next layers + int maxLayer = layer.Count > 0 ? layer.Values.Max() : 0; + foreach (var n in nodes) + { + if (!layer.ContainsKey(n.id)) + { + maxLayer++; + layer[n.id] = maxLayer; + } + } + + // Group nodes by layer (left to right) + var layers = layer.GroupBy(kv => kv.Value).OrderBy(g => g.Key).Select(g => g.Select(x => x.Key).ToList()).ToList(); + + // Layout parameters (horizontal spacing drives left->right) + float hSpacing = 220f; + float vSpacing = 120f; + + // Place nodes: x increases with layer index, y spaced within layer + for (int li = 0; li < layers.Count; li++) + { + var lst = layers[li]; + float totalHeight = (lst.Count - 1) * vSpacing; + for (int i = 0; i < lst.Count; i++) + { + int id = lst[i]; + var n = GetNodeById(id); + if (n == null) continue; + float x = li * hSpacing; + float y = -totalHeight / 2f + i * vSpacing; + n.position = new Vector2(x, y); + } + } + + Repaint(); + } + + void FitToView() + { + if (nodes.Count == 0) return; + Rect bounds = new Rect(nodes[0].position - Vector2.one * nodes[0].radius, Vector2.one * nodes[0].radius * 2f); + foreach (var n in nodes) + bounds = RectUnion(bounds, new Rect(n.position - Vector2.one * n.radius, Vector2.one * n.radius * 2f)); + + Vector2 center = bounds.center; + pan = -center; + zoom = 1.0f; + Repaint(); + } + + static Rect RectUnion(Rect a, Rect b) + { + float xMin = Mathf.Min(a.xMin, b.xMin); + float xMax = Mathf.Max(a.xMax, b.xMax); + float yMin = Mathf.Min(a.yMin, b.yMin); + float yMax = Mathf.Max(a.yMax, b.yMax); + return Rect.MinMaxRect(xMin, yMin, xMax, yMax); + } + + Vector2 ScreenToGraph(Vector2 screenPos) + { + Vector2 origin = new Vector2(position.width / 2, position.height / 2); + // invert the GUI.matrix transform (approx for current simple transforms) + return (screenPos - (origin + pan)) / zoom + origin * (1 - 1 / zoom); + } + + int HitTestNode(Vector2 graphPos) + { + // returns node id under point or -1 + for (int i = nodes.Count - 1; i >= 0; i--) + { + var n = nodes[i]; + if ((graphPos - n.position).sqrMagnitude <= n.radius * n.radius) return n.id; + } + return -1; + } +} diff --git a/Editor/DAGWindow.cs.meta b/Editor/DAGWindow.cs.meta new file mode 100644 index 0000000..ea0ee9e --- /dev/null +++ b/Editor/DAGWindow.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 95393aed582b8b30d965400672aec4d8 \ No newline at end of file From 537064d84be62d14ae41ce59265492bb70edfafb Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 12 Feb 2026 15:14:55 +0100 Subject: [PATCH 141/179] Receptorarrays seems to work --- Cluster.cs | 2 +- Editor/ClusterInspector.cs | 54 +++++-- Neuron.cs | 2 +- Nucleus.cs | 7 +- ReceptorArray.cs | 301 ++++++++++++++++++++++++++++--------- 5 files changed, 275 insertions(+), 91 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index a05f20b..84ee436 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -368,7 +368,7 @@ public class Cluster : Nucleus { } public override void UpdateStateIsolated() { - Vector3 sum = this.bias; + float3 sum = this.bias; //Applying the weight factors foreach (Synapse synapse in this.synapses) { diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index bd0e313..22c786b 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -424,13 +424,16 @@ public class ClusterInspector : Editor { normal = { textColor = Color.white }, fontStyle = FontStyle.Bold, }; - //if (nucleus is Nucleus neuron) { + if (nucleus.array == null || nucleus.array.nuclei == null || nucleus.array.nuclei.Count() == 0) nucleus.array = new NucleusArray(nucleus); if ((!expandArray || nucleus.array.nuclei.First() != this.currentNucleus) && nucleus.array.nuclei.Count() > 1) { Handles.Label(labelPosition, nucleus.array.nuclei.Count().ToString(), style); } + if (!expandArray && nucleus is ReceptorArray receptor) { + Handles.Label(labelPosition, receptor.receptors.Count().ToString(), style); + } if (expandArray && nucleus.array.nuclei.First() == this.currentNucleus) { int arrayIx = 0; foreach (Nucleus n in nucleus.array.nuclei) { @@ -456,12 +459,6 @@ public class ClusterInspector : Editor { Handles.color = Color.white; Handles.DrawWireDisc(position, Vector3.forward, size + 10); } - // } - // else { - // style.alignment = TextAnchor.UpperCenter; - // Vector3 labelPos = position - Vector3.down * (size + 10); // below disc along up axis - // Handles.Label(labelPos, nucleus.name, style); - // } // Tooltip Rect neuronRect = new(position.x - size, position.y - size, size * 2, size * 2); @@ -565,6 +562,21 @@ public class ClusterInspector : Editor { if (this.currentNucleus is MemoryCell memory) { memory.staticMemory = EditorGUILayout.Toggle("Static Memory", memory.staticMemory); } + if (this.currentNucleus is ReceptorArray receptor) { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.IntField("Receptor size", receptor.receptors.Count()); + if (GUILayout.Button("Add")) { + Undo.RecordObject(prefabAsset, "Receptor add " + prefabAsset.name); + receptor.AddReceptor(this.prefab); + anythingChanged = true; + } + if (GUILayout.Button("Del")) { + Undo.RecordObject(prefabAsset, "Receptor delete " + prefabAsset.name); + receptor.RemoveReceptor(); + anythingChanged = true; + } + EditorGUILayout.EndHorizontal(); + } // Synapses @@ -689,10 +701,20 @@ public class ClusterInspector : Editor { void OnSceneGUI(SceneView sceneView) { if (this.gameObject != null) { - foreach (Nucleus nucleus in this.currentNucleus.array.nuclei) { - Vector3 worldVector = this.gameObject.transform.TransformVector(nucleus.outputValue); - Handles.color = Color.yellow; - Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); + if (this.currentNucleus is ReceptorArray receptor) { + foreach (Nucleus nucleus in receptor.receptors) { + Vector3 worldVector = this.gameObject.transform.TransformVector(nucleus.outputValue); + Handles.color = Color.yellow; + Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); + } + + } + else { + foreach (Nucleus nucleus in this.currentNucleus.array.nuclei) { + Vector3 worldVector = this.gameObject.transform.TransformVector(nucleus.outputValue); + Handles.color = Color.yellow; + Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); + } } } } @@ -714,6 +736,9 @@ public class ClusterInspector : Editor { case Nucleus.Type.Pulsar: AddPulsarInput(nucleus); break; + case Nucleus.Type.Receptor: + AddReceptorInput(nucleus); + break; default: break; } @@ -793,6 +818,13 @@ public class ClusterInspector : Editor { ClusterPickerWindow.ShowPicker(brain => OnClusterPicked(nucleus, brain), "Select Cluster"); } + protected virtual void AddReceptorInput(Nucleus nucleus) { + ReceptorArray newReceptor = new(this.prefab, "New Receptor"); + newReceptor.AddReceiver(nucleus); + this.currentNucleus = newReceptor; + BuildLayers(); + } + private void OnClusterPicked(Nucleus nucleus, ClusterPrefab prefab) { Cluster subclusterInstance = new(prefab, this.prefab); subclusterInstance.AddReceiver(nucleus); diff --git a/Neuron.cs b/Neuron.cs index 0a58257..461240a 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -192,7 +192,7 @@ public class Neuron : Nucleus { }; public float3 CombinatorSum() { - Vector3 sum = this.bias; + float3 sum = this.bias; foreach (Synapse synapse in this.synapses) sum += synapse.weight * synapse.nucleus.outputValue; return sum; diff --git a/Nucleus.cs b/Nucleus.cs index 64d1fe4..83fb34a 100644 --- a/Nucleus.cs +++ b/Nucleus.cs @@ -13,7 +13,7 @@ public abstract class Nucleus { public Cluster parent { get; set; } protected float3 _outputValue; - public virtual Vector3 outputValue { + public virtual float3 outputValue { get { return _outputValue; } set { //this.stale = 0; @@ -40,7 +40,8 @@ public abstract class Nucleus { MemoryCell, Selector, Cluster, - Pulsar + Pulsar, + Receptor } #region Synapses @@ -110,7 +111,7 @@ public abstract class Nucleus { } } - public void ProcessStimulus(int thingId, Vector3 inputValue, string thingName = null) { + public virtual void ProcessStimulus(int thingId, Vector3 inputValue, string thingName = null) { this.array.ProcessStimulus(thingId, inputValue, thingName); } diff --git a/ReceptorArray.cs b/ReceptorArray.cs index 70afe30..27ba835 100644 --- a/ReceptorArray.cs +++ b/ReceptorArray.cs @@ -1,87 +1,238 @@ -/* +using System; using System.Collections.Generic; +using System.Linq; using UnityEngine; +using Unity.Mathematics; +using static Unity.Mathematics.math; -public class ReceptorArray { - public string name; - - public Cluster parent { get; set; } - - public NucleusArray nuclei; - public int size => nuclei.nuclei.Length; - - public Dictionary thingReceivers = new(); - - public ReceptorArray(Cluster parent, NucleusArray nuclei) { +[Serializable] +public class ReceptorInstance : Nucleus { + public ReceptorInstance(Cluster parent, string name) { this.parent = parent; - this.nuclei = nuclei; + this.name = name; + // We explicitly do not add this to the parent, as it is serialized in the ReceptorArray + } + public ReceptorInstance(ClusterPrefab prefab, string name) { + this.cluster = prefab; + this.name = name; + // We explicitly do not add this to the prefab, as it is serialized in the ReceptorArray + } + public override Nucleus ShallowCloneTo(Cluster parent) { + ReceptorInstance clone = new(parent, name + " +1"); + return clone; + } + public override Nucleus Clone(ClusterPrefab prefab) { + ReceptorInstance clone = new(prefab, name); + return clone; + } + public override void UpdateStateIsolated() { + } +} + +[Serializable] +public class ReceptorArray : Nucleus { + public ReceptorArray(Cluster parent, string name) { + this.parent = parent; + this.name = name; + this._receptors = new ReceptorInstance[1]; + this._receptors[0] = new ReceptorInstance(parent, this.name + "[0]"); + this.parent?.nuclei.Add(this); + } + public ReceptorArray(ClusterPrefab prefab, string name) { + this.cluster = prefab; + this.name = name; + this._receptors = new ReceptorInstance[1]; + this._receptors[0] = new ReceptorInstance(prefab, this.name + "[0]"); + if (this.cluster != null) + this.cluster.nuclei.Add(this); + else + Debug.LogError("No prefab when adding receptor to prefab"); + } - public virtual void ProcessStimulus(int thingId, Vector3 newLocalPositionVector, string thingName = null) { - if (!thingReceivers.TryGetValue(thingId, out INucleus selectedReceiver)) { - foreach (IReceptor receptor in this.nuclei.nuclei) { - if (receptor is not INucleus receiver) - continue; - if (thingReceivers.ContainsValue(receiver)) - continue; - // receiver is not used yet + public override Nucleus ShallowCloneTo(Cluster parent) { + ReceptorArray clone = new(parent, name) { + _receptors = new ReceptorInstance[this.receptors.Length] + }; + for (int ix = 0; ix < this.receptors.Length; ix++) { + clone._receptors[ix] = new ReceptorInstance(parent, $"{this.name} [{ix}]"); + } + + return clone; + } + + public override Nucleus Clone(ClusterPrefab prefab) { + ReceptorArray clone = new(prefab, this.name) { + }; + clone._receptors = new ReceptorInstance[this.receptors.Length]; + for (int ix = 0; ix < this.receptors.Length; ix++) { + clone._receptors[ix] = new ReceptorInstance(prefab, this.name); + } + + foreach (Synapse synapse in this.synapses) { + Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); + clonedSynapse.weight = synapse.weight; + } + foreach (Nucleus receiver in this.receivers) { + clone.AddReceiver(receiver); + } + return clone; + } + + [SerializeReference] + private ReceptorInstance[] _receptors; + public ReceptorInstance[] receptors { + get { + return _receptors; + } + } + + public void AddReceptor(ClusterPrefab prefab) { + if (this._receptors.Length == 0) { + Debug.LogError("Empty receptor array, cannot add"); + return; + } + int newLength = this._receptors.Length + 1; + ReceptorInstance[] newArray = new ReceptorInstance[newLength]; + + for (int i = 0; i < this._receptors.Length; i++) + newArray[i] = this._receptors[i]; + newArray[newLength - 1] = (ReceptorInstance)this._receptors[0].Clone(prefab); + + this._receptors = newArray; + } + + public void RemoveReceptor() { + int newLength = this._receptors.Length - 1; + if (newLength == 0) { + Debug.LogWarning("Receptor array cannot be empty"); + return; + } + ReceptorInstance[] newPerceptei = new ReceptorInstance[newLength]; + for (int i = 0; i < newLength; i++) + newPerceptei[i] = this._receptors[i]; + // Delete the last perception + if (this._receptors[newLength] is Nucleus nucleus) + Neuron.Delete(nucleus); //this._nuclei[newLength]); + + this._receptors = newPerceptei; + } + + private Dictionary thingReceivers = new(); + + public override void ProcessStimulus(int thingId, Vector3 inputValue, string thingName = null) { + ProcessStimulus(inputValue, thingId, thingName); + } + public void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) { + CleanupReceivers(); + if (!thingReceivers.TryGetValue(thingId, out Nucleus selectedReceiver)) { + Debug.Log($" no receiver found for {thingId}"); + // No existing nucleus for this thing + selectedReceiver = SelectReceptor(thingId, inputValue); + } + if (selectedReceiver == null) + return; + + if (thingName != null) { + string baseName = selectedReceiver.name; + int colonPos = selectedReceiver.name.IndexOf(":"); + if (colonPos > 0) + baseName = selectedReceiver.name[..colonPos]; + selectedReceiver.name = baseName + ": " + thingName; + } + + //if (selectedReceiver is Neuron selectedNucleus) { + selectedReceiver.stale = 0; + selectedReceiver.outputValue = inputValue; + this.parent.UpdateFromNucleus(this); + //selectedNucleus.ProcessStimulus(inputValue); + //} + } + + private void CleanupReceivers() { + // Remove a thing-receiver connection when the nucleus is inactive + List receiversToRemove = new(); + foreach (KeyValuePair item in thingReceivers) { + if (item.Value.isSleeping) + receiversToRemove.Add(item.Key); + } + foreach (int thingId in receiversToRemove) { + Nucleus selectedReceiver = thingReceivers[thingId]; + + Debug.Log($" removed receiver for {thingId}"); + thingReceivers.Remove(thingId); + + int colonPos = selectedReceiver.name.IndexOf(":"); + if (colonPos > 0) + selectedReceiver.name = selectedReceiver.name[..colonPos]; + } + } + + private Nucleus SelectReceptor(int thingId, float3 inputValue) { + // No existing nucleus for this thing + float inputMagnitude = length(inputValue); + Nucleus selectedReceiver = null; + float selectedMagnitude = 0; + foreach (Nucleus receiver in this._receptors) { + if (thingReceivers.ContainsValue(receiver) == false) { + // We found an unusued receiver + Debug.Log($"{thingId} -> [{receiver.name}]"); thingReceivers.Add(thingId, receiver); + return receiver; + } + else if (receiver.isSleeping) { + // A sleeping receiver is not active and can therefore always be used + thingReceivers.Add(thingId, receiver); + Debug.Log($"{thingId} -> [{selectedReceiver.name}]"); + return receiver; + } + else if (selectedReceiver == null) { + // If we haven't found a receiver yet, just start by taking the first selectedReceiver = receiver; + selectedMagnitude = length(selectedReceiver.outputValue); + } + // Look for the receiver with the lowest magnitude + else { + float magnitude = length(receiver.outputValue); + + if (magnitude < inputMagnitude && length(receiver.outputValue) < selectedMagnitude) { + selectedReceiver = receiver; + selectedMagnitude = length(selectedReceiver.outputValue); + } } } - //selectedReceiver.outputValue = newLocalPositionVector; - - - - // int receiverIx = 0; - // INucleus selectedReceiver = null; - // int selectedReceiverIx = 0; - // foreach (INucleus receiver in this.receivers) { - // if (thingIds[receiverIx] == thingId) { - // // We found an existing receiver for this thing - // selectedReceiver = receiver; - // selectedReceiverIx = receiverIx; - // // Do not look any further - // break; - // } - // else if (receiver.isSleeping) { - // // A sleeping receiver is not active and can therefore always be used - // selectedReceiver = receiver; - // selectedReceiverIx = receiverIx; - // // Look further because we may find an existing receiver for this thing - // } - // else if (selectedReceiver == null) { - // // If we haven't found a receiver yet, just start by taking the first - // selectedReceiver = receiver; - // selectedReceiverIx = receiverIx; - // } - // else if (selectedReceiver.isSleeping == false) { - // // If no existing or sleeping receiver is found, we look for - // // the receiver with the furthest/least interesting stimulus - // if (length(receiver.outputValue) < length(selectedReceiver.outputValue)) { - // // Debug.Log($"{selectedReceiver.name}[{selectedReceiverIx}] {length(selectedReceiver.outputValue)}" + - // // $" {receiver.name}[{receiverIx}] {length(receiver.outputValue)} "); - // selectedReceiver = receiver; - // selectedReceiverIx = receiverIx; - // } - // } - // receiverIx++; - // } - // if (selectedReceiverIx >= thingIds.Length) - // return; - - // thingIds[selectedReceiverIx] = thingId; - // if (thingName != null) { - // string baseName = selectedReceiver.name; - // int colonPos = selectedReceiver.name.IndexOf(":"); - // if (colonPos > 0) - // baseName = selectedReceiver.name.Substring(0, colonPos); - // selectedReceiver.name = baseName + ": " + thingName; - // } - // Debug.Log($"Receiver {selectedReceiver.name}[{selectedReceiverIx}] for thing {thingId}"); - // selectedReceiver.parent.UpdateStateIsolated(); - + if (selectedReceiver != null) { + // Replace the receiver + // Find the thingId current associated with the receiver + int keyToRemove = thingReceivers.FirstOrDefault(r => r.Value.Equals(selectedReceiver)).Key; + if (keyToRemove != 0 || thingReceivers.ContainsKey(keyToRemove)) + thingReceivers.Remove(keyToRemove); + // And add the new association + thingReceivers.Add(thingId, selectedReceiver); + } + return selectedReceiver; } -} -*/ \ No newline at end of file + public override void UpdateStateIsolated() { + float3 sum = this.bias; + + // Receptors do not have inputs, so we ignore the synapses + foreach (Nucleus nucleus in this._receptors) + sum += nucleus.outputValue; + + this.outputValue = sum / _receptors.Length; + this.stale = 0; + + UpdateNuclei(); + } + + public override void UpdateNuclei() { + foreach (Nucleus nucleus in this.receptors) { + nucleus.stale++; + if (nucleus.stale > staleValueForSleep && lengthsq(nucleus.outputValue) > 0) { + nucleus.outputValue = Vector3.zero; + this.UpdateStateIsolated(); + } + } + } +} \ No newline at end of file From 19398ade9883ae7be07684970d490e3a8dd7457b Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 12 Feb 2026 17:02:27 +0100 Subject: [PATCH 142/179] Improved receptor --- Editor/ClusterInspector.cs | 120 ++++++++++++++++++++++++++----------- ReceptorArray.cs | 94 ++++++++++++++++++----------- 2 files changed, 143 insertions(+), 71 deletions(-) diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 22c786b..0b5eed1 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -263,35 +263,69 @@ public class ClusterInspector : Editor { // Draw selected Nucleus if (expandArray) { - float maxValue = 0; - foreach (Nucleus nucleus in this.currentNucleus.array.nuclei) { - float value = length(nucleus.outputValue); - if (value > maxValue) - maxValue = value; - } + if (this.currentNucleus is Receptor receptor) { + float maxValue = 0; + foreach (Nucleus nucleus in receptor.instances) { + float value = length(nucleus.outputValue); + if (value > maxValue) + maxValue = value; + } - float spacing = 400f / this.currentNucleus.array.nuclei.Count(); - float margin = 10 + spacing / 2; - float xMin = 150 - size; - float xMax = 150 + size; - float yMin = 10 + margin - size / 2; - float yMax = 400 - margin + size; - Vector3[] verts = new Vector3[4] { + float spacing = 400f / receptor.instances.Count(); + float margin = 10 + spacing / 2; + float xMin = 150 - size; + float xMax = 150 + size; + float yMin = 10 + margin - size / 2; + float yMax = 400 - margin + size; + Vector3[] verts = new Vector3[4] { new(xMin, yMin, 0), new(xMax, yMin, 0), new(xMax, yMax, 0), new(xMin, yMax, 0) }; - Handles.color = Color.black; - Handles.DrawAAConvexPolygon(verts); - int row = 0; - foreach (Nucleus nucleus in this.currentNucleus.array.nuclei) { - Vector3 pos = new(150, margin + row * spacing, 0.0f); - Handles.color = Color.white; - // The selected nucleus highlight ring - Handles.DrawSolidDisc(pos, Vector3.forward, size + 2); - DrawNucleus(nucleus, pos, maxValue, size); - row++; + Handles.color = Color.black; + Handles.DrawAAConvexPolygon(verts); + int row = 0; + foreach (Nucleus nucleus in receptor.instances) { + Vector3 pos = new(150, margin + row * spacing, 0.0f); + Handles.color = Color.white; + // The selected nucleus highlight ring + Handles.DrawSolidDisc(pos, Vector3.forward, size + 2); + DrawNucleus(nucleus, pos, maxValue, size); + row++; + } + } + else { + float maxValue = 0; + foreach (Nucleus nucleus in this.currentNucleus.array.nuclei) { + float value = length(nucleus.outputValue); + if (value > maxValue) + maxValue = value; + } + + float spacing = 400f / this.currentNucleus.array.nuclei.Count(); + float margin = 10 + spacing / 2; + float xMin = 150 - size; + float xMax = 150 + size; + float yMin = 10 + margin - size / 2; + float yMax = 400 - margin + size; + Vector3[] verts = new Vector3[4] { + new(xMin, yMin, 0), + new(xMax, yMin, 0), + new(xMax, yMax, 0), + new(xMin, yMax, 0) + }; + Handles.color = Color.black; + Handles.DrawAAConvexPolygon(verts); + int row = 0; + foreach (Nucleus nucleus in this.currentNucleus.array.nuclei) { + Vector3 pos = new(150, margin + row * spacing, 0.0f); + Handles.color = Color.white; + // The selected nucleus highlight ring + Handles.DrawSolidDisc(pos, Vector3.forward, size + 2); + DrawNucleus(nucleus, pos, maxValue, size); + row++; + } } } else { @@ -431,9 +465,20 @@ public class ClusterInspector : Editor { if ((!expandArray || nucleus.array.nuclei.First() != this.currentNucleus) && nucleus.array.nuclei.Count() > 1) { Handles.Label(labelPosition, nucleus.array.nuclei.Count().ToString(), style); } - if (!expandArray && nucleus is ReceptorArray receptor) { - Handles.Label(labelPosition, receptor.receptors.Count().ToString(), style); + if (nucleus is Receptor receptor) { + Handles.Label(labelPosition, receptor.instances.Count().ToString(), style); } + // else if (nucleus is ReceptorInstance receptorI) { + // if (expandArray) { + // int arrayIx = 0; + // foreach (ReceptorInstance n in receptorI.receptorArray.receptors) { + // if (n == receptorI) + // break; + // arrayIx++; + // } + // Handles.Label(labelPosition, $"[{arrayIx}]", style); + // } + // } if (expandArray && nucleus.array.nuclei.First() == this.currentNucleus) { int arrayIx = 0; foreach (Nucleus n in nucleus.array.nuclei) { @@ -494,10 +539,12 @@ public class ClusterInspector : Editor { private void HandleClicked(Nucleus nucleus) { if (nucleus == this.currentNucleus) { - if (nucleus is Nucleus n) { - expandArray = !expandArray; - return; - } + expandArray = !expandArray; + } + else if (nucleus is ReceptorInstance receptor) { + expandArray = false; + this.currentNucleus = receptor.receptor; + BuildLayers(); } else if (nucleus is Nucleus n) { this.currentNucleus = n; @@ -562,9 +609,9 @@ public class ClusterInspector : Editor { if (this.currentNucleus is MemoryCell memory) { memory.staticMemory = EditorGUILayout.Toggle("Static Memory", memory.staticMemory); } - if (this.currentNucleus is ReceptorArray receptor) { + if (this.currentNucleus is Receptor receptor) { EditorGUILayout.BeginHorizontal(); - EditorGUILayout.IntField("Receptor size", receptor.receptors.Count()); + EditorGUILayout.IntField("Receptor size", receptor.instances.Count()); if (GUILayout.Button("Add")) { Undo.RecordObject(prefabAsset, "Receptor add " + prefabAsset.name); receptor.AddReceptor(this.prefab); @@ -621,8 +668,11 @@ public class ClusterInspector : Editor { else { EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField(synapse.nucleus.name); - if (GUILayout.Button("Disconnect")) + if (GUILayout.Button("Disconnect")) { synapse.nucleus.RemoveReceiver(this.currentNucleus); + this.prefab.GarbageCollection(); + anythingChanged = true; + } EditorGUILayout.EndHorizontal(); } @@ -701,8 +751,8 @@ public class ClusterInspector : Editor { void OnSceneGUI(SceneView sceneView) { if (this.gameObject != null) { - if (this.currentNucleus is ReceptorArray receptor) { - foreach (Nucleus nucleus in receptor.receptors) { + if (this.currentNucleus is Receptor receptor && expandArray) { + foreach (Nucleus nucleus in receptor.instances) { Vector3 worldVector = this.gameObject.transform.TransformVector(nucleus.outputValue); Handles.color = Color.yellow; Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); @@ -819,7 +869,7 @@ public class ClusterInspector : Editor { } protected virtual void AddReceptorInput(Nucleus nucleus) { - ReceptorArray newReceptor = new(this.prefab, "New Receptor"); + Receptor newReceptor = new(this.prefab, "New Receptor"); newReceptor.AddReceiver(nucleus); this.currentNucleus = newReceptor; BuildLayers(); diff --git a/ReceptorArray.cs b/ReceptorArray.cs index 27ba835..1cc0533 100644 --- a/ReceptorArray.cs +++ b/ReceptorArray.cs @@ -18,31 +18,43 @@ public class ReceptorInstance : Nucleus { // We explicitly do not add this to the prefab, as it is serialized in the ReceptorArray } public override Nucleus ShallowCloneTo(Cluster parent) { - ReceptorInstance clone = new(parent, name + " +1"); + ReceptorInstance clone = new(parent, name + " +1") { + receptor = this.receptor + }; return clone; } public override Nucleus Clone(ClusterPrefab prefab) { - ReceptorInstance clone = new(prefab, name); + ReceptorInstance clone = new(prefab, name) { + receptor = this.receptor + }; return clone; } + + [SerializeReference] + public Receptor receptor; + public override void UpdateStateIsolated() { } } [Serializable] -public class ReceptorArray : Nucleus { - public ReceptorArray(Cluster parent, string name) { +public class Receptor : Nucleus { + public Receptor(Cluster parent, string name) { this.parent = parent; this.name = name; - this._receptors = new ReceptorInstance[1]; - this._receptors[0] = new ReceptorInstance(parent, this.name + "[0]"); + this._instances = new ReceptorInstance[1]; + this._instances[0] = new ReceptorInstance(parent, this.name + "[0]") { + receptor = this + }; this.parent?.nuclei.Add(this); } - public ReceptorArray(ClusterPrefab prefab, string name) { + public Receptor(ClusterPrefab prefab, string name) { this.cluster = prefab; this.name = name; - this._receptors = new ReceptorInstance[1]; - this._receptors[0] = new ReceptorInstance(prefab, this.name + "[0]"); + this._instances = new ReceptorInstance[1]; + this._instances[0] = new ReceptorInstance(prefab, this.name + "[0]") { + receptor = this + }; if (this.cluster != null) this.cluster.nuclei.Add(this); else @@ -51,22 +63,26 @@ public class ReceptorArray : Nucleus { } public override Nucleus ShallowCloneTo(Cluster parent) { - ReceptorArray clone = new(parent, name) { - _receptors = new ReceptorInstance[this.receptors.Length] + Receptor clone = new(parent, name) { + _instances = new ReceptorInstance[this.instances.Length] }; - for (int ix = 0; ix < this.receptors.Length; ix++) { - clone._receptors[ix] = new ReceptorInstance(parent, $"{this.name} [{ix}]"); + for (int ix = 0; ix < this.instances.Length; ix++) { + clone._instances[ix] = new ReceptorInstance(parent, $"{this.name} [{ix}]") { + receptor = clone + }; } return clone; } public override Nucleus Clone(ClusterPrefab prefab) { - ReceptorArray clone = new(prefab, this.name) { + Receptor clone = new(prefab, this.name) { + _instances = new ReceptorInstance[this.instances.Length] }; - clone._receptors = new ReceptorInstance[this.receptors.Length]; - for (int ix = 0; ix < this.receptors.Length; ix++) { - clone._receptors[ix] = new ReceptorInstance(prefab, this.name); + for (int ix = 0; ix < this.instances.Length; ix++) { + clone._instances[ix] = new ReceptorInstance(prefab, this.name) { + receptor = this + }; } foreach (Synapse synapse in this.synapses) { @@ -80,42 +96,44 @@ public class ReceptorArray : Nucleus { } [SerializeReference] - private ReceptorInstance[] _receptors; - public ReceptorInstance[] receptors { + private ReceptorInstance[] _instances; + public ReceptorInstance[] instances { get { - return _receptors; + return _instances; } } public void AddReceptor(ClusterPrefab prefab) { - if (this._receptors.Length == 0) { + if (this._instances.Length == 0) { Debug.LogError("Empty receptor array, cannot add"); return; } - int newLength = this._receptors.Length + 1; + int newLength = this._instances.Length + 1; ReceptorInstance[] newArray = new ReceptorInstance[newLength]; - for (int i = 0; i < this._receptors.Length; i++) - newArray[i] = this._receptors[i]; - newArray[newLength - 1] = (ReceptorInstance)this._receptors[0].Clone(prefab); + for (int i = 0; i < this._instances.Length; i++) + newArray[i] = this._instances[i]; + ReceptorInstance newReceptor = (ReceptorInstance)this._instances[0].Clone(prefab); + newReceptor.name = $"{this.name} [{this._instances.Length}]"; + newArray[newLength - 1] = newReceptor; - this._receptors = newArray; + this._instances = newArray; } public void RemoveReceptor() { - int newLength = this._receptors.Length - 1; + int newLength = this._instances.Length - 1; if (newLength == 0) { Debug.LogWarning("Receptor array cannot be empty"); return; } ReceptorInstance[] newPerceptei = new ReceptorInstance[newLength]; for (int i = 0; i < newLength; i++) - newPerceptei[i] = this._receptors[i]; + newPerceptei[i] = this._instances[i]; // Delete the last perception - if (this._receptors[newLength] is Nucleus nucleus) + if (this._instances[newLength] is Nucleus nucleus) Neuron.Delete(nucleus); //this._nuclei[newLength]); - this._receptors = newPerceptei; + this._instances = newPerceptei; } private Dictionary thingReceivers = new(); @@ -152,6 +170,8 @@ public class ReceptorArray : Nucleus { private void CleanupReceivers() { // Remove a thing-receiver connection when the nucleus is inactive List receiversToRemove = new(); + thingReceivers ??= new(); + foreach (KeyValuePair item in thingReceivers) { if (item.Value.isSleeping) receiversToRemove.Add(item.Key); @@ -165,7 +185,8 @@ public class ReceptorArray : Nucleus { int colonPos = selectedReceiver.name.IndexOf(":"); if (colonPos > 0) selectedReceiver.name = selectedReceiver.name[..colonPos]; - } + } + } private Nucleus SelectReceptor(int thingId, float3 inputValue) { @@ -173,7 +194,7 @@ public class ReceptorArray : Nucleus { float inputMagnitude = length(inputValue); Nucleus selectedReceiver = null; float selectedMagnitude = 0; - foreach (Nucleus receiver in this._receptors) { + foreach (Nucleus receiver in this._instances) { if (thingReceivers.ContainsValue(receiver) == false) { // We found an unusued receiver Debug.Log($"{thingId} -> [{receiver.name}]"); @@ -217,21 +238,22 @@ public class ReceptorArray : Nucleus { float3 sum = this.bias; // Receptors do not have inputs, so we ignore the synapses - foreach (Nucleus nucleus in this._receptors) + foreach (Nucleus nucleus in this._instances) sum += nucleus.outputValue; - this.outputValue = sum / _receptors.Length; + this.outputValue = sum / _instances.Length; this.stale = 0; UpdateNuclei(); } public override void UpdateNuclei() { - foreach (Nucleus nucleus in this.receptors) { + foreach (Nucleus nucleus in this.instances) { nucleus.stale++; if (nucleus.stale > staleValueForSleep && lengthsq(nucleus.outputValue) > 0) { nucleus.outputValue = Vector3.zero; - this.UpdateStateIsolated(); + //this.UpdateStateIsolated(); + this.parent.UpdateFromNucleus(this); } } } From 9b948fdd074c0d978dc8972450210ea93049c42b Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 12 Feb 2026 17:24:10 +0100 Subject: [PATCH 143/179] Works with major scrums with many ants --- Editor/ClusterInspector.cs | 14 ++++++++------ ReceptorArray.cs | 6 +++--- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 0b5eed1..be6cfa9 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -413,9 +413,10 @@ public class ClusterInspector : Editor { Handles.DrawLine(parentPos, pos); if (synapse.nucleus != null) { Color color = Color.black; - if (synapse.nucleus.isSleeping) - color = Color.darkRed; - else if (Application.isPlaying) { + // if (synapse.nucleus.isSleeping) + // color = Color.darkRed; + // else + if (Application.isPlaying) { float brightness = length(synapse.nucleus.outputValue) * synapse.weight / maxValue; color = new Color(brightness, brightness, brightness, 1f); } @@ -427,9 +428,10 @@ public class ClusterInspector : Editor { private void DrawNucleus(Nucleus nucleus, Vector3 position, float maxValue, float size) { Color color; - if (nucleus.isSleeping) - color = Color.darkRed; - else { + // if (nucleus.isSleeping) + // color = Color.darkRed; + // else + { if (Application.isPlaying) { float brightness = length(nucleus.outputValue) / maxValue; color = new Color(brightness, brightness, brightness, 1f); diff --git a/ReceptorArray.cs b/ReceptorArray.cs index 1cc0533..c9e6702 100644 --- a/ReceptorArray.cs +++ b/ReceptorArray.cs @@ -144,7 +144,7 @@ public class Receptor : Nucleus { public void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) { CleanupReceivers(); if (!thingReceivers.TryGetValue(thingId, out Nucleus selectedReceiver)) { - Debug.Log($" no receiver found for {thingId}"); + //Debug.Log($" no receiver found for {thingId}"); // No existing nucleus for this thing selectedReceiver = SelectReceptor(thingId, inputValue); } @@ -179,7 +179,7 @@ public class Receptor : Nucleus { foreach (int thingId in receiversToRemove) { Nucleus selectedReceiver = thingReceivers[thingId]; - Debug.Log($" removed receiver for {thingId}"); + // Debug.Log($" removed receiver for {thingId}"); thingReceivers.Remove(thingId); int colonPos = selectedReceiver.name.IndexOf(":"); @@ -197,7 +197,7 @@ public class Receptor : Nucleus { foreach (Nucleus receiver in this._instances) { if (thingReceivers.ContainsValue(receiver) == false) { // We found an unusued receiver - Debug.Log($"{thingId} -> [{receiver.name}]"); + // Debug.Log($"{thingId} -> [{receiver.name}]"); thingReceivers.Add(thingId, receiver); return receiver; } From f295da9c5559700735ae9ef1b6eee0fc0f1aca8c Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Fri, 13 Feb 2026 14:52:17 +0100 Subject: [PATCH 144/179] Further improve receptor / nucleusarray combination --- Editor/ClusterInspector.cs | 63 ++++++++++---- Neuron.cs | 4 +- Nucleus.cs | 7 +- Receptor.cs | 172 ++++++------------------------------- ReceptorArray.cs | 17 ++-- 5 files changed, 91 insertions(+), 172 deletions(-) diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index be6cfa9..55efb1e 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -263,7 +263,7 @@ public class ClusterInspector : Editor { // Draw selected Nucleus if (expandArray) { - if (this.currentNucleus is Receptor receptor) { + if (this.currentNucleus is ReceptorArray receptor) { float maxValue = 0; foreach (Nucleus nucleus in receptor.instances) { float value = length(nucleus.outputValue); @@ -467,7 +467,7 @@ public class ClusterInspector : Editor { if ((!expandArray || nucleus.array.nuclei.First() != this.currentNucleus) && nucleus.array.nuclei.Count() > 1) { Handles.Label(labelPosition, nucleus.array.nuclei.Count().ToString(), style); } - if (nucleus is Receptor receptor) { + if (nucleus is ReceptorArray receptor) { Handles.Label(labelPosition, receptor.instances.Count().ToString(), style); } // else if (nucleus is ReceptorInstance receptorI) { @@ -611,7 +611,7 @@ public class ClusterInspector : Editor { if (this.currentNucleus is MemoryCell memory) { memory.staticMemory = EditorGUILayout.Toggle("Static Memory", memory.staticMemory); } - if (this.currentNucleus is Receptor receptor) { + if (this.currentNucleus is ReceptorArray receptor) { EditorGUILayout.BeginHorizontal(); EditorGUILayout.IntField("Receptor size", receptor.instances.Count()); if (GUILayout.Button("Add")) { @@ -626,6 +626,22 @@ public class ClusterInspector : Editor { } EditorGUILayout.EndHorizontal(); } + if (this.currentNucleus is Receptor receptor1) { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.IntField("Array size", receptor1.array.nuclei.Count()); + if (GUILayout.Button("Add")) { + Undo.RecordObject(prefabAsset, "Array add " + prefabAsset.name); + receptor1.array.AddNucleus(this.prefab); + anythingChanged = true; + } + if (GUILayout.Button("Del")) { + Undo.RecordObject(prefabAsset, "Array delete " + prefabAsset.name); + receptor1.array.RemoveNucleus(); + anythingChanged = true; + } + EditorGUILayout.EndHorizontal(); + } + // Synapses @@ -707,19 +723,22 @@ public class ClusterInspector : Editor { } if (neuron.array == null || neuron.array.nuclei == null || neuron.array.nuclei.Count() == 0) neuron.array = new NucleusArray(neuron); - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.IntField("Array size", neuron.array.nuclei.Count()); - if (GUILayout.Button("Add")) { - Undo.RecordObject(prefabAsset, "Array add " + prefabAsset.name); - neuron.array.AddNucleus(this.prefab); - anythingChanged = true; - } - if (GUILayout.Button("Del")) { - Undo.RecordObject(prefabAsset, "Array delete " + prefabAsset.name); - neuron.array.RemoveNucleus(); - anythingChanged = true; - } - EditorGUILayout.EndHorizontal(); + + // if (this.currentNucleus is Receptor receptor1) { + // EditorGUILayout.BeginHorizontal(); + // EditorGUILayout.IntField("Array size", receptor1.array.nuclei.Count()); + // if (GUILayout.Button("Add")) { + // Undo.RecordObject(prefabAsset, "Array add " + prefabAsset.name); + // receptor1.array.AddNucleus(this.prefab); + // anythingChanged = true; + // } + // if (GUILayout.Button("Del")) { + // Undo.RecordObject(prefabAsset, "Array delete " + prefabAsset.name); + // receptor1.array.RemoveNucleus(); + // anythingChanged = true; + // } + // EditorGUILayout.EndHorizontal(); + // } } EditorGUILayout.Space(); @@ -753,7 +772,7 @@ public class ClusterInspector : Editor { void OnSceneGUI(SceneView sceneView) { if (this.gameObject != null) { - if (this.currentNucleus is Receptor receptor && expandArray) { + if (this.currentNucleus is ReceptorArray receptor && expandArray) { foreach (Nucleus nucleus in receptor.instances) { Vector3 worldVector = this.gameObject.transform.TransformVector(nucleus.outputValue); Handles.color = Color.yellow; @@ -791,6 +810,9 @@ public class ClusterInspector : Editor { case Nucleus.Type.Receptor: AddReceptorInput(nucleus); break; + case Nucleus.Type.ReceptorArray: + AddReceptorArrayInput(nucleus); + break; default: break; } @@ -877,6 +899,13 @@ public class ClusterInspector : Editor { BuildLayers(); } + protected virtual void AddReceptorArrayInput(Nucleus nucleus) { + ReceptorArray newReceptor = new(this.prefab, "New Receptor"); + newReceptor.AddReceiver(nucleus); + this.currentNucleus = newReceptor; + BuildLayers(); + } + private void OnClusterPicked(Nucleus nucleus, ClusterPrefab prefab) { Cluster subclusterInstance = new(prefab, this.prefab); subclusterInstance.AddReceiver(nucleus); diff --git a/Neuron.cs b/Neuron.cs index 461240a..7719547 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -14,8 +14,8 @@ public class Neuron : Nucleus { this.name = name; this.parent?.nuclei.Add(this); } - public Neuron(ClusterPrefab parent, string name) { - this.cluster = parent; + public Neuron(ClusterPrefab prefab, string name) { + this.cluster = prefab; this.name = name; if (this.cluster != null) this.cluster.nuclei.Add(this); diff --git a/Nucleus.cs b/Nucleus.cs index 83fb34a..2eead83 100644 --- a/Nucleus.cs +++ b/Nucleus.cs @@ -41,7 +41,8 @@ public abstract class Nucleus { Selector, Cluster, Pulsar, - Receptor + Receptor, + ReceptorArray } #region Synapses @@ -111,6 +112,10 @@ public abstract class Nucleus { } } + public virtual void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) { + this.array.ProcessStimulus(thingId, inputValue, thingName); + } + public virtual void ProcessStimulus(int thingId, Vector3 inputValue, string thingName = null) { this.array.ProcessStimulus(thingId, inputValue, thingName); } diff --git a/Receptor.cs b/Receptor.cs index 71a1d0a..38c6181 100644 --- a/Receptor.cs +++ b/Receptor.cs @@ -1,159 +1,43 @@ -/* -using System; -using System.Collections.Generic; using UnityEngine; using Unity.Mathematics; using static Unity.Mathematics.math; -public class Receptor : IReceptor { +[System.Serializable] +public class Receptor : Neuron { + public Receptor(Cluster parent, string name) : base(parent, name) { } + public Receptor(ClusterPrefab prefab, string name) : base(prefab, name) { } - [SerializeField] - protected string _name; - public virtual string name { - get => _name; - set => _name = value; - } - - public Receptor(Cluster parent) { - this.parent = parent; - parent?.nuclei.Add(this); - } - - public Receptor(Cluster parent, string name, string nucleusName) { - this.parent = parent ?? throw new ArgumentNullException(nameof(parent), "Parent cannot be null."); - - this.name = name; - this.parent.nuclei.Add(this); - foreach (INucleus nucleus in parent.inputs) { - if (nucleus != null && nucleus.name == nucleusName) { - this.AddReceiver(nucleus); - } - } - } - - private readonly Cluster parent; - - public virtual IReceptor ShallowCloneTo(Cluster parent) { - Receptor clone = new(parent); + public override Nucleus ShallowCloneTo(Cluster parent) { + Receptor clone = new(parent, name); return clone; } - - public virtual IReceptor Clone() { - Receptor clone = new(this.parent); - - foreach (INucleus receiver in this.receivers) { + public override Nucleus Clone(ClusterPrefab prefab) { + Receptor clone = new(prefab, name); + CloneFields(clone); + // Adding receivers will also add synapses to the receivers + foreach (Nucleus receiver in this.receivers) clone.AddReceiver(receiver); - } - return clone; } - class Receiver { - public INucleus nucleus; - public int thingId; - public string thingName; - public Receiver(INucleus nucleus, int thingId, string thingName) { - this.nucleus = nucleus; - this.thingId = thingId; - this.thingName = thingName; - } + // [SerializeReference] + // private NucleusArray _array; + // public NucleusArray array { + // get { return _array; } + // set { _array = value; } + // } + + + public override void UpdateStateIsolated() { + this.outputValue = this.bias; } - [SerializeReference] - private List _receivers = new(); - public List receivers { - get { return _receivers; } - set { _receivers = value; } - } - - protected int[] thingIds; // every receiver can handle a thing with this id - - public virtual void AddReceiver(INucleus receivingNucleus, float weight = 1) { - this._receivers.Add(receivingNucleus); - receivingNucleus.AddSynapse(this, weight); - } - - public void RemoveReceiver(INucleus receiverNucleus) { - this._receivers.RemoveAll(receiver => receiver == receiverNucleus); - receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); - } - - private int stale = 1000; - - private bool _isSleeping = false; - public bool isSleeping => _isSleeping; - - private float3 _outputValue; - public float3 outputValue { - get { return this._outputValue; } - set { - this.stale = 0; - this._isSleeping = false; - this._outputValue = value; - } - } - - public virtual void ProcessStimulus(int thingId, Vector3 newLocalPositionVector, string thingName = null) { - this.outputValue = newLocalPositionVector; - if (this._receivers == null) - return; - - thingIds ??= new int[this._receivers.Count]; - - int receiverIx = 0; - INucleus selectedReceiver = null; - int selectedReceiverIx = 0; - foreach (INucleus receiver in this.receivers) { - if (thingIds[receiverIx] == thingId) { - // We found an existing receiver for this thing - selectedReceiver = receiver; - selectedReceiverIx = receiverIx; - // Do not look any further - break; - } - else if (receiver.isSleeping) { - // A sleeping receiver is not active and can therefore always be used - selectedReceiver = receiver; - selectedReceiverIx = receiverIx; - // Look further because we may find an existing receiver for this thing - } - else if (selectedReceiver == null) { - // If we haven't found a receiver yet, just start by taking the first - selectedReceiver = receiver; - selectedReceiverIx = receiverIx; - } - else if (selectedReceiver.isSleeping == false) { - // If no existing or sleeping receiver is found, we look for - // the receiver with the furthest/least interesting stimulus - if (length(receiver.outputValue) < length(selectedReceiver.outputValue)) { - // Debug.Log($"{selectedReceiver.name}[{selectedReceiverIx}] {length(selectedReceiver.outputValue)}" + - // $" {receiver.name}[{receiverIx}] {length(receiver.outputValue)} "); - selectedReceiver = receiver; - selectedReceiverIx = receiverIx; - } - } - receiverIx++; - } - if (selectedReceiverIx >= thingIds.Length) - return; - - thingIds[selectedReceiverIx] = thingId; - if (thingName != null) { - string baseName = selectedReceiver.name; - int colonPos = selectedReceiver.name.IndexOf(":"); - if (colonPos > 0) - baseName = selectedReceiver.name.Substring(0, colonPos); - selectedReceiver.name = baseName + ": " + thingName; - } - Debug.Log($"Receiver {selectedReceiver.name}[{selectedReceiverIx}] for thing {thingId}"); - selectedReceiver.parent.UpdateStateIsolated(); - } - - public void UpdateNuclei() { + public override void UpdateNuclei() { this.stale++; - this._isSleeping = this.stale > 2; - if (isSleeping) - this._outputValue = Vector3.zero; + if (this.stale > staleValueForSleep && lengthsq(this.bias) > 0) { + this.bias = new float3(0, 0, 0); + this.parent.UpdateFromNucleus(this); + } } -} -*/ \ No newline at end of file + +} \ No newline at end of file diff --git a/ReceptorArray.cs b/ReceptorArray.cs index c9e6702..baf2dc2 100644 --- a/ReceptorArray.cs +++ b/ReceptorArray.cs @@ -31,15 +31,15 @@ public class ReceptorInstance : Nucleus { } [SerializeReference] - public Receptor receptor; + public ReceptorArray receptor; public override void UpdateStateIsolated() { } } [Serializable] -public class Receptor : Nucleus { - public Receptor(Cluster parent, string name) { +public class ReceptorArray : Nucleus { + public ReceptorArray(Cluster parent, string name) { this.parent = parent; this.name = name; this._instances = new ReceptorInstance[1]; @@ -48,7 +48,7 @@ public class Receptor : Nucleus { }; this.parent?.nuclei.Add(this); } - public Receptor(ClusterPrefab prefab, string name) { + public ReceptorArray(ClusterPrefab prefab, string name) { this.cluster = prefab; this.name = name; this._instances = new ReceptorInstance[1]; @@ -63,7 +63,7 @@ public class Receptor : Nucleus { } public override Nucleus ShallowCloneTo(Cluster parent) { - Receptor clone = new(parent, name) { + ReceptorArray clone = new(parent, name) { _instances = new ReceptorInstance[this.instances.Length] }; for (int ix = 0; ix < this.instances.Length; ix++) { @@ -76,7 +76,7 @@ public class Receptor : Nucleus { } public override Nucleus Clone(ClusterPrefab prefab) { - Receptor clone = new(prefab, this.name) { + ReceptorArray clone = new(prefab, this.name) { _instances = new ReceptorInstance[this.instances.Length] }; for (int ix = 0; ix < this.instances.Length; ix++) { @@ -96,7 +96,7 @@ public class Receptor : Nucleus { } [SerializeReference] - private ReceptorInstance[] _instances; + private ReceptorInstance[] _instances = new ReceptorInstance[0]; public ReceptorInstance[] instances { get { return _instances; @@ -141,7 +141,7 @@ public class Receptor : Nucleus { public override void ProcessStimulus(int thingId, Vector3 inputValue, string thingName = null) { ProcessStimulus(inputValue, thingId, thingName); } - public void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) { + public override void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) { CleanupReceivers(); if (!thingReceivers.TryGetValue(thingId, out Nucleus selectedReceiver)) { //Debug.Log($" no receiver found for {thingId}"); @@ -194,6 +194,7 @@ public class Receptor : Nucleus { float inputMagnitude = length(inputValue); Nucleus selectedReceiver = null; float selectedMagnitude = 0; + this._instances ??= new ReceptorInstance[0]; foreach (Nucleus receiver in this._instances) { if (thingReceivers.ContainsValue(receiver) == false) { // We found an unusued receiver From f8aaa4ca809a39cd096fde8b324cec22279b3a27 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Fri, 13 Feb 2026 15:12:45 +0100 Subject: [PATCH 145/179] NucleusArray to Receptor --- Cluster.cs | 8 +-- Editor/ClusterInspector.cs | 71 ++++++++++++++++----------- Neuron.cs | 14 +++--- Nucleus.cs | 48 ++++++++++-------- Receptor.cs | 18 ++++--- ReceptorArray.cs | 6 +-- Scripts/Experimental/SelectorBrain.cs | 4 +- Selector.cs | 2 +- 8 files changed, 99 insertions(+), 72 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index 84ee436..521a75c 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -79,13 +79,13 @@ public class Cluster : Nucleus { // Copy nucleus arrays for (int nucleusIx = 0; nucleusIx < prefabNuclei.Length; nucleusIx++) { Nucleus prefabReceptor = prefabNuclei[nucleusIx]; - if (prefabReceptor is not Nucleus prefabNucleus) + if (prefabReceptor is not Receptor prefabNucleus) continue; if (prefabNucleus.array == null || prefabNucleus.array.nuclei == null || prefabNucleus.array.nuclei.Length == 0) continue; - Nucleus clonedNucleus = clonedNuclei[nucleusIx] as Nucleus; + Receptor clonedNucleus = clonedNuclei[nucleusIx] as Receptor; if (prefabNucleus == prefabNucleus.array.nuclei[0]) { // We clone the array only for the first entry NucleusArray clonedArray = new(prefabNucleus.array.nuclei.Length, "array"); @@ -106,7 +106,7 @@ public class Cluster : Nucleus { else { // The others will refer to the array created for the first nucleus in the array int firstNucleusIx = GetNucleusIndex(prefabNuclei, prefabNucleus.array.nuclei[0]); - Nucleus clonedFirstNucleus = clonedNuclei[firstNucleusIx] as Nucleus; + Receptor clonedFirstNucleus = clonedNuclei[firstNucleusIx] as Receptor; clonedNucleus.array = clonedFirstNucleus.array; } } @@ -153,7 +153,7 @@ public class Cluster : Nucleus { public override Nucleus Clone(ClusterPrefab prefab) { //Neuron clone = new(this.cluster, this.name) { Neuron clone = new(prefab, this.name) { - array = this.array, + // array = this.array, }; foreach (Synapse synapse in this.synapses) { diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 55efb1e..04fe3b5 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -295,30 +295,30 @@ public class ClusterInspector : Editor { row++; } } - else { + else if (this.currentNucleus is Receptor receptor1) { float maxValue = 0; - foreach (Nucleus nucleus in this.currentNucleus.array.nuclei) { + foreach (Nucleus nucleus in receptor1.array.nuclei) { float value = length(nucleus.outputValue); if (value > maxValue) maxValue = value; } - float spacing = 400f / this.currentNucleus.array.nuclei.Count(); + float spacing = 400f / receptor1.array.nuclei.Count(); float margin = 10 + spacing / 2; float xMin = 150 - size; float xMax = 150 + size; float yMin = 10 + margin - size / 2; float yMax = 400 - margin + size; Vector3[] verts = new Vector3[4] { - new(xMin, yMin, 0), - new(xMax, yMin, 0), - new(xMax, yMax, 0), - new(xMin, yMax, 0) - }; + new(xMin, yMin, 0), + new(xMax, yMin, 0), + new(xMax, yMax, 0), + new(xMin, yMax, 0) + }; Handles.color = Color.black; Handles.DrawAAConvexPolygon(verts); int row = 0; - foreach (Nucleus nucleus in this.currentNucleus.array.nuclei) { + foreach (Nucleus nucleus in receptor1.array.nuclei) { Vector3 pos = new(150, margin + row * spacing, 0.0f); Handles.color = Color.white; // The selected nucleus highlight ring @@ -357,9 +357,11 @@ public class ClusterInspector : Editor { int row = 0; List drawnArrays = new(); foreach (Nucleus receiver in nucleus.receivers) { - if (drawnArrays.Contains(receiver.array)) - continue; - drawnArrays.Add(receiver.array); + if (receiver is Receptor receptor) { + if (drawnArrays.Contains(receptor.array)) + continue; + drawnArrays.Add(receptor.array); + } Nucleus receiverNucleus = receiver; if (receiverNucleus == null) @@ -383,10 +385,10 @@ public class ClusterInspector : Editor { int neuronCount = 0; List drawnArrays = new(); foreach (Synapse synapse in nucleus.synapses) { - if (synapse.nucleus is Neuron neuroid) { - if (drawnArrays.Contains(neuroid.array)) + if (synapse.nucleus is Receptor receptor) { + if (drawnArrays.Contains(receptor.array)) continue; - drawnArrays.Add(neuroid.array); + drawnArrays.Add(receptor.array); } float value = length(synapse.nucleus.outputValue) * synapse.weight; @@ -403,7 +405,7 @@ public class ClusterInspector : Editor { int row = 0; drawnArrays = new(); foreach (Synapse synapse in nucleus.synapses) { - if (synapse.nucleus is Neuron neuron) { + if (synapse.nucleus is Receptor neuron) { if (drawnArrays.Contains(neuron.array)) continue; drawnArrays.Add(neuron.array); @@ -461,11 +463,13 @@ public class ClusterInspector : Editor { fontStyle = FontStyle.Bold, }; - if (nucleus.array == null || nucleus.array.nuclei == null || nucleus.array.nuclei.Count() == 0) - nucleus.array = new NucleusArray(nucleus); + if (nucleus is Receptor receptor1) { + if (receptor1.array == null || receptor1.array.nuclei == null || receptor1.array.nuclei.Count() == 0) + receptor1.array = new NucleusArray(nucleus); - if ((!expandArray || nucleus.array.nuclei.First() != this.currentNucleus) && nucleus.array.nuclei.Count() > 1) { - Handles.Label(labelPosition, nucleus.array.nuclei.Count().ToString(), style); + if ((!expandArray || receptor1.array.nuclei.First() != this.currentNucleus) && receptor1.array.nuclei.Count() > 1) { + Handles.Label(labelPosition, receptor1.array.nuclei.Count().ToString(), style); + } } if (nucleus is ReceptorArray receptor) { Handles.Label(labelPosition, receptor.instances.Count().ToString(), style); @@ -481,9 +485,9 @@ public class ClusterInspector : Editor { // Handles.Label(labelPosition, $"[{arrayIx}]", style); // } // } - if (expandArray && nucleus.array.nuclei.First() == this.currentNucleus) { + if (expandArray && nucleus is Receptor receptor2 && receptor2.array.nuclei.First() == this.currentNucleus) { int arrayIx = 0; - foreach (Nucleus n in nucleus.array.nuclei) { + foreach (Nucleus n in receptor2.array.nuclei) { if (n == nucleus) break; arrayIx++; @@ -672,8 +676,8 @@ public class ClusterInspector : Editor { continue; } else { - if (synapse.nucleus.array != null && synapse.nucleus.array.nuclei.Length > 1) - array = synapse.nucleus.array; + if (synapse.nucleus is Receptor receptor2 && receptor2.array != null && receptor2.array.nuclei.Length > 1) + array = receptor2.array; } EditorGUILayout.Space(); @@ -721,8 +725,10 @@ public class ClusterInspector : Editor { neuron.curvePreset = newPreset; EditorGUILayout.EndHorizontal(); } - if (neuron.array == null || neuron.array.nuclei == null || neuron.array.nuclei.Count() == 0) - neuron.array = new NucleusArray(neuron); + if (neuron is Receptor receptor2) { + if (receptor2.array == null || receptor2.array.nuclei == null || receptor2.array.nuclei.Count() == 0) + receptor2.array = new NucleusArray(neuron); + } // if (this.currentNucleus is Receptor receptor1) { // EditorGUILayout.BeginHorizontal(); @@ -778,13 +784,20 @@ public class ClusterInspector : Editor { Handles.color = Color.yellow; Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); } - } else { - foreach (Nucleus nucleus in this.currentNucleus.array.nuclei) { - Vector3 worldVector = this.gameObject.transform.TransformVector(nucleus.outputValue); + if (this.currentNucleus is Receptor receptor1) { + foreach (Nucleus nucleus in receptor1.array.nuclei) { + Vector3 worldVector = this.gameObject.transform.TransformVector(nucleus.outputValue); + Handles.color = Color.yellow; + Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); + } + } + else { + Vector3 worldVector = this.gameObject.transform.TransformVector(this.currentNucleus.outputValue); Handles.color = Color.yellow; Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); + } } } diff --git a/Neuron.cs b/Neuron.cs index 7719547..e32a081 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -45,12 +45,12 @@ public class Neuron : Nucleus { public CurvePresets curvePreset { get { return _curvePreset; } set { - if (this.array != null && this.array.nuclei != null) { - foreach (Neuron nucleus in this.array.nuclei.Cast()) { - nucleus._curvePreset = value; - nucleus.curve = GenerateCurve(); - } - } + // if (this.array != null && this.array.nuclei != null) { + // foreach (Neuron nucleus in this.array.nuclei.Cast()) { + // nucleus._curvePreset = value; + // nucleus.curve = GenerateCurve(); + // } + // } _curvePreset = value; this.curve = GenerateCurve(); } @@ -145,7 +145,7 @@ public class Neuron : Nucleus { } protected virtual void CloneFields(Neuron clone) { - clone.array = this.array; + // clone.array = this.array; clone.bias = this.bias; clone.combinator = this.combinator; clone.curve = this.curve; diff --git a/Nucleus.cs b/Nucleus.cs index 2eead83..6ce9900 100644 --- a/Nucleus.cs +++ b/Nucleus.cs @@ -6,8 +6,8 @@ using static Unity.Mathematics.math; [Serializable] public abstract class Nucleus { - public string name; - + public string name; + //[Obsolete] public ClusterPrefab cluster { get; set; } public Cluster parent { get; set; } @@ -48,7 +48,7 @@ public abstract class Nucleus { #region Synapses public Vector3 bias = Vector3.zero; - + [SerializeField] private List _synapses = new(); public List synapses => _synapses; @@ -90,35 +90,43 @@ public abstract class Nucleus { #endregion Receivers - [SerializeReference] - private NucleusArray _array; - public NucleusArray array { - get { return _array; } - set { _array = value; } - } + // [SerializeReference] + // private NucleusArray _array; + // public NucleusArray array { + // get { return _array; } + // set { _array = value; } + // } #region Update public abstract void UpdateStateIsolated(); public virtual void UpdateNuclei() { - if (this.array == null || this.array.nuclei == null || this.array.nuclei.Length <= 1) - return; + // if (this.array == null || this.array.nuclei == null || this.array.nuclei.Length <= 1) + return; - this.stale++; - if (this.stale > staleValueForSleep) { - //Debug.Log($"{this.name} goes to sleep, stale = {this.stale}"); - _outputValue = Vector3.zero; - } + // this.stale++; + // if (this.stale > staleValueForSleep) { + // //Debug.Log($"{this.name} goes to sleep, stale = {this.stale}"); + // _outputValue = Vector3.zero; + // } } public virtual void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) { - this.array.ProcessStimulus(thingId, inputValue, thingName); + //this.array.ProcessStimulus(thingId, inputValue, thingName); + // this.ProcessStimulus(inputValue); + this.stale = 0; + this.bias = inputValue; + this.parent.UpdateFromNucleus(this); } - public virtual void ProcessStimulus(int thingId, Vector3 inputValue, string thingName = null) { - this.array.ProcessStimulus(thingId, inputValue, thingName); - } + // public virtual void ProcessStimulus(int thingId, Vector3 inputValue, string thingName = null) { + // // this.array.ProcessStimulus(thingId, inputValue, thingName); + // // this.ProcessStimulus(inputValue); + // this.stale = 0; + // this.bias = inputValue; + // this.parent.UpdateFromNucleus(this); + // } #endregion Update diff --git a/Receptor.cs b/Receptor.cs index 38c6181..bc92f57 100644 --- a/Receptor.cs +++ b/Receptor.cs @@ -9,23 +9,26 @@ public class Receptor : Neuron { public override Nucleus ShallowCloneTo(Cluster parent) { Receptor clone = new(parent, name); + CloneFields(clone); + clone.array = this.array; return clone; } public override Nucleus Clone(ClusterPrefab prefab) { Receptor clone = new(prefab, name); CloneFields(clone); + clone.array = this.array; // Adding receivers will also add synapses to the receivers foreach (Nucleus receiver in this.receivers) clone.AddReceiver(receiver); return clone; } - // [SerializeReference] - // private NucleusArray _array; - // public NucleusArray array { - // get { return _array; } - // set { _array = value; } - // } + [SerializeReference] + private NucleusArray _array; + public NucleusArray array { + get { return _array; } + set { _array = value; } + } public override void UpdateStateIsolated() { @@ -40,4 +43,7 @@ public class Receptor : Neuron { } } + public override void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) { + this.array.ProcessStimulus(thingId, inputValue, thingName); + } } \ No newline at end of file diff --git a/ReceptorArray.cs b/ReceptorArray.cs index baf2dc2..1c7edeb 100644 --- a/ReceptorArray.cs +++ b/ReceptorArray.cs @@ -138,9 +138,9 @@ public class ReceptorArray : Nucleus { private Dictionary thingReceivers = new(); - public override void ProcessStimulus(int thingId, Vector3 inputValue, string thingName = null) { - ProcessStimulus(inputValue, thingId, thingName); - } + // public override void ProcessStimulus(int thingId, Vector3 inputValue, string thingName = null) { + // ProcessStimulus(inputValue, thingId, thingName); + // } public override void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) { CleanupReceivers(); if (!thingReceivers.TryGetValue(thingId, out Nucleus selectedReceiver)) { diff --git a/Scripts/Experimental/SelectorBrain.cs b/Scripts/Experimental/SelectorBrain.cs index b5a6c79..282305a 100644 --- a/Scripts/Experimental/SelectorBrain.cs +++ b/Scripts/Experimental/SelectorBrain.cs @@ -14,8 +14,8 @@ public class SelectorBrain : NanoBrain { } protected void Update() { - receptor.ProcessStimulus(0, input1); - receptor.ProcessStimulus(1, input2); + receptor.ProcessStimulus(input1, 0); + receptor.ProcessStimulus(input2, 1); output = this.brain.outputValue; this.brain.UpdateNuclei(); diff --git a/Selector.cs b/Selector.cs index 6364053..320f807 100644 --- a/Selector.cs +++ b/Selector.cs @@ -9,7 +9,7 @@ public class Selector : Neuron { public override Nucleus ShallowCloneTo(Cluster newParent) { Selector clone = new(newParent, this.name) { - array = this.array, + // array = this.array, curve = this.curve, curvePreset = this.curvePreset, curveMax = this.curveMax, From 885d649be199bfbbb7a6066c375bb82fba3b6ac6 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Fri, 13 Feb 2026 15:42:22 +0100 Subject: [PATCH 146/179] Cleanup --- Cluster.cs | 16 ++++++++++++---- Neuron.cs | 8 -------- Nucleus.cs | 27 +-------------------------- NucleusArray.cs | 2 +- Receptor.cs | 6 +++--- ReceptorArray.cs | 2 +- Scripts/Experimental/SelectorBrain.cs | 4 ++-- 7 files changed, 20 insertions(+), 45 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index 521a75c..22c52db 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -339,10 +339,18 @@ public class Cluster : Nucleus { } public Nucleus GetNucleus(string nucleusName) { - foreach (Nucleus receptor in this.nuclei) { - if (receptor is Nucleus nucleus) - if (nucleus.name == nucleusName) - return nucleus; + foreach (Nucleus nucleus in this.nuclei) { + if (nucleus.name == nucleusName) + return nucleus; + } + return null; + } + + public Receptor GetReceptor(string receptorName) { + foreach (Nucleus nucleus in this.nuclei) { + if (nucleus is Receptor receptor) + if (receptor.name == receptorName) + return receptor; } return null; } diff --git a/Neuron.cs b/Neuron.cs index e32a081..315fc21 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -45,12 +45,6 @@ public class Neuron : Nucleus { public CurvePresets curvePreset { get { return _curvePreset; } set { - // if (this.array != null && this.array.nuclei != null) { - // foreach (Neuron nucleus in this.array.nuclei.Cast()) { - // nucleus._curvePreset = value; - // nucleus.curve = GenerateCurve(); - // } - // } _curvePreset = value; this.curve = GenerateCurve(); } @@ -196,7 +190,6 @@ public class Neuron : Nucleus { foreach (Synapse synapse in this.synapses) sum += synapse.weight * synapse.nucleus.outputValue; return sum; - //this.outputValue = Activation(sum); } public float3 CombinatorProduct() { @@ -204,7 +197,6 @@ public class Neuron : Nucleus { foreach (Synapse synapse in this.synapses) product *= synapse.weight * synapse.nucleus.outputValue; return product; - //this.outputValue = Activation(product); } public float3 CombinatorMax() { diff --git a/Nucleus.cs b/Nucleus.cs index 6ce9900..57ad5f4 100644 --- a/Nucleus.cs +++ b/Nucleus.cs @@ -90,44 +90,19 @@ public abstract class Nucleus { #endregion Receivers - // [SerializeReference] - // private NucleusArray _array; - // public NucleusArray array { - // get { return _array; } - // set { _array = value; } - // } - #region Update public abstract void UpdateStateIsolated(); public virtual void UpdateNuclei() { - // if (this.array == null || this.array.nuclei == null || this.array.nuclei.Length <= 1) - return; - - // this.stale++; - // if (this.stale > staleValueForSleep) { - // //Debug.Log($"{this.name} goes to sleep, stale = {this.stale}"); - // _outputValue = Vector3.zero; - // } } - public virtual void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) { - //this.array.ProcessStimulus(thingId, inputValue, thingName); - // this.ProcessStimulus(inputValue); + public virtual void SetBias(Vector3 inputValue) { this.stale = 0; this.bias = inputValue; this.parent.UpdateFromNucleus(this); } - // public virtual void ProcessStimulus(int thingId, Vector3 inputValue, string thingName = null) { - // // this.array.ProcessStimulus(thingId, inputValue, thingName); - // // this.ProcessStimulus(inputValue); - // this.stale = 0; - // this.bias = inputValue; - // this.parent.UpdateFromNucleus(this); - // } - #endregion Update } \ No newline at end of file diff --git a/NucleusArray.cs b/NucleusArray.cs index 5ff9876..48595b5 100644 --- a/NucleusArray.cs +++ b/NucleusArray.cs @@ -130,7 +130,7 @@ public class NucleusArray { // Remove a thing-receiver connection when the nucleus is inactive List receiversToRemove = new(); foreach (KeyValuePair item in thingReceivers) { - if (item.Value.isSleeping) + if (item.Value != null && item.Value.isSleeping) receiversToRemove.Add(item.Key); } foreach (int thingId in receiversToRemove) { diff --git a/Receptor.cs b/Receptor.cs index bc92f57..34c511c 100644 --- a/Receptor.cs +++ b/Receptor.cs @@ -30,7 +30,6 @@ public class Receptor : Neuron { set { _array = value; } } - public override void UpdateStateIsolated() { this.outputValue = this.bias; } @@ -43,7 +42,8 @@ public class Receptor : Neuron { } } - public override void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) { - this.array.ProcessStimulus(thingId, inputValue, thingName); + public virtual void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) { + this.array ??= new NucleusArray(this.parent); + this.array.ProcessStimulus(thingId, inputValue, thingName); } } \ No newline at end of file diff --git a/ReceptorArray.cs b/ReceptorArray.cs index 1c7edeb..3ac96aa 100644 --- a/ReceptorArray.cs +++ b/ReceptorArray.cs @@ -141,7 +141,7 @@ public class ReceptorArray : Nucleus { // public override void ProcessStimulus(int thingId, Vector3 inputValue, string thingName = null) { // ProcessStimulus(inputValue, thingId, thingName); // } - public override void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) { + public virtual void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) { CleanupReceivers(); if (!thingReceivers.TryGetValue(thingId, out Nucleus selectedReceiver)) { //Debug.Log($" no receiver found for {thingId}"); diff --git a/Scripts/Experimental/SelectorBrain.cs b/Scripts/Experimental/SelectorBrain.cs index 282305a..08b21f6 100644 --- a/Scripts/Experimental/SelectorBrain.cs +++ b/Scripts/Experimental/SelectorBrain.cs @@ -5,11 +5,11 @@ public class SelectorBrain : NanoBrain { public Vector3 input2; public Vector3 output; - public Nucleus receptor; + public Receptor receptor; //public Nucleus receptor2; protected void Awake() { - receptor = this.brain.GetNucleus("Selector"); + receptor = this.brain.GetReceptor("Selector"); //receptor2 = this.brain.GetNucleus("Selector"); } From 9cbf0aaa2c7325059aaaf44f41c7039b154265da Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Fri, 13 Feb 2026 17:25:48 +0100 Subject: [PATCH 147/179] Fix labels --- Editor/ClusterInspector.cs | 108 +++++++++++++------------------------ NucleusArray.cs | 4 +- 2 files changed, 41 insertions(+), 71 deletions(-) diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 04fe3b5..e4813da 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -326,6 +326,19 @@ public class ClusterInspector : Editor { DrawNucleus(nucleus, pos, maxValue, size); row++; } + GUIStyle style = new(EditorStyles.label) { + alignment = TextAnchor.UpperCenter, + normal = { textColor = Color.white }, + fontStyle = FontStyle.Bold, + }; + Vector3 labelPos = new(150, yMax + size + 5, 0); + int colonPos = receptor1.name.IndexOf(":"); + if (colonPos > 0) { + string baseName = receptor1.name[..colonPos]; + Handles.Label(labelPos, baseName, style); + } + else + Handles.Label(labelPos, receptor1.name, style); } } else { @@ -415,9 +428,6 @@ public class ClusterInspector : Editor { Handles.DrawLine(parentPos, pos); if (synapse.nucleus != null) { Color color = Color.black; - // if (synapse.nucleus.isSleeping) - // color = Color.darkRed; - // else if (Application.isPlaying) { float brightness = length(synapse.nucleus.outputValue) * synapse.weight / maxValue; color = new Color(brightness, brightness, brightness, 1f); @@ -430,17 +440,12 @@ public class ClusterInspector : Editor { private void DrawNucleus(Nucleus nucleus, Vector3 position, float maxValue, float size) { Color color; - // if (nucleus.isSleeping) - // color = Color.darkRed; - // else - { - if (Application.isPlaying) { - float brightness = length(nucleus.outputValue) / maxValue; - color = new Color(brightness, brightness, brightness, 1f); - } - else - color = Color.black; + if (Application.isPlaying) { + float brightness = length(nucleus.outputValue) / maxValue; + color = new Color(brightness, brightness, brightness, 1f); } + else + color = Color.black; DrawNucleus(nucleus, position, maxValue, size, color); } @@ -468,37 +473,35 @@ public class ClusterInspector : Editor { receptor1.array = new NucleusArray(nucleus); if ((!expandArray || receptor1.array.nuclei.First() != this.currentNucleus) && receptor1.array.nuclei.Count() > 1) { - Handles.Label(labelPosition, receptor1.array.nuclei.Count().ToString(), style); + if (color.grayscale > 0.5f) + style.normal.textColor = Color.black; + else + style.normal.textColor = Color.white; + Handles.Label(labelPosition, receptor1.array.nuclei.Length.ToString(), style); + style.normal.textColor = Color.white; } } - if (nucleus is ReceptorArray receptor) { - Handles.Label(labelPosition, receptor.instances.Count().ToString(), style); - } - // else if (nucleus is ReceptorInstance receptorI) { - // if (expandArray) { - // int arrayIx = 0; - // foreach (ReceptorInstance n in receptorI.receptorArray.receptors) { - // if (n == receptorI) - // break; - // arrayIx++; - // } - // Handles.Label(labelPosition, $"[{arrayIx}]", style); - // } + // if (nucleus is ReceptorArray receptor) { + // if (color.grayscale > 0.5f) + // style.normal.textColor = Color.black; + // else + // style.normal.textColor = Color.white; + // Handles.Label(labelPosition, receptor.instances.Count().ToString(), style); // } if (expandArray && nucleus is Receptor receptor2 && receptor2.array.nuclei.First() == this.currentNucleus) { - int arrayIx = 0; - foreach (Nucleus n in receptor2.array.nuclei) { - if (n == nucleus) - break; - arrayIx++; + style.alignment = TextAnchor.LowerCenter; + Vector3 labelPos = position + Vector3.down * (size + 5); // below disc along up axis + int colonPos = nucleus.name.IndexOf(":"); + if (colonPos > 0) { + string extName = nucleus.name[(colonPos + 2)..]; + Handles.Label(labelPos, extName, style); } - Handles.Label(labelPosition, $"[{arrayIx}]", style); } else { style.alignment = TextAnchor.UpperCenter; - Vector3 labelPos = position - Vector3.down * (size + 10f); // below disc along up axis + Vector3 labelPos = position - Vector3.down * (size + 5); // below disc along up axis int colonPos = nucleus.name.IndexOf(":"); - if (colonPos > 0) { + if (colonPos > 0 && colonPos < nucleus.name.Length - 2) { string baseName = nucleus.name[..colonPos]; Handles.Label(labelPos, baseName, style); } @@ -602,7 +605,6 @@ public class ClusterInspector : Editor { this.currentNucleus.name = newName; this.prefab.RefreshOutputs(); outputsField.choices = this.prefab.outputs.Select(output => output.name).ToList(); - //outputsField.value = newName; } if (Application.isPlaying) { @@ -729,22 +731,6 @@ public class ClusterInspector : Editor { if (receptor2.array == null || receptor2.array.nuclei == null || receptor2.array.nuclei.Count() == 0) receptor2.array = new NucleusArray(neuron); } - - // if (this.currentNucleus is Receptor receptor1) { - // EditorGUILayout.BeginHorizontal(); - // EditorGUILayout.IntField("Array size", receptor1.array.nuclei.Count()); - // if (GUILayout.Button("Add")) { - // Undo.RecordObject(prefabAsset, "Array add " + prefabAsset.name); - // receptor1.array.AddNucleus(this.prefab); - // anythingChanged = true; - // } - // if (GUILayout.Button("Del")) { - // Undo.RecordObject(prefabAsset, "Array delete " + prefabAsset.name); - // receptor1.array.RemoveNucleus(); - // anythingChanged = true; - // } - // EditorGUILayout.EndHorizontal(); - // } } EditorGUILayout.Space(); @@ -831,25 +817,7 @@ public class ClusterInspector : Editor { } } - // protected virtual void AddInput(int selectedInputType, Nucleus nucleus) { - // switch (selectedInputType) { - // case 0: // Neuron - // AddNeuronInput(nucleus); - // break; - // case 1: // MemoryCell - // AddMemoryCellInput(nucleus); - // break; - // case 2: // Selector - // AddSelectorInput(nucleus); - // break; - // case 3: // Cluster - // AddClusterInput(nucleus); - // break; - // } - // } - protected virtual void AddNeuronInput(Nucleus nucleus) { - //Neuron newNeuroid = new(this.cluster, "New neuron"); Neuron newNeuroid = new(this.prefab, "New neuron"); newNeuroid.AddReceiver(nucleus); this.currentNucleus = newNeuroid; diff --git a/NucleusArray.cs b/NucleusArray.cs index 48595b5..118f174 100644 --- a/NucleusArray.cs +++ b/NucleusArray.cs @@ -36,8 +36,10 @@ public class NucleusArray { for (int i = 0; i < this._nuclei.Length; i++) newArray[i] = this._nuclei[i]; - if (this._nuclei[0] is Nucleus nucleus) + if (this._nuclei[0] is Nucleus nucleus) { newArray[newLength - 1] = nucleus.Clone(prefab); + newArray[newLength - 1].name += $"{newLength - 1}"; + } this._nuclei = newArray; } From 5fea9880de83aa50c9f721dad413cf4e250872a8 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 16 Feb 2026 12:30:07 +0100 Subject: [PATCH 148/179] Added ClusterReceptor --- ClusterReceptor.cs | 68 ++++++++++++++++++++++++++++++++++++++ ClusterReceptor.cs.meta | 2 ++ Editor/ClusterInspector.cs | 54 ++++++++++++++++++++++++++++++ Nucleus.cs | 3 +- 4 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 ClusterReceptor.cs create mode 100644 ClusterReceptor.cs.meta diff --git a/ClusterReceptor.cs b/ClusterReceptor.cs new file mode 100644 index 0000000..38ecb0d --- /dev/null +++ b/ClusterReceptor.cs @@ -0,0 +1,68 @@ +using System; +using UnityEngine; +using Unity.Mathematics; +using static Unity.Mathematics.math; + + +[Serializable] +public class ClusterReceptor : Cluster { + public ClusterReceptor(ClusterPrefab prefab, Cluster parent, string name) : base(prefab, parent) { + this.name = name; + this.array ??= new NucleusArray(this); + } + public ClusterReceptor(ClusterPrefab prefab, ClusterPrefab parent, string name) : base(prefab, parent) { + this.name = name; + this.array = new NucleusArray(this); + } + + public override Nucleus ShallowCloneTo(Cluster parent) { + ClusterReceptor clone = new(this.prefab, parent, this.name) { + array = this.array + }; + return clone; + } + + public override Nucleus Clone(ClusterPrefab prefab) { + ClusterReceptor clone = new(prefab, parent, this.name); + clone.array = this.array; + + foreach (Synapse synapse in this.synapses) { + Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); + clonedSynapse.weight = synapse.weight; + } + foreach (Nucleus receiver in this.receivers) { + clone.AddReceiver(receiver); + } + return clone; + } + + public NucleusArray array { get; set; } + + public override void UpdateStateIsolated() { + float3 sum = this.bias; + + foreach (Nucleus nucleus in this.sortedNuclei) + nucleus.UpdateStateIsolated(); + + this.outputValue = this.output.outputValue; + this.stale = 0; + + UpdateNuclei(); + } + + public override void UpdateNuclei() { + this.stale++; + if (this.stale > staleValueForSleep && lengthsq(this.bias) > 0) { + this.bias = new float3(0, 0, 0); + this.parent.UpdateFromNucleus(this); + } + + foreach (Nucleus nucleus in this.nuclei) + nucleus.UpdateNuclei(); + } + + public virtual void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) { + this.array ??= new NucleusArray(this.parent); + this.array.ProcessStimulus(thingId, inputValue, thingName); + } +} \ No newline at end of file diff --git a/ClusterReceptor.cs.meta b/ClusterReceptor.cs.meta new file mode 100644 index 0000000..027f164 --- /dev/null +++ b/ClusterReceptor.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 4f64f5d72a422a7c8bb9ace598432aad \ No newline at end of file diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index e4813da..b8b8e30 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -340,6 +340,13 @@ public class ClusterInspector : Editor { else Handles.Label(labelPos, receptor1.name, style); } + else { + Handles.color = Color.white; + // The selected nucleus highlight ring + Handles.DrawSolidDisc(position, Vector3.forward, size + 2); + DrawNucleus(this.currentNucleus, position, length(this.currentNucleus.outputValue), 20); + + } } else { Handles.color = Color.white; @@ -488,6 +495,26 @@ public class ClusterInspector : Editor { // style.normal.textColor = Color.white; // Handles.Label(labelPosition, receptor.instances.Count().ToString(), style); // } + if (nucleus is ClusterReceptor clusterReceptor) { + if (expandArray && clusterReceptor.array.nuclei.First() == this.currentNucleus) { + style.alignment = TextAnchor.LowerCenter; + Vector3 labelPos = position + Vector3.down * (size + 5); // below disc along up axis + int colonPos = nucleus.name.IndexOf(":"); + if (colonPos > 0) { + string extName = nucleus.name[(colonPos + 2)..]; + Handles.Label(labelPos, extName, style); + } + } + else { + if (color.grayscale > 0.5f) + style.normal.textColor = Color.black; + else + style.normal.textColor = Color.white; + Handles.Label(labelPosition, clusterReceptor.array.nuclei.Length.ToString(), style); + style.normal.textColor = Color.white; + } + } + if (expandArray && nucleus is Receptor receptor2 && receptor2.array.nuclei.First() == this.currentNucleus) { style.alignment = TextAnchor.LowerCenter; Vector3 labelPos = position + Vector3.down * (size + 5); // below disc along up axis @@ -647,6 +674,21 @@ public class ClusterInspector : Editor { } EditorGUILayout.EndHorizontal(); } + else if (this.currentNucleus is ClusterReceptor receptor2) { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.IntField("Array size", receptor2.array.nuclei.Count()); + if (GUILayout.Button("Add")) { + Undo.RecordObject(prefabAsset, "Array add " + prefabAsset.name); + receptor2.array.AddNucleus(this.prefab); + anythingChanged = true; + } + if (GUILayout.Button("Del")) { + Undo.RecordObject(prefabAsset, "Array delete " + prefabAsset.name); + receptor2.array.RemoveNucleus(); + anythingChanged = true; + } + EditorGUILayout.EndHorizontal(); + } // Synapses @@ -812,6 +854,9 @@ public class ClusterInspector : Editor { case Nucleus.Type.ReceptorArray: AddReceptorArrayInput(nucleus); break; + case Nucleus.Type.ClusterReceptor: + AddClusterReceptorInput(nucleus); + break; default: break; } @@ -887,6 +932,10 @@ public class ClusterInspector : Editor { BuildLayers(); } + protected virtual void AddClusterReceptorInput(Nucleus nucleus) { + ClusterPickerWindow.ShowPicker(brain => OnClusterReceptorPicked(nucleus, brain), "Select Cluster"); + } + private void OnClusterPicked(Nucleus nucleus, ClusterPrefab prefab) { Cluster subclusterInstance = new(prefab, this.prefab); subclusterInstance.AddReceiver(nucleus); @@ -895,6 +944,11 @@ public class ClusterInspector : Editor { // BuildLayers(); } + private void OnClusterReceptorPicked(Nucleus nucleus, ClusterPrefab prefab) { + ClusterReceptor clusterInstance = new(prefab, this.prefab, "New " + prefab.name); + clusterInstance.AddReceiver(nucleus); + } + private void EditCluster(Cluster subCluster) { // May be used with storedPrefab... Selection.activeObject = subCluster.prefab; diff --git a/Nucleus.cs b/Nucleus.cs index 57ad5f4..1a014b3 100644 --- a/Nucleus.cs +++ b/Nucleus.cs @@ -42,7 +42,8 @@ public abstract class Nucleus { Cluster, Pulsar, Receptor, - ReceptorArray + ReceptorArray, + ClusterReceptor, } #region Synapses From a394f582cf770e51c13e8d9dc50ed33ea3ae0760 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 16 Feb 2026 17:23:52 +0100 Subject: [PATCH 149/179] Improved clusterreceptor --- Cluster.cs | 16 +-- ClusterReceptor.cs | 40 +++++-- Editor/ClusterInspector.cs | 212 ++++++++++++++++++++++--------------- Neuron.cs | 14 +-- Nucleus.cs | 9 +- ReceptorArray.cs | 8 +- 6 files changed, 179 insertions(+), 120 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index 22c52db..84ff4b2 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -20,23 +20,19 @@ public class Cluster : Nucleus { ClonePrefab(); _ = this.inputs; this.sortedNuclei = TopologicalSort(this.nuclei); - // Does not work because we have nuclei with the same names in an nucleusArray - // 'Pheromone steering' - //this.nucleiDict = nuclei.ToDictionary(nucleus => nucleus.name); } public Cluster(ClusterPrefab prefab, ClusterPrefab parent = null) { this.prefab = prefab; this.name = prefab.name; - this.cluster = parent; + this.clusterPrefab = parent; - if (this.cluster != null) - this.cluster.nuclei.Add(this); + if (this.clusterPrefab != null) + this.clusterPrefab.nuclei.Add(this); ClonePrefab(); _ = this.inputs; this.sortedNuclei = TopologicalSort(this.nuclei); - //this.nucleiDict = nuclei.ToDictionary(nucleus => nucleus.name); } private void ClonePrefab() { @@ -151,10 +147,7 @@ public class Cluster : Nucleus { } public override Nucleus Clone(ClusterPrefab prefab) { - //Neuron clone = new(this.cluster, this.name) { - Neuron clone = new(prefab, this.name) { - // array = this.array, - }; + Neuron clone = new(prefab, this.name); foreach (Synapse synapse in this.synapses) { Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); @@ -169,6 +162,7 @@ public class Cluster : Nucleus { public override Nucleus ShallowCloneTo(Cluster parent) { Cluster clone = new(this.prefab, parent) { name = this.name, + clusterPrefab = this.clusterPrefab, }; return clone; } diff --git a/ClusterReceptor.cs b/ClusterReceptor.cs index 38ecb0d..d6aca1b 100644 --- a/ClusterReceptor.cs +++ b/ClusterReceptor.cs @@ -1,30 +1,32 @@ using System; +using System.Collections.Generic; using UnityEngine; using Unity.Mathematics; using static Unity.Mathematics.math; - [Serializable] public class ClusterReceptor : Cluster { public ClusterReceptor(ClusterPrefab prefab, Cluster parent, string name) : base(prefab, parent) { this.name = name; this.array ??= new NucleusArray(this); } - public ClusterReceptor(ClusterPrefab prefab, ClusterPrefab parent, string name) : base(prefab, parent) { + public ClusterReceptor(ClusterPrefab prefabToInstantiate, ClusterPrefab parent, string name) : base(prefabToInstantiate, parent) { this.name = name; this.array = new NucleusArray(this); } public override Nucleus ShallowCloneTo(Cluster parent) { ClusterReceptor clone = new(this.prefab, parent, this.name) { + clusterPrefab = this.clusterPrefab, array = this.array }; return clone; } - public override Nucleus Clone(ClusterPrefab prefab) { - ClusterReceptor clone = new(prefab, parent, this.name); - clone.array = this.array; + public override Nucleus Clone(ClusterPrefab parent) { + ClusterReceptor clone = new(prefab, parent, this.name) { + array = this.array + }; foreach (Synapse synapse in this.synapses) { Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); @@ -36,7 +38,33 @@ public class ClusterReceptor : Cluster { return clone; } - public NucleusArray array { get; set; } + [SerializeReference] + private NucleusArray _array; + public NucleusArray array { + get { return _array; } + set { _array = value; } + } + + #region Receivers + + private List _clusterReceivers = null; + public override List receivers { + get { + if (_clusterReceivers == null || _clusterReceivers.Count == 0) { + _clusterReceivers = new(); + foreach (Nucleus output in this.nuclei) { + _clusterReceivers.AddRange(output.receivers); + } + } + return _clusterReceivers; + } + } + public override void AddReceiver(Nucleus receivingNucleus, float weight = 1) { + this.output.receivers.Add(receivingNucleus); + receivingNucleus.AddSynapse(this.output, weight); + } + + #endregion Receivers public override void UpdateStateIsolated() { float3 sum = this.bias; diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index b8b8e30..bafeee7 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -409,7 +409,10 @@ public class ClusterInspector : Editor { if (drawnArrays.Contains(receptor.array)) continue; drawnArrays.Add(receptor.array); - + } else if (synapse.nucleus.parent is ClusterReceptor clusterReceptor) { + if (drawnArrays.Contains(clusterReceptor.array)) + continue; + drawnArrays.Add(clusterReceptor.array); } float value = length(synapse.nucleus.outputValue) * synapse.weight; // Debug.Log($"{synapse.nucleus.name}: {value} {length(synapse.nucleus.outputValue)} {synapse.weight}"); @@ -429,16 +432,27 @@ public class ClusterInspector : Editor { if (drawnArrays.Contains(neuron.array)) continue; drawnArrays.Add(neuron.array); + } else if (synapse.nucleus.parent is ClusterReceptor clusterReceptor) { + if (drawnArrays.Contains(clusterReceptor.array)) + continue; + drawnArrays.Add(clusterReceptor.array); } Vector3 pos = new(250, margin + row * spacing, 0.0f); Handles.color = Color.white; Handles.DrawLine(parentPos, pos); - if (synapse.nucleus != null) { - Color color = Color.black; - if (Application.isPlaying) { - float brightness = length(synapse.nucleus.outputValue) * synapse.weight / maxValue; - color = new Color(brightness, brightness, brightness, 1f); - } + Color color = Color.black; + if (Application.isPlaying) { + float brightness = length(synapse.nucleus.outputValue) * synapse.weight / maxValue; + color = new Color(brightness, brightness, brightness, 1f); + } + if (synapse.nucleus.parent != null && synapse.nucleus.parent != this.currentNucleus) { + // the synapse nucleus is part of a subcluster + DrawNucleus(synapse.nucleus.parent, pos, maxValue, size, color); + } + // else if (synapse.nucleus.cluster != null && synapse.nucleus.cluster != this.currentNucleus.cluster) { + // DrawNucleus(synapse.nucleus.parent, pos, maxValue, size, color); + // } + else { DrawNucleus(synapse.nucleus, pos, maxValue, size, color); } row++; @@ -495,6 +509,7 @@ public class ClusterInspector : Editor { // style.normal.textColor = Color.white; // Handles.Label(labelPosition, receptor.instances.Count().ToString(), style); // } + if (nucleus is ClusterReceptor clusterReceptor) { if (expandArray && clusterReceptor.array.nuclei.First() == this.currentNucleus) { style.alignment = TextAnchor.LowerCenter; @@ -575,7 +590,8 @@ public class ClusterInspector : Editor { private void HandleClicked(Nucleus nucleus) { if (nucleus == this.currentNucleus) { - expandArray = !expandArray; + if (nucleus is Receptor || nucleus is ClusterReceptor) + expandArray = !expandArray; } else if (nucleus is ReceptorInstance receptor) { expandArray = false; @@ -693,64 +709,78 @@ public class ClusterInspector : Editor { // Synapses - showSynapses = EditorGUILayout.BeginFoldoutHeaderGroup(showSynapses, "Synapses"); - if (showSynapses) { + if (this.currentNucleus is not Receptor && this.currentNucleus is not ClusterReceptor) { + showSynapses = EditorGUILayout.BeginFoldoutHeaderGroup(showSynapses, "Synapses"); + if (showSynapses) { - anythingChanged = ConnectNucleus(this.prefab, this.currentNucleus); - anythingChanged = AddSynapse(this.prefab, this.currentNucleus); - EditorGUILayout.Space(); + anythingChanged = ConnectNucleus(this.prefab, this.currentNucleus); + anythingChanged = AddSynapse(this.prefab, this.currentNucleus); + EditorGUILayout.Space(); - if (this.currentNucleus is Neuron neuron2) { - Neuron.CombinatorType newCombinator = (Neuron.CombinatorType)EditorGUILayout.EnumPopup("Combinator", neuron2.combinator); - anythingChanged |= newCombinator != neuron2.combinator; - neuron2.combinator = newCombinator; - } + if (this.currentNucleus is Neuron neuron2) { + Neuron.CombinatorType newCombinator = (Neuron.CombinatorType)EditorGUILayout.EnumPopup("Combinator", neuron2.combinator); + anythingChanged |= newCombinator != neuron2.combinator; + neuron2.combinator = newCombinator; + } - Vector3 newBias = EditorGUILayout.Vector3Field("Bias", this.currentNucleus.bias); - anythingChanged |= newBias != this.currentNucleus.bias; - this.currentNucleus.bias = newBias; + Vector3 newBias = EditorGUILayout.Vector3Field("Bias", this.currentNucleus.bias); + anythingChanged |= newBias != this.currentNucleus.bias; + this.currentNucleus.bias = newBias; - NucleusArray array = null; - if (this.currentNucleus.synapses.Count > 0) { - Synapse[] synapses = this.currentNucleus.synapses.ToArray(); - foreach (Synapse synapse in synapses) { - if (synapse.nucleus != null) { - if (array != null) { - if (array.nuclei.Contains(synapse.nucleus)) - continue; - } - else { - if (synapse.nucleus is Receptor receptor2 && receptor2.array != null && receptor2.array.nuclei.Length > 1) - array = receptor2.array; - } - - EditorGUILayout.Space(); - - if (Application.isPlaying) { - Vector3 value = synapse.nucleus.outputValue * synapse.weight; - GUIContent synapseValueLabel = new(synapse.nucleus.name, synapse.nucleus.outputValue.ToString()); - EditorGUILayout.FloatField(synapseValueLabel, length(synapse.nucleus.outputValue)); - } - else { - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.LabelField(synapse.nucleus.name); - if (GUILayout.Button("Disconnect")) { - synapse.nucleus.RemoveReceiver(this.currentNucleus); - this.prefab.GarbageCollection(); - anythingChanged = true; + NucleusArray array = null; + if (this.currentNucleus.synapses.Count > 0) { + Synapse[] synapses = this.currentNucleus.synapses.ToArray(); + foreach (Synapse synapse in synapses) { + if (synapse.nucleus != null) { + if (array != null) { + if (array.nuclei.Contains(synapse.nucleus)) + continue; + } + else { + if (synapse.nucleus is Receptor receptor2 && receptor2.array != null && receptor2.array.nuclei.Length > 1) + array = receptor2.array; } - EditorGUILayout.EndHorizontal(); - } - EditorGUI.indentLevel++; - synapse.weight = EditorGUILayout.FloatField("Weight", synapse.weight); - EditorGUI.indentLevel--; + EditorGUILayout.Space(); + + if (Application.isPlaying) { + Vector3 value = synapse.nucleus.outputValue * synapse.weight; + GUIContent synapseValueLabel = new(synapse.nucleus.name, synapse.nucleus.outputValue.ToString()); + EditorGUILayout.FloatField(synapseValueLabel, length(synapse.nucleus.outputValue)); + } + else { + EditorGUILayout.BeginHorizontal(); + + if (synapse.nucleus.parent != null && synapse.nucleus.parent != this.currentNucleus) { + GUIStyle labelStyle = new(GUI.skin.label); + float labelWidth = labelStyle.CalcSize(new GUIContent($"{synapse.nucleus.clusterPrefab.name}.")).x; + EditorGUILayout.LabelField($"{synapse.nucleus.clusterPrefab.name}", GUILayout.Width(labelWidth)); + string[] options = synapse.nucleus.parent.nuclei.Select(n => n.name).ToArray(); + int selectedIndex = System.Array.IndexOf(options, synapse.nucleus.name); + int newIndex = EditorGUILayout.Popup(selectedIndex, options); + if (newIndex != selectedIndex) { + ChangeSynapse(synapse, synapse.nucleus.parent.nuclei[newIndex]); + } + } + else + EditorGUILayout.LabelField(synapse.nucleus.name); + if (GUILayout.Button("Disconnect")) { + synapse.nucleus.RemoveReceiver(this.currentNucleus); + this.prefab.GarbageCollection(); + anythingChanged = true; + } + EditorGUILayout.EndHorizontal(); + } + + EditorGUI.indentLevel++; + synapse.weight = EditorGUILayout.FloatField("Weight", synapse.weight); + EditorGUI.indentLevel--; + } } } } + EditorGUILayout.EndFoldoutHeaderGroup(); } - EditorGUILayout.EndFoldoutHeaderGroup(); - // Activation EditorGUILayout.Space(); @@ -831,6 +861,8 @@ public class ClusterInspector : Editor { } } + #region Synapses + protected virtual void AddInput(Nucleus.Type selectedType, Nucleus nucleus) { switch (selectedType) { case Nucleus.Type.Neuron: @@ -869,30 +901,6 @@ public class ClusterInspector : Editor { BuildLayers(); } - protected virtual void DeleteNeuron(Nucleus nucleus) { - if (nucleus == null) - return; - - foreach (Nucleus receiver in nucleus.receivers) { - if (receiver != null) { - this.currentNucleus = receiver; - break; - } - } - this.prefab.nuclei.Remove(nucleus); - - if (outputsField.value == nucleus.name) { - this.prefab.RefreshOutputs(); - outputsField.choices = this.prefab.outputs.Select(output => output.name).ToList(); - outputsField.index = 0; - } - - Neuron.Delete(nucleus); - - this.currentNucleus = this.prefab.output; - BuildLayers(); - } - protected void AddSelectorInput(Nucleus nucleus) { Selector newSelector = new(this.prefab, "New Selector"); newSelector.AddReceiver(nucleus); @@ -933,19 +941,16 @@ public class ClusterInspector : Editor { } protected virtual void AddClusterReceptorInput(Nucleus nucleus) { - ClusterPickerWindow.ShowPicker(brain => OnClusterReceptorPicked(nucleus, brain), "Select Cluster"); + ClusterPickerWindow.ShowPicker(prefab => OnClusterReceptorPicked(nucleus, prefab), "Select Cluster"); } private void OnClusterPicked(Nucleus nucleus, ClusterPrefab prefab) { Cluster subclusterInstance = new(prefab, this.prefab); subclusterInstance.AddReceiver(nucleus); - // This does not work somehow - // this.currentNucleus = subclusterInstance; - // BuildLayers(); } - private void OnClusterReceptorPicked(Nucleus nucleus, ClusterPrefab prefab) { - ClusterReceptor clusterInstance = new(prefab, this.prefab, "New " + prefab.name); + private void OnClusterReceptorPicked(Nucleus nucleus, ClusterPrefab selectedPrefab) { + ClusterReceptor clusterInstance = new(selectedPrefab, this.prefab, "New " + selectedPrefab.name); clusterInstance.AddReceiver(nucleus); } @@ -980,6 +985,30 @@ public class ClusterInspector : Editor { return true; } + protected virtual void DeleteNeuron(Nucleus nucleus) { + if (nucleus == null) + return; + + foreach (Nucleus receiver in nucleus.receivers) { + if (receiver != null) { + this.currentNucleus = receiver; + break; + } + } + this.prefab.nuclei.Remove(nucleus); + + if (outputsField.value == nucleus.name) { + this.prefab.RefreshOutputs(); + outputsField.choices = this.prefab.outputs.Select(output => output.name).ToList(); + outputsField.index = 0; + } + + Neuron.Delete(nucleus); + + this.currentNucleus = this.prefab.output; + BuildLayers(); + } + protected virtual bool AddSynapse(ClusterPrefab cluster, Nucleus nucleus) { if (cluster == null) return false; @@ -992,18 +1021,25 @@ public class ClusterInspector : Editor { return true; } + protected virtual void ChangeSynapse(Synapse synapse, Nucleus newNucleus) { + synapse.nucleus.RemoveReceiver(this.currentNucleus); + newNucleus.AddReceiver(this.currentNucleus); + } + protected virtual void DisconnectNucleus(Neuron nucleus) { - if (this.currentNucleus.cluster == null) + if (this.currentNucleus.clusterPrefab == null) return; string[] names = this.currentNucleus.synapses.Select(synapse => synapse.nucleus.name).ToArray(); int selectedIndex = -1; selectedIndex = EditorGUILayout.Popup("Disconnect from", selectedIndex, names); //if (selectedIndex >= 0 && selectedIndex < this.currentNucleus.brain.perceptei.Count) { - if (selectedIndex >= 0 && selectedIndex < this.currentNucleus.cluster.nuclei.Count) { + if (selectedIndex >= 0 && selectedIndex < this.currentNucleus.clusterPrefab.nuclei.Count) { Synapse synapse = this.currentNucleus.synapses[selectedIndex]; synapse.nucleus.RemoveReceiver(this.currentNucleus); } } + + #endregion Synapses } #endregion Start diff --git a/Neuron.cs b/Neuron.cs index 315fc21..6fa9d4b 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -15,10 +15,10 @@ public class Neuron : Nucleus { this.parent?.nuclei.Add(this); } public Neuron(ClusterPrefab prefab, string name) { - this.cluster = prefab; + this.clusterPrefab = prefab; this.name = name; - if (this.cluster != null) - this.cluster.nuclei.Add(this); + if (this.clusterPrefab != null) + this.clusterPrefab.nuclei.Add(this); else Debug.LogError("No prefab when adding neuron to prefab"); } @@ -139,7 +139,7 @@ public class Neuron : Nucleus { } protected virtual void CloneFields(Neuron clone) { - // clone.array = this.array; + clone.clusterPrefab = this.clusterPrefab; clone.bias = this.bias; clone.combinator = this.combinator; clone.curve = this.curve; @@ -165,9 +165,9 @@ public class Neuron : Nucleus { receiver.synapses.RemoveAll(s => s.nucleus == nucleus); } - if (nucleus.cluster != null) { - nucleus.cluster.nuclei.RemoveAll(n => n == nucleus); - nucleus.cluster.GarbageCollection(); + if (nucleus.clusterPrefab != null) { + nucleus.clusterPrefab.nuclei.RemoveAll(n => n == nucleus); + nucleus.clusterPrefab.GarbageCollection(); } } diff --git a/Nucleus.cs b/Nucleus.cs index 1a014b3..e659008 100644 --- a/Nucleus.cs +++ b/Nucleus.cs @@ -8,9 +8,10 @@ using static Unity.Mathematics.math; public abstract class Nucleus { public string name; - //[Obsolete] - public ClusterPrefab cluster { get; set; } - public Cluster parent { get; set; } + [SerializeReference] + public ClusterPrefab clusterPrefab; + [SerializeReference] + public Cluster parent; protected float3 _outputValue; public virtual float3 outputValue { @@ -73,7 +74,7 @@ public abstract class Nucleus { [SerializeReference] private List _receivers = new(); - public List receivers { + public virtual List receivers { get { return _receivers; } set { _receivers = value; } } diff --git a/ReceptorArray.cs b/ReceptorArray.cs index 3ac96aa..c8441db 100644 --- a/ReceptorArray.cs +++ b/ReceptorArray.cs @@ -13,7 +13,7 @@ public class ReceptorInstance : Nucleus { // We explicitly do not add this to the parent, as it is serialized in the ReceptorArray } public ReceptorInstance(ClusterPrefab prefab, string name) { - this.cluster = prefab; + this.clusterPrefab = prefab; this.name = name; // We explicitly do not add this to the prefab, as it is serialized in the ReceptorArray } @@ -49,14 +49,14 @@ public class ReceptorArray : Nucleus { this.parent?.nuclei.Add(this); } public ReceptorArray(ClusterPrefab prefab, string name) { - this.cluster = prefab; + this.clusterPrefab = prefab; this.name = name; this._instances = new ReceptorInstance[1]; this._instances[0] = new ReceptorInstance(prefab, this.name + "[0]") { receptor = this }; - if (this.cluster != null) - this.cluster.nuclei.Add(this); + if (this.clusterPrefab != null) + this.clusterPrefab.nuclei.Add(this); else Debug.LogError("No prefab when adding receptor to prefab"); From 36e73081f9b887414dcb05c724038c96f2eb85d9 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Tue, 17 Feb 2026 12:31:39 +0100 Subject: [PATCH 150/179] cluster no longer have receivers --- Cluster.cs | 156 +++++++++++++++++++-------------- ClusterPrefab.cs | 8 +- ClusterReceptor.cs | 43 ++++----- Editor/BrainEditorWindow.cs | 12 +-- Editor/ClusterInspector.cs | 169 +++++++++++++++++++++--------------- Editor/NanoBrain_Editor.cs | 2 +- IReceptor.cs | 5 ++ IReceptor.cs.meta | 2 + NanoBrain.cs | 2 +- Neuron.cs | 54 ++++++++++-- Nucleus.cs | 25 +----- Receptor.cs | 2 +- ReceptorArray.cs | 8 +- 13 files changed, 289 insertions(+), 199 deletions(-) create mode 100644 IReceptor.cs create mode 100644 IReceptor.cs.meta diff --git a/Cluster.cs b/Cluster.cs index 84ff4b2..aaa6429 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -15,11 +15,11 @@ public class Cluster : Nucleus { this.name = prefab.name; this.parent = parent; - this.parent?.nuclei.Add(this); + this.parent?.clusterNuclei.Add(this); ClonePrefab(); _ = this.inputs; - this.sortedNuclei = TopologicalSort(this.nuclei); + this.sortedNuclei = TopologicalSort(this.clusterNuclei); } public Cluster(ClusterPrefab prefab, ClusterPrefab parent = null) { @@ -32,7 +32,7 @@ public class Cluster : Nucleus { ClonePrefab(); _ = this.inputs; - this.sortedNuclei = TopologicalSort(this.nuclei); + this.sortedNuclei = TopologicalSort(this.clusterNuclei); } private void ClonePrefab() { @@ -40,7 +40,7 @@ public class Cluster : Nucleus { // first clone the nuclei without their connections foreach (Nucleus nucleus in this.prefab.nuclei) nucleus.ShallowCloneTo(this); - Nucleus[] clonedNuclei = this.nuclei.ToArray(); + Nucleus[] clonedNuclei = this.clusterNuclei.ToArray(); // Now clone the connections for (int nucleusIx = 0; nucleusIx < prefabNuclei.Length; nucleusIx++) { @@ -50,26 +50,27 @@ public class Cluster : Nucleus { continue; // Copy the receivers, which will also create the synapses - foreach (Nucleus receiver in prefabNucleus.receivers) { - int ix = GetNucleusIndex(prefabNuclei, receiver); - if (ix < 0) - continue; + // Clusters do not have receivers... + // foreach (Nucleus receiver in prefabNucleus.receivers) { + // int ix = GetNucleusIndex(prefabNuclei, receiver); + // if (ix < 0) + // continue; - if (clonedNuclei[ix] is not Nucleus clonedReceiver) - continue; + // if (clonedNuclei[ix] is not Nucleus clonedReceiver) + // continue; - // Find the synapse for the weight - float weight = 1; - foreach (Synapse synapse in receiver.synapses) { - // Find the weight for this synapse - if (synapse.nucleus == prefabNucleus) { - weight = synapse.weight; - break; - } - } + // // Find the synapse for the weight + // float weight = 1; + // foreach (Synapse synapse in receiver.synapses) { + // // Find the weight for this synapse + // if (synapse.nucleus == prefabNucleus) { + // weight = synapse.weight; + // break; + // } + // } - clonedReceptor.AddReceiver(clonedReceiver, weight); - } + // clonedReceptor.AddReceiver(clonedReceiver, weight); + // } } // Copy nucleus arrays @@ -116,8 +117,10 @@ public class Cluster : Nucleus { // Calculate in-degrees foreach (Nucleus node in nodes) { - foreach (Nucleus receiver in node.receivers) - inDegree[receiver]++; + if (node is Neuron neuron) { + foreach (Nucleus receiver in neuron.receivers) + inDegree[receiver]++; + } } Queue queue = new(); @@ -132,10 +135,12 @@ public class Cluster : Nucleus { Nucleus current = queue.Dequeue(); sortedOrder.Add(current); // Process the node - foreach (Nucleus receiver in current.receivers) { - inDegree[receiver]--; - if (inDegree[receiver] == 0) // If all dependencies resolved - queue.Enqueue(receiver); + if (current is Neuron neuron) { + foreach (Nucleus receiver in neuron.receivers) { + inDegree[receiver]--; + if (inDegree[receiver] == 0) // If all dependencies resolved + queue.Enqueue(receiver); + } } } @@ -153,9 +158,9 @@ public class Cluster : Nucleus { Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); clonedSynapse.weight = synapse.weight; } - foreach (Nucleus receiver in this.receivers) { - clone.AddReceiver(receiver); - } + // foreach (Nucleus receiver in this.receivers) { + // clone.AddReceiver(receiver); + // } return clone; } @@ -181,7 +186,7 @@ public class Cluster : Nucleus { [SerializeReference] - public List nuclei = new(); + public List clusterNuclei = new(); // the nuclei sorted using topological sorting // to ensure that the cluster is computer in the right order public List sortedNuclei; @@ -192,7 +197,7 @@ public class Cluster : Nucleus { get { if (this._inputs == null) { this._inputs = new(); - foreach (Nucleus nucleus in this.nuclei) { + foreach (Nucleus nucleus in this.clusterNuclei) { // inputs have no synapses if (nucleus.synapses.Count == 0) this._inputs.Add(nucleus); @@ -215,7 +220,7 @@ public class Cluster : Nucleus { HashSet visited = new HashSet(); // Initialize in-degrees and mark all nodes as unvisited - foreach (Nucleus node in this.nuclei) { + foreach (Nucleus node in this.clusterNuclei) { inDegree[node] = 0; } @@ -226,12 +231,14 @@ public class Cluster : Nucleus { while (queue.Count > 0) { Nucleus current = queue.Dequeue(); - foreach (Nucleus receiver in current.receivers) { - if (!visited.Contains(receiver)) { - visited.Add(receiver); - queue.Enqueue(receiver); + if (current is Neuron neuron) { + foreach (Nucleus receiver in neuron.receivers) { + if (!visited.Contains(receiver)) { + visited.Add(receiver); + queue.Enqueue(receiver); + } + inDegree[receiver]++; } - inDegree[receiver]++; } } @@ -248,11 +255,13 @@ public class Cluster : Nucleus { Nucleus current = queue.Dequeue(); sortedOrder.Add(current); // Process the node - foreach (Nucleus receiver in current.receivers) { - if (visited.Contains(receiver)) { - inDegree[receiver]--; - if (inDegree[receiver] == 0) // If all dependencies resolved - queue.Enqueue(receiver); + if (current is Neuron neuron) { + foreach (Nucleus receiver in neuron.receivers) { + if (visited.Contains(receiver)) { + inDegree[receiver]--; + if (inDegree[receiver] == 0) // If all dependencies resolved + queue.Enqueue(receiver); + } } } } @@ -266,13 +275,15 @@ public class Cluster : Nucleus { private List TopologicalSort3(Nucleus startNode) { Dictionary inDegree = new(); - foreach (Nucleus node in this.nuclei) + foreach (Nucleus node in this.clusterNuclei) inDegree[node] = 0; // Initialize in-degree to zero // Calculate in-degrees - foreach (Nucleus node in this.nuclei) { - foreach (Nucleus receiver in node.receivers) - inDegree[receiver]++; + foreach (Nucleus node in this.clusterNuclei) { + if (node is Neuron neuron) { + foreach (Nucleus receiver in neuron.receivers) + inDegree[receiver]++; + } } Queue queue = new(); @@ -283,10 +294,12 @@ public class Cluster : Nucleus { Nucleus current = queue.Dequeue(); sortedOrder.Add(current); // Process the node - foreach (Nucleus receiver in current.receivers) { - inDegree[receiver]--; - if (inDegree[receiver] == 0) // If all dependencies resolved - queue.Enqueue(receiver); + if (current is Neuron neuron) { + foreach (Nucleus receiver in neuron.receivers) { + inDegree[receiver]--; + if (inDegree[receiver] == 0) // If all dependencies resolved + queue.Enqueue(receiver); + } } } @@ -298,22 +311,21 @@ public class Cluster : Nucleus { return sortedOrder; } - public virtual Nucleus output {//=> this.nuclei[0] as Nucleus; + public virtual Neuron defaultOutput {//=> this.nuclei[0] as Nucleus; get { - if (this.nuclei.Count > 0) - return this.nuclei[0]; + if (this.clusterNuclei.Count > 0) + return this.clusterNuclei[0] as Neuron; return null; } } - public List _outputs = null; - public List outputs { + private List _outputs = null; + public List outputs { get { if (this._outputs == null) { this._outputs = new(); - foreach (Nucleus nucleus in this.nuclei) { - // outputs have not receivers - if (nucleus.receivers.Count == 0) - this._outputs.Add(nucleus); + foreach (Nucleus nucleus in this.clusterNuclei) { + if (nucleus is Neuron neuron) // && neuron.receivers.Count == 0) + this._outputs.Add(neuron); } } return this._outputs; @@ -321,7 +333,7 @@ public class Cluster : Nucleus { } public bool TryGetNucleus(string nucleusName, out Nucleus foundNucleus) { - foreach (Nucleus receptor in this.nuclei) { + foreach (Nucleus receptor in this.clusterNuclei) { if (receptor is Nucleus nucleus) if (nucleus.name == nucleusName) { foundNucleus = nucleus; @@ -333,7 +345,7 @@ public class Cluster : Nucleus { } public Nucleus GetNucleus(string nucleusName) { - foreach (Nucleus nucleus in this.nuclei) { + foreach (Nucleus nucleus in this.clusterNuclei) { if (nucleus.name == nucleusName) return nucleus; } @@ -341,7 +353,7 @@ public class Cluster : Nucleus { } public Receptor GetReceptor(string receptorName) { - foreach (Nucleus nucleus in this.nuclei) { + foreach (Nucleus nucleus in this.clusterNuclei) { if (nucleus is Receptor receptor) if (receptor.name == receptorName) return receptor; @@ -349,6 +361,18 @@ public class Cluster : Nucleus { return null; } + #region Receivers + + public virtual List CollectReceivers() { + List receivers = new(); + foreach (Neuron output in this.outputs) { + receivers.AddRange(output.receivers); + } + return receivers; + } + + #endregion Receivers + #region Update public void UpdateFromNucleus(Nucleus startNucleus) { @@ -363,7 +387,7 @@ public class Cluster : Nucleus { Debug.Log($" {nucleus.name} = {nucleus.outputValue}"); } - this.outputValue = this.output.outputValue; + this.outputValue = this.defaultOutput.outputValue; this.stale = 0; UpdateNuclei(); @@ -383,14 +407,14 @@ public class Cluster : Nucleus { foreach (Nucleus nucleus in this.sortedNuclei) nucleus.UpdateStateIsolated(); - this.outputValue = this.output.outputValue; + this.outputValue = this.defaultOutput.outputValue; this.stale = 0; UpdateNuclei(); } public override void UpdateNuclei() { - foreach (Nucleus nucleus in this.nuclei) + foreach (Nucleus nucleus in this.clusterNuclei) nucleus.UpdateNuclei(); } diff --git a/ClusterPrefab.cs b/ClusterPrefab.cs index e58e6c6..d8dd30b 100644 --- a/ClusterPrefab.cs +++ b/ClusterPrefab.cs @@ -38,7 +38,7 @@ public class ClusterPrefab : ScriptableObject { public void RefreshOutputs() { this._outputs = new(); foreach (Nucleus nucleus in this.nuclei) { - if (nucleus.receivers.Count == 0) + if (nucleus is Neuron neuron && neuron.receivers.Count == 0) this._outputs.Add(nucleus); } } @@ -85,15 +85,15 @@ public class ClusterPrefab : ScriptableObject { } nucleus.synapses.RemoveAll(synapse => visitedSynapses.Contains(synapse) == false); } - if (nucleus.receivers != null) { + if (nucleus is Neuron neuron && neuron.receivers != null) { HashSet visitedReceivers = new(); - foreach (Nucleus receiver in nucleus.receivers) { + foreach (Nucleus receiver in neuron.receivers) { if (receiver != null && receiver != null) { visitedReceivers.Add(receiver); visitedNuclei.Add(receiver); } } - nucleus.receivers.RemoveAll(receiver => visitedReceivers.Contains(receiver) == false); + neuron.receivers.RemoveAll(receiver => visitedReceivers.Contains(receiver) == false); } } diff --git a/ClusterReceptor.cs b/ClusterReceptor.cs index d6aca1b..e72cdd7 100644 --- a/ClusterReceptor.cs +++ b/ClusterReceptor.cs @@ -5,7 +5,7 @@ using Unity.Mathematics; using static Unity.Mathematics.math; [Serializable] -public class ClusterReceptor : Cluster { +public class ClusterReceptor : Cluster, IReceptor { public ClusterReceptor(ClusterPrefab prefab, Cluster parent, string name) : base(prefab, parent) { this.name = name; this.array ??= new NucleusArray(this); @@ -32,9 +32,9 @@ public class ClusterReceptor : Cluster { Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); clonedSynapse.weight = synapse.weight; } - foreach (Nucleus receiver in this.receivers) { - clone.AddReceiver(receiver); - } + // foreach (Nucleus receiver in this.receivers) { + // clone.AddReceiver(receiver); + // } return clone; } @@ -48,21 +48,22 @@ public class ClusterReceptor : Cluster { #region Receivers private List _clusterReceivers = null; - public override List receivers { - get { - if (_clusterReceivers == null || _clusterReceivers.Count == 0) { - _clusterReceivers = new(); - foreach (Nucleus output in this.nuclei) { - _clusterReceivers.AddRange(output.receivers); - } - } - return _clusterReceivers; - } - } - public override void AddReceiver(Nucleus receivingNucleus, float weight = 1) { - this.output.receivers.Add(receivingNucleus); - receivingNucleus.AddSynapse(this.output, weight); - } + // public override List receivers { + // get { + // if (_clusterReceivers == null || _clusterReceivers.Count == 0) { + // _clusterReceivers = new(); + // foreach (Nucleus output in this.clusterNuclei) { + // _clusterReceivers.AddRange(output.receivers); + // } + // } + // return _clusterReceivers; + // } + // } + // public override void AddReceiver(Nucleus receivingNucleus, float weight = 1) { + // string nucleusName = this. + // this.output.receivers.Add(receivingNucleus); + // receivingNucleus.AddSynapse(this.output, weight); + // } #endregion Receivers @@ -72,7 +73,7 @@ public class ClusterReceptor : Cluster { foreach (Nucleus nucleus in this.sortedNuclei) nucleus.UpdateStateIsolated(); - this.outputValue = this.output.outputValue; + this.outputValue = this.defaultOutput.outputValue; this.stale = 0; UpdateNuclei(); @@ -85,7 +86,7 @@ public class ClusterReceptor : Cluster { this.parent.UpdateFromNucleus(this); } - foreach (Nucleus nucleus in this.nuclei) + foreach (Nucleus nucleus in this.clusterNuclei) nucleus.UpdateNuclei(); } diff --git a/Editor/BrainEditorWindow.cs b/Editor/BrainEditorWindow.cs index aa4e292..11bba19 100644 --- a/Editor/BrainEditorWindow.cs +++ b/Editor/BrainEditorWindow.cs @@ -74,9 +74,11 @@ public class BrainEditorWindow : EditorWindow { int ix = 0; foreach (Nucleus nucleus in prefab.nuclei) { nodes.Add(new DagNode() { id = ix, title = nucleus.name }); - foreach (Nucleus receiver in nucleus.receivers) { - int receiverIx = prefab.GetNucleusIndex(receiver); - edges.Add(new DagEdge() { fromId = ix, toId = receiverIx }); + if (nucleus is Neuron neuron) { + foreach (Nucleus receiver in neuron.receivers) { + int receiverIx = prefab.GetNucleusIndex(receiver); + edges.Add(new DagEdge() { fromId = ix, toId = receiverIx }); + } } ix++; } @@ -191,9 +193,9 @@ public class BrainEditorWindow : EditorWindow { Handles.DrawSolidDisc(n.position, Vector3.forward, n.radius); if (GetIncomingEdges(n).Count == 0) - DrawArrowHead(n.position - new Vector2(n.radius + 10, 0), n.position - new Vector2(n.radius + 5, 0), 10f/zoom, 12f/zoom, Color.white); + DrawArrowHead(n.position - new Vector2(n.radius + 10, 0), n.position - new Vector2(n.radius + 5, 0), 10f / zoom, 12f / zoom, Color.white); if (GetOutgoingEdges(n).Count == 0) - DrawArrowHead(n.position + new Vector2(n.radius + 10, 0), n.position + new Vector2(n.radius + 15, 0), 10f/zoom, 12f/zoom, Color.white); + DrawArrowHead(n.position + new Vector2(n.radius + 10, 0), n.position + new Vector2(n.radius + 15, 0), 10f / zoom, 12f / zoom, Color.white); Handles.color = Color.white; GUIStyle style = new(EditorStyles.label) { diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index bafeee7..a099a5d 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -195,8 +195,8 @@ public class ClusterInspector : Editor { return; NeuroidLayer currentLayer = new() { ix = layerIx }; - if (selectedNucleus.receivers != null) { - foreach (Nucleus receiver in selectedNucleus.receivers) { + if (selectedNucleus is Neuron selectedNeuron && selectedNeuron.receivers != null) { + foreach (Nucleus receiver in selectedNeuron.receivers) { Nucleus outputNeuroid = receiver; if (outputNeuroid != null) { AddToLayer(currentLayer, outputNeuroid); @@ -357,12 +357,20 @@ public class ClusterInspector : Editor { } private void DrawReceivers(Nucleus nucleus, Vector3 parentPos, float size) { - int nodeCount = nucleus.receivers.Count(); + List receivers = null; + if (nucleus is Neuron neuron) + receivers = neuron.receivers; + else if (nucleus is Cluster cluster) + receivers = cluster.CollectReceivers(); + else + return; + + int nodeCount = receivers.Count(); //neuron != null ? neuron.receivers.Count() : 1; // Determine the maximum value in this layer // This is used to 'scale' the output value colors of the nuclei float maxValue = 0; - foreach (Nucleus receiver in nucleus.receivers) { + foreach (Nucleus receiver in receivers) { if (receiver is Neuron neuroid) { float value = length(neuroid.outputValue); if (value > maxValue) @@ -376,7 +384,7 @@ public class ClusterInspector : Editor { int row = 0; List drawnArrays = new(); - foreach (Nucleus receiver in nucleus.receivers) { + foreach (Nucleus receiver in receivers) { if (receiver is Receptor receptor) { if (drawnArrays.Contains(receptor.array)) continue; @@ -409,7 +417,8 @@ public class ClusterInspector : Editor { if (drawnArrays.Contains(receptor.array)) continue; drawnArrays.Add(receptor.array); - } else if (synapse.nucleus.parent is ClusterReceptor clusterReceptor) { + } + else if (synapse.nucleus.parent is ClusterReceptor clusterReceptor) { if (drawnArrays.Contains(clusterReceptor.array)) continue; drawnArrays.Add(clusterReceptor.array); @@ -432,7 +441,8 @@ public class ClusterInspector : Editor { if (drawnArrays.Contains(neuron.array)) continue; drawnArrays.Add(neuron.array); - } else if (synapse.nucleus.parent is ClusterReceptor clusterReceptor) { + } + else if (synapse.nucleus.parent is ClusterReceptor clusterReceptor) { if (drawnArrays.Contains(clusterReceptor.array)) continue; drawnArrays.Add(clusterReceptor.array); @@ -731,56 +741,61 @@ public class ClusterInspector : Editor { if (this.currentNucleus.synapses.Count > 0) { Synapse[] synapses = this.currentNucleus.synapses.ToArray(); foreach (Synapse synapse in synapses) { - if (synapse.nucleus != null) { - if (array != null) { - if (array.nuclei.Contains(synapse.nucleus)) - continue; - } - else { - if (synapse.nucleus is Receptor receptor2 && receptor2.array != null && receptor2.array.nuclei.Length > 1) - array = receptor2.array; - } + if (synapse.nucleus == null) + continue; - EditorGUILayout.Space(); - - if (Application.isPlaying) { - Vector3 value = synapse.nucleus.outputValue * synapse.weight; - GUIContent synapseValueLabel = new(synapse.nucleus.name, synapse.nucleus.outputValue.ToString()); - EditorGUILayout.FloatField(synapseValueLabel, length(synapse.nucleus.outputValue)); - } - else { - EditorGUILayout.BeginHorizontal(); - - if (synapse.nucleus.parent != null && synapse.nucleus.parent != this.currentNucleus) { - GUIStyle labelStyle = new(GUI.skin.label); - float labelWidth = labelStyle.CalcSize(new GUIContent($"{synapse.nucleus.clusterPrefab.name}.")).x; - EditorGUILayout.LabelField($"{synapse.nucleus.clusterPrefab.name}", GUILayout.Width(labelWidth)); - string[] options = synapse.nucleus.parent.nuclei.Select(n => n.name).ToArray(); - int selectedIndex = System.Array.IndexOf(options, synapse.nucleus.name); - int newIndex = EditorGUILayout.Popup(selectedIndex, options); - if (newIndex != selectedIndex) { - ChangeSynapse(synapse, synapse.nucleus.parent.nuclei[newIndex]); - } - } - else - EditorGUILayout.LabelField(synapse.nucleus.name); - if (GUILayout.Button("Disconnect")) { - synapse.nucleus.RemoveReceiver(this.currentNucleus); - this.prefab.GarbageCollection(); - anythingChanged = true; - } - EditorGUILayout.EndHorizontal(); - } - - EditorGUI.indentLevel++; - synapse.weight = EditorGUILayout.FloatField("Weight", synapse.weight); - EditorGUI.indentLevel--; + if (array != null) { + if (array.nuclei.Contains(synapse.nucleus)) + continue; + if (array.nuclei.Contains(synapse.nucleus.parent)) + continue; } + else { + if (synapse.nucleus.parent is ClusterReceptor clusterReceptor) + array = clusterReceptor.array; + else if (synapse.nucleus is Receptor receptor2) // && receptor2.array != null && receptor2.array.nuclei.Length > 1) + array = receptor2.array; + } + + EditorGUILayout.Space(); + + if (Application.isPlaying) { + Vector3 value = synapse.nucleus.outputValue * synapse.weight; + GUIContent synapseValueLabel = new(synapse.nucleus.name, synapse.nucleus.outputValue.ToString()); + EditorGUILayout.FloatField(synapseValueLabel, length(synapse.nucleus.outputValue)); + } + else { + EditorGUILayout.BeginHorizontal(); + + if (synapse.nucleus.parent != null && synapse.nucleus.parent != this.currentNucleus) { + GUIStyle labelStyle = new(GUI.skin.label); + float labelWidth = labelStyle.CalcSize(new GUIContent($"{synapse.nucleus.clusterPrefab.name}.")).x; + EditorGUILayout.LabelField($"{synapse.nucleus.clusterPrefab.name}", GUILayout.Width(labelWidth)); + string[] options = synapse.nucleus.parent.clusterNuclei.Select(n => n.name).ToArray(); + int selectedIndex = System.Array.IndexOf(options, synapse.nucleus.name); + int newIndex = EditorGUILayout.Popup(selectedIndex, options); + if (newIndex != selectedIndex && synapse.nucleus.parent.clusterNuclei[newIndex] is Neuron newNeuron) + ChangeSynapse(synapse, newNeuron); + } + else + EditorGUILayout.LabelField(synapse.nucleus.name); + if (GUILayout.Button("Disconnect") && synapse.nucleus is Neuron synapseNeuron) { + synapseNeuron.RemoveReceiver(this.currentNucleus); + this.prefab.GarbageCollection(); + anythingChanged = true; + } + EditorGUILayout.EndHorizontal(); + } + + EditorGUI.indentLevel++; + synapse.weight = EditorGUILayout.FloatField("Weight", synapse.weight); + EditorGUI.indentLevel--; } } } EditorGUILayout.EndFoldoutHeaderGroup(); } + // Activation EditorGUILayout.Space(); @@ -811,7 +826,7 @@ public class ClusterInspector : Editor { if (GUILayout.Button("Delete this neuron")) - DeleteNeuron(this.currentNucleus); + DeleteNucleus(this.currentNucleus); if (this.currentNucleus is Cluster subCluster) { if (GUILayout.Button("Edit Cluster")) @@ -934,10 +949,10 @@ public class ClusterInspector : Editor { } protected virtual void AddReceptorArrayInput(Nucleus nucleus) { - ReceptorArray newReceptor = new(this.prefab, "New Receptor"); - newReceptor.AddReceiver(nucleus); - this.currentNucleus = newReceptor; - BuildLayers(); + // ReceptorArray newReceptor = new(this.prefab, "New Receptor"); + // newReceptor.AddReceiver(nucleus); + // this.currentNucleus = newReceptor; + // BuildLayers(); } protected virtual void AddClusterReceptorInput(Nucleus nucleus) { @@ -946,12 +961,12 @@ public class ClusterInspector : Editor { private void OnClusterPicked(Nucleus nucleus, ClusterPrefab prefab) { Cluster subclusterInstance = new(prefab, this.prefab); - subclusterInstance.AddReceiver(nucleus); + subclusterInstance.defaultOutput.AddReceiver(nucleus); } private void OnClusterReceptorPicked(Nucleus nucleus, ClusterPrefab selectedPrefab) { ClusterReceptor clusterInstance = new(selectedPrefab, this.prefab, "New " + selectedPrefab.name); - clusterInstance.AddReceiver(nucleus); + clusterInstance.defaultOutput.AddReceiver(nucleus); } private void EditCluster(Cluster subCluster) { @@ -962,7 +977,7 @@ public class ClusterInspector : Editor { } // Connect to another nucleus in the same cluster - protected virtual bool ConnectNucleus(ClusterPrefab cluster, Nucleus nucleus) { + protected virtual bool ConnectNucleus(ClusterPrefab cluster, Nucleus nucleusToConnect) { if (cluster == null) return false; @@ -980,19 +995,25 @@ public class ClusterInspector : Editor { if (selectedIndex < 0) return false; - Nucleus receptor = nuclei.ElementAt(selectedIndex); - receptor.AddReceiver(this.currentNucleus); + Nucleus nucleus = nuclei.ElementAt(selectedIndex); + if (nucleus is Neuron neuron) + neuron.AddReceiver(this.currentNucleus); + else if (nucleus is Cluster subCluster) + subCluster.defaultOutput.AddReceiver(this.currentNucleus); + return true; } - protected virtual void DeleteNeuron(Nucleus nucleus) { + protected virtual void DeleteNucleus(Nucleus nucleus) { if (nucleus == null) return; - foreach (Nucleus receiver in nucleus.receivers) { - if (receiver != null) { - this.currentNucleus = receiver; - break; + if (nucleus is Neuron neuron) { + foreach (Nucleus receiver in neuron.receivers) { + if (receiver != null) { + this.currentNucleus = receiver; + break; + } } } this.prefab.nuclei.Remove(nucleus); @@ -1021,9 +1042,17 @@ public class ClusterInspector : Editor { return true; } - protected virtual void ChangeSynapse(Synapse synapse, Nucleus newNucleus) { - synapse.nucleus.RemoveReceiver(this.currentNucleus); - newNucleus.AddReceiver(this.currentNucleus); + protected virtual void ChangeSynapse(Synapse synapse, Neuron newNucleus) { + Neuron synapseNeuron = synapse.nucleus as Neuron; + if (synapse.nucleus.parent is Cluster subCluster && subCluster.prefab != this.prefab) { + // it is a neuron in a subcluster + synapseNeuron.RemoveReceiver(this.currentNucleus); + newNucleus.AddReceiver(this.currentNucleus); + } + else { + synapseNeuron.RemoveReceiver(this.currentNucleus); + newNucleus.AddReceiver(this.currentNucleus); + } } protected virtual void DisconnectNucleus(Neuron nucleus) { @@ -1032,10 +1061,10 @@ public class ClusterInspector : Editor { string[] names = this.currentNucleus.synapses.Select(synapse => synapse.nucleus.name).ToArray(); int selectedIndex = -1; selectedIndex = EditorGUILayout.Popup("Disconnect from", selectedIndex, names); - //if (selectedIndex >= 0 && selectedIndex < this.currentNucleus.brain.perceptei.Count) { if (selectedIndex >= 0 && selectedIndex < this.currentNucleus.clusterPrefab.nuclei.Count) { Synapse synapse = this.currentNucleus.synapses[selectedIndex]; - synapse.nucleus.RemoveReceiver(this.currentNucleus); + Neuron synapseNeuron = synapse.nucleus as Neuron; + synapseNeuron.RemoveReceiver(this.currentNucleus); } } diff --git a/Editor/NanoBrain_Editor.cs b/Editor/NanoBrain_Editor.cs index 6c37746..376e9f0 100644 --- a/Editor/NanoBrain_Editor.cs +++ b/Editor/NanoBrain_Editor.cs @@ -36,7 +36,7 @@ public class NanoBrainComponent_Editor : Editor { root.Add(brainField); } - ClusterInspector.CreateInspector(root, brain.prefab, brain.output, component.gameObject); + ClusterInspector.CreateInspector(root, brain.prefab, brain.defaultOutput, component.gameObject); if (Application.isPlaying == false) serializedObject.ApplyModifiedProperties(); diff --git a/IReceptor.cs b/IReceptor.cs new file mode 100644 index 0000000..94d9ae2 --- /dev/null +++ b/IReceptor.cs @@ -0,0 +1,5 @@ +public interface IReceptor { + public NucleusArray array { + get; set; + } +} \ No newline at end of file diff --git a/IReceptor.cs.meta b/IReceptor.cs.meta new file mode 100644 index 0000000..0c0ee6f --- /dev/null +++ b/IReceptor.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 73f052292ad16bb53a3c07aa1694c705 \ No newline at end of file diff --git a/NanoBrain.cs b/NanoBrain.cs index 3e3ee21..831b9db 100644 --- a/NanoBrain.cs +++ b/NanoBrain.cs @@ -18,7 +18,7 @@ public class NanoBrain : MonoBehaviour { } public static void UpdateWeight(Cluster brain, string name, float weight) { - Nucleus root = brain.output; + Nucleus root = brain.defaultOutput; foreach (Synapse synapse in root.synapses) { if (synapse.nucleus.name == name) { if (synapse.weight != weight) { diff --git a/Neuron.cs b/Neuron.cs index 6fa9d4b..f24eaa3 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -12,7 +12,7 @@ public class Neuron : Nucleus { public Neuron(Cluster parent, string name) { this.parent = parent; this.name = name; - this.parent?.nuclei.Add(this); + this.parent?.clusterNuclei.Add(this); } public Neuron(ClusterPrefab prefab, string name) { this.clusterPrefab = prefab; @@ -25,7 +25,6 @@ public class Neuron : Nucleus { #region Serialization - //public Type type = Type.Neuron; public enum CombinatorType { Sum, Product, @@ -160,11 +159,14 @@ public class Neuron : Nucleus { } } } - foreach (Nucleus receiver in nucleus.receivers) { - if (receiver != null && receiver.synapses != null) - receiver.synapses.RemoveAll(s => s.nucleus == nucleus); + if (nucleus is Neuron neuron) { + foreach (Nucleus receiver in neuron.receivers) { + if (receiver != null && receiver.synapses != null) + receiver.synapses.RemoveAll(s => s.nucleus == nucleus); + } } + if (nucleus.clusterPrefab != null) { nucleus.clusterPrefab.nuclei.RemoveAll(n => n == nucleus); nucleus.clusterPrefab.GarbageCollection(); @@ -259,6 +261,48 @@ public class Neuron : Nucleus { #endregion Activator + #region Receivers + + [SerializeReference] + private List _receivers = new(); + public virtual List receivers { + get { return _receivers; } + set { _receivers = value; } + } + + public virtual void AddReceiver(Nucleus receiverToAdd, float weight = 1) { + if (this is IReceptor receptor) { + foreach (Nucleus element in receptor.array.nuclei) { + if (element is Neuron neuron) { + neuron._receivers.Add(receiverToAdd); + receiverToAdd.AddSynapse(element, weight); + } + } + } + else { + this._receivers.Add(receiverToAdd); + receiverToAdd.AddSynapse(this, weight); + } + } + + public virtual void RemoveReceiver(Nucleus receiverToRemove) { + if (this is IReceptor receptor) { + foreach (Nucleus element in receptor.array.nuclei) { + if (element is Neuron neuron) { + neuron._receivers.RemoveAll(receiver => receiver == receiverToRemove); + receiverToRemove.synapses.RemoveAll(synapse => synapse.nucleus == neuron); + } + } + } + else { + this._receivers.RemoveAll(receiver => receiver == receiverToRemove); + receiverToRemove.synapses.RemoveAll(synapse => synapse.nucleus == this); + } + } + + + #endregion Receivers + public virtual void ProcessStimulus(Vector3 inputValue, string thingName = null) { this.stale = 0; this.bias = inputValue; diff --git a/Nucleus.cs b/Nucleus.cs index e659008..3193686 100644 --- a/Nucleus.cs +++ b/Nucleus.cs @@ -17,7 +17,6 @@ public abstract class Nucleus { public virtual float3 outputValue { get { return _outputValue; } set { - //this.stale = 0; _outputValue = value; if (this.isFiring) WhenFiring?.Invoke(); @@ -68,29 +67,13 @@ public abstract class Nucleus { return null; } + public void RemoveSynapse(Nucleus sendingNucleus) { + this.synapses.RemoveAll(synapse => synapse.nucleus == sendingNucleus); + } + #endregion Synapses - #region Receivers - [SerializeReference] - private List _receivers = new(); - public virtual List receivers { - get { return _receivers; } - set { _receivers = value; } - } - - public virtual void AddReceiver(Nucleus receivingNucleus, float weight = 1) { - this._receivers.Add(receivingNucleus); - receivingNucleus.AddSynapse(this, weight); - } - - public void RemoveReceiver(Nucleus receiverNucleus) { - this._receivers.RemoveAll(receiver => receiver == receiverNucleus); - receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); - } - - - #endregion Receivers #region Update diff --git a/Receptor.cs b/Receptor.cs index 34c511c..7ff4011 100644 --- a/Receptor.cs +++ b/Receptor.cs @@ -3,7 +3,7 @@ using Unity.Mathematics; using static Unity.Mathematics.math; [System.Serializable] -public class Receptor : Neuron { +public class Receptor : Neuron, IReceptor { public Receptor(Cluster parent, string name) : base(parent, name) { } public Receptor(ClusterPrefab prefab, string name) : base(prefab, name) { } diff --git a/ReceptorArray.cs b/ReceptorArray.cs index c8441db..2eea9f6 100644 --- a/ReceptorArray.cs +++ b/ReceptorArray.cs @@ -46,7 +46,7 @@ public class ReceptorArray : Nucleus { this._instances[0] = new ReceptorInstance(parent, this.name + "[0]") { receptor = this }; - this.parent?.nuclei.Add(this); + this.parent?.clusterNuclei.Add(this); } public ReceptorArray(ClusterPrefab prefab, string name) { this.clusterPrefab = prefab; @@ -89,9 +89,9 @@ public class ReceptorArray : Nucleus { Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); clonedSynapse.weight = synapse.weight; } - foreach (Nucleus receiver in this.receivers) { - clone.AddReceiver(receiver); - } + // foreach (Nucleus receiver in this.receivers) { + // clone.AddReceiver(receiver); + // } return clone; } From e26244717462733e8a0f3a1eb0dba4c3eb7ff762 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Tue, 17 Feb 2026 13:02:43 +0100 Subject: [PATCH 151/179] Fix array extension for clusters --- Cluster.cs | 39 ++++++++++++++++++++++++++++++--------- ClusterReceptor.cs | 33 +++++++++++---------------------- 2 files changed, 41 insertions(+), 31 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index aaa6429..a2bc161 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -151,16 +151,27 @@ public class Cluster : Nucleus { return sortedOrder; } - public override Nucleus Clone(ClusterPrefab prefab) { - Neuron clone = new(prefab, this.name); + public override Nucleus Clone(ClusterPrefab parent) { + Cluster clone = new(this.prefab, parent); foreach (Synapse synapse in this.synapses) { Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); clonedSynapse.weight = synapse.weight; } - // foreach (Nucleus receiver in this.receivers) { - // clone.AddReceiver(receiver); - // } + + foreach (Neuron output in this.outputs) { + foreach (Nucleus receiver in output.receivers) { + int ix = GetNucleusIndex(this.clusterNuclei.ToArray(), output); + if (ix < 0) + continue; + + if (clone.clusterNuclei[ix] is not Neuron clonedOutput) + continue; + + clonedOutput.AddReceiver(receiver); + } + } + return clone; } @@ -172,9 +183,19 @@ public class Cluster : Nucleus { return clone; } - private int GetNucleusIndex(Nucleus[] nucleiArray, Nucleus nucleus) { - for (int i = 0; i < nucleiArray.Length; i++) { - if (nucleus == nucleiArray[i]) + protected int GetNucleusIndex(Nucleus[] nuclei, Nucleus nucleus) { + for (int i = 0; i < nuclei.Length; i++) { + if (nucleus == nuclei[i]) + return i; + } + return -1; + } + + protected int GetNucleusIndex(List nuclei, Nucleus nucleus) { + int i = 0; + foreach (Nucleus nucleiElement in nuclei) { + //for (int i = 0; i < nuclei.Length; i++) { + if (nucleus == nucleiElement) return i; } return -1; @@ -318,7 +339,7 @@ public class Cluster : Nucleus { return null; } } - private List _outputs = null; + protected List _outputs = null; public List outputs { get { if (this._outputs == null) { diff --git a/ClusterReceptor.cs b/ClusterReceptor.cs index e72cdd7..8e13779 100644 --- a/ClusterReceptor.cs +++ b/ClusterReceptor.cs @@ -32,9 +32,20 @@ public class ClusterReceptor : Cluster, IReceptor { Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); clonedSynapse.weight = synapse.weight; } + // foreach (Nucleus receiver in this.receivers) { // clone.AddReceiver(receiver); // } + + this._outputs = null; // Make sure the output are regenerated + foreach (Neuron output in this.outputs) { + int ix = GetNucleusIndex(this.clusterNuclei, output); + if (ix < 0 || clone.clusterNuclei[ix] is not Neuron clonedOutput) + continue; + + foreach (Nucleus receiver in output.receivers) + clonedOutput.AddReceiver(receiver); + } return clone; } @@ -45,28 +56,6 @@ public class ClusterReceptor : Cluster, IReceptor { set { _array = value; } } - #region Receivers - - private List _clusterReceivers = null; - // public override List receivers { - // get { - // if (_clusterReceivers == null || _clusterReceivers.Count == 0) { - // _clusterReceivers = new(); - // foreach (Nucleus output in this.clusterNuclei) { - // _clusterReceivers.AddRange(output.receivers); - // } - // } - // return _clusterReceivers; - // } - // } - // public override void AddReceiver(Nucleus receivingNucleus, float weight = 1) { - // string nucleusName = this. - // this.output.receivers.Add(receivingNucleus); - // receivingNucleus.AddSynapse(this.output, weight); - // } - - #endregion Receivers - public override void UpdateStateIsolated() { float3 sum = this.bias; From b644d0fd5b9391f9a46f3c16564f8e3f80bbb451 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Tue, 17 Feb 2026 14:27:09 +0100 Subject: [PATCH 152/179] Fix array decrease for clusters --- ClusterPrefab.cs | 7 +++++-- Neuron.cs | 8 ++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/ClusterPrefab.cs b/ClusterPrefab.cs index d8dd30b..ada3553 100644 --- a/ClusterPrefab.cs +++ b/ClusterPrefab.cs @@ -66,14 +66,17 @@ public class ClusterPrefab : ScriptableObject { MarkNuclei(visitedNuclei, output); //MarkNuclei(visitedNuclei, this.output); //Debug.Log($"Garbage collection found {visitedNuclei.Count} Nuclei"); - this.nuclei.RemoveAll(nucleus => nucleus is Nucleus n && visitedNuclei.Contains(n) == false); + this.nuclei.RemoveAll(nucleus => visitedNuclei.Contains(nucleus) == false); } public void MarkNuclei(HashSet visitedNuclei, Nucleus nucleus) { if (nucleus is null) return; - visitedNuclei.Add(nucleus); + if (nucleus.parent != null && nucleus.parent.prefab != this) + visitedNuclei.Add(nucleus.parent); + else + visitedNuclei.Add(nucleus); if (nucleus.synapses != null) { HashSet visitedSynapses = new(); foreach (Synapse synapse in nucleus.synapses) { diff --git a/Neuron.cs b/Neuron.cs index f24eaa3..2f5e0f3 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -164,11 +164,19 @@ public class Neuron : Nucleus { if (receiver != null && receiver.synapses != null) receiver.synapses.RemoveAll(s => s.nucleus == nucleus); } + } else if (nucleus is Cluster cluster) { + // remove all receivers for this cluster + foreach (Neuron output in cluster.outputs) { + foreach (Nucleus receiver in output.receivers) { + receiver.synapses.RemoveAll(s => s.nucleus == output); + } + } } if (nucleus.clusterPrefab != null) { nucleus.clusterPrefab.nuclei.RemoveAll(n => n == nucleus); + nucleus.clusterPrefab.RefreshOutputs(); nucleus.clusterPrefab.GarbageCollection(); } } From 76d8714778950106442b3a86a9f3235a775ef3d5 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 18 Feb 2026 15:22:49 +0100 Subject: [PATCH 153/179] clone subcluster --- Cluster.cs | 87 +++++++++++++++++++++++++++++--------- ClusterPrefab.cs | 2 +- ClusterReceptor.cs | 7 ++- Editor/NanoBrain_Editor.cs | 3 +- 4 files changed, 76 insertions(+), 23 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index a2bc161..315d2f8 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -38,39 +38,45 @@ public class Cluster : Nucleus { private void ClonePrefab() { Nucleus[] prefabNuclei = this.prefab.nuclei.ToArray(); // first clone the nuclei without their connections - foreach (Nucleus nucleus in this.prefab.nuclei) + foreach (Nucleus nucleus in this.prefab.nuclei) { + Debug.Log($"prefab clone {nucleus.name}"); nucleus.ShallowCloneTo(this); + } + Debug.Log(" complete"); Nucleus[] clonedNuclei = this.clusterNuclei.ToArray(); // Now clone the connections for (int nucleusIx = 0; nucleusIx < prefabNuclei.Length; nucleusIx++) { Nucleus prefabNucleus = prefabNuclei[nucleusIx]; - Nucleus clonedReceptor = clonedNuclei[nucleusIx]; - if (clonedReceptor == null) + if (prefabNucleus is not Neuron prefabNeuron) + continue; + + Nucleus clonedNucleus = clonedNuclei[nucleusIx]; + if (clonedNucleus == null || clonedNucleus is not Neuron clonedNeuron) continue; // Copy the receivers, which will also create the synapses // Clusters do not have receivers... - // foreach (Nucleus receiver in prefabNucleus.receivers) { - // int ix = GetNucleusIndex(prefabNuclei, receiver); - // if (ix < 0) - // continue; + foreach (Nucleus receiver in prefabNeuron.receivers) { + int ix = GetNucleusIndex(prefabNuclei, receiver); + if (ix < 0) + continue; - // if (clonedNuclei[ix] is not Nucleus clonedReceiver) - // continue; + if (clonedNuclei[ix] is not Nucleus clonedReceiver) + continue; - // // Find the synapse for the weight - // float weight = 1; - // foreach (Synapse synapse in receiver.synapses) { - // // Find the weight for this synapse - // if (synapse.nucleus == prefabNucleus) { - // weight = synapse.weight; - // break; - // } - // } + // Find the synapse for the weight + float weight = 1; + foreach (Synapse synapse in receiver.synapses) { + // Find the weight for this synapse + if (synapse.nucleus == prefabNucleus) { + weight = synapse.weight; + break; + } + } - // clonedReceptor.AddReceiver(clonedReceiver, weight); - // } + clonedNeuron.AddReceiver(clonedReceiver, weight); + } } // Copy nucleus arrays @@ -180,9 +186,50 @@ public class Cluster : Nucleus { name = this.name, clusterPrefab = this.clusterPrefab, }; + // This cloned the prefab with the clusternuclei, + // but did not clone the receivers outside the cluster + RestoreExternalReceivers(clone, this.clusterPrefab, parent); + return clone; } + protected void RestoreExternalReceivers(Cluster clone, ClusterPrefab prefabParent, Cluster clonedParent) { + for (int nucleusIx = 0; nucleusIx < this.clusterNuclei.Count; nucleusIx++) { + Nucleus prefabNucleus = this.clusterNuclei[nucleusIx]; + if (prefabNucleus is not Neuron prefabNeuron) + continue; + + Nucleus clonedNucleus = clone.clusterNuclei[nucleusIx]; + if (clonedNucleus == null || clonedNucleus is not Neuron clonedNeuron) + continue; + + // Copy the receivers, which will also create the synapses + foreach (Nucleus receiver in prefabNeuron.receivers) { + int ix = GetNucleusIndex(prefabParent.nuclei, receiver); + if (ix < 0) + continue; + + //if (clone.clusterNuclei[ix] is not Nucleus clonedReceiver) + if (clonedParent.clusterNuclei[ix] is not Nucleus clonedReceiver) + continue; + + // Find the synapse for the weight + float weight = 1; + foreach (Synapse synapse in receiver.synapses) { + // Find the weight for this synapse + if (synapse.nucleus == prefabNucleus) { + weight = synapse.weight; + break; + } + } + + clonedNeuron.AddReceiver(clonedReceiver, weight); + } + } + + + } + protected int GetNucleusIndex(Nucleus[] nuclei, Nucleus nucleus) { for (int i = 0; i < nuclei.Length; i++) { if (nucleus == nuclei[i]) diff --git a/ClusterPrefab.cs b/ClusterPrefab.cs index ada3553..90db0db 100644 --- a/ClusterPrefab.cs +++ b/ClusterPrefab.cs @@ -114,4 +114,4 @@ public class ClusterPrefab : ScriptableObject { } return -1; } -} \ No newline at end of file +} diff --git a/ClusterReceptor.cs b/ClusterReceptor.cs index 8e13779..8b409bc 100644 --- a/ClusterReceptor.cs +++ b/ClusterReceptor.cs @@ -20,6 +20,11 @@ public class ClusterReceptor : Cluster, IReceptor { clusterPrefab = this.clusterPrefab, array = this.array }; + + // This cloned the prefab with the clusternuclei, + // but did not clone the receivers outside the cluster + RestoreExternalReceivers(clone, this.clusterPrefab, parent); + return clone; } @@ -44,7 +49,7 @@ public class ClusterReceptor : Cluster, IReceptor { continue; foreach (Nucleus receiver in output.receivers) - clonedOutput.AddReceiver(receiver); + clonedOutput.AddReceiver(receiver); } return clone; } diff --git a/Editor/NanoBrain_Editor.cs b/Editor/NanoBrain_Editor.cs index 376e9f0..4dcb4c5 100644 --- a/Editor/NanoBrain_Editor.cs +++ b/Editor/NanoBrain_Editor.cs @@ -36,7 +36,8 @@ public class NanoBrainComponent_Editor : Editor { root.Add(brainField); } - ClusterInspector.CreateInspector(root, brain.prefab, brain.defaultOutput, component.gameObject); + if (brain != null) + ClusterInspector.CreateInspector(root, brain.prefab, brain.defaultOutput, component.gameObject); if (Application.isPlaying == false) serializedObject.ApplyModifiedProperties(); From f72a37b2482c79df39902f7d7a2c4f7ad09a5cae Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 18 Feb 2026 17:26:45 +0100 Subject: [PATCH 154/179] Containment works again --- Cluster.cs | 11 +++++------ ClusterReceptor.cs | 4 ++++ Editor/ClusterInspector.cs | 6 ++++-- IReceptor.cs | 6 ++++++ Receptor.cs | 23 ++++++++++++++++------ Scripts/Experimental/SelectorBrain.cs | 23 ---------------------- Scripts/Experimental/SelectorBrain.cs.meta | 2 -- 7 files changed, 36 insertions(+), 39 deletions(-) delete mode 100644 Scripts/Experimental/SelectorBrain.cs delete mode 100644 Scripts/Experimental/SelectorBrain.cs.meta diff --git a/Cluster.cs b/Cluster.cs index 315d2f8..0c0d507 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -39,10 +39,9 @@ public class Cluster : Nucleus { Nucleus[] prefabNuclei = this.prefab.nuclei.ToArray(); // first clone the nuclei without their connections foreach (Nucleus nucleus in this.prefab.nuclei) { - Debug.Log($"prefab clone {nucleus.name}"); + // Debug.Log($"prefab clone {nucleus.name}"); nucleus.ShallowCloneTo(this); } - Debug.Log(" complete"); Nucleus[] clonedNuclei = this.clusterNuclei.ToArray(); // Now clone the connections @@ -57,7 +56,7 @@ public class Cluster : Nucleus { // Copy the receivers, which will also create the synapses // Clusters do not have receivers... - foreach (Nucleus receiver in prefabNeuron.receivers) { + foreach (Nucleus receiver in prefabNeuron.receivers.ToArray()) { int ix = GetNucleusIndex(prefabNuclei, receiver); if (ix < 0) continue; @@ -420,10 +419,10 @@ public class Cluster : Nucleus { return null; } - public Receptor GetReceptor(string receptorName) { + public IReceptor GetReceptor(string receptorName) { foreach (Nucleus nucleus in this.clusterNuclei) { - if (nucleus is Receptor receptor) - if (receptor.name == receptorName) + if (nucleus is IReceptor receptor) + if (receptor.GetName() == receptorName) return receptor; } return null; diff --git a/ClusterReceptor.cs b/ClusterReceptor.cs index 8b409bc..f5bb1ad 100644 --- a/ClusterReceptor.cs +++ b/ClusterReceptor.cs @@ -15,6 +15,10 @@ public class ClusterReceptor : Cluster, IReceptor { this.array = new NucleusArray(this); } + public string GetName() { + return this.name; + } + public override Nucleus ShallowCloneTo(Cluster parent) { ClusterReceptor clone = new(this.prefab, parent, this.name) { clusterPrefab = this.clusterPrefab, diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index a099a5d..5ffb38f 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -452,10 +452,12 @@ public class ClusterInspector : Editor { Handles.DrawLine(parentPos, pos); Color color = Color.black; if (Application.isPlaying) { - float brightness = length(synapse.nucleus.outputValue) * synapse.weight / maxValue; + if (maxValue == 0 || !float.IsFinite(maxValue)) + maxValue = 1; + float brightness = length(synapse.nucleus.outputValue * synapse.weight) / maxValue; color = new Color(brightness, brightness, brightness, 1f); } - if (synapse.nucleus.parent != null && synapse.nucleus.parent != this.currentNucleus) { + if (synapse.nucleus.parent != null && synapse.nucleus.parent != this.currentNucleus.parent) { // the synapse nucleus is part of a subcluster DrawNucleus(synapse.nucleus.parent, pos, maxValue, size, color); } diff --git a/IReceptor.cs b/IReceptor.cs index 94d9ae2..18c3c35 100644 --- a/IReceptor.cs +++ b/IReceptor.cs @@ -1,5 +1,11 @@ +using UnityEngine; + public interface IReceptor { + public string GetName(); + public NucleusArray array { get; set; } + + public void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName =null); } \ No newline at end of file diff --git a/Receptor.cs b/Receptor.cs index 7ff4011..22d42aa 100644 --- a/Receptor.cs +++ b/Receptor.cs @@ -4,19 +4,29 @@ using static Unity.Mathematics.math; [System.Serializable] public class Receptor : Neuron, IReceptor { - public Receptor(Cluster parent, string name) : base(parent, name) { } - public Receptor(ClusterPrefab prefab, string name) : base(prefab, name) { } + public Receptor(Cluster parent, string name) : base(parent, name) { + this.array ??= new NucleusArray(this); + } + public Receptor(ClusterPrefab prefab, string name) : base(prefab, name) { + this.array ??= new NucleusArray(this); + } + + public string GetName() { + return this.name; + } public override Nucleus ShallowCloneTo(Cluster parent) { - Receptor clone = new(parent, name); + Receptor clone = new(parent, name) { + //array = this.array + }; CloneFields(clone); - clone.array = this.array; return clone; } public override Nucleus Clone(ClusterPrefab prefab) { - Receptor clone = new(prefab, name); + Receptor clone = new(prefab, name) { + //array = this.array + }; CloneFields(clone); - clone.array = this.array; // Adding receivers will also add synapses to the receivers foreach (Nucleus receiver in this.receivers) clone.AddReceiver(receiver); @@ -32,6 +42,7 @@ public class Receptor : Neuron, IReceptor { public override void UpdateStateIsolated() { this.outputValue = this.bias; + //Debug.Log($"Receptor {this.name} outputvalue = {this.outputValue}"); } public override void UpdateNuclei() { diff --git a/Scripts/Experimental/SelectorBrain.cs b/Scripts/Experimental/SelectorBrain.cs deleted file mode 100644 index 08b21f6..0000000 --- a/Scripts/Experimental/SelectorBrain.cs +++ /dev/null @@ -1,23 +0,0 @@ -using UnityEngine; - -public class SelectorBrain : NanoBrain { - public Vector3 input1; - public Vector3 input2; - public Vector3 output; - - public Receptor receptor; - //public Nucleus receptor2; - - protected void Awake() { - receptor = this.brain.GetReceptor("Selector"); - //receptor2 = this.brain.GetNucleus("Selector"); - } - - protected void Update() { - receptor.ProcessStimulus(input1, 0); - receptor.ProcessStimulus(input2, 1); - output = this.brain.outputValue; - - this.brain.UpdateNuclei(); - } -} \ No newline at end of file diff --git a/Scripts/Experimental/SelectorBrain.cs.meta b/Scripts/Experimental/SelectorBrain.cs.meta deleted file mode 100644 index ef88825..0000000 --- a/Scripts/Experimental/SelectorBrain.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 9051408e82b511584998506096af4bf0 \ No newline at end of file From c110a6e72395755555128944ab20f120424c9316 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 18 Feb 2026 17:47:48 +0100 Subject: [PATCH 155/179] Separation works again --- Editor/ClusterInspector.cs | 214 +++++++++++++++++++------------------ NucleusArray.cs | 2 +- 2 files changed, 113 insertions(+), 103 deletions(-) diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 5ffb38f..39e1ad9 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -263,90 +263,92 @@ public class ClusterInspector : Editor { // Draw selected Nucleus if (expandArray) { - if (this.currentNucleus is ReceptorArray receptor) { - float maxValue = 0; - foreach (Nucleus nucleus in receptor.instances) { - float value = length(nucleus.outputValue); - if (value > maxValue) - maxValue = value; - } + // if (this.currentNucleus is ReceptorArray receptor) { + // float maxValue = 0; + // foreach (Nucleus nucleus in receptor.instances) { + // float value = length(nucleus.outputValue); + // if (value > maxValue) + // maxValue = value; + // } - float spacing = 400f / receptor.instances.Count(); - float margin = 10 + spacing / 2; - float xMin = 150 - size; - float xMax = 150 + size; - float yMin = 10 + margin - size / 2; - float yMax = 400 - margin + size; - Vector3[] verts = new Vector3[4] { - new(xMin, yMin, 0), - new(xMax, yMin, 0), - new(xMax, yMax, 0), - new(xMin, yMax, 0) - }; - Handles.color = Color.black; - Handles.DrawAAConvexPolygon(verts); - int row = 0; - foreach (Nucleus nucleus in receptor.instances) { - Vector3 pos = new(150, margin + row * spacing, 0.0f); - Handles.color = Color.white; - // The selected nucleus highlight ring - Handles.DrawSolidDisc(pos, Vector3.forward, size + 2); - DrawNucleus(nucleus, pos, maxValue, size); - row++; - } - } - else if (this.currentNucleus is Receptor receptor1) { - float maxValue = 0; - foreach (Nucleus nucleus in receptor1.array.nuclei) { - float value = length(nucleus.outputValue); - if (value > maxValue) - maxValue = value; - } + // float spacing = 400f / receptor.instances.Count(); + // float margin = 10 + spacing / 2; + // float xMin = 150 - size; + // float xMax = 150 + size; + // float yMin = 10 + margin - size / 2; + // float yMax = 400 - margin + size; + // Vector3[] verts = new Vector3[4] { + // new(xMin, yMin, 0), + // new(xMax, yMin, 0), + // new(xMax, yMax, 0), + // new(xMin, yMax, 0) + // }; + // Handles.color = Color.black; + // Handles.DrawAAConvexPolygon(verts); + // int row = 0; + // foreach (Nucleus nucleus in receptor.instances) { + // Vector3 pos = new(150, margin + row * spacing, 0.0f); + // Handles.color = Color.white; + // // The selected nucleus highlight ring + // Handles.DrawSolidDisc(pos, Vector3.forward, size + 2); + // DrawNucleus(nucleus, pos, maxValue, size); + // row++; + // } + // } + // else + if (this.currentNucleus is IReceptor receptor1) { + float maxValue = 0; + foreach (Nucleus nucleus in receptor1.array.nuclei) { + float value = length(nucleus.outputValue); + if (value > maxValue) + maxValue = value; + } - float spacing = 400f / receptor1.array.nuclei.Count(); - float margin = 10 + spacing / 2; - float xMin = 150 - size; - float xMax = 150 + size; - float yMin = 10 + margin - size / 2; - float yMax = 400 - margin + size; - Vector3[] verts = new Vector3[4] { + float spacing = 400f / receptor1.array.nuclei.Count(); + float margin = 10 + spacing / 2; + float xMin = 150 - size; + float xMax = 150 + size; + float yMin = 10 + margin - size / 2; + float yMax = 400 - margin + size; + Vector3[] verts = new Vector3[4] { new(xMin, yMin, 0), new(xMax, yMin, 0), new(xMax, yMax, 0), new(xMin, yMax, 0) }; - Handles.color = Color.black; - Handles.DrawAAConvexPolygon(verts); - int row = 0; - foreach (Nucleus nucleus in receptor1.array.nuclei) { - Vector3 pos = new(150, margin + row * spacing, 0.0f); + Handles.color = Color.black; + Handles.DrawAAConvexPolygon(verts); + int row = 0; + foreach (Nucleus nucleus in receptor1.array.nuclei) { + Vector3 pos = new(150, margin + row * spacing, 0.0f); + Handles.color = Color.white; + // The selected nucleus highlight ring + Handles.DrawSolidDisc(pos, Vector3.forward, size + 2); + DrawNucleus(nucleus, pos, maxValue, size); + row++; + } + GUIStyle style = new(EditorStyles.label) { + alignment = TextAnchor.UpperCenter, + normal = { textColor = Color.white }, + fontStyle = FontStyle.Bold, + }; + Vector3 labelPos = new(150, yMax + size + 5, 0); + string receptorName = receptor1.GetName(); + int colonPos = receptorName.IndexOf(":"); + if (colonPos > 0) { + string baseName = receptorName[..colonPos]; + Handles.Label(labelPos, baseName, style); + } + else + Handles.Label(labelPos, receptorName, style); + } + else { Handles.color = Color.white; // The selected nucleus highlight ring - Handles.DrawSolidDisc(pos, Vector3.forward, size + 2); - DrawNucleus(nucleus, pos, maxValue, size); - row++; - } - GUIStyle style = new(EditorStyles.label) { - alignment = TextAnchor.UpperCenter, - normal = { textColor = Color.white }, - fontStyle = FontStyle.Bold, - }; - Vector3 labelPos = new(150, yMax + size + 5, 0); - int colonPos = receptor1.name.IndexOf(":"); - if (colonPos > 0) { - string baseName = receptor1.name[..colonPos]; - Handles.Label(labelPos, baseName, style); - } - else - Handles.Label(labelPos, receptor1.name, style); - } - else { - Handles.color = Color.white; - // The selected nucleus highlight ring - Handles.DrawSolidDisc(position, Vector3.forward, size + 2); - DrawNucleus(this.currentNucleus, position, length(this.currentNucleus.outputValue), 20); + Handles.DrawSolidDisc(position, Vector3.forward, size + 2); + DrawNucleus(this.currentNucleus, position, length(this.currentNucleus.outputValue), 20); - } + } } else { Handles.color = Color.white; @@ -502,10 +504,17 @@ public class ClusterInspector : Editor { }; if (nucleus is Receptor receptor1) { - if (receptor1.array == null || receptor1.array.nuclei == null || receptor1.array.nuclei.Count() == 0) - receptor1.array = new NucleusArray(nucleus); - - if ((!expandArray || receptor1.array.nuclei.First() != this.currentNucleus) && receptor1.array.nuclei.Count() > 1) { + // draw the array size label + if (expandArray) { //} && receptor1.array.nuclei.First() == this.currentNucleus) { + style.alignment = TextAnchor.LowerCenter; + Vector3 labelPos1 = position + Vector3.down * (size + 5); // below disc along up axis + int colonPos1 = nucleus.name.IndexOf(":"); + if (colonPos1 > 0) { + string extName = nucleus.name[(colonPos1 + 2)..]; + Handles.Label(labelPos1, extName, style); + } + } + else { if (color.grayscale > 0.5f) style.normal.textColor = Color.black; else @@ -523,13 +532,14 @@ public class ClusterInspector : Editor { // } if (nucleus is ClusterReceptor clusterReceptor) { + // draw the array size label if (expandArray && clusterReceptor.array.nuclei.First() == this.currentNucleus) { style.alignment = TextAnchor.LowerCenter; - Vector3 labelPos = position + Vector3.down * (size + 5); // below disc along up axis - int colonPos = nucleus.name.IndexOf(":"); - if (colonPos > 0) { - string extName = nucleus.name[(colonPos + 2)..]; - Handles.Label(labelPos, extName, style); + Vector3 labelPos2 = position + Vector3.down * (size + 5); // below disc along up axis + int colonPos2 = nucleus.name.IndexOf(":"); + if (colonPos2 > 0) { + string extName = nucleus.name[(colonPos2 + 2)..]; + Handles.Label(labelPos2, extName, style); } } else { @@ -542,26 +552,26 @@ public class ClusterInspector : Editor { } } - if (expandArray && nucleus is Receptor receptor2 && receptor2.array.nuclei.First() == this.currentNucleus) { - style.alignment = TextAnchor.LowerCenter; - Vector3 labelPos = position + Vector3.down * (size + 5); // below disc along up axis - int colonPos = nucleus.name.IndexOf(":"); - if (colonPos > 0) { - string extName = nucleus.name[(colonPos + 2)..]; - Handles.Label(labelPos, extName, style); - } - } - else { - style.alignment = TextAnchor.UpperCenter; - Vector3 labelPos = position - Vector3.down * (size + 5); // below disc along up axis - int colonPos = nucleus.name.IndexOf(":"); - if (colonPos > 0 && colonPos < nucleus.name.Length - 2) { - string baseName = nucleus.name[..colonPos]; - Handles.Label(labelPos, baseName, style); - } - else - Handles.Label(labelPos, nucleus.name, style); + // if (expandArray && nucleus is Receptor receptor2 && receptor2.array.nuclei.First() == this.currentNucleus) { + // style.alignment = TextAnchor.LowerCenter; + // Vector3 labelPos = position + Vector3.down * (size + 5); // below disc along up axis + // int colonPos = nucleus.name.IndexOf(":"); + // if (colonPos > 0) { + // string extName = nucleus.name[(colonPos + 2)..]; + // Handles.Label(labelPos, extName, style); + // } + // } + // else { + style.alignment = TextAnchor.UpperCenter; + Vector3 labelPos = position - Vector3.down * (size + 5); // below disc along up axis + int colonPos = nucleus.name.IndexOf(":"); + if (expandArray || (colonPos > 0 && colonPos < nucleus.name.Length - 2)) { + // string baseName = nucleus.name[..colonPos]; + // Handles.Label(labelPos, baseName, style); } + else + Handles.Label(labelPos, nucleus.name, style); + // } if (nucleus is Cluster) { Handles.color = Color.white; diff --git a/NucleusArray.cs b/NucleusArray.cs index 118f174..2f8fe2d 100644 --- a/NucleusArray.cs +++ b/NucleusArray.cs @@ -38,7 +38,7 @@ public class NucleusArray { newArray[i] = this._nuclei[i]; if (this._nuclei[0] is Nucleus nucleus) { newArray[newLength - 1] = nucleus.Clone(prefab); - newArray[newLength - 1].name += $"{newLength - 1}"; + newArray[newLength - 1].name += $": {newLength - 1}"; } this._nuclei = newArray; From 15b298f39960948cbea0152c2661e6e9a5dfe8c9 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 19 Feb 2026 09:49:00 +0100 Subject: [PATCH 156/179] Add Gaze scene --- Cluster.cs | 13 +-- Editor/ClusterInspector.cs | 161 +++++++++++++++++++------------------ Receptor.cs | 11 +-- 3 files changed, 95 insertions(+), 90 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index 0c0d507..69b9bad 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -169,7 +169,7 @@ public class Cluster : Nucleus { int ix = GetNucleusIndex(this.clusterNuclei.ToArray(), output); if (ix < 0) continue; - + if (clone.clusterNuclei[ix] is not Neuron clonedOutput) continue; @@ -226,7 +226,7 @@ public class Cluster : Nucleus { } } - + } protected int GetNucleusIndex(Nucleus[] nuclei, Nucleus nucleus) { @@ -240,7 +240,7 @@ public class Cluster : Nucleus { protected int GetNucleusIndex(List nuclei, Nucleus nucleus) { int i = 0; foreach (Nucleus nucleiElement in nuclei) { - //for (int i = 0; i < nuclei.Length; i++) { + //for (int i = 0; i < nuclei.Length; i++) { if (nucleus == nucleiElement) return i; } @@ -420,10 +420,13 @@ public class Cluster : Nucleus { } public IReceptor GetReceptor(string receptorName) { + string receptorName0 = receptorName + ": 0"; foreach (Nucleus nucleus in this.clusterNuclei) { - if (nucleus is IReceptor receptor) - if (receptor.GetName() == receptorName) + if (nucleus is IReceptor receptor) { + if (nucleus.name == receptorName | nucleus.name == receptorName0) + //if (receptor.GetName() == receptorName) return receptor; + } } return null; } diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 39e1ad9..d8319c6 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -108,11 +108,13 @@ public class ClusterInspector : Editor { }; List names = this.prefab.outputs.Select(output => output.name).ToList(); - outputsField = new(names, names.First()) { - style = { flexGrow = 1 } - }; - outputsField.RegisterValueChangedCallback(evt => OnOutputChanged(evt.newValue)); - outputContainer.Add(outputsField); + if (names.Count > 0 && names.First() != null) { + outputsField = new(names, names.First()) { + style = { flexGrow = 1 } + }; + outputsField.RegisterValueChangedCallback(evt => OnOutputChanged(evt.newValue)); + outputContainer.Add(outputsField); + } Button addButton = new(() => OnAddClusterOutput()) { text = "Add" @@ -271,84 +273,84 @@ public class ClusterInspector : Editor { // maxValue = value; // } - // float spacing = 400f / receptor.instances.Count(); - // float margin = 10 + spacing / 2; - // float xMin = 150 - size; - // float xMax = 150 + size; - // float yMin = 10 + margin - size / 2; - // float yMax = 400 - margin + size; - // Vector3[] verts = new Vector3[4] { - // new(xMin, yMin, 0), - // new(xMax, yMin, 0), - // new(xMax, yMax, 0), - // new(xMin, yMax, 0) - // }; - // Handles.color = Color.black; - // Handles.DrawAAConvexPolygon(verts); - // int row = 0; - // foreach (Nucleus nucleus in receptor.instances) { - // Vector3 pos = new(150, margin + row * spacing, 0.0f); - // Handles.color = Color.white; - // // The selected nucleus highlight ring - // Handles.DrawSolidDisc(pos, Vector3.forward, size + 2); - // DrawNucleus(nucleus, pos, maxValue, size); - // row++; - // } - // } - // else - if (this.currentNucleus is IReceptor receptor1) { - float maxValue = 0; - foreach (Nucleus nucleus in receptor1.array.nuclei) { - float value = length(nucleus.outputValue); - if (value > maxValue) - maxValue = value; - } + // float spacing = 400f / receptor.instances.Count(); + // float margin = 10 + spacing / 2; + // float xMin = 150 - size; + // float xMax = 150 + size; + // float yMin = 10 + margin - size / 2; + // float yMax = 400 - margin + size; + // Vector3[] verts = new Vector3[4] { + // new(xMin, yMin, 0), + // new(xMax, yMin, 0), + // new(xMax, yMax, 0), + // new(xMin, yMax, 0) + // }; + // Handles.color = Color.black; + // Handles.DrawAAConvexPolygon(verts); + // int row = 0; + // foreach (Nucleus nucleus in receptor.instances) { + // Vector3 pos = new(150, margin + row * spacing, 0.0f); + // Handles.color = Color.white; + // // The selected nucleus highlight ring + // Handles.DrawSolidDisc(pos, Vector3.forward, size + 2); + // DrawNucleus(nucleus, pos, maxValue, size); + // row++; + // } + // } + // else + if (this.currentNucleus is IReceptor receptor1) { + float maxValue = 0; + foreach (Nucleus nucleus in receptor1.array.nuclei) { + float value = length(nucleus.outputValue); + if (value > maxValue) + maxValue = value; + } - float spacing = 400f / receptor1.array.nuclei.Count(); - float margin = 10 + spacing / 2; - float xMin = 150 - size; - float xMax = 150 + size; - float yMin = 10 + margin - size / 2; - float yMax = 400 - margin + size; - Vector3[] verts = new Vector3[4] { + float spacing = 400f / receptor1.array.nuclei.Count(); + float margin = 10 + spacing / 2; + float xMin = 150 - size; + float xMax = 150 + size; + float yMin = 10 + margin - size / 2; + float yMax = 400 - margin + size; + Vector3[] verts = new Vector3[4] { new(xMin, yMin, 0), new(xMax, yMin, 0), new(xMax, yMax, 0), new(xMin, yMax, 0) }; - Handles.color = Color.black; - Handles.DrawAAConvexPolygon(verts); - int row = 0; - foreach (Nucleus nucleus in receptor1.array.nuclei) { - Vector3 pos = new(150, margin + row * spacing, 0.0f); - Handles.color = Color.white; - // The selected nucleus highlight ring - Handles.DrawSolidDisc(pos, Vector3.forward, size + 2); - DrawNucleus(nucleus, pos, maxValue, size); - row++; - } - GUIStyle style = new(EditorStyles.label) { - alignment = TextAnchor.UpperCenter, - normal = { textColor = Color.white }, - fontStyle = FontStyle.Bold, - }; - Vector3 labelPos = new(150, yMax + size + 5, 0); - string receptorName = receptor1.GetName(); - int colonPos = receptorName.IndexOf(":"); - if (colonPos > 0) { - string baseName = receptorName[..colonPos]; - Handles.Label(labelPos, baseName, style); - } - else - Handles.Label(labelPos, receptorName, style); - } - else { + Handles.color = Color.black; + Handles.DrawAAConvexPolygon(verts); + int row = 0; + foreach (Nucleus nucleus in receptor1.array.nuclei) { + Vector3 pos = new(150, margin + row * spacing, 0.0f); Handles.color = Color.white; // The selected nucleus highlight ring - Handles.DrawSolidDisc(position, Vector3.forward, size + 2); - DrawNucleus(this.currentNucleus, position, length(this.currentNucleus.outputValue), 20); - + Handles.DrawSolidDisc(pos, Vector3.forward, size + 2); + DrawNucleus(nucleus, pos, maxValue, size); + row++; } + GUIStyle style = new(EditorStyles.label) { + alignment = TextAnchor.UpperCenter, + normal = { textColor = Color.white }, + fontStyle = FontStyle.Bold, + }; + Vector3 labelPos = new(150, yMax + size + 5, 0); + string receptorName = receptor1.GetName(); + int colonPos = receptorName.IndexOf(":"); + if (colonPos > 0) { + string baseName = receptorName[..colonPos]; + Handles.Label(labelPos, baseName, style); + } + else + Handles.Label(labelPos, receptorName, style); + } + else { + Handles.color = Color.white; + // The selected nucleus highlight ring + Handles.DrawSolidDisc(position, Vector3.forward, size + 2); + DrawNucleus(this.currentNucleus, position, length(this.currentNucleus.outputValue), 20); + + } } else { Handles.color = Color.white; @@ -565,7 +567,7 @@ public class ClusterInspector : Editor { style.alignment = TextAnchor.UpperCenter; Vector3 labelPos = position - Vector3.down * (size + 5); // below disc along up axis int colonPos = nucleus.name.IndexOf(":"); - if (expandArray || (colonPos > 0 && colonPos < nucleus.name.Length - 2)) { + if (expandArray && nucleus is Receptor) { //} || (colonPos > 0 && colonPos < nucleus.name.Length - 2)) { // string baseName = nucleus.name[..colonPos]; // Handles.Label(labelPos, baseName, style); } @@ -614,14 +616,17 @@ public class ClusterInspector : Editor { if (nucleus == this.currentNucleus) { if (nucleus is Receptor || nucleus is ClusterReceptor) expandArray = !expandArray; + else + expandArray = false; } else if (nucleus is ReceptorInstance receptor) { - expandArray = false; this.currentNucleus = receptor.receptor; + expandArray = false; BuildLayers(); } - else if (nucleus is Nucleus n) { - this.currentNucleus = n; + else { + this.currentNucleus = nucleus; + expandArray = false; BuildLayers(); } } diff --git a/Receptor.cs b/Receptor.cs index 22d42aa..577caec 100644 --- a/Receptor.cs +++ b/Receptor.cs @@ -6,6 +6,8 @@ using static Unity.Mathematics.math; public class Receptor : Neuron, IReceptor { public Receptor(Cluster parent, string name) : base(parent, name) { this.array ??= new NucleusArray(this); + if (this.name.IndexOf(":") < 0) + this.name += ": 0"; } public Receptor(ClusterPrefab prefab, string name) : base(prefab, name) { this.array ??= new NucleusArray(this); @@ -16,20 +18,15 @@ public class Receptor : Neuron, IReceptor { } public override Nucleus ShallowCloneTo(Cluster parent) { - Receptor clone = new(parent, name) { - //array = this.array - }; + Receptor clone = new(parent, name); CloneFields(clone); return clone; } public override Nucleus Clone(ClusterPrefab prefab) { Receptor clone = new(prefab, name) { - //array = this.array + array = this.array }; CloneFields(clone); - // Adding receivers will also add synapses to the receivers - foreach (Nucleus receiver in this.receivers) - clone.AddReceiver(receiver); return clone; } From 116a5819e00205849b400f63afb26ecd3e20d1fc Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 19 Feb 2026 11:44:50 +0100 Subject: [PATCH 157/179] First gaze version --- Neuron.cs | 22 ++++----- Receptor.cs | 16 ++++++- Selector.asset | 106 -------------------------------------------- Selector.asset.meta | 8 ---- 4 files changed, 26 insertions(+), 126 deletions(-) delete mode 100644 Selector.asset delete mode 100644 Selector.asset.meta diff --git a/Neuron.cs b/Neuron.cs index 2f5e0f3..31f033a 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -278,19 +278,19 @@ public class Neuron : Nucleus { set { _receivers = value; } } - public virtual void AddReceiver(Nucleus receiverToAdd, float weight = 1) { - if (this is IReceptor receptor) { - foreach (Nucleus element in receptor.array.nuclei) { - if (element is Neuron neuron) { - neuron._receivers.Add(receiverToAdd); - receiverToAdd.AddSynapse(element, weight); - } - } - } - else { + public virtual void AddReceiver(Nucleus receiverToAdd, float weight = 1) { + // if (this is IReceptor receptor) { + // foreach (Nucleus element in receptor.array.nuclei) { + // if (element is Neuron neuron) { + // neuron._receivers.Add(receiverToAdd); + // receiverToAdd.AddSynapse(element, weight); + // } + // } + // } + // else { this._receivers.Add(receiverToAdd); receiverToAdd.AddSynapse(this, weight); - } + // } } public virtual void RemoveReceiver(Nucleus receiverToRemove) { diff --git a/Receptor.cs b/Receptor.cs index 577caec..36e33ca 100644 --- a/Receptor.cs +++ b/Receptor.cs @@ -18,7 +18,9 @@ public class Receptor : Neuron, IReceptor { } public override Nucleus ShallowCloneTo(Cluster parent) { - Receptor clone = new(parent, name); + Receptor clone = new(parent, name) { + + }; CloneFields(clone); return clone; } @@ -27,6 +29,10 @@ public class Receptor : Neuron, IReceptor { array = this.array }; CloneFields(clone); + // Adding receivers will also add synapses to the receivers + foreach (Nucleus receiver in this.receivers.ToArray()) + clone.AddReceiver(receiver); + return clone; } @@ -37,6 +43,14 @@ public class Receptor : Neuron, IReceptor { set { _array = value; } } + public virtual void AddArrayReceiver(Nucleus receiverToAdd, float weight = 1) { + foreach (Nucleus element in this.array.nuclei) { + if (element is Neuron neuron) { + neuron.AddReceiver(receiverToAdd, weight); + } + } + } + public override void UpdateStateIsolated() { this.outputValue = this.bias; //Debug.Log($"Receptor {this.name} outputvalue = {this.outputValue}"); diff --git a/Selector.asset b/Selector.asset deleted file mode 100644 index a1bfc0c..0000000 --- a/Selector.asset +++ /dev/null @@ -1,106 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3} - m_Name: Selector - m_EditorClassIdentifier: Assembly-CSharp::ClusterPrefab - nuclei: - - rid: 5479437130421501952 - - rid: 5479437186280456251 - references: - version: 2 - RefIds: - - rid: 5479437130421501952 - type: {class: Neuron, ns: , asm: Assembly-CSharp} - data: - _name: Output - _synapses: - - nucleus: - rid: 5479437186280456251 - weight: 1 - _receivers: [] - _array: - rid: 5479437130421501953 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 1 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1000 - value: 1000 - inSlope: 1 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 1 - - rid: 5479437130421501953 - type: {class: NucleusArray, ns: , asm: Assembly-CSharp} - data: - _nuclei: - - rid: 5479437130421501952 - name: Output - - rid: 5479437186280456251 - type: {class: Selector, ns: , asm: Assembly-CSharp} - data: - _name: Selector - _synapses: [] - _receivers: - - rid: 5479437130421501952 - _array: - rid: 5479437186280456252 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 1 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1000 - value: 1000 - inSlope: 1 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - - rid: 5479437186280456252 - type: {class: NucleusArray, ns: , asm: Assembly-CSharp} - data: - _nuclei: - - rid: 5479437186280456251 - name: New Selector diff --git a/Selector.asset.meta b/Selector.asset.meta deleted file mode 100644 index 2365967..0000000 --- a/Selector.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: d5b3a22d9bb7d13aeb3174077125967b -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: From d2b5d2feacbd81c0b1526d8159681e7f68e222da Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 19 Feb 2026 12:13:02 +0100 Subject: [PATCH 158/179] Step to get rid of NucleusArray --- Cluster.cs | 12 ++++----- ClusterReceptor.cs | 15 +++++++++++ Editor/ClusterInspector.cs | 54 ++++++++++++++++++++------------------ IReceptor.cs | 46 +++++++++++++++++++++++++++++--- Neuron.cs | 2 +- NucleusArray.cs | 5 +++- Receptor.cs | 26 +++++++++++++----- 7 files changed, 116 insertions(+), 44 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index 69b9bad..3f0df80 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -84,15 +84,15 @@ public class Cluster : Nucleus { if (prefabReceptor is not Receptor prefabNucleus) continue; - if (prefabNucleus.array == null || prefabNucleus.array.nuclei == null || prefabNucleus.array.nuclei.Length == 0) + if (prefabNucleus.nucleiArray == null || prefabNucleus.nucleiArray.Length == 0) continue; Receptor clonedNucleus = clonedNuclei[nucleusIx] as Receptor; - if (prefabNucleus == prefabNucleus.array.nuclei[0]) { + if (prefabNucleus == prefabNucleus.nucleiArray[0]) { // We clone the array only for the first entry - NucleusArray clonedArray = new(prefabNucleus.array.nuclei.Length, "array"); + NucleusArray clonedArray = new(prefabNucleus.nucleiArray.Length, "array"); int arrayIx = 0; - foreach (Nucleus prefabArrayNucleus in prefabNucleus.array.nuclei) { + foreach (Nucleus prefabArrayNucleus in prefabNucleus.nucleiArray) { int arrayNucleusIx = GetNucleusIndex(prefabNuclei, prefabArrayNucleus); if (arrayNucleusIx >= 0) { Nucleus clonedArrayNucleus = clonedNuclei[arrayNucleusIx]; @@ -107,9 +107,9 @@ public class Cluster : Nucleus { } else { // The others will refer to the array created for the first nucleus in the array - int firstNucleusIx = GetNucleusIndex(prefabNuclei, prefabNucleus.array.nuclei[0]); + int firstNucleusIx = GetNucleusIndex(prefabNuclei, prefabNucleus.nucleiArray[0]); Receptor clonedFirstNucleus = clonedNuclei[firstNucleusIx] as Receptor; - clonedNucleus.array = clonedFirstNucleus.array; + clonedNucleus.nucleiArray = clonedFirstNucleus.nucleiArray; } } } diff --git a/ClusterReceptor.cs b/ClusterReceptor.cs index f5bb1ad..3df0d35 100644 --- a/ClusterReceptor.cs +++ b/ClusterReceptor.cs @@ -65,6 +65,21 @@ public class ClusterReceptor : Cluster, IReceptor { set { _array = value; } } + //[SerializeReference] + //private Nucleus[] _nucleusArray; + public Nucleus[] nucleiArray { + get { return _array.nuclei; } + set { _array.nuclei = value; } + } + + public void AddReceptorElement(ClusterPrefab prefab) { + this.nucleiArray = IReceptorHelpers.AddReceptorElement(this.nucleiArray, prefab); + } + + public void RemoveReceptorElement() { + this.nucleiArray = IReceptorHelpers.RemoveReceptorElement(this.nucleiArray); + } + public override void UpdateStateIsolated() { float3 sum = this.bias; diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index d8319c6..b175124 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -300,13 +300,13 @@ public class ClusterInspector : Editor { // else if (this.currentNucleus is IReceptor receptor1) { float maxValue = 0; - foreach (Nucleus nucleus in receptor1.array.nuclei) { + foreach (Nucleus nucleus in receptor1.nucleiArray) { float value = length(nucleus.outputValue); if (value > maxValue) maxValue = value; } - float spacing = 400f / receptor1.array.nuclei.Count(); + float spacing = 400f / receptor1.nucleiArray.Count(); float margin = 10 + spacing / 2; float xMin = 150 - size; float xMax = 150 + size; @@ -321,7 +321,7 @@ public class ClusterInspector : Editor { Handles.color = Color.black; Handles.DrawAAConvexPolygon(verts); int row = 0; - foreach (Nucleus nucleus in receptor1.array.nuclei) { + foreach (Nucleus nucleus in receptor1.nucleiArray) { Vector3 pos = new(150, margin + row * spacing, 0.0f); Handles.color = Color.white; // The selected nucleus highlight ring @@ -387,12 +387,12 @@ public class ClusterInspector : Editor { float margin = 10 + spacing / 2; int row = 0; - List drawnArrays = new(); + List drawnArrays = new(); foreach (Nucleus receiver in receivers) { if (receiver is Receptor receptor) { - if (drawnArrays.Contains(receptor.array)) + if (drawnArrays.Contains(receptor.nucleiArray)) continue; - drawnArrays.Add(receptor.array); + drawnArrays.Add(receptor.nucleiArray); } Nucleus receiverNucleus = receiver; @@ -415,17 +415,17 @@ public class ClusterInspector : Editor { // This is used to 'scale' the output value colors of the nuclei float maxValue = 0; int neuronCount = 0; - List drawnArrays = new(); + List drawnArrays = new(); foreach (Synapse synapse in nucleus.synapses) { if (synapse.nucleus is Receptor receptor) { - if (drawnArrays.Contains(receptor.array)) + if (drawnArrays.Contains(receptor.nucleiArray)) continue; - drawnArrays.Add(receptor.array); + drawnArrays.Add(receptor.nucleiArray); } else if (synapse.nucleus.parent is ClusterReceptor clusterReceptor) { - if (drawnArrays.Contains(clusterReceptor.array)) + if (drawnArrays.Contains(clusterReceptor.nucleiArray)) continue; - drawnArrays.Add(clusterReceptor.array); + drawnArrays.Add(clusterReceptor.nucleiArray); } float value = length(synapse.nucleus.outputValue) * synapse.weight; // Debug.Log($"{synapse.nucleus.name}: {value} {length(synapse.nucleus.outputValue)} {synapse.weight}"); @@ -442,14 +442,14 @@ public class ClusterInspector : Editor { drawnArrays = new(); foreach (Synapse synapse in nucleus.synapses) { if (synapse.nucleus is Receptor neuron) { - if (drawnArrays.Contains(neuron.array)) + if (drawnArrays.Contains(neuron.nucleiArray)) continue; - drawnArrays.Add(neuron.array); + drawnArrays.Add(neuron.nucleiArray); } else if (synapse.nucleus.parent is ClusterReceptor clusterReceptor) { - if (drawnArrays.Contains(clusterReceptor.array)) + if (drawnArrays.Contains(clusterReceptor.nucleiArray)) continue; - drawnArrays.Add(clusterReceptor.array); + drawnArrays.Add(clusterReceptor.nucleiArray); } Vector3 pos = new(250, margin + row * spacing, 0.0f); Handles.color = Color.white; @@ -521,7 +521,7 @@ public class ClusterInspector : Editor { style.normal.textColor = Color.black; else style.normal.textColor = Color.white; - Handles.Label(labelPosition, receptor1.array.nuclei.Length.ToString(), style); + Handles.Label(labelPosition, receptor1.nucleiArray.Length.ToString(), style); style.normal.textColor = Color.white; } } @@ -704,15 +704,17 @@ public class ClusterInspector : Editor { } if (this.currentNucleus is Receptor receptor1) { EditorGUILayout.BeginHorizontal(); - EditorGUILayout.IntField("Array size", receptor1.array.nuclei.Count()); + EditorGUILayout.IntField("Array size", receptor1.nucleiArray.Count()); if (GUILayout.Button("Add")) { Undo.RecordObject(prefabAsset, "Array add " + prefabAsset.name); - receptor1.array.AddNucleus(this.prefab); + //receptor1.array.AddNucleus(this.prefab); + receptor1.AddReceptorElement(this.prefab); anythingChanged = true; } if (GUILayout.Button("Del")) { Undo.RecordObject(prefabAsset, "Array delete " + prefabAsset.name); - receptor1.array.RemoveNucleus(); + //receptor1.array.RemoveNucleus(); + receptor1.RemoveReceptorElement(); anythingChanged = true; } EditorGUILayout.EndHorizontal(); @@ -754,7 +756,7 @@ public class ClusterInspector : Editor { anythingChanged |= newBias != this.currentNucleus.bias; this.currentNucleus.bias = newBias; - NucleusArray array = null; + Nucleus[] array = null; if (this.currentNucleus.synapses.Count > 0) { Synapse[] synapses = this.currentNucleus.synapses.ToArray(); foreach (Synapse synapse in synapses) { @@ -762,16 +764,16 @@ public class ClusterInspector : Editor { continue; if (array != null) { - if (array.nuclei.Contains(synapse.nucleus)) + if (array.Contains(synapse.nucleus)) continue; - if (array.nuclei.Contains(synapse.nucleus.parent)) + if (array.Contains(synapse.nucleus.parent)) continue; } else { if (synapse.nucleus.parent is ClusterReceptor clusterReceptor) - array = clusterReceptor.array; + array = clusterReceptor.nucleiArray; else if (synapse.nucleus is Receptor receptor2) // && receptor2.array != null && receptor2.array.nuclei.Length > 1) - array = receptor2.array; + array = receptor2.nucleiArray; } EditorGUILayout.Space(); @@ -832,7 +834,7 @@ public class ClusterInspector : Editor { EditorGUILayout.EndHorizontal(); } if (neuron is Receptor receptor2) { - if (receptor2.array == null || receptor2.array.nuclei == null || receptor2.array.nuclei.Count() == 0) + if (receptor2.nucleiArray == null || receptor2.nucleiArray.Count() == 0) receptor2.array = new NucleusArray(neuron); } } @@ -877,7 +879,7 @@ public class ClusterInspector : Editor { } else { if (this.currentNucleus is Receptor receptor1) { - foreach (Nucleus nucleus in receptor1.array.nuclei) { + foreach (Nucleus nucleus in receptor1.nucleiArray) { Vector3 worldVector = this.gameObject.transform.TransformVector(nucleus.outputValue); Handles.color = Color.yellow; Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); diff --git a/IReceptor.cs b/IReceptor.cs index 18c3c35..08bb505 100644 --- a/IReceptor.cs +++ b/IReceptor.cs @@ -3,9 +3,49 @@ using UnityEngine; public interface IReceptor { public string GetName(); - public NucleusArray array { - get; set; + // public NucleusArray array { + // get; set; + // } + public Nucleus[] nucleiArray { get; set; } + + public void AddReceptorElement(ClusterPrefab prefab); + public void RemoveReceptorElement(); + + public void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null); +} + +public static class IReceptorHelpers { + public static Nucleus[] AddReceptorElement(Nucleus[] nucleiArray, ClusterPrefab prefab) { + if (nucleiArray.Length == 0) { + Debug.LogError("Empty perceptoid array, cannot add"); + return null; + } + int newLength = nucleiArray.Length + 1; + Nucleus[] newArray = new Nucleus[newLength]; + + for (int i = 0; i < nucleiArray.Length; i++) + newArray[i] = nucleiArray[i]; + if (nucleiArray[0] is Nucleus nucleus) { + newArray[newLength - 1] = nucleus.Clone(prefab); + newArray[newLength - 1].name += $": {newLength - 1}"; + } + + return newArray; } - public void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName =null); + public static Nucleus[] RemoveReceptorElement(Nucleus[] nucleiArray) { + int newLength = nucleiArray.Length - 1; + if (newLength == 0) { + Debug.LogWarning("Perceptoid array cannot be empty"); + return null; + } + Nucleus[] newPerceptei = new Nucleus[newLength]; + for (int i = 0; i < newLength; i++) + newPerceptei[i] = nucleiArray[i]; + // Delete the last perception + if (nucleiArray[newLength] is Nucleus nucleus) + Neuron.Delete(nucleus); //this._nuclei[newLength]); + + return newPerceptei; + } } \ No newline at end of file diff --git a/Neuron.cs b/Neuron.cs index 31f033a..7822ba8 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -295,7 +295,7 @@ public class Neuron : Nucleus { public virtual void RemoveReceiver(Nucleus receiverToRemove) { if (this is IReceptor receptor) { - foreach (Nucleus element in receptor.array.nuclei) { + foreach (Nucleus element in receptor.nucleiArray) { if (element is Neuron neuron) { neuron._receivers.RemoveAll(receiver => receiver == receiverToRemove); receiverToRemove.synapses.RemoveAll(synapse => synapse.nucleus == neuron); diff --git a/NucleusArray.cs b/NucleusArray.cs index 2f8fe2d..b3651df 100644 --- a/NucleusArray.cs +++ b/NucleusArray.cs @@ -12,6 +12,9 @@ public class NucleusArray { get { return _nuclei; } + set { + _nuclei = value; + } } public NucleusArray(Nucleus nucleus) { @@ -68,7 +71,7 @@ public class NucleusArray { float inputMagnitude = length(inputValue); Nucleus selectedReceiver = null; float selectedMagnitude = 0; - foreach (Nucleus receiver in this.nuclei) { + foreach (Nucleus receiver in this._nuclei) { if (thingReceivers.ContainsValue(receiver) == false) { // We found an unusued receiver thingReceivers.Add(thingId, receiver); diff --git a/Receptor.cs b/Receptor.cs index 36e33ca..2547f36 100644 --- a/Receptor.cs +++ b/Receptor.cs @@ -5,12 +5,12 @@ using static Unity.Mathematics.math; [System.Serializable] public class Receptor : Neuron, IReceptor { public Receptor(Cluster parent, string name) : base(parent, name) { - this.array ??= new NucleusArray(this); + this.array = new NucleusArray(this); if (this.name.IndexOf(":") < 0) this.name += ": 0"; } public Receptor(ClusterPrefab prefab, string name) : base(prefab, name) { - this.array ??= new NucleusArray(this); + this.array = new NucleusArray(this); } public string GetName() { @@ -26,7 +26,7 @@ public class Receptor : Neuron, IReceptor { } public override Nucleus Clone(ClusterPrefab prefab) { Receptor clone = new(prefab, name) { - array = this.array + array = this._array }; CloneFields(clone); // Adding receivers will also add synapses to the receivers @@ -39,12 +39,24 @@ public class Receptor : Neuron, IReceptor { [SerializeReference] private NucleusArray _array; public NucleusArray array { - get { return _array; } set { _array = value; } } + public Nucleus[] nucleiArray { + get { return _array.nuclei; } + set { _array.nuclei = value; } + } + + public void AddReceptorElement(ClusterPrefab prefab) { + this.nucleiArray = IReceptorHelpers.AddReceptorElement(this.nucleiArray, prefab); + } + + public void RemoveReceptorElement() { + this.nucleiArray = IReceptorHelpers.RemoveReceptorElement(this.nucleiArray); + } + public virtual void AddArrayReceiver(Nucleus receiverToAdd, float weight = 1) { - foreach (Nucleus element in this.array.nuclei) { + foreach (Nucleus element in this._array.nuclei) { if (element is Neuron neuron) { neuron.AddReceiver(receiverToAdd, weight); } @@ -65,7 +77,7 @@ public class Receptor : Neuron, IReceptor { } public virtual void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) { - this.array ??= new NucleusArray(this.parent); - this.array.ProcessStimulus(thingId, inputValue, thingName); + this._array ??= new NucleusArray(this.parent); + this._array.ProcessStimulus(thingId, inputValue, thingName); } } \ No newline at end of file From 2ef9629e4ddeaeacceb700d196a05b38f02643eb Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 19 Feb 2026 16:35:57 +0100 Subject: [PATCH 159/179] Enable stimulus processing in any nucleus --- Cluster.cs | 18 ++++----- Editor/ClusterInspector.cs | 43 +++++++------------- Editor/NanoBrain_Editor.cs | 6 ++- Neuroid.cs | 82 -------------------------------------- Neuroid.cs.meta | 2 - Neuron.cs | 12 ++++-- Nucleus.cs | 5 ++- NucleusArray.cs | 7 +++- Receptor.cs | 2 +- ReceptorArray.cs | 2 +- 10 files changed, 46 insertions(+), 133 deletions(-) delete mode 100644 Neuroid.cs delete mode 100644 Neuroid.cs.meta diff --git a/Cluster.cs b/Cluster.cs index 3f0df80..c605d76 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -412,23 +412,21 @@ public class Cluster : Nucleus { } public Nucleus GetNucleus(string nucleusName) { + string nucleusName0 = nucleusName + ": 0"; foreach (Nucleus nucleus in this.clusterNuclei) { - if (nucleus.name == nucleusName) + if (nucleus is IReceptor receptor) { + if (nucleus.name == nucleusName | nucleus.name == nucleusName0) + return nucleus; + } + else if (nucleus.name == nucleusName) return nucleus; } return null; } + [Obsolete("Use GetNucleus instead")] public IReceptor GetReceptor(string receptorName) { - string receptorName0 = receptorName + ": 0"; - foreach (Nucleus nucleus in this.clusterNuclei) { - if (nucleus is IReceptor receptor) { - if (nucleus.name == receptorName | nucleus.name == receptorName0) - //if (receptor.GetName() == receptorName) - return receptor; - } - } - return null; + return GetNucleus(receptorName) as IReceptor; } #region Receivers diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index b175124..f0b9948 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -507,9 +507,9 @@ public class ClusterInspector : Editor { if (nucleus is Receptor receptor1) { // draw the array size label - if (expandArray) { //} && receptor1.array.nuclei.First() == this.currentNucleus) { + if (expandArray) { style.alignment = TextAnchor.LowerCenter; - Vector3 labelPos1 = position + Vector3.down * (size + 5); // below disc along up axis + Vector3 labelPos1 = position + Vector3.down * (size + 5); // below disc int colonPos1 = nucleus.name.IndexOf(":"); if (colonPos1 > 0) { string extName = nucleus.name[(colonPos1 + 2)..]; @@ -525,19 +525,12 @@ public class ClusterInspector : Editor { style.normal.textColor = Color.white; } } - // if (nucleus is ReceptorArray receptor) { - // if (color.grayscale > 0.5f) - // style.normal.textColor = Color.black; - // else - // style.normal.textColor = Color.white; - // Handles.Label(labelPosition, receptor.instances.Count().ToString(), style); - // } if (nucleus is ClusterReceptor clusterReceptor) { // draw the array size label if (expandArray && clusterReceptor.array.nuclei.First() == this.currentNucleus) { style.alignment = TextAnchor.LowerCenter; - Vector3 labelPos2 = position + Vector3.down * (size + 5); // below disc along up axis + Vector3 labelPos2 = position + Vector3.down * (size + 5); // below disc int colonPos2 = nucleus.name.IndexOf(":"); if (colonPos2 > 0) { string extName = nucleus.name[(colonPos2 + 2)..]; @@ -554,25 +547,19 @@ public class ClusterInspector : Editor { } } - // if (expandArray && nucleus is Receptor receptor2 && receptor2.array.nuclei.First() == this.currentNucleus) { - // style.alignment = TextAnchor.LowerCenter; - // Vector3 labelPos = position + Vector3.down * (size + 5); // below disc along up axis - // int colonPos = nucleus.name.IndexOf(":"); - // if (colonPos > 0) { - // string extName = nucleus.name[(colonPos + 2)..]; - // Handles.Label(labelPos, extName, style); - // } - // } - // else { - style.alignment = TextAnchor.UpperCenter; - Vector3 labelPos = position - Vector3.down * (size + 5); // below disc along up axis - int colonPos = nucleus.name.IndexOf(":"); - if (expandArray && nucleus is Receptor) { //} || (colonPos > 0 && colonPos < nucleus.name.Length - 2)) { - // string baseName = nucleus.name[..colonPos]; - // Handles.Label(labelPos, baseName, style); + if (!expandArray || nucleus is not Receptor) { + Vector3 labelPos = position - Vector3.down * (size + 5); // below neuron + style.alignment = TextAnchor.UpperCenter; + + int colonPos = nucleus.name.IndexOf(":"); + if (colonPos > 0 && colonPos < nucleus.name.Length - 2) { + string baseName = nucleus.name[..colonPos]; + Handles.Label(labelPos, baseName, style); + } + else + Handles.Label(labelPos, nucleus.name, style); + } - else - Handles.Label(labelPos, nucleus.name, style); // } if (nucleus is Cluster) { diff --git a/Editor/NanoBrain_Editor.cs b/Editor/NanoBrain_Editor.cs index 4dcb4c5..164e1db 100644 --- a/Editor/NanoBrain_Editor.cs +++ b/Editor/NanoBrain_Editor.cs @@ -17,8 +17,10 @@ public class NanoBrainComponent_Editor : Editor { public void OnEnable() { component = target as NanoBrain; - if (Application.isPlaying == false) - brainProp = serializedObject.FindProperty(nameof(NanoBrain.defaultBrain)); + if (Application.isPlaying == false && serializedObject != null) { + string propertyName = nameof(NanoBrain.defaultBrain); + brainProp = serializedObject.FindProperty(propertyName); + } } public override VisualElement CreateInspectorGUI() { diff --git a/Neuroid.cs b/Neuroid.cs deleted file mode 100644 index d4a64f2..0000000 --- a/Neuroid.cs +++ /dev/null @@ -1,82 +0,0 @@ -/* -using UnityEngine; -using Unity.Mathematics; -using static Unity.Mathematics.math; - -[System.Serializable] -public class Neuroid : Neuron { - - public bool average = false; - - public Neuroid(Cluster brain, string name) : base(name) { - this.cluster = brain; - if (this.cluster != null) { - this.cluster.nuclei.Add(this); - } - else - Debug.LogError("No neuroid network"); - } - - public Neuroid(string name) : base(name) { } - - public override INucleus Clone() { - Neuroid clone = new(this.name) { - cluster = this.cluster, - array = this.array, - curve = this.curve, - curvePreset = this.curvePreset, - curveMax = this.curveMax, - average = this.average - }; - if (clone.cluster != null) - clone.cluster.nuclei.Add(clone); - - foreach (Synapse synapse in this.synapses) { - Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); - clonedSynapse.weight = synapse.weight; - } - foreach (INucleus receiver in this.receivers) { - clone.AddReceiver(receiver); - } - return clone; - } - - public override void UpdateState() { - float3 sum = new(0, 0, 0); - int n = 0; - - //Applying the weight factgors - foreach (Synapse synapse in this.synapses) { - sum = sum + (synapse.weight * synapse.nucleus.outputValue); - if (lengthsq(synapse.nucleus.outputValue) != 0) - n++; - } - if (average) - sum /= n; - - // Activation function - Vector3 result; - switch (this.curvePreset) { - case CurvePresets.Linear: - result = sum; - break; - case CurvePresets.Sqrt: - result = normalize(sum) * System.MathF.Sqrt(length(sum)); - break; - case CurvePresets.Power: - result = normalize(sum) * System.MathF.Pow(length(sum), 2); - break; - case CurvePresets.Reciprocal: - result = normalize(sum) * (1 / length(sum)); - break; - default: - float activatedValue = this.curve.Evaluate(length(sum)); - result = normalize(sum) * activatedValue; - break; - } - UpdateResult(result); - } - -} - -*/ \ No newline at end of file diff --git a/Neuroid.cs.meta b/Neuroid.cs.meta deleted file mode 100644 index 1c633f0..0000000 --- a/Neuroid.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 771f64aec709af240a39b1d918bbc829 \ No newline at end of file diff --git a/Neuron.cs b/Neuron.cs index 7822ba8..5b33597 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -230,7 +230,7 @@ public class Neuron : Nucleus { #region Activator - protected Func Activator => this.curvePreset switch { + public Func Activator => this.curvePreset switch { CurvePresets.Linear => ActivatorLinear, CurvePresets.Sqrt => ActivatorSqrt, CurvePresets.Power => ActivatorPower, @@ -311,10 +311,16 @@ public class Neuron : Nucleus { #endregion Receivers - public virtual void ProcessStimulus(Vector3 inputValue, string thingName = null) { + public override void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) { + ProcessStimulusDirect(inputValue, thingId, thingName); + // this.stale = 0; + // this.bias = inputValue; + // this.parent.UpdateFromNucleus(this); + } + + public void ProcessStimulusDirect(Vector3 inputValue, int thingId = 0, string thingName = null) { this.stale = 0; this.bias = inputValue; this.parent.UpdateFromNucleus(this); } - } \ No newline at end of file diff --git a/Nucleus.cs b/Nucleus.cs index 3193686..78fed33 100644 --- a/Nucleus.cs +++ b/Nucleus.cs @@ -73,8 +73,6 @@ public abstract class Nucleus { #endregion Synapses - - #region Update public abstract void UpdateStateIsolated(); @@ -88,6 +86,9 @@ public abstract class Nucleus { this.parent.UpdateFromNucleus(this); } + public virtual void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = "") { + } + #endregion Update } \ No newline at end of file diff --git a/NucleusArray.cs b/NucleusArray.cs index b3651df..774d0f7 100644 --- a/NucleusArray.cs +++ b/NucleusArray.cs @@ -111,6 +111,10 @@ public class NucleusArray { public virtual void ProcessStimulus(int thingId, Vector3 inputValue, string thingName = null) { CleanupReceivers(); + + if (this._nuclei[0] is Neuron neuron) + inputValue = neuron.Activator(inputValue); + if (!thingReceivers.TryGetValue(thingId, out Nucleus selectedReceiver)) { // No existing nucleus for this thing selectedReceiver = FindReceiver(thingId, inputValue); @@ -127,8 +131,7 @@ public class NucleusArray { } if (selectedReceiver is Neuron selectedNucleus) - selectedNucleus.ProcessStimulus(inputValue); - //selectedReceiver.parent.UpdateFromNucleus(selectedReceiver); + selectedNucleus.ProcessStimulusDirect(inputValue); } private void CleanupReceivers() { diff --git a/Receptor.cs b/Receptor.cs index 2547f36..8d84bcb 100644 --- a/Receptor.cs +++ b/Receptor.cs @@ -76,7 +76,7 @@ public class Receptor : Neuron, IReceptor { } } - public virtual void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) { + public override void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) { this._array ??= new NucleusArray(this.parent); this._array.ProcessStimulus(thingId, inputValue, thingName); } diff --git a/ReceptorArray.cs b/ReceptorArray.cs index 2eea9f6..35e1a90 100644 --- a/ReceptorArray.cs +++ b/ReceptorArray.cs @@ -141,7 +141,7 @@ public class ReceptorArray : Nucleus { // public override void ProcessStimulus(int thingId, Vector3 inputValue, string thingName = null) { // ProcessStimulus(inputValue, thingId, thingName); // } - public virtual void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) { + public override void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) { CleanupReceivers(); if (!thingReceivers.TryGetValue(thingId, out Nucleus selectedReceiver)) { //Debug.Log($" no receiver found for {thingId}"); From f9ce73fd7a784b9c72e287c14d8fde39c11edf46 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 19 Feb 2026 17:19:15 +0100 Subject: [PATCH 160/179] Fix max combinator and connecting to receptors --- Cluster.cs | 2 +- ClusterReceptor.cs | 2 +- Editor/ClusterInspector.cs | 85 +++++++++++++++++++++----------------- Neuron.cs | 8 ++-- Nucleus.cs | 2 +- Receptor.cs | 9 ++++ ReceptorArray.cs | 4 +- 7 files changed, 65 insertions(+), 47 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index c605d76..40641ef 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -99,7 +99,7 @@ public class Cluster : Nucleus { clonedArray.nuclei[arrayIx] = clonedArrayNucleus; } else { - Debug.LogError($" Could not find prefab nuclues {prefabNucleus.name} in the clones"); + Debug.LogError($" Could not find prefab nucleus {prefabNucleus.name} in the clones"); } arrayIx++; } diff --git a/ClusterReceptor.cs b/ClusterReceptor.cs index 3df0d35..5039458 100644 --- a/ClusterReceptor.cs +++ b/ClusterReceptor.cs @@ -103,7 +103,7 @@ public class ClusterReceptor : Cluster, IReceptor { nucleus.UpdateNuclei(); } - public virtual void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) { + public override void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) { this.array ??= new NucleusArray(this.parent); this.array.ProcessStimulus(thingId, inputValue, thingName); } diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index f0b9948..b597132 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -606,11 +606,11 @@ public class ClusterInspector : Editor { else expandArray = false; } - else if (nucleus is ReceptorInstance receptor) { - this.currentNucleus = receptor.receptor; - expandArray = false; - BuildLayers(); - } + // else if (nucleus is ReceptorInstance receptor) { + // this.currentNucleus = receptor.receptor; + // expandArray = false; + // BuildLayers(); + // } else { this.currentNucleus = nucleus; expandArray = false; @@ -674,21 +674,21 @@ public class ClusterInspector : Editor { if (this.currentNucleus is MemoryCell memory) { memory.staticMemory = EditorGUILayout.Toggle("Static Memory", memory.staticMemory); } - if (this.currentNucleus is ReceptorArray receptor) { - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.IntField("Receptor size", receptor.instances.Count()); - if (GUILayout.Button("Add")) { - Undo.RecordObject(prefabAsset, "Receptor add " + prefabAsset.name); - receptor.AddReceptor(this.prefab); - anythingChanged = true; - } - if (GUILayout.Button("Del")) { - Undo.RecordObject(prefabAsset, "Receptor delete " + prefabAsset.name); - receptor.RemoveReceptor(); - anythingChanged = true; - } - EditorGUILayout.EndHorizontal(); - } + // if (this.currentNucleus is ReceptorArray receptor) { + // EditorGUILayout.BeginHorizontal(); + // EditorGUILayout.IntField("Receptor size", receptor.instances.Count()); + // if (GUILayout.Button("Add")) { + // Undo.RecordObject(prefabAsset, "Receptor add " + prefabAsset.name); + // receptor.AddReceptor(this.prefab); + // anythingChanged = true; + // } + // if (GUILayout.Button("Del")) { + // Undo.RecordObject(prefabAsset, "Receptor delete " + prefabAsset.name); + // receptor.RemoveReceptor(); + // anythingChanged = true; + // } + // EditorGUILayout.EndHorizontal(); + // } if (this.currentNucleus is Receptor receptor1) { EditorGUILayout.BeginHorizontal(); EditorGUILayout.IntField("Array size", receptor1.nucleiArray.Count()); @@ -857,28 +857,28 @@ public class ClusterInspector : Editor { void OnSceneGUI(SceneView sceneView) { if (this.gameObject != null) { - if (this.currentNucleus is ReceptorArray receptor && expandArray) { - foreach (Nucleus nucleus in receptor.instances) { + // if (this.currentNucleus is ReceptorArray receptor && expandArray) { + // foreach (Nucleus nucleus in receptor.instances) { + // Vector3 worldVector = this.gameObject.transform.TransformVector(nucleus.outputValue); + // Handles.color = Color.yellow; + // Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); + // } + // } + // else { + if (this.currentNucleus is Receptor receptor1) { + foreach (Nucleus nucleus in receptor1.nucleiArray) { Vector3 worldVector = this.gameObject.transform.TransformVector(nucleus.outputValue); Handles.color = Color.yellow; Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); } } else { - if (this.currentNucleus is Receptor receptor1) { - foreach (Nucleus nucleus in receptor1.nucleiArray) { - Vector3 worldVector = this.gameObject.transform.TransformVector(nucleus.outputValue); - Handles.color = Color.yellow; - Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); - } - } - else { - Vector3 worldVector = this.gameObject.transform.TransformVector(this.currentNucleus.outputValue); - Handles.color = Color.yellow; - Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); + Vector3 worldVector = this.gameObject.transform.TransformVector(this.currentNucleus.outputValue); + Handles.color = Color.yellow; + Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); - } } + // } } } @@ -904,9 +904,9 @@ public class ClusterInspector : Editor { case Nucleus.Type.Receptor: AddReceptorInput(nucleus); break; - case Nucleus.Type.ReceptorArray: - AddReceptorArrayInput(nucleus); - break; + // case Nucleus.Type.ReceptorArray: + // AddReceptorArrayInput(nucleus); + // break; case Nucleus.Type.ClusterReceptor: AddClusterReceptorInput(nucleus); break; @@ -993,7 +993,12 @@ public class ClusterInspector : Editor { IEnumerable nuclei = cluster.nuclei .Except(synapseNuclei); - IEnumerable nucleiNames = nuclei.Select(n => n.name); + IEnumerable nucleiNames = nuclei + .Select(n => { + int idx = n.name.IndexOf(':'); + return idx < 0 ? n.name : n.name[..idx]; + }) + .Distinct(); string[] names = nucleiNames.ToArray(); int selectedIndex = -1; @@ -1002,7 +1007,9 @@ public class ClusterInspector : Editor { return false; Nucleus nucleus = nuclei.ElementAt(selectedIndex); - if (nucleus is Neuron neuron) + if (nucleus is Receptor receptor) + receptor.AddArrayReceiver(this.currentNucleus); + else if (nucleus is Neuron neuron) neuron.AddReceiver(this.currentNucleus); else if (nucleus is Cluster subCluster) subCluster.defaultOutput.AddReceiver(this.currentNucleus); diff --git a/Neuron.cs b/Neuron.cs index 5b33597..8fcc529 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -211,16 +211,16 @@ public class Neuron : Nucleus { public float3 CombinatorMax() { float3 max = this.bias; - float maxSqrLength = lengthsq(max); + float maxLength = length(max); //Applying the weight factors foreach (Synapse synapse in this.synapses) { float3 input = synapse.weight * synapse.nucleus.outputValue; - float inputSqrlength = lengthsq(input); - if (inputSqrlength > maxSqrLength) { + float inputLength = length(input); + if (inputLength > maxLength) { max = input; - maxSqrLength = inputSqrlength; + maxLength = inputLength; } } return max; diff --git a/Nucleus.cs b/Nucleus.cs index 78fed33..cf4ff74 100644 --- a/Nucleus.cs +++ b/Nucleus.cs @@ -42,7 +42,7 @@ public abstract class Nucleus { Cluster, Pulsar, Receptor, - ReceptorArray, + // ReceptorArray, ClusterReceptor, } diff --git a/Receptor.cs b/Receptor.cs index 8d84bcb..e89837c 100644 --- a/Receptor.cs +++ b/Receptor.cs @@ -55,6 +55,15 @@ public class Receptor : Neuron, IReceptor { this.nucleiArray = IReceptorHelpers.RemoveReceptorElement(this.nucleiArray); } + // public override void AddReceiver(Nucleus receiverToAdd, float weight = 1) { + // foreach (Nucleus element in receptorToAdd.nucleiArray) { + // if (element is Neuron neuron) { + // neuron._receivers.Add(receiverToAdd); + // receiverToAdd.AddSynapse(element, weight); + // } + // } + + // } public virtual void AddArrayReceiver(Nucleus receiverToAdd, float weight = 1) { foreach (Nucleus element in this._array.nuclei) { if (element is Neuron neuron) { diff --git a/ReceptorArray.cs b/ReceptorArray.cs index 35e1a90..00c8bbb 100644 --- a/ReceptorArray.cs +++ b/ReceptorArray.cs @@ -1,3 +1,4 @@ +/* using System; using System.Collections.Generic; using System.Linq; @@ -258,4 +259,5 @@ public class ReceptorArray : Nucleus { } } } -} \ No newline at end of file +} +*/ \ No newline at end of file From 97ea988ccaec3c53698d03c80810acd8fd37b5ff Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 19 Feb 2026 17:30:56 +0100 Subject: [PATCH 161/179] Fix changing weight to receptors --- Editor/ClusterInspector.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index b597132..0b28264 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -794,7 +794,17 @@ public class ClusterInspector : Editor { } EditorGUI.indentLevel++; - synapse.weight = EditorGUILayout.FloatField("Weight", synapse.weight); + float newWeight = EditorGUILayout.FloatField("Weight", synapse.weight); + if (newWeight != synapse.weight) { + if (synapse.nucleus is IReceptor receptor) { + Nucleus[] receptorArray = receptor.nucleiArray; + foreach (Synapse s in this.currentNucleus.synapses) { + if (s.nucleus is IReceptor r && r.nucleiArray == receptorArray) + s.weight = newWeight; + } + } else + synapse.weight= newWeight; + } EditorGUI.indentLevel--; } } From 83e8bd70f1f8fae31d29e6dc5055018fd267f0b1 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 2 Mar 2026 11:07:40 +0100 Subject: [PATCH 162/179] Improved UI --- Editor/ClusterInspector.cs | 86 +++++++++++++++++++++++++------------- 1 file changed, 57 insertions(+), 29 deletions(-) diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 0b28264..18e6b94 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -618,6 +618,7 @@ public class ClusterInspector : Editor { } } + private VisualElement inspectorIMGUIContainer; private bool showSynapses = true; private bool showActivation = true; protected bool breakOnWake = false; @@ -632,9 +633,9 @@ public class ClusterInspector : Editor { // create a SerializedObject wrapper so Unity inspector controls work (and Undo) SerializedObject so = new(prefabAsset); - IMGUIContainer container = new(() => InspectorHandler(so)); + this.inspectorIMGUIContainer = new IMGUIContainer(() => InspectorHandler(so)); - inspectorContainer.Add(container); + inspectorContainer.Add(inspectorIMGUIContainer); } void InspectorHandler(SerializedObject serializedObject) { @@ -728,18 +729,15 @@ public class ClusterInspector : Editor { if (this.currentNucleus is not Receptor && this.currentNucleus is not ClusterReceptor) { showSynapses = EditorGUILayout.BeginFoldoutHeaderGroup(showSynapses, "Synapses"); if (showSynapses) { - - anythingChanged = ConnectNucleus(this.prefab, this.currentNucleus); - anythingChanged = AddSynapse(this.prefab, this.currentNucleus); - EditorGUILayout.Space(); - if (this.currentNucleus is Neuron neuron2) { Neuron.CombinatorType newCombinator = (Neuron.CombinatorType)EditorGUILayout.EnumPopup("Combinator", neuron2.combinator); anythingChanged |= newCombinator != neuron2.combinator; neuron2.combinator = newCombinator; } - Vector3 newBias = EditorGUILayout.Vector3Field("Bias", this.currentNucleus.bias); + EditorGUIUtility.wideMode = true; + EditorGUIUtility.labelWidth = 100; + Vector3 newBias = EditorGUILayout.Vector3Field("Bias", this.currentNucleus.bias); //, GUILayout.Width(200)); anythingChanged |= newBias != this.currentNucleus.bias; this.currentNucleus.bias = newBias; @@ -776,7 +774,7 @@ public class ClusterInspector : Editor { if (synapse.nucleus.parent != null && synapse.nucleus.parent != this.currentNucleus) { GUIStyle labelStyle = new(GUI.skin.label); float labelWidth = labelStyle.CalcSize(new GUIContent($"{synapse.nucleus.clusterPrefab.name}.")).x; - EditorGUILayout.LabelField($"{synapse.nucleus.clusterPrefab.name}", GUILayout.Width(labelWidth)); + GUILayout.Label($"{synapse.nucleus.clusterPrefab.name}", GUILayout.Width(labelWidth)); string[] options = synapse.nucleus.parent.clusterNuclei.Select(n => n.name).ToArray(); int selectedIndex = System.Array.IndexOf(options, synapse.nucleus.name); int newIndex = EditorGUILayout.Popup(selectedIndex, options); @@ -784,13 +782,16 @@ public class ClusterInspector : Editor { ChangeSynapse(synapse, newNeuron); } else - EditorGUILayout.LabelField(synapse.nucleus.name); - if (GUILayout.Button("Disconnect") && synapse.nucleus is Neuron synapseNeuron) { + GUILayout.Label(synapse.nucleus.name); + + bool disconnecting = GUILayout.Button("Disconnect", GUILayout.Width(80)); + if (disconnecting && synapse.nucleus is Neuron synapseNeuron) { synapseNeuron.RemoveReceiver(this.currentNucleus); this.prefab.GarbageCollection(); anythingChanged = true; } EditorGUILayout.EndHorizontal(); + } EditorGUI.indentLevel++; @@ -802,12 +803,17 @@ public class ClusterInspector : Editor { if (s.nucleus is IReceptor r && r.nucleiArray == receptorArray) s.weight = newWeight; } - } else - synapse.weight= newWeight; + } + else + synapse.weight = newWeight; } EditorGUI.indentLevel--; } } + + EditorGUILayout.Space(); + anythingChanged = ConnectNucleus(this.prefab, this.currentNucleus); + anythingChanged = AddSynapse(this.prefab, this.currentNucleus); } EditorGUILayout.EndFoldoutHeaderGroup(); } @@ -1012,19 +1018,33 @@ public class ClusterInspector : Editor { string[] names = nucleiNames.ToArray(); int selectedIndex = -1; - selectedIndex = EditorGUILayout.Popup("Connect", selectedIndex, names); - if (selectedIndex < 0) - return false; + EditorGUILayout.BeginHorizontal(); + selectedIndex = EditorGUILayout.Popup(selectedIndex, names); + bool connecting = GUILayout.Button("Connect", GUILayout.Width(80)); + EditorGUILayout.EndHorizontal(); + if (connecting) { + Nucleus nucleus = nuclei.ElementAt(selectedIndex); + if (nucleus is Receptor receptor) + receptor.AddArrayReceiver(this.currentNucleus); + else if (nucleus is Neuron neuron) + neuron.AddReceiver(this.currentNucleus); + else if (nucleus is Cluster subCluster) + subCluster.defaultOutput.AddReceiver(this.currentNucleus); - Nucleus nucleus = nuclei.ElementAt(selectedIndex); - if (nucleus is Receptor receptor) - receptor.AddArrayReceiver(this.currentNucleus); - else if (nucleus is Neuron neuron) - neuron.AddReceiver(this.currentNucleus); - else if (nucleus is Cluster subCluster) - subCluster.defaultOutput.AddReceiver(this.currentNucleus); + } + return connecting; + // if (selectedIndex < 0) + // return false; - return true; + // Nucleus nucleus = nuclei.ElementAt(selectedIndex); + // if (nucleus is Receptor receptor) + // receptor.AddArrayReceiver(this.currentNucleus); + // else if (nucleus is Neuron neuron) + // neuron.AddReceiver(this.currentNucleus); + // else if (nucleus is Cluster subCluster) + // subCluster.defaultOutput.AddReceiver(this.currentNucleus); + + // return true; } protected virtual void DeleteNucleus(Nucleus nucleus) { @@ -1057,12 +1077,20 @@ public class ClusterInspector : Editor { if (cluster == null) return false; - Nucleus.Type selectedType = (Nucleus.Type)EditorGUILayout.EnumPopup("Add", Nucleus.Type.None); - if (selectedType == Nucleus.Type.None) - return false; + EditorGUILayout.BeginHorizontal(); + Nucleus.Type selectedType = (Nucleus.Type)EditorGUILayout.EnumPopup(Nucleus.Type.None); + bool connecting = GUILayout.Button("Add", GUILayout.Width(80)); + EditorGUILayout.EndHorizontal(); - AddInput(selectedType, this.currentNucleus); - return true; + if (connecting) { + AddInput(selectedType, this.currentNucleus); + } + return connecting; + // if (selectedType == Nucleus.Type.None) + // return false; + + // AddInput(selectedType, this.currentNucleus); + // return true; } protected virtual void ChangeSynapse(Synapse synapse, Neuron newNucleus) { From b0ee3add3ae046d9d3389e06dbeeae473b161b4e Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 2 Mar 2026 12:09:00 +0100 Subject: [PATCH 163/179] Fix cluster receivers --- Cluster.cs | 7 +- ClusterReceptor.cs | 7 +- Editor/ClusterInspector.cs | 96 +++++----------- Icons.meta | 8 ++ Icons/NeuraalNetwerkIcoonSchets1.png | Bin 0 -> 60406 bytes Icons/NeuraalNetwerkIcoonSchets1.png.meta | 117 ++++++++++++++++++++ Icons/NeuraalNetwerkIcoonSchets2.png | Bin 0 -> 39373 bytes Icons/NeuraalNetwerkIcoonSchets2.png.meta | 117 ++++++++++++++++++++ Icons/NeuraalNetwerkIcoonSchets3.png | Bin 0 -> 40575 bytes Icons/NeuraalNetwerkIcoonSchets3.png.meta | 117 ++++++++++++++++++++ Identity.asset | 27 +++-- Scripts/NeuraalNetwerkIcoonSchets1.png | Bin 0 -> 63771 bytes Scripts/NeuraalNetwerkIcoonSchets1.png.meta | 117 ++++++++++++++++++++ Scripts/NeuraalNetwerkIcoonSchets2.png | Bin 0 -> 39373 bytes Scripts/NeuraalNetwerkIcoonSchets2.png.meta | 117 ++++++++++++++++++++ 15 files changed, 646 insertions(+), 84 deletions(-) create mode 100644 Icons.meta create mode 100644 Icons/NeuraalNetwerkIcoonSchets1.png create mode 100644 Icons/NeuraalNetwerkIcoonSchets1.png.meta create mode 100644 Icons/NeuraalNetwerkIcoonSchets2.png create mode 100644 Icons/NeuraalNetwerkIcoonSchets2.png.meta create mode 100644 Icons/NeuraalNetwerkIcoonSchets3.png create mode 100644 Icons/NeuraalNetwerkIcoonSchets3.png.meta create mode 100644 Scripts/NeuraalNetwerkIcoonSchets1.png create mode 100644 Scripts/NeuraalNetwerkIcoonSchets1.png.meta create mode 100644 Scripts/NeuraalNetwerkIcoonSchets2.png create mode 100644 Scripts/NeuraalNetwerkIcoonSchets2.png.meta diff --git a/Cluster.cs b/Cluster.cs index 40641ef..0393422 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -434,7 +434,12 @@ public class Cluster : Nucleus { public virtual List CollectReceivers() { List receivers = new(); foreach (Neuron output in this.outputs) { - receivers.AddRange(output.receivers); + foreach (Nucleus receiver in output.receivers) { + // Only add receivers outside this cluster + if (receiver.clusterPrefab != this.prefab) + receivers.Add(receiver); + //receivers.AddRange(output.receivers); + } } return receivers; } diff --git a/ClusterReceptor.cs b/ClusterReceptor.cs index 5039458..66eabc7 100644 --- a/ClusterReceptor.cs +++ b/ClusterReceptor.cs @@ -8,9 +8,12 @@ using static Unity.Mathematics.math; public class ClusterReceptor : Cluster, IReceptor { public ClusterReceptor(ClusterPrefab prefab, Cluster parent, string name) : base(prefab, parent) { this.name = name; - this.array ??= new NucleusArray(this); + this.array = new NucleusArray(this); + if (this.name.IndexOf(":") < 0) + this.name += ": 0"; + } - public ClusterReceptor(ClusterPrefab prefabToInstantiate, ClusterPrefab parent, string name) : base(prefabToInstantiate, parent) { + public ClusterReceptor(ClusterPrefab prefab, ClusterPrefab parent, string name) : base(prefab, parent) { this.name = name; this.array = new NucleusArray(this); } diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 18e6b94..1c7f84a 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -16,6 +16,16 @@ public class ClusterInspector : Editor { #region Start + private void OnEnable() { + // Load an icon from resources or assets + Texture2D icon = Resources.Load("ClusterIcon.png"); + + // Ensure the texture is valid; set the icon for the ScriptableObject + if (icon != null) { + EditorGUIUtility.SetIconForObject(target, icon); + } + } + public override VisualElement CreateInspectorGUI() { ClusterPrefab prefab = target as ClusterPrefab; @@ -265,39 +275,6 @@ public class ClusterInspector : Editor { // Draw selected Nucleus if (expandArray) { - // if (this.currentNucleus is ReceptorArray receptor) { - // float maxValue = 0; - // foreach (Nucleus nucleus in receptor.instances) { - // float value = length(nucleus.outputValue); - // if (value > maxValue) - // maxValue = value; - // } - - // float spacing = 400f / receptor.instances.Count(); - // float margin = 10 + spacing / 2; - // float xMin = 150 - size; - // float xMax = 150 + size; - // float yMin = 10 + margin - size / 2; - // float yMax = 400 - margin + size; - // Vector3[] verts = new Vector3[4] { - // new(xMin, yMin, 0), - // new(xMax, yMin, 0), - // new(xMax, yMax, 0), - // new(xMin, yMax, 0) - // }; - // Handles.color = Color.black; - // Handles.DrawAAConvexPolygon(verts); - // int row = 0; - // foreach (Nucleus nucleus in receptor.instances) { - // Vector3 pos = new(150, margin + row * spacing, 0.0f); - // Handles.color = Color.white; - // // The selected nucleus highlight ring - // Handles.DrawSolidDisc(pos, Vector3.forward, size + 2); - // DrawNucleus(nucleus, pos, maxValue, size); - // row++; - // } - // } - // else if (this.currentNucleus is IReceptor receptor1) { float maxValue = 0; foreach (Nucleus nucleus in receptor1.nucleiArray) { @@ -560,8 +537,8 @@ public class ClusterInspector : Editor { Handles.Label(labelPos, nucleus.name, style); } - // } + // Draw Cluster ring if (nucleus is Cluster) { Handles.color = Color.white; Handles.DrawWireDisc(position, Vector3.forward, size + 10); @@ -773,8 +750,11 @@ public class ClusterInspector : Editor { if (synapse.nucleus.parent != null && synapse.nucleus.parent != this.currentNucleus) { GUIStyle labelStyle = new(GUI.skin.label); - float labelWidth = labelStyle.CalcSize(new GUIContent($"{synapse.nucleus.clusterPrefab.name}.")).x; - GUILayout.Label($"{synapse.nucleus.clusterPrefab.name}", GUILayout.Width(labelWidth)); + float labelWidth = 200; + if (synapse.nucleus.clusterPrefab != null) { + labelWidth = labelStyle.CalcSize(new GUIContent($"{synapse.nucleus.clusterPrefab.name}.")).x; + GUILayout.Label($"{synapse.nucleus.clusterPrefab.name}", GUILayout.Width(labelWidth)); + } string[] options = synapse.nucleus.parent.clusterNuclei.Select(n => n.name).ToArray(); int selectedIndex = System.Array.IndexOf(options, synapse.nucleus.name); int newIndex = EditorGUILayout.Popup(selectedIndex, options); @@ -783,7 +763,7 @@ public class ClusterInspector : Editor { } else GUILayout.Label(synapse.nucleus.name); - + bool disconnecting = GUILayout.Button("Disconnect", GUILayout.Width(80)); if (disconnecting && synapse.nucleus is Neuron synapseNeuron) { synapseNeuron.RemoveReceiver(this.currentNucleus); @@ -791,7 +771,7 @@ public class ClusterInspector : Editor { anythingChanged = true; } EditorGUILayout.EndHorizontal(); - + } EditorGUI.indentLevel++; @@ -962,6 +942,10 @@ public class ClusterInspector : Editor { protected virtual void AddClusterInput(Nucleus nucleus) { ClusterPickerWindow.ShowPicker(brain => OnClusterPicked(nucleus, brain), "Select Cluster"); } + private void OnClusterPicked(Nucleus nucleus, ClusterPrefab prefab) { + Cluster subclusterInstance = new(prefab, this.prefab); + subclusterInstance.defaultOutput.AddReceiver(nucleus); + } protected virtual void AddReceptorInput(Nucleus nucleus) { Receptor newReceptor = new(this.prefab, "New Receptor"); @@ -970,25 +954,14 @@ public class ClusterInspector : Editor { BuildLayers(); } - protected virtual void AddReceptorArrayInput(Nucleus nucleus) { - // ReceptorArray newReceptor = new(this.prefab, "New Receptor"); - // newReceptor.AddReceiver(nucleus); - // this.currentNucleus = newReceptor; - // BuildLayers(); - } - protected virtual void AddClusterReceptorInput(Nucleus nucleus) { ClusterPickerWindow.ShowPicker(prefab => OnClusterReceptorPicked(nucleus, prefab), "Select Cluster"); } - - private void OnClusterPicked(Nucleus nucleus, ClusterPrefab prefab) { - Cluster subclusterInstance = new(prefab, this.prefab); - subclusterInstance.defaultOutput.AddReceiver(nucleus); - } - private void OnClusterReceptorPicked(Nucleus nucleus, ClusterPrefab selectedPrefab) { ClusterReceptor clusterInstance = new(selectedPrefab, this.prefab, "New " + selectedPrefab.name); clusterInstance.defaultOutput.AddReceiver(nucleus); + this.currentNucleus = clusterInstance; + BuildLayers(); } private void EditCluster(Cluster subCluster) { @@ -998,6 +971,7 @@ public class ClusterInspector : Editor { var editor = Editor.CreateEditor(subCluster.prefab); } + int selectedConnectNucleus = -1; // Connect to another nucleus in the same cluster protected virtual bool ConnectNucleus(ClusterPrefab cluster, Nucleus nucleusToConnect) { if (cluster == null) @@ -1017,13 +991,12 @@ public class ClusterInspector : Editor { .Distinct(); string[] names = nucleiNames.ToArray(); - int selectedIndex = -1; EditorGUILayout.BeginHorizontal(); - selectedIndex = EditorGUILayout.Popup(selectedIndex, names); + selectedConnectNucleus = EditorGUILayout.Popup(selectedConnectNucleus, names); bool connecting = GUILayout.Button("Connect", GUILayout.Width(80)); EditorGUILayout.EndHorizontal(); if (connecting) { - Nucleus nucleus = nuclei.ElementAt(selectedIndex); + Nucleus nucleus = nuclei.ElementAt(selectedConnectNucleus); if (nucleus is Receptor receptor) receptor.AddArrayReceiver(this.currentNucleus); else if (nucleus is Neuron neuron) @@ -1033,18 +1006,6 @@ public class ClusterInspector : Editor { } return connecting; - // if (selectedIndex < 0) - // return false; - - // Nucleus nucleus = nuclei.ElementAt(selectedIndex); - // if (nucleus is Receptor receptor) - // receptor.AddArrayReceiver(this.currentNucleus); - // else if (nucleus is Neuron neuron) - // neuron.AddReceiver(this.currentNucleus); - // else if (nucleus is Cluster subCluster) - // subCluster.defaultOutput.AddReceiver(this.currentNucleus); - - // return true; } protected virtual void DeleteNucleus(Nucleus nucleus) { @@ -1073,12 +1034,13 @@ public class ClusterInspector : Editor { BuildLayers(); } + Nucleus.Type selectedType = Nucleus.Type.None; protected virtual bool AddSynapse(ClusterPrefab cluster, Nucleus nucleus) { if (cluster == null) return false; EditorGUILayout.BeginHorizontal(); - Nucleus.Type selectedType = (Nucleus.Type)EditorGUILayout.EnumPopup(Nucleus.Type.None); + selectedType = (Nucleus.Type)EditorGUILayout.EnumPopup(selectedType); bool connecting = GUILayout.Button("Add", GUILayout.Width(80)); EditorGUILayout.EndHorizontal(); diff --git a/Icons.meta b/Icons.meta new file mode 100644 index 0000000..4b8dfb3 --- /dev/null +++ b/Icons.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 885c5a70637820322b07e023ce18fdd5 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Icons/NeuraalNetwerkIcoonSchets1.png b/Icons/NeuraalNetwerkIcoonSchets1.png new file mode 100644 index 0000000000000000000000000000000000000000..3a314eedf02c118cc7d939130ddf6ccec4766091 GIT binary patch literal 60406 zcmV*HKxn^-P)FMd%zI{95zyc6R0^ zq<43BN2^w?5E&VX?%lg1A|e7F9vmL99iGh2lnmThpAJi;=Av@!>U!Q3^Muzgdj4=8-boq@bPei zn~MXS?1=CclmZ-_Q340#v5OL`6j%_gd9mzva97tw0L_sNZ@u z>Cr-t{rmSDB-dw&J{ji(8629xaMX9PiYrlR==G1}e_GeED*`{PN3~ zHESk0a6ZDLI$}ha1BP^Hg+Wn1@UhE+Q$-ORO7dY}lm(QQz|O@J<*wc+ad1O^xidB# zsK7U|nV7vH895mT5f&C^2*9XOqaXzC*|Vo1P`0tGSh2zooP`S)A~`u38B{rP$^8$5 zy$gklBJ-zIjBee!;q0@|#^}+b(Ytr=7D8}%p&IW)3jt`nwQSIpa&mGE_g%Mcok4JM z!^FfyBNi7G6&YkNC@4fxQK5BxM;CZ{c^hdwFFTV6Q)0fC4jvd7Xb^DNuwe!PhYT5V zj2JEA@%7hV8{}WJW)1v;+u))B;W)QF(ART6{L2ne45#Q_UJSBizL)Y{5&&-_iQJx2 zh66Q6y(%2Bw>%K@lb!L!PG|hKJ|4w+nFi^@!^5F*^zYvvp`oD=w}0=w_pou}Ml&Zj zFCVmv?uh8H5Ons)MXTauIG1Fj$Ta|43R_`r>^>wX#KFzY4KXn>M#7MkF?8rqYaLqt zZw z$#Bo#PoykHo_Bl1J4IpXt_&<+y#`4M@jSEQFanMkF#_YpjWgU++*t;^&p!JMk38}S z_Uze%j$M0U%DFvpq1!6>=kGSxL}?|mYY;Y|`hOUzrjF@*2YZw|x+1 z9pF%w3$j_>n~3V-jZz0MWRy7KkXIXxaqEkpQv&ew+}{wtCjt31 z^l6S=yToA1`2#S?aT&ad4+4ehR4rswtV&h*rwooxZYXm0LrSp+el6;ZH|NJ=-Nr2> z1kM;RU;u8v{dP>8I1$dy&L=YJ)BfBR0?>?GK)QEqY%Csq^ij;7JsWP$j_BR7E&g)m zU`!4#Mo24#d2@<=D9A0Fv_^ky+-3P`6@S9hHIMZac|+8|#KOTt{QE!HLouCkJeC>Va3b z_~Pf~+i>tuI?g-yT-gOM!ADEazvrHNFn8`;gtiUG9pgLW zZ>=}OJ1?oh*R1hGA)8*p37;U8hYm)%M>M?BH^ODtoVs)18gFtEex#t28afsqCq>|$ z?|wtv?mZZP)>(M!>8H`RZ{L$Jpg;C4TL?fiJilGLcH!>3@5Z!g(-0jUja$ce#q|N} z;hC2}eYctcRHGJGb5z~G5+Se&7`mUt>OV5jo>0_g5Ppnz#!K_lurhWV#*P_*fBow@ z^y}B}k36$xAA1V{XyPT8wg3M6@5j6EzKh7H_ITjDp18t$62H`ZU|bBTt?5$-U}?D^uLA%_|$yM z2v5d_Xg}bB4#0VQg?RCfEkvNEWk&_Q1&h!N&#tD?bN*6{9X%2+zWAaELaOn^mLJUu zv=D$3*a#^pDVRThJ~nLFfX$mXn*bh#?1}*R`TH}7#U1f`_u)`x4(=Ttggc^>v214= zKHLn;=@5iuSZ)DPUelRN^boXOIBrs(F&^3?;NPM?(J$`I~BUhlD#C479 zU_88}0&^EErA^>Wyzs&cCV=S3BU}DDdIeetz|kvG%inV4DN^sNufD>ZIdiaW+cw7O zXCjdP_L!K?2oDRVd(R%BL}Gu(d<0}}L_lEzI(rx4yUm4oX)O?!WrsjtPn~r zToXd;>gs~rtPD*5=5xIH!KcVAEW@OB!1JR3M(0vQsAXWM`_GIISn4?>$%D}%j%E()1a`^qZdg*8A?g%i#m+68yr`yd96IR|d;ZdLA5 zfi7LTpiL`pJn_=o_;GhJT9J@E#pqX~4%iHNRnBPnSh)fv#TblbxPQnX< zz)q#Ct~XlT^QgnWy&iaaISqS^qyOvpez@o9R}d02P?xU;Dv+MA6(2nNPdxtqPYkss z0T>MYtv3VzWF`EAs{&^D{LeNG+q-Qc1B6eFGuDk9! zJoVI5CR?)J*E<_Hw|fxho5~O0o}*cFdjR&&~^~!R)jq(7h-)%5psC$ zsJ1ZDz+ud(;R+}1CxgAbyY0PlAX*lc5-1{#%xCUW2I=J?<~GR&a)43IseG3qR4-~i za3#@W%uj=;fE{xwqU@949^4MAlgqGr?Rt}*tTg5Nrb|~2|4;qaq5>S}@k-ZMtp30L z^)DnQ@5hxx!f|~+5A=1V`96ioI0A9x;{lOiTN>~N1%yPp`fln1{PUU#@aZ=8cxN2` z-rm^_;X@|k+;ivQx7}Z3H9Z9zc&!fp4Z?}T*KPCkl+n!4S2ffN51L-j%B5|&~rUf zhj+$3fHk? zN4UDW*6|9b$6+l5;Hc-U5><-Wd*Fcw;OgmzM=$A*3!E0gErYvKyR?oNC@#1100{wi z_2r#`&TVMy^A0`gZZ-XBkKK9BNGq})5exGe-T0)c0GhjypX;zE15{5KfU^%+o63MD zBEASg9=W;y@i>fWs@BErMq&6Hpd))I7fW>%w{E4(}zCs9!hhul=y9oUSr#8_ly z7hoGDhDC|MCK8j~S->v7?i)aYK&im2e_e?HiFiQS0bJ2F7z;Q0n`f$2Viinjf!|l4 zg#i4%7N#WCym|BR&_fTw-pvQkUNZ`l@e7<%chn2{bxGy+NW^t>0>V6r3uVNP5>kaa zfKrB4ob!{frs7~mmWd09V054agTrjH4%cbaLxlW%ZDkhk&!mNO5`c|FQi=2>m8{#| z(TPN=jCBVbFnsuMoOj-NtQj~0N=3F+5SC?Lsln36X@Q0v>lz?82^HIBqHN{I$l0+O zGf7llq2V-^_xftP6)E}XP)bswpCZC_B?9?57!jC*p`C-VVEtAsUAokSVz<}=e%~1_ z1fX&)RQ_5Oa-MzmSsLuh@X}2qa9-I=IHc{gjt~OW1H`etnW`=#u!G#PxWXRJ6nkp} zjYGvjUU}selQ>jCPIgXvpt}Ns>bmi3yGeb2=iE6Ad_y|;HfG$#jf;$53hr(mQtGHt0cWC2Pf~Qtc8b|_Wk=QVs z8PAUZdQzRL4-pJ4+mE5)?eWX%3RC#>(n~KjRfcLF)9Lf8cuEU!1yr(1A*8$GcH+)+ zdg6kz8NVZc16Ig~#;aj8WO@C5jyVqQ=-jz8F2DS8Q=Usb0aRUB?$Yt&$D4Ww zetzWW4Fz9f{K&g$AD|b&?j1Z?k%K!I!gxYtRP9Fz;MP90rPlTOB)A>?>=ESUY`i&& z;#7IG7O+;}w2uRj$gRz*Dm@*;g79SjJcO2032g*!>rI1m-(X98-atYyZ~b2Cp-WK2 zx_jd8>FF6rB}dB4%s@)gUK*-?z(4Q1-+V6#VnAyW63S@a{2V45Ky&U|-gh@G_)jed zKB5F8kzXaq&t(A)1=jrKFMly*$u%SeN=a?````cGILPHpamSb9Q`#hV+;Xn&ZRt+?^S0)dMZ!iM8>8pzIWbv z2L*Y#xbgfLM7gXat7{}>n?xj(T>MEIu!gk(zTRGe`MWmZvHS0aJM~^KZyyBs`E=X+3Il#b_=!=V&46MrxvxZU`NkQCRJTokA`8NE%lL{*2Oe9hF0x3QXx|u-~t8qcQ{g@RGe7Do`I4n-0xu70GhBJy0 z=;yo?{SReLRaQoHC;)PF97U&iYg9|`=DU=hRR$(DLmw;-Vk z)7!w$E6_+?s?Q*)?`ZX_+A*94U!K+kK;3B6701KX377S7g)fL@O#wtA#-+fQp#T%e z*u-L0a^HaoLvSE_CxJLb;}#458l%_v_Kb+5C5YRrK*?+CEJRbAu4}Ko7Ps7T ziz#r@l=nXFwZjJj?S>+dl2L2E1c@Y;ia)3`6y?B??al1D=q>#Qk6bm|Hazm%)8H>z z{zU*v8Ju&`$R6-2B%5tQ&U(a>>OQuYe&A=t3FZJptmYyBM?M4VFG&XyK&p;` zLu%z|xdOXU6o!~A^;^^ zqXUWu(3;f+oV~cT4n%%tT2iWMf!|l)v?Tzl)T`j1-d&>MowI|xifpBc5bO8lZonrJ zfuU`gPte6O2!2XcAWPzJV~>^Blb=0_20$T+s_RMuI3KDB~!U;{U1DWWx@Q!JXjCC`3&`bIPPGq*Qa$TxtSx z{W4}H9?HmuA{3?Cw7~Bxa9X+n3s|Esg%W@hb;4GqWT)lzF)9DPc+L8Wh<-_DD+5mn zG9S?(s3=1P#VBHLKSg&H*(fA|a3WI3rKnKiFdEK+s5`6BhN=w*(Wd4@W1}09-i=RR zhDPNm{kD&mbrK9GXJ=DQw<{Z!o=RZn5d`^$Z?n;D&9Z6XjA z6;+p0PMc#+TLO@o$pW6tO?S&D0dSCM{nQ7A1>ez!jYE8Bsi)Vne~48$gE347Bn{+~ z2<)YSOvO3YQxce)KrbVSf&&pp;l=Vcc<|-PC(rPBFa*NX8vHGh(gn|Vb|^O;ixuAM z&(h|n47hs3DJYBtU>7Ms<)~_-0Q%h{0Lu(7NqciM1N%15C)Wcqr=GzmqV$0#<;bxMR>Xo5rEycCMu9V`x zT5#6}LSVh*M)GV;z0wO=bew0hCRQdZeiqOo8^vp4Rw>zWKC!T* z(s3=~z_05pzw*$kpfLFW5&?1VIeQo$Of`UQ2!7{^{9UyOf;o<0iv5Zt92QR1fcF)m z7n3l^iy(y0rL-WIqKLx_tL(6c!)(*0jS2f5HELAV+n)5#4BkbdoeLW!=^^N^I?z<# z)|i{>izTreaM9%PQ2KI<2jIv@d0G+x#e&Na2s>hmX8?_9WR0vVZ+4Y!eS~QW9pzh@ zt0&65J78D72VzOhhkk_uh1KRp)*((_0FcpMeeau%cXWCl+w#_L7|`=X7HGb7k4 z;ALOLaMT=D4=*$sb;CP{pjG@F%P42NUmf4I@qLKgk=_*V_gV(Pj;;8mh>Ac2Mo@*O ziD|m)L_KZ36jFN_cr8Ev?YUkDRKT5jwi=i!^Y2uG5_0|ItP-=%ilS`AG3)*Ce2*Gz z1)tqMyAXUHn}^6Y!MNs{YvJw9MQed0R^YTG01^Y8Y3wR0DnW@mS!e|qthlVz`5uyRWxt?K32m7ay911ZR3=Aej(GkgDO6RKXnD|Kgk?#9#{JM2Ed z>N7m2gp!8*&hBn*lr|h0hh9ocv>WbVCg4rlybT0#{EmJM3fgU1{-fz3sPS?(qF{Tk zdS4O>ookSZ6tJ903hHloszD(|m(6<*Qi`d72kCYv&R>#FwLnisj%Or($mocbYZqhi zzylV34l03IEzB4MqHA87{%Z%^nT@{*rPS}*#~2%OE3Ji zb{|&nNWgx|%GudjeEJm#@Nz}R04IcZ>wxIUFhsQtL=bnQU)e#pr^dprAQMGCkw|ul zMr>jhHt*bvr1Tu><0L9}PH?6G8{)#a^mH1sxPcFI?Rsu2WeBQ?s0?~@bXy%?rMx(GlONyj$kQW^}`c#pyR)7B&7 zP%7&!WHvMenAQ~VZhu}lZ3#ffjvY`$t`eJEfb$|ekr^D0-*Thz$+81j7CQ@R89DIu z@kOUlKa6bWimnlX7#tmd4$f)tDmetF!WD2Sp)#FK#HpZS?Mz1D$o*oMgFYoYaaKSD z3g~~!_lZJwtKKMZZUy(^H2CeA0j~o3@N6P`1NN4*6D7y=qV@latt_5NJLZ{D4Y*L{ zDXKHzYC3V08v-DNIn_V~M|LOEnn{pbQ|`@bc`^xFZmSr4x-1EsW7n}mvm-{19EtYr z+naOi`QM)&KmPO+tnPu!5Y)D9TZ+AQ*btYD_Wf*f`)stQ4t(K|P8i<0 z1cM?y5mCAu_Sq|l>_l{17a$t~R~4%zBo@n@USxdnPWIXGPD??^A)YI&RhXR&jykUD zdDRWFmhZT)F**XK)35@A28B{0kf3TCS1sos{+Y)sE#s-KVkTgWJ+ zuPUb=eZ0M zzVquw0SXeTIXEtoE_Ov2Mdw69E`V*JiIE8ZE`TL|X+UwBbXmUt{`*g{kY;PR zr_%pbx9q7jt|lFe8gIw|xMRl-_)yQk>93dK<#R(Y&VDIeQn#~VU4eznbwMT_!&OwC zzDifWL-qbG(vAiEtf)Lg6zX!F2F#eoZnUSLKbYdMLU|SV(;xysI@iBTB)Z0QB2HC6 ziBiA*`m0d~8ZfLzKV|OBY1kE?Xs)a1$L>@C4s(AZf0181%y6BEJKvm+P3zYnJUkr# z{O3P$&N=6_`2A~n8mE;CAm9JNg9lCB{pX*59y!!^Z=2WycMU3p-@adnv5W_(C$dVy zS6{q0)&t+}B<&zF34EziU(}JJc^9j#m0Wi$O4GQ&>k0YW(G9pXneDl#$^V2Q%p1=VpG`Ir^fNJ@z*v}(vV)1cLs^$j~y~H(`G-fb*_UvV198@pi zhaY}0M$u}{X!5Vr5h*QsFW!Fr6|A70MmE&m^m?2bY28|ZKE;8ZFw=c99!`@MD*yl> z07*naRQ_y4oNGaT+hQF3ep>VeC@Cp1ZK2fjZ|2OI2n_JUJ)?v1 z_lS6Sl@jqA!kM`tl|K9UGE4lvG6r~J7%Tdc>yHk%Ty)A>Q);gI=xs@->yA=E8z%B7 zTd%Qzu}Ij?ynuz2kmbocKbpI}zSr0B`Dt*A=#Ao5ow0DyA}C)XIXT(%^^?8CNjGXH zQ1_&i5_A7Yv{ZH7Fpu!M3H3S(KNv(>=pVz7@<~WbTBVR1Vme@6>a`ElA-;UdE zyNzlc7ulk>Tp8ASZGq#iz-d7M)M!&W;f}a?bn4KKg*P4X_wWRGRWK{2Asmy-sa$k5 z%#hA6uJrV9a$<($3YWyK+HwyLZDXb6?xOp8VUi^+bmDeY5Kp54mADjYF7s$}P@&9A zJ5!t|p{W;W&=j%lnHS;LXA(B=JA}BMJ4`^3)-EzK(sb2rt~mO0SE=;dduwhC$qMX@d2VOn@vl~5{p#f`^x=NEXF+8Kqe2Y&A-1!`J>KfMZ| z%(fR^cmeBUH{!OxjKaH@wZk3l$oVU%FgFnSh2=`5Q3YKk<=ouED%in5KTDdBL_w|7 zpZfW=-GO({1jbM**hqEZb*cr%I9StDsn2hmg9wUp|5Zj@t-2cooReMr5=13U!#}RM z5FNX4;DoJPx0-IrGiJHEz@M4`DC_UP|NSq%ojMg`y9VLf zR_o9s^+&julR-2T`775`VzxNF3R9>$jkz5EJ_2NV;t%~IfXNI*b0xRlPE}yH_H|>e zJns?i#obQiP(6V4BuWjwHY+4KZTJeKis$3e>n9;1D#}b}^XARC@4ox+#TQ@D)hO3S z)4+lK$$0Lm$MMwj|3TtG;W03RQq-e^tk7Tmy`#VnPfgp370Z?|zrq0*UwknheDFb| zs_CWRw~hb9Ujk#0 zKQR{K8^GEQf`%H{nnc zP`=AflVlf+e{F4zS*y1)5z7&0opqM!>8Pkq>j+5nKPAL|?LS48su`)e63Y(d>gsAF z7ByJWo>a!A>=h?7O7Txg0JNc|lIyEYwI0G96S`oy!+MKFo&e$rm$S(Le@$SQo>f*I zJ}=tFq<=rS7`U#hm8GYa;HusuP>0#VV))ddU~1FMD&MqEA?gBB2ENI3}o#5C7xZ2NbqFHv{mAju}wuo zCQX`z-o1Mp5nM$#Z5#M_n^@1whWLx0j#rbA-rbjmRBwL4f(!+| zQFuRZ7#{m*4i2U6hw2sn=Rg0!xN+ljia^NkYd)Q%{}f*`XZ9?-`{oe;FF_P~Jy@Ww^$(K~$_SD%WvxLX52RdZA@^S|qXf3Kz> zLBu+bI{kg*Q0ywklwmf~+zu?;&tM#i;403UPGX@>V}+&sn?8DF+nzx~;J-(bIEYVi zLo^yt3i)g!>jnNw#HSka@pxb$b?2%n2q$zeN*LP?0(=3?pMEl&(q>aofl|d$+(?6}x*W`&rGo0vpLqHt*RF7Y`qd7%|+; zO;SN~6fpTi5&(trrlqAB#Q*B6uS|nvd(l#^{eDiL~tW-^TydUKS?s!L}a;pA&Ya8<~Z_uNd{*|Ql#w< z*a~EJGlm> zQ!^pOZA(YfyCz5mQ10N4bUQz6&-27DNv@c-F4+)*o-AE<>;L_qiNw^NZc6yW5dcN- zDO>H+Pd~-?-+yl;fPkRZ7}O~Qz1Zc)xx5&~x#<|*rUD}!H^8N+;hbO3Nn-!=tAPKI z`>B$yqWu2eo64s4pSE9B(6i+;-b;z#ALPcWwWo%b6QhWnG2H01)*HlcOzyAy^PWP+ zGrqAp3E#%?Jv)-yOna{}f%g%vZ_gybp*pZI(GKemIU%LQ4H?DuD99zHtT=j6svm$n zA}VVpl}Uw7hlbLn>c(Tq^-XdQOBC&O?}~dCJLB8=u?%vu!&O&Zg@66)UkD5g)J3(5 z98vRuq)UZJzxVzJIIwRIt{fJH^V()2ymSxjvPpqeVfA>=_UP|5a@)(n1zC=*uqM+J zA8oS3kLwSRcn0E*+i&HZuQr6Qsb=|yA^`G93+cc4<{Oi-X6NjVQNsq|${ubwGl<1D z?DAOQI|~kFg>VujE+ETl=oTSY%_j2yha&$Ae2McvIEaS6ZrrHk=rxJg(wh@VcQSas zMDn&I;wF1do4cuie60JZw4Ne#oTEG-i8&6~R@N4q%fqp& z&tFwh`~sF2A2kp+_jbTA*IjVQ*+;R9 z5BfwwYwF~T-4$VYH!ct#FJui0Np==Vg>cM^0%6hUze5GuUvhDDEdO2*tWU#cT)iGF^qcu`h-vznuVaRas$DvHxV&bi^Pi*5JmdR3lFnX4D(WJcnP1?vp*ck9*-Q>IKgDUC{HSbq57hw;W6Z=g+R8~pv! zF}Sg}9Xh1{MwiQhx~^L7$7zqyrWNIsfLl8|(1;j=_kN4R>%6aQC;vy4Kv|BB4Yo(n z*w<~e>&ajwi|^0$4=bwApQ6z<%;3AWO9_j1&>x(_oz5I~vw^hPZD9K>gslYDJx*(@L^h-bS<4%7tnEaJ+>~_tL+%hMPjtF5D!uX zoxhKH3Dl{BrFL+68XdHDhlyG#9J3PPlamY|iaKqaiQSG|I1fr;VH}LH5md9-htL0g zbQOFyYf9ST?ccUx-|ij8Wv0!qMy1UO((|QiDzRw8h7IV^y&E39d=w_QuYp%0scaD? zo5lt$QE@5SA`UmVXYo^)PI%|n-Sm`vWSE{>wX23jW5Ov*02Iad?YG~WFkTS>CvK>5 zL;K+WdfQ{P?-qEM9->vM`1iH2Aw0j)epCJU-I*1bwZ{sN%_S13F217XMpExoTB*_F zkJ^{A-oL+*ZZ9IguiR@xt(IJJ=`|}t|30%if0AfDp`GQbRC3U_+h|qq$>`Zik-g3r zYUqK|fy?+ziuls=ussvoyRLiGdLMBs>iq`-hvLJHL0G!(Cv*Bm7hQzQFTcEMYVQ%J zG{GO46#0D>`uyaRPa5R!-MuTOTrv_DI4^_aUUCK*_NvaQu?Io-QLx=ETpL~ipR+sQ z%?0~RP+MwhstLxDw?&54#(-0j0H`RX{KGH4_@c>3YZn%ZD<=%XEnSKblJpC8dv365 zHj)@hT9E@Y@Eq{zc1JATSIWSca{99EX+$bV1x0{T9`yNEU{pBc%lk zH^MQ2TtO+GN6)Y7BpT~;5!I#g-MA!(rRB%A$7}QLjr~i8$Oj&Hz*IVt$K^!flp+8! zw#bM7>Z`Bf%{SjP(NjYP_Q##0LU5kzLO3SUtZv*Y$4*;5_x0(ncx|gEe%xLN)sgq{ z@k1CZ`Gy7sAkw20{`v9Px%U7&;g(_gF8c2&#l0|!qBA7|`L(C-0A4167s5X@$O=d? z)w229sSb>n!Ga{KS%{(&hqSRq{KRrA75SlomR+K8_(tQeMk)Q{zwCF%o6~<}uuP_D zOZMoakD4YWyqic!Q={DnME>i9{4c%q5>~8OL7hJY*G(LZN!~l)lDL$cq?wT4w!GYw zUO9U)*`omVL!Y~<-98+ z3Y!}Ff8}yqw`$cYlRKioG7nF0{N>DHxGd}td{dTDH|GL2^(c;hCVEa(t9)3kX_9vd z+=h3=Bl+R@;m2vlHllzi1znv8oHF$Qlnf%B>wo|IAG{en^4Fo^cyOdAx@Gg(Wq7rxnWn13kLV=iJ?P=&{z^<7Ripfk|YboVkcF!LaTONnO@59%dEXvoXCKV zEUq!72Zi`1=2{`BH%o68X*|Uc<(LPp4M~EvHO+9l*&943N%z7`(Te{Zx`z7|@a?35YNWWvI-N;|8VJP`f6+(UX z*=I3}9M;*@4VOQ4?`;Iab_{=N6yQ3!u!Vhl zzcTnl55(%kA}m|H(8LD}960cV*6EZW0LzyzHz}QS=FCBxun62bHVSuj+K)DQv0VJZ z<5ONDf2Lyq9$M>#Rn+^(ju?!7{rVZ5QAn?sElN$Cq_{92huD(GzwC>kh z75~D?6L8-se{@Qxy@^3(Li!S}rQ$kL7+NCLQR^PZj8K(&J4pJFL1%~TE$kC(-q|>){!Ciu@r9BO-}HT>>SR)Xm8U=;gx#HwxkuzuZIlT6gWrYGi3CtU@Q*e^fpZ@>M9 z_RK%O?dJF*_{+w%Hsyo`0Cqv5NJS$F@dH`p+oINHs{mhwHY9QkGuHM0Q18>Lt&T z93L_wO9+ssNGhZ{L`(gO^0D$8RK-}GjP(5p0o4$XeG73-P#5eS5QdNDZNe+Gmnk?Z zGBUD3mp-WyfKow){7MW_D&$=k48Zk)vGC4I;11z@v_Y!_{pQ709Ww>5ugJ$fCRGd@ zI@pwk64yU2kO0U>n9U9|LG62B{q7V~D^SPlk}9k1%tI8pXXnf>bbs56A5S$O8eP(6VaKin%;x&aWArIs({=-k z60NFEJIVEx^d)IPYnjS-eO4ZbzK_e|ag-{T(=M}!YT1@UmJLSgnNpqU?Q9rmFVc{!AIsO%CC;u#N-I{qf%?KplK>RmrvM) zTAHJME1H}b-7(IHlL4LaXw4&PPO$j%U^S`H*@n@cS z#_T^g7blGF7KYn<6vA!yY`n8R-UL#uBNFc?QnNF;;qb~>3}D!@8xh!vY~Ps-#ngS^ zyWH{>d@#k_f&~-{82o6mKt&J~9=(jjVD$l78oSX$6IvMssoB;Sv^q>j?dO|`3%Z43 z%U&n^$S7GEOot8~YBQSF`Kl*{0LbF6WS);d{@6V3nx_)k9hM8z>Qm8M?B^BG|F zxgz{jEJixNa`s2{Y=?8ga+qJT7Sp$v81IlgOG0Wr`%n+6Q6!c6YYU6=*rm$ScRR=|3Zd(NWICKuHv;uu>OL6xF_c`%GsbeV#aRqA@;Arw@AZ z%IE=1+=^6mlVoBWnD2`bJ778{IloR>4x%9xRyCU(y z7hj8AqEDYbrp_Si2{Z@tZ(~aG^UIbkbC=jJgR`rv3kLP-j3}=>{J16=3*t)+*Oo3H zETrc%9Y8|gJH!cH+V~@ky0&-BDA+{|peR5L_M%J0g~~nWW&s~SUNTw!CRztqAa~QR zNZP&`b9ZFnhh3#c3Xml5%ql)AuJ<{-gu70y@4D+*ac@RCAH)QTs4L=p4NfUsdi?nD zMyjnGP_1vxY6B4RE6_)Q77G?EK<~bN@!F6)v;h}Q@w;^ecVGN(V=f+iXBtuu&|451 zYVyu)x#zWAM!D%K*QD%15e>zApLgDQIBV=EjB8tjetC<~(Wl%L?vNTFV~)aXRd-Lw zFFY$Ehmg)EJ@3a|R%f0ABo>U_Foqxs8HbHS4Wb5m$W>mp)lr3^m)EjNPlDBaM4pSW z?W}v%Wg|(9RiKbOA5wc{80I;QcSZXBjFB z`K9y6#KbfQ@`Idz{o=)o`^&>HckWy!-nn2n`yqC0<$wiiwqj92i4osLz}0^2(oRhN zqRMoBS8wzlJQN}0{|?s?x4^E)U%2r6!GnwD=*mUohBypdKxc9Ve`0pjNI19ahk!tT zbahKZd;2tINtR;|RRXC6suj^uDkk@qmc8DG^D6%&3Bbdr6>d8-2JPMEvwRM*rmm}?;}~y#kcgkfdVem?&L(P%8_ARd6OlO{ zNdMRGyLaz4i5~hpA|isXa7%aMso|a_2=7>dv)fx&QF^;7{ABQzLWCE>Bv9|(nZYVK z>D0mbw<_eUq<*KDILD~AR=$A{OKrPYTFrjTAqAk>yjWg*oQ z6!8(Uk)1-HCq$BqaGWM!iNDtcBn9*(SG%bPgM}7ZgiDfu>>jMMX;OTd@oL0h5AJUf z3j=k${t;u)94Vb0@av6NcecZa-~4Fm`NdS0^kO8Nj;QOCKjPB$`Ge)+KH#3aPS*aV zOP9jQ)g9wT4nfz}ZkRo90XFRCgbAuhBs>V`G>Y*BpP%-MqE3~Y($Sw+t!_WmbTb{#y&UeCiUD-{EMy9` z@JfuVK8aJ!N&s>g%_n!Cs=`b<=WLAgKLGobr221xl3Ya6-{Q}{*6BF~CSgOITCGXK}-D3>2EQ5)zsew@oCoh>4! z03o@j_Hr&u6It+duVvX5QHkQ%rQR^>8X=T`4v)3Ao9K6KP*Rk=KK=0g_Hev6btcM- z3!v0qg?bMeGDJscI86$aIG_6R%P${#@4fd-$v77`cT67M6aCth;>U%{uwh@edBzHu zQuy~-;S|gDe0p3!ed#tJav1l*37`pc`Vl?WNDSQ>m~pS;&%AgkKI8tF%e9tKwjHGa z5%h+DYko3DQ3C!cJOHuVb{YaVV88&lxM&i!!wJl+_KR0NLdYk*TlxI1p1v5viaj9( z+qj#B0rdo)GdwUCXGA#Rn~mkz$u7U*?23v~eLA^AY(zlFFQcPUiB&&P63@Ct z^+$)8?g$PFgnhzt=Fq-GxqiL1EwweZMFqBZ8yDnnq&Sh){j_it@6Ih~Tw^T=RDWA8fX+A;O{%-|9e? zXa)213*oN~K_OnZl`Al%Kcy8SxUAF)8J1e1km0KEExDDBQH+GiFF4Mas-9y*{*>Th z`1j@@y#L)VD9X)3FP6GeQ&w92>vEMNF4>SjNbGN8Ux?Q}`sgF`?ERQZe$nXO810{m z|IJ^6m2t&p{RVO^9~=Oj9Z6jGCuJRc6Dj=-r271!F+k6#HASvLHzVrcHr!IM9r0ZA z+3^;^ReecGiih`EJ??2=T7n4oL+IpNft6Hk)yYW(aurTp7id-jp!(Q(}=S<)|!}Bm#vR%e}aZ zudV!h<$n5>N%zEE6_zWng470a_>VT*vD=U?EU-f;DSLoxDN3?Z5SLC>pzNKP-$BRkK=EPgRa7iO7Xe#1W>qcej zc5dWoyuZ60KA!eHi+W_3U=@Yho^i$*wvpENsn=;vwu5NtzlB9S-cV?HR(2M`!oqON z1tT%uKM7yVpkXeq#1L4iY03(n5Xr~hrYl8&CrH&Na#8EXL2dV|^XerRe-;{bVu4m=(n`8LHuoRw2^wX4c#|vshe(R_s{}&;sBnGN=rfQSfQ9}sAqITceWmD=Lm-g za_EUKkot`#?bTv70XS21iyQ(c-w<^2i8nC?sywBhj#_W?4C{ScI}Xgq$8#fZu!XvRUcD->2itFoT z1KmO;s=IcHL7(=mNjS+LD!oK$p}$a^ZDdxX}XmVs|p*>`(zC zg_26Q&wv+R*x-eO2?tF;)I$$GU~12)qOQ~z16?EVYW@z~9lHvP4p`BD64hl7P$Z!G z0`{Raa9pIcu5$Q)arfVnz%X13`7h|e&qHaWAUCvKLvBGy2)EGApiTPp3idxB5m-lB zIXaTZ9fx)o1$M{hx&83uJ6~Xb;$Fjvl)8HU`RA8aB7c+aIU2&AWZ}>kWe{_wD`xnB zUijPa5LWWpgk3x0@M$a!waZGH-q^XWhaBEM>H{od_|0qtZiGg9fXx#w;?g=b7 zQ(;st-z6Z1c0d^FF#Ai8TVrWtDOmf5->R_lX72GJoUsruJK9$?M-o6%d24!IKe| zw-McgtZuo_5Fr&1qzu5X$jN0%HnHYa?)Ccxe*Yu`;@X2&a}%{U6B0Z*#4=DGgVa2h z(maMyt!cfmOf_X{ycwy!bNZgxXi0<8Y-z_(58Ht%hutt`vj~oS& z{$G?d9#)SC4>wng=+O?hpV0;*-FBcjX}9s7EGGfgGf;Wlt zzKmcKJtt+NXtU~RoB+_Vhv>3h@UFFWhwnshstut@`jYr)UE%Q0nPHgZ$5 z;VE6K3YRtqH1~g+H(z;0&iE<86?+e*p?9BNxap>wO+G`l!|8nm+3)|DB((__ceD(Q zDgY{ko)vGk1+R+~plr1TiPozh4VVuMtVI6ftqHHMx`+ynQ4o^E)#{+k-U-X{LhB0kf#C8K1Q$~=J{m}1+SA~s z&AW=!|EzWmCbUOi`NaO_xKgO|uZcgzS`$S$>&!Eaq3XC7^^atx4@K4en-S<%VcLz$ zyP)he#Useu(3=Qd8$C@U0x#TWxt-LpxNj)$sFP~gfwDO$z)5z z@TmX?8P1%VPHzZ(#p-ugv+tHz*I^tLMMo29C`-K(l>{PgGAP!R2&v<=$D}sI(oHD? zSbrkF)RCHyUy7+B92E>DU$vT>nhWvGyi?CU7&;pN*&Bn|3)qE;!&GvQ%6ZWco6pu^ zO^W=?D7}V}rEgFB@kiJ(GH()V_TSpG!a{!L8ZhY4j9=x_WOq>{A;!Vm2ns9 z$utLW*Q@%k+*cd8@fCtuE1PVNaq%8P+){c%9GTl7x24vnMrcEe9Gju&C?zUsGuuE# zK*gbJo15H?3NBK`V>K-?$JfGrc2L4lwPdLRF|;)pf}wL*&?7zkOuR^U-+N#E$ejKH zQ>;=(KL%wLk)SoH&d>I6euL88 zh-eNS+!vnX?&O3hGMyx__YQ%*heaE;lnn|5;)&T_5%_6Sx^Z>NZ5$O9Rj(N}D*=!c zP{a_pQa=uo8@aha!C0NRam4|)b2FO_Tnnx>$Ji8iu2j^L!aU=?)cVv2+%)i_^-2$( zbCEu40~ZnlLqBS{ggKtaDBICwFxGTDubE28LTRibR*Dl)@{n0S?wkVONPHL{i2wd? z1`6owkB*Kum7SQCmP0*MS8g&{i|*u0UwiGf513JEUre{ku>QU9k0IU|ShfcC1zFaz z@EI480topfAqjef`=a{=cfc;RxAnzI`rnDj@8V9g2*;>}vN?R}JRF_GYb-48h94Nz zUZ$PsV0J*eO>7}6D5m_#@ggR0NZ7$$qY4fV}v|_Le#THHh0uaI_i1cTO zGRu{3+qTt2EY`RrlAMb3O{B8?@>@jADnVtxxd&CUW_8cLZ=^ZhO-y#CFv$Vg2x{rc{^?>?}-bs}A^a``oxY|Xfii{EVfABB_b|1y(-)vi7OLq)7yLm7K z-C}~r*j0`>y8172yrUTqX2*g!NhYLS6_qOcCRTq!HQzSNDoC{TqGeX%NmgDVix^}w zpNHG8S?1;aV)M>D$jIfcYOcGJ6&P+yL`mhQmnHn91INVY zh9RxX%-B{gUx76%SD=is-BlyG^tpsF3;F5E*gE}fJiVycv>sRIVSy0(FCDCGJ|jz7 zUmy2>alwux7D9~q`H$wu?&F-Woqiz4P^M=36Iz}!P}_t_(M z`yONQzxCEzb1uE~(#bSHUC*mE8RzGL{usA5K{@2Pb^Ub?MZfQrtuvnylk^encnu6!zWzf8lA;;QShEWAzW;(5HCkVg@L zYC8J29^(G?n3)oU`&T<*>-MeiU^Sc@ZnzCUWJz{PN2kl~3YI z@%j9*>bm{7p2A52bzTd?BBm1@4x>(6r0_uRR9LYgu>IE6kEye%?Olg zP123>`V9yps@ph~KR5XsH)tSLlPk%TgFy5||Y zn{7NoN_hZOxZyfrls_km6>cd(Oxp$AzsSl<(08h6`_gLW2<)`(qAf_yL$F8`Y#%poaRaX_>e*5ibM@B|AIr6i3%g?OjGf{y)PV|~g8aD#} z*Q*4<=_{>hDBI#xc^5%5`gP@Z_Kd}MP-x>R0J}D?#g4cnQ;A90oeZU@H#iojp{w(L zs@9Q)04M^IY1Z`$1gawZ)%*T+IzhhwufP5pZ@>LExj)NqjTwyd8GYicoRC^LR-JB8 zkAq|YQxc34K~4z}(w12gz(45WQ-RJxewUSBjAUgnvTlM3msVXS1yD-oSN#4HLt%Ox zn)Di7s}3MLK@3#@Wxy#7RYgahBl=!Do9V#|thxqTCmBq~M_3tv!`s>8*YsdaS>{3H zk2Ch1i!Z)7mwNvs+I1Gy;kGAq$d)Zzex|!`qFTh4k)4koIuQRH?v5_GOG(jX(5W6Y z4+<@Z1^z;I-YvF;fLDJ?vwWMMeTX)nh1f@9lnV-`qH*6XAKb5a(}_#WTP zT!>tXCq5jXo_~XY&px1HKZb|+;4prK_j2OK)G19bbVjy<|-u8ja*v^KVkeV?rezXiHw2!)gp0B6+2a95fK~d z8S{wz4=i@V<{i7?!V0=qTye#6_HUGxe=1*13N-Znj|D_7`QnQ&kWXvnAQpVN_pC^a zwp$3hZ0bz40HgMgS5M6HU7%_52G7@WVfcd17GU ze43rP)0z|cxl-czs)fIbhA&0J&5pOC;Z){ZDX`*ps?=kiNIkhJ&uSD<2ekJ#S^MDM zqo{k6(L`-X0qBL>U05ci1*v|dO2#t_rR*^zi^l@nHNjpO}Faq-1h zEv5f`$Pvdi(I2cGF`YI1F8TcP&rO-PL4yY1zVmwGY%GG)!Q?vKRRlosAF8{ju0973 z9zq;d7*&XB;vmIi#wS&H-P(0{<)!Dab=@jskls%Zg`z7JsoGGmV~$OzeF8?b4a1U< zAQFJZroZ8J*IieqoPZ`F0J8WqNW-*SvbT4@l$)-=xei~!UTz9KmF5E8OICkX(S0YD zK_R@oKt(wccUkT&74PUtBJkK?miB7TABhyr4%`I4?6&Is%NVDGC2`}!AfnV*NPqaE zl^=9ny{bSlk$-J&TRgtf4GUvgZmp~smtTH)0;BFkCYu~+@SDS&{zd=NNWjYVC&#VTfiR1K2&C;%3ao+1VCP}eBSfdnLpy->YrJ3v>c1+ zZAqplT+)eZN1h0{m*!zat8}c6cEyK_;_=yMpP7>DQkQCzbQ+xiDC_UL@4mxFAALkh zTY{T!x*j(MZH8ka#r|dn?dz|%)3UwB(ytZBGNP@e=gJtSyns)(TBW^TSk0_ZK8Pqi zjH3{uNrz1i%!D;lL{tXKtLPChxPLMT5hq&4bk*3xHh6M*- zCazY~0^4&-7l)#6iK!vKrv8LhhP*19U(NtJe!!d`P ze+TPFs%(}&-K@<8b|e5U#hDo8nShZ4icJj0Pw`w@j;}RUE!ka81RVH`BAqjFQIGbF zbd6xq+f`t&6gqY4RO>t&l>n$BuUamt0&D8QgBU+<4DM{b0p7`U)!3Y|)y!0>rg;?8 zOSm99Ok$~rO*g9M_&R;XYpmT5yh@)ojp}%C5O7-``drCvZQND&jUo5HX%1C{Buhn5 zyR2pfK7nO>Sdo|aA4KDuYSh)0!!`Ce%ZXX*3R>gQEuomRbTvbZ?QqVy=Psfc9^4$r zPj~UFME={SPW{&8$@l9NhQAH+!bJDAa7|30+nC~9U6H?XakQ6|0HnTriV09vDygUS zO`18OwPpyn%dVLim@$*lNWhyLt>P-WrffU11Dwz^CxLNikAR^*2XRi<5NwZ6FexcgAhK%F&@{gOyBP%_xNIYILzS)rv}!h@M+yRnS$( z9Yvn$;Ym-b*K_AXSK*5f$iP%KOPzmj?pY;RhW8c7_u7{}blpSE9o6ocVfn^&bV3ir zx_s^b^ZwF`X6mD?eL8jO z)T0aD_GQ6HJ(7WJipN9$Eeeu)g z5NzDO+my>!rR$Tme3-bLK(O!tgm+Sxn z<;tr%OS1vzq}+r#@e~C;tt!9uqjV=YQX8RhcEy^!VBEPb6u&KDLJb3u7*O&e{qD_z z{G3JZJ@?$xm99RQ5@P?^V}|11(ZM*|e-A}xB0mX2L)S&po+3a8gs_n(C7LXDhE`Xq zgOpI41@h8}{7;j^#L=S5SZ4mIx{4xlQcYx^ut}sRG#))m7TJmNEJCMHQapl+@TwSZ zP0(l(fGY2@?;2LET7`)AoiMqhBfPRUSFf{?^6lb6C<<*lxnGY!2DXs!yyb0u||$ifJ~R4LQs& zP4FM*SxPBI^OXPn7D_0QUc67`SeoFDM_$r4zqY+GKO-1-E#8fFo7a&mI+F9B`3YOL zPdW00Ci^RA%9JVb^e%KSDk;TTV@BZ4k-->Jya*1t#FP_V56)9M_K?tW1kr+#lv80O zfY{hrQ#|8v;nk*?ow3Cjp0*?c*lcABLFJLtxBxr^zjYu5P)uu@tiT`dv5e2z=76SBB-+2RMJXu=Fbkd z#C^r<8{k8q)R7T#J6V#N($m{KR@rL`Nmc#*8ZGs_pPFjS%%AmE)cr&--#sln-D!(o{FjrWlOo8PON>-6r7PZ{`#EcTrTd$K=W9 z&Z8K9byM8(=xb7HoJ-`7U|d0W^=lk8WB~3O6N;gw%ixejOlhR&;7p0ITYy!|ASs7L zfIT99nm!GKhmC}vH^qadf=%C1w|$vJj0L+nhSe1P#qgw_s!`17aLYE)Xt$>g&ZQ`m z$z^`5#^jFljPzO)ggC4d2Z{f(t}0I3-`59Y+q)s4h!|)>?vA=XH{LoL=M-<=mTUj$ zAQAyCgegwJg@Ing$}keG8_5-48pVVe8cM$2K{bKIz!br#VbmhJ(x=soLl0eHug4G} zer5Y^6~|(84=Q7j46x}zgr}U6;a;o0zlw883TifB+-XH~p+9%bo#2u%TrYpB~j$)L9s(+OCCNMCGYaS{qO68Xn*&x`0QRJqZB zYvxD-;A2-{+Meey^H$N5H9@1?UV#;}X3a8HZMsGTptt)0I25HHdtXjmHRh)g`6ZrT z(S>d~E`njhRUf!MlL#p8{p@xm5`(P>IhDUw?>d9L{H;3Bsm!P~-ULNhF%02Y(7Ajq z+Q;(Ps~I82HBv#1-a&jIA^=s#a_rfS@{PiMMF13;DA!~gNjA-JUj>~P`E|lVkF)W} z7mKlM$zoHcjfp)gKmGL6QH?UWS}sDpG?CW+QRMvY^7D`C-5!q&B0@NBusDAW9-~?= zecYeb_;d`{d0>d8X6`+ZhBse+5v!k=jPlrTk9%H&ekkRJTK73cjV;_zqyc1VKgLh^Bxd+Yk#kU8Ie`)ykVisey7?9;I| z{?VJg9_b^ulTm~S(j>sORVejUooP!Fu_Y|plaE(sZo$qaKd~_sH&Gv?2mH_wYven>fR0G%U( zacy@8oaskVi2hfFK38S_BIbHE3UKnWwTz3jx;noVO9suo@N;|#0={30+lFmIyDq)! zRZ;htanTir6mtFL@6nQ-WRPDi+}`HBRF_cRrZcz?|3YRXLeS{XoNHyrN<$S6&Qx=_ zn7V~@;u?TMI&oONdbNqKjtpyO>D=i_$8dk$MS(tQsjUjO(WJt4j)CUH6fq?VzMIG| zBsPeu&2jYn__s=4-QL?Ow4nIpcUK=+r2K;6FuO0>B!+6oei^y3%Snwj64>OVaf zB_qw+VsWL*9q8%C79_Bw98>ps-CpvDo4C70ilH|T$x!>v?qIxxwIJ#U{y*ksF6 z^HtM=O($|ZjSBzI-B-ZJUEcq{FP=2sNRu>LcQ@)nOK}+t*#-<43>kxsv9YlgAAge5u;LCa#p>?fCT){O+eqV{-2eT4zPWNuBNw@{-~V~_dY8NJ_xV2daU(p~ne(8Y zF~)Ti%Y&J6O6kJdYF$PEQUJ0r1F?4_Vxz**FOoZ!&)sT4xR9%>a?A@51<=~$jx+&} z?5C=}+vei2e`UD2WhAS=P{Aho%TYi>c6T)eh+N6dxMc*Dkzxrua=?Um)b#H7tiQFP zdg(j9OWVuZALdXi2uajU9*>JCmdFQUAQ9S>cq_SwTSX7<#gT?c{9$*zaqsmc?>TAG zBxUfugSq6~4*XQQ)i7gCAfE>Xhxsuf=0&3-abv%uw7phfE7w9AawYE+RhIN9YAMCt z8L?LQvx0g~tS>)yr77>iFS+me&!~*xSHopVy{Ww%Jb0ejqH-0c?N45g#gHjvra&J z&Q4uM0IK=Nm~A?buq=^(J%Sp@UkeCYXo4|ec>ONhtXbk#u03%(fl1zhUmUiaW)#7v zLLUwwJ8@m}5A0X6{TZaNdg+-v3H;K;9_PkiNI6Wp1+y8h0KXHUi>s37pep<-j$Q{= zVv0(039-lmu_DXzLX?=HgQf(Y5`pxR2qPC&9R|4~yR~uL>4?Q2>EZX;+MQ&n?JUuK zCP?|;898#~Gj4r0J16irFn_=EeSEPK6%{kW3 z4q5vyfK{wUcQqwZRZjvzmDcB8s-4aPbq^wzm|YaXz1O+&Uj>132y*hFLiug2ei}1NikIninb?eQ>PW zlTojY2xmcDrEP1gbr}K3rpgV5pN}`9dr9D$^gUB0## zczl!P%gyZ1RwZ0v4+37hjR0pF`x_QTivl-8&OSYaMD&~Eck8N?|8E+DzLa<;k3=0* zRmok?m(p^}geb8>V#k;mPr97iiD=0F5f6&$x7HM-qLO7{d~Xe5wsx<}-*b&KJ$mDj zJ-zY4nmu$ps>0N%Q$_g?(iN6R(!GsreLMA`$ zz4RA~?GW;k+#gQyqs{YXdhO(YI;(u;(u;2U!J~%j7&vI48FyPfb{PRk`KK6wKw1D& zqC+TD5h^s87FyF74FHM~w%VGILtZ)X;tmE+Y_k+*QW^@ADv?Epv8XnkFXQ&BfwTdf zW?V!tI)o~WA-#iuUQ}Hbbrnur$wT{nvl-{6?~XL$yCc@ON?Ms58IBOoYIs)`7$+m8 zq8E1{ZLki#l5*z+-#_zdZ+<`i z?*Bx>FW~o(%)fBqLe!EEo=J1xt)pvkI5QVdtg)L~eJa#BH_=k^N?cP(a($;QlDPQN zPM!h2-aTNM@B~PPJJ)`8rRjb?WJn}EQpa05spojs4ji`|N1=~C`p7u8B_}7FVjIe` z6BQL@l!QV8itm>@@t2Fgz=rkf;pfq4bW0L*)uiN`oj_02p_Z9f(TLr;zvd~;{`2mE z%*rsP-Oo0x|CrIEP432KSDo}{mk~f}YO3)!j*ab!VG^z~TZb%RL}fq~V2PSaCN_=` zO^arBo!7`zxHO&4Lfmx8P|}*Kvdh%Pj%o^4YHw`j3GMtxOj8z^h}Vw}!)q(Iprok49O4Hbd{A}!?&sZa zw$nqGekO%%VC=o;Bab|SMT-_Oh_4hGx4B7J zN@BTkA0ZO{FqN+~mi3Awk`Mvtj&*7}3qm?KkxDB=^J{xNu;Qpc@~FHiC1FzrV(GZ( z8f`cLi)PP+{E?@#N6Puqg_S-3ILMBK{$orBwvy?QFc zqLhRC32cvUu;ena*4iV5@XB%GGGbFNeW7Q#sqvB6mk&Hf_Vg1X0C^tjk*Xx)!!lk; ziHR6HcC5)wCqpiTEpfl z5vQyZDpK8zRq#CJEgdapnnu=Qs>hbpdl1;v-i zE~N$Q5(3acKgO!0l8K^2dcd!~u+1s@5;07OQZ z;i4(`og+X;RecqzYg~rgd`jnkBrIZG7Vyw|25n?m{ixKkYOYH&JZ;)EQ~Xj@Sd>sg zP8LddDznzCS+j7%4L2}%|0XD;HIH`g9O_3t&CNx8athA4`yp0uWst`DS1}^G27jAo zDKlT$ZLzxIHsljuR2s8|vWG$oPI+E%iQj zBM!=$?6QHtlQW$9SAT8H%jwE4f0St3Sng;|6V$ZwR4Sm6K=$pz>~j?t@)u;sHgi#BFa4BM z@^u1<+-8+DV`dUNcSZTv${1SvTIXs7pRs^QNuG)xJf*#R$1)Gzk8$xOKQd*PRD0dI ziOMVg0c+vm?z``%c6|=!&!4Y2dMJhUu3fv}Lp$vBGbX}2Jc&Hv-IODaQ?30TQ-C)b z_I4c+p3Gm%_-th;lA_Xa7@eQx%IA77e=PBvkH_9vi39ug7@1XOExP#%_#fu$9#{J5 z%rydji9S-IDFwWg!$bS@#ucN2a6zw36dx-#9&zHRs2cu%{!rIw%C zrEjZjUidD%5pR6E1r2r85b(Q_4ona25&{tLtJ;s3mp9^t04m7KnjLCmK3rfW`gmfx z#R5yd6V;QpRKXEaBd8DgZ4-77!q?(-;BblM%p)1lSP)z|IBksLzvXDD~3ggdN7YO85cd5x;s4CO&M(H!^bcLKL@65{(f z%2T2i@9wv>@Y2W+)P3zC07rj%Kx?1%8(Vr2a6e&kRhIR4Lazus@W2DO@@Ln!sYH<& z5E2q%H~=r@^>%71n5oyvjRQ%Xz(DYy6RX{4^3{!rrlRqXrRbEEL4M-Rm0>6M(ZXLm zb^Gdi;r5jtCO14i`*7if7s{!ng66Ahc*naf+|_MgiSmmWux20V>I-iYgmZ`W#FdE! zh_Vy%2^jLYQ_z*liz_wTXwJJ$;BOk8_FK9bS&e2VS}`PYZ+D!JZkt3~9qCN!)x2># z6nl$L--*v2!o{iF7Wy=pxYeelR{h z{&rsane*lD_^ezIqWnrkDcktmSu=6NgmNTP>1Pbm9HS_|wn%!NN#x>Glc7C8DI`$I z2S7d-LL73k`sWslA}e@H^%4wVwsfA{G0_(Kl>SO{l8)+FMH2#O;ks`BigUIHMc~VV zQTSr#4n)$mTEMTpZ_jzjc`RK*05UO%`ili@5cA_7O6VfL)&ej(Kh%77b<^0FHorf+ zmJNOt55wGK%hlH$AU%tHIeh$;@IlTx+c}I3BBbL4EFl0@-I2{*?!^3OD(&>3_~A6^Z!k?r40maUX2V4m)e+JpBImzu%RdoUC5m4*U{>6xsLhfB)N5 z-I+3V8tyu82u4>f=7flCoAx=3^OW^R5tSHO3Wrmdr zRosC3xpBA^!FeL5o~vidX$iaZkL9t0j${t<gPAGiV!byvB}n|?5oN-pTk;yV!x#nY_s_h^GFof{swC#mKcSTu2*U@hq9~9`}HI7 zNVaDJp57macUSK-jy^I^(#3bhz<~p&wR?XzTp$rp8K9qe<{6UwV=fM1W2Zf8;qt03>Qst>F3kUa6E2M{7~z>8#BRVk9l_taL4OZ&-C+AaqXv2< zu#Xj)R=W2+JZcvcm&!Rvx%FfrQeUUDN%B)}KPjno4yW;486DMW7=&kaF=Bkn$=Nc; z139nul7F-`q%I)G1VUjKfve-h|+u zy*e}l$^P@^%`+xJeHI7Me&aC>A_nUb343G7_lKY3=f8GaBe{rtuQ)uP)faEB+>J8o zUWN`GsxoX}({*)DyB&1H1=9Vz^2#gt$3OmIJmUKGAAozVnuYnE8{m;iGA-=tfJRO# zjsSlR0eMd$ox2Du53VOwA4aPO_el<7;(R0qiGy3h-#({AE9h9?ENI}RJ z{%afELw6AgR9SMpWU%x2o2a_P1$lHaH32-d3670$yf;1eI1ic}aU>oHXwN)rK8BB- z;QFAPt`y7PCfo0H?TL>)$SVeLpp9v=I+-TVNFlMdnw`L(>(v`C7mmcgzuAK0Mfn&! zco67yw~W?@(*pc*c9Og=rJv&Zlj5TAt8+%+T>owG%3gOe@M|)fA2;y~BIcV%S|!N8 z%&|de2 z%C#p)BR3pH&E}*guA?ux8*!-zhyax7$>lKjlX~jJ9}Sg=Y~cFG$6(*VbmO(Cx`3`) z0QAHzApmtCbC*guWpdY+XEow{@jueOb#qf7#WmdA-DLZuER!g$3_fBjr5zp>O${+O z!R)#o&jZzJ;}F;9S^oXHCMqHlv(B7HB_7Gl>1vFMgSWq_bs^SYP0T}^j!xv43j_P$ zor=kLe#v*p&&xIlm5k8us@#2*ghuY&SwvuiNrcQAxcS+l9MOR`j3V2! zWoLy6wU%4@XvP4z+PaJY7+7K)PI5AjU;_p4vq#0kD=*XXk#uzwE?lS3UilCFkwp4a zZnP?@%;)CIF6_@kW11^?hy6(Am&c)ka@2ZLlo>o^sP)I``rng-_V7UoshvadCjegs_M_(Z)Gs9RRe*NoT?`BpXu8LcmP?U#!8ov7KD=4FnDnP|B*y(5E zBk_xrEQHkZk5 zo32Q{3;J4C00GO1grBYee$zlCno5bJya0~o>*woIB~{1u-Sf^=(Nt$ELy{xNNO=zA zC3i~WMps7-!hh>#;el6{AT#}-LAtl!etX)DH{LkplS!j&<#BpW>_$>jybDu&4d?~n8~ zn9?sC3%|>yAI7&h=bUp)AdvHQt$pq?o{|%YeBkBnwrzg~KG;`>>K-K3?r2<4VO*Jg z%wZAWcL4aMVO~cz?SVBGt7sw--7!vA`fRL2ei`G>iHzhxqNbEll7~-XTRG>d$U%6c zdMfUF)dK$By?f(Vzxve{x*roAy1i}V6TH`~StBK*sXy=Q7l897_QS7+7PB-pPkaaV zz>HRaLEzS2%F9l377{Q3@7U9h0FSQaeNq%&Mo!?7DbxeRQ<0cv)rQO=elptME}wSx z(?ZiZ633$blRLM9+)moV7Vhb;uWX!mv_}yp$2K5|uIqbfj#g(VLo1e~RuPni8 z`Zur1wRC10i$og3_BsuuJhU$smW;-OZ+wd*hb_u~(@i&RW>SyQPM5js;|mOUnxp_H z0l(OPWt}~9+(6tlrULyvv#Iat!lNB~sdv4)+K5ynLdgpBz!_GuSEYmdCsEigiW@2t zYq(OKdcA~n^y*?0@>2Al6ws9fNa+F0bh@GM_J?MNUtJ}}_V&e;5q)s<=ut>1FaHcz zT9?7pVGfc^D1Y}5mbVG=CHCP${I4`}nOMiOx`32lCPN(%z5cVyMxOz@iR+eT`*gO# z>=B6bTT6QgAKfkdMSD|d<9F_$ zl+yC?zk7vcD$)T^H6mYG!o_r(m(@vr7NP(2ET7sv8FmH;ccUEG&& zfLM7Ila+^P1QCQhG^Lzmw5|0!uQ8%Z3-cDTP(EC_uFF$V<2YT-#yI)F>H?ZbW01mp z6#{-Cf%Yl`YkZtq=bALaEbstUcrm~~X~ZD>@!Vw0i#P<^A+G-a0Pt%g6xXk;J1WT} z%fW(4^wvs}H=#FTL%fhySZ*9yl-f+;yzXvHmV?yY+wj7okCDv`C^{#iOyU4!>9F(U z3_!%z`s_$~fF{Mh{G? zUjv(}T>dXMu3t$teMR<$rBsxU zzpN1^7Xd#Dap-RqauJYwJKbyg;NS8(m8YpFfAgOm&vDng50wFfSl((_iZ62-?qy_P zs?h_S8jyDK2s(`b`$JPd43Hy{IfKR?N{|vWoL_F=*gGOIrC^6U=WYo}YY-=mK{iX~ru311ePm^N_? zZkrKHy?61$3yDL5;ffGtIz{7w{-E{7zUE$RGuVm*`}K%#~A z)Nl&y>vT1ny&fUnXYHmRQ%7mkY7g7!dg+<~wm(Rwes#h#63pe5i zZG67iFS&=_zmC|R=T(U(1pMdrX&M<1N}xvrqG*)1F{_K6fWKwS78BAc4ZFKqT3Q+& zdGH~6(Y6VBndJb8GEy?Wx+tbzFVnhX>j%{KO2D*KjRdF7RJ-8H7>{W8y; zZNY*Ccx~ZA%Eq2JYy1G*G&360Y@6V5{D`HgZ+=sE{>?Qpts}t0d&K6;AOEq9R^9;x z8~uJfJp+eYa=sRP0MCIEddL*4;IJYBx^cqd-;T#BLR2Z=g&dRzQl5RvMIhI6eJAch zRjo%50Vt$d6|VFwDV1fNk}|LtMF@jA*w<-m4a`(jdIY^}k?`~NF=ttdK)LF-)p+bW z-UKX4dnE<+cx7>0|hr%gcow8)IKPx@)S!3lI8%3mD<{OO{bBExm zuTznqn`wZb9)91PPT-eLM|S>a7~SVd>@^dOD)rq@uT~nV@ zoSDozyyp}Xt@f^!rr@uy(wSstvsGY3Zn<}iVRoq@mhXtOLRtzx9ePpg5CZFo*3!I) zRFwT$9D)#qkb%Spi53d{`SLKM05i!QupdRM4kwo>&LE0hfa9E<=-=HRxOiT573k>| zia;vj3k!=(fLeQx?Jxom(0}m32UIfbM4y2}acxoo0*ZE>{t34*Go2A_h-7~GhRd<$ zu5kqZzWhNyHakQ!hsI&Tp+J02m)dd`s(kLb=a8J7j0-NfpoQK$_m#wo<;$1j@y8#> z(xogJ#f_5esal5%&akLRWk3uT7L3GGOZOPyA248ml6WpA@XznuQ#*c_#>rCMMxm>? zhO?Q!|BewAnCP1Y&tgJ>tU4_LNyi^`(jD3oQ+A)u0Wy`=~{ zDR|{brJVi?_gG=zsyHR2s=y-?W=+67sX3nk=g%iy^!*>A>L#T(zmm(ZT+XXFUZpHo z4uEWqSJ{9xZYdrW&ybJ@T-x8_3REzrRqsy6V;tjfyz6_db%)m522Y}zHr9tg#Tf26x;gmlA{BzT{`jf_AS#D*g zR#hN-Xm2d8n~JBt+G5;$6<|e~fBESIe(5HZ#8b&bmE!u$G5vAdsA^0MItowjxiM9A z=rFptay;;=_^c{AAEjATRn%M|(c%C?eQg*RW@iwXjUJ$O6L90)^WH)$FifGt$~GjK zUqv{s9d0=Vb<|hHx$hI71(Z&JDdeqqg}!=)S$YSF6yg*V#w@=B)fZ5V!>j}=UO`Go zDI?|dWSXNty$eD0pmHH7(t2r~Rb#M}6s(d;3zwV9f(4?|CxYS){Y5ASv?u?o>kc6R zQGYoZCtWx3}&is zJEr!?{2ut-FbEwP$<{9rSVX-u`C0pDHEoU^g{Ks@OoMx~5Y8z_TpiyH`4O| zd9@W4CKHZ=O@2EL_}fON-aBmho%?fxPFh5ru^LuTJ@`3pnDZ!d3$9@{+viZtVh_uf zEi-xa<^86LFs`sta=pyR$S}F^6)NknDrg-fZz{+|+WwnKp-eSkR&m)JI17LIG!2_K zZ>HQ9fZJ}nZ3T4@({uwPfOP->AOJ~3K~&G_Xrlbmd(gRv8sl%5iG%_dUjGYE8%KIMI~A7I=s1$7Lp1ZLxJrk zcH+q`wCiV+8gst|^f#00E9Jb=zPk(fTbr(9o%pWAGq({DO^u^SaLD3rq>z@&x0Hux zB{FSBJjH~_KtxZt20k-?g(H;#c>AqIEHm~o(hjB>MBKAy1Sa$e!-a7vnC*Xv76+!@ zlbNEmM(imBo|}K%r0GjaN^&V6$Ylf|_FpyARNb{VJD)l@2Eh#nI*w@tcxr9T#k!#V z|Lw%Qd6WSK=pS>j#a;lkKufLz{k_8>{+LP|Q-rhmGkL$V^M>tSh+kiI zCrZo9u;|S3PXWQ`Is)LMkx8aH_uiQ=T`)LJ!)$3E*@Iq>fCygG8J0=EV zUcgRx*OP5(zE;i?@8V}E)Wj;kveN>7t*gYYv(7rp6y;P2E>+zT5|#dB4ZRVy7t6Ek zMiVa$zD#;jp8jNzl`c%B<4tqpxLuky=cZFKihHf#B#C=V(y1`yOJ>CbBvy+#_W}JQ zaK)^N=$%`OmtT6?R8SJaQ%0#^BEYiZLVWODI@Ux-;K%(V@zbOd3<{|xG2sMTnj_iW zY7*xBq7s7ut?m<)4KFe$VeHQl7eacJA2T zubD|E4)_1+C#I6k2k(DqidqP$HD?`6MOdjoqz59|RG=91E(y<76 z@_=L<$1i6jV4m-K_*Rvix<=hOD(*o#5%T-=!ptL!uk}<4HPtRqQp=>Iq!S#M)>GM* zUViyylYm6tno6CnCNI7lhO&kPDZeQlt}k^K|5qCKTAbeqiY!WKGP5@`Sy5dk-N61T zmLALYM9-C*P`P9oKKkfGYV8Zn+<)|=9~se8$WPq1EN;)QuSfQAU)(aJ0h6O^tteO? zTjyq{9l6dk5LGoi_#{lqSLq7p>M{aQ&N~gpla3)H<3kWxwvP}^!L2>uCuEk_+31UJ zH`!a18=iQ;&J8H+~I?dKlvQT3-U~!H5G~!wG?*NqKfhh z0SGCc+-#&u9t=(O#FYc;Splh$u@SsN&*XtnEAWcMztfZO>ZWv5mldnpP&Iw+e?vfc z!@9z~{|opf;)v~63aMd(2jY(NN8^%!HSjH@;>q1W#QrxH&|ke+52`g(YQ~Hixc>U< zPbp<33O0QBaEV5SBTx!5t-Ivy*#sz6m5L2!H#$G=9(QN9MPuULOZhiG)=Ez|d%`g6 zh&%@eNximj--;dEw;S$8g z%rDX48;S;-as=8=5UTcu?J@#T0!V4egIEQ4C=IQl-UJ#QYLVX78Z{)@<-T}fdm|R@ zu0>w8HzIm)a0ED+Ok_*_>olwElgk^(=M~ZX@+2w0YU(MLeoPbLk4OW`M{q`24^TsMC-E)CxY-yE_@8m~JW`>&vudM8tw71!~3L;wmSS0R;@ zl$2JVEN2!aJbnND_YI}gg{s`66k#XrcdI@8z&|vtYXsT(d1v2>K{4|gVD(Sz+_A#| zzw-G1?sva4wHzF&Wm==bb@e_i{c?fLqHVj zi5)#X^IW3-S{0WOfY>j|VPQdjj65o!+hlX<*KCmqRO!{B_{%0QyuG~y5xtUe)|5W1 z31>re)nUB5J{^np)td-7v2kWI+dF`qXI3ex{x(a2BnJ&;d=cA!W^&VlIQPNNGQlW` zh{{VVkK6_11RNZ~Nh8)_(!B>)Bc?bVHz!QM?8_4IaZCwTY%a#J(gvelRmm_~@_7RN zX&<(+)R~Q`pgk}wxB_D%>XAsm=iYq}_<9I&L2X0|-Yyx3r@!8aqP#2}T}P8ng4ByKMs9&~e--)Fe#BH(#&DhabFWbVtnKY|6?h zpMOg-yG(hPTyinF&2l{O2;H*}X5t*4b%~gU`)-=M#Om^TFI3yTScB5na1m{-sbe-S zBLD%vOk6#DdcePqq`Q`6xU~br?+Y43@dV}E|L!=3xZad6=gdMZ6+QLL)Y<4U023Kh zvgPOwyiFt^DlLUhn~ihAyHLog6jp6D#b<~^_|c`8 zV#AshSe>75in=J+>;Fs>mF}6sDpd9OLN+In~799Q}y&+0-_xSG}v z4XNYOW8tLyrIee4FlXj;gXuNss(Na`?a`?0H5TFAc)3=lx5QaD8;mOayu8aY8yVma zp^NWit14@o+ykGfgpD%6DI!pufKk#rE#66w()Xg^ax<$cVK_QOQ^xdLbTue=GLy-DP~US-3;B1fJrr)M2~7 zNpz8ypW-)Up_n#lEPg$y2NI7hr2?gmeeBMmX)S^iNEoQ$F10pX6iV9vcIzlKjYH-^ zeBTcYU8MjQZ z^gYtHp@D^Aa~ay6k(rB7maCIPnJdj@1fW5v)$_>>Ha|X`w_0DF{2T($p-O+ev9p$# zz6Mh!O)!Iz;>=EsyK1Z38NZBxp70KiFr~Y85}#CaH>J!|LSY4VoOtnXd0BmZ*rNVI z1d7U%C!I<%8#l|A#^E$7Ici7=IG*Cbn|m#P?(Y}R=|bm^LIjT0;TVj(r91)WGT_Bk&#R~RyvN($IZ^)Dm;UbUKvD1VL1|+6QI2y zAjdOZ76F8%gam4M@aufT2zkd1g>-b}c(>cUvFR9J%n+QClt9gHiZys507nxd@TR+z zA9KrzonA)!uF8H%p{JN?C1VhKqlrq+ODkrWXS(Hc9Yw9W+&zCx;5RP5-*@Zi{?vC~ z6GyiHLW&v-)>_S{sQ5w7|4^aLm32SQ7 zcI(w{Bga{sx)BB0hmEt3Tx%7g`+ug1fEFIYpeg?N9ZShS_Y5gE#WIJ_NL%v|+-Wb1 z=x;(JlLa2lTe~g1y_jDi}P;YbgjM?K^FB_fe>%X z_9ry#{McUeBA{Q`#|jc!L<{B<)O$TJnFxo-rn><_7&*N*43F*&z$Y8i5lBUZWIZB) zR4R4ok>LKOL$hktDm?q_v&K&$Dk>V6jg7#$!F%CXo$ofp*XqoK0FE=Wk!>w}8!ZL0 z4*zj-C~{yqrLoQ-hEU#Mg%~;4Jpmk?3wO^1=4K2TA#(Oh#Z=;sEqq zml1&SjH~LX;-$+#(&>4s+*0G=k39`Z*uXHU0DnL9;$Xz)iT!Wh6cuMzL3K7w=&U3b zjpVtMi>Q=4(x(xQjJZcqT?+G6kjU(KD=MqQ8_)Zda_dHN4=OpW2r?BGxneM%;lMCv zG+p~oWxH}cBJr=xc)Ydw2=l`?f`L79x+$Zt|DEjp)2=(5wrbisUY?w;l=5G-mir<=tZ`~QYy-Uh+dhNym4ZH zo&Rv$KLM{~^})Ya?Ii&#z@?X6W^B9+&bWoW@}#@J?Vx@6!3Q72x8Hut;vHeQXhI@x z8d!uR8-ZUbZ%${^IpiMJ5^$GhP>H*>P9Yd(Ps@qXv-fYq!B_74%s1$6~|YP3YUF53ac43S$9it-t2qyNm!t z{pF)wka`HY#TBRws|S60PP8hUKX!NyMotx3{@Mz7Q(N0oopM^q85Ku>+P5w3#?z{-P=PCej%cJiIU^iQvC4ak1N&KgcWOL2;6!phf?6WKl7M8qRWJk}uUd;xTHCI^`fB4;C9d1m z<}w11Od(9QediwJ6%?a9ks4gdbplAXDq03|J$k{D1uqMw<#%!oaUcVYGR zmB=b6HAx#pg=I-|^kq79$A8?Y;%c)0yRE{MqavHC#1n6Q8U^ zVNQmr)xKcC0@X`c#xAaNrJJr^qj-e-@4w$D{(OnB&z~{`Hx4et5DzA5t>wP7Gf(rg z(={$~ku45e+?rB!iRv#W?oq*vIf+)L9+h}g^&CY=KC=z@mO7wy$E-x0@^TZ$CtZ+o z_o>K+EI%qQK9~0^afopMawGL`Y%>4IxoztfmA>0S$QLjW;oE%2dppIfM6{d{aZoQM~%tgLwbl_l@pLg-`p2^M1~~!ao)t z)=tC=i`S!`?A6bHaxH%T^Pd~5iu2>z`|L6TkT;fMjO}!p%`GfNrHy2pNN*6u}{Y%@2)_`p;Qyh@xTKQ=sjJ(^5xbhB&(pMhaP$e zpMCZj#X?V9IC~;)8(xVK4XJd!J{kCxJX2;@mCh1ElwXC)tE)nhfJ>QkrD#)Wb(Pgp z(3V(lqj+j%CRzsdtI*y}N139FfWIW2j2?A53Wj-X8cnfe-Ia!0>n*PDhT-(&q(SM! zH0pnd0F+fndLWsA1qwP7%Ib7UU*OuImdvkgPqG+IiKFal2QIRW!moc|}C>DtwMq)C^|uUvjg zK%)Hpmz_TszZq4JA;s%qlfzciVbq)SD@ugqVrn@$t+nbq&P}E= zHkuyTr1S>~H=_83>`Mn-CSNK1MvzmBCI^tp{?%03S>B^61?HHW`Jt2lF&8u=G{f*g zVKNryNzYXdU!OYkjEH8*tw>z#y$X7R;%n9LhS1d2`P+=4GXk>rCqq0+1q5t)$KyOPRvW};^pzGm#} z(ZXU>({||<7KrfLEX=O{3eonX$oIE{3Teb~L+>2TFv&#T+;l)qNACEKhe;WO9^YuC zj`}4jkK)J;pW<{NJNjsu`}UUv;?EmPuxUpQ`uFQ=N@&fRHLHYxc{W{GNw3`3WFC@V z|C3KXX`&V71AaMy|Bguk7+0Q>n3)6YuhYmZe3-HB4(^ zt?5~9xPqQNEJPscFHTLy0EvrA$?dpT+=FyC%Z^y3#V7Z+IEAJwI`vi$Z|td$#lLB_ zd4E$jb24tFn=&yWn_O`7MvXz;@H23g-zvm3=AMEC?6iE^dAf zv=bv~=PWt03yb(D1HZs+3*|tT}&t3T_`#ih%_y$;&s9ORj|gU9k{v?y~^ZWZ>cbQalAR zx-*o4K_Njs5bW=5s^s`IR-%sXx;e*+kww`+GB~|VAtj!~hKHwE$u71KsV+{pGT-bg zvPx~qJojU+vA8SA_}VU)5Ipxnmr6f;l9!(oaWF|jqpV~ij!aKdDt4vGWc$Xk6uh_L z5RPVNnDZSP(bM?6C`NztrVWgLnS`j}V{oa*cL-=KZ}zwb0|q{HY?GL4r%SE{7fu6j zc8B?sKkJ;HnP}~g!rHfS%XCI1YDq*@`nVeiD<))K*noPS5?e6pJ-x~HpM|^byxl|$ zw$#0=-?@wcL?vVflqI07lBtJSJ)u6tb`m=%APn)W!jBWHurG&{fs2<(${{&h6hV`v zdw_-7+F2h>Komx@YCXdogJS!@CyY7>E^wXQlj23S$=s8d$sGE5M^IBb z2WUTN5D^_lMbnvq1;;Ij;?cS*Xw(p)`8R+$Xis2HRRr{#IGHG25(WT z_6Wez%KrF#cM*=}95G2Wl?T!hov7T7a^c=g+Lbb~Jsn8Vq@`QqlEIVaU8)I6jo*?f%1pxUyCDSl-Fk*N~r7*;^o!aD#J0SSnR z?}0OC&qQb0e&=Cy2mvS|hJrV8ckV_GOKR297t<()oGB?MHL@2o@Jz70?!>k!Gp}J` zbe+XrIgjDg&%}UING<0kAF+pF@R^rj;(0$qecT{q=a*uC+7awOun$?enb^0x0U6}) zE13sf3L~*qa`2g*M9j%W6?^(TslQ}Og&hy&K{b@0bL{$w3Yv5>Qp;jii>t`Ap*y-iiG@WQ)f)IsQzHvW>*T zW+D!S0F7uB40^OkJlueC(_oa$O5XK`%@dJOgb8Zi*NcJ z5-+|QHK8F``1)HctnmT%(AJ%ik$$2V8?{TGRK}!IrM=-OtGDbS(uucRhS%gUUpx=3 z6j7?cV>V6;+nL6VIn)q^NB2bGl{FcNW?)BCa8DsOVivpH(V1>tyho$9sT7+izY>p1 z{5gBlP~0`1*>Y`J7UefrS@OOzCjECGDP0rNRdyX|i!Z$JLf4!{d7)!ga;uxm61Mr)=*50WK&v;VCRovHak63BnsC@5mYh=aG zef2TepHs>JqjD-weTtVi5IeK16j$A(B8ahLX;Id+}M@u$1iPXwx8`Dxca86@!LCYGgMA#x}SXF z2^?o$0!2_Mi;7~NW%^J|xtxwN8So-oxL!*$YOuD6AnL%}O1Yo8OkCqYS{gVvhaiu~ z_Ql}km4^@$)&qaK_g*<)6f#a?CU0>k@K>{cKLNiAcE0h(8-_BSHDe;~oF0VnH7jZ7 z=fY{-xrU0Vcx%6v4^hA`mVfHhsY*F+l5Xm-cdU8Cv(GG?_uC-a?|+2{-&%(wR8&cy zBNjY7fW5VFU_15<7p~^~lwM2z8{+na>}7dSe26)QO@QP=PbjwqB8Qs)s;YD}(2}Au zXhNt0d`HvY$^$uO%ovn1Yw`-3A-?Qs$Mu6r7VT(hIiTy_&DPDJ0neGTA? zO%od=9fjDn%*-SB{G<2rJe6Zd@@T*1K8RAOh=Z#v*(oC>@E`T+g{Sr<;J<6r(35Qc zUluF?3wD+uNP2*g3Mr4Y6 zjWWL~)+mTez|ZVMCIy++sk6-|aUAAc`&)dm{dQziV=j}T3Tc{kRkz)62HG2&9;3bN z7fvo9n@E6jYV1S+03ZNKL_t(yfJDp?A@>fnO8BF~JB+%I5_6sf>{?e*RVln3h(PNl z|Cf>U)?2<}88)yK(8VdtY8BWtS-u5&+c7xOMqddV4(FFKdz6Q%F5H3Pw0|kbp~Rmh z6%9=PUE^}n&-Oa*5CRaO$!$?-jMi`1h_$6dFt1lBf@;&cy!rC{Vg#{q4=t?o!7Ue@ zhoM7;8eeIp+g6%r-uH7IMnT$|RzE(ac={u_}w&?{vzk1Nc=(SyTdl z8NIGv%pQu@S8YXrpAQv&_bNSA87b-6?2*EX+Zr(|d=)hE;)^eu?6{Ks=FgdldoLM@ ziFvQVRz*_W)N~}}Nb|x@%hs=hthxrj{N*pZ1pER9`5VZ=s7Jpk=-F=^Y+Eb@APa$m z^KgvA-S6@ioIrV5QKS;_QvQVI2|C0xRhY7gFUpq`3RPh)xN_JtwqU*j2!%wmcwxr+##>sXoBrsz1SUhymKul~J+OkZG6JYl)HXF+QqVPuj9Q^hD z&8TA%i+k?*gW~$L$O&D;PS(5FQD-g_Se57J=lj3&&O0nP@*kbbL4+rBr|Wx50!?3sVfDKZYCq0$@*d`FiP9?{ zzc>L00ucA3GTZXGkWXuDJONJ#z=@NzdHBF1B$l=L_&wLePEM)25uD6>N6sg!|w?yK96K&W5SRm+&s<))4X>Q_^Bun z`E_cFx|3PV00O_)Ixz1bl1M2!+jRIv{lpd%85x&j)knz7%OiJ2aG*@8YD|W!I(ayq zeWc6xMUcgwOfJCBi(ZY#tbilpe;4-l`$zPo<60oITia}21_6j;(%iPw?5FvP6A&_x zQdwo+;^PyLketGEPZq>^zO+EuBL|w|oE}^=FRlx*%E{M!|JY7_s;AZBU|}uNvWw8K zPal_4ezo_oP9XrvAG2o7g3=D9(plo`nxWJXMz!~>R)3d0c|8wr5t-hev@}TTs;2(u z%$Z}V#<(i)h}xZf_SqOSf@2Eqg|P_%%-ULfO6pf^{;;=0?feV5&dxcBtM)Po(=ChPQdx_ zX&^jnDzv$dRu2XB2r-WzKmNozc6O|yf|7@mlaq}iOxbIcRajhrstAYoj6zsXlH%s$ z>FfhLaGy6}Ok#lI6y!Q9H{>HUPqw+Y&HArq1Zxf5o-}-adbkc7Hp~znxmT+KwhG~D zzN-Axt5=L!(_VBv^kSX@=OzxK4gqK+V(_B}l=?EBtIij7Bk-G<(U>2a4!=4=xu~2|)8QqNhLD@&VKD~c zp2RVAh4ptlLMB6rV>4&YG%}|sq>74&+Zr-zEc%R?Oaa_+^=W+PJe5dhT5ldZo*|ih zr4TfYf4kBw@F&JpO`SbQq1R2DHX%Jd-RK9V&zOP4-Z4mOID%k1F^$tR8koN9 zcqtv@=&I=F?SUYQ$;860ol)!QZT{at4kf296f2L^BPzNV#*G`-Eeb$Av{MK`H})YL zqGAStG!5?9y$?^UC_srXs4E_4`Jt6DMwl6NgA&*&o zaOJsK&KuBb-&9nEF}s90bI?b?n=4$#sOl$R? z?)#yFz~7gY$5&y!a`l}wZWQi5yD!cTVjjO5E)W6zl*aXwm!A}2nN)VF$<0?{)XD2+ z{np<9V*8~_(Yu=Z5K_MCs;dkI)OQjKe7HC9DFYBPfZSS3Aq-unI^!O%r78!G$8>|9i^LcWSgy~ zQgp}ugT`yqBnxO|e2zZc@vc*#I1`nIQ(H+SC{D;#1mH!`9a_H!@%C&M)vU&@UAv3| zSqiqvlP4R5CoWeAP`ZK%wd)bbh`^H@bs;t%7QL-APHKLPNAarTAe7X!8=3;)iW@_) zyfBQSXqVrsOJHZIYm1gya4&P?DUGXe)H@FUOz(@&cOJ#r^Us#8e+z+V z)G61x;S1W>H!fSYtiNRb&15^z7&9FAUN9JQ>zBd1B%@`7)ie%8=gBQr?7v!KVuI0| zG`D42zqbFs5W8Gow3=Xix4#Gz#*W5#!dhoIyVjmT zCaPR{i6WoCHjsCZx)Grn<9UF~Bt2SZW*fGkfw}~Ro*zd1# z-zNh9ek#?*$<=xN+O-(pFA9GiTZy@)AHc@6Q75oh3qz3gL{*iR9Hx&0=cuZ%vuDgO zx|tR(clj%s!lVe3m?!5iWu;Y>+LvB>$y7*|d#v1&%Sw+U_t0KO1d)a75-D+cXs28# z3y*?m6iv7BsP)RFD3n0=6qg#K`6_Z#v3FA%>MHD*J0hN;%$^9bAA}DTuF3|~r|~di z8_0#VxEXdj26?dLH?wBj8Zja%lD;Qo$tc!#6#>|ZjB^`%;)R0|3|1;PCS7?Yc4zA{ z0uVNmN${zso-zd}7QX&EHtfm3;)K2!J2Z^gkh{_n)oq#uZ-?T%rO1)DnSvbT=PZAN zF14a`LdSX>DzsaQKXxY5k)Cy8V`!==_KU%*71QwS7pshi;{*5Ke}H-Xg1Yo<7jLGv zKZ8zA15~)Naip(0_k0*#mkuGc+HwMtZDxdmysAqcGdQW+PQ(aaF@tM_fkMHgOx8AR^g-MWkb90QW9BriERj>vOuds#3F zdITfBhPDFq@cP6dw1--dT;P$OuzIP$GACw{AlK z8koX`lwd&{t(*ikfw6e6aW0la^o86nKTdE2BQTpD-OBvx&UV{%?axxdN}UQK!W2Kq54f;g@d5NUqu@PD$t$daJQ zPf>iy`*OjSFUHobTaAT6x`80C2BeVU{m?Cddn*ngj^~J?vUybzhnn03Ee(!qCA^?; z;^!I0CB4wi^kq9I#ac&~5gGfTu*#ejy(k8hqJK;w$_w5XsiBp&bB&cZ`<@eL#J|LxJg$=o9Y(hZ$? zWJm8I_4JgB^Yg6OYbUk8aY`@zEGZu$HVTdeYFC<$n6&J)Y1%y)I9((NR3f0ZjhO^HrTl%fXNQsebI z$vHi-nT#Tbe8lYUmq~$P8H#ezeJ|b)+Bb4(tDbFl_N2 zj|VC&&T?88@yUfVL-x6*9|)xcX`#_oOj_~@_|B%*V0W)fNCXo_}0eei+DTxPe~ z$PiK+9(m*uR%<=i(HYT$dz&cd;>C-Nqfb?NDXyQ9j9>OUhHwv_S{H#|Bb1aQzXlVH z$G?^1Fp>#ZefE4nx4^A#nS?9=QV_~YprkKD!kG@sj|1uKVeh6<5)MsbQROEPX38Nd z&l5UtX_kWp#O?wXFwp(t-_19m2N_3+2XLhHR!n0BS4JN|0Sa{!Ba6 zM$^v<>`?JewZq3s@W6wQ;?w6JMtxzr`Oc;Pn3o`X#XBsF@g07<(ux(=eG)G&?q`E{ zbRT@uFctT|yNUS&ZS*qy8|KcPt4qiP(wEcCO~5br(z{t5wjlo)u9(~xcMix!w5_N^ z!0#9)v$GrJss5HSOc`ZR$CF>z3B>8>w2gO#A}c7Sl~!gNbcs(Z@2O!j^vqBq8Jq#Z4p_VbaS&mg!jnZ9;l7L?z}2Q zh6ZAEzi5{HA{JL6%Z@aP%%#3j_^P}Q?)$DBn-3nvO*j4mx7~JIx7z$$8WL%5_cliw zB{?f>-@FmKrp-b>pDdE%w%O8N1i$OZhAGM9W{R=v4;A2!KRt%cOv-rn<=0@qxETlu zk2-0vGEXT#p4?NbSQq`sp3V5?-B++~Uj>emHP$w$z{M2cGj1In;a> zzYHty><3=l$(jS?Ht!(t%ZGqJb-eM!R0UE|ml4Wftv#4OCI$WK4^aN+e!AKr31$Nq zFpo7g7gr9)i>nSJuegeo{}!fhyWZ`H?L0e5v0XrFA1t#k$EQTeUmam7GP3>>pMFK)Kc5_D zXAxMVe-Jj6hGX#tWd!!YIiusy3+t$u;e*;j08)xGTCjoaS|w{}>?!fX>lu;w`T+Y0 z4#A)9x!ri!D*M*yXx)wgG-v_;j2SabSml!MR%7ebi!rVC4ekPWq>ZMckY{sKbg&;@ zPyhBDVp(GCT^R*@ePTSInkcq8ggS`MP3vx)eK;$L6h9&Gi}f$}=z)9I(Jbi^j)(4B zaN2=i;iU>{+O~BY&YLzGHxI2sKW30=9@6VPmv%pMvc8;W2-k|shFWr-`JNG|3Ga^{ z(sXuntE)JU)D7Pt_ei=q-_p28l8XK>H6Z}yD3mXNIDn107DA8}TA|X)kgRCXUyQI6 ze^Nf5pcbx9L`RO^s+obK@b*SeTAK23#oP&);GaPZ%mYiRZZ%$LKJ#x9Ma3F4Fr>HE zH<+R3aX3=$gB2N#_+(!tjxdLX+_x2Pp&&bl!qwFwb>%v@AOJb>C?r>PIS!}OTGAb#DECT73ekfwy_V6}IQ2YI!as>;%=B)o1t3O+WqS8u(WCxSU zP=5aZnZ`4rdJr=8en#AyO+}y5mrvy1vIso6#i~E38iO|u=d~1JI;8Y-Oq9B#>WD#D zdMpv2Z(501TD)crib7AHY}oxHm?V^#xPgRDFXajF3q?afBr3eZkyqn`L&c5Qn(B#- z>E+C;N#$>3G*h-+ZOpC8N_4uLTM&RIq4)qP*rYUCwqZL~OgIzg`Wz+{6O!9%+(aWNx7pcH#+Q+?U{WUDo~La=8fFoVbuC_fpd=|fQ~E)0gI7c?16iB z#9}v#cs%^zy*P(R=`=OX!T`Ur_`db_yEucuf9LEtjIUk>TV-*Vhaoy65l2){?^=_M zhl}vthMhS<%bRviEC?L-6W1OifSZ z?v<2?CF^!0H$DRKktqnHDYm{mkAXo&C~EXW3AxT9qU2)@!8le{kL;X0?;6Wo#eP1xh1UuU(H3DZLP1z7v@ZKKR|1D5Tn>@#w?% z(9S=vsS~%qnUPB`@x&8P;+5B4$C#1B@yGK9vpDKWXe?%EmLAdQpix-(@l! zxTqWp-}(R}CQhT{$b_yxp@fM)mp_9QA1=fTOLIuU$Z7GJs!}V;YWA_Uxrmk1i+knR zOLM)x(>+93-L($v>BN~5SE7o;8m9=xGdylOGcqyH>`kIUF2RgLXRx)gtG|{S6$U#i z!tw0-4D8%jU|h$`7$o)D^8N4+3}(u5FNAtG&_v4k0*V?X)yxrKCnsRbgD>kg#?q57 zF)0P-Upxxq8C@w|nc^yb$mTW#ph<}fko%~LSFYKcg%4>SytXHIfbPO(6WW`(HpqFC zxM^bh$?RK=zwPv&jC;SX$Lclf&_6zsMKYKc%r_5z+}aCyfdlc(eSb2s@s3;E`0g03 zhkWN18?k87e=)j$93D6)22+?q(DPWT1rY5aKo)=z$=}&2w{}czv1$?}x98>3yN8iTPmQALk zfZ)7Y{9Mx`8voi-hc#emy-3XT;>=(XFv43>}W=|MpO~CQoQ%!!$C{I!`4f zmCV0z;cFP15`jNVYQ)ryv0i2y|nNR<-lgmoCU8NJNs;V|6 z%M`8YP@J~W)yY5Y{ggcOQ`ov<1)f}2kELW?{~Dm2cA9D3vaO;Tuf{n?)dfXM$xV0DGFlK zyW(K9|N1NsN^!xeTcLuwN;2}l*gWY2zrdXXQy_^FD=u5UoN22Y5t=fJIo(;{sPtIp zfkCG+BpmORkHX)-*h{~cDqMT@&+v=$CgN3^4l;ws;F*6s!Q>)IywL4U%&bP_rL@wj zVekT7d`G54;ZGA9FvT~Gk$vO`WwGEv>h2~*vwYqaPoY2Hu_ zZRHlrRk?xyDJLbd_nEXI}2pLI6@u>ze=7#^rKv)1mvxPkv%_0jpN8#($S?!kF`^ zIpt#6s+#z-jt+rXeV_MWytui_qz+e-#Pct@1m9$5peki9{`K3t46D`AZaZ;3kDrld z{p2L`>Z`9B;2%mo#2+Sj;0&+*uqkHO%}pigM^F^_<3x+veR@cm?>dvtTTW66;9(Ub zBqb%8gQ`6_feh#rWv{32#PJN&t$YSYzIg**?JL7usaCdK>05+c?i_0Yl=Kb;-8G++ zfRVtxXs=a@U97hPbVTJ<=~gB~$>HJ#o~B0r3j*z%yjJlUy`_}n96H*h_!RKpzs~X- zi3_rv$*vv*t6Z29-1TGs5u693O|?YEz2u3g(u~^__z1sy$4G zJJZCuP(vL^=SyAEcNrB|J+0&9w4iA$&arx)UK^Qy79L%_7yG{StZO6^-t~<$T*aSWm!zHNeX$4Y`h4U9BZx|XaSb7n~T?J-uP^Jzbd*;Vu-Tz3fTTI0XR3= z^6MbZInjLhS!{SJxs^Rd)XMW2Is*J>fYJF{r`t~4uMZl=R*qBVz1`#{`cbFw%Mo<^ zBJi7tPj%L8tg2M~V{!*dLI3svtAyI@1Pf`lgn$~D=Re1@C*I5Kg+*(=Vx_9VCPTCm zrTqWWP74B%{G$xNO0TW5)=O4xCfOW|-;EuM(Shj*tfpYrj+2lUT)>}c5626YIwfrY z03ZNKL_t*hV({j=EGm^687XzK$$#%)y-wrCaM0+fxOkpR@LC^Pr#CMO|S@FGk`iVHA1O?e$hSxBLQ0e2?Dh9Qz(NwSZv2y@Y;do zR)koT$VB10Bl)*H^+eGH{NghHUwdZ)US)Od{S`9L1VR#~3`}7(41$6Ravi`rP#k*e z++L^JYH$7YvAxz#x6k){*502Pz+aoki z-}PFa(DZ+pBOZ)5bG@wyTN1VgM?5QCyFqBZEfLxF#Og?UW#MY;o|0+p@+4n z0N403ecd4pfC&K{gh7yS(!VMW{+$m$v#t5*cK6pWwkx`Bwycotiqy#SaPfKp+$kg0 z@c!EVuq1o2XrMi_u+aAJ-R)`=_u?0X|U)%)pHUdn9t=5>m+#9GaZLKprT1c-(H5=lmqYRoIv zdE9L)_k(e7L6MSj>V=*2e5ux;FiDQ>jU6-69=QL0himCblwQkmor?c!Dm$jZH8V0YT$Nf}ASA}xY%#fv?vZG_OZY38f;H|nrpju6g$@*p}d42pN2MD zFytv@@BP)IzqY~xB}1J)#-?>$Z;`HQ&q*8+E8NErAwoY3_Nc4rIM9)J2L^~}fK)@s z#8)8k=mJYQw1STu$CzmC;v=e$xc@jEJ4PA`!DOvnPrtf*0E$l@ zK^Ps3>j)E#zN?K%wIz`g?7uW&Z!TPE7fzaJN)zYO-nl-$Vs9PB0DSX?Jpji8APAC7 zqMFW`JKvV9+GyvWGuoyo6VQZSLv2Jtr9~Cb7uqMzN_$PVH@1e@BQhWsXNYI0oSFzVw~EUQU8TR1h+Idamua>6krY7}yx%Mex%GcvuEhclPKMabf#$NW_l^ zfsE0NmvLY-fLXxEw(I{G8eufp8{8QEUa;Ahx;7fdKFvX;`ef?>iqgm2s>0&!)4CD% z_^0Le{-X6ZLA4eB^B2GP$`U^_)8Pz&i~6<$6tAHAF9k5k$^PE^vuyUK2{u$^!N>LQ zZqa*s+CG_BzQ8<+>-a=U*x7`oCR1&hAVv zu-IKIJzZIg>|`~F;2ja+ua}4bM5L6$VsA|dt5bJHc*krIr^b{Ls~5}z#-ab0i5aYr z^d&fkc=!j$dc>%#*iMono%7{ZL``>Yzd-k;{y^VB$P4sD@cRc$=q!z{R{g%Gds-?& z28=^Ieva-ZRQJlhzd0eZoj?u&++QSe3_$y8P%++aO0KSJr`Y@`_QpFZV@b=qp zJKy!^OXl0^6%l&)S`o^$qGjbyA@S%#4?R>Pbm5=0rTDhKWJz~q`-`&U-a2E(4EuEU zdv^VVL3U?9C4=0x_@om*1wY=;Gy9c@f4w9%(h=7csys}91eOCtxVQj)5-i|EG(SdD zN^s26t7Wm*{ySAH6mZX#B49`S&520IqJ~2>5FrxYUjySZLCoo*zDl;S*V~^%xDd3j zDN@;XOJYB_#>>V-pXA^pQ7cJ>+-9DGePh+RobT%c41qJ&sUNfx;{55JxPG<`$D9ND z)(J3?6=FUBkN`FTDW|Exw=FA;uz728Eh!<+?z;0X7oqo6GWdCSdgS|QWdIBXphQlN zSMCU3H5PTkX8~4_iW>hqUIenzPMbEZLCiu*qJ2j%WK~DDKMLh_55E4lUwzT8%{*v# z_Ss~~W!p|J@oSN?FP)`s9})2*t?rP88-F@mff*v8$5wjovzrEM&)!o~Ol*+JfFN3J zIsi-i%NsmcEYkMYVPYui2LMfT2@0{3Y!k`5TUr8R!uaO5iD*Ii5g~{LpE?CoGNsyU zug;iYW~-$g{ArchYg;^KLPXxZIo_7R@7^6o(6Ti#2R<+u(oo?80+YN$zIfMQNEr?Y zslW6_yc=Fq0TfL}qf&B(g@s#cN|M9*pQ=23zN?-IpMf4}hmQ@oWWRp>EHg9HrJRQI zl8qKiyO_iV{k~p^s_9Jw>qz1+*EN?^96WdrTFM)*ykr-3-)*-Ks<348zhR|fm7k2J zejqp>@uN=T*ZzUjzX6NNXauLsWg%~DzB#aPJCfV=Na5k7>6 zeSjQ%Fdl$GZIawAF3c7KgCSZ8W#!7GS>RSYRzvHUTjbdl{#EyV_#C)hM6`v)BuXRb zB6~)tTZ6~y@2l|p8N&cHnObJ{v55Q=z4S;eTP~O3`sAgh| zzx2Z2YyTzage8CwI05Y(O4@E6zMdU|aX z0g?}ojJRkHq+p}4rauXc3J>9D zPftnWZ?${JR9IHrK{ky?wx&ggs*Hu5NVuJ1W4NnOSGhT?-o0bxvWkD5&Ut8g zZIQ0r`Z7Y!_{(#)X5k$B(eQE`-77*BV0u_=NSO$sX(emHS7@Q5jzh#iQ%fp5)xTw@ z{J*fgUd*AW)zg_(YLh1Rg0YVPnJ4QXU6==Uz;`f~h6VN$B#CW8{csIu< zV{IBQ|2@%`D28&g?uGlBt+_`Fz+Qpf0b}XBB6$d6yx=1T7!o7G)k&nFixp^kd<|id zwza;ey}hDXQLB5Eq2~&RFF8}gcTaTQTAm+d04--k8l=98*}s3k0(@Sv1#{lDe;>A2 z(zMYY&l{k0ST%NK+#U;)X&dz121%7?*9cIf1xW5fn)6yHS6pv_o~V;RhF2h@#EqAg zmRY{w(0kSY=G}X2^IDbL);Xx_sHR9Km&zI)q^+%qxRBIYl7LxVJ*)uX!9>0hmW%Zt zHT>SuO`63qh!Jc*FC=&$jV(ldACn>Z#@oE_=70NsKM9{~NATnSyY2^24{786u4jP3 z5nBoji=-uteWIA`dA&Ra={y-t#E)859iC_(6^9Fmwm~JqQ(eFmm908U3o?KspEOG& zk^rBjOBUPedGFZW19n(WVx#?hL98tAg?9JZVfM9btuXz=qWq``j3_t{QyyYHl9TMx zDO2r=E3dNt@@f!xL!7ve0gy9*j6olM_@T|1@vLp%u9d3>)}8QK7j$zx#P7~-defL3 zk&2^$&Ld42nhC@YcnAiAYwnoRSm$G1&l3ZIfL!qpD5|~VY8u{2{m{L#rMNiL`+Rzh z_Z)~a#76KhZ|-#@8y zsLp~6;K&(enJb%4l_SzCr(SG*4qQsABdz^uU-!OKrl{4MY(lNh?iziBek{KUXcU?l?OPd z-A%+x(a?Wxkne=Svc{1vtchAGH~jAZ|yp>YPmVz1{cL@woc9Ryb_1)9L)&d*G*k`tkQ>t+3L+(g)`}C*Is+=Y0uH;8(T+x1{r{# znFatdc*s!Ou+Ho!v-a7$i;68Jxtm=*u8*CQRALRv?uxq(4M1zqx=F;`anrSS>-X-r z?BSy%K}3ZC8nq1O&70?51Tx+5&2QM!&*s`o|9neGzXqqSUM=Z`#(msPmqprtAVNSh z$(1{fgrT?+FYBj1VQ+p2;fU*~j{_q7g`Q&KaQ67_k9pn^opkJfh%Ow|O-4VB)0cgS zU?XlfAmb7MEjM(Ky{=@3)vBs;`4yK_9lB!&eg<6a%gz9xzrfVi&IwlOZd;;~WZ?Z* ztXOHuslDv_3y0c`nS%Wu%2$AjG7yVEK*(|NNn?lE_kQqz^&KKgYeUP<&UU#G&Q?Bz z@#81hp!8H*ykMSfEZ*&y%B2}nyJh4$E~3*wKu)^?7|XmIfke-NB><=IkbcJ^e#Wjo zu>J#=1!7B}4J!0;jfH+Xvat&E0?O>*%v`(ayFkOJi|=W(cct6f!cS$V>0wu1d1a^Z z{WqVJFFON({!VHuEG%?{|Ln8>tNppkcV+gqJ0=gXo3qNSca?N>`H460Q|T!Y2y3is zbc9Wvc3qo^pKSrzlE;i0b2xL+$g$_yIbsHzi{E!fEPymQFo5G}nu!(L&HmqF4;(~* z4)Fq5$^#+&{C2OKVjs=c0oNU%qc%65M$0F13_@&k-)%XtEewu+8z$M3HS@*bGwr(Tu5&571D^90{vpT!njUU(adDI6e^zL) zYP)uPfBXJQJ-bv$+&47(E{o>P@DD>XknpYme8ZOMaITiWAz>n zVGO~vp+T_QWv&0yO0(Bx_~ZZ6wcr1qb|Y@@-o}31rNl^f%J_#X%}2!SsX@|(svp2i zjv2J*6Qd#SP;v__mKIVWBP7g`Bpn3YoZs8CMX)b-oUIM_b*c`jO6X_r*N(JTmMn7+ z?W?c8+5vw~)%DKweuE4^PYA%z<9 z53zy&ryoEyWb2_wE7gY}WU>q4TaVNB!ZqeXuZ<#pAk26kU>wOh2Bm{s{qJq_40LQq zaLs{UJZ<&_`2sf_jI-yL8Z%F0~UTnv5($}8;Baf9tgqYv7MhB%v?>;KM}n zk;9+uK#sf$00v10A2fmmGMN7KGr1O}sQ^SuQ(x_2 zPVKrU-$@!qt&NE+@F9DSni>E<6ey*ID|Wnl_v8}>ju7@tqRx787l??27Xh1oBiN-x z#0AiY0vwxVv;*FH+c4qd`#T#~`=qQG0QQ5gtB*`cdlHf?6ajD5wbzx##RN4~10YoGSKSF??6fu#% zpE6t^^}Z?MyHS$c!H9KCyPNJCquse_9@Mr(1YDpOn0vefpYQS*0zpro6p7hL6Jc9K zB2ZFuXLoNJy1t8-A&`te8PXKM<^Sgb*($^cvJyNGg+u4Hd!TJQ5#rw$)zjYEKiFn0 z+$!)@h246~&35CBH=Z%|`Pz0Tr{<_m%>bxcOyP{Q-syJx#l!8qu-VoHk=9CswvcQt zI!?%%gg6i8+sY}&{OOQ94n=Z5HVFRHzgJh)`x9kzftF3gM&QwFGPb$QI{H0X+l8wn zv9b8Kx57@#%lLQ?_6QP+0Bhpa~I$cu^)>A|0>o$x%(msAh^|5_lM1&(-!~o3Rj@kbYXVuT|oQ z7{H!8Bb}y=ZA96wo$j+evq(@7IR+njOPVgVsx#ESdTjIWPCy2y1p+U2oxkXQo@CaH2`(!`_1p=#2C`Vq!@3ch!a}^^$1#H zwto9*p7IYQ2GXZJwV9|s@CaZBu()G|@5n~p zLACbuA5yQ_?n6F=%-Rw*et?UMiR8MgI`t{BdO)7MsFZ!SVeBJ&cjo_N(L+VSM zroqpKTEoLQhr|VhgTEfZ>s*H?N=QeHwDtdxevFDjSpOAR*Sh*oR~k1=g4zHWQPBci zfRev4b8Pb#=opTRh_brKMBCq(XzN3>?cMwYd*R*Bte~ja1`irwKm6f?_Kk0R!^k=v zY)8*Pr)2AO*n(#E9_mLih}YtzDljOMz^xBt9hpDoH$X4IXu_o(l}E z9`!(m)h^+Y79t{-t|JCgrL9kdBz>CIG)7vf81T;8NX2DD+tS_9_TidMwr*>o42z*Q z@%#y{Bt4o{^SF!F#@HEu>$D7jhfTH~j6(0e`>xV-71|qXD{bgm>DDJw#z5`w{Wh&j za`2J(lH{Mub_nezT=`@F{agFdLqDu|zlk7(pb;hkiTdO=H?2DNeevRPE>SNVIlc zhJ+roQ^!BE+5-iV(i>x-vl}!Yb6AA!PaJ3q3TkcT)?F4Rl^#1yT5P;EmKRy&o zV6{A9u$5HD*p`yLRP%Xb41dFh46!S&xWd5r!(cJ?23z16=+q1VwUDsf z%Pzaj#Q}V{bc3CrnPXQclv-q6zQj=T)%nFFvi}AjPwH-pT;?CBx7S{O)4_Rfx%JyN z9Lb)TsMz#y2{BJJ<8ma^(9WGZZQHhOj__yAn&oODVoV%8_8j{^ci(1L#C&cM3nV7F zw7<10zCc=UJOMt09@cc1Zu^TNp1Qvnlg7r>kOdiLz_r~_8MF7Z`yDR<+XSKui4y=Z z2=lr-NAS}$@7TldBHsNeqwU4*8TR-mOKnqrjbPCgmY7)NwhAGK4p?A$psIefXL-$r6`R@sDav456@TN(>1PYl8}jk_{2!`>;+w%^ZOuIG^JszfCxCp)-y*`9I> z6@!S3>23*0kt)g(;Zk>zSOskgLuyu5mir76e$$+`@gqbk>8V;OZ5+bsKa32(zy0lR z?RUTXos%jLPCLuKo4&=O4`_w^7HNQCQo{NfVdKHNgO&F+jEg-IW35}VOypsa4uY!M zf(GoEl;SD9Gi>~X^X%GdrrX8ZcBJk4R2%C*OQcFn`rFToNZ9L>@;h(8h+l+76d;87 zwM@??2R?yHKV%qoeH>%#zOf$fC*Ys=^2{FkOomW-O{w%VM8u6T9&Kd1h@UM2aR4xb zMA-@`81k*5Uge_0#y?h`P*wXQlkN2bIrh6xR0Uc^Sg0DUBCs}KzyK>y24(6);=Tj7 zL4s9YadB~O3+J#L`YqVnHv>Ti&@^wWSFg4QAAHbe&V1j_9-3u85mj9ly~@HXrN6eu zB1Np_Qgg8fkemL~BCjG4VX;Rv5l3{im_oO%HfnH&U3TtScHvolt$$ptg%vLlRWBB` zNM!oa$zajjrHsrHKf;K%PD7%`JqAG0qEUSZBOvNE1v)91K^ib3_*xzN5d%EF|3KLP z-0T(nBoDvK8K5zM7z8PaRzLwxl8O?djH}Sq;?r-3#}pZDr3u6BA6vqt_Ls^zn@-cyxPaAjklkW{p(fFTVJq{q(0lHIjo&9Ghd`Kfjw@61%~o&;%f8 z7O%h7w5ZVrD8fM={?ALj!Wu|R{N5?CT`W_9K10%?Y?vx-WJr~bh$)ty000YANklV!k0WF6yA^22+O_)o1idw#u_trssqUrBn(jA4+ZGB25ck;YqeERvYwoA-_O z%8(rKwf}9JocFOp1Un4 zJIkhy$+GLuinW1dA6eL;CVYONT@#C3O|E`dtODZ4Wd>j;Mv@)W9_~A5n1-@>!8~~R zX8{5o8_Zul}&YD=Yq+NeaS|q4HSU7(bV8 z+gDBFW^3Zpc#!^J5+L{^4Dj45jmo=%U+0AnwPy-@+uz<_Zo7Av+SDnRIrGV0y!%l&JLbY?;#Cr5xxeeKyHr%8!Je5h!&a=@Z0quhY~I#UcFV{yc417e^$Oi% z;k6YO(jXnUrI$d2KqJ5PG8a;`)NvFk@*L8`r&iTrew+e=C6PC zNAw;Lf*;P+RzcGFlo3CJZn_uL{usTEX#D28SAGDgC&E9Jm}SdC$JifdZm(TeLLFCXCFs ztB3cr@ja?6Gpy9&>JM0Gb-9>asA$KT(sAKujD`m9&wo$`h#D+%dgAMZ`Gx7O^l zr5g%_hd5~2g9h33>C^4zn{T#^j12Fb;CqM9K#&0(W6BBnC30`(%$fGqTW>i=fUTgL zQhAT;-_yqR>t^G6)?0S;J{jdgET(#gg=&k?1rb~;BOiu&M3LlLK}3EYFRT|V*>o<``r<}cWuR1 z%OaU1JXSmJzJm2PR+-ZAumszTca7>vp#jd&L8k;DiUuP-99ccPb z_xC{t(8ebKBOrs&oH=tGGg!QMv3&Y_6^jyWy}HNS@cw;lNUsDN5Ou)P1&!+^(|2-} zvJHjovo2LKksl`?fWD|b@YqVv;CGFD=)mFqHi%H$g3a|DiDG6mL`GHdso%eEi4JYQ+KG zko13HgW1m~D0n7SC;Pz``1bfqb}BWuRR4GKyxf4l)H&qk57^`@+}CZWJzqA=o|?7B z3X8T|T1v7_7~0qVrB{^=j;pl(iu6eclNM8>d#gUAu;T`+35&7H@OazZ5G})`^6k|| zTYg2jZ7SYp8w<;9+umB+F8uEvRY7i0eT9sSbXRqU(pvz0h=B-N`2#+c4*wy@0NOd_ zE{|VPkrBzaX3ZK~DF`t61q%y{Y@fCWl?M-6xK!$l-f8v|>F>An+^WbOIr7`s4vN?x zm?P`Iq%f+yi!^SocB>!Kg5&pJBtQKBuJy17q~(4{o`QZ|b%5`9Ki6y!DCzC;5%!CZ z%I)(FTPz_yPDaCerAVu@l*Aaz?42S_Ce8*b;wQatZ|j!SRmkW{+qJjCwhNlOO+h&M z#idpz6jVh`qaCWLwHn1V5bc)kV3X<} zW@Xx~w|+|!zR^DT-~(H=dW~u%l)H>akr9y=E7)zcf^J|C5P3}vuNq-D|1K)rg} zK*4qg4<77ZKzOsVvRt{XhzPkPg6)i*fgl4o$&UsiBIyTt{-1vOY1JD1qm`DG3h&>? zesG>#iQNxcboE{fsj0LO=cn^8rmOVzFNL*#LECZAbua)L#Lufr_5kdQzt5y z(ACD|47Kr@u{OSUqYVg?@vX7cqLq?7RE0r8NHzed2rPjbDnIHzSbsc=K#2+dff0~u z+cg-6k9lCJ=Wk`jX$*^2v_Yip>C#md-kSs`(W)Z zE6m&C)b(l8ra6^=bkKvreYkGjIwK3vym|AS*PvL8p-z!P zDalEe-6z?GWTaWYxI;>KQD@x}VwJHt+NJ)As1uezkmHEP8jF-s4K+MWNiiC04_IT> z9t)||UO^E#4N8Yy8IfZ7b;-7JN3DHasQml##g}Z`;+P46HdMpKB^UI=chG}B!!HwL z03G~*u$~icynOj`Textcdu`mf$#(DE=aLaeE6HBB#CWOYNkS8bN)xEH@Wxu9^ujDL zLEk4NSfWz$P#DB&_KPtHbyz1~z1pG1DBD>bZiN+Lwz+VJOFu@!j8UUTxk8wz`$LBg zRTf|0-oc#~eCxzB5M%(S>EUA^*ekFMR(34zD^{$KhOkyeLU+jOe$crV@gy9o@`&3T zrnUo8|GUT^h)YmmHg3O9*e$sS<$#bP(C9Me^b{CrvE*HU4R$^N|s|Y;1hfSjqL;0cuI+pRJ2ln9Ndi%JTA9-*#SZoXCFfvGUYhz zCm%c+adUEVT?PWB~qVaRaj969V^P3t$v%A^3zj@B&@Oiwwu) z%0skI@LKxcjO!TS!* zfMy`b0D{XPI0Kz{27(Nr6F>amtp{fy$N++CAUFe^cn1DIZh%IwJkGi@00000NkvXX Hu0mjfMCK@{ literal 0 HcmV?d00001 diff --git a/Icons/NeuraalNetwerkIcoonSchets1.png.meta b/Icons/NeuraalNetwerkIcoonSchets1.png.meta new file mode 100644 index 0000000..1ea36b8 --- /dev/null +++ b/Icons/NeuraalNetwerkIcoonSchets1.png.meta @@ -0,0 +1,117 @@ +fileFormatVersion: 2 +guid: 288088fdc016525a59f83f1c608e514d +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Icons/NeuraalNetwerkIcoonSchets2.png b/Icons/NeuraalNetwerkIcoonSchets2.png new file mode 100644 index 0000000000000000000000000000000000000000..35853d65078c2e6c2326da8a10e5f8d57db43a76 GIT binary patch literal 39373 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 literal 0 HcmV?d00001 diff --git a/Icons/NeuraalNetwerkIcoonSchets2.png.meta b/Icons/NeuraalNetwerkIcoonSchets2.png.meta new file mode 100644 index 0000000..524e4c8 --- /dev/null +++ b/Icons/NeuraalNetwerkIcoonSchets2.png.meta @@ -0,0 +1,117 @@ +fileFormatVersion: 2 +guid: e16264b4b7305e5c5b5b1389d6b2f13e +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Icons/NeuraalNetwerkIcoonSchets3.png b/Icons/NeuraalNetwerkIcoonSchets3.png new file mode 100644 index 0000000000000000000000000000000000000000..f2faf0ceb6c7192aa42dd7536bb0755b7cead3b9 GIT binary patch literal 40575 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

Qn64b=iQ=0`h)j4_K*TP7AwdnvVO9~Me7l%cQ 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 literal 0 HcmV?d00001 diff --git a/Icons/NeuraalNetwerkIcoonSchets3.png.meta b/Icons/NeuraalNetwerkIcoonSchets3.png.meta new file mode 100644 index 0000000..e7b0a3c --- /dev/null +++ b/Icons/NeuraalNetwerkIcoonSchets3.png.meta @@ -0,0 +1,117 @@ +fileFormatVersion: 2 +guid: 948c13386d926b7bbbca85239a974d85 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Identity.asset b/Identity.asset index 076c284..2471b04 100644 --- a/Identity.asset +++ b/Identity.asset @@ -11,20 +11,25 @@ MonoBehaviour: m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3} m_Name: Identity - m_EditorClassIdentifier: Assembly-CSharp::Cluster + m_EditorClassIdentifier: Assembly-CSharp::ClusterPrefab nuclei: - - rid: 2243601383627161705 + - rid: 2262690531574022216 references: version: 2 RefIds: - - rid: 2243601383627161705 + - rid: -2 + type: {class: , ns: , asm: } + - rid: 2262690531574022216 type: {class: Neuron, ns: , asm: Assembly-CSharp} data: - _name: Output + name: Output + clusterPrefab: {fileID: 11400000} + parent: + rid: -2 + trace: 0 + bias: {x: 0, y: 0, z: 0} _synapses: [] - _receivers: [] - _array: - rid: 2243601383627161706 + combinator: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -51,10 +56,4 @@ MonoBehaviour: m_PostInfinity: 2 m_RotationOrder: 4 curveMax: 1 - average: 0 - - rid: 2243601383627161706 - type: {class: NucleusArray, ns: , asm: Assembly-CSharp} - data: - _nuclei: - - rid: 2243601383627161705 - name: Output + _receivers: [] diff --git a/Scripts/NeuraalNetwerkIcoonSchets1.png b/Scripts/NeuraalNetwerkIcoonSchets1.png new file mode 100644 index 0000000000000000000000000000000000000000..82980ef9531ebefbf60dfd4bb2d8f0c0b99f2798 GIT binary patch literal 63771 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 s)rO#lD@ literal 0 HcmV?d00001 diff --git a/Scripts/NeuraalNetwerkIcoonSchets1.png.meta b/Scripts/NeuraalNetwerkIcoonSchets1.png.meta new file mode 100644 index 0000000..f31713f --- /dev/null +++ b/Scripts/NeuraalNetwerkIcoonSchets1.png.meta @@ -0,0 +1,117 @@ +fileFormatVersion: 2 +guid: cad48149d984d2eddae5808eb1517cb5 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/NeuraalNetwerkIcoonSchets2.png b/Scripts/NeuraalNetwerkIcoonSchets2.png new file mode 100644 index 0000000000000000000000000000000000000000..35853d65078c2e6c2326da8a10e5f8d57db43a76 GIT binary patch literal 39373 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 literal 0 HcmV?d00001 diff --git a/Scripts/NeuraalNetwerkIcoonSchets2.png.meta b/Scripts/NeuraalNetwerkIcoonSchets2.png.meta new file mode 100644 index 0000000..9abd599 --- /dev/null +++ b/Scripts/NeuraalNetwerkIcoonSchets2.png.meta @@ -0,0 +1,117 @@ +fileFormatVersion: 2 +guid: 2e644ed036e8939bf94586314a4f4607 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: From 463bef08688fc0bccc12c0b560e5cdb00f4ca3b5 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 2 Mar 2026 15:46:05 +0100 Subject: [PATCH 164/179] Improved ClusterReceptor --- Cluster.cs | 26 ++++---- ClusterReceptor.cs | 40 +++++++++--- Editor/ClusterInspector.cs | 130 ++++++++++++++++--------------------- IReceptor.cs | 57 +++++++++++----- Receptor.cs | 17 +++-- 5 files changed, 152 insertions(+), 118 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index 0393422..e240d58 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -78,21 +78,21 @@ public class Cluster : Nucleus { } } - // Copy nucleus arrays + // Copy nucleus arrays for receptors for (int nucleusIx = 0; nucleusIx < prefabNuclei.Length; nucleusIx++) { - Nucleus prefabReceptor = prefabNuclei[nucleusIx]; - if (prefabReceptor is not Receptor prefabNucleus) + Nucleus prefabNucleus = prefabNuclei[nucleusIx]; + if (prefabNucleus is not IReceptor prefabReceptor) continue; - if (prefabNucleus.nucleiArray == null || prefabNucleus.nucleiArray.Length == 0) + if (prefabReceptor.nucleiArray == null || prefabReceptor.nucleiArray.Length == 0) continue; - Receptor clonedNucleus = clonedNuclei[nucleusIx] as Receptor; - if (prefabNucleus == prefabNucleus.nucleiArray[0]) { + IReceptor clonedNucleus = clonedNuclei[nucleusIx] as IReceptor; + if (prefabReceptor == prefabReceptor.nucleiArray[0]) { // We clone the array only for the first entry - NucleusArray clonedArray = new(prefabNucleus.nucleiArray.Length, "array"); + NucleusArray clonedArray = new(prefabReceptor.nucleiArray.Length, "array"); int arrayIx = 0; - foreach (Nucleus prefabArrayNucleus in prefabNucleus.nucleiArray) { + foreach (Nucleus prefabArrayNucleus in prefabReceptor.nucleiArray) { int arrayNucleusIx = GetNucleusIndex(prefabNuclei, prefabArrayNucleus); if (arrayNucleusIx >= 0) { Nucleus clonedArrayNucleus = clonedNuclei[arrayNucleusIx]; @@ -103,12 +103,13 @@ public class Cluster : Nucleus { } arrayIx++; } - clonedNucleus.array = clonedArray; + //clonedNucleus.array = clonedArray; + clonedNucleus.nucleiArray = clonedArray.nuclei; } else { // The others will refer to the array created for the first nucleus in the array - int firstNucleusIx = GetNucleusIndex(prefabNuclei, prefabNucleus.nucleiArray[0]); - Receptor clonedFirstNucleus = clonedNuclei[firstNucleusIx] as Receptor; + int firstNucleusIx = GetNucleusIndex(prefabNuclei, prefabReceptor.nucleiArray[0]); + IReceptor clonedFirstNucleus = clonedNuclei[firstNucleusIx] as IReceptor; clonedNucleus.nucleiArray = clonedFirstNucleus.nucleiArray; } } @@ -237,12 +238,13 @@ public class Cluster : Nucleus { return -1; } - protected int GetNucleusIndex(List nuclei, Nucleus nucleus) { + public int GetNucleusIndex(List nuclei, Nucleus nucleus) { int i = 0; foreach (Nucleus nucleiElement in nuclei) { //for (int i = 0; i < nuclei.Length; i++) { if (nucleus == nucleiElement) return i; + i++; } return -1; } diff --git a/ClusterReceptor.cs b/ClusterReceptor.cs index 66eabc7..48a2c85 100644 --- a/ClusterReceptor.cs +++ b/ClusterReceptor.cs @@ -25,9 +25,9 @@ public class ClusterReceptor : Cluster, IReceptor { public override Nucleus ShallowCloneTo(Cluster parent) { ClusterReceptor clone = new(this.prefab, parent, this.name) { clusterPrefab = this.clusterPrefab, - array = this.array + //array = this.array }; - + //CloneFields(clone); // This cloned the prefab with the clusternuclei, // but did not clone the receivers outside the cluster RestoreExternalReceivers(clone, this.clusterPrefab, parent); @@ -37,9 +37,10 @@ public class ClusterReceptor : Cluster, IReceptor { public override Nucleus Clone(ClusterPrefab parent) { ClusterReceptor clone = new(prefab, parent, this.name) { - array = this.array + array = this._array }; + //CloneFields(clone); foreach (Synapse synapse in this.synapses) { Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); clonedSynapse.weight = synapse.weight; @@ -61,10 +62,29 @@ public class ClusterReceptor : Cluster, IReceptor { return clone; } + public override List CollectReceivers() { + List receivers = new(); + foreach (Nucleus element in this.nucleiArray) { + if (element is not Cluster clusterElement) + continue; + + //receivers.AddRange(clusterElement.CollectReceivers()); + foreach (Neuron output in clusterElement.outputs) { + foreach (Nucleus receiver in output.receivers) { + // Only add receivers outside clusterElement cluster + if (receiver.clusterPrefab != clusterElement.prefab && + receivers.Contains(receiver) == false) + receivers.Add(receiver); + } + } + } + return receivers; + } + [SerializeReference] private NucleusArray _array; public NucleusArray array { - get { return _array; } + //get { return _array; } set { _array = value; } } @@ -76,11 +96,15 @@ public class ClusterReceptor : Cluster, IReceptor { } public void AddReceptorElement(ClusterPrefab prefab) { - this.nucleiArray = IReceptorHelpers.AddReceptorElement(this.nucleiArray, prefab); + IReceptorHelpers.AddReceptorElement(this, prefab); } public void RemoveReceptorElement() { - this.nucleiArray = IReceptorHelpers.RemoveReceptorElement(this.nucleiArray); + IReceptorHelpers.RemoveReceptorElement(this); + } + + public void AddArrayReceiver(Nucleus receiverToAdd, float weight = 1) { + IReceptorHelpers.AddArrayReceiver(this, receiverToAdd, weight); } public override void UpdateStateIsolated() { @@ -107,7 +131,7 @@ public class ClusterReceptor : Cluster, IReceptor { } public override void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) { - this.array ??= new NucleusArray(this.parent); - this.array.ProcessStimulus(thingId, inputValue, thingName); + this._array ??= new NucleusArray(this.parent); + this._array.ProcessStimulus(thingId, inputValue, thingName); } } \ No newline at end of file diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 1c7f84a..7af110c 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -16,25 +16,9 @@ public class ClusterInspector : Editor { #region Start - private void OnEnable() { - // Load an icon from resources or assets - Texture2D icon = Resources.Load("ClusterIcon.png"); - - // Ensure the texture is valid; set the icon for the ScriptableObject - if (icon != null) { - EditorGUIUtility.SetIconForObject(target, icon); - } - } - public override VisualElement CreateInspectorGUI() { ClusterPrefab prefab = target as ClusterPrefab; - // string path = AssetDatabase.GetAssetPath(prefab); // or known path - // Debug.Log($"{path}"); - // ClusterPrefab currentWrapper = AssetDatabase.LoadAssetAtPath(path); - // if (currentWrapper == null) - // Debug.LogError("CreateInspectorGUI: Cluster Prefab is not found on disk"); - if (prefab != null) prefab.EnsureInitialization(); @@ -482,9 +466,9 @@ public class ClusterInspector : Editor { fontStyle = FontStyle.Bold, }; - if (nucleus is Receptor receptor1) { - // draw the array size label + if (nucleus is IReceptor receptor1) { if (expandArray) { + // Put array indices above elements style.alignment = TextAnchor.LowerCenter; Vector3 labelPos1 = position + Vector3.down * (size + 5); // below disc int colonPos1 = nucleus.name.IndexOf(":"); @@ -494,6 +478,7 @@ public class ClusterInspector : Editor { } } else { + // draw the array size label if (color.grayscale > 0.5f) style.normal.textColor = Color.black; else @@ -503,33 +488,14 @@ public class ClusterInspector : Editor { } } - if (nucleus is ClusterReceptor clusterReceptor) { - // draw the array size label - if (expandArray && clusterReceptor.array.nuclei.First() == this.currentNucleus) { - style.alignment = TextAnchor.LowerCenter; - Vector3 labelPos2 = position + Vector3.down * (size + 5); // below disc - int colonPos2 = nucleus.name.IndexOf(":"); - if (colonPos2 > 0) { - string extName = nucleus.name[(colonPos2 + 2)..]; - Handles.Label(labelPos2, extName, style); - } - } - else { - if (color.grayscale > 0.5f) - style.normal.textColor = Color.black; - else - style.normal.textColor = Color.white; - Handles.Label(labelPosition, clusterReceptor.array.nuclei.Length.ToString(), style); - style.normal.textColor = Color.white; - } - } - - if (!expandArray || nucleus is not Receptor) { + if (expandArray == false) { + // put name below nucleus Vector3 labelPos = position - Vector3.down * (size + 5); // below neuron style.alignment = TextAnchor.UpperCenter; int colonPos = nucleus.name.IndexOf(":"); if (colonPos > 0 && colonPos < nucleus.name.Length - 2) { + // if it is an array, we should not show the :0 of the first element string baseName = nucleus.name[..colonPos]; Handles.Label(labelPos, baseName, style); } @@ -652,22 +618,8 @@ public class ClusterInspector : Editor { if (this.currentNucleus is MemoryCell memory) { memory.staticMemory = EditorGUILayout.Toggle("Static Memory", memory.staticMemory); } - // if (this.currentNucleus is ReceptorArray receptor) { - // EditorGUILayout.BeginHorizontal(); - // EditorGUILayout.IntField("Receptor size", receptor.instances.Count()); - // if (GUILayout.Button("Add")) { - // Undo.RecordObject(prefabAsset, "Receptor add " + prefabAsset.name); - // receptor.AddReceptor(this.prefab); - // anythingChanged = true; - // } - // if (GUILayout.Button("Del")) { - // Undo.RecordObject(prefabAsset, "Receptor delete " + prefabAsset.name); - // receptor.RemoveReceptor(); - // anythingChanged = true; - // } - // EditorGUILayout.EndHorizontal(); - // } - if (this.currentNucleus is Receptor receptor1) { + + if (this.currentNucleus is IReceptor receptor1) { EditorGUILayout.BeginHorizontal(); EditorGUILayout.IntField("Array size", receptor1.nucleiArray.Count()); if (GUILayout.Button("Add")) { @@ -684,21 +636,21 @@ public class ClusterInspector : Editor { } EditorGUILayout.EndHorizontal(); } - else if (this.currentNucleus is ClusterReceptor receptor2) { - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.IntField("Array size", receptor2.array.nuclei.Count()); - if (GUILayout.Button("Add")) { - Undo.RecordObject(prefabAsset, "Array add " + prefabAsset.name); - receptor2.array.AddNucleus(this.prefab); - anythingChanged = true; - } - if (GUILayout.Button("Del")) { - Undo.RecordObject(prefabAsset, "Array delete " + prefabAsset.name); - receptor2.array.RemoveNucleus(); - anythingChanged = true; - } - EditorGUILayout.EndHorizontal(); - } + // else if (this.currentNucleus is ClusterReceptor receptor2) { + // EditorGUILayout.BeginHorizontal(); + // EditorGUILayout.IntField("Array size", receptor2.array.nuclei.Count()); + // if (GUILayout.Button("Add")) { + // Undo.RecordObject(prefabAsset, "Array add " + prefabAsset.name); + // receptor2.array.AddNucleus(this.prefab); + // anythingChanged = true; + // } + // if (GUILayout.Button("Del")) { + // Undo.RecordObject(prefabAsset, "Array delete " + prefabAsset.name); + // receptor2.array.RemoveNucleus(); + // anythingChanged = true; + // } + // EditorGUILayout.EndHorizontal(); + // } // Synapses @@ -749,6 +701,7 @@ public class ClusterInspector : Editor { EditorGUILayout.BeginHorizontal(); if (synapse.nucleus.parent != null && synapse.nucleus.parent != this.currentNucleus) { + // If it is a cluster GUIStyle labelStyle = new(GUI.skin.label); float labelWidth = 200; if (synapse.nucleus.clusterPrefab != null) { @@ -997,7 +950,7 @@ public class ClusterInspector : Editor { EditorGUILayout.EndHorizontal(); if (connecting) { Nucleus nucleus = nuclei.ElementAt(selectedConnectNucleus); - if (nucleus is Receptor receptor) + if (nucleus is IReceptor receptor) receptor.AddArrayReceiver(this.currentNucleus); else if (nucleus is Neuron neuron) neuron.AddReceiver(this.currentNucleus); @@ -1058,9 +1011,36 @@ public class ClusterInspector : Editor { protected virtual void ChangeSynapse(Synapse synapse, Neuron newNucleus) { Neuron synapseNeuron = synapse.nucleus as Neuron; if (synapse.nucleus.parent is Cluster subCluster && subCluster.prefab != this.prefab) { - // it is a neuron in a subcluster - synapseNeuron.RemoveReceiver(this.currentNucleus); - newNucleus.AddReceiver(this.currentNucleus); + if (synapse.nucleus.parent is ClusterReceptor receptor) { + // the new nucleus is part of a (cluster) receptor, + // so we have to change all synapses to this nucleus array elements + int oldNucleusIx = subCluster.GetNucleusIndex(subCluster.clusterNuclei, synapse.nucleus); + int newNucleusIx = subCluster.GetNucleusIndex(subCluster.clusterNuclei, newNucleus); + foreach(Nucleus element in receptor.nucleiArray) { + if (element is not ClusterReceptor clusterReceptor) + continue; + // Get the same neuron as the synapse.nucleus in a different element + // of the ClusterReceptor array + Nucleus oldElementNucleus = clusterReceptor.clusterNuclei[oldNucleusIx]; + if (oldElementNucleus is not Neuron oldElementNeuron) + continue; + // Get the same neuron as newNucleus in a different element + // of the ClusterReceptor array + Nucleus newElementNucleus = clusterReceptor.clusterNuclei[newNucleusIx]; + if (newElementNucleus is not Neuron newElementNeuron) + continue; + + oldElementNeuron.RemoveReceiver(this.currentNucleus); + newElementNeuron.AddReceiver(this.currentNucleus); + // Now find the synapse which pointed to the old Neuron + // Synapse synapseForUpdate = this.currentNucleus.GetSynapse(oldElementNeuron); + // synapseForUpdate.nucleus = newElementNeuron; + } + } else { + // it is a neuron in a subcluster + synapseNeuron.RemoveReceiver(this.currentNucleus); + newNucleus.AddReceiver(this.currentNucleus); + } } else { synapseNeuron.RemoveReceiver(this.currentNucleus); diff --git a/IReceptor.cs b/IReceptor.cs index 08bb505..5dee615 100644 --- a/IReceptor.cs +++ b/IReceptor.cs @@ -11,41 +11,66 @@ public interface IReceptor { public void AddReceptorElement(ClusterPrefab prefab); public void RemoveReceptorElement(); + public void AddArrayReceiver(Nucleus receiverToAdd, float weight = 1); + public void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null); } public static class IReceptorHelpers { - public static Nucleus[] AddReceptorElement(Nucleus[] nucleiArray, ClusterPrefab prefab) { - if (nucleiArray.Length == 0) { + + public static void AddReceptorElement(IReceptor receptor, ClusterPrefab prefab) { + if (receptor.nucleiArray.Length == 0) { Debug.LogError("Empty perceptoid array, cannot add"); - return null; } - int newLength = nucleiArray.Length + 1; + int newLength = receptor.nucleiArray.Length + 1; Nucleus[] newArray = new Nucleus[newLength]; - for (int i = 0; i < nucleiArray.Length; i++) - newArray[i] = nucleiArray[i]; - if (nucleiArray[0] is Nucleus nucleus) { + string baseName = receptor.GetName(); + int colonPos = baseName.IndexOf(":"); + if (colonPos > 0) + baseName = baseName[..colonPos]; + + for (int i = 0; i < receptor.nucleiArray.Length; i++) + newArray[i] = receptor.nucleiArray[i]; + if (receptor.nucleiArray[0] is Nucleus nucleus) { newArray[newLength - 1] = nucleus.Clone(prefab); - newArray[newLength - 1].name += $": {newLength - 1}"; + newArray[newLength - 1].name = $"{baseName}: {newLength - 1}"; } - return newArray; + foreach (Nucleus element in receptor.nucleiArray) { + if (element is IReceptor receptorElement) { + receptorElement.nucleiArray = newArray; + } + } } - public static Nucleus[] RemoveReceptorElement(Nucleus[] nucleiArray) { - int newLength = nucleiArray.Length - 1; + public static void RemoveReceptorElement(IReceptor receptor) { + int newLength = receptor.nucleiArray.Length - 1; if (newLength == 0) { Debug.LogWarning("Perceptoid array cannot be empty"); - return null; } - Nucleus[] newPerceptei = new Nucleus[newLength]; + Nucleus[] newArray = new Nucleus[newLength]; for (int i = 0; i < newLength; i++) - newPerceptei[i] = nucleiArray[i]; + newArray[i] = receptor.nucleiArray[i]; // Delete the last perception - if (nucleiArray[newLength] is Nucleus nucleus) + if (receptor.nucleiArray[newLength] is Nucleus nucleus) Neuron.Delete(nucleus); //this._nuclei[newLength]); - return newPerceptei; + foreach (Nucleus element in receptor.nucleiArray) { + if (element is IReceptor receptorElement) { + receptorElement.nucleiArray = newArray; + } + } + + } + + public static void AddArrayReceiver(IReceptor receptor, Nucleus receiverToAdd, float weight = 1) { + foreach (Nucleus element in receptor.nucleiArray) { + if (element is Cluster cluster) + cluster.defaultOutput.AddReceiver(receiverToAdd, weight); + if (element is Neuron neuron) + neuron.AddReceiver(receiverToAdd, weight); + } + } } \ No newline at end of file diff --git a/Receptor.cs b/Receptor.cs index e89837c..48ecb5a 100644 --- a/Receptor.cs +++ b/Receptor.cs @@ -48,11 +48,13 @@ public class Receptor : Neuron, IReceptor { } public void AddReceptorElement(ClusterPrefab prefab) { - this.nucleiArray = IReceptorHelpers.AddReceptorElement(this.nucleiArray, prefab); + //this.nucleiArray = IReceptorHelpers.AddReceptorElement(this.nucleiArray, prefab); + IReceptorHelpers.AddReceptorElement(this, prefab); } public void RemoveReceptorElement() { - this.nucleiArray = IReceptorHelpers.RemoveReceptorElement(this.nucleiArray); + // this.nucleiArray = IReceptorHelpers.RemoveReceptorElement(this.nucleiArray); + IReceptorHelpers.RemoveReceptorElement(this); } // public override void AddReceiver(Nucleus receiverToAdd, float weight = 1) { @@ -65,11 +67,12 @@ public class Receptor : Neuron, IReceptor { // } public virtual void AddArrayReceiver(Nucleus receiverToAdd, float weight = 1) { - foreach (Nucleus element in this._array.nuclei) { - if (element is Neuron neuron) { - neuron.AddReceiver(receiverToAdd, weight); - } - } + IReceptorHelpers.AddArrayReceiver(this, receiverToAdd, weight); + // foreach (Nucleus element in this._array.nuclei) { + // if (element is Neuron neuron) { + // neuron.AddReceiver(receiverToAdd, weight); + // } + // } } public override void UpdateStateIsolated() { From 96b240ad6c32754b07c85e36bcc56b326c44b586 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 2 Mar 2026 16:04:09 +0100 Subject: [PATCH 165/179] Fix clusterreceptor output connections --- ClusterReceptor.cs | 8 ++++++-- Editor/ClusterInspector.cs | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/ClusterReceptor.cs b/ClusterReceptor.cs index 48a2c85..b5aef2c 100644 --- a/ClusterReceptor.cs +++ b/ClusterReceptor.cs @@ -68,8 +68,12 @@ public class ClusterReceptor : Cluster, IReceptor { if (element is not Cluster clusterElement) continue; - //receivers.AddRange(clusterElement.CollectReceivers()); - foreach (Neuron output in clusterElement.outputs) { + foreach (Nucleus outputNucleus in clusterElement.clusterNuclei) { + if (outputNucleus is not Neuron output) + continue; + + // this should be clusterElement.outputs, + // but outputs is not updated when correctly and may contain old data... foreach (Nucleus receiver in output.receivers) { // Only add receivers outside clusterElement cluster if (receiver.clusterPrefab != clusterElement.prefab && diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 7af110c..5c18824 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -322,7 +322,7 @@ public class ClusterInspector : Editor { } private void DrawReceivers(Nucleus nucleus, Vector3 parentPos, float size) { - List receivers = null; + List receivers; if (nucleus is Neuron neuron) receivers = neuron.receivers; else if (nucleus is Cluster cluster) From bd24e6e19bea6b795c380125fdf8486bf5c8a130 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Tue, 3 Mar 2026 08:51:09 +0100 Subject: [PATCH 166/179] Get subcluster nucleus --- Cluster.cs | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index e240d58..ac9f2db 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -414,16 +414,32 @@ public class Cluster : Nucleus { } public Nucleus GetNucleus(string nucleusName) { - string nucleusName0 = nucleusName + ": 0"; - foreach (Nucleus nucleus in this.clusterNuclei) { - if (nucleus is IReceptor receptor) { - if (nucleus.name == nucleusName | nucleus.name == nucleusName0) + int dotPosition = nucleusName.IndexOf('.'); + if (dotPosition >= 0) { + string clusterName = nucleusName[..dotPosition]; + string clusterName0 = clusterName + ": 0"; + foreach (Nucleus nucleus in this.clusterNuclei) { + if (nucleus is Cluster cluster) { + if (cluster.name == clusterName || cluster.name == clusterName0) { + string subNucleusName = nucleusName[(dotPosition + 1)..]; + return cluster.GetNucleus(subNucleusName); + } + } + } + return null; + } + else { + string nucleusName0 = nucleusName + ": 0"; + foreach (Nucleus nucleus in this.clusterNuclei) { + if (nucleus is IReceptor receptor) { + if (nucleus.name == nucleusName | nucleus.name == nucleusName0) + return nucleus; + } + else if (nucleus.name == nucleusName) return nucleus; } - else if (nucleus.name == nucleusName) - return nucleus; + return null; } - return null; } [Obsolete("Use GetNucleus instead")] @@ -440,7 +456,7 @@ public class Cluster : Nucleus { // Only add receivers outside this cluster if (receiver.clusterPrefab != this.prefab) receivers.Add(receiver); - //receivers.AddRange(output.receivers); + //receivers.AddRange(output.receivers); } } return receivers; From 3cdca017d694a153a17ccfaa0cdafea7aa57566e Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Tue, 3 Mar 2026 11:48:16 +0100 Subject: [PATCH 167/179] process signal for clsuter receptor --- Cluster.cs | 114 ++++++++++++++++++++++++++--------------------------- 1 file changed, 56 insertions(+), 58 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index ac9f2db..4fd1363 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -123,7 +123,11 @@ public class Cluster : Nucleus { // Calculate in-degrees foreach (Nucleus node in nodes) { - if (node is Neuron neuron) { + if (node is Cluster cluster) { + foreach (Nucleus receiver in cluster.CollectReceivers()) + inDegree[receiver]++; + } + else if (node is Neuron neuron) { foreach (Nucleus receiver in neuron.receivers) inDegree[receiver]++; } @@ -148,6 +152,13 @@ public class Cluster : Nucleus { queue.Enqueue(receiver); } } + else if (current is Cluster cluster) { + foreach (Nucleus receiver in cluster.CollectReceivers()) { + inDegree[receiver]--; + if (inDegree[receiver] == 0) // If all dependencies resolved + queue.Enqueue(receiver); + } + } } // Check for cycles in the graph @@ -279,19 +290,17 @@ public class Cluster : Nucleus { public Dictionary> computeOrders = new(); private void ComputeOrders() { - foreach (Nucleus input in this._inputs) { + foreach (Nucleus input in this._inputs) computeOrders[input] = TopologicalSort2(input); - } } private List TopologicalSort2(Nucleus startNode) { - Dictionary inDegree = new Dictionary(); - HashSet visited = new HashSet(); + Dictionary inDegree = new(); + HashSet visited = new(); // Initialize in-degrees and mark all nodes as unvisited - foreach (Nucleus node in this.clusterNuclei) { + foreach (Nucleus node in this.clusterNuclei) inDegree[node] = 0; - } // Calculate in-degrees for all nodes reachable from the start node Queue queue = new Queue(); @@ -300,23 +309,28 @@ public class Cluster : Nucleus { while (queue.Count > 0) { Nucleus current = queue.Dequeue(); - if (current is Neuron neuron) { - foreach (Nucleus receiver in neuron.receivers) { - if (!visited.Contains(receiver)) { - visited.Add(receiver); - queue.Enqueue(receiver); - } - inDegree[receiver]++; + List receivers = null; + if (current is Neuron neuron) + receivers = neuron.receivers; + else if (current is Cluster cluster) + receivers = cluster.CollectReceivers(); + + // if (current is Neuron neuron) { + foreach (Nucleus receiver in receivers) { + if (!visited.Contains(receiver)) { + visited.Add(receiver); + queue.Enqueue(receiver); } + inDegree[receiver]++; } + // } } // Perform topological sort on all reachable nodes queue.Clear(); - foreach (var node in visited) { - if (inDegree[node] == 0) { + foreach (Nucleus node in visited) { + if (inDegree[node] == 0) queue.Enqueue(node); - } } List sortedOrder = new List(); @@ -324,15 +338,22 @@ public class Cluster : Nucleus { Nucleus current = queue.Dequeue(); sortedOrder.Add(current); // Process the node - if (current is Neuron neuron) { - foreach (Nucleus receiver in neuron.receivers) { + List receivers = null; + if (current is Neuron neuron) + receivers = neuron.receivers; + else if (current is Cluster cluster) + receivers = cluster.CollectReceivers(); + + //if (current is Neuron neuron) { + + foreach (Nucleus receiver in receivers) { if (visited.Contains(receiver)) { inDegree[receiver]--; if (inDegree[receiver] == 0) // If all dependencies resolved queue.Enqueue(receiver); } } - } + //} } // Check for cycles in the graph @@ -342,44 +363,6 @@ public class Cluster : Nucleus { return sortedOrder; } - private List TopologicalSort3(Nucleus startNode) { - Dictionary inDegree = new(); - foreach (Nucleus node in this.clusterNuclei) - inDegree[node] = 0; // Initialize in-degree to zero - - // Calculate in-degrees - foreach (Nucleus node in this.clusterNuclei) { - if (node is Neuron neuron) { - foreach (Nucleus receiver in neuron.receivers) - inDegree[receiver]++; - } - } - - Queue queue = new(); - queue.Enqueue(startNode); - - List sortedOrder = new(); - while (queue.Count > 0) { - Nucleus current = queue.Dequeue(); - sortedOrder.Add(current); // Process the node - - if (current is Neuron neuron) { - foreach (Nucleus receiver in neuron.receivers) { - inDegree[receiver]--; - if (inDegree[receiver] == 0) // If all dependencies resolved - queue.Enqueue(receiver); - } - } - } - - Debug.Log($"Compute order for {startNode.name} length = {sortedOrder.Count}"); - // Check for cycles in the graph - // if (sortedOrder.Count != this.nuclei.Count) - // throw new InvalidOperationException("Graph is not a DAG; a cycle exists."); - - return sortedOrder; - } - public virtual Neuron defaultOutput {//=> this.nuclei[0] as Nucleus; get { if (this.clusterNuclei.Count > 0) @@ -469,6 +452,11 @@ public class Cluster : Nucleus { public void UpdateFromNucleus(Nucleus startNucleus) { // no bias+synapse input state calculation for now... + if (this.computeOrders.ContainsKey(startNucleus) == false) { + Debug.LogError($"{this.name} compute orders does not contain an order for {startNucleus.name}"); + return; + } + List computeOrder = this.computeOrders[startNucleus]; if (startNucleus.trace) Debug.Log($"Update from {startNucleus.name}"); @@ -481,6 +469,16 @@ public class Cluster : Nucleus { this.outputValue = this.defaultOutput.outputValue; this.stale = 0; + if (this.parent != null) { + // continue in parent + this.parent.UpdateFromNucleus(this); + // continue in parent with the receivers of the last nucleus in the compute order + // if (computeOrder.Last() is Neuron lastNeuron) { + // foreach (Nucleus receiver in lastNeuron.receivers) + // this.parent?.UpdateFromNucleus(this); + // } + } + UpdateNuclei(); } From abbce409927a730b196e9e793b8e54ad30582e9b Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Tue, 3 Mar 2026 12:19:41 +0100 Subject: [PATCH 168/179] Process clusterreceptor per thingId --- ClusterReceptor.cs | 72 +++++++++++++++++++++++++++++++++++++- Editor/ClusterInspector.cs | 21 ++++------- Neuron.cs | 5 ++- 3 files changed, 81 insertions(+), 17 deletions(-) diff --git a/ClusterReceptor.cs b/ClusterReceptor.cs index b5aef2c..2ecbd8f 100644 --- a/ClusterReceptor.cs +++ b/ClusterReceptor.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using UnityEngine; using Unity.Mathematics; using static Unity.Mathematics.math; +using System.Linq; [Serializable] public class ClusterReceptor : Cluster, IReceptor { @@ -71,7 +72,7 @@ public class ClusterReceptor : Cluster, IReceptor { foreach (Nucleus outputNucleus in clusterElement.clusterNuclei) { if (outputNucleus is not Neuron output) continue; - + // this should be clusterElement.outputs, // but outputs is not updated when correctly and may contain old data... foreach (Nucleus receiver in output.receivers) { @@ -138,4 +139,73 @@ public class ClusterReceptor : Cluster, IReceptor { this._array ??= new NucleusArray(this.parent); this._array.ProcessStimulus(thingId, inputValue, thingName); } + + private Dictionary thingReceivers = new(); + + public virtual void ProcessStimulus(Neuron input, Vector3 inputValue, int thingId = 0, string thingName = null) { + inputValue = input.Activator(inputValue); + + if (!thingReceivers.TryGetValue(thingId, out ClusterReceptor selectedReceiver)) + selectedReceiver = FindReceiver(thingId, inputValue); + if (selectedReceiver == null) + return; + + if (thingName != null) { + string baseName = selectedReceiver.name; + int colonPos = selectedReceiver.name.IndexOf(":"); + if (colonPos > 0) + baseName = selectedReceiver.name[..colonPos]; + selectedReceiver.name = baseName + ": " + thingName; + } + + int inputIx = this.GetNucleusIndex(this.clusterNuclei, input); + if (inputIx < 0) + return; + + if (selectedReceiver.clusterNuclei[inputIx] is Neuron selectedNeuron) + selectedNeuron.ProcessStimulusDirect(inputValue); + } + + private ClusterReceptor FindReceiver(int thingId, float3 inputValue) { + // No existing nucleus for this thing + float inputMagnitude = length(inputValue); + ClusterReceptor selectedReceiver = null; + float selectedMagnitude = 0; + foreach (ClusterReceptor receiver in nucleiArray.Cast()) { + if (thingReceivers.ContainsValue(receiver) == false) { + // We found an unusued receiver + thingReceivers.Add(thingId, receiver); + return receiver; + } + else if (receiver.isSleeping) { + // A sleeping receiver is not active and can therefore always be used + thingReceivers.Add(thingId, receiver); + return receiver; + } + else if (selectedReceiver == null) { + // If we haven't found a receiver yet, just start by taking the first + selectedReceiver = receiver; + selectedMagnitude = length(selectedReceiver.outputValue); + } + // Look for the receiver with the lowest magnitude + else { + float magnitude = length(receiver.outputValue); + + if (magnitude < inputMagnitude && length(receiver.outputValue) < selectedMagnitude) { + selectedReceiver = receiver; + selectedMagnitude = length(selectedReceiver.outputValue); + } + } + } + if (selectedReceiver != null) { + // Replace the receiver + // Find the thingId current associated with the receiver + int keyToRemove = thingReceivers.FirstOrDefault(r => r.Value.Equals(selectedReceiver)).Key; + if (keyToRemove != 0 || thingReceivers.ContainsKey(keyToRemove)) + thingReceivers.Remove(keyToRemove); + // And add the new association + thingReceivers.Add(thingId, selectedReceiver); + } + return selectedReceiver; + } } \ No newline at end of file diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 5c18824..2ec258a 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -806,16 +806,8 @@ public class ClusterInspector : Editor { void OnSceneGUI(SceneView sceneView) { if (this.gameObject != null) { - // if (this.currentNucleus is ReceptorArray receptor && expandArray) { - // foreach (Nucleus nucleus in receptor.instances) { - // Vector3 worldVector = this.gameObject.transform.TransformVector(nucleus.outputValue); - // Handles.color = Color.yellow; - // Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); - // } - // } - // else { - if (this.currentNucleus is Receptor receptor1) { - foreach (Nucleus nucleus in receptor1.nucleiArray) { + if (this.currentNucleus is IReceptor receptor) { + foreach (Nucleus nucleus in receptor.nucleiArray) { Vector3 worldVector = this.gameObject.transform.TransformVector(nucleus.outputValue); Handles.color = Color.yellow; Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); @@ -825,9 +817,7 @@ public class ClusterInspector : Editor { Vector3 worldVector = this.gameObject.transform.TransformVector(this.currentNucleus.outputValue); Handles.color = Color.yellow; Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); - } - // } } } @@ -1016,7 +1006,7 @@ public class ClusterInspector : Editor { // so we have to change all synapses to this nucleus array elements int oldNucleusIx = subCluster.GetNucleusIndex(subCluster.clusterNuclei, synapse.nucleus); int newNucleusIx = subCluster.GetNucleusIndex(subCluster.clusterNuclei, newNucleus); - foreach(Nucleus element in receptor.nucleiArray) { + foreach (Nucleus element in receptor.nucleiArray) { if (element is not ClusterReceptor clusterReceptor) continue; // Get the same neuron as the synapse.nucleus in a different element @@ -1029,14 +1019,15 @@ public class ClusterInspector : Editor { Nucleus newElementNucleus = clusterReceptor.clusterNuclei[newNucleusIx]; if (newElementNucleus is not Neuron newElementNeuron) continue; - + oldElementNeuron.RemoveReceiver(this.currentNucleus); newElementNeuron.AddReceiver(this.currentNucleus); // Now find the synapse which pointed to the old Neuron // Synapse synapseForUpdate = this.currentNucleus.GetSynapse(oldElementNeuron); // synapseForUpdate.nucleus = newElementNeuron; } - } else { + } + else { // it is a neuron in a subcluster synapseNeuron.RemoveReceiver(this.currentNucleus); newNucleus.AddReceiver(this.currentNucleus); diff --git a/Neuron.cs b/Neuron.cs index 8fcc529..92b9c7d 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -312,7 +312,10 @@ public class Neuron : Nucleus { #endregion Receivers public override void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) { - ProcessStimulusDirect(inputValue, thingId, thingName); + if (this.parent is ClusterReceptor clusterReceptor) { + clusterReceptor.ProcessStimulus(this, inputValue, thingId, thingName); + } else + ProcessStimulusDirect(inputValue, thingId, thingName); // this.stale = 0; // this.bias = inputValue; // this.parent.UpdateFromNucleus(this); From f8b487cef7435a095fc8168fa72ef5a2667cc72a Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Tue, 3 Mar 2026 14:47:24 +0100 Subject: [PATCH 169/179] starting to work with 6 cluster receptors --- Cluster.cs | 60 ++++++++++++++++++++++++++++++++------ ClusterReceptor.cs | 4 +-- Editor/ClusterInspector.cs | 4 +-- 3 files changed, 55 insertions(+), 13 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index 4fd1363..f922bc8 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -113,6 +113,11 @@ public class Cluster : Nucleus { clonedNucleus.nucleiArray = clonedFirstNucleus.nucleiArray; } } + + foreach (Nucleus nucleus in this.clusterNuclei) { + if (nucleus is Cluster clonedSubCluster) + RestoreAllExternalReceivers(clonedSubCluster, this.prefab, this); + } } // Sort the nuclei in a correct evaluation order @@ -204,7 +209,44 @@ public class Cluster : Nucleus { return clone; } + private static void RestoreAllExternalReceivers(Cluster clonedCluster, ClusterPrefab prefabParent, Cluster clonedParent) { + int clonedClusterIx = GetNucleusIndex(clonedParent.clusterNuclei, clonedCluster); + if (prefabParent.nuclei[clonedClusterIx] is not Cluster sourceCluster) + return; + + for (int nucleusIx = 0; nucleusIx < sourceCluster.clusterNuclei.Count; nucleusIx++) { + Nucleus sourceNucleus = sourceCluster.clusterNuclei[nucleusIx]; + if (sourceNucleus is not Neuron sourceNeuron) + continue; + + Nucleus clonedNucleus = clonedCluster.clusterNuclei[nucleusIx]; + if (clonedNucleus is not Neuron clonedNeuron) + continue; + + // copy the receivers (and thus synapses) from the source to the clone + foreach (Nucleus receiver in sourceNeuron.receivers) { + int ix = GetNucleusIndex(prefabParent.nuclei, receiver); + if (ix < 0 || ix >= clonedParent.clusterNuclei.Count) + continue; + + Nucleus clonedReceiver = clonedParent.clusterNuclei[ix]; + + // Find the synapse for the weight + float weight = 1; + foreach (Synapse synapse in receiver.synapses) { + // Find the weight for this synapse + if (synapse.nucleus == sourceNucleus) { + weight = synapse.weight; + break; + } + } + + clonedNeuron.AddReceiver(clonedReceiver, weight); + } + } + } protected void RestoreExternalReceivers(Cluster clone, ClusterPrefab prefabParent, Cluster clonedParent) { + // Loop over all nuclei of this (the prefab of the clone?) for (int nucleusIx = 0; nucleusIx < this.clusterNuclei.Count; nucleusIx++) { Nucleus prefabNucleus = this.clusterNuclei[nucleusIx]; if (prefabNucleus is not Neuron prefabNeuron) @@ -217,7 +259,7 @@ public class Cluster : Nucleus { // Copy the receivers, which will also create the synapses foreach (Nucleus receiver in prefabNeuron.receivers) { int ix = GetNucleusIndex(prefabParent.nuclei, receiver); - if (ix < 0) + if (ix < 0 || ix >= clonedParent.clusterNuclei.Count) continue; //if (clone.clusterNuclei[ix] is not Nucleus clonedReceiver) @@ -249,7 +291,7 @@ public class Cluster : Nucleus { return -1; } - public int GetNucleusIndex(List nuclei, Nucleus nucleus) { + public static int GetNucleusIndex(List nuclei, Nucleus nucleus) { int i = 0; foreach (Nucleus nucleiElement in nuclei) { //for (int i = 0; i < nuclei.Length; i++) { @@ -345,14 +387,14 @@ public class Cluster : Nucleus { receivers = cluster.CollectReceivers(); //if (current is Neuron neuron) { - - foreach (Nucleus receiver in receivers) { - if (visited.Contains(receiver)) { - inDegree[receiver]--; - if (inDegree[receiver] == 0) // If all dependencies resolved - queue.Enqueue(receiver); - } + + foreach (Nucleus receiver in receivers) { + if (visited.Contains(receiver)) { + inDegree[receiver]--; + if (inDegree[receiver] == 0) // If all dependencies resolved + queue.Enqueue(receiver); } + } //} } diff --git a/ClusterReceptor.cs b/ClusterReceptor.cs index 2ecbd8f..33cba20 100644 --- a/ClusterReceptor.cs +++ b/ClusterReceptor.cs @@ -31,7 +31,7 @@ public class ClusterReceptor : Cluster, IReceptor { //CloneFields(clone); // This cloned the prefab with the clusternuclei, // but did not clone the receivers outside the cluster - RestoreExternalReceivers(clone, this.clusterPrefab, parent); + //RestoreExternalReceivers(clone, this.clusterPrefab, parent); return clone; } @@ -158,7 +158,7 @@ public class ClusterReceptor : Cluster, IReceptor { selectedReceiver.name = baseName + ": " + thingName; } - int inputIx = this.GetNucleusIndex(this.clusterNuclei, input); + int inputIx = GetNucleusIndex(this.clusterNuclei, input); if (inputIx < 0) return; diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 2ec258a..d35acff 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -1004,8 +1004,8 @@ public class ClusterInspector : Editor { if (synapse.nucleus.parent is ClusterReceptor receptor) { // the new nucleus is part of a (cluster) receptor, // so we have to change all synapses to this nucleus array elements - int oldNucleusIx = subCluster.GetNucleusIndex(subCluster.clusterNuclei, synapse.nucleus); - int newNucleusIx = subCluster.GetNucleusIndex(subCluster.clusterNuclei, newNucleus); + int oldNucleusIx = Cluster.GetNucleusIndex(subCluster.clusterNuclei, synapse.nucleus); + int newNucleusIx = Cluster.GetNucleusIndex(subCluster.clusterNuclei, newNucleus); foreach (Nucleus element in receptor.nucleiArray) { if (element is not ClusterReceptor clusterReceptor) continue; From cbc8296e55446b23b97c9e682a39a7ecd7416fb5 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Tue, 3 Mar 2026 15:52:35 +0100 Subject: [PATCH 170/179] Fix velocity not updating --- Cluster.cs | 57 ++++---------------------------------- ClusterReceptor.cs | 38 +++++++++++++++++++++---- Editor/ClusterInspector.cs | 2 +- 3 files changed, 38 insertions(+), 59 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index f922bc8..f81d190 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -202,9 +202,6 @@ public class Cluster : Nucleus { name = this.name, clusterPrefab = this.clusterPrefab, }; - // This cloned the prefab with the clusternuclei, - // but did not clone the receivers outside the cluster - RestoreExternalReceivers(clone, this.clusterPrefab, parent); return clone; } @@ -219,8 +216,7 @@ public class Cluster : Nucleus { if (sourceNucleus is not Neuron sourceNeuron) continue; - Nucleus clonedNucleus = clonedCluster.clusterNuclei[nucleusIx]; - if (clonedNucleus is not Neuron clonedNeuron) + if (clonedCluster.clusterNuclei[nucleusIx] is not Neuron clonedNeuron) continue; // copy the receivers (and thus synapses) from the source to the clone @@ -242,46 +238,10 @@ public class Cluster : Nucleus { } clonedNeuron.AddReceiver(clonedReceiver, weight); + // Debug.Log($"external: {clonedReceiver.name} receives from {clonedNeuron.name} {clonedNeuron.GetHashCode()}"); } } } - protected void RestoreExternalReceivers(Cluster clone, ClusterPrefab prefabParent, Cluster clonedParent) { - // Loop over all nuclei of this (the prefab of the clone?) - for (int nucleusIx = 0; nucleusIx < this.clusterNuclei.Count; nucleusIx++) { - Nucleus prefabNucleus = this.clusterNuclei[nucleusIx]; - if (prefabNucleus is not Neuron prefabNeuron) - continue; - - Nucleus clonedNucleus = clone.clusterNuclei[nucleusIx]; - if (clonedNucleus == null || clonedNucleus is not Neuron clonedNeuron) - continue; - - // Copy the receivers, which will also create the synapses - foreach (Nucleus receiver in prefabNeuron.receivers) { - int ix = GetNucleusIndex(prefabParent.nuclei, receiver); - if (ix < 0 || ix >= clonedParent.clusterNuclei.Count) - continue; - - //if (clone.clusterNuclei[ix] is not Nucleus clonedReceiver) - if (clonedParent.clusterNuclei[ix] is not Nucleus clonedReceiver) - continue; - - // Find the synapse for the weight - float weight = 1; - foreach (Synapse synapse in receiver.synapses) { - // Find the weight for this synapse - if (synapse.nucleus == prefabNucleus) { - weight = synapse.weight; - break; - } - } - - clonedNeuron.AddReceiver(clonedReceiver, weight); - } - } - - - } protected int GetNucleusIndex(Nucleus[] nuclei, Nucleus nucleus) { for (int i = 0; i < nuclei.Length; i++) { @@ -505,21 +465,14 @@ public class Cluster : Nucleus { foreach (Nucleus nucleus in computeOrder) { nucleus.UpdateStateIsolated(); if (startNucleus.trace) - Debug.Log($" {nucleus.name} = {nucleus.outputValue}"); + Debug.Log($" {nucleus.name}[{nucleus.GetHashCode()}] = {nucleus.outputValue}"); } this.outputValue = this.defaultOutput.outputValue; this.stale = 0; - if (this.parent != null) { - // continue in parent - this.parent.UpdateFromNucleus(this); - // continue in parent with the receivers of the last nucleus in the compute order - // if (computeOrder.Last() is Neuron lastNeuron) { - // foreach (Nucleus receiver in lastNeuron.receivers) - // this.parent?.UpdateFromNucleus(this); - // } - } + // continue in parent + this.parent?.UpdateFromNucleus(this); UpdateNuclei(); } diff --git a/ClusterReceptor.cs b/ClusterReceptor.cs index 33cba20..d6fd3bf 100644 --- a/ClusterReceptor.cs +++ b/ClusterReceptor.cs @@ -113,15 +113,19 @@ public class ClusterReceptor : Cluster, IReceptor { } public override void UpdateStateIsolated() { - float3 sum = this.bias; + // Clusters don't do anything, + // The nuclei in them do the work + // and should be called directly, not from the cluster + + // float3 sum = this.bias; - foreach (Nucleus nucleus in this.sortedNuclei) - nucleus.UpdateStateIsolated(); + // foreach (Nucleus nucleus in this.sortedNuclei) + // nucleus.UpdateStateIsolated(); - this.outputValue = this.defaultOutput.outputValue; - this.stale = 0; + // this.outputValue = this.defaultOutput.outputValue; + // this.stale = 0; - UpdateNuclei(); + // UpdateNuclei(); } public override void UpdateNuclei() { @@ -143,6 +147,8 @@ public class ClusterReceptor : Cluster, IReceptor { private Dictionary thingReceivers = new(); public virtual void ProcessStimulus(Neuron input, Vector3 inputValue, int thingId = 0, string thingName = null) { + CleanupReceivers(); + inputValue = input.Activator(inputValue); if (!thingReceivers.TryGetValue(thingId, out ClusterReceptor selectedReceiver)) @@ -208,4 +214,24 @@ public class ClusterReceptor : Cluster, IReceptor { } return selectedReceiver; } + + + private void CleanupReceivers() { + // Remove a thing-receiver connection when the nucleus is inactive + List receiversToRemove = new(); + foreach (KeyValuePair item in thingReceivers) { + if (item.Value != null && item.Value.isSleeping) + receiversToRemove.Add(item.Key); + } + foreach (int thingId in receiversToRemove) { + Nucleus selectedReceiver = thingReceivers[thingId]; + + thingReceivers.Remove(thingId); + + int colonPos = selectedReceiver.name.IndexOf(":"); + if (colonPos > 0) + selectedReceiver.name = selectedReceiver.name[..colonPos]; + + } + } } \ No newline at end of file diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index d35acff..572b092 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -507,7 +507,7 @@ public class ClusterInspector : Editor { // Draw Cluster ring if (nucleus is Cluster) { Handles.color = Color.white; - Handles.DrawWireDisc(position, Vector3.forward, size + 10); + Handles.DrawWireDisc(position, Vector3.forward, size + 5); } // Tooltip From 9c730709f1a9f368f6b2c1e19fcd677fb39dc006 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Tue, 3 Mar 2026 17:05:16 +0100 Subject: [PATCH 171/179] gaze with clusterreceptor --- Cluster.cs | 9 ++++ Editor/ClusterInspector.cs | 75 ++++++++++++------------------ Velocity.asset | 94 ++++++++++++++++++++++++++++++++------ 3 files changed, 119 insertions(+), 59 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index f81d190..da88e53 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -8,6 +8,15 @@ using static Unity.Mathematics.math; [Serializable] public class Cluster : Nucleus { + public string baseName { + get { + int colonPositon = this.name.IndexOf(':'); + if (colonPositon < 0) + return this.name; + return this.name[..colonPositon]; + } + } + #region Init public Cluster(ClusterPrefab prefab, Cluster parent) { diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 572b092..d979703 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -488,7 +488,7 @@ public class ClusterInspector : Editor { } } - if (expandArray == false) { + if (expandArray == false || nucleus is not IReceptor) { // put name below nucleus Vector3 labelPos = position - Vector3.down * (size + 5); // below neuron style.alignment = TextAnchor.UpperCenter; @@ -624,34 +624,16 @@ public class ClusterInspector : Editor { EditorGUILayout.IntField("Array size", receptor1.nucleiArray.Count()); if (GUILayout.Button("Add")) { Undo.RecordObject(prefabAsset, "Array add " + prefabAsset.name); - //receptor1.array.AddNucleus(this.prefab); receptor1.AddReceptorElement(this.prefab); anythingChanged = true; } if (GUILayout.Button("Del")) { Undo.RecordObject(prefabAsset, "Array delete " + prefabAsset.name); - //receptor1.array.RemoveNucleus(); receptor1.RemoveReceptorElement(); anythingChanged = true; } EditorGUILayout.EndHorizontal(); } - // else if (this.currentNucleus is ClusterReceptor receptor2) { - // EditorGUILayout.BeginHorizontal(); - // EditorGUILayout.IntField("Array size", receptor2.array.nuclei.Count()); - // if (GUILayout.Button("Add")) { - // Undo.RecordObject(prefabAsset, "Array add " + prefabAsset.name); - // receptor2.array.AddNucleus(this.prefab); - // anythingChanged = true; - // } - // if (GUILayout.Button("Del")) { - // Undo.RecordObject(prefabAsset, "Array delete " + prefabAsset.name); - // receptor2.array.RemoveNucleus(); - // anythingChanged = true; - // } - // EditorGUILayout.EndHorizontal(); - // } - // Synapses @@ -666,7 +648,7 @@ public class ClusterInspector : Editor { EditorGUIUtility.wideMode = true; EditorGUIUtility.labelWidth = 100; - Vector3 newBias = EditorGUILayout.Vector3Field("Bias", this.currentNucleus.bias); //, GUILayout.Width(200)); + Vector3 newBias = EditorGUILayout.Vector3Field("Bias", this.currentNucleus.bias); anythingChanged |= newBias != this.currentNucleus.bias; this.currentNucleus.bias = newBias; @@ -705,8 +687,8 @@ public class ClusterInspector : Editor { GUIStyle labelStyle = new(GUI.skin.label); float labelWidth = 200; if (synapse.nucleus.clusterPrefab != null) { - labelWidth = labelStyle.CalcSize(new GUIContent($"{synapse.nucleus.clusterPrefab.name}.")).x; - GUILayout.Label($"{synapse.nucleus.clusterPrefab.name}", GUILayout.Width(labelWidth)); + labelWidth = labelStyle.CalcSize(new GUIContent($"{synapse.nucleus.parent.baseName}.")).x; + GUILayout.Label($"{synapse.nucleus.parent.baseName}", GUILayout.Width(labelWidth)); } string[] options = synapse.nucleus.parent.clusterNuclei.Select(n => n.name).ToArray(); int selectedIndex = System.Array.IndexOf(options, synapse.nucleus.name); @@ -753,32 +735,33 @@ public class ClusterInspector : Editor { // Activation - EditorGUILayout.Space(); - showActivation = EditorGUILayout.BeginFoldoutHeaderGroup(showActivation, "Activation"); - if (showActivation) { - if (this.currentNucleus is Neuron neuron) { - if (this.currentNucleus is not MemoryCell) { - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.LabelField("Activation Curve", GUILayout.Width(150)); - if (neuron.curveMax > 0) - EditorGUILayout.CurveField(neuron.curve, Color.cyan, new Rect(0, 0, 1, neuron.curveMax)); - else - EditorGUILayout.CurveField(neuron.curve, Color.cyan, new Rect(0, neuron.curveMax, 1, -neuron.curveMax)); - Neuron.CurvePresets newPreset = (Neuron.CurvePresets)EditorGUILayout.EnumPopup(neuron.curvePreset, GUILayout.Width(100)); - anythingChanged |= newPreset != neuron.curvePreset; - neuron.curvePreset = newPreset; - EditorGUILayout.EndHorizontal(); - } - if (neuron is Receptor receptor2) { - if (receptor2.nucleiArray == null || receptor2.nucleiArray.Count() == 0) - receptor2.array = new NucleusArray(neuron); - } - } - + if (this.currentNucleus is not Cluster) { EditorGUILayout.Space(); - } - EditorGUILayout.EndFoldoutHeaderGroup(); + showActivation = EditorGUILayout.BeginFoldoutHeaderGroup(showActivation, "Activation"); + if (showActivation) { + if (this.currentNucleus is Neuron neuron) { + if (this.currentNucleus is not MemoryCell) { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Activation Curve", GUILayout.Width(150)); + if (neuron.curveMax > 0) + EditorGUILayout.CurveField(neuron.curve, Color.cyan, new Rect(0, 0, 1, neuron.curveMax)); + else + EditorGUILayout.CurveField(neuron.curve, Color.cyan, new Rect(0, neuron.curveMax, 1, -neuron.curveMax)); + Neuron.CurvePresets newPreset = (Neuron.CurvePresets)EditorGUILayout.EnumPopup(neuron.curvePreset, GUILayout.Width(100)); + anythingChanged |= newPreset != neuron.curvePreset; + neuron.curvePreset = newPreset; + EditorGUILayout.EndHorizontal(); + } + if (neuron is Receptor receptor2) { + if (receptor2.nucleiArray == null || receptor2.nucleiArray.Count() == 0) + receptor2.array = new NucleusArray(neuron); + } + } + EditorGUILayout.Space(); + } + EditorGUILayout.EndFoldoutHeaderGroup(); + } if (GUILayout.Button("Delete this neuron")) DeleteNucleus(this.currentNucleus); diff --git a/Velocity.asset b/Velocity.asset index aad36ea..0001385 100644 --- a/Velocity.asset +++ b/Velocity.asset @@ -13,18 +13,31 @@ MonoBehaviour: m_Name: Velocity m_EditorClassIdentifier: Assembly-CSharp::ClusterPrefab nuclei: - - rid: 2243601425629446539 + - rid: 2262690551513219315 + - rid: 2262690551513219316 + - rid: 2262690551513219317 references: version: 2 RefIds: - - rid: 2243601425629446539 + - rid: -2 + type: {class: , ns: , asm: } + - rid: 2262690551513219315 type: {class: Neuron, ns: , asm: Assembly-CSharp} data: - _name: Output - _synapses: [] - _receivers: [] - _array: - rid: 2243601425629446540 + name: Velocity + clusterPrefab: {fileID: 11400000} + parent: + rid: -2 + trace: 0 + bias: {x: 0, y: 0, z: 0} + _synapses: + - nucleus: + rid: 2262690551513219316 + weight: 1 + - nucleus: + rid: 2262690551513219317 + weight: 1 + combinator: 0 _curvePreset: 0 curve: serializedVersion: 2 @@ -51,10 +64,65 @@ MonoBehaviour: m_PostInfinity: 2 m_RotationOrder: 4 curveMax: 1 - average: 0 - - rid: 2243601425629446540 - type: {class: NucleusArray, ns: , asm: Assembly-CSharp} + _receivers: [] + - rid: 2262690551513219316 + type: {class: Neuron, ns: , asm: Assembly-CSharp} data: - _nuclei: - - rid: 2243601425629446539 - name: Output + name: Position + clusterPrefab: {fileID: 11400000} + parent: + rid: -2 + trace: 0 + bias: {x: 0, y: 0, z: 0} + _synapses: [] + combinator: 0 + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1000 + value: 1000 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + _receivers: + - rid: 2262690551513219315 + - rid: 2262690551513219317 + type: {class: MemoryCell, ns: , asm: Assembly-CSharp} + data: + name: New memory cell + clusterPrefab: {fileID: 11400000} + parent: + rid: -2 + trace: 0 + bias: {x: 0, y: 0, z: 0} + _synapses: [] + combinator: 0 + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + _receivers: + - rid: 2262690551513219315 + staticMemory: 0 From 172d7ca8e8576c8e932e65dfe00ff07ad3459cc2 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Tue, 3 Mar 2026 17:24:28 +0100 Subject: [PATCH 172/179] Gaze includes velocity --- Editor/ClusterInspector.cs | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index d979703..2790aa8 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -653,6 +653,7 @@ public class ClusterInspector : Editor { this.currentNucleus.bias = newBias; Nucleus[] array = null; + int elementIx = -1; if (this.currentNucleus.synapses.Count > 0) { Synapse[] synapses = this.currentNucleus.synapses.ToArray(); foreach (Synapse synapse in synapses) { @@ -660,16 +661,26 @@ public class ClusterInspector : Editor { continue; if (array != null) { - if (array.Contains(synapse.nucleus)) - continue; - if (array.Contains(synapse.nucleus.parent)) + if (synapse.nucleus.parent is Cluster iCluster && elementIx > 0) { + int thisElementIx = Cluster.GetNucleusIndex(iCluster.clusterNuclei, synapse.nucleus); + if (thisElementIx == elementIx) + continue; + else + elementIx = thisElementIx; + } + // if (array.Contains(synapse.nucleus)) + // continue; + else if (array.Contains(synapse.nucleus.parent)) continue; } else { - if (synapse.nucleus.parent is ClusterReceptor clusterReceptor) - array = clusterReceptor.nucleiArray; - else if (synapse.nucleus is Receptor receptor2) // && receptor2.array != null && receptor2.array.nuclei.Length > 1) - array = receptor2.nucleiArray; + if (synapse.nucleus.parent is IReceptor iReceptor) { + array = iReceptor.nucleiArray; + if (iReceptor is Cluster iCluster) + elementIx = Cluster.GetNucleusIndex(iCluster.clusterNuclei, synapse.nucleus); + } + // else if (synapse.nucleus is Receptor receptor2) // && receptor2.array != null && receptor2.array.nuclei.Length > 1) + // array = receptor2.nucleiArray; } EditorGUILayout.Space(); From 1dfe65eefaeb203b973f7466a57dac0454ce9703 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 4 Mar 2026 14:20:23 +0100 Subject: [PATCH 173/179] Cluster no longer has output --- Cluster.cs | 22 ++++--- ClusterReceptor.cs | 92 ++++++++++++++++++++------- Editor/ClusterInspector.cs | 123 +++++++++++++++++++++++-------------- Neuron.cs | 55 ++++++++++++----- Nucleus.cs | 32 +++++----- NucleusArray.cs | 8 ++- Pulsar.cs | 98 ++++++++++++++--------------- Selector.cs | 112 ++++++++++++++++----------------- 8 files changed, 325 insertions(+), 217 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index da88e53..2a7fe34 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -104,7 +104,7 @@ public class Cluster : Nucleus { foreach (Nucleus prefabArrayNucleus in prefabReceptor.nucleiArray) { int arrayNucleusIx = GetNucleusIndex(prefabNuclei, prefabArrayNucleus); if (arrayNucleusIx >= 0) { - Nucleus clonedArrayNucleus = clonedNuclei[arrayNucleusIx]; + Neuron clonedArrayNucleus = clonedNuclei[arrayNucleusIx] as Neuron; clonedArray.nuclei[arrayIx] = clonedArrayNucleus; } else { @@ -473,12 +473,12 @@ public class Cluster : Nucleus { Debug.Log($"Update from {startNucleus.name}"); foreach (Nucleus nucleus in computeOrder) { nucleus.UpdateStateIsolated(); - if (startNucleus.trace) - Debug.Log($" {nucleus.name}[{nucleus.GetHashCode()}] = {nucleus.outputValue}"); + if (startNucleus.trace && nucleus is Neuron neuron) + Debug.Log($" {nucleus.name}[{nucleus.GetHashCode()}] = {neuron.outputValue}"); } - this.outputValue = this.defaultOutput.outputValue; - this.stale = 0; + // this.outputValue = this.defaultOutput.outputValue; + // this.stale = 0; // continue in parent this.parent?.UpdateFromNucleus(this); @@ -491,17 +491,19 @@ public class Cluster : Nucleus { //Applying the weight factors foreach (Synapse synapse in this.synapses) { - if (lengthsq(synapse.nucleus.outputValue) > 0) { - sum += synapse.weight * synapse.nucleus.outputValue; - this.stale = 0; + if (synapse.nucleus is Neuron neuron) { + if (lengthsq(neuron.outputValue) > 0) { + sum += synapse.weight * neuron.outputValue; + //this.stale = 0; + } } } foreach (Nucleus nucleus in this.sortedNuclei) nucleus.UpdateStateIsolated(); - this.outputValue = this.defaultOutput.outputValue; - this.stale = 0; + // this.outputValue = this.defaultOutput.outputValue; + // this.stale = 0; UpdateNuclei(); } diff --git a/ClusterReceptor.cs b/ClusterReceptor.cs index d6fd3bf..fb9a7bc 100644 --- a/ClusterReceptor.cs +++ b/ClusterReceptor.cs @@ -100,6 +100,8 @@ public class ClusterReceptor : Cluster, IReceptor { set { _array.nuclei = value; } } + //public ClusterReceptor[] nucleiArray; + public void AddReceptorElement(ClusterPrefab prefab) { IReceptorHelpers.AddReceptorElement(this, prefab); } @@ -116,7 +118,7 @@ public class ClusterReceptor : Cluster, IReceptor { // Clusters don't do anything, // The nuclei in them do the work // and should be called directly, not from the cluster - + // float3 sum = this.bias; // foreach (Nucleus nucleus in this.sortedNuclei) @@ -129,30 +131,31 @@ public class ClusterReceptor : Cluster, IReceptor { } public override void UpdateNuclei() { - this.stale++; - if (this.stale > staleValueForSleep && lengthsq(this.bias) > 0) { - this.bias = new float3(0, 0, 0); - this.parent.UpdateFromNucleus(this); - } + // this.stale++; + // if (this.stale > staleValueForSleep && lengthsq(this.bias) > 0) { + // this.bias = new float3(0, 0, 0); + // this.parent.UpdateFromNucleus(this); + // } foreach (Nucleus nucleus in this.clusterNuclei) nucleus.UpdateNuclei(); } public override void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) { - this._array ??= new NucleusArray(this.parent); - this._array.ProcessStimulus(thingId, inputValue, thingName); + //this._array ??= new NucleusArray(this.parent); + //this._array.ProcessStimulus(thingId, inputValue, thingName); + Debug.LogError("Process Stimulus was called on clusterreceptor without a neuron specified"); } - private Dictionary thingReceivers = new(); + private readonly Dictionary thingReceivers = new(); public virtual void ProcessStimulus(Neuron input, Vector3 inputValue, int thingId = 0, string thingName = null) { CleanupReceivers(); - inputValue = input.Activator(inputValue); + //inputValue = input.Activator(inputValue); if (!thingReceivers.TryGetValue(thingId, out ClusterReceptor selectedReceiver)) - selectedReceiver = FindReceiver(thingId, inputValue); + selectedReceiver = FindReceiver2(thingId, inputValue); if (selectedReceiver == null) return; @@ -172,18 +175,61 @@ public class ClusterReceptor : Cluster, IReceptor { selectedNeuron.ProcessStimulusDirect(inputValue); } - private ClusterReceptor FindReceiver(int thingId, float3 inputValue) { + // private ClusterReceptor FindReceiver(int thingId, float3 inputValue) { + // // No existing nucleus for this thing + // float inputMagnitude = length(inputValue); + // ClusterReceptor selectedReceiver = null; + // float selectedMagnitude = 0; + // foreach (ClusterReceptor receiver in nucleiArray.Cast()) { + // if (thingReceivers.ContainsValue(receiver) == false) { + // // We found an unusued receiver + // thingReceivers.Add(thingId, receiver); + // return receiver; + // } + // else if (receiver.isSleeping) { + // // A sleeping receiver is not active and can therefore always be used + // thingReceivers.Add(thingId, receiver); + // return receiver; + // } + // else if (selectedReceiver == null) { + // // If we haven't found a receiver yet, just start by taking the first + // selectedReceiver = receiver; + // selectedMagnitude = length(selectedReceiver.outputValue); + // } + // // Look for the receiver with the lowest magnitude + // else { + // float magnitude = length(receiver.outputValue); + + // if (magnitude < inputMagnitude && length(receiver.outputValue) < selectedMagnitude) { + // selectedReceiver = receiver; + // selectedMagnitude = length(selectedReceiver.outputValue); + // } + // } + // } + // if (selectedReceiver != null) { + // // Replace the receiver + // // Find the thingId current associated with the receiver + // int keyToRemove = thingReceivers.FirstOrDefault(r => r.Value.Equals(selectedReceiver)).Key; + // if (keyToRemove != 0 || thingReceivers.ContainsKey(keyToRemove)) + // thingReceivers.Remove(keyToRemove); + // // And add the new association + // thingReceivers.Add(thingId, selectedReceiver); + // } + // return selectedReceiver; + // } + + private ClusterReceptor FindReceiver2(int thingId, float3 inputValue) { // No existing nucleus for this thing - float inputMagnitude = length(inputValue); + //float inputMagnitude = length(inputValue); ClusterReceptor selectedReceiver = null; float selectedMagnitude = 0; - foreach (ClusterReceptor receiver in nucleiArray.Cast()) { + foreach (ClusterReceptor receiver in this.nucleiArray.Cast()) { if (thingReceivers.ContainsValue(receiver) == false) { // We found an unusued receiver thingReceivers.Add(thingId, receiver); return receiver; } - else if (receiver.isSleeping) { + else if (receiver.defaultOutput.isSleeping) { // A sleeping receiver is not active and can therefore always be used thingReceivers.Add(thingId, receiver); return receiver; @@ -191,15 +237,15 @@ public class ClusterReceptor : Cluster, IReceptor { else if (selectedReceiver == null) { // If we haven't found a receiver yet, just start by taking the first selectedReceiver = receiver; - selectedMagnitude = length(selectedReceiver.outputValue); + selectedMagnitude = length(selectedReceiver.defaultOutput.outputValue); } - // Look for the receiver with the lowest magnitude + // Look for the receiver with the lowest output magnitude else { - float magnitude = length(receiver.outputValue); + float magnitude = length(receiver.defaultOutput.outputValue); - if (magnitude < inputMagnitude && length(receiver.outputValue) < selectedMagnitude) { + if (length(receiver.defaultOutput.outputValue) < selectedMagnitude) { selectedReceiver = receiver; - selectedMagnitude = length(selectedReceiver.outputValue); + selectedMagnitude = length(selectedReceiver.defaultOutput.outputValue); } } } @@ -215,13 +261,13 @@ public class ClusterReceptor : Cluster, IReceptor { return selectedReceiver; } - + private void CleanupReceivers() { // Remove a thing-receiver connection when the nucleus is inactive List receiversToRemove = new(); foreach (KeyValuePair item in thingReceivers) { - if (item.Value != null && item.Value.isSleeping) - receiversToRemove.Add(item.Key); + if (item.Value != null && item.Value.defaultOutput.isSleeping) + receiversToRemove.Add(item.Key); } foreach (int thingId in receiversToRemove) { Nucleus selectedReceiver = thingReceivers[thingId]; diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 2790aa8..d2c7e2d 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -262,9 +262,11 @@ public class ClusterInspector : Editor { if (this.currentNucleus is IReceptor receptor1) { float maxValue = 0; foreach (Nucleus nucleus in receptor1.nucleiArray) { - float value = length(nucleus.outputValue); - if (value > maxValue) - maxValue = value; + if (nucleus is Neuron neuron) { + float value = length(neuron.outputValue); + if (value > maxValue) + maxValue = value; + } } float spacing = 400f / receptor1.nucleiArray.Count(); @@ -309,7 +311,13 @@ public class ClusterInspector : Editor { Handles.color = Color.white; // The selected nucleus highlight ring Handles.DrawSolidDisc(position, Vector3.forward, size + 2); - DrawNucleus(this.currentNucleus, position, length(this.currentNucleus.outputValue), 20); + float maxValue = 1; + if (this.currentNucleus is Neuron neuron) + maxValue = length(neuron.outputValue); + else if (this.currentNucleus is Cluster cluster) + maxValue = length(cluster.defaultOutput.outputValue); + + DrawNucleus(this.currentNucleus, position, maxValue, 20); } } @@ -317,7 +325,12 @@ public class ClusterInspector : Editor { Handles.color = Color.white; // The selected nucleus highlight ring Handles.DrawSolidDisc(position, Vector3.forward, size + 2); - DrawNucleus(this.currentNucleus, position, length(this.currentNucleus.outputValue), 20); + float maxValue = 1; + if (this.currentNucleus is Neuron neuron) + maxValue = length(neuron.outputValue); + else if (this.currentNucleus is Cluster cluster) + maxValue = length(cluster.defaultOutput.outputValue); + DrawNucleus(this.currentNucleus, position, maxValue, 20); } } @@ -388,10 +401,12 @@ public class ClusterInspector : Editor { continue; drawnArrays.Add(clusterReceptor.nucleiArray); } - float value = length(synapse.nucleus.outputValue) * synapse.weight; - // Debug.Log($"{synapse.nucleus.name}: {value} {length(synapse.nucleus.outputValue)} {synapse.weight}"); - if (value > maxValue) - maxValue = value; + if (synapse.nucleus is Neuron synapseNeuron) { + float value = length(synapseNeuron.outputValue) * synapse.weight; + // Debug.Log($"{synapse.nucleus.name}: {value} {length(synapse.nucleus.outputValue)} {synapse.weight}"); + if (value > maxValue) + maxValue = value; + } neuronCount++; } @@ -419,7 +434,9 @@ public class ClusterInspector : Editor { if (Application.isPlaying) { if (maxValue == 0 || !float.IsFinite(maxValue)) maxValue = 1; - float brightness = length(synapse.nucleus.outputValue * synapse.weight) / maxValue; + float brightness = 0; + if (synapse.nucleus is Neuron synapseNeuron) + brightness = length(synapseNeuron.outputValue * synapse.weight) / maxValue; color = new Color(brightness, brightness, brightness, 1f); } if (synapse.nucleus.parent != null && synapse.nucleus.parent != this.currentNucleus.parent) { @@ -439,7 +456,9 @@ public class ClusterInspector : Editor { private void DrawNucleus(Nucleus nucleus, Vector3 position, float maxValue, float size) { Color color; if (Application.isPlaying) { - float brightness = length(nucleus.outputValue) / maxValue; + float brightness = 0; + if (nucleus is Neuron neuron) + brightness = length(neuron.outputValue) / maxValue; color = new Color(brightness, brightness, brightness, 1f); } else @@ -529,9 +548,13 @@ public class ClusterInspector : Editor { private void HandleMouseHover(Nucleus nucleus, Rect rect) { GUIContent tooltip; - tooltip = new( - $"{nucleus.name}" + - $"\nValue: {length(nucleus.outputValue)}"); + if (nucleus is Neuron neuron) { + tooltip = new( + $"{nucleus.name}" + + $"\nValue: {length(neuron.outputValue)}"); + } + else + tooltip = new($"{nucleus.name}"); Vector2 mousePosition = Event.current.mousePosition; @@ -609,8 +632,12 @@ public class ClusterInspector : Editor { } if (Application.isPlaying) { - GUIContent nameLabel = new("Output", this.currentNucleus.outputValue.ToString()); - EditorGUILayout.FloatField(nameLabel, length(this.currentNucleus.outputValue)); + if (currentNucleus is Neuron currentNeuron1) { + GUIContent nameLabel = new("Output", currentNeuron1.outputValue.ToString()); + EditorGUILayout.FloatField(nameLabel, length(currentNeuron1.outputValue)); + } + else + EditorGUILayout.LabelField(" "); } else EditorGUILayout.LabelField(" "); @@ -686,9 +713,11 @@ public class ClusterInspector : Editor { EditorGUILayout.Space(); if (Application.isPlaying) { - Vector3 value = synapse.nucleus.outputValue * synapse.weight; - GUIContent synapseValueLabel = new(synapse.nucleus.name, synapse.nucleus.outputValue.ToString()); - EditorGUILayout.FloatField(synapseValueLabel, length(synapse.nucleus.outputValue)); + if (synapse.nucleus is Neuron synapseNeuron) { + Vector3 value = synapseNeuron.outputValue * synapse.weight; + GUIContent synapseValueLabel = new(synapse.nucleus.name, synapseNeuron.outputValue.ToString()); + EditorGUILayout.FloatField(synapseValueLabel, length(synapseNeuron.outputValue)); + } } else { EditorGUILayout.BeginHorizontal(); @@ -784,8 +813,8 @@ public class ClusterInspector : Editor { EditorGUILayout.Space(); breakOnWake = EditorGUILayout.Toggle("Break on wake", breakOnWake); - if (breakOnWake) { - if (this.currentNucleus.isSleeping == false) + if (breakOnWake && this.currentNucleus is Neuron currentNeuron) { + if (currentNeuron.isSleeping == false) Debug.Break(); } trace = EditorGUILayout.Toggle("Trace", trace); @@ -802,15 +831,19 @@ public class ClusterInspector : Editor { if (this.gameObject != null) { if (this.currentNucleus is IReceptor receptor) { foreach (Nucleus nucleus in receptor.nucleiArray) { - Vector3 worldVector = this.gameObject.transform.TransformVector(nucleus.outputValue); - Handles.color = Color.yellow; - Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); + if (nucleus is Neuron neuron) { + Vector3 worldVector = this.gameObject.transform.TransformVector(neuron.outputValue); + Handles.color = Color.yellow; + Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); + } } } else { - Vector3 worldVector = this.gameObject.transform.TransformVector(this.currentNucleus.outputValue); - Handles.color = Color.yellow; - Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); + if (this.currentNucleus is Neuron currentNeuron) { + Vector3 worldVector = this.gameObject.transform.TransformVector(currentNeuron.outputValue); + Handles.color = Color.yellow; + Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); + } } } } @@ -825,15 +858,15 @@ public class ClusterInspector : Editor { case Nucleus.Type.MemoryCell: AddMemoryCellInput(nucleus); break; - case Nucleus.Type.Selector: - AddSelectorInput(nucleus); - break; + // case Nucleus.Type.Selector: + // AddSelectorInput(nucleus); + // break; case Nucleus.Type.Cluster: AddClusterInput(nucleus); break; - case Nucleus.Type.Pulsar: - AddPulsarInput(nucleus); - break; + // case Nucleus.Type.Pulsar: + // AddPulsarInput(nucleus); + // break; case Nucleus.Type.Receptor: AddReceptorInput(nucleus); break; @@ -855,19 +888,19 @@ public class ClusterInspector : Editor { BuildLayers(); } - protected void AddSelectorInput(Nucleus nucleus) { - Selector newSelector = new(this.prefab, "New Selector"); - newSelector.AddReceiver(nucleus); - this.currentNucleus = newSelector; - BuildLayers(); - } + // protected void AddSelectorInput(Nucleus nucleus) { + // Selector newSelector = new(this.prefab, "New Selector"); + // newSelector.AddReceiver(nucleus); + // this.currentNucleus = newSelector; + // BuildLayers(); + // } - protected void AddPulsarInput(Nucleus nucleus) { - Pulsar newPulsar = new(this.prefab, "New Pulsar"); - newPulsar.AddReceiver(nucleus); - this.currentNucleus = newPulsar; - BuildLayers(); - } + // protected void AddPulsarInput(Nucleus nucleus) { + // Pulsar newPulsar = new(this.prefab, "New Pulsar"); + // newPulsar.AddReceiver(nucleus); + // this.currentNucleus = newPulsar; + // BuildLayers(); + // } protected virtual void AddMemoryCellInput(Nucleus nucleus) { MemoryCell newMemory = new(this.prefab, "New memory cell"); diff --git a/Neuron.cs b/Neuron.cs index 92b9c7d..57abcac 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -117,6 +117,23 @@ public class Neuron : Nucleus { #endregion Serialization + protected float3 _outputValue; + public virtual float3 outputValue { + get { return _outputValue; } + set { + _outputValue = value; + if (this.isFiring) + WhenFiring?.Invoke(); + } + } + public bool isFiring => length(_outputValue) > 0.5f; + public Action WhenFiring; + + public virtual bool isSleeping => lengthsq(this.outputValue) == 0; + [NonSerialized] + public int stale = 1000; + public readonly int staleValueForSleep = 20; + // this clone the nucleus without the synapses and receivers public override Nucleus ShallowCloneTo(Cluster newParent) { Neuron clone = new(newParent, this.name); @@ -164,7 +181,8 @@ public class Neuron : Nucleus { if (receiver != null && receiver.synapses != null) receiver.synapses.RemoveAll(s => s.nucleus == nucleus); } - } else if (nucleus is Cluster cluster) { + } + else if (nucleus is Cluster cluster) { // remove all receivers for this cluster foreach (Neuron output in cluster.outputs) { foreach (Nucleus receiver in output.receivers) { @@ -197,15 +215,19 @@ public class Neuron : Nucleus { public float3 CombinatorSum() { float3 sum = this.bias; - foreach (Synapse synapse in this.synapses) - sum += synapse.weight * synapse.nucleus.outputValue; + foreach (Synapse synapse in this.synapses) { + if (synapse.nucleus is Neuron neuron) + sum += synapse.weight * neuron.outputValue; + } return sum; } public float3 CombinatorProduct() { float3 product = this.bias; - foreach (Synapse synapse in this.synapses) - product *= synapse.weight * synapse.nucleus.outputValue; + foreach (Synapse synapse in this.synapses) { + if (synapse.nucleus is Neuron neuron) + product *= synapse.weight * neuron.outputValue; + } return product; } @@ -215,12 +237,14 @@ public class Neuron : Nucleus { //Applying the weight factors foreach (Synapse synapse in this.synapses) { - float3 input = synapse.weight * synapse.nucleus.outputValue; + if (synapse.nucleus is Neuron neuron) { + float3 input = synapse.weight * neuron.outputValue; - float inputLength = length(input); - if (inputLength > maxLength) { - max = input; - maxLength = inputLength; + float inputLength = length(input); + if (inputLength > maxLength) { + max = input; + maxLength = inputLength; + } } } return max; @@ -278,7 +302,7 @@ public class Neuron : Nucleus { set { _receivers = value; } } - public virtual void AddReceiver(Nucleus receiverToAdd, float weight = 1) { + public virtual void AddReceiver(Nucleus receiverToAdd, float weight = 1) { // if (this is IReceptor receptor) { // foreach (Nucleus element in receptor.array.nuclei) { // if (element is Neuron neuron) { @@ -288,8 +312,8 @@ public class Neuron : Nucleus { // } // } // else { - this._receivers.Add(receiverToAdd); - receiverToAdd.AddSynapse(this, weight); + this._receivers.Add(receiverToAdd); + receiverToAdd.AddSynapse(this, weight); // } } @@ -313,8 +337,9 @@ public class Neuron : Nucleus { public override void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) { if (this.parent is ClusterReceptor clusterReceptor) { - clusterReceptor.ProcessStimulus(this, inputValue, thingId, thingName); - } else + clusterReceptor.ProcessStimulus(this, inputValue, thingId, thingName); + } + else ProcessStimulusDirect(inputValue, thingId, thingName); // this.stale = 0; // this.bias = inputValue; diff --git a/Nucleus.cs b/Nucleus.cs index cf4ff74..f3045c4 100644 --- a/Nucleus.cs +++ b/Nucleus.cs @@ -13,22 +13,22 @@ public abstract class Nucleus { [SerializeReference] public Cluster parent; - protected float3 _outputValue; - public virtual float3 outputValue { - get { return _outputValue; } - set { - _outputValue = value; - if (this.isFiring) - WhenFiring?.Invoke(); - } - } - public bool isFiring => length(_outputValue) > 0.5f; - public Action WhenFiring; + // protected float3 _outputValue; + // public virtual float3 outputValue { + // get { return _outputValue; } + // set { + // _outputValue = value; + // if (this.isFiring) + // WhenFiring?.Invoke(); + // } + // } + // public bool isFiring => length(_outputValue) > 0.5f; + // public Action WhenFiring; - public virtual bool isSleeping => lengthsq(this.outputValue) == 0; - [NonSerialized] - public int stale = 1000; - public readonly int staleValueForSleep = 20; + // public virtual bool isSleeping => lengthsq(this.outputValue) == 0; + // [NonSerialized] + // public int stale = 1000; + // public readonly int staleValueForSleep = 20; public bool trace = false; public abstract Nucleus ShallowCloneTo(Cluster parent); @@ -81,7 +81,7 @@ public abstract class Nucleus { } public virtual void SetBias(Vector3 inputValue) { - this.stale = 0; + //this.stale = 0; this.bias = inputValue; this.parent.UpdateFromNucleus(this); } diff --git a/NucleusArray.cs b/NucleusArray.cs index 774d0f7..9f8a172 100644 --- a/NucleusArray.cs +++ b/NucleusArray.cs @@ -69,9 +69,11 @@ public class NucleusArray { private Nucleus FindReceiver(int thingId, float3 inputValue) { // No existing nucleus for this thing float inputMagnitude = length(inputValue); - Nucleus selectedReceiver = null; + Neuron selectedReceiver = null; float selectedMagnitude = 0; - foreach (Nucleus receiver in this._nuclei) { + foreach (Nucleus nucleusReceiver in this._nuclei) { + if (nucleusReceiver is not Neuron receiver) + continue; if (thingReceivers.ContainsValue(receiver) == false) { // We found an unusued receiver thingReceivers.Add(thingId, receiver); @@ -138,7 +140,7 @@ public class NucleusArray { // Remove a thing-receiver connection when the nucleus is inactive List receiversToRemove = new(); foreach (KeyValuePair item in thingReceivers) { - if (item.Value != null && item.Value.isSleeping) + if (item.Value != null && item.Value is Neuron neuron && neuron.isSleeping) receiversToRemove.Add(item.Key); } foreach (int thingId in receiversToRemove) { diff --git a/Pulsar.cs b/Pulsar.cs index 8e2cc54..b302951 100644 --- a/Pulsar.cs +++ b/Pulsar.cs @@ -1,54 +1,54 @@ -using System; -using Unity.Mathematics; +// using System; +// using Unity.Mathematics; -///

-/// The Pulsar represents a type of neuron that operates based on -/// the product of its weighted inputs rather than the traditional summation. -/// Drawing inspiration from the concept of pulsars in astrophysics -/// —highly magnetized rotating neutron stars that emit beams of radiation— -/// the Pulsar could symbolize dynamic, focused output based on the interaction of multiple factors. -/// -/// Multiplicative Functionality: -/// Instead of summing inputs, the Pulsar takes the weighted product of its inputs. -/// This means that all inputs must be active (non-zero) for the neuron to "pulse" or activate. -/// Output Behavior: -/// The output could amplify or diminish depending on the magnitude of the inputs. -/// The product would be sensitive to small values, -/// which means that even a small input could significantly lower the overall output if multiplied. -/// Activation Mechanism: -/// The activation function can further refine the output from the product result. -/// For instance, a certain threshold could be used to determine if a pulse occurs. -/// Modeling Complex Interactions: -/// The Pulsar could be particularly beneficial for modeling situations where interactions multiply rather than add. -/// This is useful in fields such as economics (e.g., compound growth models), -/// biology (e.g., interaction of hormones), and machine learning where multiplicative relationships exist. -[Serializable] -public class Pulsar : Neuron { - public Pulsar(Cluster parent, string name) : base(parent, name) { - // To prevent mistakes, bias one (instead of zero for standard neurons) - this.bias = new float3(1, 1, 1); - } - public Pulsar(ClusterPrefab parent, string name) : base(parent, name) { - // To prevent mistakes, bias one (instead of zero for standard neurons) - this.bias = new float3(1, 1, 1); - } +// /// +// /// The Pulsar represents a type of neuron that operates based on +// /// the product of its weighted inputs rather than the traditional summation. +// /// Drawing inspiration from the concept of pulsars in astrophysics +// /// —highly magnetized rotating neutron stars that emit beams of radiation— +// /// the Pulsar could symbolize dynamic, focused output based on the interaction of multiple factors. +// /// +// /// Multiplicative Functionality: +// /// Instead of summing inputs, the Pulsar takes the weighted product of its inputs. +// /// This means that all inputs must be active (non-zero) for the neuron to "pulse" or activate. +// /// Output Behavior: +// /// The output could amplify or diminish depending on the magnitude of the inputs. +// /// The product would be sensitive to small values, +// /// which means that even a small input could significantly lower the overall output if multiplied. +// /// Activation Mechanism: +// /// The activation function can further refine the output from the product result. +// /// For instance, a certain threshold could be used to determine if a pulse occurs. +// /// Modeling Complex Interactions: +// /// The Pulsar could be particularly beneficial for modeling situations where interactions multiply rather than add. +// /// This is useful in fields such as economics (e.g., compound growth models), +// /// biology (e.g., interaction of hormones), and machine learning where multiplicative relationships exist. +// [Serializable] +// public class Pulsar : Neuron { +// public Pulsar(Cluster parent, string name) : base(parent, name) { +// // To prevent mistakes, bias one (instead of zero for standard neurons) +// this.bias = new float3(1, 1, 1); +// } +// public Pulsar(ClusterPrefab parent, string name) : base(parent, name) { +// // To prevent mistakes, bias one (instead of zero for standard neurons) +// this.bias = new float3(1, 1, 1); +// } - public override Nucleus ShallowCloneTo(Cluster newParent) { - Pulsar clone = new(newParent, this.name); - CloneFields(clone); - return clone; - } +// public override Nucleus ShallowCloneTo(Cluster newParent) { +// Pulsar clone = new(newParent, this.name); +// CloneFields(clone); +// return clone; +// } - public override void UpdateStateIsolated() { - float3 product = this.bias; +// public override void UpdateStateIsolated() { +// float3 product = this.bias; - //Applying the weight factors - foreach (Synapse synapse in this.synapses) { - float3 input = synapse.weight * synapse.nucleus.outputValue; - product *= input; - } +// //Applying the weight factors +// foreach (Synapse synapse in this.synapses) { +// float3 input = synapse.weight * synapse.nucleus.outputValue; +// product *= input; +// } - // Activation function - this.outputValue = Activator(product); - } -} \ No newline at end of file +// // Activation function +// this.outputValue = Activator(product); +// } +// } \ No newline at end of file diff --git a/Selector.cs b/Selector.cs index 320f807..ad68c3d 100644 --- a/Selector.cs +++ b/Selector.cs @@ -1,62 +1,62 @@ -using System; -using Unity.Mathematics; -using static Unity.Mathematics.math; +// using System; +// using Unity.Mathematics; +// using static Unity.Mathematics.math; -[Serializable] -public class Selector : Neuron { - public Selector(Cluster parent, string name) : base(parent, name) { } - public Selector(ClusterPrefab parent, string name) : base(parent, name) {} +// [Serializable] +// public class Selector : Neuron { +// public Selector(Cluster parent, string name) : base(parent, name) { } +// public Selector(ClusterPrefab parent, string name) : base(parent, name) {} - public override Nucleus ShallowCloneTo(Cluster newParent) { - Selector clone = new(newParent, this.name) { - // array = this.array, - curve = this.curve, - curvePreset = this.curvePreset, - curveMax = this.curveMax, - }; - return clone; - } +// public override Nucleus ShallowCloneTo(Cluster newParent) { +// Selector clone = new(newParent, this.name) { +// // array = this.array, +// curve = this.curve, +// curvePreset = this.curvePreset, +// curveMax = this.curveMax, +// }; +// return clone; +// } - public override void UpdateStateIsolated() { //float3 bias) { - float3 max = this.bias; - float maxSqrLength = lengthsq(max); +// public override void UpdateStateIsolated() { //float3 bias) { +// float3 max = this.bias; +// float maxSqrLength = lengthsq(max); - //Applying the weight factors - foreach (Synapse synapse in this.synapses) { - float3 input = synapse.weight * synapse.nucleus.outputValue; +// //Applying the weight factors +// foreach (Synapse synapse in this.synapses) { +// float3 input = synapse.weight * synapse.nucleus.outputValue; - float inputSqrlength = lengthsq(input); - if (inputSqrlength > maxSqrLength) { - max = input; - maxSqrLength = inputSqrlength; - } - } +// float inputSqrlength = lengthsq(input); +// if (inputSqrlength > maxSqrLength) { +// max = input; +// maxSqrLength = inputSqrlength; +// } +// } - // Activation function - float3 result; - switch (this.curvePreset) { - case CurvePresets.Linear: - result = max; - break; - case CurvePresets.Sqrt: - result = normalize(max) * System.MathF.Sqrt(length(max)); - break; - case CurvePresets.Power: - result = normalize(max) * System.MathF.Pow(length(max), 2); - break; - case CurvePresets.Reciprocal: { - float magnitude = length(max); - if (magnitude > 0) - result = normalize(max) * (1 / magnitude); - else - result = float3(0, 0, 0); - break; - } - default: - float activatedValue = this.curve.Evaluate(length(max)); - result = normalize(max) * activatedValue; - break; - } - this.outputValue = result; - } -} \ No newline at end of file +// // Activation function +// float3 result; +// switch (this.curvePreset) { +// case CurvePresets.Linear: +// result = max; +// break; +// case CurvePresets.Sqrt: +// result = normalize(max) * System.MathF.Sqrt(length(max)); +// break; +// case CurvePresets.Power: +// result = normalize(max) * System.MathF.Pow(length(max), 2); +// break; +// case CurvePresets.Reciprocal: { +// float magnitude = length(max); +// if (magnitude > 0) +// result = normalize(max) * (1 / magnitude); +// else +// result = float3(0, 0, 0); +// break; +// } +// default: +// float activatedValue = this.curve.Evaluate(length(max)); +// result = normalize(max) * activatedValue; +// break; +// } +// this.outputValue = result; +// } +// } \ No newline at end of file From 28ffae8ce7b03cbf3a655ff8cdf0bb12eedadb12 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 4 Mar 2026 15:22:36 +0100 Subject: [PATCH 174/179] Fix set weight on receptor arrays --- Cluster.cs | 2 +- ClusterReceptor.cs | 3 +- Editor/ClusterInspector.cs | 6 +- NewVelocity.asset | 1305 ++++++++++++++++++++++++++++++++++++ NewVelocity.asset.meta | 8 + Pulsar.cs | 54 -- Pulsar.cs.meta | 2 - Selector.cs | 62 -- Selector.cs.meta | 2 - 9 files changed, 1319 insertions(+), 125 deletions(-) create mode 100644 NewVelocity.asset create mode 100644 NewVelocity.asset.meta delete mode 100644 Pulsar.cs delete mode 100644 Pulsar.cs.meta delete mode 100644 Selector.cs delete mode 100644 Selector.cs.meta diff --git a/Cluster.cs b/Cluster.cs index 2a7fe34..c9842dd 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -104,7 +104,7 @@ public class Cluster : Nucleus { foreach (Nucleus prefabArrayNucleus in prefabReceptor.nucleiArray) { int arrayNucleusIx = GetNucleusIndex(prefabNuclei, prefabArrayNucleus); if (arrayNucleusIx >= 0) { - Neuron clonedArrayNucleus = clonedNuclei[arrayNucleusIx] as Neuron; + Nucleus clonedArrayNucleus = clonedNuclei[arrayNucleusIx]; clonedArray.nuclei[arrayIx] = clonedArrayNucleus; } else { diff --git a/ClusterReceptor.cs b/ClusterReceptor.cs index fb9a7bc..b93e205 100644 --- a/ClusterReceptor.cs +++ b/ClusterReceptor.cs @@ -152,6 +152,7 @@ public class ClusterReceptor : Cluster, IReceptor { public virtual void ProcessStimulus(Neuron input, Vector3 inputValue, int thingId = 0, string thingName = null) { CleanupReceivers(); + Debug.Log($"{input.name} is {inputValue}, 1/{inputValue} = {1 / inputValue.x}, {1/inputValue.y}, {1/inputValue.z}"); //inputValue = input.Activator(inputValue); if (!thingReceivers.TryGetValue(thingId, out ClusterReceptor selectedReceiver)) @@ -173,6 +174,7 @@ public class ClusterReceptor : Cluster, IReceptor { if (selectedReceiver.clusterNuclei[inputIx] is Neuron selectedNeuron) selectedNeuron.ProcessStimulusDirect(inputValue); + Debug.Log($"cluster output = {selectedReceiver.defaultOutput.outputValue}"); } // private ClusterReceptor FindReceiver(int thingId, float3 inputValue) { @@ -220,7 +222,6 @@ public class ClusterReceptor : Cluster, IReceptor { private ClusterReceptor FindReceiver2(int thingId, float3 inputValue) { // No existing nucleus for this thing - //float inputMagnitude = length(inputValue); ClusterReceptor selectedReceiver = null; float selectedMagnitude = 0; foreach (ClusterReceptor receiver in this.nucleiArray.Cast()) { diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index d2c7e2d..56cb636 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -176,7 +176,7 @@ public class ClusterInspector : Editor { if (this.prefabAsset == null) { // create in memory save if it doesn't exist this.prefabAsset = CreateInstance(); - Debug.LogError("Cluster Prefab is not found on disk"); + //Debug.LogError("Cluster Prefab is not found on disk"); } DrawInspector(inspectorContainer); } @@ -752,10 +752,10 @@ public class ClusterInspector : Editor { EditorGUI.indentLevel++; float newWeight = EditorGUILayout.FloatField("Weight", synapse.weight); if (newWeight != synapse.weight) { - if (synapse.nucleus is IReceptor receptor) { + if (synapse.nucleus.parent is IReceptor receptor) { Nucleus[] receptorArray = receptor.nucleiArray; foreach (Synapse s in this.currentNucleus.synapses) { - if (s.nucleus is IReceptor r && r.nucleiArray == receptorArray) + if (s.nucleus.parent is IReceptor r && r.nucleiArray == receptorArray) s.weight = newWeight; } } diff --git a/NewVelocity.asset b/NewVelocity.asset new file mode 100644 index 0000000..87c56b4 --- /dev/null +++ b/NewVelocity.asset @@ -0,0 +1,1305 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3} + m_Name: NewVelocity + m_EditorClassIdentifier: Assembly-CSharp::ClusterPrefab + nuclei: + - rid: 2262690579536937007 + - rid: 2262690579536937008 + - rid: 2262690579536937009 + - rid: 2262690579536937010 + references: + version: 2 + RefIds: + - rid: -2 + type: {class: , ns: , asm: } + - rid: 2262690579536937007 + type: {class: Neuron, ns: , asm: Assembly-CSharp} + data: + name: Proximity + clusterPrefab: {fileID: 11400000} + parent: + rid: -2 + trace: 0 + bias: {x: 0, y: 0, z: 0} + _synapses: + - nucleus: + rid: 2262690579536937008 + weight: 1 + combinator: 0 + _curvePreset: 3 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.001 + value: 999.99994 + inSlope: 0 + outSlope: -112788.63 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.008866142 + value: 112.788635 + inSlope: -112788.63 + outSlope: -6740.78 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.016732283 + value: 59.76471 + inSlope: -6740.78 + outSlope: -2429.6155 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.024598425 + value: 40.653008 + inSlope: -2429.6155 + outSlope: -1252.2269 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.032464568 + value: 30.802813 + inSlope: -1252.2269 + outSlope: -763.7558 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.040330708 + value: 24.795002 + inSlope: -763.7558 + outSlope: -514.45264 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.04819685 + value: 20.748245 + inSlope: -514.45264 + outSlope: -370.0882 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.056062993 + value: 17.837078 + inSlope: -370.0882 + outSlope: -279.01324 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.06392913 + value: 15.642321 + inSlope: -279.01324 + outSlope: -217.87398 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.07179528 + value: 13.928493 + inSlope: -217.87398 + outSlope: -174.8461 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.079661414 + value: 12.553129 + inSlope: -174.8461 + outSlope: -143.41913 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.087527566 + value: 11.424973 + inSlope: -143.41913 + outSlope: -119.76661 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.0953937 + value: 10.482872 + inSlope: -119.76661 + outSlope: -101.519356 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.10325985 + value: 9.684306 + inSlope: -101.519356 + outSlope: -87.14706 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.11112598 + value: 8.9987955 + inSlope: -87.14706 + outSlope: -75.62513 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.11899213 + value: 8.403917 + inSlope: -75.62513 + outSlope: -66.24654 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.12685826 + value: 7.882813 + inSlope: -66.24654 + outSlope: -58.510654 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.13472441 + value: 7.4225597 + inSlope: -58.510654 + outSlope: -52.055042 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.14259055 + value: 7.0130873 + inSlope: -52.055042 + outSlope: -46.612007 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.1504567 + value: 6.6464305 + inSlope: -46.612007 + outSlope: -41.98024 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.15832284 + value: 6.316208 + inSlope: -41.98024 + outSlope: -38.006134 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.16618897 + value: 6.0172467 + inSlope: -38.006134 + outSlope: -34.570965 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.17405513 + value: 5.745306 + inSlope: -34.570965 + outSlope: -31.581244 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.18192126 + value: 5.496884 + inSlope: -31.581244 + outSlope: -28.963417 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.1897874 + value: 5.2690535 + inSlope: -28.963417 + outSlope: -26.658009 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.19765353 + value: 5.059358 + inSlope: -26.658009 + outSlope: -24.617418 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.20551969 + value: 4.8657136 + inSlope: -24.617418 + outSlope: -22.802412 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.21338584 + value: 4.6863465 + inSlope: -22.802412 + outSlope: -21.181019 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.22125196 + value: 4.519734 + inSlope: -21.181019 + outSlope: -19.72667 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.22911811 + value: 4.364561 + inSlope: -19.72667 + outSlope: -18.417059 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.23698425 + value: 4.21969 + inSlope: -18.417059 + outSlope: -17.233776 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2448504 + value: 4.0841265 + inSlope: -17.233776 + outSlope: -16.160883 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.25271654 + value: 3.9570026 + inSlope: -16.160883 + outSlope: -15.185221 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2605827 + value: 3.8375535 + inSlope: -15.185221 + outSlope: -14.295299 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2684488 + value: 3.725105 + inSlope: -14.295299 + outSlope: -13.481375 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.27631494 + value: 3.6190586 + inSlope: -13.481375 + outSlope: -12.735047 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.28418112 + value: 3.5188825 + inSlope: -12.735047 + outSlope: -12.04901 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.29204726 + value: 3.4241033 + inSlope: -12.04901 + outSlope: -11.416967 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.2999134 + value: 3.3342957 + inSlope: -11.416967 + outSlope: -10.8334 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.30777952 + value: 3.249079 + inSlope: -10.8334 + outSlope: -10.293426 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.31564566 + value: 3.1681094 + inSlope: -10.293426 + outSlope: -9.792865 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.3235118 + value: 3.0910773 + inSlope: -9.792865 + outSlope: -9.327949 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.33137795 + value: 3.0177023 + inSlope: -9.327949 + outSlope: -8.895375 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.33924407 + value: 2.9477303 + inSlope: -8.895375 + outSlope: -8.492224 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.34711024 + value: 2.880929 + inSlope: -8.492224 + outSlope: -8.115812 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.3549764 + value: 2.8170888 + inSlope: -8.115812 + outSlope: -7.76395 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.36284253 + value: 2.7560165 + inSlope: -7.76395 + outSlope: -7.434456 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.37070867 + value: 2.697536 + inSlope: -7.434456 + outSlope: -7.1255083 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.3785748 + value: 2.641486 + inSlope: -7.1255083 + outSlope: -6.8354197 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.38644093 + value: 2.5877175 + inSlope: -6.8354197 + outSlope: -6.562695 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.39430708 + value: 2.5360944 + inSlope: -6.562695 + outSlope: -6.305974 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.40217322 + value: 2.4864907 + inSlope: -6.305974 + outSlope: -6.064021 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4100394 + value: 2.43879 + inSlope: -6.064021 + outSlope: -5.835745 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4179055 + value: 2.3928854 + inSlope: -5.835745 + outSlope: -5.6201315 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.42577165 + value: 2.3486767 + inSlope: -5.6201315 + outSlope: -5.4162097 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4336378 + value: 2.306072 + inSlope: -5.4162097 + outSlope: -5.223229 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.44150394 + value: 2.2649853 + inSlope: -5.223229 + outSlope: -5.040342 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4493701 + value: 2.2253373 + inSlope: -5.040342 + outSlope: -4.8669295 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4572362 + value: 2.1870534 + inSlope: -4.8669295 + outSlope: -4.7023005 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.46510234 + value: 2.1500645 + inSlope: -4.7023005 + outSlope: -4.5458865 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.47296852 + value: 2.1143057 + inSlope: -4.5458865 + outSlope: -4.3971753 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.48083466 + value: 2.079717 + inSlope: -4.3971753 + outSlope: -4.2555995 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.4887008 + value: 2.0462418 + inSlope: -4.2555995 + outSlope: -4.1207685 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.49656692 + value: 2.0138273 + inSlope: -4.1207685 + outSlope: -3.9922712 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5044331 + value: 1.9824234 + inSlope: -3.9922712 + outSlope: -3.8696532 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5122992 + value: 1.9519844 + inSlope: -3.8696532 + outSlope: -3.7526293 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5201653 + value: 1.9224657 + inSlope: -3.7526293 + outSlope: -3.6408176 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.52803147 + value: 1.8938265 + inSlope: -3.6408176 + outSlope: -3.5339315 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5358976 + value: 1.8660281 + inSlope: -3.5339315 + outSlope: -3.4316826 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.54376376 + value: 1.839034 + inSlope: -3.4316826 + outSlope: -3.3338284 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5516299 + value: 1.8128096 + inSlope: -3.3338284 + outSlope: -3.240066 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.55949605 + value: 1.7873228 + inSlope: -3.240066 + outSlope: -3.1502352 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.56736225 + value: 1.7625424 + inSlope: -3.1502352 + outSlope: -3.0640743 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5752284 + value: 1.7384399 + inSlope: -3.0640743 + outSlope: -2.9814053 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.58309454 + value: 1.7149878 + inSlope: -2.9814053 + outSlope: -2.9020314 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.5909606 + value: 1.6921601 + inSlope: -2.9020314 + outSlope: -2.8257964 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.59882677 + value: 1.669932 + inSlope: -2.8257964 + outSlope: -2.7525082 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6066929 + value: 1.6482804 + inSlope: -2.7525082 + outSlope: -2.6820538 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.61455905 + value: 1.627183 + inSlope: -2.6820538 + outSlope: -2.6142666 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6224252 + value: 1.6066188 + inSlope: -2.6142666 + outSlope: -2.5490105 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.63029134 + value: 1.5865679 + inSlope: -2.5490105 + outSlope: -2.4861636 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6381575 + value: 1.5670114 + inSlope: -2.4861636 + outSlope: -2.4256358 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.64602363 + value: 1.547931 + inSlope: -2.4256358 + outSlope: -2.3672597 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6538898 + value: 1.5293097 + inSlope: -2.3672597 + outSlope: -2.3109925 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.66175586 + value: 1.5111313 + inSlope: -2.3109925 + outSlope: -2.2566907 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.669622 + value: 1.4933798 + inSlope: -2.2566907 + outSlope: -2.2042859 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.67748815 + value: 1.4760406 + inSlope: -2.2042859 + outSlope: -2.1536992 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6853543 + value: 1.4590993 + inSlope: -2.1536992 + outSlope: -2.1048093 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.6932205 + value: 1.4425424 + inSlope: -2.1048093 + outSlope: -2.0575728 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.70108664 + value: 1.4263573 + inSlope: -2.0575728 + outSlope: -2.011927 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7089528 + value: 1.4105312 + inSlope: -2.011927 + outSlope: -1.9677659 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7168189 + value: 1.3950524 + inSlope: -1.9677659 + outSlope: -1.9250447 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7246851 + value: 1.3799098 + inSlope: -1.9250447 + outSlope: -1.8837026 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7325512 + value: 1.3650923 + inSlope: -1.8837026 + outSlope: -1.8436778 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7404173 + value: 1.3505898 + inSlope: -1.8436778 + outSlope: -1.8049132 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.74828345 + value: 1.336392 + inSlope: -1.8049132 + outSlope: -1.7673749 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7561496 + value: 1.3224896 + inSlope: -1.7673749 + outSlope: -1.7309732 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.76401573 + value: 1.3088735 + inSlope: -1.7309732 + outSlope: -1.695693 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7718819 + value: 1.295535 + inSlope: -1.695693 + outSlope: -1.6614736 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.779748 + value: 1.2824656 + inSlope: -1.6614736 + outSlope: -1.6282848 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.78761417 + value: 1.2696573 + inSlope: -1.6282848 + outSlope: -1.5960962 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.7954803 + value: 1.2571021 + inSlope: -1.5960962 + outSlope: -1.564832 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.80334646 + value: 1.2447929 + inSlope: -1.564832 + outSlope: -1.5344887 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.81121254 + value: 1.2327225 + inSlope: -1.5344887 + outSlope: -1.5050048 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.81907874 + value: 1.2208838 + inSlope: -1.5050048 + outSlope: -1.4763738 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8269449 + value: 1.2092705 + inSlope: -1.4763738 + outSlope: -1.4485649 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.83481103 + value: 1.1978759 + inSlope: -1.4485649 + outSlope: -1.4215137 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8426772 + value: 1.186694 + inSlope: -1.4215137 + outSlope: -1.3952202 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8505433 + value: 1.175719 + inSlope: -1.3952202 + outSlope: -1.369639 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.85840946 + value: 1.1649452 + inSlope: -1.369639 + outSlope: -1.3447852 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8662756 + value: 1.154367 + inSlope: -1.3447852 + outSlope: -1.320568 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.87414175 + value: 1.1439792 + inSlope: -1.320568 + outSlope: -1.2970176 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8820079 + value: 1.1337767 + inSlope: -1.2970176 + outSlope: -1.2740829 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.889874 + value: 1.1237546 + inSlope: -1.2740829 + outSlope: -1.2517655 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.8977401 + value: 1.113908 + inSlope: -1.2517655 + outSlope: -1.2300034 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.90560627 + value: 1.1042327 + inSlope: -1.2300034 + outSlope: -1.2088321 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9134724 + value: 1.0947238 + inSlope: -1.2088321 + outSlope: -1.1881914 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.92133856 + value: 1.0853773 + inSlope: -1.1881914 + outSlope: -1.1680659 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9292047 + value: 1.0761892 + inSlope: -1.1680659 + outSlope: -1.1484709 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.93707085 + value: 1.0671551 + inSlope: -1.1484709 + outSlope: -1.1293371 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.94493705 + value: 1.0582715 + inSlope: -1.1293371 + outSlope: -1.1106901 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9528032 + value: 1.0495347 + inSlope: -1.1106901 + outSlope: -1.0925045 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.96066934 + value: 1.0409409 + inSlope: -1.0925045 + outSlope: -1.0747513 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9685354 + value: 1.0324868 + inSlope: -1.0747513 + outSlope: -1.0574516 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.97640157 + value: 1.0241687 + inSlope: -1.0574516 + outSlope: -1.0405389 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.9842677 + value: 1.0159837 + inSlope: -1.0405389 + outSlope: -1.0240355 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.99213386 + value: 1.0079285 + inSlope: -1.0240355 + outSlope: -1.0079259 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: -1.0079259 + outSlope: 0 + tangentMode: 69 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 100 + _receivers: [] + - rid: 2262690579536937008 + type: {class: Neuron, ns: , asm: Assembly-CSharp} + data: + name: Position + clusterPrefab: {fileID: 11400000} + parent: + rid: -2 + trace: 0 + bias: {x: 0, y: 0, z: 0} + _synapses: [] + combinator: 0 + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1000 + value: 1000 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + _receivers: + - rid: 2262690579536937007 + - rid: 2262690579536937009 + - rid: 2262690579536937009 + type: {class: Neuron, ns: , asm: Assembly-CSharp} + data: + name: Velocity + clusterPrefab: {fileID: 11400000} + parent: + rid: -2 + trace: 0 + bias: {x: 0, y: 0, z: 0} + _synapses: + - nucleus: + rid: 2262690579536937008 + weight: 1 + - nucleus: + rid: 2262690579536937010 + weight: 1 + combinator: 0 + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1000 + value: 1000 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + _receivers: [] + - rid: 2262690579536937010 + type: {class: MemoryCell, ns: , asm: Assembly-CSharp} + data: + name: New memory cell + clusterPrefab: {fileID: 11400000} + parent: + rid: -2 + trace: 0 + bias: {x: 0, y: 0, z: 0} + _synapses: [] + combinator: 0 + _curvePreset: 0 + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curveMax: 1 + _receivers: + - rid: 2262690579536937009 + staticMemory: 0 diff --git a/NewVelocity.asset.meta b/NewVelocity.asset.meta new file mode 100644 index 0000000..5718f8b --- /dev/null +++ b/NewVelocity.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 61eea9f818639ec20b7a7bf4e86fff66 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Pulsar.cs b/Pulsar.cs deleted file mode 100644 index b302951..0000000 --- a/Pulsar.cs +++ /dev/null @@ -1,54 +0,0 @@ -// using System; -// using Unity.Mathematics; - -// /// -// /// The Pulsar represents a type of neuron that operates based on -// /// the product of its weighted inputs rather than the traditional summation. -// /// Drawing inspiration from the concept of pulsars in astrophysics -// /// —highly magnetized rotating neutron stars that emit beams of radiation— -// /// the Pulsar could symbolize dynamic, focused output based on the interaction of multiple factors. -// /// -// /// Multiplicative Functionality: -// /// Instead of summing inputs, the Pulsar takes the weighted product of its inputs. -// /// This means that all inputs must be active (non-zero) for the neuron to "pulse" or activate. -// /// Output Behavior: -// /// The output could amplify or diminish depending on the magnitude of the inputs. -// /// The product would be sensitive to small values, -// /// which means that even a small input could significantly lower the overall output if multiplied. -// /// Activation Mechanism: -// /// The activation function can further refine the output from the product result. -// /// For instance, a certain threshold could be used to determine if a pulse occurs. -// /// Modeling Complex Interactions: -// /// The Pulsar could be particularly beneficial for modeling situations where interactions multiply rather than add. -// /// This is useful in fields such as economics (e.g., compound growth models), -// /// biology (e.g., interaction of hormones), and machine learning where multiplicative relationships exist. -// [Serializable] -// public class Pulsar : Neuron { -// public Pulsar(Cluster parent, string name) : base(parent, name) { -// // To prevent mistakes, bias one (instead of zero for standard neurons) -// this.bias = new float3(1, 1, 1); -// } -// public Pulsar(ClusterPrefab parent, string name) : base(parent, name) { -// // To prevent mistakes, bias one (instead of zero for standard neurons) -// this.bias = new float3(1, 1, 1); -// } - -// public override Nucleus ShallowCloneTo(Cluster newParent) { -// Pulsar clone = new(newParent, this.name); -// CloneFields(clone); -// return clone; -// } - -// public override void UpdateStateIsolated() { -// float3 product = this.bias; - -// //Applying the weight factors -// foreach (Synapse synapse in this.synapses) { -// float3 input = synapse.weight * synapse.nucleus.outputValue; -// product *= input; -// } - -// // Activation function -// this.outputValue = Activator(product); -// } -// } \ No newline at end of file diff --git a/Pulsar.cs.meta b/Pulsar.cs.meta deleted file mode 100644 index e73f7db..0000000 --- a/Pulsar.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 46bd155173053a01585411c3e07f85d4 \ No newline at end of file diff --git a/Selector.cs b/Selector.cs deleted file mode 100644 index ad68c3d..0000000 --- a/Selector.cs +++ /dev/null @@ -1,62 +0,0 @@ -// using System; -// using Unity.Mathematics; -// using static Unity.Mathematics.math; - -// [Serializable] -// public class Selector : Neuron { -// public Selector(Cluster parent, string name) : base(parent, name) { } -// public Selector(ClusterPrefab parent, string name) : base(parent, name) {} - -// public override Nucleus ShallowCloneTo(Cluster newParent) { -// Selector clone = new(newParent, this.name) { -// // array = this.array, -// curve = this.curve, -// curvePreset = this.curvePreset, -// curveMax = this.curveMax, -// }; -// return clone; -// } - -// public override void UpdateStateIsolated() { //float3 bias) { -// float3 max = this.bias; -// float maxSqrLength = lengthsq(max); - -// //Applying the weight factors -// foreach (Synapse synapse in this.synapses) { -// float3 input = synapse.weight * synapse.nucleus.outputValue; - -// float inputSqrlength = lengthsq(input); -// if (inputSqrlength > maxSqrLength) { -// max = input; -// maxSqrLength = inputSqrlength; -// } -// } - -// // Activation function -// float3 result; -// switch (this.curvePreset) { -// case CurvePresets.Linear: -// result = max; -// break; -// case CurvePresets.Sqrt: -// result = normalize(max) * System.MathF.Sqrt(length(max)); -// break; -// case CurvePresets.Power: -// result = normalize(max) * System.MathF.Pow(length(max), 2); -// break; -// case CurvePresets.Reciprocal: { -// float magnitude = length(max); -// if (magnitude > 0) -// result = normalize(max) * (1 / magnitude); -// else -// result = float3(0, 0, 0); -// break; -// } -// default: -// float activatedValue = this.curve.Evaluate(length(max)); -// result = normalize(max) * activatedValue; -// break; -// } -// this.outputValue = result; -// } -// } \ No newline at end of file diff --git a/Selector.cs.meta b/Selector.cs.meta deleted file mode 100644 index 1273f83..0000000 --- a/Selector.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 4218c2f3f15af944db0eadd6e1500d17 \ No newline at end of file From 8a9700981b747a2a84d34ccb3125d16286a44ba4 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 4 Mar 2026 15:46:55 +0100 Subject: [PATCH 175/179] They are swarming! --- ClusterReceptor.cs | 18 ++++++++++++++---- Editor/ClusterInspector.cs | 5 +++-- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/ClusterReceptor.cs b/ClusterReceptor.cs index b93e205..ba444c0 100644 --- a/ClusterReceptor.cs +++ b/ClusterReceptor.cs @@ -152,11 +152,11 @@ public class ClusterReceptor : Cluster, IReceptor { public virtual void ProcessStimulus(Neuron input, Vector3 inputValue, int thingId = 0, string thingName = null) { CleanupReceivers(); - Debug.Log($"{input.name} is {inputValue}, 1/{inputValue} = {1 / inputValue.x}, {1/inputValue.y}, {1/inputValue.z}"); + // Debug.Log($"{input.name} is {inputValue}, 1/{inputValue} = {1 / inputValue.x}, {1/inputValue.y}, {1/inputValue.z}"); //inputValue = input.Activator(inputValue); if (!thingReceivers.TryGetValue(thingId, out ClusterReceptor selectedReceiver)) - selectedReceiver = FindReceiver2(thingId, inputValue); + selectedReceiver = FindReceiver2(thingId, inputValue, input); if (selectedReceiver == null) return; @@ -174,7 +174,7 @@ public class ClusterReceptor : Cluster, IReceptor { if (selectedReceiver.clusterNuclei[inputIx] is Neuron selectedNeuron) selectedNeuron.ProcessStimulusDirect(inputValue); - Debug.Log($"cluster output = {selectedReceiver.defaultOutput.outputValue}"); + // Debug.Log($"cluster output = {selectedReceiver.defaultOutput.outputValue}"); } // private ClusterReceptor FindReceiver(int thingId, float3 inputValue) { @@ -220,7 +220,7 @@ public class ClusterReceptor : Cluster, IReceptor { // return selectedReceiver; // } - private ClusterReceptor FindReceiver2(int thingId, float3 inputValue) { + private ClusterReceptor FindReceiver2(int thingId, float3 inputValue, Neuron input) { // No existing nucleus for this thing ClusterReceptor selectedReceiver = null; float selectedMagnitude = 0; @@ -233,6 +233,7 @@ public class ClusterReceptor : Cluster, IReceptor { else if (receiver.defaultOutput.isSleeping) { // A sleeping receiver is not active and can therefore always be used thingReceivers.Add(thingId, receiver); + receiver.bias = float3(0, 0, 0); return receiver; } else if (selectedReceiver == null) { @@ -251,6 +252,15 @@ public class ClusterReceptor : Cluster, IReceptor { } } if (selectedReceiver != null) { + // To re-initialize the cluster (esp. memory cells) + // we update the cluster neuron twice. + // Bit of a hack..... + int inputIx = GetNucleusIndex(this.clusterNuclei, input); + if (inputIx >= 0) { + if (selectedReceiver.clusterNuclei[inputIx] is Neuron selectedNeuron) + selectedNeuron.ProcessStimulusDirect(inputValue); + } + // Replace the receiver // Find the thingId current associated with the receiver int keyToRemove = thingReceivers.FirstOrDefault(r => r.Value.Equals(selectedReceiver)).Key; diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 56cb636..ef62a43 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -629,6 +629,7 @@ public class ClusterInspector : Editor { this.currentNucleus.name = newName; this.prefab.RefreshOutputs(); outputsField.choices = this.prefab.outputs.Select(output => output.name).ToList(); + anythingChanged = true; } if (Application.isPlaying) { @@ -767,8 +768,8 @@ public class ClusterInspector : Editor { } EditorGUILayout.Space(); - anythingChanged = ConnectNucleus(this.prefab, this.currentNucleus); - anythingChanged = AddSynapse(this.prefab, this.currentNucleus); + anythingChanged |= ConnectNucleus(this.prefab, this.currentNucleus); + anythingChanged |= AddSynapse(this.prefab, this.currentNucleus); } EditorGUILayout.EndFoldoutHeaderGroup(); } From ccb7a41577e32631b14b270e5d54426e86db7406 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 5 Mar 2026 16:04:28 +0100 Subject: [PATCH 176/179] Cleanup --- Cluster.cs | 9 -- ClusterPrefab.cs | 1 - ClusterReceptor.cs | 80 ------------- IReceptor.cs | 7 +- MemoryCell.cs | 2 - Neuron.cs | 14 --- Nucleus.cs | 22 ---- Perceptoid.cs | 105 ----------------- Perceptoid.cs.meta | 2 - Receptor.cs | 17 --- ReceptorArray.cs | 263 ------------------------------------------ ReceptorArray.cs.meta | 2 - 12 files changed, 2 insertions(+), 522 deletions(-) delete mode 100644 Perceptoid.cs delete mode 100644 Perceptoid.cs.meta delete mode 100644 ReceptorArray.cs delete mode 100644 ReceptorArray.cs.meta diff --git a/Cluster.cs b/Cluster.cs index c9842dd..f8491ee 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using UnityEngine; using Unity.Mathematics; using static Unity.Mathematics.math; @@ -48,7 +47,6 @@ public class Cluster : Nucleus { Nucleus[] prefabNuclei = this.prefab.nuclei.ToArray(); // first clone the nuclei without their connections foreach (Nucleus nucleus in this.prefab.nuclei) { - // Debug.Log($"prefab clone {nucleus.name}"); nucleus.ShallowCloneTo(this); } Nucleus[] clonedNuclei = this.clusterNuclei.ToArray(); @@ -477,9 +475,6 @@ public class Cluster : Nucleus { Debug.Log($" {nucleus.name}[{nucleus.GetHashCode()}] = {neuron.outputValue}"); } - // this.outputValue = this.defaultOutput.outputValue; - // this.stale = 0; - // continue in parent this.parent?.UpdateFromNucleus(this); @@ -494,7 +489,6 @@ public class Cluster : Nucleus { if (synapse.nucleus is Neuron neuron) { if (lengthsq(neuron.outputValue) > 0) { sum += synapse.weight * neuron.outputValue; - //this.stale = 0; } } } @@ -502,9 +496,6 @@ public class Cluster : Nucleus { foreach (Nucleus nucleus in this.sortedNuclei) nucleus.UpdateStateIsolated(); - // this.outputValue = this.defaultOutput.outputValue; - // this.stale = 0; - UpdateNuclei(); } diff --git a/ClusterPrefab.cs b/ClusterPrefab.cs index 90db0db..3b27733 100644 --- a/ClusterPrefab.cs +++ b/ClusterPrefab.cs @@ -64,7 +64,6 @@ public class ClusterPrefab : ScriptableObject { HashSet visitedNuclei = new(); foreach (Nucleus output in this.outputs) MarkNuclei(visitedNuclei, output); - //MarkNuclei(visitedNuclei, this.output); //Debug.Log($"Garbage collection found {visitedNuclei.Count} Nuclei"); this.nuclei.RemoveAll(nucleus => visitedNuclei.Contains(nucleus) == false); } diff --git a/ClusterReceptor.cs b/ClusterReceptor.cs index ba444c0..384c72e 100644 --- a/ClusterReceptor.cs +++ b/ClusterReceptor.cs @@ -26,12 +26,7 @@ public class ClusterReceptor : Cluster, IReceptor { public override Nucleus ShallowCloneTo(Cluster parent) { ClusterReceptor clone = new(this.prefab, parent, this.name) { clusterPrefab = this.clusterPrefab, - //array = this.array }; - //CloneFields(clone); - // This cloned the prefab with the clusternuclei, - // but did not clone the receivers outside the cluster - //RestoreExternalReceivers(clone, this.clusterPrefab, parent); return clone; } @@ -41,16 +36,11 @@ public class ClusterReceptor : Cluster, IReceptor { array = this._array }; - //CloneFields(clone); foreach (Synapse synapse in this.synapses) { Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); clonedSynapse.weight = synapse.weight; } - // foreach (Nucleus receiver in this.receivers) { - // clone.AddReceiver(receiver); - // } - this._outputs = null; // Make sure the output are regenerated foreach (Neuron output in this.outputs) { int ix = GetNucleusIndex(this.clusterNuclei, output); @@ -89,19 +79,14 @@ public class ClusterReceptor : Cluster, IReceptor { [SerializeReference] private NucleusArray _array; public NucleusArray array { - //get { return _array; } set { _array = value; } } - //[SerializeReference] - //private Nucleus[] _nucleusArray; public Nucleus[] nucleiArray { get { return _array.nuclei; } set { _array.nuclei = value; } } - //public ClusterReceptor[] nucleiArray; - public void AddReceptorElement(ClusterPrefab prefab) { IReceptorHelpers.AddReceptorElement(this, prefab); } @@ -118,32 +103,14 @@ public class ClusterReceptor : Cluster, IReceptor { // Clusters don't do anything, // The nuclei in them do the work // and should be called directly, not from the cluster - - // float3 sum = this.bias; - - // foreach (Nucleus nucleus in this.sortedNuclei) - // nucleus.UpdateStateIsolated(); - - // this.outputValue = this.defaultOutput.outputValue; - // this.stale = 0; - - // UpdateNuclei(); } public override void UpdateNuclei() { - // this.stale++; - // if (this.stale > staleValueForSleep && lengthsq(this.bias) > 0) { - // this.bias = new float3(0, 0, 0); - // this.parent.UpdateFromNucleus(this); - // } - foreach (Nucleus nucleus in this.clusterNuclei) nucleus.UpdateNuclei(); } public override void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) { - //this._array ??= new NucleusArray(this.parent); - //this._array.ProcessStimulus(thingId, inputValue, thingName); Debug.LogError("Process Stimulus was called on clusterreceptor without a neuron specified"); } @@ -152,9 +119,6 @@ public class ClusterReceptor : Cluster, IReceptor { public virtual void ProcessStimulus(Neuron input, Vector3 inputValue, int thingId = 0, string thingName = null) { CleanupReceivers(); - // Debug.Log($"{input.name} is {inputValue}, 1/{inputValue} = {1 / inputValue.x}, {1/inputValue.y}, {1/inputValue.z}"); - //inputValue = input.Activator(inputValue); - if (!thingReceivers.TryGetValue(thingId, out ClusterReceptor selectedReceiver)) selectedReceiver = FindReceiver2(thingId, inputValue, input); if (selectedReceiver == null) @@ -174,52 +138,8 @@ public class ClusterReceptor : Cluster, IReceptor { if (selectedReceiver.clusterNuclei[inputIx] is Neuron selectedNeuron) selectedNeuron.ProcessStimulusDirect(inputValue); - // Debug.Log($"cluster output = {selectedReceiver.defaultOutput.outputValue}"); } - // private ClusterReceptor FindReceiver(int thingId, float3 inputValue) { - // // No existing nucleus for this thing - // float inputMagnitude = length(inputValue); - // ClusterReceptor selectedReceiver = null; - // float selectedMagnitude = 0; - // foreach (ClusterReceptor receiver in nucleiArray.Cast()) { - // if (thingReceivers.ContainsValue(receiver) == false) { - // // We found an unusued receiver - // thingReceivers.Add(thingId, receiver); - // return receiver; - // } - // else if (receiver.isSleeping) { - // // A sleeping receiver is not active and can therefore always be used - // thingReceivers.Add(thingId, receiver); - // return receiver; - // } - // else if (selectedReceiver == null) { - // // If we haven't found a receiver yet, just start by taking the first - // selectedReceiver = receiver; - // selectedMagnitude = length(selectedReceiver.outputValue); - // } - // // Look for the receiver with the lowest magnitude - // else { - // float magnitude = length(receiver.outputValue); - - // if (magnitude < inputMagnitude && length(receiver.outputValue) < selectedMagnitude) { - // selectedReceiver = receiver; - // selectedMagnitude = length(selectedReceiver.outputValue); - // } - // } - // } - // if (selectedReceiver != null) { - // // Replace the receiver - // // Find the thingId current associated with the receiver - // int keyToRemove = thingReceivers.FirstOrDefault(r => r.Value.Equals(selectedReceiver)).Key; - // if (keyToRemove != 0 || thingReceivers.ContainsKey(keyToRemove)) - // thingReceivers.Remove(keyToRemove); - // // And add the new association - // thingReceivers.Add(thingId, selectedReceiver); - // } - // return selectedReceiver; - // } - private ClusterReceptor FindReceiver2(int thingId, float3 inputValue, Neuron input) { // No existing nucleus for this thing ClusterReceptor selectedReceiver = null; diff --git a/IReceptor.cs b/IReceptor.cs index 5dee615..b56a360 100644 --- a/IReceptor.cs +++ b/IReceptor.cs @@ -3,9 +3,6 @@ using UnityEngine; public interface IReceptor { public string GetName(); - // public NucleusArray array { - // get; set; - // } public Nucleus[] nucleiArray { get; set; } public void AddReceptorElement(ClusterPrefab prefab); @@ -54,8 +51,8 @@ public static class IReceptorHelpers { newArray[i] = receptor.nucleiArray[i]; // Delete the last perception if (receptor.nucleiArray[newLength] is Nucleus nucleus) - Neuron.Delete(nucleus); //this._nuclei[newLength]); - + Neuron.Delete(nucleus); + foreach (Nucleus element in receptor.nucleiArray) { if (element is IReceptor receptorElement) { receptorElement.nucleiArray = newArray; diff --git a/MemoryCell.cs b/MemoryCell.cs index e531922..7b7b8e5 100644 --- a/MemoryCell.cs +++ b/MemoryCell.cs @@ -1,7 +1,5 @@ using System; -using UnityEngine; using Unity.Mathematics; -using static Unity.Mathematics.math; [Serializable] public class MemoryCell : Neuron { diff --git a/Neuron.cs b/Neuron.cs index 57abcac..f4fe981 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using UnityEngine; using UnityEditor; using Unity.Mathematics; @@ -303,18 +302,8 @@ public class Neuron : Nucleus { } public virtual void AddReceiver(Nucleus receiverToAdd, float weight = 1) { - // if (this is IReceptor receptor) { - // foreach (Nucleus element in receptor.array.nuclei) { - // if (element is Neuron neuron) { - // neuron._receivers.Add(receiverToAdd); - // receiverToAdd.AddSynapse(element, weight); - // } - // } - // } - // else { this._receivers.Add(receiverToAdd); receiverToAdd.AddSynapse(this, weight); - // } } public virtual void RemoveReceiver(Nucleus receiverToRemove) { @@ -341,9 +330,6 @@ public class Neuron : Nucleus { } else ProcessStimulusDirect(inputValue, thingId, thingName); - // this.stale = 0; - // this.bias = inputValue; - // this.parent.UpdateFromNucleus(this); } public void ProcessStimulusDirect(Vector3 inputValue, int thingId = 0, string thingName = null) { diff --git a/Nucleus.cs b/Nucleus.cs index f3045c4..0c83cca 100644 --- a/Nucleus.cs +++ b/Nucleus.cs @@ -1,8 +1,6 @@ using System; using System.Collections.Generic; using UnityEngine; -using Unity.Mathematics; -using static Unity.Mathematics.math; [Serializable] public abstract class Nucleus { @@ -13,22 +11,6 @@ public abstract class Nucleus { [SerializeReference] public Cluster parent; - // protected float3 _outputValue; - // public virtual float3 outputValue { - // get { return _outputValue; } - // set { - // _outputValue = value; - // if (this.isFiring) - // WhenFiring?.Invoke(); - // } - // } - // public bool isFiring => length(_outputValue) > 0.5f; - // public Action WhenFiring; - - // public virtual bool isSleeping => lengthsq(this.outputValue) == 0; - // [NonSerialized] - // public int stale = 1000; - // public readonly int staleValueForSleep = 20; public bool trace = false; public abstract Nucleus ShallowCloneTo(Cluster parent); @@ -38,11 +20,8 @@ public abstract class Nucleus { None, Neuron, MemoryCell, - Selector, Cluster, - Pulsar, Receptor, - // ReceptorArray, ClusterReceptor, } @@ -81,7 +60,6 @@ public abstract class Nucleus { } public virtual void SetBias(Vector3 inputValue) { - //this.stale = 0; this.bias = inputValue; this.parent.UpdateFromNucleus(this); } diff --git a/Perceptoid.cs b/Perceptoid.cs deleted file mode 100644 index 447a3d7..0000000 --- a/Perceptoid.cs +++ /dev/null @@ -1,105 +0,0 @@ -/* -using UnityEngine; - -[System.Serializable] -public class Perceptoid : Neuroid { - // A neuroid which has no neurons as input - // But receives value from a receptor - - public NanoBrain brain; - public Receptor receptor; - public string baseName; - - public int thingId; - - //[SerializeField] - // Needs serialization!!!! - [SerializeReference] - public PercepteiArray array; - - #region Serialization - - [SerializeField] - public int thingType; - - public override void Rebuild(NanoBrain brain) { - base.Rebuild(brain); - this.receptor = Receptor.GetReceptor(brain, thingType); - this.receptor.perceptei.Add(this); - if (string.IsNullOrEmpty(this.baseName)) - this.baseName = this.name; - } - - public override void Deserialize(Nucleus nucleus) { - base.Deserialize(nucleus); - - if (nucleus is Perceptoid perceptoid) - this.receptor.thingType = perceptoid.thingType; - - // Point all receivers to this perceptoid instead of the default nucleus - foreach (INucleus receiver in nucleus.receivers) { - foreach (Synapse synapse in receiver.synapses) { - if (synapse.nucleus == nucleus) - synapse.nucleus = this; - } - } - // Point all synapses to this perceptoid instead of the default nucleus - // foreach (Synapse synapse in nucleus.synapses) { - // foreach (INucleus r in synapse.nucleus.receivers) { - // if (r == nucleus) - // this.receiver = this; - // } - // } - // Copying disabled for now - // // Copy all the synapses - // this.synapses = nucleus.synapses; - // // Copy all receivers - // this.receivers = nucleus.receivers; - } - - #endregion Serialization - - public Perceptoid(NanoBrain brain, int thingType, string name = "sensor") : base(name) { - this.brain = brain; - this.cluster = brain.cluster; - if (this.cluster != null) { - brain.perceptei.Add(this); - } - else - Debug.LogError("No neuroid network"); - - this.nucleusType = nameof(Perceptoid); - this.name = name; - this.baseName = name; - this.thingType = thingType; - this.receptor = Receptor.GetReceptor(brain, thingType); - this.receptor.perceptei.Add(this); - this.array = new PercepteiArray(this); - } - - public Perceptoid(PercepteiArray array) : base(array.name) { - this.array = array; - Perceptoid source = array.perceptei[0]; - this.brain = source.brain; - this.cluster = source.cluster; - if (this.brain != null) { - this.brain.perceptei.Add(this); - } - else - Debug.LogError("No neuroid network"); - - this.nucleusType = nameof(Perceptoid); - this.name = source.baseName; - this.baseName = source.baseName; - this.thingType = source.thingType; - this.receptor = Receptor.GetReceptor(this.brain, this.thingType); - this.receptor.perceptei.Add(this); - } - - public override void UpdateState() { - Vector3 result = this.receptor.localPosition; - UpdateResult(result); - } - -} -*/ \ No newline at end of file diff --git a/Perceptoid.cs.meta b/Perceptoid.cs.meta deleted file mode 100644 index ebac122..0000000 --- a/Perceptoid.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 702f634001a21a9d7ae1057c8ce356e9 \ No newline at end of file diff --git a/Receptor.cs b/Receptor.cs index 48ecb5a..a102835 100644 --- a/Receptor.cs +++ b/Receptor.cs @@ -48,36 +48,19 @@ public class Receptor : Neuron, IReceptor { } public void AddReceptorElement(ClusterPrefab prefab) { - //this.nucleiArray = IReceptorHelpers.AddReceptorElement(this.nucleiArray, prefab); IReceptorHelpers.AddReceptorElement(this, prefab); } public void RemoveReceptorElement() { - // this.nucleiArray = IReceptorHelpers.RemoveReceptorElement(this.nucleiArray); IReceptorHelpers.RemoveReceptorElement(this); } - // public override void AddReceiver(Nucleus receiverToAdd, float weight = 1) { - // foreach (Nucleus element in receptorToAdd.nucleiArray) { - // if (element is Neuron neuron) { - // neuron._receivers.Add(receiverToAdd); - // receiverToAdd.AddSynapse(element, weight); - // } - // } - - // } public virtual void AddArrayReceiver(Nucleus receiverToAdd, float weight = 1) { IReceptorHelpers.AddArrayReceiver(this, receiverToAdd, weight); - // foreach (Nucleus element in this._array.nuclei) { - // if (element is Neuron neuron) { - // neuron.AddReceiver(receiverToAdd, weight); - // } - // } } public override void UpdateStateIsolated() { this.outputValue = this.bias; - //Debug.Log($"Receptor {this.name} outputvalue = {this.outputValue}"); } public override void UpdateNuclei() { diff --git a/ReceptorArray.cs b/ReceptorArray.cs deleted file mode 100644 index 00c8bbb..0000000 --- a/ReceptorArray.cs +++ /dev/null @@ -1,263 +0,0 @@ -/* -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using Unity.Mathematics; -using static Unity.Mathematics.math; - -[Serializable] -public class ReceptorInstance : Nucleus { - public ReceptorInstance(Cluster parent, string name) { - this.parent = parent; - this.name = name; - // We explicitly do not add this to the parent, as it is serialized in the ReceptorArray - } - public ReceptorInstance(ClusterPrefab prefab, string name) { - this.clusterPrefab = prefab; - this.name = name; - // We explicitly do not add this to the prefab, as it is serialized in the ReceptorArray - } - public override Nucleus ShallowCloneTo(Cluster parent) { - ReceptorInstance clone = new(parent, name + " +1") { - receptor = this.receptor - }; - return clone; - } - public override Nucleus Clone(ClusterPrefab prefab) { - ReceptorInstance clone = new(prefab, name) { - receptor = this.receptor - }; - return clone; - } - - [SerializeReference] - public ReceptorArray receptor; - - public override void UpdateStateIsolated() { - } -} - -[Serializable] -public class ReceptorArray : Nucleus { - public ReceptorArray(Cluster parent, string name) { - this.parent = parent; - this.name = name; - this._instances = new ReceptorInstance[1]; - this._instances[0] = new ReceptorInstance(parent, this.name + "[0]") { - receptor = this - }; - this.parent?.clusterNuclei.Add(this); - } - public ReceptorArray(ClusterPrefab prefab, string name) { - this.clusterPrefab = prefab; - this.name = name; - this._instances = new ReceptorInstance[1]; - this._instances[0] = new ReceptorInstance(prefab, this.name + "[0]") { - receptor = this - }; - if (this.clusterPrefab != null) - this.clusterPrefab.nuclei.Add(this); - else - Debug.LogError("No prefab when adding receptor to prefab"); - - } - - public override Nucleus ShallowCloneTo(Cluster parent) { - ReceptorArray clone = new(parent, name) { - _instances = new ReceptorInstance[this.instances.Length] - }; - for (int ix = 0; ix < this.instances.Length; ix++) { - clone._instances[ix] = new ReceptorInstance(parent, $"{this.name} [{ix}]") { - receptor = clone - }; - } - - return clone; - } - - public override Nucleus Clone(ClusterPrefab prefab) { - ReceptorArray clone = new(prefab, this.name) { - _instances = new ReceptorInstance[this.instances.Length] - }; - for (int ix = 0; ix < this.instances.Length; ix++) { - clone._instances[ix] = new ReceptorInstance(prefab, this.name) { - receptor = this - }; - } - - foreach (Synapse synapse in this.synapses) { - Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); - clonedSynapse.weight = synapse.weight; - } - // foreach (Nucleus receiver in this.receivers) { - // clone.AddReceiver(receiver); - // } - return clone; - } - - [SerializeReference] - private ReceptorInstance[] _instances = new ReceptorInstance[0]; - public ReceptorInstance[] instances { - get { - return _instances; - } - } - - public void AddReceptor(ClusterPrefab prefab) { - if (this._instances.Length == 0) { - Debug.LogError("Empty receptor array, cannot add"); - return; - } - int newLength = this._instances.Length + 1; - ReceptorInstance[] newArray = new ReceptorInstance[newLength]; - - for (int i = 0; i < this._instances.Length; i++) - newArray[i] = this._instances[i]; - ReceptorInstance newReceptor = (ReceptorInstance)this._instances[0].Clone(prefab); - newReceptor.name = $"{this.name} [{this._instances.Length}]"; - newArray[newLength - 1] = newReceptor; - - this._instances = newArray; - } - - public void RemoveReceptor() { - int newLength = this._instances.Length - 1; - if (newLength == 0) { - Debug.LogWarning("Receptor array cannot be empty"); - return; - } - ReceptorInstance[] newPerceptei = new ReceptorInstance[newLength]; - for (int i = 0; i < newLength; i++) - newPerceptei[i] = this._instances[i]; - // Delete the last perception - if (this._instances[newLength] is Nucleus nucleus) - Neuron.Delete(nucleus); //this._nuclei[newLength]); - - this._instances = newPerceptei; - } - - private Dictionary thingReceivers = new(); - - // public override void ProcessStimulus(int thingId, Vector3 inputValue, string thingName = null) { - // ProcessStimulus(inputValue, thingId, thingName); - // } - public override void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) { - CleanupReceivers(); - if (!thingReceivers.TryGetValue(thingId, out Nucleus selectedReceiver)) { - //Debug.Log($" no receiver found for {thingId}"); - // No existing nucleus for this thing - selectedReceiver = SelectReceptor(thingId, inputValue); - } - if (selectedReceiver == null) - return; - - if (thingName != null) { - string baseName = selectedReceiver.name; - int colonPos = selectedReceiver.name.IndexOf(":"); - if (colonPos > 0) - baseName = selectedReceiver.name[..colonPos]; - selectedReceiver.name = baseName + ": " + thingName; - } - - //if (selectedReceiver is Neuron selectedNucleus) { - selectedReceiver.stale = 0; - selectedReceiver.outputValue = inputValue; - this.parent.UpdateFromNucleus(this); - //selectedNucleus.ProcessStimulus(inputValue); - //} - } - - private void CleanupReceivers() { - // Remove a thing-receiver connection when the nucleus is inactive - List receiversToRemove = new(); - thingReceivers ??= new(); - - foreach (KeyValuePair item in thingReceivers) { - if (item.Value.isSleeping) - receiversToRemove.Add(item.Key); - } - foreach (int thingId in receiversToRemove) { - Nucleus selectedReceiver = thingReceivers[thingId]; - - // Debug.Log($" removed receiver for {thingId}"); - thingReceivers.Remove(thingId); - - int colonPos = selectedReceiver.name.IndexOf(":"); - if (colonPos > 0) - selectedReceiver.name = selectedReceiver.name[..colonPos]; - } - - } - - private Nucleus SelectReceptor(int thingId, float3 inputValue) { - // No existing nucleus for this thing - float inputMagnitude = length(inputValue); - Nucleus selectedReceiver = null; - float selectedMagnitude = 0; - this._instances ??= new ReceptorInstance[0]; - foreach (Nucleus receiver in this._instances) { - if (thingReceivers.ContainsValue(receiver) == false) { - // We found an unusued receiver - // Debug.Log($"{thingId} -> [{receiver.name}]"); - thingReceivers.Add(thingId, receiver); - return receiver; - } - else if (receiver.isSleeping) { - // A sleeping receiver is not active and can therefore always be used - thingReceivers.Add(thingId, receiver); - Debug.Log($"{thingId} -> [{selectedReceiver.name}]"); - return receiver; - } - else if (selectedReceiver == null) { - // If we haven't found a receiver yet, just start by taking the first - selectedReceiver = receiver; - selectedMagnitude = length(selectedReceiver.outputValue); - } - // Look for the receiver with the lowest magnitude - else { - float magnitude = length(receiver.outputValue); - - if (magnitude < inputMagnitude && length(receiver.outputValue) < selectedMagnitude) { - selectedReceiver = receiver; - selectedMagnitude = length(selectedReceiver.outputValue); - } - } - } - if (selectedReceiver != null) { - // Replace the receiver - // Find the thingId current associated with the receiver - int keyToRemove = thingReceivers.FirstOrDefault(r => r.Value.Equals(selectedReceiver)).Key; - if (keyToRemove != 0 || thingReceivers.ContainsKey(keyToRemove)) - thingReceivers.Remove(keyToRemove); - // And add the new association - thingReceivers.Add(thingId, selectedReceiver); - } - return selectedReceiver; - } - - public override void UpdateStateIsolated() { - float3 sum = this.bias; - - // Receptors do not have inputs, so we ignore the synapses - foreach (Nucleus nucleus in this._instances) - sum += nucleus.outputValue; - - this.outputValue = sum / _instances.Length; - this.stale = 0; - - UpdateNuclei(); - } - - public override void UpdateNuclei() { - foreach (Nucleus nucleus in this.instances) { - nucleus.stale++; - if (nucleus.stale > staleValueForSleep && lengthsq(nucleus.outputValue) > 0) { - nucleus.outputValue = Vector3.zero; - //this.UpdateStateIsolated(); - this.parent.UpdateFromNucleus(this); - } - } - } -} -*/ \ No newline at end of file diff --git a/ReceptorArray.cs.meta b/ReceptorArray.cs.meta deleted file mode 100644 index 4a0e23a..0000000 --- a/ReceptorArray.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 9e915c8563642f23891b20522b3589cf \ No newline at end of file From 28ef70c773a1e70090a3dbea9bda1f24d5ce8c88 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 5 Mar 2026 17:04:17 +0100 Subject: [PATCH 177/179] synapses connect to neurons --- Cluster.cs | 37 +++++++++--------- ClusterPrefab.cs | 4 +- ClusterReceptor.cs | 2 +- Editor/ClusterInspector.cs | 80 ++++++++++++++++++++------------------ NanoBrain.cs | 2 +- Neuron.cs | 36 +++++++---------- Nucleus.cs | 6 +-- Synapse.cs | 6 +-- 8 files changed, 86 insertions(+), 87 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index f8491ee..56a12a0 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -75,7 +75,7 @@ public class Cluster : Nucleus { float weight = 1; foreach (Synapse synapse in receiver.synapses) { // Find the weight for this synapse - if (synapse.nucleus == prefabNucleus) { + if (synapse.neuron == prefabNucleus) { weight = synapse.weight; break; } @@ -184,7 +184,7 @@ public class Cluster : Nucleus { Cluster clone = new(this.prefab, parent); foreach (Synapse synapse in this.synapses) { - Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); + Synapse clonedSynapse = clone.AddSynapse(synapse.neuron); clonedSynapse.weight = synapse.weight; } @@ -238,7 +238,7 @@ public class Cluster : Nucleus { float weight = 1; foreach (Synapse synapse in receiver.synapses) { // Find the weight for this synapse - if (synapse.nucleus == sourceNucleus) { + if (synapse.neuron == sourceNucleus) { weight = synapse.weight; break; } @@ -434,10 +434,10 @@ public class Cluster : Nucleus { } } - [Obsolete("Use GetNucleus instead")] - public IReceptor GetReceptor(string receptorName) { - return GetNucleus(receptorName) as IReceptor; - } + // [Obsolete("Use GetNucleus instead")] + // public IReceptor GetReceptor(string receptorName) { + // return GetNucleus(receptorName) as IReceptor; + // } #region Receivers @@ -482,21 +482,20 @@ public class Cluster : Nucleus { } public override void UpdateStateIsolated() { - float3 sum = this.bias; + throw new Exception("Cluster should not be updated!"); + // float3 sum = this.bias; - //Applying the weight factors - foreach (Synapse synapse in this.synapses) { - if (synapse.nucleus is Neuron neuron) { - if (lengthsq(neuron.outputValue) > 0) { - sum += synapse.weight * neuron.outputValue; - } - } - } + // //Applying the weight factors + // foreach (Synapse synapse in this.synapses) { + // if (lengthsq(synapse.neuron.outputValue) > 0) { + // sum += synapse.weight * synapse.neuron.outputValue; + // } + // } - foreach (Nucleus nucleus in this.sortedNuclei) - nucleus.UpdateStateIsolated(); + // foreach (Nucleus nucleus in this.sortedNuclei) + // nucleus.UpdateStateIsolated(); - UpdateNuclei(); + // UpdateNuclei(); } public override void UpdateNuclei() { diff --git a/ClusterPrefab.cs b/ClusterPrefab.cs index 3b27733..760e8bb 100644 --- a/ClusterPrefab.cs +++ b/ClusterPrefab.cs @@ -79,9 +79,9 @@ public class ClusterPrefab : ScriptableObject { if (nucleus.synapses != null) { HashSet visitedSynapses = new(); foreach (Synapse synapse in nucleus.synapses) { - if (synapse != null && synapse.nucleus != null) { + if (synapse != null && synapse.neuron != null) { visitedSynapses.Add(synapse); - if (synapse.nucleus is Nucleus synapse_nucleus) + if (synapse.neuron is Nucleus synapse_nucleus) MarkNuclei(visitedNuclei, synapse_nucleus); } } diff --git a/ClusterReceptor.cs b/ClusterReceptor.cs index 384c72e..ac65e7a 100644 --- a/ClusterReceptor.cs +++ b/ClusterReceptor.cs @@ -37,7 +37,7 @@ public class ClusterReceptor : Cluster, IReceptor { }; foreach (Synapse synapse in this.synapses) { - Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); + Synapse clonedSynapse = clone.AddSynapse(synapse.neuron); clonedSynapse.weight = synapse.weight; } diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index ef62a43..c4af8d6 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -215,7 +215,7 @@ public class ClusterInspector : Editor { if (selectedNucleus.synapses != null) { foreach (Synapse synapse in selectedNucleus.synapses) { - Nucleus input = synapse.nucleus; + Nucleus input = synapse.neuron; AddToLayer(currentLayer, input); // Debug.Log($"layer {layerIx} nucleus {input.name}"); } @@ -391,17 +391,20 @@ public class ClusterInspector : Editor { int neuronCount = 0; List drawnArrays = new(); foreach (Synapse synapse in nucleus.synapses) { - if (synapse.nucleus is Receptor receptor) { + if (synapse.neuron == null) + continue; + + if (synapse.neuron is Receptor receptor) { if (drawnArrays.Contains(receptor.nucleiArray)) continue; drawnArrays.Add(receptor.nucleiArray); } - else if (synapse.nucleus.parent is ClusterReceptor clusterReceptor) { + else if (synapse.neuron.parent is ClusterReceptor clusterReceptor) { if (drawnArrays.Contains(clusterReceptor.nucleiArray)) continue; drawnArrays.Add(clusterReceptor.nucleiArray); } - if (synapse.nucleus is Neuron synapseNeuron) { + if (synapse.neuron is Neuron synapseNeuron) { float value = length(synapseNeuron.outputValue) * synapse.weight; // Debug.Log($"{synapse.nucleus.name}: {value} {length(synapse.nucleus.outputValue)} {synapse.weight}"); if (value > maxValue) @@ -417,12 +420,15 @@ public class ClusterInspector : Editor { int row = 0; drawnArrays = new(); foreach (Synapse synapse in nucleus.synapses) { - if (synapse.nucleus is Receptor neuron) { + if (synapse.neuron is null) + continue; + + if (synapse.neuron is Receptor neuron) { if (drawnArrays.Contains(neuron.nucleiArray)) continue; drawnArrays.Add(neuron.nucleiArray); } - else if (synapse.nucleus.parent is ClusterReceptor clusterReceptor) { + else if (synapse.neuron.parent is ClusterReceptor clusterReceptor) { if (drawnArrays.Contains(clusterReceptor.nucleiArray)) continue; drawnArrays.Add(clusterReceptor.nucleiArray); @@ -435,19 +441,19 @@ public class ClusterInspector : Editor { if (maxValue == 0 || !float.IsFinite(maxValue)) maxValue = 1; float brightness = 0; - if (synapse.nucleus is Neuron synapseNeuron) + if (synapse.neuron is Neuron synapseNeuron) brightness = length(synapseNeuron.outputValue * synapse.weight) / maxValue; color = new Color(brightness, brightness, brightness, 1f); } - if (synapse.nucleus.parent != null && synapse.nucleus.parent != this.currentNucleus.parent) { + if (synapse.neuron.parent != null && synapse.neuron.parent != this.currentNucleus.parent) { // the synapse nucleus is part of a subcluster - DrawNucleus(synapse.nucleus.parent, pos, maxValue, size, color); + DrawNucleus(synapse.neuron.parent, pos, maxValue, size, color); } // else if (synapse.nucleus.cluster != null && synapse.nucleus.cluster != this.currentNucleus.cluster) { // DrawNucleus(synapse.nucleus.parent, pos, maxValue, size, color); // } else { - DrawNucleus(synapse.nucleus, pos, maxValue, size, color); + DrawNucleus(synapse.neuron, pos, maxValue, size, color); } row++; } @@ -685,12 +691,12 @@ public class ClusterInspector : Editor { if (this.currentNucleus.synapses.Count > 0) { Synapse[] synapses = this.currentNucleus.synapses.ToArray(); foreach (Synapse synapse in synapses) { - if (synapse.nucleus == null) + if (synapse.neuron == null) continue; if (array != null) { - if (synapse.nucleus.parent is Cluster iCluster && elementIx > 0) { - int thisElementIx = Cluster.GetNucleusIndex(iCluster.clusterNuclei, synapse.nucleus); + if (synapse.neuron.parent is Cluster iCluster && elementIx > 0) { + int thisElementIx = Cluster.GetNucleusIndex(iCluster.clusterNuclei, synapse.neuron); if (thisElementIx == elementIx) continue; else @@ -698,14 +704,14 @@ public class ClusterInspector : Editor { } // if (array.Contains(synapse.nucleus)) // continue; - else if (array.Contains(synapse.nucleus.parent)) + else if (array.Contains(synapse.neuron.parent)) continue; } else { - if (synapse.nucleus.parent is IReceptor iReceptor) { + if (synapse.neuron.parent is IReceptor iReceptor) { array = iReceptor.nucleiArray; if (iReceptor is Cluster iCluster) - elementIx = Cluster.GetNucleusIndex(iCluster.clusterNuclei, synapse.nucleus); + elementIx = Cluster.GetNucleusIndex(iCluster.clusterNuclei, synapse.neuron); } // else if (synapse.nucleus is Receptor receptor2) // && receptor2.array != null && receptor2.array.nuclei.Length > 1) // array = receptor2.nucleiArray; @@ -714,34 +720,34 @@ public class ClusterInspector : Editor { EditorGUILayout.Space(); if (Application.isPlaying) { - if (synapse.nucleus is Neuron synapseNeuron) { + if (synapse.neuron is Neuron synapseNeuron) { Vector3 value = synapseNeuron.outputValue * synapse.weight; - GUIContent synapseValueLabel = new(synapse.nucleus.name, synapseNeuron.outputValue.ToString()); + GUIContent synapseValueLabel = new(synapse.neuron.name, synapseNeuron.outputValue.ToString()); EditorGUILayout.FloatField(synapseValueLabel, length(synapseNeuron.outputValue)); } } else { EditorGUILayout.BeginHorizontal(); - if (synapse.nucleus.parent != null && synapse.nucleus.parent != this.currentNucleus) { + if (synapse.neuron.parent != null && synapse.neuron.parent != this.currentNucleus) { // If it is a cluster GUIStyle labelStyle = new(GUI.skin.label); float labelWidth = 200; - if (synapse.nucleus.clusterPrefab != null) { - labelWidth = labelStyle.CalcSize(new GUIContent($"{synapse.nucleus.parent.baseName}.")).x; - GUILayout.Label($"{synapse.nucleus.parent.baseName}", GUILayout.Width(labelWidth)); + if (synapse.neuron.clusterPrefab != null) { + labelWidth = labelStyle.CalcSize(new GUIContent($"{synapse.neuron.parent.baseName}.")).x; + GUILayout.Label($"{synapse.neuron.parent.baseName}", GUILayout.Width(labelWidth)); } - string[] options = synapse.nucleus.parent.clusterNuclei.Select(n => n.name).ToArray(); - int selectedIndex = System.Array.IndexOf(options, synapse.nucleus.name); + string[] options = synapse.neuron.parent.clusterNuclei.Select(n => n.name).ToArray(); + int selectedIndex = System.Array.IndexOf(options, synapse.neuron.name); int newIndex = EditorGUILayout.Popup(selectedIndex, options); - if (newIndex != selectedIndex && synapse.nucleus.parent.clusterNuclei[newIndex] is Neuron newNeuron) + if (newIndex != selectedIndex && synapse.neuron.parent.clusterNuclei[newIndex] is Neuron newNeuron) ChangeSynapse(synapse, newNeuron); } else - GUILayout.Label(synapse.nucleus.name); + GUILayout.Label(synapse.neuron.name); bool disconnecting = GUILayout.Button("Disconnect", GUILayout.Width(80)); - if (disconnecting && synapse.nucleus is Neuron synapseNeuron) { + if (disconnecting && synapse.neuron is Neuron synapseNeuron) { synapseNeuron.RemoveReceiver(this.currentNucleus); this.prefab.GarbageCollection(); anythingChanged = true; @@ -753,10 +759,10 @@ public class ClusterInspector : Editor { EditorGUI.indentLevel++; float newWeight = EditorGUILayout.FloatField("Weight", synapse.weight); if (newWeight != synapse.weight) { - if (synapse.nucleus.parent is IReceptor receptor) { + if (synapse.neuron.parent is IReceptor receptor) { Nucleus[] receptorArray = receptor.nucleiArray; foreach (Synapse s in this.currentNucleus.synapses) { - if (s.nucleus.parent is IReceptor r && r.nucleiArray == receptorArray) + if (s.neuron.parent is IReceptor r && r.nucleiArray == receptorArray) s.weight = newWeight; } } @@ -949,8 +955,8 @@ public class ClusterInspector : Editor { return false; IEnumerable synapseNuclei = this.currentNucleus.synapses - .Where(synapse => synapse.nucleus != null) - .Select(synapse => synapse.nucleus); + .Where(synapse => synapse.neuron != null) + .Select(synapse => synapse.neuron); IEnumerable nuclei = cluster.nuclei .Except(synapseNuclei); @@ -1027,12 +1033,12 @@ public class ClusterInspector : Editor { } protected virtual void ChangeSynapse(Synapse synapse, Neuron newNucleus) { - Neuron synapseNeuron = synapse.nucleus as Neuron; - if (synapse.nucleus.parent is Cluster subCluster && subCluster.prefab != this.prefab) { - if (synapse.nucleus.parent is ClusterReceptor receptor) { + Neuron synapseNeuron = synapse.neuron as Neuron; + if (synapse.neuron.parent is Cluster subCluster && subCluster.prefab != this.prefab) { + if (synapse.neuron.parent is ClusterReceptor receptor) { // the new nucleus is part of a (cluster) receptor, // so we have to change all synapses to this nucleus array elements - int oldNucleusIx = Cluster.GetNucleusIndex(subCluster.clusterNuclei, synapse.nucleus); + int oldNucleusIx = Cluster.GetNucleusIndex(subCluster.clusterNuclei, synapse.neuron); int newNucleusIx = Cluster.GetNucleusIndex(subCluster.clusterNuclei, newNucleus); foreach (Nucleus element in receptor.nucleiArray) { if (element is not ClusterReceptor clusterReceptor) @@ -1070,12 +1076,12 @@ public class ClusterInspector : Editor { protected virtual void DisconnectNucleus(Neuron nucleus) { if (this.currentNucleus.clusterPrefab == null) return; - string[] names = this.currentNucleus.synapses.Select(synapse => synapse.nucleus.name).ToArray(); + string[] names = this.currentNucleus.synapses.Select(synapse => synapse.neuron.name).ToArray(); int selectedIndex = -1; selectedIndex = EditorGUILayout.Popup("Disconnect from", selectedIndex, names); if (selectedIndex >= 0 && selectedIndex < this.currentNucleus.clusterPrefab.nuclei.Count) { Synapse synapse = this.currentNucleus.synapses[selectedIndex]; - Neuron synapseNeuron = synapse.nucleus as Neuron; + Neuron synapseNeuron = synapse.neuron as Neuron; synapseNeuron.RemoveReceiver(this.currentNucleus); } } diff --git a/NanoBrain.cs b/NanoBrain.cs index 831b9db..5a7525e 100644 --- a/NanoBrain.cs +++ b/NanoBrain.cs @@ -20,7 +20,7 @@ public class NanoBrain : MonoBehaviour { public static void UpdateWeight(Cluster brain, string name, float weight) { Nucleus root = brain.defaultOutput; foreach (Synapse synapse in root.synapses) { - if (synapse.nucleus.name == name) { + if (synapse.neuron.name == name) { if (synapse.weight != weight) { synapse.weight = weight; // Debug.Log($"Updated weight for {name}"); diff --git a/Neuron.cs b/Neuron.cs index f4fe981..05982de 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -144,7 +144,7 @@ public class Neuron : Nucleus { Neuron clone = new(prefab, this.name); CloneFields(clone); foreach (Synapse synapse in this.synapses) { - Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); + Synapse clonedSynapse = clone.AddSynapse(synapse.neuron); clonedSynapse.weight = synapse.weight; } foreach (Nucleus receiver in this.receivers) { @@ -164,7 +164,7 @@ public class Neuron : Nucleus { public static void Delete(Nucleus nucleus) { foreach (Synapse synapse in nucleus.synapses) { - if (synapse.nucleus is Neuron synapse_nucleus) { + if (synapse.neuron is Neuron synapse_nucleus) { if (synapse_nucleus.receivers.Count > 1) { // there is another nucleus feeding into this input nucleus synapse_nucleus.receivers.RemoveAll(r => r == nucleus); @@ -178,14 +178,14 @@ public class Neuron : Nucleus { if (nucleus is Neuron neuron) { foreach (Nucleus receiver in neuron.receivers) { if (receiver != null && receiver.synapses != null) - receiver.synapses.RemoveAll(s => s.nucleus == nucleus); + receiver.synapses.RemoveAll(s => s.neuron == nucleus); } } else if (nucleus is Cluster cluster) { // remove all receivers for this cluster foreach (Neuron output in cluster.outputs) { foreach (Nucleus receiver in output.receivers) { - receiver.synapses.RemoveAll(s => s.nucleus == output); + receiver.synapses.RemoveAll(s => s.neuron == output); } } } @@ -214,18 +214,15 @@ public class Neuron : Nucleus { public float3 CombinatorSum() { float3 sum = this.bias; - foreach (Synapse synapse in this.synapses) { - if (synapse.nucleus is Neuron neuron) - sum += synapse.weight * neuron.outputValue; - } + foreach (Synapse synapse in this.synapses) + sum += synapse.weight * synapse.neuron.outputValue; return sum; } public float3 CombinatorProduct() { float3 product = this.bias; foreach (Synapse synapse in this.synapses) { - if (synapse.nucleus is Neuron neuron) - product *= synapse.weight * neuron.outputValue; + product *= synapse.weight * synapse.neuron.outputValue; } return product; } @@ -236,14 +233,12 @@ public class Neuron : Nucleus { //Applying the weight factors foreach (Synapse synapse in this.synapses) { - if (synapse.nucleus is Neuron neuron) { - float3 input = synapse.weight * neuron.outputValue; + float3 input = synapse.weight * synapse.neuron.outputValue; - float inputLength = length(input); - if (inputLength > maxLength) { - max = input; - maxLength = inputLength; - } + float inputLength = length(input); + if (inputLength > maxLength) { + max = input; + maxLength = inputLength; } } return max; @@ -311,13 +306,13 @@ public class Neuron : Nucleus { foreach (Nucleus element in receptor.nucleiArray) { if (element is Neuron neuron) { neuron._receivers.RemoveAll(receiver => receiver == receiverToRemove); - receiverToRemove.synapses.RemoveAll(synapse => synapse.nucleus == neuron); + receiverToRemove.synapses.RemoveAll(synapse => synapse.neuron == neuron); } } } else { this._receivers.RemoveAll(receiver => receiver == receiverToRemove); - receiverToRemove.synapses.RemoveAll(synapse => synapse.nucleus == this); + receiverToRemove.synapses.RemoveAll(synapse => synapse.neuron == this); } } @@ -325,9 +320,8 @@ public class Neuron : Nucleus { #endregion Receivers public override void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) { - if (this.parent is ClusterReceptor clusterReceptor) { + if (this.parent is ClusterReceptor clusterReceptor) clusterReceptor.ProcessStimulus(this, inputValue, thingId, thingName); - } else ProcessStimulusDirect(inputValue, thingId, thingName); } diff --git a/Nucleus.cs b/Nucleus.cs index 0c83cca..2b1f5da 100644 --- a/Nucleus.cs +++ b/Nucleus.cs @@ -33,7 +33,7 @@ public abstract class Nucleus { private List _synapses = new(); public List synapses => _synapses; - public Synapse AddSynapse(Nucleus sendingNucleus, float weight = 1.0f) { + public Synapse AddSynapse(Neuron sendingNucleus, float weight = 1.0f) { Synapse synapse = new(sendingNucleus, weight); this.synapses.Add(synapse); return synapse; @@ -41,13 +41,13 @@ public abstract class Nucleus { public Synapse GetSynapse(Nucleus sender) { foreach (Synapse synapse in this.synapses) - if (synapse.nucleus == sender) + if (synapse.neuron == sender) return synapse; return null; } public void RemoveSynapse(Nucleus sendingNucleus) { - this.synapses.RemoveAll(synapse => synapse.nucleus == sendingNucleus); + this.synapses.RemoveAll(synapse => synapse.neuron == sendingNucleus); } #endregion Synapses diff --git a/Synapse.cs b/Synapse.cs index 53a7a51..424b7e6 100644 --- a/Synapse.cs +++ b/Synapse.cs @@ -4,12 +4,12 @@ using UnityEngine; [Serializable] public class Synapse { [SerializeReference] - public Nucleus nucleus; + public Neuron neuron; public float weight; - public Synapse(Nucleus nucleus, float weight = 1.0f) { - this.nucleus = nucleus; + public Synapse(Neuron nucleus, float weight = 1.0f) { + this.neuron = nucleus; this.weight = weight; } } \ No newline at end of file From 4805e81f0900329051aa3655ed18bc3144536cf6 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 5 Mar 2026 17:17:38 +0100 Subject: [PATCH 178/179] synapse weight change updates nanobrain --- Editor/ClusterInspector.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index c4af8d6..5aeb9c9 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -768,6 +768,7 @@ public class ClusterInspector : Editor { } else synapse.weight = newWeight; + anythingChanged = true; } EditorGUI.indentLevel--; } From b3423b99a752cdabbc4e7c51565fb54425481feb Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Fri, 6 Mar 2026 17:03:41 +0100 Subject: [PATCH 179/179] AnimatedWalkingAnt --- Cluster.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cluster.cs b/Cluster.cs index 56a12a0..996fb2c 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -462,7 +462,7 @@ public class Cluster : Nucleus { // no bias+synapse input state calculation for now... if (this.computeOrders.ContainsKey(startNucleus) == false) { - Debug.LogError($"{this.name} compute orders does not contain an order for {startNucleus.name}"); + //Debug.LogError($"{this.name} compute orders does not contain an order for {startNucleus.name}"); return; }