From 8d6b55f567067cc65ef12f0219a68a4b5133adbc Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Sat, 20 Apr 2024 19:23:02 +0100 Subject: [PATCH 001/205] Update animal-ai-unity.sln --- animal-ai-unity.sln | 8 -------- 1 file changed, 8 deletions(-) diff --git a/animal-ai-unity.sln b/animal-ai-unity.sln index 4c2200b9..1d06ca09 100644 --- a/animal-ai-unity.sln +++ b/animal-ai-unity.sln @@ -10,24 +10,16 @@ EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {c5669da5-14ae-7753-4f48-16c137875402}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {c5669da5-14ae-7753-4f48-16c137875402}.Debug|Any CPU.Build.0 = Debug|Any CPU - {c5669da5-14ae-7753-4f48-16c137875402}.Release|Any CPU.ActiveCfg = Release|Any CPU # Add this line - {c5669da5-14ae-7753-4f48-16c137875402}.Release|Any CPU.Build.0 = Release|Any CPU # Add this line {17f1d71b-73ce-7c86-c9e3-fbf811561d56}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {17f1d71b-73ce-7c86-c9e3-fbf811561d56}.Debug|Any CPU.Build.0 = Debug|Any CPU - {17f1d71b-73ce-7c86-c9e3-fbf811561d56}.Release|Any CPU.ActiveCfg = Release|Any CPU # Add this line - {17f1d71b-73ce-7c86-c9e3-fbf811561d56}.Release|Any CPU.Build.0 = Release|Any CPU # Add this line {bf9f0105-b32c-3a54-e123-7859aaf8d854}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {bf9f0105-b32c-3a54-e123-7859aaf8d854}.Debug|Any CPU.Build.0 = Debug|Any CPU - {bf9f0105-b32c-3a54-e123-7859aaf8d854}.Release|Any CPU.ActiveCfg = Release|Any CPU # Add this line - {bf9f0105-b32c-3a54-e123-7859aaf8d854}.Release|Any CPU.Build.0 = Release|Any CPU # Add this line EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal - From f9b661a1347a625da53d3486f5ffc67029232c84 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Sat, 20 Apr 2024 19:23:04 +0100 Subject: [PATCH 002/205] Update Assembly-CSharp.csproj --- Assembly-CSharp.csproj | 773 +++++++++++++++++++++-------------------- 1 file changed, 387 insertions(+), 386 deletions(-) diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index 4db33470..140e9356 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -22,7 +22,7 @@ full false Temp\bin\Debug\ - DEBUG;TRACE;UNITY_2021_3_21;UNITY_2021_3;UNITY_2021;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;PLATFORM_ARCH_64;UNITY_64;UNITY_INCLUDE_TESTS;ENABLE_AR;ENABLE_AUDIO;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_MICROPHONE;ENABLE_MULTIPLE_DISPLAYS;ENABLE_PHYSICS;ENABLE_TEXTURE_STREAMING;ENABLE_VIRTUALTEXTURING;ENABLE_UNET;ENABLE_LZMA;ENABLE_UNITYEVENTS;ENABLE_VR;ENABLE_WEBCAM;ENABLE_UNITYWEBREQUEST;ENABLE_WWW;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_COLLAB;ENABLE_CLOUD_SERVICES_COLLAB_SOFTLOCKS;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_SERVICES_USE_WEBREQUEST;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_NATIVE_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_UNET;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_CLOUD_LICENSE;ENABLE_EDITOR_HUB_LICENSE;ENABLE_WEBSOCKET_CLIENT;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_VIDEO;ENABLE_ACCELERATOR_CLIENT_DEBUGGING;PLATFORM_STANDALONE;TEXTCORE_1_0_OR_NEWER;PLATFORM_STANDALONE_OSX;UNITY_STANDALONE_OSX;UNITY_STANDALONE;ENABLE_GAMECENTER;ENABLE_RUNTIME_GI;ENABLE_MOVIES;ENABLE_NETWORK;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_UNITY_GAME_SERVICES_ANALYTICS_SUPPORT;ENABLE_CLUSTER_SYNC;ENABLE_CLUSTERINPUT;ENABLE_SPATIALTRACKING;PLATFORM_UPDATES_TIME_OUTSIDE_OF_PLAYER_LOOP;ENABLE_WEBSOCKET_HOST;ENABLE_MONO;NET_4_6;NET_UNITY_4_8;ENABLE_PROFILER;UNITY_ASSERTIONS;UNITY_EDITOR;UNITY_EDITOR_64;UNITY_EDITOR_OSX;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_LEGACY_INPUT_MANAGER;TEXTCORE_FONT_ENGINE_1_5_OR_NEWER;CSHARP_7_OR_LATER;CSHARP_7_3_OR_NEWER + DEBUG;TRACE;UNITY_2021_3_21;UNITY_2021_3;UNITY_2021;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;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_UNET;ENABLE_LZMA;ENABLE_UNITYEVENTS;ENABLE_VR;ENABLE_WEBCAM;ENABLE_UNITYWEBREQUEST;ENABLE_WWW;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_COLLAB;ENABLE_CLOUD_SERVICES_COLLAB_SOFTLOCKS;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_SERVICES_USE_WEBREQUEST;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_UNET;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_CLOUD_LICENSE;ENABLE_EDITOR_HUB_LICENSE;ENABLE_WEBSOCKET_CLIENT;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_VIDEO;ENABLE_ACCELERATOR_CLIENT_DEBUGGING;PLATFORM_STANDALONE;TEXTCORE_1_0_OR_NEWER;PLATFORM_STANDALONE_WIN;UNITY_STANDALONE_WIN;UNITY_STANDALONE;ENABLE_RUNTIME_GI;ENABLE_MOVIES;ENABLE_NETWORK;ENABLE_NVIDIA;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_UNITY_GAME_SERVICES_ANALYTICS_SUPPORT;ENABLE_OUT_OF_PROCESS_CRASH_HANDLER;ENABLE_CLUSTER_SYNC;ENABLE_CLUSTERINPUT;PLATFORM_UPDATES_TIME_OUTSIDE_OF_PLAYER_LOOP;GFXDEVICE_WAITFOREVENT_MESSAGEPUMP;ENABLE_WEBSOCKET_HOST;ENABLE_MONO;NET_4_6;NET_UNITY_4_8;ENABLE_PROFILER;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_LEGACY_INPUT_MANAGER;TEXTCORE_FONT_ENGINE_1_5_OR_NEWER;CSHARP_7_OR_LATER;CSHARP_7_3_OR_NEWER prompt 4 0169 @@ -36,868 +36,869 @@ false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AIModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.AIModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ARModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.ARModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AccessibilityModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.AccessibilityModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AndroidJNIModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.AndroidJNIModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AnimationModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.AnimationModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AssetBundleModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.AssetBundleModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AudioModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.AudioModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ClothModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.ClothModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ClusterInputModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.ClusterInputModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ClusterRendererModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.ClusterRendererModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.CoreModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.CrashReportingModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.CrashReportingModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.DSPGraphModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.DSPGraphModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.DirectorModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.DirectorModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.GIModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.GIModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.GameCenterModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.GameCenterModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.GridModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.GridModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.HotReloadModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.HotReloadModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.IMGUIModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.IMGUIModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ImageConversionModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.ImageConversionModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.InputModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.InputModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.InputLegacyModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.InputLegacyModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.JSONSerializeModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.JSONSerializeModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.LocalizationModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.LocalizationModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ParticleSystemModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.ParticleSystemModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.PerformanceReportingModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.PerformanceReportingModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.PhysicsModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.PhysicsModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.Physics2DModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.Physics2DModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ProfilerModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.ProfilerModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.RuntimeInitializeOnLoadManagerInitializerModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.RuntimeInitializeOnLoadManagerInitializerModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ScreenCaptureModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.ScreenCaptureModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.SharedInternalsModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.SharedInternalsModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.SpriteMaskModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.SpriteMaskModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.SpriteShapeModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.SpriteShapeModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.StreamingModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.StreamingModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.SubstanceModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.SubstanceModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.SubsystemsModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.SubsystemsModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TLSModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.TLSModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TerrainModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.TerrainModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TerrainPhysicsModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.TerrainPhysicsModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TextCoreFontEngineModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.TextCoreFontEngineModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TextCoreTextEngineModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.TextCoreTextEngineModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TextRenderingModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.TextRenderingModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TilemapModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.TilemapModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UIModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.UIModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UIElementsModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.UIElementsModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UIElementsNativeModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.UIElementsNativeModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UNETModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.UNETModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UmbraModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.UmbraModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityAnalyticsModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.UnityAnalyticsModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityAnalyticsCommonModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.UnityAnalyticsCommonModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityConnectModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.UnityConnectModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityCurlModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.UnityCurlModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityTestProtocolModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.UnityTestProtocolModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityWebRequestModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityWebRequestAssetBundleModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestAssetBundleModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityWebRequestAudioModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestAudioModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityWebRequestTextureModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestTextureModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityWebRequestWWWModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestWWWModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.VFXModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.VFXModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.VRModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.VRModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.VehiclesModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.VehiclesModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.VideoModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.VideoModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.VirtualTexturingModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.VirtualTexturingModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.WindModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.WindModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.XRModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.XRModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEditor.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.CoreModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEditor.CoreModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.DeviceSimulatorModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEditor.DeviceSimulatorModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.DiagnosticsModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEditor.DiagnosticsModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.GraphViewModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEditor.GraphViewModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.PackageManagerUIModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEditor.PackageManagerUIModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.QuickSearchModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEditor.QuickSearchModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.SceneTemplateModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEditor.SceneTemplateModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.TextCoreFontEngineModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEditor.TextCoreFontEngineModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.TextCoreTextEngineModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEditor.TextCoreTextEngineModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.UIBuilderModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEditor.UIBuilderModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.UIElementsModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEditor.UIElementsModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.UIElementsSamplesModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEditor.UIElementsSamplesModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.UIServiceModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEditor.UIServiceModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.UnityConnectModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEditor.UnityConnectModule.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/PackageCache/com.unity.ml-agents@2.3.0-exp.3/Plugins/System.IO.Abstractions.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\PackageCache\com.unity.ml-agents@2.3.0-exp.3\Plugins\System.IO.Abstractions.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/PackageCache/com.unity.burst@1.8.2/Unity.Burst.CodeGen/Unity.Burst.Cecil.Mdb.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\PackageCache\com.unity.burst@1.8.2\Unity.Burst.CodeGen\Unity.Burst.Cecil.Mdb.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/PackageCache/com.unity.barracuda@3.0.0/Barracuda/Runtime/Plugins/ProtoBuffer/Google.Protobuf.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\PackageCache\com.unity.barracuda@3.0.0\Barracuda\Runtime\Plugins\ProtoBuffer\Google.Protobuf.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/PackageCache/com.unity.burst@1.8.2/Unity.Burst.CodeGen/Unity.Burst.Cecil.Pdb.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\PackageCache\com.unity.burst@1.8.2\Unity.Burst.CodeGen\Unity.Burst.Cecil.Pdb.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/PackageCache/com.unity.burst@1.8.2/Unity.Burst.CodeGen/Unity.Burst.Cecil.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\PackageCache\com.unity.burst@1.8.2\Unity.Burst.CodeGen\Unity.Burst.Cecil.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/PackageCache/com.unity.burst@1.8.2/Unity.Burst.CodeGen/Unity.Burst.Cecil.Rocks.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\PackageCache\com.unity.burst@1.8.2\Unity.Burst.CodeGen\Unity.Burst.Cecil.Rocks.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/PackageCache/com.unity.ml-agents@2.3.0-exp.3/Plugins/System.IO.Abstractions.TestingHelpers.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\PackageCache\com.unity.ml-agents@2.3.0-exp.3\Plugins\System.IO.Abstractions.TestingHelpers.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/PackageCache/com.unity.ml-agents@2.3.0-exp.3/Plugins/ProtoBuffer/System.Interactive.Async.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\PackageCache\com.unity.ml-agents@2.3.0-exp.3\Plugins\ProtoBuffer\System.Interactive.Async.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/PackageCache/com.unity.ml-agents@2.3.0-exp.3/Plugins/ProtoBuffer/Grpc.Core.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\PackageCache\com.unity.ml-agents@2.3.0-exp.3\Plugins\ProtoBuffer\Grpc.Core.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/mscorlib.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\mscorlib.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Core.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Core.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Runtime.Serialization.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Runtime.Serialization.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Xml.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Xml.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Xml.Linq.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Xml.Linq.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Numerics.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Numerics.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Numerics.Vectors.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Numerics.Vectors.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Net.Http.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Net.Http.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.IO.Compression.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.IO.Compression.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Microsoft.CSharp.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Microsoft.CSharp.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Data.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Data.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Data.DataSetExtensions.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Data.DataSetExtensions.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Drawing.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Drawing.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.IO.Compression.FileSystem.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.IO.Compression.FileSystem.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.ComponentModel.Composition.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.ComponentModel.Composition.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Transactions.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Transactions.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/Microsoft.Win32.Primitives.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\Microsoft.Win32.Primitives.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\netstandard.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.AppContext.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.AppContext.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Buffers.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Buffers.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.Concurrent.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Collections.Concurrent.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Collections.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.NonGeneric.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Collections.NonGeneric.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.Specialized.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Collections.Specialized.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.Annotations.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ComponentModel.Annotations.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ComponentModel.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.EventBasedAsync.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ComponentModel.EventBasedAsync.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.Primitives.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ComponentModel.Primitives.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.TypeConverter.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ComponentModel.TypeConverter.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Console.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Console.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Data.Common.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Data.Common.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Contracts.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.Contracts.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Debug.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.Debug.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.FileVersionInfo.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.FileVersionInfo.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Process.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.Process.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.StackTrace.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.StackTrace.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.TextWriterTraceListener.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.TextWriterTraceListener.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Tools.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.Tools.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.TraceSource.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.TraceSource.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Drawing.Primitives.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Drawing.Primitives.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Dynamic.Runtime.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Dynamic.Runtime.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Globalization.Calendars.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Globalization.Extensions.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Globalization.Calendars.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Globalization.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Globalization.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Globalization.Extensions.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.Compression.ZipFile.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.Compression.ZipFile.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.FileSystem.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.DriveInfo.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.FileSystem.DriveInfo.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.Primitives.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.FileSystem.Primitives.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.Watcher.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.FileSystem.Watcher.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.IsolatedStorage.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.IsolatedStorage.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.MemoryMappedFiles.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.MemoryMappedFiles.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.Pipes.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.Pipes.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.UnmanagedMemoryStream.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.UnmanagedMemoryStream.dll - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.dll + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Linq.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.Expressions.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Linq.Expressions.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.Parallel.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Linq.Parallel.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.Queryable.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Linq.Queryable.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Memory.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Memory.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Http.Rtc.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.Http.Rtc.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.NameResolution.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.NameResolution.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.NetworkInformation.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.NetworkInformation.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Ping.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.Ping.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Primitives.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.Primitives.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Requests.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.Requests.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Security.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.Security.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Sockets.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.Sockets.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.WebHeaderCollection.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.WebHeaderCollection.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.WebSockets.Client.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.WebSockets.Client.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.WebSockets.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.WebSockets.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ObjectModel.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ObjectModel.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.DispatchProxy.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.DispatchProxy.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.Emit.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Emit.ILGeneration.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.Emit.ILGeneration.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Emit.Lightweight.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Emit.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.Emit.Lightweight.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Extensions.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.Extensions.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Primitives.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.Primitives.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Resources.Reader.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Resources.Reader.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Resources.ResourceManager.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Resources.ResourceManager.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Resources.Writer.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Resources.Writer.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.CompilerServices.VisualC.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.CompilerServices.VisualC.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Extensions.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Extensions.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Handles.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Handles.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.InteropServices.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.InteropServices.RuntimeInformation.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.InteropServices.RuntimeInformation.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.InteropServices.WindowsRuntime.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.InteropServices.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.InteropServices.WindowsRuntime.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Numerics.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Numerics.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Formatters.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Serialization.Formatters.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Json.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Serialization.Json.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Primitives.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Serialization.Primitives.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Xml.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Serialization.Xml.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Claims.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Claims.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Algorithms.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Cryptography.Algorithms.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Csp.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Cryptography.Csp.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Encoding.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Cryptography.Encoding.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Primitives.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Cryptography.Primitives.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.X509Certificates.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Cryptography.X509Certificates.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Principal.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Principal.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.SecureString.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.SecureString.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Duplex.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ServiceModel.Duplex.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Http.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ServiceModel.Http.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.NetTcp.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ServiceModel.NetTcp.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Primitives.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ServiceModel.Primitives.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Security.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Text.Encoding.Extensions.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ServiceModel.Security.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Text.Encoding.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Text.Encoding.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Text.Encoding.Extensions.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Text.RegularExpressions.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Text.RegularExpressions.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Overlapped.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.Overlapped.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.Tasks.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Tasks.Extensions.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.Tasks.Extensions.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Tasks.Parallel.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Tasks.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.Tasks.Parallel.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Thread.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.Thread.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.ThreadPool.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.ThreadPool.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Timer.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.Timer.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ValueTuple.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ValueTuple.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.ReaderWriter.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Xml.ReaderWriter.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XDocument.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XPath.XDocument.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XPath.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Xml.XDocument.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XmlDocument.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Xml.XmlDocument.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XmlSerializer.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Xml.XmlSerializer.dll - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/netstandard.dll + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Xml.XPath.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Xml.XPath.XDocument.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/Unity.ML-Agents.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.ML-Agents.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/Unity.Barracuda.iOSBLAS.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.Barracuda.iOSBLAS.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/Unity.Barracuda.ONNX.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.Barracuda.ONNX.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/Unity.VSCode.Editor.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.VSCode.Editor.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/Unity.Barracuda.BurstBLAS.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.Barracuda.BurstBLAS.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/Unity.RenderPipelines.Universal.Shaders.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.RenderPipelines.Universal.Shaders.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/Unity.RenderPipelines.Universal.Runtime.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.RenderPipelines.Universal.Runtime.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/PPv2URPConverters.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\PPv2URPConverters.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/Unity.TextMeshPro.Editor.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.TextMeshPro.Editor.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/Unity.VisualStudio.Editor.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.VisualStudio.Editor.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/Unity.Barracuda.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.Barracuda.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/Unity.Sysroot.Linux_x86_64.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.Sysroot.Linux_x86_64.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/Unity.Timeline.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.Timeline.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/Unity.TextMeshPro.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.TextMeshPro.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/Unity.Burst.Editor.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.Burst.Editor.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/Unity.Searcher.Editor.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.Searcher.Editor.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/Unity.RenderPipelines.Core.Runtime.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.RenderPipelines.Core.Runtime.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/Unity.Toolchain.Linux-x86_64.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.Toolchain.Linux-x86_64.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/UnityEditor.UI.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\UnityEditor.UI.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/Unity.PlasticSCM.Editor.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.PlasticSCM.Editor.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/Unity.Rider.Editor.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.Rider.Editor.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/Unity.RenderPipelines.Core.ShaderLibrary.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.RenderPipelines.Core.ShaderLibrary.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/UnityEngine.UI.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\UnityEngine.UI.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/Unity.Mathematics.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.Mathematics.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/Unity.ML-Agents.CommunicatorObjects.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.ML-Agents.CommunicatorObjects.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/Unity.ShaderGraph.Editor.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.ShaderGraph.Editor.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/Unity.Burst.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.Burst.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/Unity.RenderPipelines.Universal.Editor.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.RenderPipelines.Universal.Editor.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/Unity.Toolchain.Win-x86_64-Linux-x86_64.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.Toolchain.Win-x86_64-Linux-x86_64.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/Unity.Timeline.Editor.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.Timeline.Editor.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/Unity.RenderPipeline.Universal.ShaderLibrary.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.RenderPipeline.Universal.ShaderLibrary.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/Unity.Mathematics.Editor.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.Mathematics.Editor.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/Unity.Barracuda.Editor.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.Barracuda.Editor.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/Unity.RenderPipelines.Core.Editor.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.RenderPipelines.Core.Editor.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/Unity.Barracuda.MacBLAS.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.Barracuda.MacBLAS.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/Unity.ML-Agents.Editor.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.ML-Agents.Editor.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/Unity.SysrootPackage.Editor.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.SysrootPackage.Editor.dll From 9e3d6262028db7fbda91c2c0850d0d19ebff403c Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Sat, 20 Apr 2024 19:24:32 +0100 Subject: [PATCH 003/205] added code to save to csv file its foundational right now and saves per step information on agent. it needs to be able to save the .csv file outside of the root directory (currently in unity folder so not ideal to user). Next step would be to save to desktop or better still to save the .csv in a specified location in the yaml file as a new syntax. --- Assets/Scripts/TrainingAgent.cs | 819 ++++++++++++++++---------------- 1 file changed, 421 insertions(+), 398 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 8fb4304f..eb7065c1 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -8,6 +8,7 @@ using PrefabInterface; using Unity.MLAgents.Sensors; using YAMLDefs; +using System.IO; /// /// The TrainingAgent class is a subclass of the Agent class in the ML-Agents library. @@ -16,403 +17,425 @@ /// public class TrainingAgent : Agent, IPrefab { - [Header("Agent Settings")] - public float speed = 25f; - public float quickStopRatio = 0.9f; - public float rotationSpeed = 100f; - public float rotationAngle = 0.25f; - - [Header("Agent State / Other Variables")] - [HideInInspector] - public int numberOfGoalsCollected = 0; - - [HideInInspector] - public ProgressBar progBar; - private Rigidbody _rigidBody; - private bool _isGrounded; - private ContactPoint _lastContactPoint; - - [Header("Agent Rewards & Score")] - private float _rewardPerStep; - private float _previousScore = 0; - private float _currentScore = 0; - - [Header("Agent Health")] - public float health = 100f; - private float _maxHealth = 100f; - - [Header("Agent Freeze & Countdown")] - public float timeLimit = 0f; - private float _nextUpdateHealth = 0f; - private float _freezeDelay = 0f; - private bool _isFrozen = false; - - private bool _nextUpdateCompleteArena = false; - - [Header("Agent Notification")] - public bool showNotification = false; - private TrainingArena _arena; - private bool _isCountdownActive = false; - - public override void Initialize() - { - _arena = GetComponentInParent(); - _rigidBody = GetComponent(); - _rewardPerStep = timeLimit > 0 ? -1f / timeLimit : 0; - progBar = GameObject.Find("UI ProgressBar").GetComponent(); - progBar.AssignAgent(this); - health = _maxHealth; - } - - public float GetPreviousScore() - { - return _previousScore; - } - - #region Agent Freeze Methods + [Header("Agent Settings")] + public float speed = 25f; + public float quickStopRatio = 0.9f; + public float rotationSpeed = 100f; + public float rotationAngle = 0.25f; + + [Header("Agent State / Other Variables")] + [HideInInspector] + public int numberOfGoalsCollected = 0; + + [HideInInspector] + public ProgressBar progBar; + private Rigidbody _rigidBody; + private bool _isGrounded; + private ContactPoint _lastContactPoint; + + [Header("Agent Rewards & Score")] + private float _rewardPerStep; + private float _previousScore = 0; + private float _currentScore = 0; + + [Header("Agent Health")] + public float health = 100f; + private float _maxHealth = 100f; + + [Header("Agent Freeze & Countdown")] + public float timeLimit = 0f; + private float _nextUpdateHealth = 0f; + private float _freezeDelay = 0f; + private bool _isFrozen = false; + + private bool _nextUpdateCompleteArena = false; + + [Header("Agent Notification")] + public bool showNotification = false; + private TrainingArena _arena; + private bool _isCountdownActive = false; + + [Header("CSV Logging")] + public string csvFilePath = "Observations.csv"; + private bool headerWritten = false; - public float GetFreezeDelay() - { - return _freezeDelay; - } - - public void SetFreezeDelay(float v) - { - _freezeDelay = Mathf.Clamp(v, 0f, v); - if (v != 0f && !_isCountdownActive) - { - Debug.Log( - "Starting coroutine unfreezeCountdown() with wait seconds == " + GetFreezeDelay() - ); - StartCoroutine(unfreezeCountdown()); - } - } - - public bool IsFrozen() - { - return _freezeDelay > 0f || _isFrozen; - } - - public void FreezeAgent(bool freeze) - { - _isFrozen = freeze; - if (_isFrozen) - { - _rigidBody.velocity = Vector3.zero; - _rigidBody.angularVelocity = Vector3.zero; - } - } - - private IEnumerator unfreezeCountdown() - { - _isCountdownActive = true; - yield return new WaitForSeconds(GetFreezeDelay()); - - Debug.Log("unfreezing!"); - SetFreezeDelay(0f); - _isCountdownActive = false; - } - - #endregion - - #region Agent Core Methods - - public override void CollectObservations(VectorSensor sensor) - { - sensor.AddObservation(health); - Vector3 localVel = transform.InverseTransformDirection(_rigidBody.velocity); - sensor.AddObservation(localVel); - Vector3 localPos = transform.position; - sensor.AddObservation(localPos); - Debug.Log("Health:" + health + "\nVelocity: " + localVel + "\nPosition:" + localPos); - } - - public override void OnActionReceived(ActionBuffers action) - { - int actionForward = Mathf.FloorToInt(action.DiscreteActions[0]); - int actionRotate = Mathf.FloorToInt(action.DiscreteActions[1]); - if (!IsFrozen()) - { - MoveAgent(actionForward, actionRotate); - } - - UpdateHealth(_rewardPerStep); - } - - private void MoveAgent(int actionForward, int actionRotate) - { - if (IsFrozen()) - { - // If the agent is frozen, stop all movement and rotation - _rigidBody.velocity = Vector3.zero; - _rigidBody.angularVelocity = Vector3.zero; - return; - } - - Vector3 directionToGo = Vector3.zero; - Vector3 rotateDirection = Vector3.zero; - Vector3 quickStop = Vector3.zero; - - if (_isGrounded) - { - switch (actionForward) - { - case 1: - directionToGo = transform.forward * 1f; - break; - case 2: - directionToGo = transform.forward * -1f; - break; - case 0: // Slow down faster than drag with no input - quickStop = _rigidBody.velocity * quickStopRatio; - _rigidBody.velocity = quickStop; - break; - } - } - - switch (actionRotate) - { - case 1: - rotateDirection = transform.up * 1f; - break; - case 2: - rotateDirection = transform.up * -1f; - break; - } - - transform.Rotate(rotateDirection, Time.fixedDeltaTime * rotationSpeed); - _rigidBody.AddForce( - directionToGo.normalized * speed * 100f * Time.fixedDeltaTime, - ForceMode.Acceleration - ); - } - - public override void Heuristic(in ActionBuffers actionsOut) - { - var discreteActionsOut = actionsOut.DiscreteActions; - discreteActionsOut[0] = 0; - discreteActionsOut[1] = 0; - if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow)) - { - discreteActionsOut[0] = 1; - } - if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow)) - { - discreteActionsOut[0] = 2; - } - if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow)) - { - discreteActionsOut[1] = 1; - } - if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow)) - { - discreteActionsOut[1] = 2; - } - } - - #endregion - - #region Agent Health Methods - - public void UpdateHealthNextStep(float updateAmount, bool andCompleteArena = false) - { - /// - /// ML-Agents doesn't guarantee behaviour if an episode ends outside of OnActionReceived - /// Therefore we queue any health updates to happen on the next action step. - /// - _nextUpdateHealth += updateAmount; - if (andCompleteArena) - { - _nextUpdateCompleteArena = true; - } - } - - public void UpdateHealth(float updateAmount, bool andCompleteArena = false) - { - if (NotificationManager.Instance == null && showNotification == true) - { - Debug.LogError("NotificationManager instance is not set."); - return; - } - /// - /// Update the health of the agent and reset any queued updates - /// If health reaches 0 or the episode is queued to end then call EndEpisode(). - /// - if (!IsFrozen()) - { - health += 100 * updateAmount; - health += 100 * _nextUpdateHealth; - _nextUpdateHealth = 0; - AddReward(updateAmount); - } - _currentScore = GetCumulativeReward(); - if (health > _maxHealth) - { - health = _maxHealth; - } - else if (health <= 0) - { - health = 0; - if (showNotification) - { - NotificationManager.Instance.ShowFailureNotification(); - } - StartCoroutine(EndEpisodeAfterDelay()); - return; - } - if (andCompleteArena || _nextUpdateCompleteArena) - { - _nextUpdateCompleteArena = false; - float cumulativeReward = this.GetCumulativeReward(); - - if (cumulativeReward >= Arena.CurrentPassMark) - { - // If passed and the next arena is merged load that without ending the episode - if (_arena.mergeNextArena) - { - _arena.LoadNextArena(); - return; - } - if (showNotification) - { - NotificationManager.Instance.ShowSuccessNotification(); - } - } - else - { - if (showNotification) - { - NotificationManager.Instance.ShowFailureNotification(); - } - } - StartCoroutine(EndEpisodeAfterDelay()); - } - } - - public void AddExtraReward(float rewardFactor) - { - UpdateHealth(Math.Min(rewardFactor * _rewardPerStep, -0.001f)); - } - - #endregion - - #region Agent Episode Methods - - IEnumerator EndEpisodeAfterDelay() - { - if (!showNotification) - { - EndEpisode(); - yield break; - } - - yield return new WaitForSeconds(2.5f); - NotificationManager.Instance.HideNotification(); - EndEpisode(); - } - - public override void OnEpisodeBegin() - { - EpisodeDebugLog(); - - StopCoroutine("unfreezeCountdown"); - _previousScore = _currentScore; - numberOfGoalsCollected = 0; - _arena.ResetArena(); - _rewardPerStep = timeLimit > 0 ? -1f / timeLimit : 0; - _isGrounded = false; - health = _maxHealth; - - SetFreezeDelay(GetFreezeDelay()); - } - - private void EpisodeDebugLog() - { - Debug.Log("Episode Begin"); - Debug.Log($"Value of showNotification: {showNotification}"); - Debug.Log("Current Pass Mark: " + Arena.CurrentPassMark); - Debug.Log("Number of Goals Collected: " + numberOfGoalsCollected); - } - - #endregion - - #region Collision Detection Methods - - void OnCollisionEnter(Collision collision) - { - foreach (ContactPoint contact in collision.contacts) - { - if (contact.normal.y > 0) - { - _isGrounded = true; - } - } - _lastContactPoint = collision.contacts.Last(); - } - - void OnCollisionStay(Collision collision) - { - foreach (ContactPoint contact in collision.contacts) - { - if (contact.normal.y > 0) - { - _isGrounded = true; - } - } - _lastContactPoint = collision.contacts.Last(); - } - - void OnCollisionExit(Collision collision) - { - if (_lastContactPoint.normal.y > 0) - { - _isGrounded = false; - } - } - - #endregion - - #region Prefab Interface Methods - - //****************************** - //PREFAB INTERFACE FOR THE AGENT - //****************************** - public void SetColor(Vector3 color) { } - - public void SetSize(Vector3 scale) { } - - /// - /// Returns a random position within the range for the object. - /// - public virtual Vector3 GetPosition( - Vector3 position, - Vector3 boundingBox, - float rangeX, - float rangeZ - ) - { - float xBound = boundingBox.x; - float zBound = boundingBox.z; - float xOut = - position.x < 0 - ? Random.Range(xBound, rangeX - xBound) - : Math.Max(0, Math.Min(position.x, rangeX)); - float yOut = Math.Max(position.y, 0) + transform.localScale.y / 2 + 0.01f; - float zOut = - position.z < 0 - ? Random.Range(zBound, rangeZ - zBound) - : Math.Max(0, Math.Min(position.z, rangeZ)); - - return new Vector3(xOut, yOut, zOut); - } - - /// - /// If rotationY set to < 0 change to random rotation. - /// - public virtual Vector3 GetRotation(float rotationY) - { - return new Vector3(0, rotationY < 0 ? Random.Range(0f, 360f) : rotationY, 0); - } - - #endregion + public override void Initialize() + { + _arena = GetComponentInParent(); + _rigidBody = GetComponent(); + _rewardPerStep = timeLimit > 0 ? -1f / timeLimit : 0; + progBar = GameObject.Find("UI ProgressBar").GetComponent(); + progBar.AssignAgent(this); + health = _maxHealth; + + if (!File.Exists(csvFilePath)) + { + headerWritten = false; // If the file doesn't exist, we need to write the header + } + } + + public float GetPreviousScore() + { + return _previousScore; + } + + #region Agent Freeze Methods + + public float GetFreezeDelay() + { + return _freezeDelay; + } + + public void SetFreezeDelay(float v) + { + _freezeDelay = Mathf.Clamp(v, 0f, v); + if (v != 0f && !_isCountdownActive) + { + Debug.Log( + "Starting coroutine unfreezeCountdown() with wait seconds == " + GetFreezeDelay() + ); + StartCoroutine(unfreezeCountdown()); + } + } + + public bool IsFrozen() + { + return _freezeDelay > 0f || _isFrozen; + } + + public void FreezeAgent(bool freeze) + { + _isFrozen = freeze; + if (_isFrozen) + { + _rigidBody.velocity = Vector3.zero; + _rigidBody.angularVelocity = Vector3.zero; + } + } + + private IEnumerator unfreezeCountdown() + { + _isCountdownActive = true; + yield return new WaitForSeconds(GetFreezeDelay()); + + Debug.Log("unfreezing!"); + SetFreezeDelay(0f); + _isCountdownActive = false; + } + + #endregion + + #region Agent Core Methods + + public override void CollectObservations(VectorSensor sensor) + { + sensor.AddObservation(health); + Vector3 localVel = transform.InverseTransformDirection(_rigidBody.velocity); + sensor.AddObservation(localVel); + Vector3 localPos = transform.position; + sensor.AddObservation(localPos); + LogToCSV(localVel, localPos); + } + + private void LogToCSV(Vector3 velocity, Vector3 position) + { + using (StreamWriter sw = new StreamWriter(csvFilePath, true)) + { + if (!headerWritten) + { + sw.WriteLine("Step,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition"); + headerWritten = true; + } + sw.WriteLine($"{StepCount},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z}"); + } + } + + public override void OnActionReceived(ActionBuffers action) + { + int actionForward = Mathf.FloorToInt(action.DiscreteActions[0]); + int actionRotate = Mathf.FloorToInt(action.DiscreteActions[1]); + if (!IsFrozen()) + { + MoveAgent(actionForward, actionRotate); + } + + UpdateHealth(_rewardPerStep); + } + + private void MoveAgent(int actionForward, int actionRotate) + { + if (IsFrozen()) + { + // If the agent is frozen, stop all movement and rotation + _rigidBody.velocity = Vector3.zero; + _rigidBody.angularVelocity = Vector3.zero; + return; + } + + Vector3 directionToGo = Vector3.zero; + Vector3 rotateDirection = Vector3.zero; + Vector3 quickStop = Vector3.zero; + + if (_isGrounded) + { + switch (actionForward) + { + case 1: + directionToGo = transform.forward * 1f; + break; + case 2: + directionToGo = transform.forward * -1f; + break; + case 0: // Slow down faster than drag with no input + quickStop = _rigidBody.velocity * quickStopRatio; + _rigidBody.velocity = quickStop; + break; + } + } + + switch (actionRotate) + { + case 1: + rotateDirection = transform.up * 1f; + break; + case 2: + rotateDirection = transform.up * -1f; + break; + } + + transform.Rotate(rotateDirection, Time.fixedDeltaTime * rotationSpeed); + _rigidBody.AddForce( + directionToGo.normalized * speed * 100f * Time.fixedDeltaTime, + ForceMode.Acceleration + ); + } + + public override void Heuristic(in ActionBuffers actionsOut) + { + var discreteActionsOut = actionsOut.DiscreteActions; + discreteActionsOut[0] = 0; + discreteActionsOut[1] = 0; + if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow)) + { + discreteActionsOut[0] = 1; + } + if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow)) + { + discreteActionsOut[0] = 2; + } + if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow)) + { + discreteActionsOut[1] = 1; + } + if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow)) + { + discreteActionsOut[1] = 2; + } + } + + #endregion + + #region Agent Health Methods + + public void UpdateHealthNextStep(float updateAmount, bool andCompleteArena = false) + { + /// + /// ML-Agents doesn't guarantee behaviour if an episode ends outside of OnActionReceived + /// Therefore we queue any health updates to happen on the next action step. + /// + _nextUpdateHealth += updateAmount; + if (andCompleteArena) + { + _nextUpdateCompleteArena = true; + } + } + + public void UpdateHealth(float updateAmount, bool andCompleteArena = false) + { + if (NotificationManager.Instance == null && showNotification == true) + { + Debug.LogError("NotificationManager instance is not set."); + return; + } + /// + /// Update the health of the agent and reset any queued updates + /// If health reaches 0 or the episode is queued to end then call EndEpisode(). + /// + if (!IsFrozen()) + { + health += 100 * updateAmount; + health += 100 * _nextUpdateHealth; + _nextUpdateHealth = 0; + AddReward(updateAmount); + } + _currentScore = GetCumulativeReward(); + if (health > _maxHealth) + { + health = _maxHealth; + } + else if (health <= 0) + { + health = 0; + if (showNotification) + { + NotificationManager.Instance.ShowFailureNotification(); + } + StartCoroutine(EndEpisodeAfterDelay()); + return; + } + if (andCompleteArena || _nextUpdateCompleteArena) + { + _nextUpdateCompleteArena = false; + float cumulativeReward = this.GetCumulativeReward(); + + if (cumulativeReward >= Arena.CurrentPassMark) + { + // If passed and the next arena is merged load that without ending the episode + if (_arena.mergeNextArena) + { + _arena.LoadNextArena(); + return; + } + if (showNotification) + { + NotificationManager.Instance.ShowSuccessNotification(); + } + } + else + { + if (showNotification) + { + NotificationManager.Instance.ShowFailureNotification(); + } + } + StartCoroutine(EndEpisodeAfterDelay()); + } + } + + public void AddExtraReward(float rewardFactor) + { + UpdateHealth(Math.Min(rewardFactor * _rewardPerStep, -0.001f)); + } + + #endregion + + #region Agent Episode Methods + + IEnumerator EndEpisodeAfterDelay() + { + if (!showNotification) + { + EndEpisode(); + yield break; + } + + yield return new WaitForSeconds(2.5f); + NotificationManager.Instance.HideNotification(); + EndEpisode(); + } + + public override void OnEpisodeBegin() + { + EpisodeDebugLog(); + + StopCoroutine("unfreezeCountdown"); + _previousScore = _currentScore; + numberOfGoalsCollected = 0; + _arena.ResetArena(); + _rewardPerStep = timeLimit > 0 ? -1f / timeLimit : 0; + _isGrounded = false; + health = _maxHealth; + + SetFreezeDelay(GetFreezeDelay()); + } + + private void EpisodeDebugLog() + { + Debug.Log("Episode Begin"); + Debug.Log($"Value of showNotification: {showNotification}"); + Debug.Log("Current Pass Mark: " + Arena.CurrentPassMark); + Debug.Log("Number of Goals Collected: " + numberOfGoalsCollected); + } + + #endregion + + #region Collision Detection Methods + + void OnCollisionEnter(Collision collision) + { + foreach (ContactPoint contact in collision.contacts) + { + if (contact.normal.y > 0) + { + _isGrounded = true; + } + } + _lastContactPoint = collision.contacts.Last(); + } + + void OnCollisionStay(Collision collision) + { + foreach (ContactPoint contact in collision.contacts) + { + if (contact.normal.y > 0) + { + _isGrounded = true; + } + } + _lastContactPoint = collision.contacts.Last(); + } + + void OnCollisionExit(Collision collision) + { + if (_lastContactPoint.normal.y > 0) + { + _isGrounded = false; + } + } + + #endregion + + #region Prefab Interface Methods + + //****************************** + //PREFAB INTERFACE FOR THE AGENT + //****************************** + public void SetColor(Vector3 color) { } + + public void SetSize(Vector3 scale) { } + + /// + /// Returns a random position within the range for the object. + /// + public virtual Vector3 GetPosition( + Vector3 position, + Vector3 boundingBox, + float rangeX, + float rangeZ + ) + { + float xBound = boundingBox.x; + float zBound = boundingBox.z; + float xOut = + position.x < 0 + ? Random.Range(xBound, rangeX - xBound) + : Math.Max(0, Math.Min(position.x, rangeX)); + float yOut = Math.Max(position.y, 0) + transform.localScale.y / 2 + 0.01f; + float zOut = + position.z < 0 + ? Random.Range(zBound, rangeZ - zBound) + : Math.Max(0, Math.Min(position.z, rangeZ)); + + return new Vector3(xOut, yOut, zOut); + } + + /// + /// If rotationY set to < 0 change to random rotation. + /// + public virtual Vector3 GetRotation(float rotationY) + { + return new Vector3(0, rotationY < 0 ? Random.Range(0f, 360f) : rotationY, 0); + } + + #endregion } From caf944ad9c5e42bd73eeb0178690277f9a7c69f8 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 30 Apr 2024 12:49:34 +0100 Subject: [PATCH 004/205] re-added core unity files --- Assembly-CSharp.csproj | 1 - YamlDotNet.Examples.csproj | 509 +++++++++++++-------------- YamlDotNet.csproj | 696 ++++++++++++++++++------------------- 3 files changed, 604 insertions(+), 602 deletions(-) diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index 140e9356..768bff14 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -99,7 +99,6 @@ - diff --git a/YamlDotNet.Examples.csproj b/YamlDotNet.Examples.csproj index 6c6fe53d..8761ae84 100644 --- a/YamlDotNet.Examples.csproj +++ b/YamlDotNet.Examples.csproj @@ -22,7 +22,7 @@ full false Temp\bin\Debug\ - DEBUG;TRACE;UNITY_2021_3_21;UNITY_2021_3;UNITY_2021;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;PLATFORM_ARCH_64;UNITY_64;UNITY_INCLUDE_TESTS;ENABLE_AR;ENABLE_AUDIO;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_MICROPHONE;ENABLE_MULTIPLE_DISPLAYS;ENABLE_PHYSICS;ENABLE_TEXTURE_STREAMING;ENABLE_VIRTUALTEXTURING;ENABLE_UNET;ENABLE_LZMA;ENABLE_UNITYEVENTS;ENABLE_VR;ENABLE_WEBCAM;ENABLE_UNITYWEBREQUEST;ENABLE_WWW;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_COLLAB;ENABLE_CLOUD_SERVICES_COLLAB_SOFTLOCKS;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_SERVICES_USE_WEBREQUEST;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_NATIVE_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_UNET;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_CLOUD_LICENSE;ENABLE_EDITOR_HUB_LICENSE;ENABLE_WEBSOCKET_CLIENT;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_VIDEO;ENABLE_ACCELERATOR_CLIENT_DEBUGGING;PLATFORM_STANDALONE;TEXTCORE_1_0_OR_NEWER;PLATFORM_STANDALONE_OSX;UNITY_STANDALONE_OSX;UNITY_STANDALONE;ENABLE_GAMECENTER;ENABLE_RUNTIME_GI;ENABLE_MOVIES;ENABLE_NETWORK;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_UNITY_GAME_SERVICES_ANALYTICS_SUPPORT;ENABLE_CLUSTER_SYNC;ENABLE_CLUSTERINPUT;ENABLE_SPATIALTRACKING;PLATFORM_UPDATES_TIME_OUTSIDE_OF_PLAYER_LOOP;ENABLE_WEBSOCKET_HOST;ENABLE_MONO;NET_4_6;NET_UNITY_4_8;ENABLE_PROFILER;UNITY_ASSERTIONS;UNITY_EDITOR;UNITY_EDITOR_64;UNITY_EDITOR_OSX;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_LEGACY_INPUT_MANAGER;TEXTCORE_FONT_ENGINE_1_5_OR_NEWER;CSHARP_7_OR_LATER;CSHARP_7_3_OR_NEWER + DEBUG;TRACE;UNITY_2021_3_21;UNITY_2021_3;UNITY_2021;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;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_UNET;ENABLE_LZMA;ENABLE_UNITYEVENTS;ENABLE_VR;ENABLE_WEBCAM;ENABLE_UNITYWEBREQUEST;ENABLE_WWW;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_COLLAB;ENABLE_CLOUD_SERVICES_COLLAB_SOFTLOCKS;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_SERVICES_USE_WEBREQUEST;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_UNET;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_CLOUD_LICENSE;ENABLE_EDITOR_HUB_LICENSE;ENABLE_WEBSOCKET_CLIENT;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_VIDEO;ENABLE_ACCELERATOR_CLIENT_DEBUGGING;PLATFORM_STANDALONE;TEXTCORE_1_0_OR_NEWER;PLATFORM_STANDALONE_WIN;UNITY_STANDALONE_WIN;UNITY_STANDALONE;ENABLE_RUNTIME_GI;ENABLE_MOVIES;ENABLE_NETWORK;ENABLE_NVIDIA;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_UNITY_GAME_SERVICES_ANALYTICS_SUPPORT;ENABLE_OUT_OF_PROCESS_CRASH_HANDLER;ENABLE_CLUSTER_SYNC;ENABLE_CLUSTERINPUT;PLATFORM_UPDATES_TIME_OUTSIDE_OF_PLAYER_LOOP;GFXDEVICE_WAITFOREVENT_MESSAGEPUMP;ENABLE_WEBSOCKET_HOST;ENABLE_MONO;NET_4_6;NET_UNITY_4_8;ENABLE_PROFILER;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_LEGACY_INPUT_MANAGER;TEXTCORE_FONT_ENGINE_1_5_OR_NEWER;CSHARP_7_OR_LATER;CSHARP_7_3_OR_NEWER prompt 4 0169 @@ -36,653 +36,656 @@ false - - - - - - - - - + + + + + + + + + - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AIModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.AIModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ARModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.ARModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AccessibilityModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.AccessibilityModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AndroidJNIModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.AndroidJNIModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AnimationModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.AnimationModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AssetBundleModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.AssetBundleModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AudioModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.AudioModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ClothModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.ClothModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ClusterInputModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.ClusterInputModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ClusterRendererModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.ClusterRendererModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.CoreModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.CrashReportingModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.CrashReportingModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.DSPGraphModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.DSPGraphModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.DirectorModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.DirectorModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.GIModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.GIModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.GameCenterModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.GameCenterModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.GridModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.GridModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.HotReloadModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.HotReloadModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.IMGUIModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.IMGUIModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ImageConversionModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.ImageConversionModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.InputModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.InputModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.InputLegacyModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.InputLegacyModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.JSONSerializeModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.JSONSerializeModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.LocalizationModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.LocalizationModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ParticleSystemModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.ParticleSystemModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.PerformanceReportingModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.PerformanceReportingModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.PhysicsModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.PhysicsModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.Physics2DModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.Physics2DModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ProfilerModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.ProfilerModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.RuntimeInitializeOnLoadManagerInitializerModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.RuntimeInitializeOnLoadManagerInitializerModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ScreenCaptureModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.ScreenCaptureModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.SharedInternalsModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.SharedInternalsModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.SpriteMaskModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.SpriteMaskModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.SpriteShapeModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.SpriteShapeModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.StreamingModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.StreamingModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.SubstanceModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.SubstanceModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.SubsystemsModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.SubsystemsModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TLSModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.TLSModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TerrainModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.TerrainModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TerrainPhysicsModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.TerrainPhysicsModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TextCoreFontEngineModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.TextCoreFontEngineModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TextCoreTextEngineModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.TextCoreTextEngineModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TextRenderingModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.TextRenderingModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TilemapModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.TilemapModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UIModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.UIModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UIElementsModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.UIElementsModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UIElementsNativeModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.UIElementsNativeModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UNETModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.UNETModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UmbraModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.UmbraModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityAnalyticsModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.UnityAnalyticsModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityAnalyticsCommonModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.UnityAnalyticsCommonModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityConnectModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.UnityConnectModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityCurlModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.UnityCurlModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityTestProtocolModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.UnityTestProtocolModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityWebRequestModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityWebRequestAssetBundleModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestAssetBundleModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityWebRequestAudioModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestAudioModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityWebRequestTextureModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestTextureModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityWebRequestWWWModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestWWWModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.VFXModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.VFXModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.VRModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.VRModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.VehiclesModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.VehiclesModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.VideoModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.VideoModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.VirtualTexturingModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.VirtualTexturingModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.WindModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.WindModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.XRModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEngine.XRModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEditor.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.CoreModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEditor.CoreModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.DeviceSimulatorModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEditor.DeviceSimulatorModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.DiagnosticsModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEditor.DiagnosticsModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.GraphViewModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEditor.GraphViewModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.PackageManagerUIModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEditor.PackageManagerUIModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.QuickSearchModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEditor.QuickSearchModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.SceneTemplateModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEditor.SceneTemplateModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.TextCoreFontEngineModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEditor.TextCoreFontEngineModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.TextCoreTextEngineModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEditor.TextCoreTextEngineModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.UIBuilderModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEditor.UIBuilderModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.UIElementsModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEditor.UIElementsModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.UIElementsSamplesModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEditor.UIElementsSamplesModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.UIServiceModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEditor.UIServiceModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.UnityConnectModule.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEngine\UnityEditor.UnityConnectModule.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/Managed/UnityEditor.Graphs.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\Managed\UnityEditor.Graphs.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/PlaybackEngines/WebGLSupport/UnityEditor.WebGL.Extensions.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\PlaybackEngines\WebGLSupport\UnityEditor.WebGL.Extensions.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/PlaybackEngines/MacStandaloneSupport/UnityEditor.OSXStandalone.Extensions.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\PlaybackEngines\MacStandaloneSupport\UnityEditor.OSXStandalone.Extensions.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/PlaybackEngines/WindowsStandaloneSupport/UnityEditor.WindowsStandalone.Extensions.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\PlaybackEngines\WindowsStandaloneSupport\UnityEditor.WindowsStandalone.Extensions.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\PlaybackEngines\LinuxStandaloneSupport\UnityEditor.LinuxStandalone.Extensions.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/mscorlib.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\mscorlib.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Core.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Core.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Runtime.Serialization.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Runtime.Serialization.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Xml.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Xml.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Xml.Linq.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Xml.Linq.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Numerics.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Numerics.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Numerics.Vectors.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Numerics.Vectors.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Net.Http.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Net.Http.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.IO.Compression.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.IO.Compression.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Microsoft.CSharp.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Microsoft.CSharp.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Data.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Data.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Data.DataSetExtensions.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Data.DataSetExtensions.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Drawing.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Drawing.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.IO.Compression.FileSystem.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.IO.Compression.FileSystem.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.ComponentModel.Composition.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.ComponentModel.Composition.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Transactions.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Transactions.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/Microsoft.Win32.Primitives.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\Microsoft.Win32.Primitives.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\netstandard.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.AppContext.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.AppContext.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Buffers.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Buffers.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.Concurrent.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Collections.Concurrent.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Collections.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.NonGeneric.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Collections.NonGeneric.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.Specialized.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Collections.Specialized.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.Annotations.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ComponentModel.Annotations.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ComponentModel.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.EventBasedAsync.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ComponentModel.EventBasedAsync.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.Primitives.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ComponentModel.Primitives.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.TypeConverter.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ComponentModel.TypeConverter.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Console.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Console.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Data.Common.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Data.Common.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Contracts.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.Contracts.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Debug.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.Debug.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.FileVersionInfo.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.FileVersionInfo.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Process.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.Process.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.StackTrace.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.StackTrace.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.TextWriterTraceListener.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.TextWriterTraceListener.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Tools.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.Tools.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.TraceSource.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.TraceSource.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Drawing.Primitives.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Drawing.Primitives.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Dynamic.Runtime.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Dynamic.Runtime.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Globalization.Calendars.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Globalization.Extensions.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Globalization.Calendars.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Globalization.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Globalization.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Globalization.Extensions.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.Compression.ZipFile.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.Compression.ZipFile.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.FileSystem.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.DriveInfo.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.FileSystem.DriveInfo.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.Primitives.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.FileSystem.Primitives.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.Watcher.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.FileSystem.Watcher.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.IsolatedStorage.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.IsolatedStorage.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.MemoryMappedFiles.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.MemoryMappedFiles.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.Pipes.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.Pipes.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.UnmanagedMemoryStream.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.UnmanagedMemoryStream.dll - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.dll + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Linq.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.Expressions.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Linq.Expressions.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.Parallel.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Linq.Parallel.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.Queryable.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Linq.Queryable.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Memory.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Memory.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Http.Rtc.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.Http.Rtc.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.NameResolution.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.NameResolution.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.NetworkInformation.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.NetworkInformation.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Ping.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.Ping.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Primitives.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.Primitives.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Requests.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.Requests.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Security.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.Security.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Sockets.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.Sockets.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.WebHeaderCollection.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.WebHeaderCollection.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.WebSockets.Client.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.WebSockets.Client.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.WebSockets.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.WebSockets.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ObjectModel.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ObjectModel.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.DispatchProxy.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.DispatchProxy.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.Emit.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Emit.ILGeneration.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.Emit.ILGeneration.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Emit.Lightweight.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Emit.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.Emit.Lightweight.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Extensions.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.Extensions.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Primitives.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.Primitives.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Resources.Reader.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Resources.Reader.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Resources.ResourceManager.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Resources.ResourceManager.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Resources.Writer.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Resources.Writer.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.CompilerServices.VisualC.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.CompilerServices.VisualC.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Extensions.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Extensions.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Handles.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Handles.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.InteropServices.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.InteropServices.RuntimeInformation.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.InteropServices.RuntimeInformation.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.InteropServices.WindowsRuntime.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.InteropServices.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.InteropServices.WindowsRuntime.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Numerics.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Numerics.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Formatters.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Serialization.Formatters.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Json.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Serialization.Json.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Primitives.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Serialization.Primitives.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Xml.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Serialization.Xml.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Claims.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Claims.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Algorithms.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Cryptography.Algorithms.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Csp.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Cryptography.Csp.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Encoding.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Cryptography.Encoding.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Primitives.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Cryptography.Primitives.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.X509Certificates.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Cryptography.X509Certificates.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Principal.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Principal.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.SecureString.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.SecureString.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Duplex.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ServiceModel.Duplex.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Http.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ServiceModel.Http.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.NetTcp.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ServiceModel.NetTcp.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Primitives.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ServiceModel.Primitives.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Security.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Text.Encoding.Extensions.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ServiceModel.Security.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Text.Encoding.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Text.Encoding.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Text.Encoding.Extensions.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Text.RegularExpressions.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Text.RegularExpressions.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Overlapped.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.Overlapped.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.Tasks.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Tasks.Extensions.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.Tasks.Extensions.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Tasks.Parallel.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Tasks.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.Tasks.Parallel.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Thread.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.Thread.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.ThreadPool.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.ThreadPool.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Timer.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.Timer.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ValueTuple.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ValueTuple.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.ReaderWriter.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Xml.ReaderWriter.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XDocument.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XPath.XDocument.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XPath.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Xml.XDocument.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XmlDocument.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Xml.XmlDocument.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XmlSerializer.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Xml.XmlSerializer.dll - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/netstandard.dll + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Xml.XPath.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Xml.XPath.XDocument.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/UnityEditor.UI.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\UnityEditor.UI.dll - /Users/vanguard/Desktop/animal-ai-unity/Library/ScriptAssemblies/UnityEngine.UI.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\UnityEngine.UI.dll diff --git a/YamlDotNet.csproj b/YamlDotNet.csproj index ff7b1d2d..0950cedf 100644 --- a/YamlDotNet.csproj +++ b/YamlDotNet.csproj @@ -22,7 +22,7 @@ full false Temp\bin\Debug\ - DEBUG;TRACE;UNITY_2021_3_21;UNITY_2021_3;UNITY_2021;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;PLATFORM_ARCH_64;UNITY_64;UNITY_INCLUDE_TESTS;ENABLE_AR;ENABLE_AUDIO;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_MICROPHONE;ENABLE_MULTIPLE_DISPLAYS;ENABLE_PHYSICS;ENABLE_TEXTURE_STREAMING;ENABLE_VIRTUALTEXTURING;ENABLE_UNET;ENABLE_LZMA;ENABLE_UNITYEVENTS;ENABLE_VR;ENABLE_WEBCAM;ENABLE_UNITYWEBREQUEST;ENABLE_WWW;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_COLLAB;ENABLE_CLOUD_SERVICES_COLLAB_SOFTLOCKS;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_SERVICES_USE_WEBREQUEST;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_NATIVE_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_UNET;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_CLOUD_LICENSE;ENABLE_EDITOR_HUB_LICENSE;ENABLE_WEBSOCKET_CLIENT;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_VIDEO;ENABLE_ACCELERATOR_CLIENT_DEBUGGING;PLATFORM_STANDALONE;TEXTCORE_1_0_OR_NEWER;PLATFORM_STANDALONE_OSX;UNITY_STANDALONE_OSX;UNITY_STANDALONE;ENABLE_GAMECENTER;ENABLE_RUNTIME_GI;ENABLE_MOVIES;ENABLE_NETWORK;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_UNITY_GAME_SERVICES_ANALYTICS_SUPPORT;ENABLE_CLUSTER_SYNC;ENABLE_CLUSTERINPUT;ENABLE_SPATIALTRACKING;PLATFORM_UPDATES_TIME_OUTSIDE_OF_PLAYER_LOOP;ENABLE_WEBSOCKET_HOST;ENABLE_MONO;NET_4_6;NET_UNITY_4_8;ENABLE_PROFILER;UNITY_ASSERTIONS;UNITY_EDITOR;UNITY_EDITOR_64;UNITY_EDITOR_OSX;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_LEGACY_INPUT_MANAGER;TEXTCORE_FONT_ENGINE_1_5_OR_NEWER;CSHARP_7_OR_LATER;CSHARP_7_3_OR_NEWER + DEBUG;TRACE;UNITY_2021_3_21;UNITY_2021_3;UNITY_2021;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;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_UNET;ENABLE_LZMA;ENABLE_UNITYEVENTS;ENABLE_VR;ENABLE_WEBCAM;ENABLE_UNITYWEBREQUEST;ENABLE_WWW;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_COLLAB;ENABLE_CLOUD_SERVICES_COLLAB_SOFTLOCKS;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_SERVICES_USE_WEBREQUEST;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_UNET;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_CLOUD_LICENSE;ENABLE_EDITOR_HUB_LICENSE;ENABLE_WEBSOCKET_CLIENT;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_VIDEO;ENABLE_ACCELERATOR_CLIENT_DEBUGGING;PLATFORM_STANDALONE;TEXTCORE_1_0_OR_NEWER;PLATFORM_STANDALONE_WIN;UNITY_STANDALONE_WIN;UNITY_STANDALONE;ENABLE_RUNTIME_GI;ENABLE_MOVIES;ENABLE_NETWORK;ENABLE_NVIDIA;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_UNITY_GAME_SERVICES_ANALYTICS_SUPPORT;ENABLE_OUT_OF_PROCESS_CRASH_HANDLER;ENABLE_CLUSTER_SYNC;ENABLE_CLUSTERINPUT;PLATFORM_UPDATES_TIME_OUTSIDE_OF_PLAYER_LOOP;GFXDEVICE_WAITFOREVENT_MESSAGEPUMP;ENABLE_WEBSOCKET_HOST;ENABLE_MONO;NET_4_6;NET_UNITY_4_8;ENABLE_PROFILER;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_LEGACY_INPUT_MANAGER;TEXTCORE_FONT_ENGINE_1_5_OR_NEWER;CSHARP_7_OR_LATER;CSHARP_7_3_OR_NEWER prompt 4 0169 @@ -36,572 +36,572 @@ false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/mscorlib.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\mscorlib.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Core.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Core.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Runtime.Serialization.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Runtime.Serialization.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Xml.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Xml.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Xml.Linq.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Xml.Linq.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Numerics.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Numerics.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Numerics.Vectors.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Numerics.Vectors.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Net.Http.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Net.Http.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.IO.Compression.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.IO.Compression.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Microsoft.CSharp.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Microsoft.CSharp.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Data.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Data.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Data.DataSetExtensions.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Data.DataSetExtensions.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Drawing.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Drawing.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.IO.Compression.FileSystem.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.IO.Compression.FileSystem.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.ComponentModel.Composition.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.ComponentModel.Composition.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Transactions.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\System.Transactions.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/Microsoft.Win32.Primitives.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\Microsoft.Win32.Primitives.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\netstandard.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.AppContext.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.AppContext.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Buffers.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Buffers.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.Concurrent.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Collections.Concurrent.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Collections.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.NonGeneric.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Collections.NonGeneric.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.Specialized.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Collections.Specialized.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.Annotations.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ComponentModel.Annotations.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ComponentModel.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.EventBasedAsync.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ComponentModel.EventBasedAsync.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.Primitives.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ComponentModel.Primitives.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.TypeConverter.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ComponentModel.TypeConverter.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Console.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Console.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Data.Common.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Data.Common.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Contracts.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.Contracts.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Debug.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.Debug.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.FileVersionInfo.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.FileVersionInfo.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Process.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.Process.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.StackTrace.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.StackTrace.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.TextWriterTraceListener.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.TextWriterTraceListener.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Tools.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.Tools.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.TraceSource.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Diagnostics.TraceSource.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Drawing.Primitives.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Drawing.Primitives.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Dynamic.Runtime.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Dynamic.Runtime.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Globalization.Calendars.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Globalization.Extensions.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Globalization.Calendars.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Globalization.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Globalization.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Globalization.Extensions.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.Compression.ZipFile.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.Compression.ZipFile.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.FileSystem.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.DriveInfo.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.FileSystem.DriveInfo.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.Primitives.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.FileSystem.Primitives.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.Watcher.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.FileSystem.Watcher.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.IsolatedStorage.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.IsolatedStorage.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.MemoryMappedFiles.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.MemoryMappedFiles.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.Pipes.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.Pipes.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.UnmanagedMemoryStream.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.IO.UnmanagedMemoryStream.dll - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.dll + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Linq.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.Expressions.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Linq.Expressions.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.Parallel.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Linq.Parallel.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.Queryable.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Linq.Queryable.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Memory.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Memory.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Http.Rtc.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.Http.Rtc.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.NameResolution.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.NameResolution.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.NetworkInformation.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.NetworkInformation.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Ping.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.Ping.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Primitives.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.Primitives.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Requests.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.Requests.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Security.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.Security.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Sockets.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.Sockets.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.WebHeaderCollection.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.WebHeaderCollection.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.WebSockets.Client.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.WebSockets.Client.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.WebSockets.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Net.WebSockets.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ObjectModel.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ObjectModel.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.DispatchProxy.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.DispatchProxy.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.Emit.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Emit.ILGeneration.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.Emit.ILGeneration.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Emit.Lightweight.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Emit.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.Emit.Lightweight.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Extensions.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.Extensions.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Primitives.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Reflection.Primitives.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Resources.Reader.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Resources.Reader.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Resources.ResourceManager.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Resources.ResourceManager.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Resources.Writer.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Resources.Writer.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.CompilerServices.VisualC.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.CompilerServices.VisualC.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Extensions.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Extensions.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Handles.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Handles.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.InteropServices.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.InteropServices.RuntimeInformation.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.InteropServices.RuntimeInformation.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.InteropServices.WindowsRuntime.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.InteropServices.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.InteropServices.WindowsRuntime.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Numerics.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Numerics.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Formatters.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Serialization.Formatters.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Json.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Serialization.Json.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Primitives.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Serialization.Primitives.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Xml.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Runtime.Serialization.Xml.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Claims.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Claims.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Algorithms.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Cryptography.Algorithms.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Csp.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Cryptography.Csp.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Encoding.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Cryptography.Encoding.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Primitives.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Cryptography.Primitives.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.X509Certificates.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Cryptography.X509Certificates.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Principal.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.Principal.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.SecureString.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Security.SecureString.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Duplex.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ServiceModel.Duplex.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Http.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ServiceModel.Http.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.NetTcp.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ServiceModel.NetTcp.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Primitives.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ServiceModel.Primitives.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Security.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Text.Encoding.Extensions.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ServiceModel.Security.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Text.Encoding.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Text.Encoding.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Text.Encoding.Extensions.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Text.RegularExpressions.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Text.RegularExpressions.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Overlapped.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.Overlapped.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.Tasks.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Tasks.Extensions.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.Tasks.Extensions.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Tasks.Parallel.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Tasks.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.Tasks.Parallel.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Thread.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.Thread.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.ThreadPool.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.ThreadPool.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Timer.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Threading.Timer.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ValueTuple.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.ValueTuple.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.ReaderWriter.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Xml.ReaderWriter.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XDocument.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XPath.XDocument.dll - - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XPath.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Xml.XDocument.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XmlDocument.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Xml.XmlDocument.dll - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XmlSerializer.dll + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Xml.XmlSerializer.dll - - /Applications/Unity/Hub/Editor/2021.3.21f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/netstandard.dll + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Xml.XPath.dll + + + C:\Program Files\Unity\Hub\Editor\2021.3.21f1\Editor\Data\UnityReferenceAssemblies\unity-4.8-api\Facades\System.Xml.XPath.XDocument.dll From e3066bf2c484896cb8f14c75e1bcab9ee5b4d87b Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 30 Apr 2024 12:49:59 +0100 Subject: [PATCH 005/205] the data is now recorded per arena/episode. However, it needs to be cleaned up further. --- Assets/Scripts/TrainingAgent.cs | 40 ++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index eb7065c1..ebbe74ea 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -57,8 +57,9 @@ public class TrainingAgent : Agent, IPrefab [Header("CSV Logging")] public string csvFilePath = "Observations.csv"; + private StreamWriter writer; private bool headerWritten = false; - + public override void Initialize() { _arena = GetComponentInParent(); @@ -67,10 +68,26 @@ public override void Initialize() progBar = GameObject.Find("UI ProgressBar").GetComponent(); progBar.AssignAgent(this); health = _maxHealth; - - if (!File.Exists(csvFilePath)) + + writer = new StreamWriter(csvFilePath, true); + if (!File.Exists(csvFilePath) || new FileInfo(csvFilePath).Length == 0) { - headerWritten = false; // If the file doesn't exist, we need to write the header + // Write header if the file is new or empty + writer.WriteLine("Episode,Step,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition"); + headerWritten = true; + } + } + + protected override void OnDisable() + { + // Call the base class method to ensure any of its functionality is executed + base.OnDisable(); + + // Your additional code + if (writer != null) + { + writer.Close(); + writer = null; // Ensure proper disposal of the resource } } @@ -139,17 +156,16 @@ public override void CollectObservations(VectorSensor sensor) private void LogToCSV(Vector3 velocity, Vector3 position) { - using (StreamWriter sw = new StreamWriter(csvFilePath, true)) + if (!headerWritten) { - if (!headerWritten) - { - sw.WriteLine("Step,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition"); - headerWritten = true; - } - sw.WriteLine($"{StepCount},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z}"); + writer.WriteLine("Episode,Step,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition"); + headerWritten = true; } + writer.WriteLine($"{Academy.Instance.EpisodeCount},{StepCount},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z}"); + writer.Flush(); // Ensure data is written immediately } + public override void OnActionReceived(ActionBuffers action) { int actionForward = Mathf.FloorToInt(action.DiscreteActions[0]); @@ -336,6 +352,8 @@ IEnumerator EndEpisodeAfterDelay() public override void OnEpisodeBegin() { + writer.WriteLine($"\nNew Episode,{Academy.Instance.EpisodeCount},,,,,,,,"); + writer.Flush(); EpisodeDebugLog(); StopCoroutine("unfreezeCountdown"); From 756b7e1e4dcf4aa75a5c724ff8787f33231b33de Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 30 Apr 2024 23:07:27 +0100 Subject: [PATCH 006/205] further work on data logs: The logs are now stored in a folder called observationLogs, in editor, play and train modes. The location of the editor/play is root directory, where in the build/training, it's currently: ""C:\Users\ia424\Desktop\WINDOWS\AnimalAI_Data\observationLogs\Observations.csv"" (on my PC). Next would need to see if we can store the folder and .csv files one directory up or potentially in root directory. Will also need to see if there is any FPS lag as the data is being written simultaneously for obvious reasons... --- Assets/Scripts/TrainingAgent.cs | 41 +++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index ebbe74ea..be862296 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -69,26 +69,49 @@ public override void Initialize() progBar.AssignAgent(this); health = _maxHealth; + //base path for the logs to be stored + string basePath; + + // not relevant to training but useful for debugging + if (Application.isEditor) + { + // setting the base path to the root of the project + basePath = Path.GetFullPath(Path.Combine(Application.dataPath, "..")); + } + else + { + // if were running a build version, set the base path to the data path. might need to be changed... + basePath = Application.dataPath; + } + + // observationLogs folder directory + string directoryPath = Path.Combine(basePath, "observationLogs"); + + // simple check if the folder exists, if not create it + if (!Directory.Exists(directoryPath)) + { + Directory.CreateDirectory(directoryPath); + } + + // so this is the path to the csv file. the first parameter is the directory path, the second is the file name. the file name should be changed... + // TODO: change the file name to something more descriptive + csvFilePath = Path.Combine(directoryPath, "Observations.csv"); + + //initialize the stream writer writer = new StreamWriter(csvFilePath, true); if (!File.Exists(csvFilePath) || new FileInfo(csvFilePath).Length == 0) { - // Write header if the file is new or empty + // need to do some testing here... writer.WriteLine("Episode,Step,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition"); headerWritten = true; } } + // TODO: does this method need to exist? i created it as it gave an error and the documentation said to override it protected override void OnDisable() { - // Call the base class method to ensure any of its functionality is executed + // close the writer when the agent is disabled base.OnDisable(); - - // Your additional code - if (writer != null) - { - writer.Close(); - writer = null; // Ensure proper disposal of the resource - } } public float GetPreviousScore() From 6afa32813551a991cc5779defd1f495a283df817 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 1 May 2024 17:47:29 +0100 Subject: [PATCH 007/205] the folder and .csv files are now stored corectly for editor, in root directory of project files and; for builds, in root directory of .exe file. Ideally, the logic for this feature should have its own class (and will so in the future). Tested on editor plus builds running on play and train modes. The folder and files are produced as expected. --- Assets/Scripts/TrainingAgent.cs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index be862296..9b631bb9 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -69,44 +69,43 @@ public override void Initialize() progBar.AssignAgent(this); health = _maxHealth; - //base path for the logs to be stored + // Base path for the logs to be stored string basePath; - // not relevant to training but useful for debugging if (Application.isEditor) { - // setting the base path to the root of the project + // The root directory is the parent of the Assets folder basePath = Path.GetFullPath(Path.Combine(Application.dataPath, "..")); } else { - // if were running a build version, set the base path to the data path. might need to be changed... - basePath = Application.dataPath; + // Important! For builds, use the parent of the directory where the executable resides + basePath = Path.GetDirectoryName(Application.dataPath); } - // observationLogs folder directory + // Folder for the CSV logs string directoryPath = Path.Combine(basePath, "observationLogs"); - // simple check if the folder exists, if not create it + // Simple check to see if the directory exists, if not create it if (!Directory.Exists(directoryPath)) { Directory.CreateDirectory(directoryPath); } - // so this is the path to the csv file. the first parameter is the directory path, the second is the file name. the file name should be changed... + // Full path for the CSV file // TODO: change the file name to something more descriptive csvFilePath = Path.Combine(directoryPath, "Observations.csv"); - //initialize the stream writer writer = new StreamWriter(csvFilePath, true); if (!File.Exists(csvFilePath) || new FileInfo(csvFilePath).Length == 0) { - // need to do some testing here... + // Attributes for the CSV file --> can be changed as needed writer.WriteLine("Episode,Step,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition"); headerWritten = true; } } + // TODO: does this method need to exist? i created it as it gave an error and the documentation said to override it protected override void OnDisable() { From 481a86adcd8fe46cced281ebffde72372cbc5575 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 1 May 2024 17:47:41 +0100 Subject: [PATCH 008/205] Update ProjectSettings.asset --- ProjectSettings/ProjectSettings.asset | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset index 0363be4c..19a2b79e 100644 --- a/ProjectSettings/ProjectSettings.asset +++ b/ProjectSettings/ProjectSettings.asset @@ -135,7 +135,13 @@ PlayerSettings: 16:9: 1 Others: 1 bundleVersion: 3 - preloadedAssets: [] + preloadedAssets: + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} metroInputSource: 0 wsaTransparentSwapchain: 0 m_HolographicPauseOnTrackingLoss: 1 @@ -155,7 +161,7 @@ PlayerSettings: androidSupportedAspectRatio: 1 androidMaxAspectRatio: 2.1 applicationIdentifier: - Standalone: com.MaCroAI.AnimalAI + Standalone: com.CFI.AnimalAI buildNumber: Standalone: 0 iPhone: 0 From a83c777b1f1007d90a4be8137c3c2036a057fdf6 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 1 May 2024 17:48:17 +0100 Subject: [PATCH 009/205] Create build.meta --- Assets/build.meta | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 Assets/build.meta diff --git a/Assets/build.meta b/Assets/build.meta new file mode 100644 index 00000000..afb262e0 --- /dev/null +++ b/Assets/build.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2e0289db0e6b9d2449f57f9e53dd6a98 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: From d2eeadcce28cbdfe4435db1887f7ebb0ec7e36c4 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 1 May 2024 17:48:44 +0100 Subject: [PATCH 010/205] minor comment fix --- Assets/Scripts/TrainingAgent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 9b631bb9..bd4ad843 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -99,7 +99,7 @@ public override void Initialize() writer = new StreamWriter(csvFilePath, true); if (!File.Exists(csvFilePath) || new FileInfo(csvFilePath).Length == 0) { - // Attributes for the CSV file --> can be changed as needed + // Attribute headers for the CSV file --> can be changed as needed writer.WriteLine("Episode,Step,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition"); headerWritten = true; } From 65f407cab4ae0ca8568d484662eed57f50fb7f35 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 1 May 2024 17:51:01 +0100 Subject: [PATCH 011/205] reformatting --- Assets/Scripts/TrainingAgent.cs | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index bd4ad843..19091a7b 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -105,6 +105,16 @@ public override void Initialize() } } + private void LogToCSV(Vector3 velocity, Vector3 position) + { + if (!headerWritten) + { + writer.WriteLine("Episode,Step,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition"); + headerWritten = true; + } + writer.WriteLine($"{Academy.Instance.EpisodeCount},{StepCount},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z}"); + writer.Flush(); // Ensure data is written immediately + } // TODO: does this method need to exist? i created it as it gave an error and the documentation said to override it protected override void OnDisable() @@ -176,17 +186,6 @@ public override void CollectObservations(VectorSensor sensor) LogToCSV(localVel, localPos); } - private void LogToCSV(Vector3 velocity, Vector3 position) - { - if (!headerWritten) - { - writer.WriteLine("Episode,Step,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition"); - headerWritten = true; - } - writer.WriteLine($"{Academy.Instance.EpisodeCount},{StepCount},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z}"); - writer.Flush(); // Ensure data is written immediately - } - public override void OnActionReceived(ActionBuffers action) { From ae5b05ae7fd5013e2266820f82a9efe7e58dd114 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 1 May 2024 17:52:17 +0100 Subject: [PATCH 012/205] minor region fix --- Assets/Scripts/TrainingAgent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 19091a7b..3c9f5c52 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -356,7 +356,7 @@ public void AddExtraReward(float rewardFactor) #endregion - #region Agent Episode Methods + #region Episode End Methods IEnumerator EndEpisodeAfterDelay() { From eb2572c0fa90212f7f58bfb19791e985f7a419a8 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 1 May 2024 17:59:55 +0100 Subject: [PATCH 013/205] removed region tags for these scripts as theyre not effective --- Assets/Scripts/TrainingAgent.cs | 25 ------------------------- Assets/Scripts/TrainingArena.cs | 13 +++---------- 2 files changed, 3 insertions(+), 35 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 3c9f5c52..4443335c 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -128,8 +128,6 @@ public float GetPreviousScore() return _previousScore; } - #region Agent Freeze Methods - public float GetFreezeDelay() { return _freezeDelay; @@ -172,10 +170,6 @@ private IEnumerator unfreezeCountdown() _isCountdownActive = false; } - #endregion - - #region Agent Core Methods - public override void CollectObservations(VectorSensor sensor) { sensor.AddObservation(health); @@ -186,7 +180,6 @@ public override void CollectObservations(VectorSensor sensor) LogToCSV(localVel, localPos); } - public override void OnActionReceived(ActionBuffers action) { int actionForward = Mathf.FloorToInt(action.DiscreteActions[0]); @@ -270,10 +263,6 @@ public override void Heuristic(in ActionBuffers actionsOut) } } - #endregion - - #region Agent Health Methods - public void UpdateHealthNextStep(float updateAmount, bool andCompleteArena = false) { /// @@ -354,10 +343,6 @@ public void AddExtraReward(float rewardFactor) UpdateHealth(Math.Min(rewardFactor * _rewardPerStep, -0.001f)); } - #endregion - - #region Episode End Methods - IEnumerator EndEpisodeAfterDelay() { if (!showNotification) @@ -396,10 +381,6 @@ private void EpisodeDebugLog() Debug.Log("Number of Goals Collected: " + numberOfGoalsCollected); } - #endregion - - #region Collision Detection Methods - void OnCollisionEnter(Collision collision) { foreach (ContactPoint contact in collision.contacts) @@ -432,10 +413,6 @@ void OnCollisionExit(Collision collision) } } - #endregion - - #region Prefab Interface Methods - //****************************** //PREFAB INTERFACE FOR THE AGENT //****************************** @@ -475,6 +452,4 @@ public virtual Vector3 GetRotation(float rotationY) { return new Vector3(0, rotationY < 0 ? Random.Range(0f, 360f) : rotationY, 0); } - - #endregion } diff --git a/Assets/Scripts/TrainingArena.cs b/Assets/Scripts/TrainingArena.cs index 767a4c94..53a0b1a7 100644 --- a/Assets/Scripts/TrainingArena.cs +++ b/Assets/Scripts/TrainingArena.cs @@ -46,7 +46,8 @@ public class TrainingArena : MonoBehaviour public bool showNotification { get; set; } public bool mergeNextArena { - get { + get + { return _arenaConfiguration.mergeNextArena; } } @@ -114,8 +115,6 @@ private List GetMergedArenas() return mergedArenas; } - #region Arena Handling Methods - /// /// Resets the arena by destroying existing objects and spawning new ones based on the current arena configuration. /// This is a custom implementation of the ResetAcademy method from the MLAgents library. It is called by the TrainingAgent when it resets. @@ -203,7 +202,7 @@ private void SetNextArenaID() private int ChooseRandomArenaID(int totalArenas) { // Populate the list of merged arenas if needed - if (_mergedArenas == null){ _mergedArenas = GetMergedArenas(); } + if (_mergedArenas == null) { _mergedArenas = GetMergedArenas(); } playedArenas.Add(arenaID); if (playedArenas.Count >= totalArenas) @@ -244,10 +243,6 @@ private void NotifyArenaChange() { _environmentManager.TriggerArenaChangeEvent(arenaID, _environmentManager.GetTotalArenas()); } - - #endregion - - #region Other Methods /// /// Destroys all spawned rewards in the arena. @@ -297,6 +292,4 @@ private void OnRewardSpawned(GameObject reward) { spawnedRewards.Add(reward); } - - #endregion } From da76cddaffa7bc38ae8d0725d6925d270d67ca3c Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Thu, 2 May 2024 18:30:53 +0100 Subject: [PATCH 014/205] added forward/backward and rotate attributes works on manual + editor. Couldn't test on training as mlagents error occurred today (attributeerror). Changes: added code to log action vector and appended to attributes list (headers in .csv file). Made actionForward and actionRotate global variables. Properly handled onDisable() so it disables streamIO writer correctly. Removed dublicate logic/code for logging data to .csv --- Assets/Scripts/TrainingAgent.cs | 35 +++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 4443335c..81d2ecab 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -23,6 +23,9 @@ public class TrainingAgent : Agent, IPrefab public float rotationSpeed = 100f; public float rotationAngle = 0.25f; + private int lastActionForward = 0; + private int lastActionRotate = 0; + [Header("Agent State / Other Variables")] [HideInInspector] public int numberOfGoalsCollected = 0; @@ -100,27 +103,25 @@ public override void Initialize() if (!File.Exists(csvFilePath) || new FileInfo(csvFilePath).Length == 0) { // Attribute headers for the CSV file --> can be changed as needed - writer.WriteLine("Episode,Step,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition"); + writer.WriteLine("Episode,Step,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate"); headerWritten = true; } } - private void LogToCSV(Vector3 velocity, Vector3 position) + private void LogToCSV(Vector3 velocity, Vector3 position, int lastActionForward, int lastActionRotate) { - if (!headerWritten) - { - writer.WriteLine("Episode,Step,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition"); - headerWritten = true; - } - writer.WriteLine($"{Academy.Instance.EpisodeCount},{StepCount},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z}"); - writer.Flush(); // Ensure data is written immediately + writer.WriteLine($"{Academy.Instance.EpisodeCount},{StepCount},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate}"); + writer.Flush(); } - // TODO: does this method need to exist? i created it as it gave an error and the documentation said to override it protected override void OnDisable() { - // close the writer when the agent is disabled base.OnDisable(); + if (writer != null) + { + writer.Flush(); + writer.Close(); + } } public float GetPreviousScore() @@ -177,21 +178,25 @@ public override void CollectObservations(VectorSensor sensor) sensor.AddObservation(localVel); Vector3 localPos = transform.position; sensor.AddObservation(localPos); - LogToCSV(localVel, localPos); + LogToCSV(localVel, localPos, lastActionForward, lastActionRotate); } public override void OnActionReceived(ActionBuffers action) { - int actionForward = Mathf.FloorToInt(action.DiscreteActions[0]); - int actionRotate = Mathf.FloorToInt(action.DiscreteActions[1]); + lastActionForward = Mathf.FloorToInt(action.DiscreteActions[0]); + lastActionRotate = Mathf.FloorToInt(action.DiscreteActions[1]); if (!IsFrozen()) { - MoveAgent(actionForward, actionRotate); + MoveAgent(lastActionForward, lastActionRotate); } + Vector3 localVel = transform.InverseTransformDirection(_rigidBody.velocity); + Vector3 localPos = transform.position; + LogToCSV(localVel, localPos, lastActionForward, lastActionRotate); UpdateHealth(_rewardPerStep); } + private void MoveAgent(int actionForward, int actionRotate) { if (IsFrozen()) From dec8bb9bb19e5a08c876899d97974b02f36dd5fe Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Thu, 2 May 2024 18:36:43 +0100 Subject: [PATCH 015/205] modularized .csv code logic for clarity --- Assets/Scripts/TrainingAgent.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 81d2ecab..c5fabbd8 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -72,6 +72,12 @@ public override void Initialize() progBar.AssignAgent(this); health = _maxHealth; + InitialiseCSVProcess(); + + } + + private void InitialiseCSVProcess() + { // Base path for the logs to be stored string basePath; From 108179adc4e5dfd5d71d4e66838544552ea38b50 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Fri, 10 May 2024 21:33:22 +0100 Subject: [PATCH 016/205] logs are now unique and contains date/time stamp. also hidden the yaml data UI - this will be used for testing purposes only. --- Assets/Scripts/TrainingAgent.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index c5fabbd8..78707f97 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -101,9 +101,10 @@ private void InitialiseCSVProcess() Directory.CreateDirectory(directoryPath); } - // Full path for the CSV file - // TODO: change the file name to something more descriptive - csvFilePath = Path.Combine(directoryPath, "Observations.csv"); + // Generate a filename with a date stamp - this will be unique for each run + string dateTimeString = DateTime.Now.ToString("dd-MM-yy_HHmm"); + string filename = $"Observations_{dateTimeString}.csv"; + csvFilePath = Path.Combine(directoryPath, filename); writer = new StreamWriter(csvFilePath, true); if (!File.Exists(csvFilePath) || new FileInfo(csvFilePath).Length == 0) From c08e43aca33c6913bd1ea011a5921c8e08cab742 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Fri, 10 May 2024 21:34:10 +0100 Subject: [PATCH 017/205] Update AAI3EnvironmentManager.unity --- Assets/Scenes/AAI3EnvironmentManager.unity | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/Scenes/AAI3EnvironmentManager.unity b/Assets/Scenes/AAI3EnvironmentManager.unity index 5d42fc63..548e3ac2 100644 --- a/Assets/Scenes/AAI3EnvironmentManager.unity +++ b/Assets/Scenes/AAI3EnvironmentManager.unity @@ -1203,7 +1203,7 @@ GameObject: m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 - m_IsActive: 1 + m_IsActive: 0 --- !u!224 &667441813 RectTransform: m_ObjectHideFlags: 0 From 53407f6cdf13f9c3d9bec0b7b6bd67bcbf68ed39 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Fri, 10 May 2024 21:52:06 +0100 Subject: [PATCH 018/205] added new package - recorder - to capture ingame footage and take screenshots --- Packages/manifest.json | 1 + Packages/packages-lock.json | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/Packages/manifest.json b/Packages/manifest.json index 0d59d49a..09e0cb0f 100644 --- a/Packages/manifest.json +++ b/Packages/manifest.json @@ -5,6 +5,7 @@ "com.unity.ide.visualstudio": "2.0.17", "com.unity.ide.vscode": "1.2.5", "com.unity.ml-agents": "2.3.0-exp.3", + "com.unity.recorder": "3.0.3", "com.unity.render-pipelines.universal": "12.1.10", "com.unity.test-framework": "1.1.33", "com.unity.textmeshpro": "3.0.6", diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json index 985ca721..c0a3275b 100644 --- a/Packages/packages-lock.json +++ b/Packages/packages-lock.json @@ -77,6 +77,15 @@ }, "url": "https://packages.unity.com" }, + "com.unity.recorder": { + "version": "3.0.3", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.timeline": "1.0.0" + }, + "url": "https://packages.unity.com" + }, "com.unity.render-pipelines.core": { "version": "12.1.10", "depth": 1, From 8eb0b7d8ee36a8669e4baae7ef191a610844f7f5 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Mon, 13 May 2024 18:36:39 +0100 Subject: [PATCH 019/205] Update Assembly-CSharp.csproj --- Assembly-CSharp.csproj | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index 768bff14..0308119d 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -791,8 +791,8 @@ C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.Barracuda.iOSBLAS.dll - - C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.Barracuda.ONNX.dll + + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.Recorder.Editor.dll C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.VSCode.Editor.dll @@ -800,9 +800,15 @@ C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.Barracuda.BurstBLAS.dll + + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.Barracuda.ONNX.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.RenderPipelines.Universal.Shaders.dll + + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.Recorder.Base.dll + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.RenderPipelines.Universal.Runtime.dll @@ -899,6 +905,9 @@ C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.SysrootPackage.Editor.dll + + C:\Users\ia424\Desktop\animal-ai-unity\Library\ScriptAssemblies\Unity.Recorder.dll + From 200400803a56251472689b9323757154770be094 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Mon, 13 May 2024 20:37:51 +0100 Subject: [PATCH 020/205] changed method to comply with naming standards unfreezeCountdown ---> UnfreezeCountdown --- Assets/Scripts/TrainingAgent.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 78707f97..6a491497 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -147,9 +147,9 @@ public void SetFreezeDelay(float v) if (v != 0f && !_isCountdownActive) { Debug.Log( - "Starting coroutine unfreezeCountdown() with wait seconds == " + GetFreezeDelay() + "Starting coroutine UnfreezeCountdown() with wait seconds == " + GetFreezeDelay() ); - StartCoroutine(unfreezeCountdown()); + StartCoroutine(UnfreezeCountdown()); } } @@ -168,7 +168,7 @@ public void FreezeAgent(bool freeze) } } - private IEnumerator unfreezeCountdown() + private IEnumerator UnfreezeCountdown() { _isCountdownActive = true; yield return new WaitForSeconds(GetFreezeDelay()); @@ -370,11 +370,11 @@ IEnumerator EndEpisodeAfterDelay() public override void OnEpisodeBegin() { - writer.WriteLine($"\nNew Episode,{Academy.Instance.EpisodeCount},,,,,,,,"); + writer.WriteLine($"\nNew Episode,{Academy.Instance.EpisodeCount}-----"); writer.Flush(); EpisodeDebugLog(); - StopCoroutine("unfreezeCountdown"); + StopCoroutine("UnfreezeCountdown"); _previousScore = _currentScore; numberOfGoalsCollected = 0; _arena.ResetArena(); From 66f62b62f390f8e27964544299bbf2f1f7c3e7ad Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Mon, 13 May 2024 21:50:21 +0100 Subject: [PATCH 021/205] Update TrainingAgent.cs --- Assets/Scripts/TrainingAgent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 6a491497..2f2ae8a2 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -93,7 +93,7 @@ private void InitialiseCSVProcess() } // Folder for the CSV logs - string directoryPath = Path.Combine(basePath, "observationLogs"); + string directoryPath = Path.Combine(basePath, "ObservationLogs"); // Simple check to see if the directory exists, if not create it if (!Directory.Exists(directoryPath)) From 1f982fc7fd6c29ad39b78265d300ac212e0b22b3 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Mon, 13 May 2024 21:52:19 +0100 Subject: [PATCH 022/205] minor changes --- Assets/Scripts/TrainingAgent.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 2f2ae8a2..668a8022 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -203,7 +203,6 @@ public override void OnActionReceived(ActionBuffers action) UpdateHealth(_rewardPerStep); } - private void MoveAgent(int actionForward, int actionRotate) { if (IsFrozen()) From e9c5763d50e34a2b3a942a6ae10b2a65602bb605 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 21 May 2024 13:05:06 +0100 Subject: [PATCH 023/205] minor comment fix --- Assets/Scripts/Prefab.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/Scripts/Prefab.cs b/Assets/Scripts/Prefab.cs index da0f7c2e..8a77f096 100644 --- a/Assets/Scripts/Prefab.cs +++ b/Assets/Scripts/Prefab.cs @@ -7,7 +7,7 @@ using System.Reflection; /// -/// A Prefab represents a GameObject that cna be spawned in an arena, it also contains the range of +/// A Prefab represents a GameObject that can be spawned in an arena, it also contains the range of /// values that the user can pass as parameters /// public class Prefab : MonoBehaviour, IPrefab From 2a51a6e6e5a1b77790aa3f8919299c4d73144e4b Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 21 May 2024 13:11:10 +0100 Subject: [PATCH 024/205] added new summary for missed method in yamlclasses.cs --- Assets/Scripts/YAMLclasses.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Assets/Scripts/YAMLclasses.cs b/Assets/Scripts/YAMLclasses.cs index 919da016..e01c8d00 100644 --- a/Assets/Scripts/YAMLclasses.cs +++ b/Assets/Scripts/YAMLclasses.cs @@ -120,6 +120,9 @@ public static class AliasMapper { "Pillar-Button", "SpawnerButton" }, }; + /// + /// ResolveAlias method is used to resolve the alias of the game object name for backwards-compatibility. + /// public static string ResolveAlias(string name) { if (AliasMap.TryGetValue(name, out string newName)) From e234121417e17667cd13a0eb64f147e3feb30978 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Mon, 3 Jun 2024 18:28:19 +0100 Subject: [PATCH 025/205] trying to read incoming msg from python --- Assets/Scripts/AAI3EnvironmentManager.cs | 733 +++++++------- Assets/Scripts/ArenasParametersEventArgs.cs | 4 +- Assets/Scripts/ArenasParametersSideChannel.cs | 94 +- Assets/Scripts/TrainingAgent.cs | 918 +++++++++--------- 4 files changed, 902 insertions(+), 847 deletions(-) diff --git a/Assets/Scripts/AAI3EnvironmentManager.cs b/Assets/Scripts/AAI3EnvironmentManager.cs index 8b9af453..dcc4bbb3 100644 --- a/Assets/Scripts/AAI3EnvironmentManager.cs +++ b/Assets/Scripts/AAI3EnvironmentManager.cs @@ -13,368 +13,373 @@ /// public class AAI3EnvironmentManager : MonoBehaviour { - [Header("Arena Settings")] - [SerializeField] - private GameObject arena; - - [SerializeField] - private GameObject uiCanvas; - - [SerializeField] - private GameObject playerControls; - - [Header("Configuration File")] - [SerializeField] - private string configFile = ""; - - [Header("Resolution Settings")] - [SerializeField] - private const int maximumResolution = 512; - - [SerializeField] - private const int minimumResolution = 4; - - [SerializeField] - private const int defaultResolution = 84; - - [SerializeField] - private const int defaultRaysPerSide = 2; - - [SerializeField] - private const int defaultRayMaxDegrees = 60; - - [SerializeField] - private const int defaultDecisionPeriod = 3; - - public bool PlayerMode { get; private set; } = true; - - private ArenasConfigurations _arenasConfigurations; - private TrainingArena _instantiatedArena; - private ArenasParametersSideChannel _arenasParametersSideChannel; - - public static event Action OnArenaChanged; - - #region Initialisation Methods - public void Awake() - { - InitialiseSideChannel(); - - Dictionary environmentParameters = RetrieveEnvironmentParameters(); - int paramValue; - bool playerMode = - (environmentParameters.TryGetValue("playerMode", out paramValue) ? paramValue : 1) > 0; - bool useCamera = - (environmentParameters.TryGetValue("useCamera", out paramValue) ? paramValue : 0) > 0; - int resolution = environmentParameters.TryGetValue("resolution", out paramValue) - ? paramValue - : defaultResolution; - bool grayscale = - (environmentParameters.TryGetValue("grayscale", out paramValue) ? paramValue : 0) > 0; - bool useRayCasts = - (environmentParameters.TryGetValue("useRayCasts", out paramValue) ? paramValue : 0) > 0; - int raysPerSide = environmentParameters.TryGetValue("raysPerSide", out paramValue) - ? paramValue - : defaultRaysPerSide; - int rayMaxDegrees = environmentParameters.TryGetValue("rayMaxDegrees", out paramValue) - ? paramValue - : defaultRayMaxDegrees; - int decisionPeriod = environmentParameters.TryGetValue("decisionPeriod", out paramValue) - ? paramValue - : defaultDecisionPeriod; - Debug.Log("Set playermode to " + playerMode); - - if (Application.isEditor) - { - Debug.Log("Using Unity Editor Default Configuration"); - playerMode = true; - useCamera = true; - resolution = 84; - grayscale = false; - useRayCasts = true; - raysPerSide = 2; - - LoadYAMLFileInEditor(); - } - - resolution = Math.Max(minimumResolution, Math.Min(maximumResolution, resolution)); - TrainingArena arena = FindObjectOfType(); - - InstantiateArenas(); - - playerControls.SetActive(playerMode); - uiCanvas.GetComponent().enabled = playerMode; - - foreach (Agent a in FindObjectsOfType(true)) - { - a.GetComponentInChildren().DecisionPeriod = decisionPeriod; - if (!useRayCasts) - { - DestroyImmediate(a.GetComponentInChildren()); - } - else - { - ChangeRayCasts( - a.GetComponentInChildren(), - raysPerSide, - rayMaxDegrees - ); - } - if (!useCamera) - { - DestroyImmediate(a.GetComponentInChildren()); - } - else - { - ChangeResolution( - a.GetComponentInChildren(), - resolution, - resolution, - grayscale - ); - } - if (playerMode) - { - a.GetComponentInChildren().BehaviorType = - BehaviorType.HeuristicOnly; - } - } - PrintDebugInfo( - playerMode, - useCamera, - resolution, - grayscale, - useRayCasts, - raysPerSide, - rayMaxDegrees - ); - _instantiatedArena._agent.gameObject.SetActive(true); - } - - private void InitialiseSideChannel() - { - _arenasConfigurations = new ArenasConfigurations(); - _arenasParametersSideChannel = new ArenasParametersSideChannel(); - _arenasParametersSideChannel.NewArenasParametersReceived += - _arenasConfigurations.UpdateWithConfigurationsReceived; - SideChannelManager.RegisterSideChannel(_arenasParametersSideChannel); - } - - private void InstantiateArenas() - { - GameObject arenaInst = Instantiate(arena, new Vector3(0f, 0f, 0f), Quaternion.identity); - _instantiatedArena = arenaInst.GetComponent(); - _instantiatedArena.arenaID = 0; - } - - private void LoadYAMLFileInEditor() - { - if (string.IsNullOrWhiteSpace(configFile)) - { - Debug.LogWarning("Config file path is null or empty."); - return; - } - - try - { - var configYAML = Resources.Load(configFile); - if (configYAML != null) - { - var YAMLReader = new YAMLDefs.YAMLReader(); - var parsed = YAMLReader.deserializer.Deserialize( - configYAML.text - ); - if (parsed != null) - { - _arenasConfigurations.UpdateWithYAML(parsed); - } - else - { - Debug.LogWarning("Deserialized YAML content is null."); - } - } - else - { - Debug.LogWarning($"YAML file '{configFile}' could not be found or loaded."); - } - } - catch (Exception ex) - { - Debug.LogError( - $"An error occurred while loading or processing the YAML file: {ex.Message}" - ); - } - } - - #endregion - - #region Public Getter/Setter Methods - - public void TriggerArenaChangeEvent(int currentArenaIndex, int totalArenas) - { - OnArenaChanged?.Invoke(currentArenaIndex, totalArenas); - } - - public bool GetRandomizeArenasStatus() - { - return _arenasConfigurations.randomizeArenas; - } - - public int GetCurrentArenaIndex() - { - return _arenasConfigurations.CurrentArenaID; - } - - public int GetTotalArenas() - { - return _arenasConfigurations.configurations.Count; - } - - #endregion - - #region Environment Configuration Methods - private void ChangeRayCasts( - RayPerceptionSensorComponent3D raySensor, - int no_raycasts, - int max_degrees - ) - { - raySensor.RaysPerDirection = no_raycasts; - raySensor.MaxRayDegrees = max_degrees; - } - - private void ChangeResolution( - CameraSensorComponent cameraSensor, - int cameraWidth, - int cameraHeight, - bool grayscale - ) - { - cameraSensor.Width = cameraWidth; - cameraSensor.Height = cameraHeight; - cameraSensor.Grayscale = grayscale; - } - - private Dictionary RetrieveEnvironmentParameters() - { - Dictionary environmentParameters = new Dictionary(); - string[] args = System.Environment.GetCommandLineArgs(); - Debug.Log("Command Line Args: " + String.Join(" ", args)); - - for (int i = 0; i < args.Length; i++) - { - switch (args[i]) - { - case "--playerMode": - int playerMode = (i < args.Length - 1) ? Int32.Parse(args[i + 1]) : 1; - environmentParameters.Add("playerMode", playerMode); - break; - case "--receiveConfiguration": - environmentParameters.Add("receiveConfiguration", 0); - break; - case "--numberOfArenas": - int nArenas = (i < args.Length - 1) ? Int32.Parse(args[i + 1]) : 1; - environmentParameters.Add("numberOfArenas", nArenas); - break; - case "--useCamera": - environmentParameters.Add("useCamera", 1); - break; - case "--resolution": - int camW = (i < args.Length - 1) ? Int32.Parse(args[i + 1]) : defaultResolution; - environmentParameters.Add("resolution", camW); - break; - case "--grayscale": - environmentParameters.Add("grayscale", 1); - break; - case "--useRayCasts": - environmentParameters.Add("useRayCasts", 1); - break; - case "--raysPerSide": - int rps = (i < args.Length - 1) ? Int32.Parse(args[i + 1]) : 2; - environmentParameters.Add("raysPerSide", rps); - break; - case "--rayMaxDegrees": - int rmd = (i < args.Length - 1) ? Int32.Parse(args[i + 1]) : 60; - environmentParameters.Add("rayMaxDegrees", rmd); - break; - case "--decisionPeriod": - int dp = (i < args.Length - 1) ? Int32.Parse(args[i + 1]) : 3; - environmentParameters.Add("decisionPeriod", dp); - break; - } - } - return environmentParameters; - } - - #endregion - - #region Configuration Management Methods - - public ArenaConfiguration GetConfiguration(int arenaID) - { - ArenaConfiguration returnConfiguration; - if (!_arenasConfigurations.configurations.TryGetValue(arenaID, out returnConfiguration)) - { - throw new KeyNotFoundException($"Tried to load arena {arenaID} but it did not exist"); - } - return returnConfiguration; - } - - public void AddConfiguration(int arenaID, ArenaConfiguration arenaConfiguration) - { - _arenasConfigurations.configurations.Add(arenaID, arenaConfiguration); - } - - #endregion - - #region Other Methods - - public void OnDestroy() - { - if (Academy.IsInitialized) - { - SideChannelManager.UnregisterSideChannel(_arenasParametersSideChannel); - } - } - - private void PrintDebugInfo( - bool playerMode, - bool useCamera, - int resolution, - bool grayscale, - bool useRayCasts, - int raysPerSide, - int rayMaxDegrees - ) - { - Debug.Log( - "Environment loaded with options:" - + "\n PlayerMode: " - + playerMode - + "\n useCamera: " - + useCamera - + "\n Resolution: " - + resolution - + "\n grayscale: " - + grayscale - + "\n useRayCasts: " - + useRayCasts - + "\n raysPerSide: " - + raysPerSide - + "\n rayMaxDegrees: " - + rayMaxDegrees - ); - } - - #endregion - - #region Read Stream - - public static byte[] ReadFully(Stream stream) - { - using var ms = new MemoryStream(); - stream.CopyTo(ms); - return ms.ToArray(); - } - - #endregion + [Header("Arena Settings")] + [SerializeField] + private GameObject arena; + + [SerializeField] + private GameObject uiCanvas; + + [SerializeField] + private GameObject playerControls; + + [Header("Configuration File")] + [SerializeField] + private string configFile = ""; + + [Header("Resolution Settings")] + [SerializeField] + private const int maximumResolution = 512; + + [SerializeField] + private const int minimumResolution = 4; + + [SerializeField] + private const int defaultResolution = 84; + + [SerializeField] + private const int defaultRaysPerSide = 2; + + [SerializeField] + private const int defaultRayMaxDegrees = 60; + + [SerializeField] + private const int defaultDecisionPeriod = 3; + + public bool PlayerMode { get; private set; } = true; + + private ArenasConfigurations _arenasConfigurations; + private TrainingArena _instantiatedArena; + private ArenasParametersSideChannel _arenasParametersSideChannel; + + public static event Action OnArenaChanged; + + #region Initialisation Methods + public void Awake() + { + InitialiseSideChannel(); + + Dictionary environmentParameters = RetrieveEnvironmentParameters(); + int paramValue; + bool playerMode = + (environmentParameters.TryGetValue("playerMode", out paramValue) ? paramValue : 1) > 0; + bool useCamera = + (environmentParameters.TryGetValue("useCamera", out paramValue) ? paramValue : 0) > 0; + int resolution = environmentParameters.TryGetValue("resolution", out paramValue) + ? paramValue + : defaultResolution; + bool grayscale = + (environmentParameters.TryGetValue("grayscale", out paramValue) ? paramValue : 0) > 0; + bool useRayCasts = + (environmentParameters.TryGetValue("useRayCasts", out paramValue) ? paramValue : 0) > 0; + int raysPerSide = environmentParameters.TryGetValue("raysPerSide", out paramValue) + ? paramValue + : defaultRaysPerSide; + int rayMaxDegrees = environmentParameters.TryGetValue("rayMaxDegrees", out paramValue) + ? paramValue + : defaultRayMaxDegrees; + int decisionPeriod = environmentParameters.TryGetValue("decisionPeriod", out paramValue) + ? paramValue + : defaultDecisionPeriod; + Debug.Log("Set playermode to " + playerMode); + + if (Application.isEditor) + { + Debug.Log("Using Unity Editor Default Configuration"); + playerMode = true; + useCamera = true; + resolution = 84; + grayscale = false; + useRayCasts = true; + raysPerSide = 2; + + LoadYAMLFileInEditor(); + } + + resolution = Math.Max(minimumResolution, Math.Min(maximumResolution, resolution)); + TrainingArena arena = FindObjectOfType(); + + InstantiateArenas(); + + playerControls.SetActive(playerMode); + uiCanvas.GetComponent().enabled = playerMode; + + foreach (Agent a in FindObjectsOfType(true)) + { + a.GetComponentInChildren().DecisionPeriod = decisionPeriod; + if (!useRayCasts) + { + DestroyImmediate(a.GetComponentInChildren()); + } + else + { + ChangeRayCasts( + a.GetComponentInChildren(), + raysPerSide, + rayMaxDegrees + ); + } + if (!useCamera) + { + DestroyImmediate(a.GetComponentInChildren()); + } + else + { + ChangeResolution( + a.GetComponentInChildren(), + resolution, + resolution, + grayscale + ); + } + if (playerMode) + { + a.GetComponentInChildren().BehaviorType = + BehaviorType.HeuristicOnly; + } + } + PrintDebugInfo( + playerMode, + useCamera, + resolution, + grayscale, + useRayCasts, + raysPerSide, + rayMaxDegrees + ); + _instantiatedArena._agent.gameObject.SetActive(true); + } + + public string GetCurrentYamlFileName() + { + return _arenasParametersSideChannel.CurrentYamlFileName; + } + + private void InitialiseSideChannel() + { + _arenasConfigurations = new ArenasConfigurations(); + _arenasParametersSideChannel = new ArenasParametersSideChannel(); + _arenasParametersSideChannel.NewArenasParametersReceived += + _arenasConfigurations.UpdateWithConfigurationsReceived; + SideChannelManager.RegisterSideChannel(_arenasParametersSideChannel); + } + + private void InstantiateArenas() + { + GameObject arenaInst = Instantiate(arena, new Vector3(0f, 0f, 0f), Quaternion.identity); + _instantiatedArena = arenaInst.GetComponent(); + _instantiatedArena.arenaID = 0; + } + + private void LoadYAMLFileInEditor() + { + if (string.IsNullOrWhiteSpace(configFile)) + { + Debug.LogWarning("Config file path is null or empty."); + return; + } + + try + { + var configYAML = Resources.Load(configFile); + if (configYAML != null) + { + var YAMLReader = new YAMLDefs.YAMLReader(); + var parsed = YAMLReader.deserializer.Deserialize( + configYAML.text + ); + if (parsed != null) + { + _arenasConfigurations.UpdateWithYAML(parsed); + } + else + { + Debug.LogWarning("Deserialized YAML content is null."); + } + } + else + { + Debug.LogWarning($"YAML file '{configFile}' could not be found or loaded."); + } + } + catch (Exception ex) + { + Debug.LogError( + $"An error occurred while loading or processing the YAML file: {ex.Message}" + ); + } + } + + #endregion + + #region Public Getter/Setter Methods + + public void TriggerArenaChangeEvent(int currentArenaIndex, int totalArenas) + { + OnArenaChanged?.Invoke(currentArenaIndex, totalArenas); + } + + public bool GetRandomizeArenasStatus() + { + return _arenasConfigurations.randomizeArenas; + } + + public int GetCurrentArenaIndex() + { + return _arenasConfigurations.CurrentArenaID; + } + + public int GetTotalArenas() + { + return _arenasConfigurations.configurations.Count; + } + + #endregion + + #region Environment Configuration Methods + private void ChangeRayCasts( + RayPerceptionSensorComponent3D raySensor, + int no_raycasts, + int max_degrees + ) + { + raySensor.RaysPerDirection = no_raycasts; + raySensor.MaxRayDegrees = max_degrees; + } + + private void ChangeResolution( + CameraSensorComponent cameraSensor, + int cameraWidth, + int cameraHeight, + bool grayscale + ) + { + cameraSensor.Width = cameraWidth; + cameraSensor.Height = cameraHeight; + cameraSensor.Grayscale = grayscale; + } + + private Dictionary RetrieveEnvironmentParameters() + { + Dictionary environmentParameters = new Dictionary(); + string[] args = System.Environment.GetCommandLineArgs(); + Debug.Log("Command Line Args: " + String.Join(" ", args)); + + for (int i = 0; i < args.Length; i++) + { + switch (args[i]) + { + case "--playerMode": + int playerMode = (i < args.Length - 1) ? Int32.Parse(args[i + 1]) : 1; + environmentParameters.Add("playerMode", playerMode); + break; + case "--receiveConfiguration": + environmentParameters.Add("receiveConfiguration", 0); + break; + case "--numberOfArenas": + int nArenas = (i < args.Length - 1) ? Int32.Parse(args[i + 1]) : 1; + environmentParameters.Add("numberOfArenas", nArenas); + break; + case "--useCamera": + environmentParameters.Add("useCamera", 1); + break; + case "--resolution": + int camW = (i < args.Length - 1) ? Int32.Parse(args[i + 1]) : defaultResolution; + environmentParameters.Add("resolution", camW); + break; + case "--grayscale": + environmentParameters.Add("grayscale", 1); + break; + case "--useRayCasts": + environmentParameters.Add("useRayCasts", 1); + break; + case "--raysPerSide": + int rps = (i < args.Length - 1) ? Int32.Parse(args[i + 1]) : 2; + environmentParameters.Add("raysPerSide", rps); + break; + case "--rayMaxDegrees": + int rmd = (i < args.Length - 1) ? Int32.Parse(args[i + 1]) : 60; + environmentParameters.Add("rayMaxDegrees", rmd); + break; + case "--decisionPeriod": + int dp = (i < args.Length - 1) ? Int32.Parse(args[i + 1]) : 3; + environmentParameters.Add("decisionPeriod", dp); + break; + } + } + return environmentParameters; + } + + #endregion + + #region Configuration Management Methods + + public ArenaConfiguration GetConfiguration(int arenaID) + { + ArenaConfiguration returnConfiguration; + if (!_arenasConfigurations.configurations.TryGetValue(arenaID, out returnConfiguration)) + { + throw new KeyNotFoundException($"Tried to load arena {arenaID} but it did not exist"); + } + return returnConfiguration; + } + + public void AddConfiguration(int arenaID, ArenaConfiguration arenaConfiguration) + { + _arenasConfigurations.configurations.Add(arenaID, arenaConfiguration); + } + + #endregion + + #region Other Methods + + public void OnDestroy() + { + if (Academy.IsInitialized) + { + SideChannelManager.UnregisterSideChannel(_arenasParametersSideChannel); + } + } + + private void PrintDebugInfo( + bool playerMode, + bool useCamera, + int resolution, + bool grayscale, + bool useRayCasts, + int raysPerSide, + int rayMaxDegrees + ) + { + Debug.Log( + "Environment loaded with options:" + + "\n PlayerMode: " + + playerMode + + "\n useCamera: " + + useCamera + + "\n Resolution: " + + resolution + + "\n grayscale: " + + grayscale + + "\n useRayCasts: " + + useRayCasts + + "\n raysPerSide: " + + raysPerSide + + "\n rayMaxDegrees: " + + rayMaxDegrees + ); + } + + #endregion + + #region Read Stream + + public static byte[] ReadFully(Stream stream) + { + using var ms = new MemoryStream(); + stream.CopyTo(ms); + return ms.ToArray(); + } + + #endregion } diff --git a/Assets/Scripts/ArenasParametersEventArgs.cs b/Assets/Scripts/ArenasParametersEventArgs.cs index a03610ba..875c85e6 100644 --- a/Assets/Scripts/ArenasParametersEventArgs.cs +++ b/Assets/Scripts/ArenasParametersEventArgs.cs @@ -1,12 +1,14 @@ using System; /// -/// ArenasParameters namespace contains classes that are used to deserialize YAML files. +/// ArenasParameters namespace contains classes that are used to deserialize YAML files. /// namespace ArenasParameters { public class ArenasParametersEventArgs : EventArgs { public byte[] arenas_yaml { get; set; } + public string yamlFileName { get; set; } + public ArenasParametersEventArgs() { } // Empty constructor } } diff --git a/Assets/Scripts/ArenasParametersSideChannel.cs b/Assets/Scripts/ArenasParametersSideChannel.cs index 927bf74b..e7e27e49 100644 --- a/Assets/Scripts/ArenasParametersSideChannel.cs +++ b/Assets/Scripts/ArenasParametersSideChannel.cs @@ -1,47 +1,69 @@ using Unity.MLAgents.SideChannels; using System; using ArenasParameters; +using UnityEngine; /// /// This class is used to communicate the environment configurations to the Unity. /// public class ArenasParametersSideChannel : SideChannel { - /// - /// Initializes a new instance of the ArenasParametersSideChannel class. - /// - public ArenasParametersSideChannel() - { - ChannelId = new Guid("9c36c837-cad5-498a-b675-bc19c9370072"); - } - - /// - /// This method is called when a message is received from the Unity. - /// - protected override void OnMessageReceived(IncomingMessage msg) - { - ArenasParametersEventArgs args = new ArenasParametersEventArgs(); - args.arenas_yaml = msg.GetRawBytes(); - OnArenasParametersReceived(args); - } - - /// - /// This method is called when the arenas parameters are received. - /// - protected virtual void OnArenasParametersReceived( - ArenasParametersEventArgs arenasParametersEvent - ) - { - EventHandler handler = NewArenasParametersReceived; - if (handler != null) - { - handler(this, arenasParametersEvent); - } - } - - /// - /// This event is triggered when new arenas parameters are received. - /// - public EventHandler NewArenasParametersReceived; + public string CurrentYamlFileName { get; private set; } // Store the current YAML file name + /// + /// Initializes a new instance of the ArenasParametersSideChannel class. + /// + public ArenasParametersSideChannel() + { + ChannelId = new Guid("9c36c837-cad5-498a-b675-bc19c9370072"); + } + + /// + /// This method is called when a message is received from the Unity. + /// + protected override void OnMessageReceived(IncomingMessage msg) + { + string fileName = msg.ReadString(); + byte[] yamlData = msg.GetRawBytes(); + + Debug.Log($"Received YAML file name: {fileName}"); + CurrentYamlFileName = fileName; + + // Create the event args including the file name and the YAML data + ArenasParametersEventArgs args = new ArenasParametersEventArgs + { + arenas_yaml = yamlData, + yamlFileName = fileName + }; + OnArenasParametersReceived(args); + UpdateTrainingAgentsWithYamlFileName(fileName); + } + + /// + /// This method is called when the arenas parameters are received. + /// + protected virtual void OnArenasParametersReceived( + ArenasParametersEventArgs arenasParametersEvent + ) + { + EventHandler handler = NewArenasParametersReceived; + if (handler != null) + { + handler(this, arenasParametersEvent); + } + } + + private void UpdateTrainingAgentsWithYamlFileName(string fileName) + { + TrainingAgent[] agents = GameObject.FindObjectsOfType(); + foreach (var agent in agents) + { + agent.SetYamlFileName(fileName); + } + } + + /// + /// This event is triggered when new arenas parameters are received. + /// + public EventHandler NewArenasParametersReceived; } diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 668a8022..1016cca5 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -17,450 +17,476 @@ /// public class TrainingAgent : Agent, IPrefab { - [Header("Agent Settings")] - public float speed = 25f; - public float quickStopRatio = 0.9f; - public float rotationSpeed = 100f; - public float rotationAngle = 0.25f; - - private int lastActionForward = 0; - private int lastActionRotate = 0; - - [Header("Agent State / Other Variables")] - [HideInInspector] - public int numberOfGoalsCollected = 0; - - [HideInInspector] - public ProgressBar progBar; - private Rigidbody _rigidBody; - private bool _isGrounded; - private ContactPoint _lastContactPoint; - - [Header("Agent Rewards & Score")] - private float _rewardPerStep; - private float _previousScore = 0; - private float _currentScore = 0; - - [Header("Agent Health")] - public float health = 100f; - private float _maxHealth = 100f; - - [Header("Agent Freeze & Countdown")] - public float timeLimit = 0f; - private float _nextUpdateHealth = 0f; - private float _freezeDelay = 0f; - private bool _isFrozen = false; - - private bool _nextUpdateCompleteArena = false; - - [Header("Agent Notification")] - public bool showNotification = false; - private TrainingArena _arena; - private bool _isCountdownActive = false; - - [Header("CSV Logging")] - public string csvFilePath = "Observations.csv"; - private StreamWriter writer; - private bool headerWritten = false; - - public override void Initialize() - { - _arena = GetComponentInParent(); - _rigidBody = GetComponent(); - _rewardPerStep = timeLimit > 0 ? -1f / timeLimit : 0; - progBar = GameObject.Find("UI ProgressBar").GetComponent(); - progBar.AssignAgent(this); - health = _maxHealth; - - InitialiseCSVProcess(); - - } - - private void InitialiseCSVProcess() - { - // Base path for the logs to be stored - string basePath; - - if (Application.isEditor) - { - // The root directory is the parent of the Assets folder - basePath = Path.GetFullPath(Path.Combine(Application.dataPath, "..")); - } - else - { - // Important! For builds, use the parent of the directory where the executable resides - basePath = Path.GetDirectoryName(Application.dataPath); - } - - // Folder for the CSV logs - string directoryPath = Path.Combine(basePath, "ObservationLogs"); - - // Simple check to see if the directory exists, if not create it - if (!Directory.Exists(directoryPath)) - { - Directory.CreateDirectory(directoryPath); - } - - // Generate a filename with a date stamp - this will be unique for each run - string dateTimeString = DateTime.Now.ToString("dd-MM-yy_HHmm"); - string filename = $"Observations_{dateTimeString}.csv"; - csvFilePath = Path.Combine(directoryPath, filename); - - writer = new StreamWriter(csvFilePath, true); - if (!File.Exists(csvFilePath) || new FileInfo(csvFilePath).Length == 0) - { - // Attribute headers for the CSV file --> can be changed as needed - writer.WriteLine("Episode,Step,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate"); - headerWritten = true; - } - } - - private void LogToCSV(Vector3 velocity, Vector3 position, int lastActionForward, int lastActionRotate) - { - writer.WriteLine($"{Academy.Instance.EpisodeCount},{StepCount},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate}"); - writer.Flush(); - } - - protected override void OnDisable() - { - base.OnDisable(); - if (writer != null) - { - writer.Flush(); - writer.Close(); - } - } - - public float GetPreviousScore() - { - return _previousScore; - } - - public float GetFreezeDelay() - { - return _freezeDelay; - } - - public void SetFreezeDelay(float v) - { - _freezeDelay = Mathf.Clamp(v, 0f, v); - if (v != 0f && !_isCountdownActive) - { - Debug.Log( - "Starting coroutine UnfreezeCountdown() with wait seconds == " + GetFreezeDelay() - ); - StartCoroutine(UnfreezeCountdown()); - } - } - - public bool IsFrozen() - { - return _freezeDelay > 0f || _isFrozen; - } - - public void FreezeAgent(bool freeze) - { - _isFrozen = freeze; - if (_isFrozen) - { - _rigidBody.velocity = Vector3.zero; - _rigidBody.angularVelocity = Vector3.zero; - } - } - - private IEnumerator UnfreezeCountdown() - { - _isCountdownActive = true; - yield return new WaitForSeconds(GetFreezeDelay()); - - Debug.Log("unfreezing!"); - SetFreezeDelay(0f); - _isCountdownActive = false; - } - - public override void CollectObservations(VectorSensor sensor) - { - sensor.AddObservation(health); - Vector3 localVel = transform.InverseTransformDirection(_rigidBody.velocity); - sensor.AddObservation(localVel); - Vector3 localPos = transform.position; - sensor.AddObservation(localPos); - LogToCSV(localVel, localPos, lastActionForward, lastActionRotate); - } - - public override void OnActionReceived(ActionBuffers action) - { - lastActionForward = Mathf.FloorToInt(action.DiscreteActions[0]); - lastActionRotate = Mathf.FloorToInt(action.DiscreteActions[1]); - if (!IsFrozen()) - { - MoveAgent(lastActionForward, lastActionRotate); - } - - Vector3 localVel = transform.InverseTransformDirection(_rigidBody.velocity); - Vector3 localPos = transform.position; - LogToCSV(localVel, localPos, lastActionForward, lastActionRotate); - UpdateHealth(_rewardPerStep); - } - - private void MoveAgent(int actionForward, int actionRotate) - { - if (IsFrozen()) - { - // If the agent is frozen, stop all movement and rotation - _rigidBody.velocity = Vector3.zero; - _rigidBody.angularVelocity = Vector3.zero; - return; - } - - Vector3 directionToGo = Vector3.zero; - Vector3 rotateDirection = Vector3.zero; - Vector3 quickStop = Vector3.zero; - - if (_isGrounded) - { - switch (actionForward) - { - case 1: - directionToGo = transform.forward * 1f; - break; - case 2: - directionToGo = transform.forward * -1f; - break; - case 0: // Slow down faster than drag with no input - quickStop = _rigidBody.velocity * quickStopRatio; - _rigidBody.velocity = quickStop; - break; - } - } - - switch (actionRotate) - { - case 1: - rotateDirection = transform.up * 1f; - break; - case 2: - rotateDirection = transform.up * -1f; - break; - } - - transform.Rotate(rotateDirection, Time.fixedDeltaTime * rotationSpeed); - _rigidBody.AddForce( - directionToGo.normalized * speed * 100f * Time.fixedDeltaTime, - ForceMode.Acceleration - ); - } - - public override void Heuristic(in ActionBuffers actionsOut) - { - var discreteActionsOut = actionsOut.DiscreteActions; - discreteActionsOut[0] = 0; - discreteActionsOut[1] = 0; - if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow)) - { - discreteActionsOut[0] = 1; - } - if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow)) - { - discreteActionsOut[0] = 2; - } - if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow)) - { - discreteActionsOut[1] = 1; - } - if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow)) - { - discreteActionsOut[1] = 2; - } - } - - public void UpdateHealthNextStep(float updateAmount, bool andCompleteArena = false) - { - /// - /// ML-Agents doesn't guarantee behaviour if an episode ends outside of OnActionReceived - /// Therefore we queue any health updates to happen on the next action step. - /// - _nextUpdateHealth += updateAmount; - if (andCompleteArena) - { - _nextUpdateCompleteArena = true; - } - } - - public void UpdateHealth(float updateAmount, bool andCompleteArena = false) - { - if (NotificationManager.Instance == null && showNotification == true) - { - Debug.LogError("NotificationManager instance is not set."); - return; - } - /// - /// Update the health of the agent and reset any queued updates - /// If health reaches 0 or the episode is queued to end then call EndEpisode(). - /// - if (!IsFrozen()) - { - health += 100 * updateAmount; - health += 100 * _nextUpdateHealth; - _nextUpdateHealth = 0; - AddReward(updateAmount); - } - _currentScore = GetCumulativeReward(); - if (health > _maxHealth) - { - health = _maxHealth; - } - else if (health <= 0) - { - health = 0; - if (showNotification) - { - NotificationManager.Instance.ShowFailureNotification(); - } - StartCoroutine(EndEpisodeAfterDelay()); - return; - } - if (andCompleteArena || _nextUpdateCompleteArena) - { - _nextUpdateCompleteArena = false; - float cumulativeReward = this.GetCumulativeReward(); - - if (cumulativeReward >= Arena.CurrentPassMark) - { - // If passed and the next arena is merged load that without ending the episode - if (_arena.mergeNextArena) - { - _arena.LoadNextArena(); - return; - } - if (showNotification) - { - NotificationManager.Instance.ShowSuccessNotification(); - } - } - else - { - if (showNotification) - { - NotificationManager.Instance.ShowFailureNotification(); - } - } - StartCoroutine(EndEpisodeAfterDelay()); - } - } - - public void AddExtraReward(float rewardFactor) - { - UpdateHealth(Math.Min(rewardFactor * _rewardPerStep, -0.001f)); - } - - IEnumerator EndEpisodeAfterDelay() - { - if (!showNotification) - { - EndEpisode(); - yield break; - } - - yield return new WaitForSeconds(2.5f); - NotificationManager.Instance.HideNotification(); - EndEpisode(); - } - - public override void OnEpisodeBegin() - { - writer.WriteLine($"\nNew Episode,{Academy.Instance.EpisodeCount}-----"); - writer.Flush(); - EpisodeDebugLog(); - - StopCoroutine("UnfreezeCountdown"); - _previousScore = _currentScore; - numberOfGoalsCollected = 0; - _arena.ResetArena(); - _rewardPerStep = timeLimit > 0 ? -1f / timeLimit : 0; - _isGrounded = false; - health = _maxHealth; - - SetFreezeDelay(GetFreezeDelay()); - } - - private void EpisodeDebugLog() - { - Debug.Log("Episode Begin"); - Debug.Log($"Value of showNotification: {showNotification}"); - Debug.Log("Current Pass Mark: " + Arena.CurrentPassMark); - Debug.Log("Number of Goals Collected: " + numberOfGoalsCollected); - } - - void OnCollisionEnter(Collision collision) - { - foreach (ContactPoint contact in collision.contacts) - { - if (contact.normal.y > 0) - { - _isGrounded = true; - } - } - _lastContactPoint = collision.contacts.Last(); - } - - void OnCollisionStay(Collision collision) - { - foreach (ContactPoint contact in collision.contacts) - { - if (contact.normal.y > 0) - { - _isGrounded = true; - } - } - _lastContactPoint = collision.contacts.Last(); - } - - void OnCollisionExit(Collision collision) - { - if (_lastContactPoint.normal.y > 0) - { - _isGrounded = false; - } - } - - //****************************** - //PREFAB INTERFACE FOR THE AGENT - //****************************** - public void SetColor(Vector3 color) { } - - public void SetSize(Vector3 scale) { } - - /// - /// Returns a random position within the range for the object. - /// - public virtual Vector3 GetPosition( - Vector3 position, - Vector3 boundingBox, - float rangeX, - float rangeZ - ) - { - float xBound = boundingBox.x; - float zBound = boundingBox.z; - float xOut = - position.x < 0 - ? Random.Range(xBound, rangeX - xBound) - : Math.Max(0, Math.Min(position.x, rangeX)); - float yOut = Math.Max(position.y, 0) + transform.localScale.y / 2 + 0.01f; - float zOut = - position.z < 0 - ? Random.Range(zBound, rangeZ - zBound) - : Math.Max(0, Math.Min(position.z, rangeZ)); - - return new Vector3(xOut, yOut, zOut); - } - - /// - /// If rotationY set to < 0 change to random rotation. - /// - public virtual Vector3 GetRotation(float rotationY) - { - return new Vector3(0, rotationY < 0 ? Random.Range(0f, 360f) : rotationY, 0); - } + [Header("Agent Settings")] + public float speed = 25f; + public float quickStopRatio = 0.9f; + public float rotationSpeed = 100f; + public float rotationAngle = 0.25f; + + private int lastActionForward = 0; + private int lastActionRotate = 0; + + [Header("Agent State / Other Variables")] + [HideInInspector] + public int numberOfGoalsCollected = 0; + + [HideInInspector] + public ProgressBar progBar; + private Rigidbody _rigidBody; + private bool _isGrounded; + private ContactPoint _lastContactPoint; + + [Header("Agent Rewards & Score")] + private float _rewardPerStep; + private float _previousScore = 0; + private float _currentScore = 0; + + [Header("Agent Health")] + public float health = 100f; + private float _maxHealth = 100f; + + [Header("Agent Freeze & Countdown")] + public float timeLimit = 0f; + private float _nextUpdateHealth = 0f; + private float _freezeDelay = 0f; + private bool _isFrozen = false; + + private bool _nextUpdateCompleteArena = false; + + [Header("Agent Notification")] + public bool showNotification = false; + private TrainingArena _arena; + private bool _isCountdownActive = false; + + [Header("CSV Logging")] + public string csvFilePath = "Observations.csv"; + private StreamWriter writer; + private bool headerWritten = false; + private string yamlFileName = ""; + + public override void Initialize() + { + _arena = GetComponentInParent(); + _rigidBody = GetComponent(); + _rewardPerStep = timeLimit > 0 ? -1f / timeLimit : 0; + progBar = GameObject.Find("UI ProgressBar").GetComponent(); + progBar.AssignAgent(this); + health = _maxHealth; + + InitialiseCSVProcess(); + + if (!Application.isEditor) + { + AAI3EnvironmentManager envManager = FindObjectOfType(); + if (envManager != null) + { + SetYamlFileName(envManager.GetCurrentYamlFileName()); + } + } + } + + public void SetYamlFileName(string fileName) + { + yamlFileName = Path.GetFileNameWithoutExtension(fileName); + Debug.Log($"Set YAML file name: {yamlFileName}"); + } + + private void InitialiseCSVProcess() + { + // Base path for the logs to be stored + string basePath; + + if (Application.isEditor) + { + // The root directory is the parent of the Assets folder + basePath = Path.GetFullPath(Path.Combine(Application.dataPath, "..")); + } + else + { + // Important! For builds, use the parent of the directory where the executable resides + basePath = Path.GetDirectoryName(Application.dataPath); + } + + // Folder for the CSV logs + string directoryPath = Path.Combine(basePath, "ObservationLogs"); + + // Simple check to see if the directory exists, if not create it + if (!Directory.Exists(directoryPath)) + { + Directory.CreateDirectory(directoryPath); + } + + // Generate a filename with a date stamp - this will be unique for each run + string dateTimeString = DateTime.Now.ToString("dd-MM-yy_HHmm"); + string filename = Application.isEditor + ? $"Observations_{yamlFileName}_{dateTimeString}.csv" + : $"Observations_{dateTimeString}.csv"; + csvFilePath = Path.Combine(directoryPath, filename); + + writer = new StreamWriter(csvFilePath, true); + if (!File.Exists(csvFilePath) || new FileInfo(csvFilePath).Length == 0) + { + // Attribute headers for the CSV file --> can be changed as needed + writer.WriteLine( + "Episode,Step,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate" + ); + headerWritten = true; + } + } + + private void LogToCSV( + Vector3 velocity, + Vector3 position, + int lastActionForward, + int lastActionRotate + ) + { + writer.WriteLine( + $"{Academy.Instance.EpisodeCount},{StepCount},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate}" + ); + writer.Flush(); + } + + protected override void OnDisable() + { + base.OnDisable(); + if (writer != null) + { + writer.Flush(); + writer.Close(); + } + } + + public float GetPreviousScore() + { + return _previousScore; + } + + public float GetFreezeDelay() + { + return _freezeDelay; + } + + public void SetFreezeDelay(float v) + { + _freezeDelay = Mathf.Clamp(v, 0f, v); + if (v != 0f && !_isCountdownActive) + { + Debug.Log( + "Starting coroutine UnfreezeCountdown() with wait seconds == " + GetFreezeDelay() + ); + StartCoroutine(UnfreezeCountdown()); + } + } + + public bool IsFrozen() + { + return _freezeDelay > 0f || _isFrozen; + } + + public void FreezeAgent(bool freeze) + { + _isFrozen = freeze; + if (_isFrozen) + { + _rigidBody.velocity = Vector3.zero; + _rigidBody.angularVelocity = Vector3.zero; + } + } + + private IEnumerator UnfreezeCountdown() + { + _isCountdownActive = true; + yield return new WaitForSeconds(GetFreezeDelay()); + + Debug.Log("unfreezing!"); + SetFreezeDelay(0f); + _isCountdownActive = false; + } + + public override void CollectObservations(VectorSensor sensor) + { + sensor.AddObservation(health); + Vector3 localVel = transform.InverseTransformDirection(_rigidBody.velocity); + sensor.AddObservation(localVel); + Vector3 localPos = transform.position; + sensor.AddObservation(localPos); + LogToCSV(localVel, localPos, lastActionForward, lastActionRotate); + } + + public override void OnActionReceived(ActionBuffers action) + { + lastActionForward = Mathf.FloorToInt(action.DiscreteActions[0]); + lastActionRotate = Mathf.FloorToInt(action.DiscreteActions[1]); + if (!IsFrozen()) + { + MoveAgent(lastActionForward, lastActionRotate); + } + + Vector3 localVel = transform.InverseTransformDirection(_rigidBody.velocity); + Vector3 localPos = transform.position; + LogToCSV(localVel, localPos, lastActionForward, lastActionRotate); + UpdateHealth(_rewardPerStep); + } + + private void MoveAgent(int actionForward, int actionRotate) + { + if (IsFrozen()) + { + // If the agent is frozen, stop all movement and rotation + _rigidBody.velocity = Vector3.zero; + _rigidBody.angularVelocity = Vector3.zero; + return; + } + + Vector3 directionToGo = Vector3.zero; + Vector3 rotateDirection = Vector3.zero; + Vector3 quickStop = Vector3.zero; + + if (_isGrounded) + { + switch (actionForward) + { + case 1: + directionToGo = transform.forward * 1f; + break; + case 2: + directionToGo = transform.forward * -1f; + break; + case 0: // Slow down faster than drag with no input + quickStop = _rigidBody.velocity * quickStopRatio; + _rigidBody.velocity = quickStop; + break; + } + } + + switch (actionRotate) + { + case 1: + rotateDirection = transform.up * 1f; + break; + case 2: + rotateDirection = transform.up * -1f; + break; + } + + transform.Rotate(rotateDirection, Time.fixedDeltaTime * rotationSpeed); + _rigidBody.AddForce( + directionToGo.normalized * speed * 100f * Time.fixedDeltaTime, + ForceMode.Acceleration + ); + } + + public override void Heuristic(in ActionBuffers actionsOut) + { + var discreteActionsOut = actionsOut.DiscreteActions; + discreteActionsOut[0] = 0; + discreteActionsOut[1] = 0; + if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow)) + { + discreteActionsOut[0] = 1; + } + if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow)) + { + discreteActionsOut[0] = 2; + } + if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow)) + { + discreteActionsOut[1] = 1; + } + if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow)) + { + discreteActionsOut[1] = 2; + } + } + + public void UpdateHealthNextStep(float updateAmount, bool andCompleteArena = false) + { + /// + /// ML-Agents doesn't guarantee behaviour if an episode ends outside of OnActionReceived + /// Therefore we queue any health updates to happen on the next action step. + /// + _nextUpdateHealth += updateAmount; + if (andCompleteArena) + { + _nextUpdateCompleteArena = true; + } + } + + public void UpdateHealth(float updateAmount, bool andCompleteArena = false) + { + if (NotificationManager.Instance == null && showNotification == true) + { + Debug.LogError("NotificationManager instance is not set."); + return; + } + /// + /// Update the health of the agent and reset any queued updates + /// If health reaches 0 or the episode is queued to end then call EndEpisode(). + /// + if (!IsFrozen()) + { + health += 100 * updateAmount; + health += 100 * _nextUpdateHealth; + _nextUpdateHealth = 0; + AddReward(updateAmount); + } + _currentScore = GetCumulativeReward(); + if (health > _maxHealth) + { + health = _maxHealth; + } + else if (health <= 0) + { + health = 0; + if (showNotification) + { + NotificationManager.Instance.ShowFailureNotification(); + } + StartCoroutine(EndEpisodeAfterDelay()); + return; + } + if (andCompleteArena || _nextUpdateCompleteArena) + { + _nextUpdateCompleteArena = false; + float cumulativeReward = this.GetCumulativeReward(); + + if (cumulativeReward >= Arena.CurrentPassMark) + { + // If passed and the next arena is merged load that without ending the episode + if (_arena.mergeNextArena) + { + _arena.LoadNextArena(); + return; + } + if (showNotification) + { + NotificationManager.Instance.ShowSuccessNotification(); + } + } + else + { + if (showNotification) + { + NotificationManager.Instance.ShowFailureNotification(); + } + } + StartCoroutine(EndEpisodeAfterDelay()); + } + } + + public void AddExtraReward(float rewardFactor) + { + UpdateHealth(Math.Min(rewardFactor * _rewardPerStep, -0.001f)); + } + + IEnumerator EndEpisodeAfterDelay() + { + if (!showNotification) + { + EndEpisode(); + yield break; + } + + yield return new WaitForSeconds(2.5f); + NotificationManager.Instance.HideNotification(); + EndEpisode(); + } + + public override void OnEpisodeBegin() + { + writer.WriteLine($"\nNew Episode,{Academy.Instance.EpisodeCount}-----"); + writer.Flush(); + EpisodeDebugLog(); + + StopCoroutine("UnfreezeCountdown"); + _previousScore = _currentScore; + numberOfGoalsCollected = 0; + _arena.ResetArena(); + _rewardPerStep = timeLimit > 0 ? -1f / timeLimit : 0; + _isGrounded = false; + health = _maxHealth; + + SetFreezeDelay(GetFreezeDelay()); + } + + private void EpisodeDebugLog() + { + Debug.Log("Episode Begin"); + Debug.Log($"Value of showNotification: {showNotification}"); + Debug.Log("Current Pass Mark: " + Arena.CurrentPassMark); + Debug.Log("Number of Goals Collected: " + numberOfGoalsCollected); + } + + void OnCollisionEnter(Collision collision) + { + foreach (ContactPoint contact in collision.contacts) + { + if (contact.normal.y > 0) + { + _isGrounded = true; + } + } + _lastContactPoint = collision.contacts.Last(); + } + + void OnCollisionStay(Collision collision) + { + foreach (ContactPoint contact in collision.contacts) + { + if (contact.normal.y > 0) + { + _isGrounded = true; + } + } + _lastContactPoint = collision.contacts.Last(); + } + + void OnCollisionExit(Collision collision) + { + if (_lastContactPoint.normal.y > 0) + { + _isGrounded = false; + } + } + + //****************************** + //PREFAB INTERFACE FOR THE AGENT + //****************************** + public void SetColor(Vector3 color) { } + + public void SetSize(Vector3 scale) { } + + /// + /// Returns a random position within the range for the object. + /// + public virtual Vector3 GetPosition( + Vector3 position, + Vector3 boundingBox, + float rangeX, + float rangeZ + ) + { + float xBound = boundingBox.x; + float zBound = boundingBox.z; + float xOut = + position.x < 0 + ? Random.Range(xBound, rangeX - xBound) + : Math.Max(0, Math.Min(position.x, rangeX)); + float yOut = Math.Max(position.y, 0) + transform.localScale.y / 2 + 0.01f; + float zOut = + position.z < 0 + ? Random.Range(zBound, rangeZ - zBound) + : Math.Max(0, Math.Min(position.z, rangeZ)); + + return new Vector3(xOut, yOut, zOut); + } + + /// + /// If rotationY set to < 0 change to random rotation. + /// + public virtual Vector3 GetRotation(float rotationY) + { + return new Vector3(0, rotationY < 0 ? Random.Range(0f, 360f) : rotationY, 0); + } } From ae1280f0d410eea8a8ec7a8b3de12b185e9198a9 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Mon, 3 Jun 2024 21:30:43 +0100 Subject: [PATCH 026/205] Update ArenasParametersSideChannel.cs --- Assets/Scripts/ArenasParametersSideChannel.cs | 106 ++++++++---------- 1 file changed, 48 insertions(+), 58 deletions(-) diff --git a/Assets/Scripts/ArenasParametersSideChannel.cs b/Assets/Scripts/ArenasParametersSideChannel.cs index e7e27e49..cb80e561 100644 --- a/Assets/Scripts/ArenasParametersSideChannel.cs +++ b/Assets/Scripts/ArenasParametersSideChannel.cs @@ -8,62 +8,52 @@ /// public class ArenasParametersSideChannel : SideChannel { - public string CurrentYamlFileName { get; private set; } // Store the current YAML file name - - /// - /// Initializes a new instance of the ArenasParametersSideChannel class. - /// - public ArenasParametersSideChannel() - { - ChannelId = new Guid("9c36c837-cad5-498a-b675-bc19c9370072"); - } - - /// - /// This method is called when a message is received from the Unity. - /// - protected override void OnMessageReceived(IncomingMessage msg) - { - string fileName = msg.ReadString(); - byte[] yamlData = msg.GetRawBytes(); - - Debug.Log($"Received YAML file name: {fileName}"); - CurrentYamlFileName = fileName; - - // Create the event args including the file name and the YAML data - ArenasParametersEventArgs args = new ArenasParametersEventArgs - { - arenas_yaml = yamlData, - yamlFileName = fileName - }; - OnArenasParametersReceived(args); - UpdateTrainingAgentsWithYamlFileName(fileName); - } - - /// - /// This method is called when the arenas parameters are received. - /// - protected virtual void OnArenasParametersReceived( - ArenasParametersEventArgs arenasParametersEvent - ) - { - EventHandler handler = NewArenasParametersReceived; - if (handler != null) - { - handler(this, arenasParametersEvent); - } - } - - private void UpdateTrainingAgentsWithYamlFileName(string fileName) - { - TrainingAgent[] agents = GameObject.FindObjectsOfType(); - foreach (var agent in agents) - { - agent.SetYamlFileName(fileName); - } - } - - /// - /// This event is triggered when new arenas parameters are received. - /// - public EventHandler NewArenasParametersReceived; + public string CurrentYamlFileName { get; private set; } // Store the current YAML file name + + /// + /// Initializes a new instance of the ArenasParametersSideChannel class. + /// + public ArenasParametersSideChannel() + { + ChannelId = new Guid("9c36c837-cad5-498a-b675-bc19c9370072"); + } + + /// + /// This method is called when a message is received from the Unity. + /// + protected override void OnMessageReceived(IncomingMessage msg) + { + string fileName = msg.ReadString(); + byte[] yamlData = msg.GetRawBytes(); + + Debug.Log($"Received YAML file name: {fileName}"); + CurrentYamlFileName = fileName; + + // Create the event args including the file name and the YAML data + ArenasParametersEventArgs args = new ArenasParametersEventArgs + { + arenas_yaml = yamlData, + yamlFileName = fileName + }; + OnArenasParametersReceived(args); + } + + /// + /// This method is called when the arenas parameters are received. + /// + protected virtual void OnArenasParametersReceived( + ArenasParametersEventArgs arenasParametersEvent + ) + { + EventHandler handler = NewArenasParametersReceived; + if (handler != null) + { + handler(this, arenasParametersEvent); + } + } + + /// + /// This event is triggered when new arenas parameters are received. + /// + public EventHandler NewArenasParametersReceived; } From f5b96b7e869e0fb5e5fd21f23de7f6fd0d8c9e28 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Mon, 3 Jun 2024 21:31:00 +0100 Subject: [PATCH 027/205] Update TrainingAgent.cs --- Assets/Scripts/TrainingAgent.cs | 939 ++++++++++++++++---------------- 1 file changed, 467 insertions(+), 472 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 1016cca5..636c9061 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -17,476 +17,471 @@ /// public class TrainingAgent : Agent, IPrefab { - [Header("Agent Settings")] - public float speed = 25f; - public float quickStopRatio = 0.9f; - public float rotationSpeed = 100f; - public float rotationAngle = 0.25f; - - private int lastActionForward = 0; - private int lastActionRotate = 0; - - [Header("Agent State / Other Variables")] - [HideInInspector] - public int numberOfGoalsCollected = 0; - - [HideInInspector] - public ProgressBar progBar; - private Rigidbody _rigidBody; - private bool _isGrounded; - private ContactPoint _lastContactPoint; - - [Header("Agent Rewards & Score")] - private float _rewardPerStep; - private float _previousScore = 0; - private float _currentScore = 0; - - [Header("Agent Health")] - public float health = 100f; - private float _maxHealth = 100f; - - [Header("Agent Freeze & Countdown")] - public float timeLimit = 0f; - private float _nextUpdateHealth = 0f; - private float _freezeDelay = 0f; - private bool _isFrozen = false; - - private bool _nextUpdateCompleteArena = false; - - [Header("Agent Notification")] - public bool showNotification = false; - private TrainingArena _arena; - private bool _isCountdownActive = false; - - [Header("CSV Logging")] - public string csvFilePath = "Observations.csv"; - private StreamWriter writer; - private bool headerWritten = false; - private string yamlFileName = ""; - - public override void Initialize() - { - _arena = GetComponentInParent(); - _rigidBody = GetComponent(); - _rewardPerStep = timeLimit > 0 ? -1f / timeLimit : 0; - progBar = GameObject.Find("UI ProgressBar").GetComponent(); - progBar.AssignAgent(this); - health = _maxHealth; - - InitialiseCSVProcess(); - - if (!Application.isEditor) - { - AAI3EnvironmentManager envManager = FindObjectOfType(); - if (envManager != null) - { - SetYamlFileName(envManager.GetCurrentYamlFileName()); - } - } - } - - public void SetYamlFileName(string fileName) - { - yamlFileName = Path.GetFileNameWithoutExtension(fileName); - Debug.Log($"Set YAML file name: {yamlFileName}"); - } - - private void InitialiseCSVProcess() - { - // Base path for the logs to be stored - string basePath; - - if (Application.isEditor) - { - // The root directory is the parent of the Assets folder - basePath = Path.GetFullPath(Path.Combine(Application.dataPath, "..")); - } - else - { - // Important! For builds, use the parent of the directory where the executable resides - basePath = Path.GetDirectoryName(Application.dataPath); - } - - // Folder for the CSV logs - string directoryPath = Path.Combine(basePath, "ObservationLogs"); - - // Simple check to see if the directory exists, if not create it - if (!Directory.Exists(directoryPath)) - { - Directory.CreateDirectory(directoryPath); - } - - // Generate a filename with a date stamp - this will be unique for each run - string dateTimeString = DateTime.Now.ToString("dd-MM-yy_HHmm"); - string filename = Application.isEditor - ? $"Observations_{yamlFileName}_{dateTimeString}.csv" - : $"Observations_{dateTimeString}.csv"; - csvFilePath = Path.Combine(directoryPath, filename); - - writer = new StreamWriter(csvFilePath, true); - if (!File.Exists(csvFilePath) || new FileInfo(csvFilePath).Length == 0) - { - // Attribute headers for the CSV file --> can be changed as needed - writer.WriteLine( - "Episode,Step,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate" - ); - headerWritten = true; - } - } - - private void LogToCSV( - Vector3 velocity, - Vector3 position, - int lastActionForward, - int lastActionRotate - ) - { - writer.WriteLine( - $"{Academy.Instance.EpisodeCount},{StepCount},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate}" - ); - writer.Flush(); - } - - protected override void OnDisable() - { - base.OnDisable(); - if (writer != null) - { - writer.Flush(); - writer.Close(); - } - } - - public float GetPreviousScore() - { - return _previousScore; - } - - public float GetFreezeDelay() - { - return _freezeDelay; - } - - public void SetFreezeDelay(float v) - { - _freezeDelay = Mathf.Clamp(v, 0f, v); - if (v != 0f && !_isCountdownActive) - { - Debug.Log( - "Starting coroutine UnfreezeCountdown() with wait seconds == " + GetFreezeDelay() - ); - StartCoroutine(UnfreezeCountdown()); - } - } - - public bool IsFrozen() - { - return _freezeDelay > 0f || _isFrozen; - } - - public void FreezeAgent(bool freeze) - { - _isFrozen = freeze; - if (_isFrozen) - { - _rigidBody.velocity = Vector3.zero; - _rigidBody.angularVelocity = Vector3.zero; - } - } - - private IEnumerator UnfreezeCountdown() - { - _isCountdownActive = true; - yield return new WaitForSeconds(GetFreezeDelay()); - - Debug.Log("unfreezing!"); - SetFreezeDelay(0f); - _isCountdownActive = false; - } - - public override void CollectObservations(VectorSensor sensor) - { - sensor.AddObservation(health); - Vector3 localVel = transform.InverseTransformDirection(_rigidBody.velocity); - sensor.AddObservation(localVel); - Vector3 localPos = transform.position; - sensor.AddObservation(localPos); - LogToCSV(localVel, localPos, lastActionForward, lastActionRotate); - } - - public override void OnActionReceived(ActionBuffers action) - { - lastActionForward = Mathf.FloorToInt(action.DiscreteActions[0]); - lastActionRotate = Mathf.FloorToInt(action.DiscreteActions[1]); - if (!IsFrozen()) - { - MoveAgent(lastActionForward, lastActionRotate); - } - - Vector3 localVel = transform.InverseTransformDirection(_rigidBody.velocity); - Vector3 localPos = transform.position; - LogToCSV(localVel, localPos, lastActionForward, lastActionRotate); - UpdateHealth(_rewardPerStep); - } - - private void MoveAgent(int actionForward, int actionRotate) - { - if (IsFrozen()) - { - // If the agent is frozen, stop all movement and rotation - _rigidBody.velocity = Vector3.zero; - _rigidBody.angularVelocity = Vector3.zero; - return; - } - - Vector3 directionToGo = Vector3.zero; - Vector3 rotateDirection = Vector3.zero; - Vector3 quickStop = Vector3.zero; - - if (_isGrounded) - { - switch (actionForward) - { - case 1: - directionToGo = transform.forward * 1f; - break; - case 2: - directionToGo = transform.forward * -1f; - break; - case 0: // Slow down faster than drag with no input - quickStop = _rigidBody.velocity * quickStopRatio; - _rigidBody.velocity = quickStop; - break; - } - } - - switch (actionRotate) - { - case 1: - rotateDirection = transform.up * 1f; - break; - case 2: - rotateDirection = transform.up * -1f; - break; - } - - transform.Rotate(rotateDirection, Time.fixedDeltaTime * rotationSpeed); - _rigidBody.AddForce( - directionToGo.normalized * speed * 100f * Time.fixedDeltaTime, - ForceMode.Acceleration - ); - } - - public override void Heuristic(in ActionBuffers actionsOut) - { - var discreteActionsOut = actionsOut.DiscreteActions; - discreteActionsOut[0] = 0; - discreteActionsOut[1] = 0; - if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow)) - { - discreteActionsOut[0] = 1; - } - if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow)) - { - discreteActionsOut[0] = 2; - } - if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow)) - { - discreteActionsOut[1] = 1; - } - if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow)) - { - discreteActionsOut[1] = 2; - } - } - - public void UpdateHealthNextStep(float updateAmount, bool andCompleteArena = false) - { - /// - /// ML-Agents doesn't guarantee behaviour if an episode ends outside of OnActionReceived - /// Therefore we queue any health updates to happen on the next action step. - /// - _nextUpdateHealth += updateAmount; - if (andCompleteArena) - { - _nextUpdateCompleteArena = true; - } - } - - public void UpdateHealth(float updateAmount, bool andCompleteArena = false) - { - if (NotificationManager.Instance == null && showNotification == true) - { - Debug.LogError("NotificationManager instance is not set."); - return; - } - /// - /// Update the health of the agent and reset any queued updates - /// If health reaches 0 or the episode is queued to end then call EndEpisode(). - /// - if (!IsFrozen()) - { - health += 100 * updateAmount; - health += 100 * _nextUpdateHealth; - _nextUpdateHealth = 0; - AddReward(updateAmount); - } - _currentScore = GetCumulativeReward(); - if (health > _maxHealth) - { - health = _maxHealth; - } - else if (health <= 0) - { - health = 0; - if (showNotification) - { - NotificationManager.Instance.ShowFailureNotification(); - } - StartCoroutine(EndEpisodeAfterDelay()); - return; - } - if (andCompleteArena || _nextUpdateCompleteArena) - { - _nextUpdateCompleteArena = false; - float cumulativeReward = this.GetCumulativeReward(); - - if (cumulativeReward >= Arena.CurrentPassMark) - { - // If passed and the next arena is merged load that without ending the episode - if (_arena.mergeNextArena) - { - _arena.LoadNextArena(); - return; - } - if (showNotification) - { - NotificationManager.Instance.ShowSuccessNotification(); - } - } - else - { - if (showNotification) - { - NotificationManager.Instance.ShowFailureNotification(); - } - } - StartCoroutine(EndEpisodeAfterDelay()); - } - } - - public void AddExtraReward(float rewardFactor) - { - UpdateHealth(Math.Min(rewardFactor * _rewardPerStep, -0.001f)); - } - - IEnumerator EndEpisodeAfterDelay() - { - if (!showNotification) - { - EndEpisode(); - yield break; - } - - yield return new WaitForSeconds(2.5f); - NotificationManager.Instance.HideNotification(); - EndEpisode(); - } - - public override void OnEpisodeBegin() - { - writer.WriteLine($"\nNew Episode,{Academy.Instance.EpisodeCount}-----"); - writer.Flush(); - EpisodeDebugLog(); - - StopCoroutine("UnfreezeCountdown"); - _previousScore = _currentScore; - numberOfGoalsCollected = 0; - _arena.ResetArena(); - _rewardPerStep = timeLimit > 0 ? -1f / timeLimit : 0; - _isGrounded = false; - health = _maxHealth; - - SetFreezeDelay(GetFreezeDelay()); - } - - private void EpisodeDebugLog() - { - Debug.Log("Episode Begin"); - Debug.Log($"Value of showNotification: {showNotification}"); - Debug.Log("Current Pass Mark: " + Arena.CurrentPassMark); - Debug.Log("Number of Goals Collected: " + numberOfGoalsCollected); - } - - void OnCollisionEnter(Collision collision) - { - foreach (ContactPoint contact in collision.contacts) - { - if (contact.normal.y > 0) - { - _isGrounded = true; - } - } - _lastContactPoint = collision.contacts.Last(); - } - - void OnCollisionStay(Collision collision) - { - foreach (ContactPoint contact in collision.contacts) - { - if (contact.normal.y > 0) - { - _isGrounded = true; - } - } - _lastContactPoint = collision.contacts.Last(); - } - - void OnCollisionExit(Collision collision) - { - if (_lastContactPoint.normal.y > 0) - { - _isGrounded = false; - } - } - - //****************************** - //PREFAB INTERFACE FOR THE AGENT - //****************************** - public void SetColor(Vector3 color) { } - - public void SetSize(Vector3 scale) { } - - /// - /// Returns a random position within the range for the object. - /// - public virtual Vector3 GetPosition( - Vector3 position, - Vector3 boundingBox, - float rangeX, - float rangeZ - ) - { - float xBound = boundingBox.x; - float zBound = boundingBox.z; - float xOut = - position.x < 0 - ? Random.Range(xBound, rangeX - xBound) - : Math.Max(0, Math.Min(position.x, rangeX)); - float yOut = Math.Max(position.y, 0) + transform.localScale.y / 2 + 0.01f; - float zOut = - position.z < 0 - ? Random.Range(zBound, rangeZ - zBound) - : Math.Max(0, Math.Min(position.z, rangeZ)); - - return new Vector3(xOut, yOut, zOut); - } - - /// - /// If rotationY set to < 0 change to random rotation. - /// - public virtual Vector3 GetRotation(float rotationY) - { - return new Vector3(0, rotationY < 0 ? Random.Range(0f, 360f) : rotationY, 0); - } + [Header("Agent Settings")] + public float speed = 25f; + public float quickStopRatio = 0.9f; + public float rotationSpeed = 100f; + public float rotationAngle = 0.25f; + + private int lastActionForward = 0; + private int lastActionRotate = 0; + + [Header("Agent State / Other Variables")] + [HideInInspector] + public int numberOfGoalsCollected = 0; + + [HideInInspector] + public ProgressBar progBar; + private Rigidbody _rigidBody; + private bool _isGrounded; + private ContactPoint _lastContactPoint; + + [Header("Agent Rewards & Score")] + private float _rewardPerStep; + private float _previousScore = 0; + private float _currentScore = 0; + + [Header("Agent Health")] + public float health = 100f; + private float _maxHealth = 100f; + + [Header("Agent Freeze & Countdown")] + public float timeLimit = 0f; + private float _nextUpdateHealth = 0f; + private float _freezeDelay = 0f; + private bool _isFrozen = false; + + private bool _nextUpdateCompleteArena = false; + + [Header("Agent Notification")] + public bool showNotification = false; + private TrainingArena _arena; + private bool _isCountdownActive = false; + + [Header("CSV Logging")] + public string csvFilePath = "Observations.csv"; + private StreamWriter writer; + private bool headerWritten = false; + private string yamlFileName; + + public override void Initialize() + { + _arena = GetComponentInParent(); + _rigidBody = GetComponent(); + _rewardPerStep = timeLimit > 0 ? -1f / timeLimit : 0; + progBar = GameObject.Find("UI ProgressBar").GetComponent(); + progBar.AssignAgent(this); + health = _maxHealth; + + InitialiseCSVProcess(); + + if (!Application.isEditor) + { + AAI3EnvironmentManager envManager = FindObjectOfType(); + if (envManager != null) + { + SetYamlFileName(envManager.GetCurrentYamlFileName()); + } + } + } + + private void InitialiseCSVProcess() + { + // Base path for the logs to be stored + string basePath; + + if (Application.isEditor) + { + // The root directory is the parent of the Assets folder + basePath = Path.GetFullPath(Path.Combine(Application.dataPath, "..")); + } + else + { + // Important! For builds, use the parent of the directory where the executable resides + basePath = Path.GetDirectoryName(Application.dataPath); + } + + // Folder for the CSV logs + string directoryPath = Path.Combine(basePath, "ObservationLogs"); + + // Simple check to see if the directory exists, if not create it + if (!Directory.Exists(directoryPath)) + { + Directory.CreateDirectory(directoryPath); + } + + // Generate a filename with the YAML file name and a date stamp + string dateTimeString = DateTime.Now.ToString("dd-MM-yy_HHmm"); + string filename = $"Observations_{yamlFileName}_{dateTimeString}.csv"; + csvFilePath = Path.Combine(directoryPath, filename); + + writer = new StreamWriter(csvFilePath, true); + if (!File.Exists(csvFilePath) || new FileInfo(csvFilePath).Length == 0) + { + // Attribute headers for the CSV file --> can be changed as needed + writer.WriteLine("Episode,Step,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate"); + headerWritten = true; + } + } + + public void SetYamlFileName(string fileName) + { + yamlFileName = fileName; + } + + private void LogToCSV( + Vector3 velocity, + Vector3 position, + int lastActionForward, + int lastActionRotate + ) + { + writer.WriteLine( + $"{Academy.Instance.EpisodeCount},{StepCount},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate}" + ); + writer.Flush(); + } + + protected override void OnDisable() + { + base.OnDisable(); + if (writer != null) + { + writer.Flush(); + writer.Close(); + } + } + + public float GetPreviousScore() + { + return _previousScore; + } + + public float GetFreezeDelay() + { + return _freezeDelay; + } + + public void SetFreezeDelay(float v) + { + _freezeDelay = Mathf.Clamp(v, 0f, v); + if (v != 0f && !_isCountdownActive) + { + Debug.Log( + "Starting coroutine UnfreezeCountdown() with wait seconds == " + GetFreezeDelay() + ); + StartCoroutine(UnfreezeCountdown()); + } + } + + public bool IsFrozen() + { + return _freezeDelay > 0f || _isFrozen; + } + + public void FreezeAgent(bool freeze) + { + _isFrozen = freeze; + if (_isFrozen) + { + _rigidBody.velocity = Vector3.zero; + _rigidBody.angularVelocity = Vector3.zero; + } + } + + private IEnumerator UnfreezeCountdown() + { + _isCountdownActive = true; + yield return new WaitForSeconds(GetFreezeDelay()); + + Debug.Log("unfreezing!"); + SetFreezeDelay(0f); + _isCountdownActive = false; + } + + public override void CollectObservations(VectorSensor sensor) + { + sensor.AddObservation(health); + Vector3 localVel = transform.InverseTransformDirection(_rigidBody.velocity); + sensor.AddObservation(localVel); + Vector3 localPos = transform.position; + sensor.AddObservation(localPos); + LogToCSV(localVel, localPos, lastActionForward, lastActionRotate); + } + + public override void OnActionReceived(ActionBuffers action) + { + lastActionForward = Mathf.FloorToInt(action.DiscreteActions[0]); + lastActionRotate = Mathf.FloorToInt(action.DiscreteActions[1]); + if (!IsFrozen()) + { + MoveAgent(lastActionForward, lastActionRotate); + } + + Vector3 localVel = transform.InverseTransformDirection(_rigidBody.velocity); + Vector3 localPos = transform.position; + LogToCSV(localVel, localPos, lastActionForward, lastActionRotate); + UpdateHealth(_rewardPerStep); + } + + private void MoveAgent(int actionForward, int actionRotate) + { + if (IsFrozen()) + { + // If the agent is frozen, stop all movement and rotation + _rigidBody.velocity = Vector3.zero; + _rigidBody.angularVelocity = Vector3.zero; + return; + } + + Vector3 directionToGo = Vector3.zero; + Vector3 rotateDirection = Vector3.zero; + Vector3 quickStop = Vector3.zero; + + if (_isGrounded) + { + switch (actionForward) + { + case 1: + directionToGo = transform.forward * 1f; + break; + case 2: + directionToGo = transform.forward * -1f; + break; + case 0: // Slow down faster than drag with no input + quickStop = _rigidBody.velocity * quickStopRatio; + _rigidBody.velocity = quickStop; + break; + } + } + + switch (actionRotate) + { + case 1: + rotateDirection = transform.up * 1f; + break; + case 2: + rotateDirection = transform.up * -1f; + break; + } + + transform.Rotate(rotateDirection, Time.fixedDeltaTime * rotationSpeed); + _rigidBody.AddForce( + directionToGo.normalized * speed * 100f * Time.fixedDeltaTime, + ForceMode.Acceleration + ); + } + + public override void Heuristic(in ActionBuffers actionsOut) + { + var discreteActionsOut = actionsOut.DiscreteActions; + discreteActionsOut[0] = 0; + discreteActionsOut[1] = 0; + if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow)) + { + discreteActionsOut[0] = 1; + } + if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow)) + { + discreteActionsOut[0] = 2; + } + if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow)) + { + discreteActionsOut[1] = 1; + } + if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow)) + { + discreteActionsOut[1] = 2; + } + } + + public void UpdateHealthNextStep(float updateAmount, bool andCompleteArena = false) + { + /// + /// ML-Agents doesn't guarantee behaviour if an episode ends outside of OnActionReceived + /// Therefore we queue any health updates to happen on the next action step. + /// + _nextUpdateHealth += updateAmount; + if (andCompleteArena) + { + _nextUpdateCompleteArena = true; + } + } + + public void UpdateHealth(float updateAmount, bool andCompleteArena = false) + { + if (NotificationManager.Instance == null && showNotification == true) + { + Debug.LogError("NotificationManager instance is not set."); + return; + } + /// + /// Update the health of the agent and reset any queued updates + /// If health reaches 0 or the episode is queued to end then call EndEpisode(). + /// + if (!IsFrozen()) + { + health += 100 * updateAmount; + health += 100 * _nextUpdateHealth; + _nextUpdateHealth = 0; + AddReward(updateAmount); + } + _currentScore = GetCumulativeReward(); + if (health > _maxHealth) + { + health = _maxHealth; + } + else if (health <= 0) + { + health = 0; + if (showNotification) + { + NotificationManager.Instance.ShowFailureNotification(); + } + StartCoroutine(EndEpisodeAfterDelay()); + return; + } + if (andCompleteArena || _nextUpdateCompleteArena) + { + _nextUpdateCompleteArena = false; + float cumulativeReward = this.GetCumulativeReward(); + + if (cumulativeReward >= Arena.CurrentPassMark) + { + // If passed and the next arena is merged load that without ending the episode + if (_arena.mergeNextArena) + { + _arena.LoadNextArena(); + return; + } + if (showNotification) + { + NotificationManager.Instance.ShowSuccessNotification(); + } + } + else + { + if (showNotification) + { + NotificationManager.Instance.ShowFailureNotification(); + } + } + StartCoroutine(EndEpisodeAfterDelay()); + } + } + + public void AddExtraReward(float rewardFactor) + { + UpdateHealth(Math.Min(rewardFactor * _rewardPerStep, -0.001f)); + } + + IEnumerator EndEpisodeAfterDelay() + { + if (!showNotification) + { + EndEpisode(); + yield break; + } + + yield return new WaitForSeconds(2.5f); + NotificationManager.Instance.HideNotification(); + EndEpisode(); + } + + public override void OnEpisodeBegin() + { + writer.WriteLine($"\nNew Episode,{Academy.Instance.EpisodeCount}-----"); + writer.Flush(); + EpisodeDebugLog(); + + StopCoroutine("UnfreezeCountdown"); + _previousScore = _currentScore; + numberOfGoalsCollected = 0; + _arena.ResetArena(); + _rewardPerStep = timeLimit > 0 ? -1f / timeLimit : 0; + _isGrounded = false; + health = _maxHealth; + + SetFreezeDelay(GetFreezeDelay()); + } + + private void EpisodeDebugLog() + { + Debug.Log("Episode Begin"); + Debug.Log($"Value of showNotification: {showNotification}"); + Debug.Log("Current Pass Mark: " + Arena.CurrentPassMark); + Debug.Log("Number of Goals Collected: " + numberOfGoalsCollected); + } + + void OnCollisionEnter(Collision collision) + { + foreach (ContactPoint contact in collision.contacts) + { + if (contact.normal.y > 0) + { + _isGrounded = true; + } + } + _lastContactPoint = collision.contacts.Last(); + } + + void OnCollisionStay(Collision collision) + { + foreach (ContactPoint contact in collision.contacts) + { + if (contact.normal.y > 0) + { + _isGrounded = true; + } + } + _lastContactPoint = collision.contacts.Last(); + } + + void OnCollisionExit(Collision collision) + { + if (_lastContactPoint.normal.y > 0) + { + _isGrounded = false; + } + } + + //****************************** + //PREFAB INTERFACE FOR THE AGENT + //****************************** + public void SetColor(Vector3 color) { } + + public void SetSize(Vector3 scale) { } + + /// + /// Returns a random position within the range for the object. + /// + public virtual Vector3 GetPosition( + Vector3 position, + Vector3 boundingBox, + float rangeX, + float rangeZ + ) + { + float xBound = boundingBox.x; + float zBound = boundingBox.z; + float xOut = + position.x < 0 + ? Random.Range(xBound, rangeX - xBound) + : Math.Max(0, Math.Min(position.x, rangeX)); + float yOut = Math.Max(position.y, 0) + transform.localScale.y / 2 + 0.01f; + float zOut = + position.z < 0 + ? Random.Range(zBound, rangeZ - zBound) + : Math.Max(0, Math.Min(position.z, rangeZ)); + + return new Vector3(xOut, yOut, zOut); + } + + /// + /// If rotationY set to < 0 change to random rotation. + /// + public virtual Vector3 GetRotation(float rotationY) + { + return new Vector3(0, rotationY < 0 ? Random.Range(0f, 360f) : rotationY, 0); + } } From 5ee86fa241d4cccb27a034fe7b9cff9b7a175fdc Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Mon, 3 Jun 2024 21:47:28 +0100 Subject: [PATCH 028/205] added data log for agent freezes tested and confimed --- Assets/Scripts/TrainingAgent.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 636c9061..726bfa26 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -119,7 +119,7 @@ private void InitialiseCSVProcess() if (!File.Exists(csvFilePath) || new FileInfo(csvFilePath).Length == 0) { // Attribute headers for the CSV file --> can be changed as needed - writer.WriteLine("Episode,Step,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate"); + writer.WriteLine("Episode,Step,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate,IsFrozen?"); headerWritten = true; } } @@ -133,11 +133,12 @@ private void LogToCSV( Vector3 velocity, Vector3 position, int lastActionForward, - int lastActionRotate + int lastActionRotate, + bool isFrozen ) { writer.WriteLine( - $"{Academy.Instance.EpisodeCount},{StepCount},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate}" + $"{Academy.Instance.EpisodeCount},{StepCount},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate},{isFrozen}" ); writer.Flush(); } @@ -206,7 +207,8 @@ public override void CollectObservations(VectorSensor sensor) sensor.AddObservation(localVel); Vector3 localPos = transform.position; sensor.AddObservation(localPos); - LogToCSV(localVel, localPos, lastActionForward, lastActionRotate); + bool isFrozen = IsFrozen(); + LogToCSV(localVel, localPos, lastActionForward, lastActionRotate, isFrozen); } public override void OnActionReceived(ActionBuffers action) @@ -220,7 +222,8 @@ public override void OnActionReceived(ActionBuffers action) Vector3 localVel = transform.InverseTransformDirection(_rigidBody.velocity); Vector3 localPos = transform.position; - LogToCSV(localVel, localPos, lastActionForward, lastActionRotate); + bool isFrozen = IsFrozen(); + LogToCSV(localVel, localPos, lastActionForward, lastActionRotate, isFrozen); UpdateHealth(_rewardPerStep); } From f96a547d5d5a99a2f7388df1f4eb0be2fc05f978 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Mon, 3 Jun 2024 22:01:15 +0100 Subject: [PATCH 029/205] added human-readable data to .csv file action movement and rotation --- Assets/Scripts/TrainingAgent.cs | 60 +++++++++++++++++++++++---------- 1 file changed, 43 insertions(+), 17 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 726bfa26..e7ea8f5e 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -85,6 +85,11 @@ public override void Initialize() } } + public void SetYamlFileName(string fileName) + { + yamlFileName = fileName; + } + private void InitialiseCSVProcess() { // Base path for the logs to be stored @@ -118,27 +123,23 @@ private void InitialiseCSVProcess() writer = new StreamWriter(csvFilePath, true); if (!File.Exists(csvFilePath) || new FileInfo(csvFilePath).Length == 0) { - // Attribute headers for the CSV file --> can be changed as needed - writer.WriteLine("Episode,Step,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate,IsFrozen?"); + writer.WriteLine("Episode,Step,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate,ActionForwardDescription,ActionRotateDescription,IsFrozen"); headerWritten = true; } } - public void SetYamlFileName(string fileName) - { - yamlFileName = fileName; - } - private void LogToCSV( - Vector3 velocity, - Vector3 position, - int lastActionForward, - int lastActionRotate, - bool isFrozen + Vector3 velocity, + Vector3 position, + int lastActionForward, + int lastActionRotate, + string actionForwardDescription, + string actionRotateDescription, + bool isFrozen ) { writer.WriteLine( - $"{Academy.Instance.EpisodeCount},{StepCount},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate},{isFrozen}" + $"{Academy.Instance.EpisodeCount},{StepCount},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate},{actionForwardDescription},{actionRotateDescription},{isFrozen}" ); writer.Flush(); } @@ -204,11 +205,11 @@ public override void CollectObservations(VectorSensor sensor) { sensor.AddObservation(health); Vector3 localVel = transform.InverseTransformDirection(_rigidBody.velocity); - sensor.AddObservation(localVel); Vector3 localPos = transform.position; - sensor.AddObservation(localPos); bool isFrozen = IsFrozen(); - LogToCSV(localVel, localPos, lastActionForward, lastActionRotate, isFrozen); + string actionForwardDescription = DescribeActionForward(lastActionForward); + string actionRotateDescription = DescribeActionRotate(lastActionRotate); + LogToCSV(localVel, localPos, lastActionForward, lastActionRotate, actionForwardDescription, actionRotateDescription, isFrozen); } public override void OnActionReceived(ActionBuffers action) @@ -223,10 +224,35 @@ public override void OnActionReceived(ActionBuffers action) Vector3 localVel = transform.InverseTransformDirection(_rigidBody.velocity); Vector3 localPos = transform.position; bool isFrozen = IsFrozen(); - LogToCSV(localVel, localPos, lastActionForward, lastActionRotate, isFrozen); + string actionForwardDescription = DescribeActionForward(lastActionForward); + string actionRotateDescription = DescribeActionRotate(lastActionRotate); + LogToCSV(localVel, localPos, lastActionForward, lastActionRotate, actionForwardDescription, actionRotateDescription, isFrozen); UpdateHealth(_rewardPerStep); } + + private string DescribeActionForward(int actionForward) + { + return actionForward switch + { + 0 => "No Movement", + 1 => "Move Forward", + 2 => "Move Backward", + _ => "Unknown Forward Action" + }; + } + + private string DescribeActionRotate(int actionRotate) + { + return actionRotate switch + { + 0 => "No Rotation", + 1 => "Rotate Right", + 2 => "Rotate Left", + _ => "Unknown Rotation Action" + }; + } + private void MoveAgent(int actionForward, int actionRotate) { if (IsFrozen()) From af4c428c1e62147a6d12cd23d7e401e284b6fd09 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 4 Jun 2024 10:22:34 +0100 Subject: [PATCH 030/205] added reward log --- Assets/Scripts/TrainingAgent.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index e7ea8f5e..ed5e9922 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -123,7 +123,7 @@ private void InitialiseCSVProcess() writer = new StreamWriter(csvFilePath, true); if (!File.Exists(csvFilePath) || new FileInfo(csvFilePath).Length == 0) { - writer.WriteLine("Episode,Step,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate,ActionForwardDescription,ActionRotateDescription,IsFrozen"); + writer.WriteLine("Episode,Step,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate,ActionForwardDescription,ActionRotateDescription,IsFrozen,Reward"); headerWritten = true; } } @@ -135,11 +135,12 @@ private void LogToCSV( int lastActionRotate, string actionForwardDescription, string actionRotateDescription, - bool isFrozen + bool isFrozen, + float reward ) { writer.WriteLine( - $"{Academy.Instance.EpisodeCount},{StepCount},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate},{actionForwardDescription},{actionRotateDescription},{isFrozen}" + $"{Academy.Instance.EpisodeCount},{StepCount},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate},{actionForwardDescription},{actionRotateDescription},{isFrozen},{reward}" ); writer.Flush(); } @@ -209,7 +210,8 @@ public override void CollectObservations(VectorSensor sensor) bool isFrozen = IsFrozen(); string actionForwardDescription = DescribeActionForward(lastActionForward); string actionRotateDescription = DescribeActionRotate(lastActionRotate); - LogToCSV(localVel, localPos, lastActionForward, lastActionRotate, actionForwardDescription, actionRotateDescription, isFrozen); + float reward = GetCumulativeReward(); // Get the cumulative reward + LogToCSV(localVel, localPos, lastActionForward, lastActionRotate, actionForwardDescription, actionRotateDescription, isFrozen, reward); } public override void OnActionReceived(ActionBuffers action) @@ -226,7 +228,8 @@ public override void OnActionReceived(ActionBuffers action) bool isFrozen = IsFrozen(); string actionForwardDescription = DescribeActionForward(lastActionForward); string actionRotateDescription = DescribeActionRotate(lastActionRotate); - LogToCSV(localVel, localPos, lastActionForward, lastActionRotate, actionForwardDescription, actionRotateDescription, isFrozen); + float reward = GetCumulativeReward(); // Get the cumulative reward + LogToCSV(localVel, localPos, lastActionForward, lastActionRotate, actionForwardDescription, actionRotateDescription, isFrozen, reward); UpdateHealth(_rewardPerStep); } From 46940fe770199ef12b18799807f724debc58aa15 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 4 Jun 2024 13:05:08 +0100 Subject: [PATCH 031/205] logging data to csv changes: added end of episode strings in csv after episode ends, added and made changes to get/set values from other scripts for data logging. also simplified and cleaned up a bit on logging. encapsulated bool from trainingarena.cs for robustness --- Assets/Scripts/NotificationManager.cs | 9 + Assets/Scripts/TrainingAgent.cs | 40 ++- Assets/Scripts/TrainingArena.cs | 7 +- .../Observations__04-06-24_1303.csv | 301 ++++++++++++++++++ 4 files changed, 348 insertions(+), 9 deletions(-) create mode 100644 ObservationLogs/Observations__04-06-24_1303.csv diff --git a/Assets/Scripts/NotificationManager.cs b/Assets/Scripts/NotificationManager.cs index afa1d558..38aa5a46 100644 --- a/Assets/Scripts/NotificationManager.cs +++ b/Assets/Scripts/NotificationManager.cs @@ -19,6 +19,7 @@ public class NotificationManager : MonoBehaviour private int currentFrame = 0; private Coroutine gifCoroutine; + private string currentNotificationState = "None"; public TrainingAgent trainingAgent; public GameObject notificationPanel; @@ -59,12 +60,14 @@ public void ShowSuccessNotification() { ShowNotification(true); trainingAgent.FreezeAgent(true); + currentNotificationState = "Success"; } public void ShowFailureNotification() { ShowNotification(false); trainingAgent.FreezeAgent(true); + currentNotificationState = "Failure"; } private void ShowNotification(bool isSuccess) @@ -99,6 +102,12 @@ public void HideNotification() currentFrame = 0; trainingAgent.FreezeAgent(false); + currentNotificationState = "None"; + } + + public string GetCurrentNotificationState() + { + return currentNotificationState; } IEnumerator AnimateSprite(Sprite[] animationFrames) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index ed5e9922..92bd49cc 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -123,7 +123,7 @@ private void InitialiseCSVProcess() writer = new StreamWriter(csvFilePath, true); if (!File.Exists(csvFilePath) || new FileInfo(csvFilePath).Length == 0) { - writer.WriteLine("Episode,Step,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate,ActionForwardDescription,ActionRotateDescription,IsFrozen,Reward"); + writer.WriteLine("Episode,Step,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate,ActionForwardDescription,ActionRotateDescription,IsFrozen,Reward,NotificationState"); headerWritten = true; } } @@ -136,11 +136,12 @@ private void LogToCSV( string actionForwardDescription, string actionRotateDescription, bool isFrozen, - float reward + float reward, + string notificationState ) { writer.WriteLine( - $"{Academy.Instance.EpisodeCount},{StepCount},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate},{actionForwardDescription},{actionRotateDescription},{isFrozen},{reward}" + $"{Academy.Instance.EpisodeCount},{StepCount},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate},{actionForwardDescription},{actionRotateDescription},{isFrozen},{reward},{notificationState}" ); writer.Flush(); } @@ -202,6 +203,16 @@ private IEnumerator UnfreezeCountdown() _isCountdownActive = false; } + private string GetNotificationState() + { + if (NotificationManager.Instance == null) + { + return "None"; + } + + return NotificationManager.Instance.GetCurrentNotificationState(); + } + public override void CollectObservations(VectorSensor sensor) { sensor.AddObservation(health); @@ -210,8 +221,10 @@ public override void CollectObservations(VectorSensor sensor) bool isFrozen = IsFrozen(); string actionForwardDescription = DescribeActionForward(lastActionForward); string actionRotateDescription = DescribeActionRotate(lastActionRotate); - float reward = GetCumulativeReward(); // Get the cumulative reward - LogToCSV(localVel, localPos, lastActionForward, lastActionRotate, actionForwardDescription, actionRotateDescription, isFrozen, reward); + float reward = GetCumulativeReward(); + string notificationState = GetNotificationState(); + + LogToCSV(localVel, localPos, lastActionForward, lastActionRotate, actionForwardDescription, actionRotateDescription, isFrozen, reward, notificationState); } public override void OnActionReceived(ActionBuffers action) @@ -228,8 +241,10 @@ public override void OnActionReceived(ActionBuffers action) bool isFrozen = IsFrozen(); string actionForwardDescription = DescribeActionForward(lastActionForward); string actionRotateDescription = DescribeActionRotate(lastActionRotate); - float reward = GetCumulativeReward(); // Get the cumulative reward - LogToCSV(localVel, localPos, lastActionForward, lastActionRotate, actionForwardDescription, actionRotateDescription, isFrozen, reward); + float reward = GetCumulativeReward(); + string notificationState = GetNotificationState(); + + LogToCSV(localVel, localPos, lastActionForward, lastActionRotate, actionForwardDescription, actionRotateDescription, isFrozen, reward, notificationState); UpdateHealth(_rewardPerStep); } @@ -422,7 +437,16 @@ IEnumerator EndEpisodeAfterDelay() public override void OnEpisodeBegin() { - writer.WriteLine($"\nNew Episode,{Academy.Instance.EpisodeCount}-----"); + if (!_arena.IsFirstArenaReset) // Don't logging for the first initialization + { + writer.WriteLine($"Number of Goals Collected: {numberOfGoalsCollected}"); + writer.WriteLine("---Episode End---"); + writer.Flush(); + } + + numberOfGoalsCollected = 0; + + writer.WriteLine($"\n---New Episode---"); writer.Flush(); EpisodeDebugLog(); diff --git a/Assets/Scripts/TrainingArena.cs b/Assets/Scripts/TrainingArena.cs index 53a0b1a7..ce18f4a6 100644 --- a/Assets/Scripts/TrainingArena.cs +++ b/Assets/Scripts/TrainingArena.cs @@ -42,8 +42,13 @@ public class TrainingArena : MonoBehaviour private List spawnedRewards = new List(); private List playedArenas = new List(); private List _mergedArenas = null; - public bool showNotification { get; set; } + + public bool IsFirstArenaReset + { + get { return isFirstArenaReset; } + set { isFirstArenaReset = value; } + } public bool mergeNextArena { get diff --git a/ObservationLogs/Observations__04-06-24_1303.csv b/ObservationLogs/Observations__04-06-24_1303.csv new file mode 100644 index 00000000..ac99a7c5 --- /dev/null +++ b/ObservationLogs/Observations__04-06-24_1303.csv @@ -0,0 +1,301 @@ +Episode,Step,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate,ActionForwardDescription,ActionRotateDescription,IsFrozen,Reward,NotificationState + +---New Episode--- +1,1,100,0,0,0,10,0.51,20,0,0,No Movement,No Rotation,False,0,None +1,1,100,0,0,0,10,0.51,20,0,0,No Movement,No Rotation,False,0,None +1,2,99.8,0,-0.1709294,0,10,0.5062016,20,0,0,No Movement,No Rotation,False,-0.002,None +1,3,99.60001,0,-0.3198432,0,10,0.4990939,20,0,0,No Movement,No Rotation,False,-0.004,None +1,4,99.40001,0,-0.3637552,0,10,0.4918188,20,0,0,No Movement,No Rotation,False,-0.006,None +1,4,99.40001,0,-0.3273797,0,10,0.4918188,20,0,0,No Movement,No Rotation,False,-0.006,None +1,5,99.20001,0,-0.06547594,0,10,0.4903638,20,0,0,No Movement,No Rotation,False,-0.008,None +1,6,99.00002,0,-0.01309347,0,10,0.4900729,20,0,0,No Movement,No Rotation,False,-0.01,None +1,7,98.80002,0,-0.002908707,0,10,0.4900147,20,0,0,No Movement,No Rotation,False,-0.012,None +1,7,98.80002,0,-0.002617836,0,10,0.4900147,20,0,0,No Movement,No Rotation,False,-0.012,None +1,8,98.60002,0,-0.0005235672,0,10,0.4900031,20,0,0,No Movement,No Rotation,False,-0.014,None +1,9,98.40002,0,-0.0001072884,0,10,0.4900007,20,0,0,No Movement,No Rotation,False,-0.016,None +1,10,98.20003,0,-2.384186E-05,0,10,0.4900002,20,0,0,No Movement,No Rotation,False,-0.018,None +1,10,98.20003,0,-2.145767E-05,0,10,0.4900002,20,0,0,No Movement,No Rotation,False,-0.018,None +1,11,98.00003,0,-4.291534E-06,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.02,None +1,12,97.80003,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.022,None +1,13,97.60004,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.024,None +1,13,97.60004,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.024,None +1,14,97.40004,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.026,None +1,15,97.20004,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.028,None +1,16,97.00005,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.03,None +1,16,97.00005,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.03,None +1,17,96.80005,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.032,None +1,18,96.60005,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.034,None +1,19,96.40005,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.036,None +1,19,96.40005,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.036,None +1,20,96.20006,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.038,None +1,21,96.00006,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.04,None +1,22,95.80006,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.042,None +1,22,95.80006,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.042,None +1,23,95.60007,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.044,None +1,24,95.40007,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.046,None +1,25,95.20007,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.048,None +1,25,95.20007,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.048,None +1,26,95.00008,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.05,None +1,27,94.80008,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.052,None +1,28,94.60008,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.05400001,None +1,28,94.60008,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.05400001,None +1,29,94.40009,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.05600001,None +1,30,94.20009,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.05800001,None +1,31,94.00009,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.06000001,None +1,31,94.00009,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.06000001,None +1,32,93.80009,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.06200001,None +1,33,93.6001,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.064,None +1,34,93.4001,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.066,None +1,34,93.4001,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.066,None +1,35,93.2001,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.068,None +1,36,93.00011,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.06999999,None +1,37,92.80011,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.07199999,None +1,37,92.80011,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.07199999,None +1,38,92.60011,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.07399999,None +1,39,92.40012,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.07599998,None +1,40,92.20012,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.07799998,None +1,40,92.20012,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.07799998,None +1,41,92.00012,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.07999998,None +1,42,91.80013,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.08199997,None +1,43,91.60013,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.08399997,None +1,43,91.60013,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.08399997,None +1,44,91.40013,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.08599997,None +1,45,91.20013,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.08799996,None +1,46,91.00014,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.08999996,None +1,46,91.00014,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.08999996,None +1,47,90.80014,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.09199996,None +1,48,90.60014,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.09399995,None +1,49,90.40015,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.09599995,None +1,49,90.40015,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.09599995,None +1,50,90.20015,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.09799995,None +1,51,90.00015,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.09999994,None +1,52,89.80016,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.1019999,None +1,52,89.80016,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.1019999,None +1,53,89.60016,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.1039999,None +1,54,89.40016,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.1059999,None +1,55,89.20016,0,0,0,10,0.4900001,20,0,0,No Movement,No Rotation,False,-0.1079999,None +1,55,89.20016,0,0,0,10,0.4900001,20,1,0,Move Forward,No Rotation,False,-0.1079999,None +1,56,89.00017,-1.739896E-08,0,0.8540472,10.01708,0.4900001,20,1,0,Move Forward,No Rotation,False,-0.1099999,None +1,57,88.80017,-3.805584E-08,0,1.680765,10.0507,0.4900001,20,1,0,Move Forward,No Rotation,False,-0.1119999,None +1,58,88.60017,5.734287E-08,0,2.481028,10.10032,0.4900001,20,1,0,Move Forward,No Rotation,False,-0.1139999,None +1,58,88.60017,5.734287E-08,0,2.481028,10.10032,0.4900001,20,1,0,Move Forward,No Rotation,False,-0.1139999,None +1,59,88.40018,-8.872973E-08,0,3.255682,10.16543,0.4900001,20,1,0,Move Forward,No Rotation,False,-0.1159999,None +1,60,88.20018,6.61089E-10,0,4.005547,10.24554,0.4900001,20,1,0,Move Forward,No Rotation,False,-0.1179999,None +1,61,88.00018,8.719144E-08,0,4.731416,10.34017,0.4900001,20,1,0,Move Forward,No Rotation,False,-0.1199999,None +1,61,88.00018,8.719144E-08,0,4.731416,10.34017,0.4900001,20,1,0,Move Forward,No Rotation,False,-0.1199999,None +1,62,87.80019,1.709528E-07,0,5.434058,10.44885,0.4900001,20,1,0,Move Forward,No Rotation,False,-0.1219999,None +1,63,87.60019,-2.248033E-07,0,6.114215,10.57113,0.4900001,20,1,0,Move Forward,No Rotation,False,-0.1239999,None +1,64,87.40019,-1.463169E-07,0,6.772607,10.70659,0.4900001,20,1,0,Move Forward,No Rotation,False,-0.1259999,None +1,64,87.40019,-1.463169E-07,0,6.772607,10.70659,0.4900001,20,1,0,Move Forward,No Rotation,False,-0.1259999,None +1,65,87.2002,-7.034203E-08,0,7.409931,10.85478,0.4900001,20,1,0,Move Forward,No Rotation,False,-0.1279999,None +1,66,87.0002,3.201762E-09,0,8.02686,11.01532,0.4900001,20,1,0,Move Forward,No Rotation,False,-0.1299999,None +1,67,86.8002,7.439212E-08,0,8.624048,11.1878,0.4900001,20,1,0,Move Forward,No Rotation,False,-0.1319999,None +1,67,86.8002,0.3009749,0,8.618794,11.1878,0.4900001,20,1,2,Move Forward,Rotate Left,False,-0.1319999,None +1,68,86.6002,0.6419088,0,9.17971,11.37185,0.4900001,20,1,2,Move Forward,Rotate Left,False,-0.1339999,None +1,69,86.40021,0.9871073,0,9.711134,11.56707,0.4900001,20.00067,1,2,Move Forward,Rotate Left,False,-0.1359999,None +1,70,86.20021,0.9784786,0,10.25435,11.77308,0.4900001,20.00264,1,2,Move Forward,Rotate Left,False,-0.1379999,None +1,70,86.20021,1.335754,0,10.21395,11.77308,0.4900001,20.00264,1,2,Move Forward,Rotate Left,False,-0.1379999,None +1,71,86.00021,1.687037,0,10.68904,11.98947,0.4900001,20.00654,1,2,Move Forward,Rotate Left,False,-0.1399999,None +1,72,85.80022,2.040155,0,11.13725,12.21583,0.4900001,20.01294,1,2,Move Forward,Rotate Left,False,-0.1419999,None +1,73,85.60022,1.989448,0,11.63595,12.45173,0.4900001,20.0224,1,2,Move Forward,Rotate Left,False,-0.1439999,None +1,73,85.60022,2.394325,0,11.55943,12.45173,0.4900001,20.0224,1,2,Move Forward,Rotate Left,False,-0.1439999,None +1,74,85.40022,2.748796,0,11.95641,12.69675,0.4900001,20.03547,1,2,Move Forward,Rotate Left,False,-0.1459999,None +1,75,85.20023,3.102846,0,12.32903,12.95044,0.4900001,20.05265,1,2,Move Forward,Rotate Left,False,-0.1479999,None +1,76,85.00023,3.011225,0,12.79099,13.21235,0.4900001,20.07442,1,2,Move Forward,Rotate Left,False,-0.1499999,None +1,76,85.00023,3.45579,0,12.6781,13.21235,0.4900001,20.07442,1,2,Move Forward,Rotate Left,False,-0.1499999,None +1,77,84.80023,3.806978,0,13.00446,13.48202,0.4900001,20.10126,1,2,Move Forward,Rotate Left,False,-0.152,None +1,78,84.60023,4.155798,0,13.30891,13.759,0.4900001,20.1336,1,2,Move Forward,Rotate Left,False,-0.154,None +1,79,84.40024,4.024567,0,13.74107,14.0428,0.4900001,20.17184,1,2,Move Forward,Rotate Left,False,-0.156,None +1,79,84.40024,4.501671,0,13.59225,14.0428,0.4900001,20.17184,1,2,Move Forward,Rotate Left,False,-0.156,None +1,80,84.20024,4.844065,0,13.85528,14.33295,0.4900001,20.2164,1,2,Move Forward,Rotate Left,False,-0.158,None +1,81,84.00024,5.182475,0,14.09878,14.62897,0.4900001,20.26762,1,2,Move Forward,Rotate Left,False,-0.16,None +1,82,83.80025,5.0132,0,14.50732,14.93038,0.4900001,20.32586,1,2,Move Forward,Rotate Left,False,-0.162,None +1,82,83.80025,5.0132,0,14.50732,14.93038,0.4900001,20.32586,1,0,Move Forward,No Rotation,False,-0.162,None +1,83,83.60025,4.817725,0,14.90266,15.23668,0.4900001,20.39145,1,0,Move Forward,No Rotation,False,-0.164,None +1,84,83.40025,4.630518,0,15.28472,15.54772,0.4900001,20.46409,1,0,Move Forward,No Rotation,False,-0.166,None +1,85,83.20026,4.451175,0,15.654,15.86337,0.4900001,20.54354,1,0,Move Forward,No Rotation,False,-0.168,None +1,85,83.20026,4.451175,0,15.654,15.86337,0.4900001,20.54354,1,0,Move Forward,No Rotation,False,-0.168,None +1,86,83.00026,4.279313,0,16.01098,16.18348,0.4900001,20.62953,1,0,Move Forward,No Rotation,False,-0.17,None +1,87,82.80026,4.114575,0,16.35612,16.50792,0.4900001,20.72182,1,0,Move Forward,No Rotation,False,-0.172,None +1,88,82.60027,3.956623,0,16.68984,16.83656,0.4900001,20.82019,1,0,Move Forward,No Rotation,False,-0.174,None +1,88,82.60027,4.536682,0,16.54159,16.83656,0.4900001,20.82019,1,2,Move Forward,Rotate Left,False,-0.174,None +1,89,82.40027,4.982607,0,16.70569,17.16928,0.4900001,20.92441,1,2,Move Forward,Rotate Left,False,-0.176,None +1,90,82.20027,5.417236,0,16.85008,17.5056,0.4900001,21.03484,1,2,Move Forward,Rotate Left,False,-0.178,None +1,91,82.00027,5.24438,0,17.16931,17.84506,0.4900001,21.15182,1,2,Move Forward,Rotate Left,False,-0.18,None +1,91,82.00027,5.840385,0,16.97583,17.84506,0.4900001,21.15182,1,2,Move Forward,Rotate Left,False,-0.18,None +1,92,81.80028,6.251904,0,17.08391,18.18717,0.4900001,21.27566,1,2,Move Forward,Rotate Left,False,-0.182,None +1,93,81.60028,6.651667,0,17.17533,18.53147,0.4900001,21.40665,1,2,Move Forward,Rotate Left,False,-0.184,None +1,94,81.40028,6.433251,0,17.48618,18.87745,0.4900001,21.54505,1,2,Move Forward,Rotate Left,False,-0.186,None +1,94,81.40028,7.039595,0,17.25101,18.87745,0.4900001,21.54505,1,2,Move Forward,Rotate Left,False,-0.186,None +1,95,81.20029,7.415621,0,17.31189,19.22466,0.4900001,21.69108,1,2,Move Forward,Rotate Left,False,-0.188,None +1,96,81.00029,7.779713,0,17.35883,19.57259,0.4900001,21.84497,1,2,Move Forward,Rotate Left,False,-0.19,None +1,97,80.80029,7.519914,0,17.66591,19.92078,0.4900001,22.0069,1,2,Move Forward,Rotate Left,False,-0.192,None +1,97,80.80029,7.519914,0,17.66591,19.92078,0.4900001,22.0069,1,0,Move Forward,No Rotation,False,-0.192,None +1,98,80.6003,7.236696,0,17.96291,20.26872,0.4900001,22.17704,1,0,Move Forward,No Rotation,False,-0.194,None +1,99,80.4003,6.964493,0,18.24963,20.61646,0.4900001,22.35508,1,0,Move Forward,No Rotation,False,-0.196,None +1,100,80.2003,6.702861,0,18.52648,20.96402,0.4900001,22.54073,1,0,Move Forward,No Rotation,False,-0.198,None +1,100,80.2003,6.702861,0,18.52648,20.96402,0.4900001,22.54073,1,0,Move Forward,No Rotation,False,-0.198,None +1,101,80.00031,6.451372,0,18.79386,21.31142,0.4900001,22.73373,1,0,Move Forward,No Rotation,False,-0.2,None +1,102,79.80031,6.209616,0,19.05211,21.65868,0.4900001,22.9338,1,0,Move Forward,No Rotation,False,-0.2020001,None +1,103,79.60031,5.9772,0,19.30159,22.00582,0.4900001,23.14069,1,0,Move Forward,No Rotation,False,-0.2040001,None +1,103,79.60031,5.9772,0,19.30159,22.00582,0.4900001,23.14069,1,0,Move Forward,No Rotation,False,-0.2040001,None +1,104,79.40031,5.753744,0,19.54263,22.35287,0.4900001,23.35415,1,0,Move Forward,No Rotation,False,-0.2060001,None +1,105,79.20032,5.538891,0,19.77553,22.69984,0.4900001,23.57394,1,0,Move Forward,No Rotation,False,-0.2080001,None +1,106,79.00032,5.332292,0,20.00061,23.04675,0.4900001,23.79985,1,0,Move Forward,No Rotation,False,-0.2100001,None +1,106,79.00032,5.332292,0,20.00061,23.04675,0.4900001,23.79985,1,0,Move Forward,No Rotation,False,-0.2100001,None +1,107,78.80032,5.133615,0,20.21814,23.39363,0.4900001,24.03165,1,0,Move Forward,No Rotation,False,-0.2120001,None +1,108,78.60033,4.942544,0,20.42841,23.74047,0.4900001,24.26913,1,0,Move Forward,No Rotation,False,-0.2140001,None +1,108,100,4.710522,1.490116E-08,20.42248,24.08295,0.4900001,24.50905,1,0,Move Forward,No Rotation,False,1.748989,None +Number of Goals Collected: 1 +---Episode End--- + +---New Episode--- +1,1,100,0,0,0,10,0.51,20,1,0,Move Forward,No Rotation,False,0,None +1,1,100,0,0,0,10,0.51,20,1,0,Move Forward,No Rotation,False,0,None +1,2,99.8,-3.814712E-09,-0.1899216,0.9680001,10.01936,0.5062016,20,1,0,Move Forward,No Rotation,False,-0.002,None +1,3,99.60001,-1.132206E-08,-0.3737657,1.905024,10.05746,0.4987262,20,1,0,Move Forward,No Rotation,False,-0.004,None +1,4,99.40001,8.230845E-08,-0.3490448,2.690454,10.11127,0.4917454,20,1,0,Move Forward,No Rotation,False,-0.006,None +1,4,99.40001,8.230845E-08,-0.3490448,2.690454,10.11127,0.4917454,20,1,0,Move Forward,No Rotation,False,-0.006,None +1,5,99.20001,-8.373664E-08,-0.06980896,3.297567,10.17722,0.4903492,20,1,0,Move Forward,No Rotation,False,-0.008,None +1,6,99.00002,1.659714E-09,-0.01396179,4.013924,10.2575,0.4900699,20,1,0,Move Forward,No Rotation,False,-0.01,None +1,7,98.80002,8.739096E-08,-0.002789497,4.733089,10.35216,0.4900141,20,1,0,Move Forward,No Rotation,False,-0.012,None +1,7,98.80002,8.739096E-08,-0.002789497,4.733089,10.35216,0.4900141,20,1,0,Move Forward,No Rotation,False,-0.012,None +1,8,98.60002,1.709927E-07,-0.0005578995,5.434392,10.46085,0.490003,20,1,0,Move Forward,No Rotation,False,-0.014,None +1,9,98.40002,-2.247951E-07,-0.0001144409,6.114284,10.58313,0.4900007,20,1,0,Move Forward,No Rotation,False,-0.016,None +1,10,98.20003,-1.463151E-07,-2.384186E-05,6.772622,10.71859,0.4900002,20,1,0,Move Forward,No Rotation,False,-0.018,None +1,10,98.20003,-1.463151E-07,-2.384186E-05,6.772622,10.71859,0.4900002,20,1,0,Move Forward,No Rotation,False,-0.018,None +1,11,98.00003,-7.034168E-08,-4.768372E-06,7.409934,10.86679,0.4900001,20,1,0,Move Forward,No Rotation,False,-0.02,None +1,12,97.80003,3.201762E-09,0,8.02686,11.02732,0.4900001,20,1,0,Move Forward,No Rotation,False,-0.022,None +1,13,97.60004,7.439212E-08,0,8.624048,11.1998,0.4900001,20,1,0,Move Forward,No Rotation,False,-0.024,None +1,13,97.60004,7.439212E-08,0,8.624048,11.1998,0.4900001,20,1,0,Move Forward,No Rotation,False,-0.024,None +1,14,97.40004,1.433044E-07,0,9.202127,11.38385,0.4900001,20,1,0,Move Forward,No Rotation,False,-0.026,None +1,15,97.20004,2.100114E-07,0,9.761705,11.57908,0.4900001,20,1,0,Move Forward,No Rotation,False,-0.028,None +1,16,97.00005,2.745838E-07,0,10.30338,11.78515,0.4900001,20,1,0,Move Forward,No Rotation,False,-0.03,None +1,16,97.00005,2.745838E-07,0,10.30338,11.78515,0.4900001,20,1,0,Move Forward,No Rotation,False,-0.03,None +1,17,96.80005,3.3709E-07,0,10.82772,12.0017,0.4900001,20,1,0,Move Forward,No Rotation,False,-0.032,None +1,18,96.60005,3.97596E-07,0,11.33528,12.22841,0.4900001,20,1,0,Move Forward,No Rotation,False,-0.034,None +1,19,96.40005,4.561657E-07,0,11.8266,12.46494,0.4900001,20,1,0,Move Forward,No Rotation,False,-0.036,None +1,19,96.40005,4.561657E-07,0,11.8266,12.46494,0.4900001,20,1,0,Move Forward,No Rotation,False,-0.036,None +1,20,96.20006,-4.40813E-07,0,12.30219,12.71098,0.4900001,20,1,0,Move Forward,No Rotation,False,-0.038,None +1,21,96.00006,-3.859318E-07,0,12.76257,12.96623,0.4900001,20,1,0,Move Forward,No Rotation,False,-0.04,None +1,22,95.80006,-3.328067E-07,0,13.20822,13.2304,0.4900001,20,1,0,Move Forward,No Rotation,False,-0.042,None +1,22,95.80006,0.4609601,0,13.20017,13.2304,0.4900001,20,1,2,Move Forward,Rotate Left,False,-0.042,None +1,23,95.60007,0.951452,0,13.60637,13.50319,0.4900001,20,1,2,Move Forward,Rotate Left,False,-0.044,None +1,24,95.40007,1.43599,0,13.98309,13.78432,0.4900001,20.00067,1,2,Move Forward,Rotate Left,False,-0.046,None +1,25,95.20007,1.412688,0,14.38963,14.07349,0.4900001,20.00265,1,2,Move Forward,Rotate Left,False,-0.048,None +1,25,95.20007,1.914018,0,14.33156,14.07349,0.4900001,20.00265,1,2,Move Forward,Rotate Left,False,-0.048,None +1,26,95.00008,2.385018,0,14.65301,14.37038,0.4900001,20.00657,1,2,Move Forward,Rotate Left,False,-0.05,None +1,27,94.80008,2.848505,0,14.9486,14.67467,0.4900001,20.013,1,2,Move Forward,Rotate Left,False,-0.052,None +1,28,94.60008,2.770862,0,15.32552,14.986,0.4900001,20.02252,1,2,Move Forward,Rotate Left,False,-0.05400001,None +1,28,94.60008,3.304028,0,15.21949,14.986,0.4900001,20.02252,1,2,Move Forward,Rotate Left,False,-0.05400001,None +1,29,94.40009,3.751172,0,15.46677,15.30403,0.4900001,20.03567,1,2,Move Forward,Rotate Left,False,-0.05600001,None +1,30,94.20009,4.189559,0,15.69153,15.6284,0.4900001,20.05296,1,2,Move Forward,Rotate Left,False,-0.05800001,None +1,31,94.00009,4.061317,0,16.04634,15.95872,0.4900001,20.07488,1,2,Move Forward,Rotate Left,False,-0.06000001,None +1,31,94.00009,4.618854,0,15.89483,15.95872,0.4900001,20.07488,1,2,Move Forward,Rotate Left,False,-0.06000001,None +1,32,93.80009,5.038743,0,16.07769,16.29461,0.4900001,20.1019,1,2,Move Forward,Rotate Left,False,-0.06200001,None +1,33,93.6001,5.448962,0,16.2411,16.63567,0.4900001,20.13446,1,2,Move Forward,Rotate Left,False,-0.064,None +1,34,93.4001,5.273837,0,16.58021,16.98151,0.4900001,20.17298,1,2,Move Forward,Rotate Left,False,-0.066,None +1,34,93.4001,5.849265,0,16.38605,16.98151,0.4900001,20.17298,1,2,Move Forward,Rotate Left,False,-0.066,None +1,35,93.2001,6.239454,0,16.51347,17.3317,0.4900001,20.21785,1,2,Move Forward,Rotate Left,False,-0.068,None +1,36,93.00011,6.61935,0,16.62429,17.68584,0.4900001,20.26944,1,2,Move Forward,Rotate Left,False,-0.06999999,None +1,37,92.80011,6.401063,0,16.95312,18.04349,0.4900001,20.3281,1,2,Move Forward,Rotate Left,False,-0.07199999,None +1,37,92.80011,6.988822,0,16.7194,18.04349,0.4900001,20.3281,1,2,Move Forward,Rotate Left,False,-0.07199999,None +1,38,92.60011,7.347745,0,16.79966,18.40421,0.4900001,20.39416,1,2,Move Forward,Rotate Left,False,-0.07399999,None +1,39,92.40012,7.696041,0,16.8659,18.76758,0.4900001,20.4679,1,2,Move Forward,Rotate Left,False,-0.07599998,None +1,40,92.20012,7.438296,0,17.18902,19.13315,0.4900001,20.54962,1,2,Move Forward,Rotate Left,False,-0.07799998,None +1,40,92.20012,8.033653,0,16.91896,19.13315,0.4900001,20.54962,1,2,Move Forward,Rotate Left,False,-0.07799998,None +1,41,92.00012,8.360549,0,16.95961,19.50047,0.4900001,20.63955,1,2,Move Forward,Rotate Left,False,-0.07999998,None +1,42,91.80013,8.676714,0,16.98862,19.86908,0.4900001,20.73795,1,2,Move Forward,Rotate Left,False,-0.08199997,None +1,43,91.60013,8.383173,0,17.30984,20.23855,0.4900001,20.845,1,2,Move Forward,Rotate Left,False,-0.08399997,None +1,43,91.60013,8.982173,0,17.00672,20.23855,0.4900001,20.845,1,2,Move Forward,Rotate Left,False,-0.08399997,None +1,44,91.40013,9.276957,0,17.01463,20.6084,0.4900001,20.9609,1,2,Move Forward,Rotate Left,False,-0.08599997,None +1,45,91.20013,9.561121,0,17.01303,20.97818,0.4900001,21.08581,1,2,Move Forward,Rotate Left,False,-0.08799996,None +1,46,91.00014,9.235371,0,17.33545,21.34744,0.4900001,21.21987,1,2,Move Forward,Rotate Left,False,-0.08999996,None +1,46,91.00014,9.834743,0,17.00258,21.34744,0.4900001,21.21987,1,2,Move Forward,Rotate Left,False,-0.08999996,None +1,47,90.80014,10.09792,0,16.98392,21.71571,0.4900001,21.3632,1,2,Move Forward,Rotate Left,False,-0.09199996,None +1,48,90.60014,10.35075,0,16.95766,22.08254,0.4900001,21.51591,1,2,Move Forward,Rotate Left,False,-0.09399995,None +1,49,90.40015,9.996256,0,17.28378,22.44747,0.4900001,21.67805,1,2,Move Forward,Rotate Left,False,-0.09599995,None +1,49,90.40015,10.59336,0,16.92439,22.44747,0.4900001,21.67805,1,2,Move Forward,Rotate Left,False,-0.09599995,None +1,50,90.20015,10.8259,0,16.88467,22.81003,0.4900001,21.8497,1,2,Move Forward,Rotate Left,False,-0.09799995,None +1,51,90.00015,11.04851,0,16.83904,23.16979,0.4900001,22.03087,1,2,Move Forward,Rotate Left,False,-0.09999994,None +1,52,89.80016,10.6686,0,17.17081,23.52628,0.4900001,22.22159,1,2,Move Forward,Rotate Left,False,-0.1019999,None +1,52,89.80016,11.26135,0,16.78802,23.52628,0.4900001,22.22159,1,2,Move Forward,Rotate Left,False,-0.1019999,None +1,53,89.60016,11.46461,0,16.7321,23.87907,0.4900001,22.42185,1,2,Move Forward,Rotate Left,False,-0.1039999,None +1,54,89.40016,11.65846,0,16.67176,24.2277,0.4900001,22.63162,1,2,Move Forward,Rotate Left,False,-0.1059999,None +1,55,89.20016,11.25629,0,17.01064,24.57174,0.4900001,22.85086,1,2,Move Forward,Rotate Left,False,-0.1079999,None +1,55,89.20016,11.84309,0,16.60744,24.57174,0.4900001,22.85086,1,2,Move Forward,Rotate Left,False,-0.1079999,None +1,56,89.00017,12.01872,0,16.53957,24.91075,0.4900001,23.07949,1,2,Move Forward,Rotate Left,False,-0.1099999,None +1,57,88.80017,12.18553,0,16.46856,25.24431,0.4900001,23.31743,1,2,Move Forward,Rotate Left,False,-0.1119999,None +1,58,88.60017,11.76405,0,16.81561,25.57201,0.4900001,23.56458,1,2,Move Forward,Rotate Left,False,-0.1139999,None +1,58,88.60017,12.34374,0,16.3948,25.57201,0.4900001,23.56458,1,2,Move Forward,Rotate Left,False,-0.1139999,None +1,58,100,11.88297,0,16.69768,25.8923,0.4900001,23.81991,1,2,Move Forward,Rotate Left,False,2.093993,None +Number of Goals Collected: 1 +---Episode End--- + +---New Episode--- +1,1,100,0,0,0,10,0.51,20,1,2,Move Forward,Rotate Left,False,0,None +1,2,99.8,0.06752437,-0.1899216,0.9656421,10.01936,0.5062016,20,1,2,Move Forward,Rotate Left,False,-0.002,None +1,3,99.60001,0.09914637,-0.3737657,1.902152,10.05745,0.4987262,20.00068,1,2,Move Forward,Rotate Left,False,-0.004,None +1,3,99.60001,0.1489234,-0.3363891,1.70778,10.05745,0.4987262,20.00068,0,2,No Movement,Rotate Left,False,-0.004,None +1,4,99.40001,0.170655,-0.3141403,1.393139,10.08863,0.4917454,20.00123,0,2,No Movement,Rotate Left,False,-0.006,None +1,5,99.20001,0.1551718,-0.06282806,0.9815168,10.11071,0.4903492,20.00162,0,2,No Movement,Rotate Left,False,-0.008,None +1,6,99.00002,0.128022,-0.01396179,0.8097845,10.12711,0.4900699,20.00191,0,2,No Movement,Rotate Left,False,-0.01,None +1,6,99.00002,0.1405846,-0.01256561,0.724341,10.12711,0.4900699,20.00191,0,2,No Movement,Rotate Left,False,-0.01,None +1,7,98.80002,0.1202465,-0.002510548,0.5215189,10.139,0.4900141,20.00212,0,2,No Movement,Rotate Left,False,-0.012,None +1,8,98.60002,0.09377422,-0.0005021095,0.3503671,10.14706,0.490003,20.00226,0,2,No Movement,Rotate Left,False,-0.014,None +1,9,98.40002,0.06125374,-0.0001144409,0.2288616,10.15179,0.4900007,20.00235,0,2,No Movement,Rotate Left,False,-0.016,None +1,9,98.40002,0.05512836,-0.0001029968,0.2059754,10.15179,0.4900007,20.00235,0,0,No Movement,No Rotation,False,-0.016,None +1,10,98.20003,0.02150144,-2.147108E-05,0.08033558,10.15364,0.4900002,20.00238,0,0,No Movement,No Rotation,False,-0.018,None +1,11,98.00003,0,-4.291534E-06,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.02,None +1,12,97.80003,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.022,None +1,12,97.80003,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.022,None +1,13,97.60004,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.024,None +1,14,97.40004,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.026,None +1,15,97.20004,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.028,None +1,15,97.20004,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.028,None +1,16,97.00005,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.03,None +1,17,96.80005,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.032,None +1,18,96.60005,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.034,None +1,18,96.60005,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.034,None +1,19,96.40005,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.036,None +1,20,96.20006,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.038,None +1,21,96.00006,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.04,None +1,21,96.00006,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.04,None +1,22,95.80006,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.042,None +1,23,95.60007,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.044,None +1,24,95.40007,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.046,None +1,24,95.40007,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.046,None +1,25,95.20007,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.048,None +1,26,95.00008,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.05,None +1,27,94.80008,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.052,None +1,27,94.80008,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.052,None +1,28,94.60008,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.05400001,None +1,29,94.40009,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.05600001,None +1,30,94.20009,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.05800001,None +1,30,94.20009,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.05800001,None +1,31,94.00009,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.06000001,None +1,32,93.80009,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.06200001,None +1,33,93.6001,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.064,None +1,33,93.6001,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.064,None +1,34,93.4001,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.066,None +1,35,93.2001,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.068,None +1,36,93.00011,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.06999999,None +1,36,93.00011,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.06999999,None +1,37,92.80011,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.07199999,None +1,38,92.60011,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.07399999,None +1,39,92.40012,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.07599998,None +1,39,92.40012,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.07599998,None +1,40,92.20012,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.07799998,None +1,41,92.00012,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.07999998,None +1,42,91.80013,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.08199997,None +1,42,91.80013,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.08199997,None +1,43,91.60013,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.08399997,None +1,44,91.40013,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.08599997,None +1,45,91.20013,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.08799996,None +1,45,91.20013,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.08799996,None +1,46,91.00014,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.08999996,None +1,47,90.80014,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.09199996,None +1,48,90.60014,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.09399995,None +1,48,90.60014,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.09399995,None +1,49,90.40015,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.09599995,None +1,50,90.20015,0,0,0,10.15366,0.4900001,20.00238,0,0,No Movement,No Rotation,False,-0.09799995,None From 22939a01611a316a829a53b55e610b07f168507e Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 4 Jun 2024 13:05:52 +0100 Subject: [PATCH 032/205] minor format --- Assets/Scripts/TrainingArena.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Assets/Scripts/TrainingArena.cs b/Assets/Scripts/TrainingArena.cs index ce18f4a6..8a83fe5a 100644 --- a/Assets/Scripts/TrainingArena.cs +++ b/Assets/Scripts/TrainingArena.cs @@ -49,6 +49,7 @@ public bool IsFirstArenaReset get { return isFirstArenaReset; } set { isFirstArenaReset = value; } } + public bool mergeNextArena { get From 7d4788e766cb0de90228e82ab8c68e55ab158e64 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 4 Jun 2024 13:13:36 +0100 Subject: [PATCH 033/205] fixed issue where episode count would not increment academy.instance is readonly and cant be incremented. --- Assets/Scripts/TrainingAgent.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 92bd49cc..5ffd5d9f 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -63,6 +63,7 @@ public class TrainingAgent : Agent, IPrefab private StreamWriter writer; private bool headerWritten = false; private string yamlFileName; + private int customEpisodeCount = 0; public override void Initialize() { @@ -137,11 +138,12 @@ private void LogToCSV( string actionRotateDescription, bool isFrozen, float reward, - string notificationState + string notificationState, + int customEpisodeCount ) { writer.WriteLine( - $"{Academy.Instance.EpisodeCount},{StepCount},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate},{actionForwardDescription},{actionRotateDescription},{isFrozen},{reward},{notificationState}" + $"{customEpisodeCount},{StepCount},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate},{actionForwardDescription},{actionRotateDescription},{isFrozen},{reward},{notificationState}" ); writer.Flush(); } @@ -224,7 +226,7 @@ public override void CollectObservations(VectorSensor sensor) float reward = GetCumulativeReward(); string notificationState = GetNotificationState(); - LogToCSV(localVel, localPos, lastActionForward, lastActionRotate, actionForwardDescription, actionRotateDescription, isFrozen, reward, notificationState); + LogToCSV(localVel, localPos, lastActionForward, lastActionRotate, actionForwardDescription, actionRotateDescription, isFrozen, reward, notificationState, customEpisodeCount); } public override void OnActionReceived(ActionBuffers action) @@ -244,7 +246,7 @@ public override void OnActionReceived(ActionBuffers action) float reward = GetCumulativeReward(); string notificationState = GetNotificationState(); - LogToCSV(localVel, localPos, lastActionForward, lastActionRotate, actionForwardDescription, actionRotateDescription, isFrozen, reward, notificationState); + LogToCSV(localVel, localPos, lastActionForward, lastActionRotate, actionForwardDescription, actionRotateDescription, isFrozen, reward, notificationState, customEpisodeCount); UpdateHealth(_rewardPerStep); } @@ -445,6 +447,7 @@ public override void OnEpisodeBegin() } numberOfGoalsCollected = 0; + customEpisodeCount++; writer.WriteLine($"\n---New Episode---"); writer.Flush(); From 9baca2d21b7c8ddd61323a86b838cae954829617 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 4 Jun 2024 13:16:34 +0100 Subject: [PATCH 034/205] added padding between data in csv file --- Assets/Scripts/TrainingAgent.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 5ffd5d9f..288d1042 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -441,6 +441,7 @@ public override void OnEpisodeBegin() { if (!_arena.IsFirstArenaReset) // Don't logging for the first initialization { + writer.WriteLine(""); writer.WriteLine($"Number of Goals Collected: {numberOfGoalsCollected}"); writer.WriteLine("---Episode End---"); writer.Flush(); From 0c911db2c3ff8f3ec5462656058b8993297cc304 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 4 Jun 2024 13:22:25 +0100 Subject: [PATCH 035/205] added TODO --- Assets/Scripts/TrainingAgent.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 288d1042..5ed43ade 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -10,6 +10,8 @@ using YAMLDefs; using System.IO; +// TODO: Implement a buffered writer for the CSV logs for improved performance and reduced IO operations. + /// /// The TrainingAgent class is a subclass of the Agent class in the ML-Agents library. /// It is used to define the behaviour of the agent in the training environment. From 50b229908df00d64fc7324ef5fca8a239f94182b Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Fri, 7 Jun 2024 17:26:36 +0100 Subject: [PATCH 036/205] minor change --- Assets/Scripts/TrainingAgent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 5ed43ade..9480bdde 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -61,7 +61,7 @@ public class TrainingAgent : Agent, IPrefab private bool _isCountdownActive = false; [Header("CSV Logging")] - public string csvFilePath = "Observations.csv"; + public string csvFilePath = ""; private StreamWriter writer; private bool headerWritten = false; private string yamlFileName; From 21c71bdd19082624cad7bc3f36ecbcc972bee850 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Sun, 9 Jun 2024 14:35:02 +0100 Subject: [PATCH 037/205] implemented experimental buffering for data log also cleaned up whats being logged and how data is presented in .csv file. --- Assets/Scripts/TrainingAgent.cs | 48 ++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 9480bdde..bbeb600f 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -9,8 +9,11 @@ using Unity.MLAgents.Sensors; using YAMLDefs; using System.IO; +using System.Collections.Concurrent; +using System.Threading; -// TODO: Implement a buffered writer for the CSV logs for improved performance and reduced IO operations. +// Remaining objectives: +// TODO: Implement/finish code to extract yaml name from side channel. /// /// The TrainingAgent class is a subclass of the Agent class in the ML-Agents library. @@ -66,6 +69,9 @@ public class TrainingAgent : Agent, IPrefab private bool headerWritten = false; private string yamlFileName; private int customEpisodeCount = 0; + private ConcurrentQueue logQueue = new ConcurrentQueue(); + private const int bufferSize = 300; + private bool isFlushing = false; public override void Initialize() { @@ -86,6 +92,8 @@ public override void Initialize() SetYamlFileName(envManager.GetCurrentYamlFileName()); } } + + StartFlushThread(); } public void SetYamlFileName(string fileName) @@ -126,7 +134,7 @@ private void InitialiseCSVProcess() writer = new StreamWriter(csvFilePath, true); if (!File.Exists(csvFilePath) || new FileInfo(csvFilePath).Length == 0) { - writer.WriteLine("Episode,Step,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate,ActionForwardDescription,ActionRotateDescription,IsFrozen,Reward,NotificationState"); + writer.WriteLine("Episode,Step,Reward,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate,ActionForwardDescription,ActionRotateDescription,IsFrozen,NotificationState"); headerWritten = true; } } @@ -144,10 +152,35 @@ private void LogToCSV( int customEpisodeCount ) { - writer.WriteLine( - $"{customEpisodeCount},{StepCount},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate},{actionForwardDescription},{actionRotateDescription},{isFrozen},{reward},{notificationState}" - ); + string logEntry = $"{customEpisodeCount},{StepCount},{reward},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate},{actionForwardDescription},{actionRotateDescription},{isFrozen},{notificationState}"; + logQueue.Enqueue(logEntry); + } + + private void FlushLogQueue() + { + while (logQueue.TryDequeue(out var logEntry)) + { + writer.WriteLine(logEntry); + } writer.Flush(); + Debug.Log("Flushed log queue"); + } + + private void StartFlushThread() + { + new Thread(() => + { + while (true) + { + if (logQueue.Count >= bufferSize && !isFlushing) + { + isFlushing = true; + FlushLogQueue(); + isFlushing = false; + } + Thread.Sleep(100); // polls every 100ms to check if the queue is full. This is to prevent the thread from running continuously and hogging resources. + } + }).Start(); } protected override void OnDisable() @@ -155,7 +188,7 @@ protected override void OnDisable() base.OnDisable(); if (writer != null) { - writer.Flush(); + FlushLogQueue(); // Ensure all buffered data is written to the file before closing writer.Close(); } } @@ -443,16 +476,13 @@ public override void OnEpisodeBegin() { if (!_arena.IsFirstArenaReset) // Don't logging for the first initialization { - writer.WriteLine(""); writer.WriteLine($"Number of Goals Collected: {numberOfGoalsCollected}"); - writer.WriteLine("---Episode End---"); writer.Flush(); } numberOfGoalsCollected = 0; customEpisodeCount++; - writer.WriteLine($"\n---New Episode---"); writer.Flush(); EpisodeDebugLog(); From 323083cb86e6e08590372b7cf6565aedc75eb6f1 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Sun, 9 Jun 2024 17:20:59 +0100 Subject: [PATCH 038/205] minor change to testing yaml case --- Assets/Resources/test_configs/decoy-file-test.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Assets/Resources/test_configs/decoy-file-test.yaml b/Assets/Resources/test_configs/decoy-file-test.yaml index 4c1bc501..96145215 100644 --- a/Assets/Resources/test_configs/decoy-file-test.yaml +++ b/Assets/Resources/test_configs/decoy-file-test.yaml @@ -11,7 +11,7 @@ arenas: - !Vector3 {x: 10, y: 0, z: 20} rotations: [90] - !Item - name: DecayGoal + name: GoodGoal positions: - !Vector3 {x: 25, y: 0, z: 25} sizes: @@ -26,7 +26,7 @@ arenas: - !Vector3 {x: 10, y: 0, z: 20} rotations: [90] - !Item - name: DecayGoal + name: BadGoal positions: - !Vector3 {x: 25, y: 0, z: 25} sizes: From 91fafb129232860ac1a9e798af0d55c292764f77 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Sun, 9 Jun 2024 17:54:08 +0100 Subject: [PATCH 039/205] added reward types to each reward goal --- Assets/Prefabs/Rewards/BadGoal.prefab | 3 ++- Assets/Prefabs/Rewards/BadGoalBounce.prefab | 3 ++- Assets/Prefabs/Rewards/DeathZone.prefab | 7 ++++++- Assets/Prefabs/Rewards/DecayGoal.prefab | 5 +++-- Assets/Prefabs/Rewards/DecoyGoal.prefab | 3 ++- Assets/Prefabs/Rewards/DecoyGoalBounce.prefab | 3 ++- Assets/Prefabs/Rewards/GoodGoal.prefab | 7 ++++++- Assets/Prefabs/Rewards/GoodGoalBounce.prefab | 7 ++++++- Assets/Prefabs/Rewards/GoodGoalMulti.prefab | 7 ++++++- Assets/Prefabs/Rewards/GoodGoalMultiBounce.prefab | 7 ++++++- Assets/Prefabs/Rewards/GrowGoal.prefab | 6 +++++- Assets/Prefabs/Rewards/HotZone.prefab | 8 ++++++-- Assets/Prefabs/Rewards/RipenGoal.prefab | 5 +++-- Assets/Prefabs/Rewards/ShrinkGoal.prefab | 6 +++++- 14 files changed, 60 insertions(+), 17 deletions(-) diff --git a/Assets/Prefabs/Rewards/BadGoal.prefab b/Assets/Prefabs/Rewards/BadGoal.prefab index 7e69b859..38dd3349 100644 --- a/Assets/Prefabs/Rewards/BadGoal.prefab +++ b/Assets/Prefabs/Rewards/BadGoal.prefab @@ -132,9 +132,10 @@ MonoBehaviour: sizeMax: {x: 5, y: 5, z: 5} canRandomizeColor: 0 ratioSize: {x: 1, y: 1, z: 1} - sizeAdjustement: 0.999 + sizeAdjustment: 0.999 textureUVOverride: 0 typicalOrigin: 1 numberOfGoals: 1 reward: -1 isMulti: 0 + rewardType: BadGoal diff --git a/Assets/Prefabs/Rewards/BadGoalBounce.prefab b/Assets/Prefabs/Rewards/BadGoalBounce.prefab index 981af5e3..50fd8ade 100644 --- a/Assets/Prefabs/Rewards/BadGoalBounce.prefab +++ b/Assets/Prefabs/Rewards/BadGoalBounce.prefab @@ -132,11 +132,12 @@ MonoBehaviour: sizeMax: {x: 5, y: 5, z: 5} canRandomizeColor: 0 ratioSize: {x: 1, y: 1, z: 1} - sizeAdjustement: 0.999 + sizeAdjustment: 0.999 textureUVOverride: 0 typicalOrigin: 1 numberOfGoals: 1 reward: -1 isMulti: 0 + rewardType: BadGoalMulti maximumVelocity: 10 forceToApply: 500 diff --git a/Assets/Prefabs/Rewards/DeathZone.prefab b/Assets/Prefabs/Rewards/DeathZone.prefab index eb4fe3b9..632d72d0 100644 --- a/Assets/Prefabs/Rewards/DeathZone.prefab +++ b/Assets/Prefabs/Rewards/DeathZone.prefab @@ -30,6 +30,7 @@ Transform: m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: -0.15, z: 0} m_LocalScale: {x: 1, y: 1.001, z: 1} + m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 0 @@ -66,6 +67,7 @@ MeshRenderer: m_CastShadows: 1 m_ReceiveShadows: 1 m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 m_MotionVectors: 1 m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 @@ -113,7 +115,10 @@ MonoBehaviour: sizeMax: {x: 40, y: 10, z: 40} canRandomizeColor: 0 ratioSize: {x: 1, y: 1, z: 1} - sizeAdjustement: 0.999 + sizeAdjustment: 0.999 + textureUVOverride: 0 + typicalOrigin: 1 numberOfGoals: 1 reward: -1 isMulti: 0 + rewardType: DeathZone diff --git a/Assets/Prefabs/Rewards/DecayGoal.prefab b/Assets/Prefabs/Rewards/DecayGoal.prefab index 2cd7c0de..d9bd3a55 100644 --- a/Assets/Prefabs/Rewards/DecayGoal.prefab +++ b/Assets/Prefabs/Rewards/DecayGoal.prefab @@ -134,16 +134,17 @@ MonoBehaviour: sizeMax: {x: 0, y: 0, z: 0} canRandomizeColor: 1 ratioSize: {x: 1, y: 1, z: 1} - sizeAdjustement: 0.999 + sizeAdjustment: 0.999 textureUVOverride: 0 typicalOrigin: 1 numberOfGoals: 1 reward: 2.5 isMulti: 1 + rewardType: DecayGoal initialReward: 3 finalReward: 0 + decayRate: -0.005 initialColour: {r: 0.913099, g: 0.72305536, b: 0.13843165, a: 1} finalColour: {r: 0.39215687, g: 0.39215687, b: 0.39215687, a: 1} - decayRate: -0.005 flipDecayDirection: 0 fixedFrameDelay: 150 diff --git a/Assets/Prefabs/Rewards/DecoyGoal.prefab b/Assets/Prefabs/Rewards/DecoyGoal.prefab index 5e0b3b09..b1f719a9 100644 --- a/Assets/Prefabs/Rewards/DecoyGoal.prefab +++ b/Assets/Prefabs/Rewards/DecoyGoal.prefab @@ -132,9 +132,10 @@ MonoBehaviour: sizeMax: {x: 5, y: 5, z: 5} canRandomizeColor: 0 ratioSize: {x: 1, y: 1, z: 1} - sizeAdjustement: 0.999 + sizeAdjustment: 0.999 textureUVOverride: 0 typicalOrigin: 1 numberOfGoals: 1 reward: 0 isMulti: 0 + rewardType: DecoyGoal diff --git a/Assets/Prefabs/Rewards/DecoyGoalBounce.prefab b/Assets/Prefabs/Rewards/DecoyGoalBounce.prefab index 5d49c1f5..6161a310 100644 --- a/Assets/Prefabs/Rewards/DecoyGoalBounce.prefab +++ b/Assets/Prefabs/Rewards/DecoyGoalBounce.prefab @@ -132,11 +132,12 @@ MonoBehaviour: sizeMax: {x: 5, y: 5, z: 5} canRandomizeColor: 0 ratioSize: {x: 1, y: 1, z: 1} - sizeAdjustement: 0.999 + sizeAdjustment: 0.999 textureUVOverride: 0 typicalOrigin: 1 numberOfGoals: 1 reward: 0 isMulti: 0 + rewardType: DecoyGoalMulti maximumVelocity: 10 forceToApply: 500 diff --git a/Assets/Prefabs/Rewards/GoodGoal.prefab b/Assets/Prefabs/Rewards/GoodGoal.prefab index cbda1725..ad1ceb88 100644 --- a/Assets/Prefabs/Rewards/GoodGoal.prefab +++ b/Assets/Prefabs/Rewards/GoodGoal.prefab @@ -31,6 +31,7 @@ Transform: m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0.5, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 0 @@ -67,6 +68,7 @@ MeshRenderer: m_CastShadows: 1 m_ReceiveShadows: 1 m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 m_MotionVectors: 1 m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 @@ -130,7 +132,10 @@ MonoBehaviour: sizeMax: {x: 5, y: 5, z: 5} canRandomizeColor: 0 ratioSize: {x: 1, y: 1, z: 1} - sizeAdjustement: 0.999 + sizeAdjustment: 0.999 + textureUVOverride: 0 + typicalOrigin: 1 numberOfGoals: 1 reward: 1 isMulti: 0 + rewardType: GoodGoal diff --git a/Assets/Prefabs/Rewards/GoodGoalBounce.prefab b/Assets/Prefabs/Rewards/GoodGoalBounce.prefab index b3ac3ab5..894c27b7 100644 --- a/Assets/Prefabs/Rewards/GoodGoalBounce.prefab +++ b/Assets/Prefabs/Rewards/GoodGoalBounce.prefab @@ -31,6 +31,7 @@ Transform: m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0.5, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 0 @@ -67,6 +68,7 @@ MeshRenderer: m_CastShadows: 1 m_ReceiveShadows: 1 m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 m_MotionVectors: 1 m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 @@ -130,9 +132,12 @@ MonoBehaviour: sizeMax: {x: 5, y: 5, z: 5} canRandomizeColor: 0 ratioSize: {x: 1, y: 1, z: 1} - sizeAdjustement: 0.999 + sizeAdjustment: 0.999 + textureUVOverride: 0 + typicalOrigin: 1 numberOfGoals: 1 reward: 1 isMulti: 0 + rewardType: GoodGoalMulti maximumVelocity: 10 forceToApply: 500 diff --git a/Assets/Prefabs/Rewards/GoodGoalMulti.prefab b/Assets/Prefabs/Rewards/GoodGoalMulti.prefab index bc49f1ae..5e5baaf7 100644 --- a/Assets/Prefabs/Rewards/GoodGoalMulti.prefab +++ b/Assets/Prefabs/Rewards/GoodGoalMulti.prefab @@ -31,6 +31,7 @@ Transform: m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0.5, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 0 @@ -67,6 +68,7 @@ MeshRenderer: m_CastShadows: 1 m_ReceiveShadows: 1 m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 m_MotionVectors: 1 m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 @@ -130,7 +132,10 @@ MonoBehaviour: sizeMax: {x: 5, y: 5, z: 5} canRandomizeColor: 0 ratioSize: {x: 1, y: 1, z: 1} - sizeAdjustement: 0.999 + sizeAdjustment: 0.999 + textureUVOverride: 0 + typicalOrigin: 1 numberOfGoals: 1 reward: 1 isMulti: 1 + rewardType: GoodGoalBounce diff --git a/Assets/Prefabs/Rewards/GoodGoalMultiBounce.prefab b/Assets/Prefabs/Rewards/GoodGoalMultiBounce.prefab index 83529ca2..0a7f3707 100644 --- a/Assets/Prefabs/Rewards/GoodGoalMultiBounce.prefab +++ b/Assets/Prefabs/Rewards/GoodGoalMultiBounce.prefab @@ -31,6 +31,7 @@ Transform: m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0.5, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 0 @@ -67,6 +68,7 @@ MeshRenderer: m_CastShadows: 1 m_ReceiveShadows: 1 m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 m_MotionVectors: 1 m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 @@ -130,9 +132,12 @@ MonoBehaviour: sizeMax: {x: 5, y: 5, z: 5} canRandomizeColor: 0 ratioSize: {x: 1, y: 1, z: 1} - sizeAdjustement: 0.999 + sizeAdjustment: 0.999 + textureUVOverride: 0 + typicalOrigin: 1 numberOfGoals: 1 reward: 1 isMulti: 1 + rewardType: GoodGoalMultiBounce maximumVelocity: 10 forceToApply: 500 diff --git a/Assets/Prefabs/Rewards/GrowGoal.prefab b/Assets/Prefabs/Rewards/GrowGoal.prefab index 35862d81..1476b65f 100644 --- a/Assets/Prefabs/Rewards/GrowGoal.prefab +++ b/Assets/Prefabs/Rewards/GrowGoal.prefab @@ -31,6 +31,7 @@ Transform: m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0.5, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 0 @@ -67,6 +68,7 @@ MeshRenderer: m_CastShadows: 1 m_ReceiveShadows: 1 m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 m_MotionVectors: 1 m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 @@ -130,11 +132,13 @@ MonoBehaviour: sizeMax: {x: 0, y: 0, z: 0} canRandomizeColor: 0 ratioSize: {x: 1, y: 1, z: 1} - sizeAdjustement: 0.999 + sizeAdjustment: 0.999 textureUVOverride: 0 + typicalOrigin: 1 numberOfGoals: 1 reward: 2 isMulti: 1 + rewardType: GrowGoal initialSize: 0.5 finalSize: 5 sizeChangeRate: -0.01 diff --git a/Assets/Prefabs/Rewards/HotZone.prefab b/Assets/Prefabs/Rewards/HotZone.prefab index 78f983dc..59dcc56f 100644 --- a/Assets/Prefabs/Rewards/HotZone.prefab +++ b/Assets/Prefabs/Rewards/HotZone.prefab @@ -30,6 +30,7 @@ Transform: m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: -0.15, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 0 @@ -66,6 +67,7 @@ MeshRenderer: m_CastShadows: 1 m_ReceiveShadows: 1 m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 m_MotionVectors: 1 m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 @@ -113,8 +115,10 @@ MonoBehaviour: sizeMax: {x: 40, y: 10, z: 40} canRandomizeColor: 0 ratioSize: {x: 1, y: 1, z: 1} - sizeAdjustement: 0.999 + sizeAdjustment: 0.999 + textureUVOverride: 0 + typicalOrigin: 1 numberOfGoals: 1 reward: 10 isMulti: 0 - playerControls: {fileID: 0} + rewardType: HotZone diff --git a/Assets/Prefabs/Rewards/RipenGoal.prefab b/Assets/Prefabs/Rewards/RipenGoal.prefab index 6956e2d8..29e05973 100644 --- a/Assets/Prefabs/Rewards/RipenGoal.prefab +++ b/Assets/Prefabs/Rewards/RipenGoal.prefab @@ -134,16 +134,17 @@ MonoBehaviour: sizeMax: {x: 0, y: 0, z: 0} canRandomizeColor: 1 ratioSize: {x: 1, y: 1, z: 1} - sizeAdjustement: 0.999 + sizeAdjustment: 0.999 textureUVOverride: 0 typicalOrigin: 1 numberOfGoals: 1 reward: 2.5 isMulti: 1 + rewardType: RipenGoal initialReward: 0 finalReward: 3 + decayRate: -0.005 initialColour: {r: 0.39157256, g: 0.39157256, b: 0.39157256, a: 1} finalColour: {r: 0.913099, g: 0.72305536, b: 0.13843165, a: 1} - decayRate: -0.005 flipDecayDirection: 0 fixedFrameDelay: 150 diff --git a/Assets/Prefabs/Rewards/ShrinkGoal.prefab b/Assets/Prefabs/Rewards/ShrinkGoal.prefab index a828c7c3..9e1425c6 100644 --- a/Assets/Prefabs/Rewards/ShrinkGoal.prefab +++ b/Assets/Prefabs/Rewards/ShrinkGoal.prefab @@ -31,6 +31,7 @@ Transform: m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0.5, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 0 @@ -67,6 +68,7 @@ MeshRenderer: m_CastShadows: 1 m_ReceiveShadows: 1 m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 m_MotionVectors: 1 m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 @@ -130,11 +132,13 @@ MonoBehaviour: sizeMax: {x: 0, y: 0, z: 0} canRandomizeColor: 0 ratioSize: {x: 1, y: 1, z: 1} - sizeAdjustement: 0.999 + sizeAdjustment: 0.999 textureUVOverride: 0 + typicalOrigin: 1 numberOfGoals: 1 reward: 5 isMulti: 1 + rewardType: ShrinkGoal initialSize: 5 finalSize: 0.5 sizeChangeRate: -0.01 From 2388e421c0ff3699d68951f6691f09e252494366 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Sun, 9 Jun 2024 17:56:43 +0100 Subject: [PATCH 040/205] added new parameter to recognize each reward type also simplified getting component for agent collision and added debug check plus minor reformatting --- Assets/Scripts/Rewards/Goal.cs | 95 ++++++++++++++++++++-------------- 1 file changed, 55 insertions(+), 40 deletions(-) diff --git a/Assets/Scripts/Rewards/Goal.cs b/Assets/Scripts/Rewards/Goal.cs index 694890aa..1da9b314 100644 --- a/Assets/Scripts/Rewards/Goal.cs +++ b/Assets/Scripts/Rewards/Goal.cs @@ -5,47 +5,62 @@ /// public class Goal : Prefab { - [Header("Goal Settings")] - public int numberOfGoals = 1; - public float reward = 1; - public bool isMulti = false; + [Header("Goal Settings")] + public int numberOfGoals = 1; + public float reward = 1; + public bool isMulti = false; + public string rewardType = "None"; // None or a color name (a placeholder for now) - void Awake() - { - canRandomizeColor = false; - } + void Awake() + { + canRandomizeColor = false; + } - public virtual void OnTriggerEnter(Collider collision) - { - if (collision.gameObject.CompareTag("agent")) - { - collision.GetComponent().UpdateHealth(reward, true); - } - } + public virtual void OnTriggerEnter(Collider other) + { + if (other.gameObject.CompareTag("agent")) + { + TrainingAgent agent = other.GetComponent(); + if (agent != null) + { + agent.UpdateHealth(reward, true); + agent.RecordRewardType(rewardType); + } + } + } - public virtual void OnCollisionEnter(Collision collision) - { - if (collision.gameObject.CompareTag("agent")) - { - TrainingAgent agentScript = collision.gameObject.GetComponent(); - if (!isMulti) - { - agentScript.UpdateHealth(reward, true); - } - else - { - agentScript.numberOfGoalsCollected++; - if (agentScript.numberOfGoalsCollected == numberOfGoals) - { - agentScript.UpdateHealth(reward, true); - } - else - { - agentScript.UpdateHealth(reward); - } - gameObject.SetActive(false); - Object.Destroy(gameObject); - } - } - } + public virtual void OnCollisionEnter(Collision collision) + { + if (collision.gameObject.CompareTag("agent")) + { + TrainingAgent agent = collision.gameObject.GetComponent(); + if (agent != null) + { + if (!isMulti) + { + agent.UpdateHealth(reward, true); + agent.RecordRewardType(rewardType); + } + else + { + agent.numberOfGoalsCollected++; + if (agent.numberOfGoalsCollected >= numberOfGoals) + { + agent.UpdateHealth(reward, true); + agent.RecordRewardType(rewardType); + } + else + { + agent.UpdateHealth(reward); + } + gameObject.SetActive(false); + Object.Destroy(gameObject); + } + } + else + { + Debug.LogError("Agent not found in the collision object."); + } + } + } } From cd9f758b2f94def9aba542fc7270a69f3953d2dc Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Sun, 9 Jun 2024 18:02:59 +0100 Subject: [PATCH 041/205] added new column to .csv file to record type of reward collected also reduced buffersize to half for better handling and flushing to .csv file more frequently Added code to prevent thread from running too long (saves memory). --- Assets/Scripts/TrainingAgent.cs | 36 +++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index bbeb600f..d62accea 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -12,9 +12,6 @@ using System.Collections.Concurrent; using System.Threading; -// Remaining objectives: -// TODO: Implement/finish code to extract yaml name from side channel. - /// /// The TrainingAgent class is a subclass of the Agent class in the ML-Agents library. /// It is used to define the behaviour of the agent in the training environment. @@ -70,8 +67,20 @@ public class TrainingAgent : Agent, IPrefab private string yamlFileName; private int customEpisodeCount = 0; private ConcurrentQueue logQueue = new ConcurrentQueue(); - private const int bufferSize = 300; + private const int bufferSize = 150; // Corresponds to rows in the CSV file to keep in memory before flushing to disk private bool isFlushing = false; + private string lastCollectedRewardType = "None"; + + public void RecordRewardType(string type) + { + lastCollectedRewardType = type; + Debug.Log($"Reward type collected: {type}"); + } + + public void SetYamlFileName(string fileName) + { + yamlFileName = fileName; + } public override void Initialize() { @@ -96,11 +105,6 @@ public override void Initialize() StartFlushThread(); } - public void SetYamlFileName(string fileName) - { - yamlFileName = fileName; - } - private void InitialiseCSVProcess() { // Base path for the logs to be stored @@ -126,7 +130,7 @@ private void InitialiseCSVProcess() Directory.CreateDirectory(directoryPath); } - // Generate a filename with the YAML file name and a date stamp + // Generate a filename with the YAML file name and a date stamp to prevent overwriting. TODO: Extract YAML name from side channel message string dateTimeString = DateTime.Now.ToString("dd-MM-yy_HHmm"); string filename = $"Observations_{yamlFileName}_{dateTimeString}.csv"; csvFilePath = Path.Combine(directoryPath, filename); @@ -134,7 +138,7 @@ private void InitialiseCSVProcess() writer = new StreamWriter(csvFilePath, true); if (!File.Exists(csvFilePath) || new FileInfo(csvFilePath).Length == 0) { - writer.WriteLine("Episode,Step,Reward,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate,ActionForwardDescription,ActionRotateDescription,IsFrozen,NotificationState"); + writer.WriteLine("Episode,Step,Reward,CollectedRewardType,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate,ActionForwardDescription,ActionRotateDescription,IsFrozen,NotificationState"); headerWritten = true; } } @@ -152,10 +156,12 @@ private void LogToCSV( int customEpisodeCount ) { - string logEntry = $"{customEpisodeCount},{StepCount},{reward},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate},{actionForwardDescription},{actionRotateDescription},{isFrozen},{notificationState}"; + string logEntry = $"{customEpisodeCount},{StepCount},{reward},{lastCollectedRewardType},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate},{actionForwardDescription},{actionRotateDescription},{isFrozen},{notificationState}"; logQueue.Enqueue(logEntry); + lastCollectedRewardType = "None"; } + private void FlushLogQueue() { while (logQueue.TryDequeue(out var logEntry)) @@ -163,7 +169,7 @@ private void FlushLogQueue() writer.WriteLine(logEntry); } writer.Flush(); - Debug.Log("Flushed log queue"); + Debug.Log("Flushed log queue to CSV file."); } private void StartFlushThread() @@ -188,7 +194,7 @@ protected override void OnDisable() base.OnDisable(); if (writer != null) { - FlushLogQueue(); // Ensure all buffered data is written to the file before closing + FlushLogQueue(); // Ensures all buffered data is written to the file before closing (important for builds) writer.Close(); } } @@ -474,7 +480,7 @@ IEnumerator EndEpisodeAfterDelay() public override void OnEpisodeBegin() { - if (!_arena.IsFirstArenaReset) // Don't logging for the first initialization + if (!_arena.IsFirstArenaReset) // Don't log for the first initialization of the arena { writer.WriteLine($"Number of Goals Collected: {numberOfGoalsCollected}"); writer.Flush(); From 826fe66808feea38263b69eef17ad29b18addeac Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Sun, 9 Jun 2024 18:06:03 +0100 Subject: [PATCH 042/205] added check to make sure header is not written more than once header = column strings --- Assets/Scripts/TrainingAgent.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index d62accea..e69af389 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -136,10 +136,18 @@ private void InitialiseCSVProcess() csvFilePath = Path.Combine(directoryPath, filename); writer = new StreamWriter(csvFilePath, true); + if (!File.Exists(csvFilePath) || new FileInfo(csvFilePath).Length == 0) { - writer.WriteLine("Episode,Step,Reward,CollectedRewardType,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate,ActionForwardDescription,ActionRotateDescription,IsFrozen,NotificationState"); - headerWritten = true; + if (!headerWritten) + { + writer.WriteLine("Episode,Step,Reward,CollectedRewardType,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate,ActionForwardDescription,ActionRotateDescription,IsFrozen,NotificationState"); + headerWritten = true; + } + else + { + Debug.LogError("Header already written to CSV file."); + } } } From 828cfbed0ba94250fb92beda70b04dca07374a88 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Sun, 9 Jun 2024 23:14:49 +0100 Subject: [PATCH 043/205] added reward types to goals stored in resources folder --- Assets/Resources/BadGoal.prefab | 3 ++- Assets/Resources/BadGoalBounce.prefab | 3 ++- Assets/Resources/GoodGoal.prefab | 7 ++++++- Assets/Resources/GoodGoalBounce.prefab | 7 ++++++- Assets/Resources/GoodGoalMulti.prefab | 7 ++++++- Assets/Resources/GoodGoalMultiBounce.prefab | 7 ++++++- 6 files changed, 28 insertions(+), 6 deletions(-) diff --git a/Assets/Resources/BadGoal.prefab b/Assets/Resources/BadGoal.prefab index 7e69b859..38dd3349 100644 --- a/Assets/Resources/BadGoal.prefab +++ b/Assets/Resources/BadGoal.prefab @@ -132,9 +132,10 @@ MonoBehaviour: sizeMax: {x: 5, y: 5, z: 5} canRandomizeColor: 0 ratioSize: {x: 1, y: 1, z: 1} - sizeAdjustement: 0.999 + sizeAdjustment: 0.999 textureUVOverride: 0 typicalOrigin: 1 numberOfGoals: 1 reward: -1 isMulti: 0 + rewardType: BadGoal diff --git a/Assets/Resources/BadGoalBounce.prefab b/Assets/Resources/BadGoalBounce.prefab index 981af5e3..772cf246 100644 --- a/Assets/Resources/BadGoalBounce.prefab +++ b/Assets/Resources/BadGoalBounce.prefab @@ -132,11 +132,12 @@ MonoBehaviour: sizeMax: {x: 5, y: 5, z: 5} canRandomizeColor: 0 ratioSize: {x: 1, y: 1, z: 1} - sizeAdjustement: 0.999 + sizeAdjustment: 0.999 textureUVOverride: 0 typicalOrigin: 1 numberOfGoals: 1 reward: -1 isMulti: 0 + rewardType: BadGoalBounce maximumVelocity: 10 forceToApply: 500 diff --git a/Assets/Resources/GoodGoal.prefab b/Assets/Resources/GoodGoal.prefab index cbda1725..ad1ceb88 100644 --- a/Assets/Resources/GoodGoal.prefab +++ b/Assets/Resources/GoodGoal.prefab @@ -31,6 +31,7 @@ Transform: m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0.5, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 0 @@ -67,6 +68,7 @@ MeshRenderer: m_CastShadows: 1 m_ReceiveShadows: 1 m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 m_MotionVectors: 1 m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 @@ -130,7 +132,10 @@ MonoBehaviour: sizeMax: {x: 5, y: 5, z: 5} canRandomizeColor: 0 ratioSize: {x: 1, y: 1, z: 1} - sizeAdjustement: 0.999 + sizeAdjustment: 0.999 + textureUVOverride: 0 + typicalOrigin: 1 numberOfGoals: 1 reward: 1 isMulti: 0 + rewardType: GoodGoal diff --git a/Assets/Resources/GoodGoalBounce.prefab b/Assets/Resources/GoodGoalBounce.prefab index b3ac3ab5..edb21125 100644 --- a/Assets/Resources/GoodGoalBounce.prefab +++ b/Assets/Resources/GoodGoalBounce.prefab @@ -31,6 +31,7 @@ Transform: m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0.5, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 0 @@ -67,6 +68,7 @@ MeshRenderer: m_CastShadows: 1 m_ReceiveShadows: 1 m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 m_MotionVectors: 1 m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 @@ -130,9 +132,12 @@ MonoBehaviour: sizeMax: {x: 5, y: 5, z: 5} canRandomizeColor: 0 ratioSize: {x: 1, y: 1, z: 1} - sizeAdjustement: 0.999 + sizeAdjustment: 0.999 + textureUVOverride: 0 + typicalOrigin: 1 numberOfGoals: 1 reward: 1 isMulti: 0 + rewardType: GoodGoalBounce maximumVelocity: 10 forceToApply: 500 diff --git a/Assets/Resources/GoodGoalMulti.prefab b/Assets/Resources/GoodGoalMulti.prefab index bc49f1ae..f4c8b6ae 100644 --- a/Assets/Resources/GoodGoalMulti.prefab +++ b/Assets/Resources/GoodGoalMulti.prefab @@ -31,6 +31,7 @@ Transform: m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0.5, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 0 @@ -67,6 +68,7 @@ MeshRenderer: m_CastShadows: 1 m_ReceiveShadows: 1 m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 m_MotionVectors: 1 m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 @@ -130,7 +132,10 @@ MonoBehaviour: sizeMax: {x: 5, y: 5, z: 5} canRandomizeColor: 0 ratioSize: {x: 1, y: 1, z: 1} - sizeAdjustement: 0.999 + sizeAdjustment: 0.999 + textureUVOverride: 0 + typicalOrigin: 1 numberOfGoals: 1 reward: 1 isMulti: 1 + rewardType: GoodGoalMulti diff --git a/Assets/Resources/GoodGoalMultiBounce.prefab b/Assets/Resources/GoodGoalMultiBounce.prefab index 83529ca2..0a7f3707 100644 --- a/Assets/Resources/GoodGoalMultiBounce.prefab +++ b/Assets/Resources/GoodGoalMultiBounce.prefab @@ -31,6 +31,7 @@ Transform: m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0.5, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 0 @@ -67,6 +68,7 @@ MeshRenderer: m_CastShadows: 1 m_ReceiveShadows: 1 m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 m_MotionVectors: 1 m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 @@ -130,9 +132,12 @@ MonoBehaviour: sizeMax: {x: 5, y: 5, z: 5} canRandomizeColor: 0 ratioSize: {x: 1, y: 1, z: 1} - sizeAdjustement: 0.999 + sizeAdjustment: 0.999 + textureUVOverride: 0 + typicalOrigin: 1 numberOfGoals: 1 reward: 1 isMulti: 1 + rewardType: GoodGoalMultiBounce maximumVelocity: 10 forceToApply: 500 From 6eb65fe8c451cbdd550a5f10a47d26acb74e93c5 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Sun, 9 Jun 2024 23:34:10 +0100 Subject: [PATCH 044/205] corrected some goal params --- Assets/Prefabs/Rewards/BadGoalBounce.prefab | 2 +- Assets/Prefabs/Rewards/DecoyGoal.prefab | 2 +- Assets/Prefabs/Rewards/DecoyGoalBounce.prefab | 4 ++-- Assets/Prefabs/Rewards/GoodGoalMulti.prefab | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Assets/Prefabs/Rewards/BadGoalBounce.prefab b/Assets/Prefabs/Rewards/BadGoalBounce.prefab index 50fd8ade..772cf246 100644 --- a/Assets/Prefabs/Rewards/BadGoalBounce.prefab +++ b/Assets/Prefabs/Rewards/BadGoalBounce.prefab @@ -138,6 +138,6 @@ MonoBehaviour: numberOfGoals: 1 reward: -1 isMulti: 0 - rewardType: BadGoalMulti + rewardType: BadGoalBounce maximumVelocity: 10 forceToApply: 500 diff --git a/Assets/Prefabs/Rewards/DecoyGoal.prefab b/Assets/Prefabs/Rewards/DecoyGoal.prefab index b1f719a9..b2026753 100644 --- a/Assets/Prefabs/Rewards/DecoyGoal.prefab +++ b/Assets/Prefabs/Rewards/DecoyGoal.prefab @@ -137,5 +137,5 @@ MonoBehaviour: typicalOrigin: 1 numberOfGoals: 1 reward: 0 - isMulti: 0 + isMulti: 1 rewardType: DecoyGoal diff --git a/Assets/Prefabs/Rewards/DecoyGoalBounce.prefab b/Assets/Prefabs/Rewards/DecoyGoalBounce.prefab index 6161a310..993e081f 100644 --- a/Assets/Prefabs/Rewards/DecoyGoalBounce.prefab +++ b/Assets/Prefabs/Rewards/DecoyGoalBounce.prefab @@ -137,7 +137,7 @@ MonoBehaviour: typicalOrigin: 1 numberOfGoals: 1 reward: 0 - isMulti: 0 - rewardType: DecoyGoalMulti + isMulti: 1 + rewardType: DecoyGoalBounce maximumVelocity: 10 forceToApply: 500 diff --git a/Assets/Prefabs/Rewards/GoodGoalMulti.prefab b/Assets/Prefabs/Rewards/GoodGoalMulti.prefab index 5e5baaf7..f4c8b6ae 100644 --- a/Assets/Prefabs/Rewards/GoodGoalMulti.prefab +++ b/Assets/Prefabs/Rewards/GoodGoalMulti.prefab @@ -138,4 +138,4 @@ MonoBehaviour: numberOfGoals: 1 reward: 1 isMulti: 1 - rewardType: GoodGoalBounce + rewardType: GoodGoalMulti From c9f9b873f5f6564dbfe1e12cce4636c6cad65d7b Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Sun, 9 Jun 2024 23:47:33 +0100 Subject: [PATCH 045/205] moved pillar-button mesh to correct folder for coherency as in same place with all other imported game object prefabs --- .../Spawners => Meshes-Models}/Pillar-Button.fbx | Bin .../Pillar-Button.fbx.meta | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename Assets/{Prefabs/Spawners => Meshes-Models}/Pillar-Button.fbx (100%) rename Assets/{Prefabs/Spawners => Meshes-Models}/Pillar-Button.fbx.meta (100%) diff --git a/Assets/Prefabs/Spawners/Pillar-Button.fbx b/Assets/Meshes-Models/Pillar-Button.fbx similarity index 100% rename from Assets/Prefabs/Spawners/Pillar-Button.fbx rename to Assets/Meshes-Models/Pillar-Button.fbx diff --git a/Assets/Prefabs/Spawners/Pillar-Button.fbx.meta b/Assets/Meshes-Models/Pillar-Button.fbx.meta similarity index 100% rename from Assets/Prefabs/Spawners/Pillar-Button.fbx.meta rename to Assets/Meshes-Models/Pillar-Button.fbx.meta From 02a2acd37ae3f464a350617d4f199f2d77d007fb Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Sun, 9 Jun 2024 23:49:09 +0100 Subject: [PATCH 046/205] made changes to record type of reward before logging to .csv a safety check --- Assets/Scripts/Rewards/Goal.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Assets/Scripts/Rewards/Goal.cs b/Assets/Scripts/Rewards/Goal.cs index 1da9b314..c1b7c8f0 100644 --- a/Assets/Scripts/Rewards/Goal.cs +++ b/Assets/Scripts/Rewards/Goal.cs @@ -23,8 +23,8 @@ public virtual void OnTriggerEnter(Collider other) TrainingAgent agent = other.GetComponent(); if (agent != null) { + agent.RecordRewardType(rewardType); // Important to record the reward type before logging to .csv file agent.UpdateHealth(reward, true); - agent.RecordRewardType(rewardType); } } } @@ -36,10 +36,11 @@ public virtual void OnCollisionEnter(Collision collision) TrainingAgent agent = collision.gameObject.GetComponent(); if (agent != null) { + agent.RecordRewardType(rewardType); if (!isMulti) { agent.UpdateHealth(reward, true); - agent.RecordRewardType(rewardType); + Debug.Log($"OnCollisionEnter: Reward type {rewardType} recorded for agent."); } else { @@ -47,7 +48,7 @@ public virtual void OnCollisionEnter(Collision collision) if (agent.numberOfGoalsCollected >= numberOfGoals) { agent.UpdateHealth(reward, true); - agent.RecordRewardType(rewardType); + Debug.Log($"OnCollisionEnter (Multi): Reward type {rewardType} recorded for agent."); } else { From a6438fe7638d6c7f2ce4ee851df16c08b7382026 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Sun, 9 Jun 2024 23:50:26 +0100 Subject: [PATCH 047/205] added code to track dispensed goal directly from parent --- Assets/Scripts/Spawners/GoalSpawner.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Assets/Scripts/Spawners/GoalSpawner.cs b/Assets/Scripts/Spawners/GoalSpawner.cs index d3c88dfe..d34a9eac 100644 --- a/Assets/Scripts/Spawners/GoalSpawner.cs +++ b/Assets/Scripts/Spawners/GoalSpawner.cs @@ -105,6 +105,16 @@ public virtual BallGoal SpawnNewGoal(int listID) if (variableSize) SetVariableSize(newGoal); + TrainingAgent agent = FindObjectOfType(); + if (agent != null) + { + agent.RecordDispensedRewardType(newGoal.rewardType); // Track the dispensed reward type + } + else + { + Debug.LogError("Training Agent not found in the scene."); + } + return newGoal; } From a71184c39fbff962ce336b768d78781f51582d13 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Mon, 10 Jun 2024 00:02:37 +0100 Subject: [PATCH 048/205] added new column to record dispensed rewards (if any) this needs more checks and implementation to cover a wide range of tests, such as what would happen if two dispensers spawned a goal at the very same timeframe - will one overwrite the other? or both be recorded appropriately? --- Assets/Scripts/TrainingAgent.cs | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index e69af389..edabbbb2 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -12,6 +12,9 @@ using System.Collections.Concurrent; using System.Threading; +// TODO: add new column to CSV file for dispensed reward boolean for more clarity and debugging +// TODO: need to check/handle what happens if two dispensed rewards are collected in the same step + /// /// The TrainingAgent class is a subclass of the Agent class in the ML-Agents library. /// It is used to define the behaviour of the agent in the training environment. @@ -70,6 +73,7 @@ public class TrainingAgent : Agent, IPrefab private const int bufferSize = 150; // Corresponds to rows in the CSV file to keep in memory before flushing to disk private bool isFlushing = false; private string lastCollectedRewardType = "None"; + private string dispensedRewardType = "None"; public void RecordRewardType(string type) { @@ -77,6 +81,12 @@ public void RecordRewardType(string type) Debug.Log($"Reward type collected: {type}"); } + public void RecordDispensedRewardType(string type) + { + dispensedRewardType = type; + Debug.Log($"Reward type dispensed: {type}"); + } + public void SetYamlFileName(string fileName) { yamlFileName = fileName; @@ -136,12 +146,12 @@ private void InitialiseCSVProcess() csvFilePath = Path.Combine(directoryPath, filename); writer = new StreamWriter(csvFilePath, true); - + if (!File.Exists(csvFilePath) || new FileInfo(csvFilePath).Length == 0) { if (!headerWritten) { - writer.WriteLine("Episode,Step,Reward,CollectedRewardType,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate,ActionForwardDescription,ActionRotateDescription,IsFrozen,NotificationState"); + writer.WriteLine("Episode,Step,Reward,CollectedRewardType,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate,ActionForwardDescription,ActionRotateDescription,IsFrozen,NotificationState,DispensedRewardType"); headerWritten = true; } else @@ -161,10 +171,11 @@ private void LogToCSV( bool isFrozen, float reward, string notificationState, - int customEpisodeCount + int customEpisodeCount, + string DispensedRewardType ) { - string logEntry = $"{customEpisodeCount},{StepCount},{reward},{lastCollectedRewardType},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate},{actionForwardDescription},{actionRotateDescription},{isFrozen},{notificationState}"; + string logEntry = $"{customEpisodeCount},{StepCount},{reward},{lastCollectedRewardType},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate},{actionForwardDescription},{actionRotateDescription},{isFrozen},{notificationState},{DispensedRewardType}"; logQueue.Enqueue(logEntry); lastCollectedRewardType = "None"; } @@ -275,7 +286,8 @@ public override void CollectObservations(VectorSensor sensor) float reward = GetCumulativeReward(); string notificationState = GetNotificationState(); - LogToCSV(localVel, localPos, lastActionForward, lastActionRotate, actionForwardDescription, actionRotateDescription, isFrozen, reward, notificationState, customEpisodeCount); + LogToCSV(localVel, localPos, lastActionForward, lastActionRotate, actionForwardDescription, actionRotateDescription, isFrozen, reward, notificationState, customEpisodeCount, dispensedRewardType); + dispensedRewardType = "None"; } public override void OnActionReceived(ActionBuffers action) @@ -295,7 +307,9 @@ public override void OnActionReceived(ActionBuffers action) float reward = GetCumulativeReward(); string notificationState = GetNotificationState(); - LogToCSV(localVel, localPos, lastActionForward, lastActionRotate, actionForwardDescription, actionRotateDescription, isFrozen, reward, notificationState, customEpisodeCount); + LogToCSV(localVel, localPos, lastActionForward, lastActionRotate, actionForwardDescription, actionRotateDescription, isFrozen, reward, notificationState, customEpisodeCount, dispensedRewardType); + dispensedRewardType = "None"; + UpdateHealth(_rewardPerStep); } From 7d6f55adf2bacb2e1fc12032f26cb4a5dd7453d4 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Mon, 10 Jun 2024 00:05:38 +0100 Subject: [PATCH 049/205] ignoring data observations folder --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 4807c8cc..ec91c82b 100644 --- a/.gitignore +++ b/.gitignore @@ -112,3 +112,4 @@ Assets/Prefabs/Other-Unique/SignPosterboard.prefab .plastic/plastic.wktree .plastic/plastic.changes .plastic/plastic.wktree +/ObservationLogs From ea82cc98c95c4ea9f69ddf30e516c6e6bb9a4bd4 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Mon, 10 Jun 2024 19:26:33 +0100 Subject: [PATCH 050/205] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index ec91c82b..e565f2bc 100644 --- a/.gitignore +++ b/.gitignore @@ -113,3 +113,4 @@ Assets/Prefabs/Other-Unique/SignPosterboard.prefab .plastic/plastic.changes .plastic/plastic.wktree /ObservationLogs +*.csv From a9669aa5ff2780af18f9a37d7f41e0fb2d47bfcb Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Mon, 10 Jun 2024 19:27:04 +0100 Subject: [PATCH 051/205] added new column to .csv file to record if a reward was dispensed (no matter the type) --- Assets/Scripts/Spawners/GoalSpawner.cs | 3 ++- Assets/Scripts/TrainingAgent.cs | 22 ++++++++++++++++------ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/Assets/Scripts/Spawners/GoalSpawner.cs b/Assets/Scripts/Spawners/GoalSpawner.cs index d34a9eac..2d22a7cd 100644 --- a/Assets/Scripts/Spawners/GoalSpawner.cs +++ b/Assets/Scripts/Spawners/GoalSpawner.cs @@ -108,7 +108,8 @@ public virtual BallGoal SpawnNewGoal(int listID) TrainingAgent agent = FindObjectOfType(); if (agent != null) { - agent.RecordDispensedRewardType(newGoal.rewardType); // Track the dispensed reward type + agent.RecordDispensedRewardType(newGoal.rewardType); // Track the dispensed reward type + agent.RecordDispensedReward(); // Track if a reward was dispensed (no matter the type) } else { diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index edabbbb2..77830687 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -74,6 +74,13 @@ public class TrainingAgent : Agent, IPrefab private bool isFlushing = false; private string lastCollectedRewardType = "None"; private string dispensedRewardType = "None"; + private bool wasRewardDispensed = false; + + public void RecordDispensedReward() + { + wasRewardDispensed = true; // Set the flag when a reward is dispensed + Debug.Log($"Reward was dispensed."); + } public void RecordRewardType(string type) { @@ -151,7 +158,7 @@ private void InitialiseCSVProcess() { if (!headerWritten) { - writer.WriteLine("Episode,Step,Reward,CollectedRewardType,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate,ActionForwardDescription,ActionRotateDescription,IsFrozen,NotificationState,DispensedRewardType"); + writer.WriteLine("Episode,Step,Reward,CollectedRewardType,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate,ActionForwardDescription,ActionRotateDescription,IsFrozen,NotificationState,DispensedRewardType,WasRewardDispensed"); headerWritten = true; } else @@ -172,10 +179,11 @@ private void LogToCSV( float reward, string notificationState, int customEpisodeCount, - string DispensedRewardType + string DispensedRewardType, + bool wasRewardDispensed ) { - string logEntry = $"{customEpisodeCount},{StepCount},{reward},{lastCollectedRewardType},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate},{actionForwardDescription},{actionRotateDescription},{isFrozen},{notificationState},{DispensedRewardType}"; + string logEntry = $"{customEpisodeCount},{StepCount},{reward},{lastCollectedRewardType},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate},{actionForwardDescription},{actionRotateDescription},{isFrozen},{notificationState},{DispensedRewardType},{wasRewardDispensed}"; logQueue.Enqueue(logEntry); lastCollectedRewardType = "None"; } @@ -286,8 +294,9 @@ public override void CollectObservations(VectorSensor sensor) float reward = GetCumulativeReward(); string notificationState = GetNotificationState(); - LogToCSV(localVel, localPos, lastActionForward, lastActionRotate, actionForwardDescription, actionRotateDescription, isFrozen, reward, notificationState, customEpisodeCount, dispensedRewardType); + LogToCSV(localVel, localPos, lastActionForward, lastActionRotate, actionForwardDescription, actionRotateDescription, isFrozen, reward, notificationState, customEpisodeCount, dispensedRewardType, wasRewardDispensed); dispensedRewardType = "None"; + wasRewardDispensed = false; } public override void OnActionReceived(ActionBuffers action) @@ -307,9 +316,10 @@ public override void OnActionReceived(ActionBuffers action) float reward = GetCumulativeReward(); string notificationState = GetNotificationState(); - LogToCSV(localVel, localPos, lastActionForward, lastActionRotate, actionForwardDescription, actionRotateDescription, isFrozen, reward, notificationState, customEpisodeCount, dispensedRewardType); + LogToCSV(localVel, localPos, lastActionForward, lastActionRotate, actionForwardDescription, actionRotateDescription, isFrozen, reward, notificationState, customEpisodeCount, dispensedRewardType, wasRewardDispensed); dispensedRewardType = "None"; - + wasRewardDispensed = false; + UpdateHealth(_rewardPerStep); } From 00c11c82551a76dcc62a1d74641cb123bb69c720 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Mon, 10 Jun 2024 19:29:36 +0100 Subject: [PATCH 052/205] added TODO for .csv feature --- Assets/Scripts/TrainingAgent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 77830687..fce6bd69 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -12,8 +12,8 @@ using System.Collections.Concurrent; using System.Threading; -// TODO: add new column to CSV file for dispensed reward boolean for more clarity and debugging // TODO: need to check/handle what happens if two dispensed rewards are collected in the same step +// TODO: raycasts? how to handle them in the agent? per timeframe or per step? whats the time complexity? does it slow the training down? /// /// The TrainingAgent class is a subclass of the Agent class in the ML-Agents library. From 2becfed88b3f032ac97d09b0243d4561ed706b84 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Mon, 10 Jun 2024 20:03:01 +0100 Subject: [PATCH 053/205] added raycast data to .csv file if enabled in python. https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Learning-Environment-Design-Agents.md#raycast-observations Based on the docs, we can also extract the tags from unity easily but need to check performance --- Assets/Scripts/TrainingAgent.cs | 38 ++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index fce6bd69..924dcd24 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -14,6 +14,9 @@ // TODO: need to check/handle what happens if two dispensed rewards are collected in the same step // TODO: raycasts? how to handle them in the agent? per timeframe or per step? whats the time complexity? does it slow the training down? +// TODO: raycast data is 3+2*raycastCount, and rays per direction is 3, so 3+2*3 = 9, so 9 raycasts per direction, 27 in total resulting in 27*3 = 81 raycasts per step +// add tags of what was hit by the raycast, and the distance to the hit object (?) +// TODO: clean up the code, remove unnecessary comments, and make sure the code is readable and understandable /// /// The TrainingAgent class is a subclass of the Agent class in the ML-Agents library. @@ -158,7 +161,7 @@ private void InitialiseCSVProcess() { if (!headerWritten) { - writer.WriteLine("Episode,Step,Reward,CollectedRewardType,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate,ActionForwardDescription,ActionRotateDescription,IsFrozen,NotificationState,DispensedRewardType,WasRewardDispensed"); + writer.WriteLine("Episode,Step,Reward,CollectedRewardType,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate,ActionForwardDescription,ActionRotateDescription,IsFrozen,NotificationState,DispensedRewardType,WasRewardDispensed,RaycastObservations"); headerWritten = true; } else @@ -180,10 +183,12 @@ private void LogToCSV( string notificationState, int customEpisodeCount, string DispensedRewardType, - bool wasRewardDispensed + bool wasRewardDispensed, + float[] raycastObservations ) { - string logEntry = $"{customEpisodeCount},{StepCount},{reward},{lastCollectedRewardType},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate},{actionForwardDescription},{actionRotateDescription},{isFrozen},{notificationState},{DispensedRewardType},{wasRewardDispensed}"; + string raycastData = string.Join(",", raycastObservations); + string logEntry = $"{customEpisodeCount},{StepCount},{reward},{lastCollectedRewardType},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate},{actionForwardDescription},{actionRotateDescription},{isFrozen},{notificationState},{DispensedRewardType},{wasRewardDispensed},{raycastData}"; logQueue.Enqueue(logEntry); lastCollectedRewardType = "None"; } @@ -294,7 +299,14 @@ public override void CollectObservations(VectorSensor sensor) float reward = GetCumulativeReward(); string notificationState = GetNotificationState(); - LogToCSV(localVel, localPos, lastActionForward, lastActionRotate, actionForwardDescription, actionRotateDescription, isFrozen, reward, notificationState, customEpisodeCount, dispensedRewardType, wasRewardDispensed); + // Collect raycast observations + float[] raycastObservations = CollectRaycastObservations(); + foreach (float observation in raycastObservations) + { + sensor.AddObservation(observation); + } + + LogToCSV(localVel, localPos, lastActionForward, lastActionRotate, actionForwardDescription, actionRotateDescription, isFrozen, reward, notificationState, customEpisodeCount, dispensedRewardType, wasRewardDispensed, raycastObservations); dispensedRewardType = "None"; wasRewardDispensed = false; } @@ -316,13 +328,29 @@ public override void OnActionReceived(ActionBuffers action) float reward = GetCumulativeReward(); string notificationState = GetNotificationState(); - LogToCSV(localVel, localPos, lastActionForward, lastActionRotate, actionForwardDescription, actionRotateDescription, isFrozen, reward, notificationState, customEpisodeCount, dispensedRewardType, wasRewardDispensed); + // Collect raycast observations + float[] raycastObservations = CollectRaycastObservations(); + + LogToCSV(localVel, localPos, lastActionForward, lastActionRotate, actionForwardDescription, actionRotateDescription, isFrozen, reward, notificationState, customEpisodeCount, dispensedRewardType, wasRewardDispensed, raycastObservations); dispensedRewardType = "None"; wasRewardDispensed = false; UpdateHealth(_rewardPerStep); } + private float[] CollectRaycastObservations() + { + RayPerceptionSensorComponent3D rayPerception = GetComponent(); + if (rayPerception == null) + { + return new float[0]; + } + + var rayPerceptionInput = rayPerception.GetRayPerceptionInput(); + var rayPerceptionOutput = RayPerceptionSensor.Perceive(rayPerceptionInput); + return rayPerceptionOutput.RayOutputs.Select(r => r.HitFraction).ToArray(); + } + private string DescribeActionForward(int actionForward) { From 3cbc7cd83658bb81d4545e97f29071dbe3ee60e6 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Mon, 10 Jun 2024 20:06:12 +0100 Subject: [PATCH 054/205] added method summaries for later recall --- Assets/Scripts/TrainingAgent.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 924dcd24..154e82a1 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -11,6 +11,7 @@ using System.IO; using System.Collections.Concurrent; using System.Threading; +using System.ComponentModel; // TODO: need to check/handle what happens if two dispensed rewards are collected in the same step // TODO: raycasts? how to handle them in the agent? per timeframe or per step? whats the time complexity? does it slow the training down? @@ -171,6 +172,9 @@ private void InitialiseCSVProcess() } } + /// + /// Logs the agent's state to a CSV file. This is called every step. The data is stored in a queue and flushed to the file in a separate thread. + /// private void LogToCSV( Vector3 velocity, Vector3 position, @@ -193,7 +197,9 @@ float[] raycastObservations lastCollectedRewardType = "None"; } - + /// + /// Flushes the log queue to the CSV file. This is called in a separate thread to prevent the main thread from being blocked. + /// private void FlushLogQueue() { while (logQueue.TryDequeue(out var logEntry)) @@ -204,6 +210,10 @@ private void FlushLogQueue() Debug.Log("Flushed log queue to CSV file."); } + /// + /// Starts a thread that checks if the log queue is full and flushes it to the CSV file if it is. + // WARNING: im not sure if this is the best way to handle this, but it works for now + /// private void StartFlushThread() { new Thread(() => @@ -221,6 +231,9 @@ private void StartFlushThread() }).Start(); } + /// + /// OnDisable is called when the training session is stopped form mlagents. It closes the CSV file and flushes the log queue at whatever the current size is. + /// protected override void OnDisable() { base.OnDisable(); From 67965d98454e5b40bfe21a3728ca83a2bae6f34d Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Mon, 10 Jun 2024 20:21:28 +0100 Subject: [PATCH 055/205] added doc ref on batched raycasts might be a good alternative to sequential --- Assets/Scripts/TrainingAgent.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 154e82a1..8ba91150 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -17,6 +17,7 @@ // TODO: raycasts? how to handle them in the agent? per timeframe or per step? whats the time complexity? does it slow the training down? // TODO: raycast data is 3+2*raycastCount, and rays per direction is 3, so 3+2*3 = 9, so 9 raycasts per direction, 27 in total resulting in 27*3 = 81 raycasts per step // add tags of what was hit by the raycast, and the distance to the hit object (?) +// batched raycasts? (https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Learning-Environment-Design-Agents.md#raycast-observations) // TODO: clean up the code, remove unnecessary comments, and make sure the code is readable and understandable /// From 939ebf6d65022d1a09a3fca65922e0b97544145c Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Mon, 10 Jun 2024 20:24:02 +0100 Subject: [PATCH 056/205] corrected calculation on raycasts in comments --- Assets/Scripts/TrainingAgent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 8ba91150..41d6c0c8 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -15,7 +15,7 @@ // TODO: need to check/handle what happens if two dispensed rewards are collected in the same step // TODO: raycasts? how to handle them in the agent? per timeframe or per step? whats the time complexity? does it slow the training down? -// TODO: raycast data is 3+2*raycastCount, and rays per direction is 3, so 3+2*3 = 9, so 9 raycasts per direction, 27 in total resulting in 27*3 = 81 raycasts per step +// TODO: raycast data is (Observation Stacks) * (1 + 2 * Rays Per Direction) * (Num Detectable Tags + 2) --> corrected calculation // add tags of what was hit by the raycast, and the distance to the hit object (?) // batched raycasts? (https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Learning-Environment-Design-Agents.md#raycast-observations) // TODO: clean up the code, remove unnecessary comments, and make sure the code is readable and understandable From cabfca26ef84f3516c5da899493295db3cc41916 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 12 Jun 2024 18:52:40 +0100 Subject: [PATCH 057/205] added raycast tags to .csv file (if enabled in python script) --- Assets/Scripts/TrainingAgent.cs | 93 +++++++++++++++++++++++---------- 1 file changed, 66 insertions(+), 27 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 41d6c0c8..be534bac 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -83,7 +83,7 @@ public class TrainingAgent : Agent, IPrefab public void RecordDispensedReward() { - wasRewardDispensed = true; // Set the flag when a reward is dispensed + wasRewardDispensed = true; Debug.Log($"Reward was dispensed."); } @@ -163,7 +163,9 @@ private void InitialiseCSVProcess() { if (!headerWritten) { - writer.WriteLine("Episode,Step,Reward,CollectedRewardType,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate,ActionForwardDescription,ActionRotateDescription,IsFrozen,NotificationState,DispensedRewardType,WasRewardDispensed,RaycastObservations"); + writer.WriteLine( + "Episode,Step,Reward,CollectedRewardType,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate,ActionForwardDescription,ActionRotateDescription,IsFrozen,NotificationState,DispensedRewardType,WasRewardDispensed,RaycastObservations,RaycastTags" + ); headerWritten = true; } else @@ -177,23 +179,26 @@ private void InitialiseCSVProcess() /// Logs the agent's state to a CSV file. This is called every step. The data is stored in a queue and flushed to the file in a separate thread. /// private void LogToCSV( - Vector3 velocity, - Vector3 position, - int lastActionForward, - int lastActionRotate, - string actionForwardDescription, - string actionRotateDescription, - bool isFrozen, - float reward, - string notificationState, - int customEpisodeCount, - string DispensedRewardType, - bool wasRewardDispensed, - float[] raycastObservations + Vector3 velocity, + Vector3 position, + int lastActionForward, + int lastActionRotate, + string actionForwardDescription, + string actionRotateDescription, + bool isFrozen, + float reward, + string notificationState, + int customEpisodeCount, + string DispensedRewardType, + bool wasRewardDispensed, + float[] raycastObservations, + string[] raycastTags ) { string raycastData = string.Join(",", raycastObservations); - string logEntry = $"{customEpisodeCount},{StepCount},{reward},{lastCollectedRewardType},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate},{actionForwardDescription},{actionRotateDescription},{isFrozen},{notificationState},{DispensedRewardType},{wasRewardDispensed},{raycastData}"; + string raycastTagsData = string.Join(",", raycastTags); + string logEntry = + $"{customEpisodeCount},{StepCount},{reward},{lastCollectedRewardType},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate},{actionForwardDescription},{actionRotateDescription},{isFrozen},{notificationState},{DispensedRewardType},{wasRewardDispensed},{raycastData},{raycastTagsData}"; logQueue.Enqueue(logEntry); lastCollectedRewardType = "None"; } @@ -313,14 +318,28 @@ public override void CollectObservations(VectorSensor sensor) float reward = GetCumulativeReward(); string notificationState = GetNotificationState(); - // Collect raycast observations - float[] raycastObservations = CollectRaycastObservations(); + (float[] raycastObservations, string[] raycastTags) = CollectRaycastObservations(); foreach (float observation in raycastObservations) { sensor.AddObservation(observation); } - LogToCSV(localVel, localPos, lastActionForward, lastActionRotate, actionForwardDescription, actionRotateDescription, isFrozen, reward, notificationState, customEpisodeCount, dispensedRewardType, wasRewardDispensed, raycastObservations); + LogToCSV( + localVel, + localPos, + lastActionForward, + lastActionRotate, + actionForwardDescription, + actionRotateDescription, + isFrozen, + reward, + notificationState, + customEpisodeCount, + dispensedRewardType, + wasRewardDispensed, + raycastObservations, + raycastTags + ); dispensedRewardType = "None"; wasRewardDispensed = false; } @@ -343,28 +362,48 @@ public override void OnActionReceived(ActionBuffers action) string notificationState = GetNotificationState(); // Collect raycast observations - float[] raycastObservations = CollectRaycastObservations(); - - LogToCSV(localVel, localPos, lastActionForward, lastActionRotate, actionForwardDescription, actionRotateDescription, isFrozen, reward, notificationState, customEpisodeCount, dispensedRewardType, wasRewardDispensed, raycastObservations); + (float[] raycastObservations, string[] raycastTags) = CollectRaycastObservations(); + + LogToCSV( + localVel, + localPos, + lastActionForward, + lastActionRotate, + actionForwardDescription, + actionRotateDescription, + isFrozen, + reward, + notificationState, + customEpisodeCount, + dispensedRewardType, + wasRewardDispensed, + raycastObservations, + raycastTags + ); dispensedRewardType = "None"; wasRewardDispensed = false; UpdateHealth(_rewardPerStep); } - private float[] CollectRaycastObservations() + private (float[] hitFractions, string[] hitTags) CollectRaycastObservations() { - RayPerceptionSensorComponent3D rayPerception = GetComponent(); + RayPerceptionSensorComponent3D rayPerception = + GetComponent(); if (rayPerception == null) { - return new float[0]; + return (new float[0], new string[0]); } var rayPerceptionInput = rayPerception.GetRayPerceptionInput(); var rayPerceptionOutput = RayPerceptionSensor.Perceive(rayPerceptionInput); - return rayPerceptionOutput.RayOutputs.Select(r => r.HitFraction).ToArray(); - } + float[] hitFractions = rayPerceptionOutput.RayOutputs.Select(r => r.HitFraction).ToArray(); + string[] hitTags = rayPerceptionOutput.RayOutputs + .Select(r => r.HitGameObject?.tag ?? "None") + .ToArray(); + return (hitFractions, hitTags); + } private string DescribeActionForward(int actionForward) { From bfcc311075a97c1721f6f29c5c60a35b4621288e Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 12 Jun 2024 18:56:49 +0100 Subject: [PATCH 058/205] removed one todo item --- Assets/Scripts/TrainingAgent.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index be534bac..1a07104b 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -14,7 +14,6 @@ using System.ComponentModel; // TODO: need to check/handle what happens if two dispensed rewards are collected in the same step -// TODO: raycasts? how to handle them in the agent? per timeframe or per step? whats the time complexity? does it slow the training down? // TODO: raycast data is (Observation Stacks) * (1 + 2 * Rays Per Direction) * (Num Detectable Tags + 2) --> corrected calculation // add tags of what was hit by the raycast, and the distance to the hit object (?) // batched raycasts? (https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Learning-Environment-Design-Agents.md#raycast-observations) From 3fdcebe6a80231242514c2ea1561bd557f3becac Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 12 Jun 2024 22:17:21 +0100 Subject: [PATCH 059/205] added logic to log event when (and if) spawnerbutton was triggered using same event/delegate subscription from spawner_interactivebutton.cs. Might need to see if this will cause any errors with multiple spawnerbuttons but unlikely... --- .../Spawners/Spawner_InteractiveButton.cs | 565 +++++++++--------- Assets/Scripts/TrainingAgent.cs | 20 +- 2 files changed, 299 insertions(+), 286 deletions(-) diff --git a/Assets/Scripts/Spawners/Spawner_InteractiveButton.cs b/Assets/Scripts/Spawners/Spawner_InteractiveButton.cs index 534f6b8f..c9d20dd4 100644 --- a/Assets/Scripts/Spawners/Spawner_InteractiveButton.cs +++ b/Assets/Scripts/Spawners/Spawner_InteractiveButton.cs @@ -9,286 +9,287 @@ /// public class Spawner_InteractiveButton : MonoBehaviour { - public List RewardNames { get; set; } - public List RewardWeights { get; set; } - public List Rewards { get; set; } - public Vector3 RewardSpawnPos { get; set; } - public List MaxRewardCounts { get; set; } - public int ButtonPressCount { get; private set; } - public GameObject LastSpawnedReward { get; private set; } - public float SpawnProbability { get; set; } = 1f; - private List rewards; - private List rewardWeights; - public Dictionary RewardSpawnCounts { get; private set; } = - new Dictionary(); - private bool IsMoving = false; - private float lastInteractionTime; - private float totalInteractionInterval = 0f; - private float _moveDuration; - private float _resetDuration; - - private ArenaBuilder arenaBuilder; - private Transform objectToControlSpawnPoint; - public delegate void OnRewardSpawned(GameObject reward); - public static event OnRewardSpawned RewardSpawned; - - [SerializeField] - private GameObject childObjectToMove; - - [SerializeField] - private Vector3 moveOffset; - - [SerializeField] - private Transform rewardSpawnPoint; - - [SerializeField] - private GameObject objectToControl; - - [SerializeField] - private bool showObject; - - public float MoveDuration - { - get { return _moveDuration; } - set { _moveDuration = value; } - } - public float ResetDuration - { - get { return _resetDuration; } - set { _resetDuration = value; } - } - - void Start() - { - lastInteractionTime = Time.time; - - UpdateObjectVisibility(); - - if (RewardNames != null && RewardNames.Count > 0) - { - Rewards = RewardNames - .Select(name => - { - GameObject reward = Resources.Load(name); - if (reward == null) - { - Debug.LogError($"Failed to load reward: {name}"); - } - return reward; - }) - .ToList(); - } - - rewardWeights = RewardWeights; - } - - private void OnTriggerEnter(Collider other) - { - if (other.CompareTag("agent")) - { - if (IsMoving) - { - return; - } - - ButtonPressCount++; - StartCoroutine(MoveAndReset()); - } - } - - private void UpdateObjectVisibility() - { - if (objectToControl != null) - { - objectToControl.SetActive(showObject); - } - } - - public bool MoveToTarget(Vector3 origin, Vector3 target, float startTime, float duration) - { - float t = (Time.time - startTime) / duration; - childObjectToMove.transform.position = Vector3.Lerp(origin, target, t); - return Time.time < startTime + duration; - } - - public IEnumerator MoveAndReset() - { - IsMoving = true; - - Vector3 originalPosition = childObjectToMove.transform.position; - Vector3 movementDirection = -transform.forward * moveOffset.x; // Use parent object's negative local Z axis - Vector3 targetPosition = originalPosition + movementDirection; - float startTime = Time.time; - - while (MoveToTarget(originalPosition, targetPosition, startTime, MoveDuration)) - { - yield return null; - } - childObjectToMove.transform.position = targetPosition; - - startTime = Time.time; - while (MoveToTarget(targetPosition, originalPosition, startTime, ResetDuration)) - { - yield return null; - } - childObjectToMove.transform.position = originalPosition; - - SpawnReward(); - - IsMoving = false; - } - - private GameObject ChooseReward() - { - if (Rewards == null || rewardWeights == null || Rewards.Count != rewardWeights.Count) - { - Debug.LogError("Invalid rewards or reward weights setup."); - return null; - } - - float totalWeight = rewardWeights.Sum(); - float randomNumber = Random.Range(0, totalWeight - float.Epsilon); - float cumulativeWeight = 0; - - for (int i = 0; i < Rewards.Count; i++) - { - cumulativeWeight += rewardWeights[i]; - if (randomNumber <= cumulativeWeight) - { - return Rewards[i]; - } - } - - // If no reward is selected within the loop (which should not happen), return the last reward - return Rewards[Rewards.Count - 1]; - } - - private void SpawnReward() - { - GameObject rewardToSpawn = ChooseReward(); - - if (rewardToSpawn == null) - { - Debug.LogError("Failed to choose a reward to spawn."); - return; - } - - int rewardIndex = Rewards.IndexOf(rewardToSpawn); - if (rewardIndex == -1) - { - Debug.LogError("Chosen reward is not in the Rewards list."); - return; - } - - if (rewardIndex < MaxRewardCounts.Count) - { - Debug.Log( - "Max allowed spawns for " + rewardToSpawn.name + ": " + MaxRewardCounts[rewardIndex] - ); - } - else - { - Debug.Log("No max spawn count set for " + rewardToSpawn.name); - } - - if ( - MaxRewardCounts != null - && rewardIndex < MaxRewardCounts.Count - && MaxRewardCounts[rewardIndex] != -1 - ) - { - if ( - RewardSpawnCounts.TryGetValue(rewardToSpawn, out var count) - && count >= MaxRewardCounts[rewardIndex] - ) - { - Debug.Log("Max reward count reached for reward: " + rewardToSpawn.name); - return; - } - } - - if (Rewards == null || Rewards.Count == 0) - { - Debug.LogError("No rewards are set to be spawned."); - return; - } - - if (Random.value <= SpawnProbability) - { - Vector3 spawnPosition = rewardSpawnPoint.position; - - if (RewardSpawnPos != Vector3.zero) - { - spawnPosition = RewardSpawnPos; - } - // Otherwise, random spawning. - else - { - float arenaWidth = arenaBuilder.ArenaWidth; - float arenaDepth = arenaBuilder.ArenaDepth; - - // Randomly generate a spawn position within the bounds of the arena, as defined by Arenabuilders.cs. - spawnPosition = new Vector3( - Random.Range(0, arenaWidth), - 0, // Assuming spawning on the ground. - Random.Range(0, arenaDepth) - ); - } - // Check for randomization flags for x and z axes - if (RewardSpawnPos.x == -1) - { - spawnPosition.x = Random.Range(0, arenaBuilder.ArenaWidth); - } - - if (RewardSpawnPos.y == -1) - { - spawnPosition.y = Random.Range(0, 50); - Debug.Log("Randomized y: " + spawnPosition.y); - } - else - { - spawnPosition.y = RewardSpawnPos.y; - Debug.Log("Set y to: " + spawnPosition.y); - } - - if (RewardSpawnPos.z == -1) - { - spawnPosition.z = Random.Range(0, arenaBuilder.ArenaDepth); - } - - LastSpawnedReward = Instantiate(rewardToSpawn, spawnPosition, Quaternion.identity); - - if (RewardSpawnCounts.TryGetValue(rewardToSpawn, out var count)) - { - RewardSpawnCounts[rewardToSpawn] = count + 1; - } - else - { - RewardSpawnCounts[rewardToSpawn] = 1; - } - - if (showObject && objectToControl != null) - { - Instantiate( - objectToControl, - objectToControlSpawnPoint.transform.position, - Quaternion.identity - ); - } - - float currentInteractionTime = Time.time; - totalInteractionInterval += currentInteractionTime - lastInteractionTime; - lastInteractionTime = currentInteractionTime; - - RewardSpawned?.Invoke(LastSpawnedReward); - } - } - - public float GetAverageInteractionInterval() - { - if (ButtonPressCount == 0) - return 0; - - return totalInteractionInterval / ButtonPressCount; - } + public List RewardNames { get; set; } + public List RewardWeights { get; set; } + public List Rewards { get; set; } + public Vector3 RewardSpawnPos { get; set; } + public List MaxRewardCounts { get; set; } + public int ButtonPressCount { get; private set; } + public GameObject LastSpawnedReward { get; private set; } + public float SpawnProbability { get; set; } = 1f; + private List rewards; + private List rewardWeights; + public Dictionary RewardSpawnCounts { get; private set; } = + new Dictionary(); + private bool IsMoving = false; + private float lastInteractionTime; + private float totalInteractionInterval = 0f; + private float _moveDuration; + private float _resetDuration; + + private ArenaBuilder arenaBuilder; + private Transform objectToControlSpawnPoint; + public delegate void OnRewardSpawned(GameObject reward); + public static event OnRewardSpawned RewardSpawned; + + [SerializeField] + private GameObject childObjectToMove; + + [SerializeField] + private Vector3 moveOffset; + + [SerializeField] + private Transform rewardSpawnPoint; + + [SerializeField] + private GameObject objectToControl; + + [SerializeField] + private bool showObject; + + public float MoveDuration + { + get { return _moveDuration; } + set { _moveDuration = value; } + } + public float ResetDuration + { + get { return _resetDuration; } + set { _resetDuration = value; } + } + + void Start() + { + lastInteractionTime = Time.time; + + UpdateObjectVisibility(); + + if (RewardNames != null && RewardNames.Count > 0) + { + Rewards = RewardNames + .Select(name => + { + GameObject reward = Resources.Load(name); + if (reward == null) + { + Debug.LogError($"Failed to load reward: {name}"); + } + return reward; + }) + .ToList(); + } + + rewardWeights = RewardWeights; + } + + private void OnTriggerEnter(Collider other) + { + if (other.CompareTag("agent")) + { + if (IsMoving) + { + return; + } + + ButtonPressCount++; + StartCoroutine(MoveAndReset()); + RewardSpawned?.Invoke(null); + } + } + + private void UpdateObjectVisibility() + { + if (objectToControl != null) + { + objectToControl.SetActive(showObject); + } + } + + public bool MoveToTarget(Vector3 origin, Vector3 target, float startTime, float duration) + { + float t = (Time.time - startTime) / duration; + childObjectToMove.transform.position = Vector3.Lerp(origin, target, t); + return Time.time < startTime + duration; + } + + public IEnumerator MoveAndReset() + { + IsMoving = true; + + Vector3 originalPosition = childObjectToMove.transform.position; + Vector3 movementDirection = -transform.forward * moveOffset.x; // Use parent object's negative local Z axis + Vector3 targetPosition = originalPosition + movementDirection; + float startTime = Time.time; + + while (MoveToTarget(originalPosition, targetPosition, startTime, MoveDuration)) + { + yield return null; + } + childObjectToMove.transform.position = targetPosition; + + startTime = Time.time; + while (MoveToTarget(targetPosition, originalPosition, startTime, ResetDuration)) + { + yield return null; + } + childObjectToMove.transform.position = originalPosition; + + SpawnReward(); + + IsMoving = false; + } + + private GameObject ChooseReward() + { + if (Rewards == null || rewardWeights == null || Rewards.Count != rewardWeights.Count) + { + Debug.LogError("Invalid rewards or reward weights setup."); + return null; + } + + float totalWeight = rewardWeights.Sum(); + float randomNumber = Random.Range(0, totalWeight - float.Epsilon); + float cumulativeWeight = 0; + + for (int i = 0; i < Rewards.Count; i++) + { + cumulativeWeight += rewardWeights[i]; + if (randomNumber <= cumulativeWeight) + { + return Rewards[i]; + } + } + + // If no reward is selected within the loop (which should not happen), return the last reward + return Rewards[Rewards.Count - 1]; + } + + private void SpawnReward() + { + GameObject rewardToSpawn = ChooseReward(); + + if (rewardToSpawn == null) + { + Debug.LogError("Failed to choose a reward to spawn."); + return; + } + + int rewardIndex = Rewards.IndexOf(rewardToSpawn); + if (rewardIndex == -1) + { + Debug.LogError("Chosen reward is not in the Rewards list."); + return; + } + + if (rewardIndex < MaxRewardCounts.Count) + { + Debug.Log( + "Max allowed spawns for " + rewardToSpawn.name + ": " + MaxRewardCounts[rewardIndex] + ); + } + else + { + Debug.Log("No max spawn count set for " + rewardToSpawn.name); + } + + if ( + MaxRewardCounts != null + && rewardIndex < MaxRewardCounts.Count + && MaxRewardCounts[rewardIndex] != -1 + ) + { + if ( + RewardSpawnCounts.TryGetValue(rewardToSpawn, out var count) + && count >= MaxRewardCounts[rewardIndex] + ) + { + Debug.Log("Max reward count reached for reward: " + rewardToSpawn.name); + return; + } + } + + if (Rewards == null || Rewards.Count == 0) + { + Debug.LogError("No rewards are set to be spawned."); + return; + } + + if (Random.value <= SpawnProbability) + { + Vector3 spawnPosition = rewardSpawnPoint.position; + + if (RewardSpawnPos != Vector3.zero) + { + spawnPosition = RewardSpawnPos; + } + // Otherwise, random spawning. + else + { + float arenaWidth = arenaBuilder.ArenaWidth; + float arenaDepth = arenaBuilder.ArenaDepth; + + // Randomly generate a spawn position within the bounds of the arena, as defined by Arenabuilders.cs. + spawnPosition = new Vector3( + Random.Range(0, arenaWidth), + 0, // Assuming spawning on the ground. + Random.Range(0, arenaDepth) + ); + } + // Check for randomization flags for x and z axes + if (RewardSpawnPos.x == -1) + { + spawnPosition.x = Random.Range(0, arenaBuilder.ArenaWidth); + } + + if (RewardSpawnPos.y == -1) + { + spawnPosition.y = Random.Range(0, 50); + Debug.Log("Randomized y: " + spawnPosition.y); + } + else + { + spawnPosition.y = RewardSpawnPos.y; + Debug.Log("Set y to: " + spawnPosition.y); + } + + if (RewardSpawnPos.z == -1) + { + spawnPosition.z = Random.Range(0, arenaBuilder.ArenaDepth); + } + + LastSpawnedReward = Instantiate(rewardToSpawn, spawnPosition, Quaternion.identity); + + if (RewardSpawnCounts.TryGetValue(rewardToSpawn, out var count)) + { + RewardSpawnCounts[rewardToSpawn] = count + 1; + } + else + { + RewardSpawnCounts[rewardToSpawn] = 1; + } + + if (showObject && objectToControl != null) + { + Instantiate( + objectToControl, + objectToControlSpawnPoint.transform.position, + Quaternion.identity + ); + } + + float currentInteractionTime = Time.time; + totalInteractionInterval += currentInteractionTime - lastInteractionTime; + lastInteractionTime = currentInteractionTime; + + RewardSpawned?.Invoke(LastSpawnedReward); + } + } + + public float GetAverageInteractionInterval() + { + if (ButtonPressCount == 0) + return 0; + + return totalInteractionInterval / ButtonPressCount; + } } diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 1a07104b..b501c4ed 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -11,11 +11,9 @@ using System.IO; using System.Collections.Concurrent; using System.Threading; -using System.ComponentModel; // TODO: need to check/handle what happens if two dispensed rewards are collected in the same step // TODO: raycast data is (Observation Stacks) * (1 + 2 * Rays Per Direction) * (Num Detectable Tags + 2) --> corrected calculation -// add tags of what was hit by the raycast, and the distance to the hit object (?) // batched raycasts? (https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Learning-Environment-Design-Agents.md#raycast-observations) // TODO: clean up the code, remove unnecessary comments, and make sure the code is readable and understandable @@ -79,6 +77,12 @@ public class TrainingAgent : Agent, IPrefab private string lastCollectedRewardType = "None"; private string dispensedRewardType = "None"; private bool wasRewardDispensed = false; + private bool wasButtonPressed = false; + + private void OnRewardSpawned(GameObject reward) + { + wasButtonPressed = true; + } public void RecordDispensedReward() { @@ -124,6 +128,7 @@ public override void Initialize() } StartFlushThread(); + Spawner_InteractiveButton.RewardSpawned += OnRewardSpawned; } private void InitialiseCSVProcess() @@ -163,7 +168,7 @@ private void InitialiseCSVProcess() if (!headerWritten) { writer.WriteLine( - "Episode,Step,Reward,CollectedRewardType,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate,ActionForwardDescription,ActionRotateDescription,IsFrozen,NotificationState,DispensedRewardType,WasRewardDispensed,RaycastObservations,RaycastTags" + "Episode,Step,Reward,CollectedRewardType,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate,ActionForwardDescription,ActionRotateDescription,IsFrozen,NotificationState,DispensedRewardType,WasRewardDispensed,WasButtonPressed,RaycastObservations,RaycastTags" ); headerWritten = true; } @@ -190,14 +195,16 @@ private void LogToCSV( int customEpisodeCount, string DispensedRewardType, bool wasRewardDispensed, + bool wasButtonPressed, float[] raycastObservations, string[] raycastTags + ) { string raycastData = string.Join(",", raycastObservations); string raycastTagsData = string.Join(",", raycastTags); string logEntry = - $"{customEpisodeCount},{StepCount},{reward},{lastCollectedRewardType},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate},{actionForwardDescription},{actionRotateDescription},{isFrozen},{notificationState},{DispensedRewardType},{wasRewardDispensed},{raycastData},{raycastTagsData}"; + $"{customEpisodeCount},{StepCount},{reward},{lastCollectedRewardType},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate},{actionForwardDescription},{actionRotateDescription},{isFrozen},{notificationState},{DispensedRewardType},{wasRewardDispensed},{wasButtonPressed},{raycastData},{raycastTagsData}"; logQueue.Enqueue(logEntry); lastCollectedRewardType = "None"; } @@ -336,11 +343,14 @@ public override void CollectObservations(VectorSensor sensor) customEpisodeCount, dispensedRewardType, wasRewardDispensed, + wasButtonPressed, raycastObservations, raycastTags + ); dispensedRewardType = "None"; wasRewardDispensed = false; + wasButtonPressed = false; } public override void OnActionReceived(ActionBuffers action) @@ -376,11 +386,13 @@ public override void OnActionReceived(ActionBuffers action) customEpisodeCount, dispensedRewardType, wasRewardDispensed, + wasButtonPressed, raycastObservations, raycastTags ); dispensedRewardType = "None"; wasRewardDispensed = false; + wasButtonPressed = false; UpdateHealth(_rewardPerStep); } From 605955da8c578be86251eeaa7222c90cf1dc2359 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 12 Jun 2024 22:18:27 +0100 Subject: [PATCH 060/205] minor - debug log added --- Assets/Scripts/TrainingAgent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index b501c4ed..54e8888f 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -29,7 +29,6 @@ public class TrainingAgent : Agent, IPrefab public float quickStopRatio = 0.9f; public float rotationSpeed = 100f; public float rotationAngle = 0.25f; - private int lastActionForward = 0; private int lastActionRotate = 0; @@ -82,6 +81,7 @@ public class TrainingAgent : Agent, IPrefab private void OnRewardSpawned(GameObject reward) { wasButtonPressed = true; + Debug.Log("Button was pressed."); } public void RecordDispensedReward() From 5cdf8f369e70012bd2c800d3c90f59c9f87db13e Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 12 Jun 2024 22:20:13 +0100 Subject: [PATCH 061/205] minor shuffle --- Assets/Scripts/TrainingAgent.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 54e8888f..2553430c 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -116,6 +116,8 @@ public override void Initialize() progBar.AssignAgent(this); health = _maxHealth; + Spawner_InteractiveButton.RewardSpawned += OnRewardSpawned; + InitialiseCSVProcess(); if (!Application.isEditor) @@ -128,7 +130,6 @@ public override void Initialize() } StartFlushThread(); - Spawner_InteractiveButton.RewardSpawned += OnRewardSpawned; } private void InitialiseCSVProcess() From 63b8a2d800d7df835d50602bb426a70460122f85 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 12 Jun 2024 22:21:45 +0100 Subject: [PATCH 062/205] minor changes --- Assets/Scripts/TrainingAgent.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 2553430c..b0781555 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -371,7 +371,7 @@ public override void OnActionReceived(ActionBuffers action) float reward = GetCumulativeReward(); string notificationState = GetNotificationState(); - // Collect raycast observations + // Collect raycast observations and tags directly from the RayPerceptionSensorComponent3D (float[] raycastObservations, string[] raycastTags) = CollectRaycastObservations(); LogToCSV( @@ -615,7 +615,7 @@ public override void OnEpisodeBegin() customEpisodeCount++; writer.Flush(); - EpisodeDebugLog(); + EpisodeDebugLogs(); StopCoroutine("UnfreezeCountdown"); _previousScore = _currentScore; @@ -628,7 +628,7 @@ public override void OnEpisodeBegin() SetFreezeDelay(GetFreezeDelay()); } - private void EpisodeDebugLog() + private void EpisodeDebugLogs() { Debug.Log("Episode Begin"); Debug.Log($"Value of showNotification: {showNotification}"); From a6085a45edf231753e7802f2f5a3caf7797f309e Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 12 Jun 2024 22:23:52 +0100 Subject: [PATCH 063/205] added code to stop listening to event to avoid memory leak for spawnerbutton which the script uses to check if the button was pressed/triggered --- Assets/Scripts/TrainingAgent.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index b0781555..61a6e5f3 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -255,6 +255,8 @@ protected override void OnDisable() FlushLogQueue(); // Ensures all buffered data is written to the file before closing (important for builds) writer.Close(); } + + Spawner_InteractiveButton.RewardSpawned -= OnRewardSpawned; } public float GetPreviousScore() From 83c89d144ec95506d82e02ee4d92b37d79cdf7fe Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 12 Jun 2024 22:29:33 +0100 Subject: [PATCH 064/205] cleaned up spawnerbutton script removed redundant code and logic --- Assets/Prefabs/Spawners/SpawnerButton.prefab | 34 ------------------- .../Spawners/Spawner_InteractiveButton.cs | 29 +--------------- 2 files changed, 1 insertion(+), 62 deletions(-) diff --git a/Assets/Prefabs/Spawners/SpawnerButton.prefab b/Assets/Prefabs/Spawners/SpawnerButton.prefab index cc3daff8..1ea7e99c 100644 --- a/Assets/Prefabs/Spawners/SpawnerButton.prefab +++ b/Assets/Prefabs/Spawners/SpawnerButton.prefab @@ -211,8 +211,6 @@ MonoBehaviour: childObjectToMove: {fileID: 2667445423738929804} moveOffset: {x: 0.09, y: 0, z: 0} rewardSpawnPoint: {fileID: 5820607059387166607} - objectToControl: {fileID: 7150004164178407081, guid: b19f8e36bd5ca73489a251d8daa9acea, type: 3} - showObject: 0 --- !u!1 &2667445423738929804 GameObject: m_ObjectHideFlags: 0 @@ -245,7 +243,6 @@ Transform: m_ConstrainProportionsScale: 0 m_Children: - {fileID: 9108657385940890846} - - {fileID: 5127077261990454499} - {fileID: 5820607059387166607} m_Father: {fileID: 5827418943653793803} m_RootOrder: 1 @@ -343,37 +340,6 @@ Transform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 360676509772820413} - m_RootOrder: 2 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &4555237295060351392 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 5127077261990454499} - m_Layer: 0 - m_Name: SignPosterSpawnLocation - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &5127077261990454499 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4555237295060351392} - m_LocalRotation: {x: -0, y: -0.7071067, z: 0, w: 0.7071068} - m_LocalPosition: {x: 0.0050915945, y: 0.05213615, z: -0.0027317442} - m_LocalScale: {x: 2.529393, y: 2.529394, z: 2.529393} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 360676509772820413} m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &6599169884992408241 diff --git a/Assets/Scripts/Spawners/Spawner_InteractiveButton.cs b/Assets/Scripts/Spawners/Spawner_InteractiveButton.cs index c9d20dd4..11fe70dd 100644 --- a/Assets/Scripts/Spawners/Spawner_InteractiveButton.cs +++ b/Assets/Scripts/Spawners/Spawner_InteractiveButton.cs @@ -17,7 +17,6 @@ public class Spawner_InteractiveButton : MonoBehaviour public int ButtonPressCount { get; private set; } public GameObject LastSpawnedReward { get; private set; } public float SpawnProbability { get; set; } = 1f; - private List rewards; private List rewardWeights; public Dictionary RewardSpawnCounts { get; private set; } = new Dictionary(); @@ -28,7 +27,6 @@ public class Spawner_InteractiveButton : MonoBehaviour private float _resetDuration; private ArenaBuilder arenaBuilder; - private Transform objectToControlSpawnPoint; public delegate void OnRewardSpawned(GameObject reward); public static event OnRewardSpawned RewardSpawned; @@ -41,12 +39,6 @@ public class Spawner_InteractiveButton : MonoBehaviour [SerializeField] private Transform rewardSpawnPoint; - [SerializeField] - private GameObject objectToControl; - - [SerializeField] - private bool showObject; - public float MoveDuration { get { return _moveDuration; } @@ -62,8 +54,6 @@ void Start() { lastInteractionTime = Time.time; - UpdateObjectVisibility(); - if (RewardNames != null && RewardNames.Count > 0) { Rewards = RewardNames @@ -97,14 +87,6 @@ private void OnTriggerEnter(Collider other) } } - private void UpdateObjectVisibility() - { - if (objectToControl != null) - { - objectToControl.SetActive(showObject); - } - } - public bool MoveToTarget(Vector3 origin, Vector3 target, float startTime, float duration) { float t = (Time.time - startTime) / duration; @@ -231,7 +213,7 @@ private void SpawnReward() // Randomly generate a spawn position within the bounds of the arena, as defined by Arenabuilders.cs. spawnPosition = new Vector3( Random.Range(0, arenaWidth), - 0, // Assuming spawning on the ground. + 0, Random.Range(0, arenaDepth) ); } @@ -268,15 +250,6 @@ private void SpawnReward() RewardSpawnCounts[rewardToSpawn] = 1; } - if (showObject && objectToControl != null) - { - Instantiate( - objectToControl, - objectToControlSpawnPoint.transform.position, - Quaternion.identity - ); - } - float currentInteractionTime = Time.time; totalInteractionInterval += currentInteractionTime - lastInteractionTime; lastInteractionTime = currentInteractionTime; From 5c742caddc7c67a7ef41f904faa94e5c75a31f92 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 12 Jun 2024 23:52:10 +0100 Subject: [PATCH 065/205] added new object - datazone transparent. will be responsible for collecting data on agent. --- Assets/Prefabs/Rewards/DataZone.prefab | 99 +++++++++++++++++++++ Assets/Prefabs/Rewards/DataZone.prefab.meta | 7 ++ 2 files changed, 106 insertions(+) create mode 100644 Assets/Prefabs/Rewards/DataZone.prefab create mode 100644 Assets/Prefabs/Rewards/DataZone.prefab.meta diff --git a/Assets/Prefabs/Rewards/DataZone.prefab b/Assets/Prefabs/Rewards/DataZone.prefab new file mode 100644 index 00000000..9d67221a --- /dev/null +++ b/Assets/Prefabs/Rewards/DataZone.prefab @@ -0,0 +1,99 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &7041498159436349378 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7038326920510554818} + - component: {fileID: 7046777348394065180} + - component: {fileID: 7013282172734433842} + - component: {fileID: 7056487143949059500} + m_Layer: 0 + m_Name: DataZone + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &7038326920510554818 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7041498159436349378} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 0, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &7046777348394065180 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7041498159436349378} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!65 &7013282172734433842 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7041498159436349378} + m_Material: {fileID: 0} + m_IsTrigger: 1 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &7056487143949059500 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7041498159436349378} + 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_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 9b0135a408e62104eb704ae5d1ad5fd6, 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: 1 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} diff --git a/Assets/Prefabs/Rewards/DataZone.prefab.meta b/Assets/Prefabs/Rewards/DataZone.prefab.meta new file mode 100644 index 00000000..a1cad6ca --- /dev/null +++ b/Assets/Prefabs/Rewards/DataZone.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 00c912a41dbd87a4ba31cad3fe3ec871 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: From ea1f8158b1d898e71d2a6113f53e0c3a92faa14e Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Thu, 13 Jun 2024 00:45:00 +0100 Subject: [PATCH 066/205] removed redundant logic causing y axis to improperly randomize --- Assets/Scripts/ArenaBuilders.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Assets/Scripts/ArenaBuilders.cs b/Assets/Scripts/ArenaBuilders.cs index 90b5751d..0ccccc26 100644 --- a/Assets/Scripts/ArenaBuilders.cs +++ b/Assets/Scripts/ArenaBuilders.cs @@ -598,12 +598,6 @@ Vector3 size { gameObjectInstanceIPrefab.SetSize(size); gameObjectBoundingBox = gameObjectInstance.GetBoundsWithChildren().extents; - if (positionIn.y == -1) - { - float minY = 0; - float maxY = 100; - positionIn.y = UnityEngine.Random.Range(minY, maxY); - } positionOut = gameObjectInstanceIPrefab.GetPosition( positionIn, From a6146207574abe71305a74b04eda1bfbb5c03c66 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Sun, 16 Jun 2024 21:31:38 +0100 Subject: [PATCH 067/205] removed redundant directory usage --- Assets/Scripts/SignBoard.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Assets/Scripts/SignBoard.cs b/Assets/Scripts/SignBoard.cs index 5f3ab251..0a3e2512 100644 --- a/Assets/Scripts/SignBoard.cs +++ b/Assets/Scripts/SignBoard.cs @@ -1,5 +1,4 @@ using System; -using System.Collections; using System.Collections.Generic; using UnityEngine; From 5aa914b94c9090681d8db1840d1db92e5f8cf35e Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Sun, 16 Jun 2024 21:33:17 +0100 Subject: [PATCH 068/205] removed unused script that handled deleted UI elements --- Assembly-CSharp.csproj | 1 - Assets/Scripts/PlayerControls.cs | 1 - Assets/Scripts/UIManager.cs | 43 -------------------------------- Assets/Scripts/UIManager.cs.meta | 11 -------- 4 files changed, 56 deletions(-) delete mode 100644 Assets/Scripts/UIManager.cs delete mode 100644 Assets/Scripts/UIManager.cs.meta diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index 0308119d..61dde044 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -64,7 +64,6 @@ - diff --git a/Assets/Scripts/PlayerControls.cs b/Assets/Scripts/PlayerControls.cs index 693feeb7..2a1929f2 100644 --- a/Assets/Scripts/PlayerControls.cs +++ b/Assets/Scripts/PlayerControls.cs @@ -28,7 +28,6 @@ public class PlayerControls : MonoBehaviour private ScreenshotCamera screenshotCam; private TrainingAgent agent; private ArenasConfigurations arenasConfigurations; - public UIManager uiManager; [Header("Score Settings")] public float prevScore = 0; diff --git a/Assets/Scripts/UIManager.cs b/Assets/Scripts/UIManager.cs deleted file mode 100644 index 57a1cc88..00000000 --- a/Assets/Scripts/UIManager.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using UnityEngine; -using TMPro; -using System.IO; - -/// -/// Manages the UI elements in the scene, particularly the arena and total objects text. -/// -public class UIManager : MonoBehaviour -{ - [Header("UI References")] - public TMP_Text arenaText; - public TMP_Text totalObjectsText; - public AAI3EnvironmentManager environmentManager; - - public TrainingArena trainingArena; - - void Awake() - { - AAI3EnvironmentManager.OnArenaChanged += UpdateArenaUI; - } - - void OnDestroy() - { - AAI3EnvironmentManager.OnArenaChanged -= UpdateArenaUI; - } - - private void Start() - { - trainingArena = GameObject.FindObjectOfType(); - Debug.Assert(trainingArena != null, "TrainingArena not found in the scene"); - UpdateArenaUI( - environmentManager.GetCurrentArenaIndex(), - environmentManager.GetTotalArenas() - ); - } - - private void UpdateArenaUI(int currentArenaIndex, int totalArenas) - { - arenaText.text = $"Arena {currentArenaIndex + 1} of {totalArenas}"; - totalObjectsText.text = $"Total Objects: {trainingArena.Builder.GetTotalObjectsSpawned()}"; - } -} diff --git a/Assets/Scripts/UIManager.cs.meta b/Assets/Scripts/UIManager.cs.meta deleted file mode 100644 index fc97b115..00000000 --- a/Assets/Scripts/UIManager.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: cd1dba16abaca0e4e83da1bfcfaab486 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: From 869aa03ca085ef6903af650ce0016d5292bf047c Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Sun, 16 Jun 2024 21:35:03 +0100 Subject: [PATCH 069/205] removed redundant directory --- Assets/Scripts/Grounded.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/Scripts/Grounded.cs b/Assets/Scripts/Grounded.cs index 8f1921e4..196e7a88 100644 --- a/Assets/Scripts/Grounded.cs +++ b/Assets/Scripts/Grounded.cs @@ -1,4 +1,4 @@ -using UnityEngine; + /// /// Represents the ground in the environment. This class is used to adjust the y position of the ground. From 83e9564ac4efac89c7ac472ad66667f23905c61a Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Sun, 16 Jun 2024 21:36:26 +0100 Subject: [PATCH 070/205] removed redundant directory usage --- Assets/Scripts/Prefab.cs | 1 - Assets/Scripts/Rewards/FullDecayGoal.cs | 1 - Assets/Scripts/Rewards/SizeChangeGoal.cs | 1 - 3 files changed, 3 deletions(-) diff --git a/Assets/Scripts/Prefab.cs b/Assets/Scripts/Prefab.cs index 8a77f096..c0db40f4 100644 --- a/Assets/Scripts/Prefab.cs +++ b/Assets/Scripts/Prefab.cs @@ -1,4 +1,3 @@ -using System.Collections; using System.Collections.Generic; using UnityEngine; using System; diff --git a/Assets/Scripts/Rewards/FullDecayGoal.cs b/Assets/Scripts/Rewards/FullDecayGoal.cs index c378b40c..c825169d 100644 --- a/Assets/Scripts/Rewards/FullDecayGoal.cs +++ b/Assets/Scripts/Rewards/FullDecayGoal.cs @@ -1,5 +1,4 @@ using UnityEngine; -using System; using Random = UnityEngine.Random; /// diff --git a/Assets/Scripts/Rewards/SizeChangeGoal.cs b/Assets/Scripts/Rewards/SizeChangeGoal.cs index 6668e06d..571a362f 100644 --- a/Assets/Scripts/Rewards/SizeChangeGoal.cs +++ b/Assets/Scripts/Rewards/SizeChangeGoal.cs @@ -1,4 +1,3 @@ -using System.Collections; using System.Collections.Generic; using UnityEngine; From 2bd9caf5655ef45c4a038a191a4ad1c3cc45c5b6 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Sun, 16 Jun 2024 21:54:19 +0100 Subject: [PATCH 071/205] modularized training agent health logic which determines notification result and episode end Code is now much cleaner --- Assets/Scripts/TrainingAgent.cs | 67 +++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 29 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 61a6e5f3..24fb638d 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -527,15 +527,14 @@ public void UpdateHealthNextStep(float updateAmount, bool andCompleteArena = fal public void UpdateHealth(float updateAmount, bool andCompleteArena = false) { - if (NotificationManager.Instance == null && showNotification == true) + // Sanity check for NotificationManager instance + if (NotificationManager.Instance == null && showNotification) { Debug.LogError("NotificationManager instance is not set."); return; } - /// - /// Update the health of the agent and reset any queued updates - /// If health reaches 0 or the episode is queued to end then call EndEpisode(). - /// + + // Updating health only if the agent is not frozen if (!IsFrozen()) { health += 100 * updateAmount; @@ -543,48 +542,58 @@ public void UpdateHealth(float updateAmount, bool andCompleteArena = false) _nextUpdateHealth = 0; AddReward(updateAmount); } + _currentScore = GetCumulativeReward(); + + // Ensure health does not exceed maximum limits if (health > _maxHealth) { health = _maxHealth; } + // Handling scenarios when health drops to zero or below else if (health <= 0) { health = 0; - if (showNotification) - { - NotificationManager.Instance.ShowFailureNotification(); - } - StartCoroutine(EndEpisodeAfterDelay()); + HandleEpisodeEnd("Failure"); return; } + if (andCompleteArena || _nextUpdateCompleteArena) { - _nextUpdateCompleteArena = false; - float cumulativeReward = this.GetCumulativeReward(); + HandleArenaCompletion(); + } + } - if (cumulativeReward >= Arena.CurrentPassMark) + private void HandleEpisodeEnd(string result) + { + if (showNotification) + { + if (result == "Failure") { - // If passed and the next arena is merged load that without ending the episode - if (_arena.mergeNextArena) - { - _arena.LoadNextArena(); - return; - } - if (showNotification) - { - NotificationManager.Instance.ShowSuccessNotification(); - } + NotificationManager.Instance.ShowFailureNotification(); } - else + else if (result == "Success") { - if (showNotification) - { - NotificationManager.Instance.ShowFailureNotification(); - } + NotificationManager.Instance.ShowSuccessNotification(); } - StartCoroutine(EndEpisodeAfterDelay()); } + StartCoroutine(EndEpisodeAfterDelay()); // Ending the episode after a delay + } + + private void HandleArenaCompletion() + { + _nextUpdateCompleteArena = false; + float cumulativeReward = GetCumulativeReward(); + + if (cumulativeReward >= Arena.CurrentPassMark && _arena.mergeNextArena) + { + _arena.LoadNextArena(); + return; + } + + // Determining the result based on the cumulative reward + string result = cumulativeReward >= Arena.CurrentPassMark ? "Success" : "Failure"; + HandleEpisodeEnd(result); } public void AddExtraReward(float rewardFactor) From 88afa06d0485fa062b6fbbe72a26e8cb684f456e Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Sun, 16 Jun 2024 22:56:42 +0100 Subject: [PATCH 072/205] Revert "modularized training agent health logic" This reverts commit 2bd9caf5655ef45c4a038a191a4ad1c3cc45c5b6. --- Assets/Scripts/TrainingAgent.cs | 67 ++++++++++++++------------------- 1 file changed, 29 insertions(+), 38 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 24fb638d..61a6e5f3 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -527,14 +527,15 @@ public void UpdateHealthNextStep(float updateAmount, bool andCompleteArena = fal public void UpdateHealth(float updateAmount, bool andCompleteArena = false) { - // Sanity check for NotificationManager instance - if (NotificationManager.Instance == null && showNotification) + if (NotificationManager.Instance == null && showNotification == true) { Debug.LogError("NotificationManager instance is not set."); return; } - - // Updating health only if the agent is not frozen + /// + /// Update the health of the agent and reset any queued updates + /// If health reaches 0 or the episode is queued to end then call EndEpisode(). + /// if (!IsFrozen()) { health += 100 * updateAmount; @@ -542,58 +543,48 @@ public void UpdateHealth(float updateAmount, bool andCompleteArena = false) _nextUpdateHealth = 0; AddReward(updateAmount); } - _currentScore = GetCumulativeReward(); - - // Ensure health does not exceed maximum limits if (health > _maxHealth) { health = _maxHealth; } - // Handling scenarios when health drops to zero or below else if (health <= 0) { health = 0; - HandleEpisodeEnd("Failure"); + if (showNotification) + { + NotificationManager.Instance.ShowFailureNotification(); + } + StartCoroutine(EndEpisodeAfterDelay()); return; } - if (andCompleteArena || _nextUpdateCompleteArena) { - HandleArenaCompletion(); - } - } + _nextUpdateCompleteArena = false; + float cumulativeReward = this.GetCumulativeReward(); - private void HandleEpisodeEnd(string result) - { - if (showNotification) - { - if (result == "Failure") + if (cumulativeReward >= Arena.CurrentPassMark) { - NotificationManager.Instance.ShowFailureNotification(); + // If passed and the next arena is merged load that without ending the episode + if (_arena.mergeNextArena) + { + _arena.LoadNextArena(); + return; + } + if (showNotification) + { + NotificationManager.Instance.ShowSuccessNotification(); + } } - else if (result == "Success") + else { - NotificationManager.Instance.ShowSuccessNotification(); + if (showNotification) + { + NotificationManager.Instance.ShowFailureNotification(); + } } + StartCoroutine(EndEpisodeAfterDelay()); } - StartCoroutine(EndEpisodeAfterDelay()); // Ending the episode after a delay - } - - private void HandleArenaCompletion() - { - _nextUpdateCompleteArena = false; - float cumulativeReward = GetCumulativeReward(); - - if (cumulativeReward >= Arena.CurrentPassMark && _arena.mergeNextArena) - { - _arena.LoadNextArena(); - return; - } - - // Determining the result based on the cumulative reward - string result = cumulativeReward >= Arena.CurrentPassMark ? "Success" : "Failure"; - HandleEpisodeEnd(result); } public void AddExtraReward(float rewardFactor) From 1f28c6b2e1afad735f920b974d4cf44e5d1ebba5 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Sun, 16 Jun 2024 23:22:13 +0100 Subject: [PATCH 073/205] added debugs to notification states --- Assets/Scripts/NotificationManager.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Assets/Scripts/NotificationManager.cs b/Assets/Scripts/NotificationManager.cs index 38aa5a46..8a2a1932 100644 --- a/Assets/Scripts/NotificationManager.cs +++ b/Assets/Scripts/NotificationManager.cs @@ -58,6 +58,7 @@ void SingletonCheck() public void ShowSuccessNotification() { + Debug.Log("Showing Success Notification"); ShowNotification(true); trainingAgent.FreezeAgent(true); currentNotificationState = "Success"; @@ -65,6 +66,7 @@ public void ShowSuccessNotification() public void ShowFailureNotification() { + Debug.Log("Showing Failure Notification"); ShowNotification(false); trainingAgent.FreezeAgent(true); currentNotificationState = "Failure"; @@ -94,6 +96,7 @@ void StopPreviousAnimation() public void HideNotification() { + Debug.Log("Hiding Notification"); notificationPanel.SetActive(false); successGradientBorderImage.gameObject.SetActive(false); failureGradientBorderImage.gameObject.SetActive(false); From c7b3960d75bb3b368caad2defdc7c77f65045aac Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Sun, 16 Jun 2024 23:45:59 +0100 Subject: [PATCH 074/205] fixed bug where the arena would reset uncontrollably if notification == failure + minor restructure --- Assets/Scripts/TrainingAgent.cs | 51 +++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 61a6e5f3..9b5e675d 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -527,15 +527,13 @@ public void UpdateHealthNextStep(float updateAmount, bool andCompleteArena = fal public void UpdateHealth(float updateAmount, bool andCompleteArena = false) { - if (NotificationManager.Instance == null && showNotification == true) + if (NotificationManager.Instance == null && showNotification) { Debug.LogError("NotificationManager instance is not set."); return; } - /// - /// Update the health of the agent and reset any queued updates - /// If health reaches 0 or the episode is queued to end then call EndEpisode(). - /// + + // Update the health of the agent and reset any queued updates if (!IsFrozen()) { health += 100 * updateAmount; @@ -543,7 +541,11 @@ public void UpdateHealth(float updateAmount, bool andCompleteArena = false) _nextUpdateHealth = 0; AddReward(updateAmount); } + _currentScore = GetCumulativeReward(); + Debug.Log($"Current cumulative reward: {_currentScore}, Current pass mark: {Arena.CurrentPassMark}"); + + // Ensure health does not exceed maximum limits if (health > _maxHealth) { health = _maxHealth; @@ -551,6 +553,7 @@ public void UpdateHealth(float updateAmount, bool andCompleteArena = false) else if (health <= 0) { health = 0; + Debug.Log("Health reached 0, showing failure notification."); if (showNotification) { NotificationManager.Instance.ShowFailureNotification(); @@ -558,21 +561,30 @@ public void UpdateHealth(float updateAmount, bool andCompleteArena = false) StartCoroutine(EndEpisodeAfterDelay()); return; } + + // Handle arena completion or episode ending if (andCompleteArena || _nextUpdateCompleteArena) { _nextUpdateCompleteArena = false; - float cumulativeReward = this.GetCumulativeReward(); + float cumulativeReward = GetCumulativeReward(); + Debug.Log($"Current pass mark: {Arena.CurrentPassMark}"); - if (cumulativeReward >= Arena.CurrentPassMark) + bool proceedToNext = Arena.CurrentPassMark == 0 || cumulativeReward >= Arena.CurrentPassMark; + Debug.Log($"Proceed to next arena: {proceedToNext}, Merge next arena: {_arena.mergeNextArena}"); + + if (proceedToNext) { - // If passed and the next arena is merged load that without ending the episode + // If the next arena is merged, load that without ending the episode if (_arena.mergeNextArena) { + Debug.Log("Merging to next arena without ending episode."); _arena.LoadNextArena(); return; } + if (showNotification) { + Debug.Log("Showing success notification."); NotificationManager.Instance.ShowSuccessNotification(); } } @@ -580,18 +592,15 @@ public void UpdateHealth(float updateAmount, bool andCompleteArena = false) { if (showNotification) { + Debug.Log("Showing failure notification due to insufficient reward."); NotificationManager.Instance.ShowFailureNotification(); } } + StartCoroutine(EndEpisodeAfterDelay()); } } - public void AddExtraReward(float rewardFactor) - { - UpdateHealth(Math.Min(rewardFactor * _rewardPerStep, -0.001f)); - } - IEnumerator EndEpisodeAfterDelay() { if (!showNotification) @@ -600,8 +609,11 @@ IEnumerator EndEpisodeAfterDelay() yield break; } + Debug.Log("Starting delay before ending episode."); yield return new WaitForSeconds(2.5f); + NotificationManager.Instance.HideNotification(); + Debug.Log("Ending episode after delay."); EndEpisode(); } @@ -619,7 +631,7 @@ public override void OnEpisodeBegin() writer.Flush(); EpisodeDebugLogs(); - StopCoroutine("UnfreezeCountdown"); + StopAllCoroutines(); _previousScore = _currentScore; numberOfGoalsCollected = 0; _arena.ResetArena(); @@ -628,6 +640,12 @@ public override void OnEpisodeBegin() health = _maxHealth; SetFreezeDelay(GetFreezeDelay()); + Debug.Log("Agent state reset in OnEpisodeBegin."); + } + + public void AddExtraReward(float rewardFactor) + { + UpdateHealth(Math.Min(rewardFactor * _rewardPerStep, -0.001f)); } private void EpisodeDebugLogs() @@ -673,8 +691,11 @@ void OnCollisionExit(Collision collision) //****************************** //PREFAB INTERFACE FOR THE AGENT //****************************** - public void SetColor(Vector3 color) { } + /// + /// Sets the colour and size of the agent. Not used in this implementation. + /// + public void SetColor(Vector3 color) { } public void SetSize(Vector3 scale) { } /// From 4a74c43bf656c75ad19798bdf23414f810a44c6f Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Mon, 17 Jun 2024 21:02:07 +0100 Subject: [PATCH 075/205] minor details on datazones such as adding the object to list of spawnable objects --- Assets/Prefabs/AAI3Arena.prefab | 2 +- Assets/Prefabs/Rewards/DataZone.prefab | 27 +++++++++++++++++++++++++- ProjectSettings/TagManager.asset | 1 + 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/Assets/Prefabs/AAI3Arena.prefab b/Assets/Prefabs/AAI3Arena.prefab index fc41b401..42edea6b 100644 --- a/Assets/Prefabs/AAI3Arena.prefab +++ b/Assets/Prefabs/AAI3Arena.prefab @@ -858,6 +858,7 @@ MonoBehaviour: - {fileID: 6599169884992408241, guid: c382c2a5deefcec4493637923a912932, type: 3} - {fileID: 1323439192758780, guid: 70289c4d2c6d4a94eb4d73531e1a9ce6, type: 3} - {fileID: 8069506010422567580, guid: 2e66c94a6ed25c641ad85c58ce7e981b, type: 3} + - {fileID: 7041498159436349378, guid: 00c912a41dbd87a4ba31cad3fe3ec871, type: 3} spawnedObjectsHolder: {fileID: 6276814220842007455, guid: ff9a0b038a04e8747a9f95217df0b26f, type: 3} maxSpawnAttemptsForAgent: 100 maxSpawnAttemptsForPrefabs: 20 @@ -866,7 +867,6 @@ MonoBehaviour: - {fileID: 7334380931721050334} - {fileID: 2049938451244076549} arenaID: -1 - maxarenaID: -1 _agent: {fileID: 0} --- !u!1 &1583564189836146 GameObject: diff --git a/Assets/Prefabs/Rewards/DataZone.prefab b/Assets/Prefabs/Rewards/DataZone.prefab index 9d67221a..89bf4e81 100644 --- a/Assets/Prefabs/Rewards/DataZone.prefab +++ b/Assets/Prefabs/Rewards/DataZone.prefab @@ -12,6 +12,7 @@ GameObject: - component: {fileID: 7046777348394065180} - component: {fileID: 7013282172734433842} - component: {fileID: 7056487143949059500} + - component: {fileID: -689990793451022363} m_Layer: 0 m_Name: DataZone m_TagString: Untagged @@ -50,7 +51,7 @@ BoxCollider: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 7041498159436349378} m_Material: {fileID: 0} - m_IsTrigger: 1 + m_IsTrigger: 0 m_Enabled: 1 serializedVersion: 2 m_Size: {x: 1, y: 1, z: 1} @@ -97,3 +98,27 @@ MeshRenderer: m_SortingLayer: 0 m_SortingOrder: 0 m_AdditionalVertexStreams: {fileID: 0} +--- !u!114 &-689990793451022363 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7041498159436349378} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ee16993e0d02ef64c8ed59aa0b63ac82, type: 3} + m_Name: + m_EditorClassIdentifier: + rotationRange: {x: 0, y: 360} + sizeMin: {x: 1, y: 0.5, z: 1} + sizeMax: {x: 40, y: 10, z: 40} + canRandomizeColor: 0 + ratioSize: {x: 1, y: 1, z: 1} + sizeAdjustment: 0.999 + textureUVOverride: 0 + typicalOrigin: 1 + numberOfGoals: 0 + reward: 0 + isMulti: 0 + rewardType: DataZone diff --git a/ProjectSettings/TagManager.asset b/ProjectSettings/TagManager.asset index 283bfcdf..74a5dbb0 100644 --- a/ProjectSettings/TagManager.asset +++ b/ProjectSettings/TagManager.asset @@ -30,6 +30,7 @@ TagManager: - SignPoster - DecoyGoal - DecoyGoalBounce + - DataZone layers: - Default - TransparentFX From beb5f9ddae2075eba43f4b222774b5a65fc4c650 Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Mon, 17 Jun 2024 21:45:33 +0100 Subject: [PATCH 076/205] minor folder changes --- Assembly-CSharp.csproj | 1 + Assets/Prefabs/DataZone.meta | 8 ++++++++ .../{Rewards => DataZone}/DataZone.prefab | 14 +++++--------- .../{Rewards => DataZone}/DataZone.prefab.meta | 0 Assets/Scripts/DataZone.cs | 18 ++++++++++++++++++ Assets/Scripts/DataZone.cs.meta | 11 +++++++++++ 6 files changed, 43 insertions(+), 9 deletions(-) create mode 100644 Assets/Prefabs/DataZone.meta rename Assets/Prefabs/{Rewards => DataZone}/DataZone.prefab (92%) rename Assets/Prefabs/{Rewards => DataZone}/DataZone.prefab.meta (100%) create mode 100644 Assets/Scripts/DataZone.cs create mode 100644 Assets/Scripts/DataZone.cs.meta diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index 61dde044..ad3d4a16 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -108,6 +108,7 @@ + diff --git a/Assets/Prefabs/DataZone.meta b/Assets/Prefabs/DataZone.meta new file mode 100644 index 00000000..934a5956 --- /dev/null +++ b/Assets/Prefabs/DataZone.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ff42cbb93388376428da76440ae30154 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Prefabs/Rewards/DataZone.prefab b/Assets/Prefabs/DataZone/DataZone.prefab similarity index 92% rename from Assets/Prefabs/Rewards/DataZone.prefab rename to Assets/Prefabs/DataZone/DataZone.prefab index 89bf4e81..d7d17d76 100644 --- a/Assets/Prefabs/Rewards/DataZone.prefab +++ b/Assets/Prefabs/DataZone/DataZone.prefab @@ -12,10 +12,10 @@ GameObject: - component: {fileID: 7046777348394065180} - component: {fileID: 7013282172734433842} - component: {fileID: 7056487143949059500} - - component: {fileID: -689990793451022363} + - component: {fileID: -2281997811760159165} m_Layer: 0 m_Name: DataZone - m_TagString: Untagged + m_TagString: DataZone m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 @@ -98,7 +98,7 @@ MeshRenderer: m_SortingLayer: 0 m_SortingOrder: 0 m_AdditionalVertexStreams: {fileID: 0} ---- !u!114 &-689990793451022363 +--- !u!114 &-2281997811760159165 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -107,18 +107,14 @@ MonoBehaviour: m_GameObject: {fileID: 7041498159436349378} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: ee16993e0d02ef64c8ed59aa0b63ac82, type: 3} + m_Script: {fileID: 11500000, guid: 0d638726ee68a164a9c73bbdaed7637d, type: 3} m_Name: m_EditorClassIdentifier: rotationRange: {x: 0, y: 360} sizeMin: {x: 1, y: 0.5, z: 1} - sizeMax: {x: 40, y: 10, z: 40} + sizeMax: {x: 30, y: 10, z: 30} canRandomizeColor: 0 ratioSize: {x: 1, y: 1, z: 1} sizeAdjustment: 0.999 textureUVOverride: 0 typicalOrigin: 1 - numberOfGoals: 0 - reward: 0 - isMulti: 0 - rewardType: DataZone diff --git a/Assets/Prefabs/Rewards/DataZone.prefab.meta b/Assets/Prefabs/DataZone/DataZone.prefab.meta similarity index 100% rename from Assets/Prefabs/Rewards/DataZone.prefab.meta rename to Assets/Prefabs/DataZone/DataZone.prefab.meta diff --git a/Assets/Scripts/DataZone.cs b/Assets/Scripts/DataZone.cs new file mode 100644 index 00000000..27837c99 --- /dev/null +++ b/Assets/Scripts/DataZone.cs @@ -0,0 +1,18 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class DataZone : Prefab +{ + // Start is called before the first frame update + void Start() + { + + } + + // Update is called once per frame + void Update() + { + + } +} diff --git a/Assets/Scripts/DataZone.cs.meta b/Assets/Scripts/DataZone.cs.meta new file mode 100644 index 00000000..382014ec --- /dev/null +++ b/Assets/Scripts/DataZone.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0d638726ee68a164a9c73bbdaed7637d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From b9fdccf424b0aae77fe1b946083647b06b96fb6d Mon Sep 17 00:00:00 2001 From: alhasacademy96 <65875290+alhasacademy96@users.noreply.github.com> Date: Mon, 17 Jun 2024 21:58:17 +0100 Subject: [PATCH 077/205] added rigidbody component to datazone obj --- Assets/Prefabs/DataZone/DataZone.prefab | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Assets/Prefabs/DataZone/DataZone.prefab b/Assets/Prefabs/DataZone/DataZone.prefab index d7d17d76..4ab7b6c7 100644 --- a/Assets/Prefabs/DataZone/DataZone.prefab +++ b/Assets/Prefabs/DataZone/DataZone.prefab @@ -10,6 +10,7 @@ GameObject: m_Component: - component: {fileID: 7038326920510554818} - component: {fileID: 7046777348394065180} + - component: {fileID: 5324416873341341450} - component: {fileID: 7013282172734433842} - component: {fileID: 7056487143949059500} - component: {fileID: -2281997811760159165} @@ -43,6 +44,22 @@ MeshFilter: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 7041498159436349378} m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!54 &5324416873341341450 +Rigidbody: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7041498159436349378} + serializedVersion: 2 + m_Mass: 1 + m_Drag: 0 + m_AngularDrag: 0.05 + m_UseGravity: 1 + m_IsKinematic: 0 + m_Interpolate: 0 + m_Constraints: 0 + m_CollisionDetection: 0 --- !u!65 &7013282172734433842 BoxCollider: m_ObjectHideFlags: 0 From 27571ff63dfcd3b0c449ac291fe5db1140385b16 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 19 Jun 2024 18:43:32 +0100 Subject: [PATCH 078/205] completed todo set by Ben: // TODO: If mergeNextArena is put in the final arena this will throw. Add some validation to move this failure sooner in execution. @benaslater check if this satisfies your concern/TODO --- Assets/Scripts/TrainingArena.cs | 585 +++++++++++++++++--------------- 1 file changed, 302 insertions(+), 283 deletions(-) diff --git a/Assets/Scripts/TrainingArena.cs b/Assets/Scripts/TrainingArena.cs index 8a83fe5a..ecf11ab8 100644 --- a/Assets/Scripts/TrainingArena.cs +++ b/Assets/Scripts/TrainingArena.cs @@ -10,292 +10,311 @@ using System.Linq; /// -/// This class is responsible for managing the training arena. +/// This class is responsible for managing the training arena. /// It contains the logic to reset the arena, update the light status, and handle the spawning of rewards. /// It also initializes the components required for the arena, such as the ArenaBuilder and the AAI3EnvironmentManager. /// public class TrainingArena : MonoBehaviour { - [SerializeField] - private ListOfPrefabs prefabs; - [SerializeField] - private GameObject spawnedObjectsHolder; - [SerializeField] - private int maxSpawnAttemptsForAgent = 100; - [SerializeField] - private int maxSpawnAttemptsForPrefabs = 20; - [SerializeField] - private ListOfBlackScreens blackScreens; - - [HideInInspector] - public int arenaID = -1; - - public TrainingAgent _agent; - - private ArenaBuilder _builder; - private ArenaConfiguration _arenaConfiguration = new ArenaConfiguration(); - private AAI3EnvironmentManager _environmentManager; - private List _fades = new List(); - private bool _lightStatus = true; - private int _agentDecisionInterval; - private bool isFirstArenaReset = true; - private List spawnedRewards = new List(); - private List playedArenas = new List(); - private List _mergedArenas = null; - public bool showNotification { get; set; } - - public bool IsFirstArenaReset - { - get { return isFirstArenaReset; } - set { isFirstArenaReset = value; } - } - - public bool mergeNextArena - { - get - { - return _arenaConfiguration.mergeNextArena; - } - } - - public ArenaBuilder Builder - { - get { return _builder; } - } - - public ArenaConfiguration ArenaConfig - { - get { return _arenaConfiguration; } - } - - internal void Awake() - { - InitializeArenaComponents(); - } - - void FixedUpdate() - { - UpdateLigthStatus(); - } - - private void OnDestroy() - { - Spawner_InteractiveButton.RewardSpawned -= OnRewardSpawned; - } - - /// - /// Initializes the components required for the arena, such as the ArenaBuilder and the AAI3EnvironmentManager. - /// - private void InitializeArenaComponents() - { - _builder = new ArenaBuilder( - gameObject, - spawnedObjectsHolder, - maxSpawnAttemptsForPrefabs, - maxSpawnAttemptsForAgent - ); - _environmentManager = GameObject.FindObjectOfType(); - _agent = FindObjectsOfType(true)[0]; - _agentDecisionInterval = _agent.GetComponentInChildren().DecisionPeriod; - _fades = blackScreens.GetFades(); - - Spawner_InteractiveButton.RewardSpawned += OnRewardSpawned; - } - - /// - /// Provides a list of the arenas in the current config file that are preceeded by an arena with - /// the mergeNextArena property, so that we can avoid loading them when arenas are randomised. - /// - private List GetMergedArenas() - { - List mergedArenas = new List(); - int totalArenas = _environmentManager.GetTotalArenas(); - ArenaConfiguration currentArena = _environmentManager.GetConfiguration(0); - bool currentlyMerged = currentArena.mergeNextArena; - for (int i = 1; i < totalArenas; i++) - { - if (currentlyMerged) { mergedArenas.Add(i); } - currentArena = _environmentManager.GetConfiguration(i); - currentlyMerged = currentArena.mergeNextArena; - } - return mergedArenas; - } - - /// - /// Resets the arena by destroying existing objects and spawning new ones based on the current arena configuration. - /// This is a custom implementation of the ResetAcademy method from the MLAgents library. It is called by the TrainingAgent when it resets. - /// - public void ResetArena() - { - Debug.Log("Resetting Arena"); - - CleanUpSpawnedObjects(); - - SetNextArenaID(); - - // Load the new configuration - ArenaConfiguration newConfiguration = _environmentManager.GetConfiguration(arenaID); - - ApplyNewArenaConfiguration(newConfiguration); - - CleanupRewards(); - - NotifyArenaChange(); - } - - public void LoadNextArena() - { - // TrainingArena must have reset() called at first to initialise arenaID - if (isFirstArenaReset) - { - throw new InvalidOperationException("LoadNextArena called before first reset"); - } - - Debug.Log($"Loading next arena. Previous: {arenaID}, next: {arenaID + 1}"); - CleanUpSpawnedObjects(); - - arenaID += 1; - // Load the new configuration - // TODO: If mergeNextArena is put in the final arena this will throw. Add some validation to move this failure sooner in execution - ArenaConfiguration newConfiguration = _environmentManager.GetConfiguration(arenaID); - - ApplyNewArenaConfiguration(newConfiguration); - - CleanupRewards(); - - NotifyArenaChange(); - } - - private void CleanUpSpawnedObjects() - { - foreach (GameObject holder in transform.FindChildrenWithTag("spawnedObjects")) - { - holder.SetActive(false); - Destroy(holder); - } - } - - private void SetNextArenaID() - { - int totalArenas = _environmentManager.GetTotalArenas(); - bool randomizeArenas = _environmentManager.GetRandomizeArenasStatus(); - - if (isFirstArenaReset) - { - isFirstArenaReset = false; - arenaID = randomizeArenas ? ChooseRandomArenaID(totalArenas) : 0; - } - else - { - if (randomizeArenas) - { - arenaID = ChooseRandomArenaID(totalArenas); - } - else - { - // If the next arena is merged, sequentially search for the next unmerged one - ArenaConfiguration preceedingArena = _arenaConfiguration; - arenaID = (arenaID + 1) % totalArenas; - while (preceedingArena.mergeNextArena) - { - preceedingArena = _environmentManager.GetConfiguration(arenaID); - arenaID = (arenaID + 1) % totalArenas; - } - } - } - } - - private int ChooseRandomArenaID(int totalArenas) - { - // Populate the list of merged arenas if needed - if (_mergedArenas == null) { _mergedArenas = GetMergedArenas(); } - - playedArenas.Add(arenaID); - if (playedArenas.Count >= totalArenas) - { - playedArenas = new List { arenaID }; - } - - var availableArenas = Enumerable.Range(0, totalArenas).Except(playedArenas).Except(_mergedArenas).ToList(); - return availableArenas[Random.Range(0, availableArenas.Count)]; - - } - - /* Note: to update the active arena to a new ID the following must be called in sequence - GetConfiguration, ApplyNewArenaConfiguration, CleanupRewards, NotifyArenaChange - */ - private void ApplyNewArenaConfiguration(ArenaConfiguration newConfiguration) - { - _arenaConfiguration = newConfiguration; - _agent.showNotification = ArenasConfigurations.Instance.showNotification; - Debug.Log("Updating Arena Configuration"); - - _arenaConfiguration.SetGameObject(prefabs.GetList()); - _builder.Spawnables = _arenaConfiguration.spawnables; - _arenaConfiguration.toUpdate = false; - _agent.MaxStep = 0; - _agent.timeLimit = _arenaConfiguration.TimeLimit * _agentDecisionInterval; - _builder.Build(); - _arenaConfiguration.lightsSwitch.Reset(); - - if (_arenaConfiguration.randomSeed != 0) - { - Random.InitState(_arenaConfiguration.randomSeed); - } - Debug.Log($"TimeLimit set to: {_arenaConfiguration.TimeLimit}"); - } - - private void NotifyArenaChange() - { - _environmentManager.TriggerArenaChangeEvent(arenaID, _environmentManager.GetTotalArenas()); - } - - /// - /// Destroys all spawned rewards in the arena. - /// - private void CleanupRewards() - { - foreach (var reward in spawnedRewards) - { - Destroy(reward); - } - spawnedRewards.Clear(); - } - - /// - /// Updates the light status in the arena based on the current step count. - /// - public void UpdateLigthStatus() - { - int stepCount = _agent.StepCount; - bool newLight = _arenaConfiguration.lightsSwitch.LightStatus( - stepCount, - _agentDecisionInterval - ); - if (newLight != _lightStatus) - { - _lightStatus = newLight; - foreach (Fade fade in _fades) - { - fade.StartFade(); - } - } - } - - /// - /// Returns the total number of spawned objects in the arena. - /// - public int GetTotalSpawnedObjects() - { - Debug.Log("Total spawned objects: " + spawnedObjectsHolder.transform.childCount); - return spawnedObjectsHolder.transform.childCount; - } - - /// - /// Callback for when a reward is spawned in the arena. - /// - private void OnRewardSpawned(GameObject reward) - { - spawnedRewards.Add(reward); - } + [SerializeField] + private ListOfPrefabs prefabs; + + [SerializeField] + private GameObject spawnedObjectsHolder; + + [SerializeField] + private int maxSpawnAttemptsForAgent = 100; + + [SerializeField] + private int maxSpawnAttemptsForPrefabs = 20; + + [SerializeField] + private ListOfBlackScreens blackScreens; + + [HideInInspector] + public int arenaID = -1; + + public TrainingAgent _agent; + + private ArenaBuilder _builder; + private ArenaConfiguration _arenaConfiguration = new ArenaConfiguration(); + private AAI3EnvironmentManager _environmentManager; + private List _fades = new List(); + private bool _lightStatus = true; + private int _agentDecisionInterval; + private bool isFirstArenaReset = true; + private List spawnedRewards = new List(); + private List playedArenas = new List(); + private List _mergedArenas = null; + public bool showNotification { get; set; } + + public bool IsFirstArenaReset + { + get { return isFirstArenaReset; } + set { isFirstArenaReset = value; } + } + + public bool mergeNextArena + { + get { return _arenaConfiguration.mergeNextArena; } + } + + public ArenaBuilder Builder + { + get { return _builder; } + } + + public ArenaConfiguration ArenaConfig + { + get { return _arenaConfiguration; } + } + + internal void Awake() + { + InitializeArenaComponents(); + } + + void FixedUpdate() + { + UpdateLigthStatus(); + } + + private void OnDestroy() + { + Spawner_InteractiveButton.RewardSpawned -= OnRewardSpawned; + } + + /// + /// Initializes the components required for the arena, such as the ArenaBuilder and the AAI3EnvironmentManager. + /// + private void InitializeArenaComponents() + { + _builder = new ArenaBuilder( + gameObject, + spawnedObjectsHolder, + maxSpawnAttemptsForPrefabs, + maxSpawnAttemptsForAgent + ); + _environmentManager = GameObject.FindObjectOfType(); + _agent = FindObjectsOfType(true)[0]; + _agentDecisionInterval = _agent.GetComponentInChildren().DecisionPeriod; + _fades = blackScreens.GetFades(); + + Spawner_InteractiveButton.RewardSpawned += OnRewardSpawned; + } + + /// + /// Provides a list of the arenas in the current config file that are preceeded by an arena with + /// the mergeNextArena property, so that we can avoid loading them when arenas are randomised. + /// + private List GetMergedArenas() + { + List mergedArenas = new List(); + int totalArenas = _environmentManager.GetTotalArenas(); + ArenaConfiguration currentArena = _environmentManager.GetConfiguration(0); + bool currentlyMerged = currentArena.mergeNextArena; + for (int i = 1; i < totalArenas; i++) + { + if (currentlyMerged) + { + mergedArenas.Add(i); + } + currentArena = _environmentManager.GetConfiguration(i); + currentlyMerged = currentArena.mergeNextArena; + } + return mergedArenas; + } + + /// + /// Resets the arena by destroying existing objects and spawning new ones based on the current arena configuration. + /// This is a custom implementation of the ResetAcademy method from the MLAgents library. It is called by the TrainingAgent when it resets. + /// + public void ResetArena() + { + Debug.Log("Resetting Arena"); + + CleanUpSpawnedObjects(); + + SetNextArenaID(); + + // Load the new configuration + ArenaConfiguration newConfiguration = _environmentManager.GetConfiguration(arenaID); + + ApplyNewArenaConfiguration(newConfiguration); + + CleanupRewards(); + + NotifyArenaChange(); + } + + public void LoadNextArena() + { + // TrainingArena must have reset() called at first to initialise arenaID + if (isFirstArenaReset) + { + throw new InvalidOperationException("LoadNextArena called before first reset"); + } + Debug.Log($"Loading next arena. Previous: {arenaID}, next: {arenaID + 1}"); + + CleanUpSpawnedObjects(); + + arenaID += 1; + + // Load the new configuration + ArenaConfiguration newConfiguration = _environmentManager.GetConfiguration(arenaID); + + // Checks if its final arena in config file and if mergeNextArena is set to true, throws an exception + int totalArenas = _environmentManager.GetTotalArenas(); + if (arenaID == totalArenas - 1 && newConfiguration.mergeNextArena) + { + throw new InvalidOperationException( + "The final arena cannot have mergeNextArena set to true." + ); + } + + ApplyNewArenaConfiguration(newConfiguration); + + CleanupRewards(); + + NotifyArenaChange(); + } + + private void CleanUpSpawnedObjects() + { + foreach (GameObject holder in transform.FindChildrenWithTag("spawnedObjects")) + { + holder.SetActive(false); + Destroy(holder); + } + } + + private void SetNextArenaID() + { + int totalArenas = _environmentManager.GetTotalArenas(); + bool randomizeArenas = _environmentManager.GetRandomizeArenasStatus(); + + if (isFirstArenaReset) + { + isFirstArenaReset = false; + arenaID = randomizeArenas ? ChooseRandomArenaID(totalArenas) : 0; + } + else + { + if (randomizeArenas) + { + arenaID = ChooseRandomArenaID(totalArenas); + } + else + { + // If the next arena is merged, sequentially search for the next unmerged one + ArenaConfiguration preceedingArena = _arenaConfiguration; + arenaID = (arenaID + 1) % totalArenas; + while (preceedingArena.mergeNextArena) + { + preceedingArena = _environmentManager.GetConfiguration(arenaID); + arenaID = (arenaID + 1) % totalArenas; + } + } + } + } + + private int ChooseRandomArenaID(int totalArenas) + { + // Populate the list of merged arenas if needed + if (_mergedArenas == null) + { + _mergedArenas = GetMergedArenas(); + } + + playedArenas.Add(arenaID); + if (playedArenas.Count >= totalArenas) + { + playedArenas = new List { arenaID }; + } + + var availableArenas = Enumerable + .Range(0, totalArenas) + .Except(playedArenas) + .Except(_mergedArenas) + .ToList(); + return availableArenas[Random.Range(0, availableArenas.Count)]; + } + + /* Note: to update the active arena to a new ID the following must be called in sequence + GetConfiguration, ApplyNewArenaConfiguration, CleanupRewards, NotifyArenaChange + */ + private void ApplyNewArenaConfiguration(ArenaConfiguration newConfiguration) + { + _arenaConfiguration = newConfiguration; + _agent.showNotification = ArenasConfigurations.Instance.showNotification; + Debug.Log("Updating Arena Configuration"); + + _arenaConfiguration.SetGameObject(prefabs.GetList()); + _builder.Spawnables = _arenaConfiguration.spawnables; + _arenaConfiguration.toUpdate = false; + _agent.MaxStep = 0; + _agent.timeLimit = _arenaConfiguration.TimeLimit * _agentDecisionInterval; + _builder.Build(); + _arenaConfiguration.lightsSwitch.Reset(); + + if (_arenaConfiguration.randomSeed != 0) + { + Random.InitState(_arenaConfiguration.randomSeed); + } + Debug.Log($"TimeLimit set to: {_arenaConfiguration.TimeLimit}"); + } + + private void NotifyArenaChange() + { + _environmentManager.TriggerArenaChangeEvent(arenaID, _environmentManager.GetTotalArenas()); + } + + /// + /// Destroys all spawned rewards in the arena. + /// + private void CleanupRewards() + { + foreach (var reward in spawnedRewards) + { + Destroy(reward); + } + spawnedRewards.Clear(); + } + + /// + /// Updates the light status in the arena based on the current step count. + /// + public void UpdateLigthStatus() + { + int stepCount = _agent.StepCount; + bool newLight = _arenaConfiguration.lightsSwitch.LightStatus( + stepCount, + _agentDecisionInterval + ); + if (newLight != _lightStatus) + { + _lightStatus = newLight; + foreach (Fade fade in _fades) + { + fade.StartFade(); + } + } + } + + /// + /// Returns the total number of spawned objects in the arena. + /// + public int GetTotalSpawnedObjects() + { + Debug.Log("Total spawned objects: " + spawnedObjectsHolder.transform.childCount); + return spawnedObjectsHolder.transform.childCount; + } + + /// + /// Callback for when a reward is spawned in the arena. + /// + private void OnRewardSpawned(GameObject reward) + { + spawnedRewards.Add(reward); + } } From f55e0d5a9f734b8811ba3b66e99bd53aa00426a5 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 19 Jun 2024 21:00:41 +0100 Subject: [PATCH 079/205] minor cleanup --- Assets/Scripts/TrainingArena.cs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/Assets/Scripts/TrainingArena.cs b/Assets/Scripts/TrainingArena.cs index ecf11ab8..ccc5055f 100644 --- a/Assets/Scripts/TrainingArena.cs +++ b/Assets/Scripts/TrainingArena.cs @@ -35,7 +35,6 @@ public class TrainingArena : MonoBehaviour public int arenaID = -1; public TrainingAgent _agent; - private ArenaBuilder _builder; private ArenaConfiguration _arenaConfiguration = new ArenaConfiguration(); private AAI3EnvironmentManager _environmentManager; @@ -160,7 +159,6 @@ public void LoadNextArena() arenaID += 1; - // Load the new configuration ArenaConfiguration newConfiguration = _environmentManager.GetConfiguration(arenaID); // Checks if its final arena in config file and if mergeNextArena is set to true, throws an exception @@ -240,15 +238,14 @@ private int ChooseRandomArenaID(int totalArenas) return availableArenas[Random.Range(0, availableArenas.Count)]; } - /* Note: to update the active arena to a new ID the following must be called in sequence + /* + Note: to update the active arena to a new ID the following must be called in sequence GetConfiguration, ApplyNewArenaConfiguration, CleanupRewards, NotifyArenaChange */ private void ApplyNewArenaConfiguration(ArenaConfiguration newConfiguration) { _arenaConfiguration = newConfiguration; _agent.showNotification = ArenasConfigurations.Instance.showNotification; - Debug.Log("Updating Arena Configuration"); - _arenaConfiguration.SetGameObject(prefabs.GetList()); _builder.Spawnables = _arenaConfiguration.spawnables; _arenaConfiguration.toUpdate = false; @@ -261,7 +258,6 @@ private void ApplyNewArenaConfiguration(ArenaConfiguration newConfiguration) { Random.InitState(_arenaConfiguration.randomSeed); } - Debug.Log($"TimeLimit set to: {_arenaConfiguration.TimeLimit}"); } private void NotifyArenaChange() @@ -306,7 +302,6 @@ public void UpdateLigthStatus() /// public int GetTotalSpawnedObjects() { - Debug.Log("Total spawned objects: " + spawnedObjectsHolder.transform.childCount); return spawnedObjectsHolder.transform.childCount; } From a389b528e14d1dadbc9f60633857a21485f91bc3 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 19 Jun 2024 21:06:46 +0100 Subject: [PATCH 080/205] minor changes to comments --- Assets/Scripts/TrainingAgent.cs | 1401 +++++++++++++++---------------- 1 file changed, 695 insertions(+), 706 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 9b5e675d..3bfc871c 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -24,710 +24,699 @@ /// public class TrainingAgent : Agent, IPrefab { - [Header("Agent Settings")] - public float speed = 25f; - public float quickStopRatio = 0.9f; - public float rotationSpeed = 100f; - public float rotationAngle = 0.25f; - private int lastActionForward = 0; - private int lastActionRotate = 0; - - [Header("Agent State / Other Variables")] - [HideInInspector] - public int numberOfGoalsCollected = 0; - - [HideInInspector] - public ProgressBar progBar; - private Rigidbody _rigidBody; - private bool _isGrounded; - private ContactPoint _lastContactPoint; - - [Header("Agent Rewards & Score")] - private float _rewardPerStep; - private float _previousScore = 0; - private float _currentScore = 0; - - [Header("Agent Health")] - public float health = 100f; - private float _maxHealth = 100f; - - [Header("Agent Freeze & Countdown")] - public float timeLimit = 0f; - private float _nextUpdateHealth = 0f; - private float _freezeDelay = 0f; - private bool _isFrozen = false; - - private bool _nextUpdateCompleteArena = false; - - [Header("Agent Notification")] - public bool showNotification = false; - private TrainingArena _arena; - private bool _isCountdownActive = false; - - [Header("CSV Logging")] - public string csvFilePath = ""; - private StreamWriter writer; - private bool headerWritten = false; - private string yamlFileName; - private int customEpisodeCount = 0; - private ConcurrentQueue logQueue = new ConcurrentQueue(); - private const int bufferSize = 150; // Corresponds to rows in the CSV file to keep in memory before flushing to disk - private bool isFlushing = false; - private string lastCollectedRewardType = "None"; - private string dispensedRewardType = "None"; - private bool wasRewardDispensed = false; - private bool wasButtonPressed = false; - - private void OnRewardSpawned(GameObject reward) - { - wasButtonPressed = true; - Debug.Log("Button was pressed."); - } - - public void RecordDispensedReward() - { - wasRewardDispensed = true; - Debug.Log($"Reward was dispensed."); - } - - public void RecordRewardType(string type) - { - lastCollectedRewardType = type; - Debug.Log($"Reward type collected: {type}"); - } - - public void RecordDispensedRewardType(string type) - { - dispensedRewardType = type; - Debug.Log($"Reward type dispensed: {type}"); - } - - public void SetYamlFileName(string fileName) - { - yamlFileName = fileName; - } - - public override void Initialize() - { - _arena = GetComponentInParent(); - _rigidBody = GetComponent(); - _rewardPerStep = timeLimit > 0 ? -1f / timeLimit : 0; - progBar = GameObject.Find("UI ProgressBar").GetComponent(); - progBar.AssignAgent(this); - health = _maxHealth; - - Spawner_InteractiveButton.RewardSpawned += OnRewardSpawned; - - InitialiseCSVProcess(); - - if (!Application.isEditor) - { - AAI3EnvironmentManager envManager = FindObjectOfType(); - if (envManager != null) - { - SetYamlFileName(envManager.GetCurrentYamlFileName()); - } - } - - StartFlushThread(); - } - - private void InitialiseCSVProcess() - { - // Base path for the logs to be stored - string basePath; - - if (Application.isEditor) - { - // The root directory is the parent of the Assets folder - basePath = Path.GetFullPath(Path.Combine(Application.dataPath, "..")); - } - else - { - // Important! For builds, use the parent of the directory where the executable resides - basePath = Path.GetDirectoryName(Application.dataPath); - } - - // Folder for the CSV logs - string directoryPath = Path.Combine(basePath, "ObservationLogs"); - - // Simple check to see if the directory exists, if not create it - if (!Directory.Exists(directoryPath)) - { - Directory.CreateDirectory(directoryPath); - } - - // Generate a filename with the YAML file name and a date stamp to prevent overwriting. TODO: Extract YAML name from side channel message - string dateTimeString = DateTime.Now.ToString("dd-MM-yy_HHmm"); - string filename = $"Observations_{yamlFileName}_{dateTimeString}.csv"; - csvFilePath = Path.Combine(directoryPath, filename); - - writer = new StreamWriter(csvFilePath, true); - - if (!File.Exists(csvFilePath) || new FileInfo(csvFilePath).Length == 0) - { - if (!headerWritten) - { - writer.WriteLine( - "Episode,Step,Reward,CollectedRewardType,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate,ActionForwardDescription,ActionRotateDescription,IsFrozen,NotificationState,DispensedRewardType,WasRewardDispensed,WasButtonPressed,RaycastObservations,RaycastTags" - ); - headerWritten = true; - } - else - { - Debug.LogError("Header already written to CSV file."); - } - } - } - - /// - /// Logs the agent's state to a CSV file. This is called every step. The data is stored in a queue and flushed to the file in a separate thread. - /// - private void LogToCSV( - Vector3 velocity, - Vector3 position, - int lastActionForward, - int lastActionRotate, - string actionForwardDescription, - string actionRotateDescription, - bool isFrozen, - float reward, - string notificationState, - int customEpisodeCount, - string DispensedRewardType, - bool wasRewardDispensed, - bool wasButtonPressed, - float[] raycastObservations, - string[] raycastTags - - ) - { - string raycastData = string.Join(",", raycastObservations); - string raycastTagsData = string.Join(",", raycastTags); - string logEntry = - $"{customEpisodeCount},{StepCount},{reward},{lastCollectedRewardType},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate},{actionForwardDescription},{actionRotateDescription},{isFrozen},{notificationState},{DispensedRewardType},{wasRewardDispensed},{wasButtonPressed},{raycastData},{raycastTagsData}"; - logQueue.Enqueue(logEntry); - lastCollectedRewardType = "None"; - } - - /// - /// Flushes the log queue to the CSV file. This is called in a separate thread to prevent the main thread from being blocked. - /// - private void FlushLogQueue() - { - while (logQueue.TryDequeue(out var logEntry)) - { - writer.WriteLine(logEntry); - } - writer.Flush(); - Debug.Log("Flushed log queue to CSV file."); - } - - /// - /// Starts a thread that checks if the log queue is full and flushes it to the CSV file if it is. - // WARNING: im not sure if this is the best way to handle this, but it works for now - /// - private void StartFlushThread() - { - new Thread(() => - { - while (true) - { - if (logQueue.Count >= bufferSize && !isFlushing) - { - isFlushing = true; - FlushLogQueue(); - isFlushing = false; - } - Thread.Sleep(100); // polls every 100ms to check if the queue is full. This is to prevent the thread from running continuously and hogging resources. - } - }).Start(); - } - - /// - /// OnDisable is called when the training session is stopped form mlagents. It closes the CSV file and flushes the log queue at whatever the current size is. - /// - protected override void OnDisable() - { - base.OnDisable(); - if (writer != null) - { - FlushLogQueue(); // Ensures all buffered data is written to the file before closing (important for builds) - writer.Close(); - } - - Spawner_InteractiveButton.RewardSpawned -= OnRewardSpawned; - } - - public float GetPreviousScore() - { - return _previousScore; - } - - public float GetFreezeDelay() - { - return _freezeDelay; - } - - public void SetFreezeDelay(float v) - { - _freezeDelay = Mathf.Clamp(v, 0f, v); - if (v != 0f && !_isCountdownActive) - { - Debug.Log( - "Starting coroutine UnfreezeCountdown() with wait seconds == " + GetFreezeDelay() - ); - StartCoroutine(UnfreezeCountdown()); - } - } - - public bool IsFrozen() - { - return _freezeDelay > 0f || _isFrozen; - } - - public void FreezeAgent(bool freeze) - { - _isFrozen = freeze; - if (_isFrozen) - { - _rigidBody.velocity = Vector3.zero; - _rigidBody.angularVelocity = Vector3.zero; - } - } - - private IEnumerator UnfreezeCountdown() - { - _isCountdownActive = true; - yield return new WaitForSeconds(GetFreezeDelay()); - - Debug.Log("unfreezing!"); - SetFreezeDelay(0f); - _isCountdownActive = false; - } - - private string GetNotificationState() - { - if (NotificationManager.Instance == null) - { - return "None"; - } - - return NotificationManager.Instance.GetCurrentNotificationState(); - } - - public override void CollectObservations(VectorSensor sensor) - { - sensor.AddObservation(health); - Vector3 localVel = transform.InverseTransformDirection(_rigidBody.velocity); - Vector3 localPos = transform.position; - bool isFrozen = IsFrozen(); - string actionForwardDescription = DescribeActionForward(lastActionForward); - string actionRotateDescription = DescribeActionRotate(lastActionRotate); - float reward = GetCumulativeReward(); - string notificationState = GetNotificationState(); - - (float[] raycastObservations, string[] raycastTags) = CollectRaycastObservations(); - foreach (float observation in raycastObservations) - { - sensor.AddObservation(observation); - } - - LogToCSV( - localVel, - localPos, - lastActionForward, - lastActionRotate, - actionForwardDescription, - actionRotateDescription, - isFrozen, - reward, - notificationState, - customEpisodeCount, - dispensedRewardType, - wasRewardDispensed, - wasButtonPressed, - raycastObservations, - raycastTags - - ); - dispensedRewardType = "None"; - wasRewardDispensed = false; - wasButtonPressed = false; - } - - public override void OnActionReceived(ActionBuffers action) - { - lastActionForward = Mathf.FloorToInt(action.DiscreteActions[0]); - lastActionRotate = Mathf.FloorToInt(action.DiscreteActions[1]); - if (!IsFrozen()) - { - MoveAgent(lastActionForward, lastActionRotate); - } - - Vector3 localVel = transform.InverseTransformDirection(_rigidBody.velocity); - Vector3 localPos = transform.position; - bool isFrozen = IsFrozen(); - string actionForwardDescription = DescribeActionForward(lastActionForward); - string actionRotateDescription = DescribeActionRotate(lastActionRotate); - float reward = GetCumulativeReward(); - string notificationState = GetNotificationState(); - - // Collect raycast observations and tags directly from the RayPerceptionSensorComponent3D - (float[] raycastObservations, string[] raycastTags) = CollectRaycastObservations(); - - LogToCSV( - localVel, - localPos, - lastActionForward, - lastActionRotate, - actionForwardDescription, - actionRotateDescription, - isFrozen, - reward, - notificationState, - customEpisodeCount, - dispensedRewardType, - wasRewardDispensed, - wasButtonPressed, - raycastObservations, - raycastTags - ); - dispensedRewardType = "None"; - wasRewardDispensed = false; - wasButtonPressed = false; - - UpdateHealth(_rewardPerStep); - } - - private (float[] hitFractions, string[] hitTags) CollectRaycastObservations() - { - RayPerceptionSensorComponent3D rayPerception = - GetComponent(); - if (rayPerception == null) - { - return (new float[0], new string[0]); - } - - var rayPerceptionInput = rayPerception.GetRayPerceptionInput(); - var rayPerceptionOutput = RayPerceptionSensor.Perceive(rayPerceptionInput); - float[] hitFractions = rayPerceptionOutput.RayOutputs.Select(r => r.HitFraction).ToArray(); - string[] hitTags = rayPerceptionOutput.RayOutputs - .Select(r => r.HitGameObject?.tag ?? "None") - .ToArray(); - - return (hitFractions, hitTags); - } - - private string DescribeActionForward(int actionForward) - { - return actionForward switch - { - 0 => "No Movement", - 1 => "Move Forward", - 2 => "Move Backward", - _ => "Unknown Forward Action" - }; - } - - private string DescribeActionRotate(int actionRotate) - { - return actionRotate switch - { - 0 => "No Rotation", - 1 => "Rotate Right", - 2 => "Rotate Left", - _ => "Unknown Rotation Action" - }; - } - - private void MoveAgent(int actionForward, int actionRotate) - { - if (IsFrozen()) - { - // If the agent is frozen, stop all movement and rotation - _rigidBody.velocity = Vector3.zero; - _rigidBody.angularVelocity = Vector3.zero; - return; - } - - Vector3 directionToGo = Vector3.zero; - Vector3 rotateDirection = Vector3.zero; - Vector3 quickStop = Vector3.zero; - - if (_isGrounded) - { - switch (actionForward) - { - case 1: - directionToGo = transform.forward * 1f; - break; - case 2: - directionToGo = transform.forward * -1f; - break; - case 0: // Slow down faster than drag with no input - quickStop = _rigidBody.velocity * quickStopRatio; - _rigidBody.velocity = quickStop; - break; - } - } - - switch (actionRotate) - { - case 1: - rotateDirection = transform.up * 1f; - break; - case 2: - rotateDirection = transform.up * -1f; - break; - } - - transform.Rotate(rotateDirection, Time.fixedDeltaTime * rotationSpeed); - _rigidBody.AddForce( - directionToGo.normalized * speed * 100f * Time.fixedDeltaTime, - ForceMode.Acceleration - ); - } - - public override void Heuristic(in ActionBuffers actionsOut) - { - var discreteActionsOut = actionsOut.DiscreteActions; - discreteActionsOut[0] = 0; - discreteActionsOut[1] = 0; - if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow)) - { - discreteActionsOut[0] = 1; - } - if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow)) - { - discreteActionsOut[0] = 2; - } - if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow)) - { - discreteActionsOut[1] = 1; - } - if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow)) - { - discreteActionsOut[1] = 2; - } - } - - public void UpdateHealthNextStep(float updateAmount, bool andCompleteArena = false) - { - /// - /// ML-Agents doesn't guarantee behaviour if an episode ends outside of OnActionReceived - /// Therefore we queue any health updates to happen on the next action step. - /// - _nextUpdateHealth += updateAmount; - if (andCompleteArena) - { - _nextUpdateCompleteArena = true; - } - } - - public void UpdateHealth(float updateAmount, bool andCompleteArena = false) - { - if (NotificationManager.Instance == null && showNotification) - { - Debug.LogError("NotificationManager instance is not set."); - return; - } - - // Update the health of the agent and reset any queued updates - if (!IsFrozen()) - { - health += 100 * updateAmount; - health += 100 * _nextUpdateHealth; - _nextUpdateHealth = 0; - AddReward(updateAmount); - } - - _currentScore = GetCumulativeReward(); - Debug.Log($"Current cumulative reward: {_currentScore}, Current pass mark: {Arena.CurrentPassMark}"); - - // Ensure health does not exceed maximum limits - if (health > _maxHealth) - { - health = _maxHealth; - } - else if (health <= 0) - { - health = 0; - Debug.Log("Health reached 0, showing failure notification."); - if (showNotification) - { - NotificationManager.Instance.ShowFailureNotification(); - } - StartCoroutine(EndEpisodeAfterDelay()); - return; - } - - // Handle arena completion or episode ending - if (andCompleteArena || _nextUpdateCompleteArena) - { - _nextUpdateCompleteArena = false; - float cumulativeReward = GetCumulativeReward(); - Debug.Log($"Current pass mark: {Arena.CurrentPassMark}"); - - bool proceedToNext = Arena.CurrentPassMark == 0 || cumulativeReward >= Arena.CurrentPassMark; - Debug.Log($"Proceed to next arena: {proceedToNext}, Merge next arena: {_arena.mergeNextArena}"); - - if (proceedToNext) - { - // If the next arena is merged, load that without ending the episode - if (_arena.mergeNextArena) - { - Debug.Log("Merging to next arena without ending episode."); - _arena.LoadNextArena(); - return; - } - - if (showNotification) - { - Debug.Log("Showing success notification."); - NotificationManager.Instance.ShowSuccessNotification(); - } - } - else - { - if (showNotification) - { - Debug.Log("Showing failure notification due to insufficient reward."); - NotificationManager.Instance.ShowFailureNotification(); - } - } - - StartCoroutine(EndEpisodeAfterDelay()); - } - } - - IEnumerator EndEpisodeAfterDelay() - { - if (!showNotification) - { - EndEpisode(); - yield break; - } - - Debug.Log("Starting delay before ending episode."); - yield return new WaitForSeconds(2.5f); - - NotificationManager.Instance.HideNotification(); - Debug.Log("Ending episode after delay."); - EndEpisode(); - } - - public override void OnEpisodeBegin() - { - if (!_arena.IsFirstArenaReset) // Don't log for the first initialization of the arena - { - writer.WriteLine($"Number of Goals Collected: {numberOfGoalsCollected}"); - writer.Flush(); - } - - numberOfGoalsCollected = 0; - customEpisodeCount++; - - writer.Flush(); - EpisodeDebugLogs(); - - StopAllCoroutines(); - _previousScore = _currentScore; - numberOfGoalsCollected = 0; - _arena.ResetArena(); - _rewardPerStep = timeLimit > 0 ? -1f / timeLimit : 0; - _isGrounded = false; - health = _maxHealth; - - SetFreezeDelay(GetFreezeDelay()); - Debug.Log("Agent state reset in OnEpisodeBegin."); - } - - public void AddExtraReward(float rewardFactor) - { - UpdateHealth(Math.Min(rewardFactor * _rewardPerStep, -0.001f)); - } - - private void EpisodeDebugLogs() - { - Debug.Log("Episode Begin"); - Debug.Log($"Value of showNotification: {showNotification}"); - Debug.Log("Current Pass Mark: " + Arena.CurrentPassMark); - Debug.Log("Number of Goals Collected: " + numberOfGoalsCollected); - } - - void OnCollisionEnter(Collision collision) - { - foreach (ContactPoint contact in collision.contacts) - { - if (contact.normal.y > 0) - { - _isGrounded = true; - } - } - _lastContactPoint = collision.contacts.Last(); - } - - void OnCollisionStay(Collision collision) - { - foreach (ContactPoint contact in collision.contacts) - { - if (contact.normal.y > 0) - { - _isGrounded = true; - } - } - _lastContactPoint = collision.contacts.Last(); - } - - void OnCollisionExit(Collision collision) - { - if (_lastContactPoint.normal.y > 0) - { - _isGrounded = false; - } - } - - //****************************** - //PREFAB INTERFACE FOR THE AGENT - //****************************** - - /// - /// Sets the colour and size of the agent. Not used in this implementation. - /// - public void SetColor(Vector3 color) { } - public void SetSize(Vector3 scale) { } - - /// - /// Returns a random position within the range for the object. - /// - public virtual Vector3 GetPosition( - Vector3 position, - Vector3 boundingBox, - float rangeX, - float rangeZ - ) - { - float xBound = boundingBox.x; - float zBound = boundingBox.z; - float xOut = - position.x < 0 - ? Random.Range(xBound, rangeX - xBound) - : Math.Max(0, Math.Min(position.x, rangeX)); - float yOut = Math.Max(position.y, 0) + transform.localScale.y / 2 + 0.01f; - float zOut = - position.z < 0 - ? Random.Range(zBound, rangeZ - zBound) - : Math.Max(0, Math.Min(position.z, rangeZ)); - - return new Vector3(xOut, yOut, zOut); - } - - /// - /// If rotationY set to < 0 change to random rotation. - /// - public virtual Vector3 GetRotation(float rotationY) - { - return new Vector3(0, rotationY < 0 ? Random.Range(0f, 360f) : rotationY, 0); - } + [Header("Agent Settings")] + public float speed = 25f; + public float quickStopRatio = 0.9f; + public float rotationSpeed = 100f; + public float rotationAngle = 0.25f; + private int lastActionForward = 0; + private int lastActionRotate = 0; + + [Header("Agent State / Other Variables")] + [HideInInspector] + public int numberOfGoalsCollected = 0; + + [HideInInspector] + public ProgressBar progBar; + private Rigidbody _rigidBody; + private bool _isGrounded; + private ContactPoint _lastContactPoint; + + [Header("Agent Rewards & Score")] + private float _rewardPerStep; + private float _previousScore = 0; + private float _currentScore = 0; + + [Header("Agent Health")] + public float health = 100f; + private float _maxHealth = 100f; + + [Header("Agent Freeze & Countdown")] + public float timeLimit = 0f; + private float _nextUpdateHealth = 0f; + private float _freezeDelay = 0f; + private bool _isFrozen = false; + + private bool _nextUpdateCompleteArena = false; + + [Header("Agent Notification")] + public bool showNotification = false; + private TrainingArena _arena; + private bool _isCountdownActive = false; + + [Header("CSV Logging")] + public string csvFilePath = ""; + private StreamWriter writer; + private bool headerWritten = false; + private string yamlFileName; + private int customEpisodeCount = 0; + private ConcurrentQueue logQueue = new ConcurrentQueue(); + private const int bufferSize = 150; /* Corresponds to rows in the CSV file to keep in memory before flushing to disk */ + private bool isFlushing = false; + private string lastCollectedRewardType = "None"; + private string dispensedRewardType = "None"; + private bool wasRewardDispensed = false; + private bool wasButtonPressed = false; + + private void OnRewardSpawned(GameObject reward) + { + wasButtonPressed = true; + } + + public void RecordDispensedReward() + { + wasRewardDispensed = true; + } + + public void RecordRewardType(string type) + { + lastCollectedRewardType = type; + } + + public void RecordDispensedRewardType(string type) + { + dispensedRewardType = type; + } + + public void SetYamlFileName(string fileName) + { + yamlFileName = fileName; + } + + public override void Initialize() + { + _arena = GetComponentInParent(); + _rigidBody = GetComponent(); + _rewardPerStep = timeLimit > 0 ? -1f / timeLimit : 0; + progBar = GameObject.Find("UI ProgressBar").GetComponent(); + progBar.AssignAgent(this); + health = _maxHealth; + + Spawner_InteractiveButton.RewardSpawned += OnRewardSpawned; + + InitialiseCSVProcess(); + + if (!Application.isEditor) + { + AAI3EnvironmentManager envManager = FindObjectOfType(); + if (envManager != null) + { + SetYamlFileName(envManager.GetCurrentYamlFileName()); + } + } + + StartFlushThread(); + } + + private void InitialiseCSVProcess() + { + // Base path for the logs to be stored + string basePath; + + if (Application.isEditor) + { + // The root directory is the parent of the Assets folder + basePath = Path.GetFullPath(Path.Combine(Application.dataPath, "..")); + } + else + { + // Important! For builds, use the parent of the directory where the executable resides + basePath = Path.GetDirectoryName(Application.dataPath); + } + + // Folder for the CSV logs + string directoryPath = Path.Combine(basePath, "ObservationLogs"); + + // Simple check to see if the directory exists, if not create it + if (!Directory.Exists(directoryPath)) + { + Directory.CreateDirectory(directoryPath); + } + + // Generate a filename with the YAML file name and a date stamp to prevent overwriting. TODO: Extract YAML name from side channel message + string dateTimeString = DateTime.Now.ToString("dd-MM-yy_HHmm"); + string filename = $"Observations_{yamlFileName}_{dateTimeString}.csv"; + csvFilePath = Path.Combine(directoryPath, filename); + + writer = new StreamWriter(csvFilePath, true); + + if (!File.Exists(csvFilePath) || new FileInfo(csvFilePath).Length == 0) + { + if (!headerWritten) + { + writer.WriteLine( + "Episode,Step,Reward,CollectedRewardType,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate,ActionForwardDescription,ActionRotateDescription,IsFrozen,NotificationState,DispensedRewardType,WasRewardDispensed,WasButtonPressed,RaycastObservations,RaycastTags" + ); + headerWritten = true; + } + else + { + Debug.LogError("Header/Columns already written to CSV file."); + } + } + } + + /// + /// Logs the agent's state to a CSV file. This is called every step. The data is stored in a queue and flushed to the file in a separate thread. + /// + private void LogToCSV( + Vector3 velocity, + Vector3 position, + int lastActionForward, + int lastActionRotate, + string actionForwardDescription, + string actionRotateDescription, + bool isFrozen, + float reward, + string notificationState, + int customEpisodeCount, + string DispensedRewardType, + bool wasRewardDispensed, + bool wasButtonPressed, + float[] raycastObservations, + string[] raycastTags + ) + { + string raycastData = string.Join(",", raycastObservations); + string raycastTagsData = string.Join(",", raycastTags); + string logEntry = + $"{customEpisodeCount},{StepCount},{reward},{lastCollectedRewardType},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate},{actionForwardDescription},{actionRotateDescription},{isFrozen},{notificationState},{DispensedRewardType},{wasRewardDispensed},{wasButtonPressed},{raycastData},{raycastTagsData}"; + logQueue.Enqueue(logEntry); + lastCollectedRewardType = "None"; + } + + /// + /// Flushes the log queue to the CSV file. This is called in a separate thread to prevent the main thread from being blocked. + /// + private void FlushLogQueue() + { + while (logQueue.TryDequeue(out var logEntry)) + { + writer.WriteLine(logEntry); + } + writer.Flush(); + Debug.Log("Flushed log queue to CSV file."); + } + + /// + /// Starts a thread that checks if the log queue is full and flushes it to the CSV file if it is. + // WARNING: im not sure if this is the best way to handle this, but it works for now + /// + private void StartFlushThread() + { + new Thread(() => + { + while (true) + { + if (logQueue.Count >= bufferSize && !isFlushing) + { + isFlushing = true; + FlushLogQueue(); + isFlushing = false; + } + Thread.Sleep(100); // polls every 100ms to check if the queue is full. This is to prevent the thread from running continuously and hogging resources. + } + }).Start(); + } + + /// + /// OnDisable is called when the training session is stopped form mlagents. It closes the CSV file and flushes the log queue at whatever the current size is. + /// + protected override void OnDisable() + { + base.OnDisable(); + if (writer != null) + { + FlushLogQueue(); // Ensures all buffered data is written to the file before closing (important for builds) + writer.Close(); + } + + Spawner_InteractiveButton.RewardSpawned -= OnRewardSpawned; + } + + public float GetPreviousScore() + { + return _previousScore; + } + + public float GetFreezeDelay() + { + return _freezeDelay; + } + + public void SetFreezeDelay(float v) + { + _freezeDelay = Mathf.Clamp(v, 0f, v); + if (v != 0f && !_isCountdownActive) + { + Debug.Log( + "Starting coroutine UnfreezeCountdown() with wait seconds == " + GetFreezeDelay() + ); + StartCoroutine(UnfreezeCountdown()); + } + } + + public bool IsFrozen() + { + return _freezeDelay > 0f || _isFrozen; + } + + public void FreezeAgent(bool freeze) + { + _isFrozen = freeze; + if (_isFrozen) + { + _rigidBody.velocity = Vector3.zero; + _rigidBody.angularVelocity = Vector3.zero; + } + } + + private IEnumerator UnfreezeCountdown() + { + _isCountdownActive = true; + yield return new WaitForSeconds(GetFreezeDelay()); + + Debug.Log("Unfreezing Agent!"); + SetFreezeDelay(0f); + _isCountdownActive = false; + } + + private string GetNotificationState() + { + if (NotificationManager.Instance == null) + { + return "None"; + } + + return NotificationManager.Instance.GetCurrentNotificationState(); + } + + public override void CollectObservations(VectorSensor sensor) + { + sensor.AddObservation(health); + Vector3 localVel = transform.InverseTransformDirection(_rigidBody.velocity); + Vector3 localPos = transform.position; + bool isFrozen = IsFrozen(); + string actionForwardDescription = DescribeActionForward(lastActionForward); + string actionRotateDescription = DescribeActionRotate(lastActionRotate); + float reward = GetCumulativeReward(); + string notificationState = GetNotificationState(); + + (float[] raycastObservations, string[] raycastTags) = CollectRaycastObservations(); + foreach (float observation in raycastObservations) + { + sensor.AddObservation(observation); + } + + LogToCSV( + localVel, + localPos, + lastActionForward, + lastActionRotate, + actionForwardDescription, + actionRotateDescription, + isFrozen, + reward, + notificationState, + customEpisodeCount, + dispensedRewardType, + wasRewardDispensed, + wasButtonPressed, + raycastObservations, + raycastTags + ); + dispensedRewardType = "None"; + wasRewardDispensed = false; + wasButtonPressed = false; + } + + public override void OnActionReceived(ActionBuffers action) + { + lastActionForward = Mathf.FloorToInt(action.DiscreteActions[0]); + lastActionRotate = Mathf.FloorToInt(action.DiscreteActions[1]); + if (!IsFrozen()) + { + MoveAgent(lastActionForward, lastActionRotate); + } + + Vector3 localVel = transform.InverseTransformDirection(_rigidBody.velocity); + Vector3 localPos = transform.position; + bool isFrozen = IsFrozen(); + string actionForwardDescription = DescribeActionForward(lastActionForward); + string actionRotateDescription = DescribeActionRotate(lastActionRotate); + float reward = GetCumulativeReward(); + string notificationState = GetNotificationState(); + + // Collect raycast observations and tags directly from the RayPerceptionSensorComponent3D + // TODO: Need to check if this is the correct way to collect raycast observations + (float[] raycastObservations, string[] raycastTags) = CollectRaycastObservations(); + + LogToCSV( + localVel, + localPos, + lastActionForward, + lastActionRotate, + actionForwardDescription, + actionRotateDescription, + isFrozen, + reward, + notificationState, + customEpisodeCount, + dispensedRewardType, + wasRewardDispensed, + wasButtonPressed, + raycastObservations, + raycastTags + ); + dispensedRewardType = "None"; + wasRewardDispensed = false; + wasButtonPressed = false; + + UpdateHealth(_rewardPerStep); + } + + private (float[] hitFractions, string[] hitTags) CollectRaycastObservations() + { + RayPerceptionSensorComponent3D rayPerception = + GetComponent(); + if (rayPerception == null) + { + return (new float[0], new string[0]); + } + + var rayPerceptionInput = rayPerception.GetRayPerceptionInput(); + var rayPerceptionOutput = RayPerceptionSensor.Perceive(rayPerceptionInput); + float[] hitFractions = rayPerceptionOutput.RayOutputs.Select(r => r.HitFraction).ToArray(); + string[] hitTags = rayPerceptionOutput.RayOutputs + .Select(r => r.HitGameObject?.tag ?? "None") + .ToArray(); + + return (hitFractions, hitTags); + } + + private string DescribeActionForward(int actionForward) + { + return actionForward switch + { + 0 => "No Movement", + 1 => "Move Forward", + 2 => "Move Backward", + _ => "Unknown Forward Action" + }; + } + + private string DescribeActionRotate(int actionRotate) + { + return actionRotate switch + { + 0 => "No Rotation", + 1 => "Rotate Right", + 2 => "Rotate Left", + _ => "Unknown Rotation Action" + }; + } + + private void MoveAgent(int actionForward, int actionRotate) + { + if (IsFrozen()) + { + // If the agent is frozen, stop all movement and rotation + _rigidBody.velocity = Vector3.zero; + _rigidBody.angularVelocity = Vector3.zero; + return; + } + + Vector3 directionToGo = Vector3.zero; + Vector3 rotateDirection = Vector3.zero; + Vector3 quickStop = Vector3.zero; + + if (_isGrounded) + { + switch (actionForward) + { + case 1: + directionToGo = transform.forward * 1f; + break; + case 2: + directionToGo = transform.forward * -1f; + break; + case 0: /* Slow down faster than drag with no input */ + quickStop = _rigidBody.velocity * quickStopRatio; + _rigidBody.velocity = quickStop; + break; + } + } + + switch (actionRotate) + { + case 1: + rotateDirection = transform.up * 1f; + break; + case 2: + rotateDirection = transform.up * -1f; + break; + } + + transform.Rotate(rotateDirection, Time.fixedDeltaTime * rotationSpeed); + _rigidBody.AddForce( + directionToGo.normalized * speed * 100f * Time.fixedDeltaTime, + ForceMode.Acceleration + ); + } + + public override void Heuristic(in ActionBuffers actionsOut) + { + var discreteActionsOut = actionsOut.DiscreteActions; + discreteActionsOut[0] = 0; + discreteActionsOut[1] = 0; + if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow)) + { + discreteActionsOut[0] = 1; + } + if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow)) + { + discreteActionsOut[0] = 2; + } + if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow)) + { + discreteActionsOut[1] = 1; + } + if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow)) + { + discreteActionsOut[1] = 2; + } + } + + public void UpdateHealthNextStep(float updateAmount, bool andCompleteArena = false) + { + /* + ML-Agents doesn't guarantee behaviour if an episode ends outside of OnActionReceived + Therefore we queue any health updates to happen on the next action step. + */ + _nextUpdateHealth += updateAmount; + if (andCompleteArena) + { + _nextUpdateCompleteArena = true; + } + } + + public void UpdateHealth(float updateAmount, bool andCompleteArena = false) + { + // Update the health of the agent and reset any queued updates + if (!IsFrozen()) + { + health += 100 * updateAmount; + health += 100 * _nextUpdateHealth; + _nextUpdateHealth = 0; + AddReward(updateAmount); + } + + _currentScore = GetCumulativeReward(); + + // Ensure health does not exceed maximum limits + if (health > _maxHealth) + { + health = _maxHealth; + } + else if (health <= 0) + { + health = 0; + + if (showNotification) + { + NotificationManager.Instance.ShowFailureNotification(); + } + StartCoroutine(EndEpisodeAfterDelay()); + return; + } + + // Handle arena completion or episode ending + if (andCompleteArena || _nextUpdateCompleteArena) + { + _nextUpdateCompleteArena = false; + float cumulativeReward = GetCumulativeReward(); + Debug.Log($"Current pass mark: {Arena.CurrentPassMark}"); + + bool proceedToNext = + Arena.CurrentPassMark == 0 || cumulativeReward >= Arena.CurrentPassMark; + Debug.Log( + $"Proceed to next arena: {proceedToNext}, Merge next arena: {_arena.mergeNextArena}" + ); + + if (proceedToNext) + { + // If the next arena is merged, load that without ending the episode + if (_arena.mergeNextArena) + { + _arena.LoadNextArena(); + return; + } + + if (showNotification) + { + NotificationManager.Instance.ShowSuccessNotification(); + } + } + else + { + if (showNotification) + { + NotificationManager.Instance.ShowFailureNotification(); + } + } + + StartCoroutine(EndEpisodeAfterDelay()); + } + } + + IEnumerator EndEpisodeAfterDelay() + { + if (!showNotification) + { + EndEpisode(); + yield break; + } + + Debug.Log("Starting delay before ending episode."); + yield return new WaitForSeconds(2.5f); + + NotificationManager.Instance.HideNotification(); + Debug.Log("Ending episode after delay."); + EndEpisode(); + } + + public override void OnEpisodeBegin() + { + if (!_arena.IsFirstArenaReset) // Don't log for the first initialization of the arena + { + writer.WriteLine($"Number of Goals Collected: {numberOfGoalsCollected}"); + writer.Flush(); + } + + numberOfGoalsCollected = 0; + customEpisodeCount++; + + writer.Flush(); + EpisodeDebugLogs(); + + StopAllCoroutines(); + _previousScore = _currentScore; + numberOfGoalsCollected = 0; + _arena.ResetArena(); + _rewardPerStep = timeLimit > 0 ? -1f / timeLimit : 0; + _isGrounded = false; + health = _maxHealth; + + SetFreezeDelay(GetFreezeDelay()); + Debug.Log("Agent state reset in OnEpisodeBegin."); + } + + public void AddExtraReward(float rewardFactor) + { + UpdateHealth(Math.Min(rewardFactor * _rewardPerStep, -0.001f)); + } + + private void EpisodeDebugLogs() + { + Debug.Log("Episode Begin"); + Debug.Log($"Value of showNotification: {showNotification}"); + Debug.Log("Current Pass Mark: " + Arena.CurrentPassMark); + Debug.Log("Number of Goals Collected: " + numberOfGoalsCollected); + } + + void OnCollisionEnter(Collision collision) + { + foreach (ContactPoint contact in collision.contacts) + { + if (contact.normal.y > 0) + { + _isGrounded = true; + } + } + _lastContactPoint = collision.contacts.Last(); + } + + void OnCollisionStay(Collision collision) + { + foreach (ContactPoint contact in collision.contacts) + { + if (contact.normal.y > 0) + { + _isGrounded = true; + } + } + _lastContactPoint = collision.contacts.Last(); + } + + void OnCollisionExit(Collision collision) + { + if (_lastContactPoint.normal.y > 0) + { + _isGrounded = false; + } + } + + //****************************** + //PREFAB INTERFACE FOR THE AGENT + //****************************** + + /// + /// Sets the colour and size of the agent. Not used in this implementation. + /// + public void SetColor(Vector3 color) { } + + public void SetSize(Vector3 scale) { } + + /// + /// Returns a random position within the range for the object. + /// + public virtual Vector3 GetPosition( + Vector3 position, + Vector3 boundingBox, + float rangeX, + float rangeZ + ) + { + float xBound = boundingBox.x; + float zBound = boundingBox.z; + float xOut = + position.x < 0 + ? Random.Range(xBound, rangeX - xBound) + : Math.Max(0, Math.Min(position.x, rangeX)); + float yOut = Math.Max(position.y, 0) + transform.localScale.y / 2 + 0.01f; + float zOut = + position.z < 0 + ? Random.Range(zBound, rangeZ - zBound) + : Math.Max(0, Math.Min(position.z, rangeZ)); + + return new Vector3(xOut, yOut, zOut); + } + + /// + /// If rotationY set to < 0 change to random rotation. + /// + public virtual Vector3 GetRotation(float rotationY) + { + return new Vector3(0, rotationY < 0 ? Random.Range(0f, 360f) : rotationY, 0); + } } From 0f0289e32be18304f57fb0f1b554915e0c0afd3c Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 19 Jun 2024 21:11:45 +0100 Subject: [PATCH 081/205] added TODO // TODO: Debug current pass mark for arena == 0 --- Assets/Scripts/TrainingAgent.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 3bfc871c..8f8e1fc0 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -551,6 +551,7 @@ public void UpdateHealth(float updateAmount, bool andCompleteArena = false) } // Handle arena completion or episode ending + // TODO: Debug current pass mark for arena == 0 if (andCompleteArena || _nextUpdateCompleteArena) { _nextUpdateCompleteArena = false; @@ -596,12 +597,10 @@ IEnumerator EndEpisodeAfterDelay() EndEpisode(); yield break; } - - Debug.Log("Starting delay before ending episode."); yield return new WaitForSeconds(2.5f); NotificationManager.Instance.HideNotification(); - Debug.Log("Ending episode after delay."); + EndEpisode(); } From 678a9ffde4427f2852a2ae1c546d39f0e960c01e Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Fri, 21 Jun 2024 21:40:56 +0100 Subject: [PATCH 082/205] moved file comments to top of file for readability for all yaml files --- Assets/Resources/test_configs/agent_freeze-delay_test.yaml | 2 +- Assets/Resources/test_configs/animal_skins_test.yaml | 2 +- Assets/Resources/test_configs/arenas_multiple_cycling_test.yaml | 2 +- Assets/Resources/test_configs/decoy-file-test.yaml | 2 +- Assets/Resources/test_configs/every_object_spawn_test.yaml | 2 +- Assets/Resources/test_configs/global_parameters_test.yaml | 2 +- Assets/Resources/test_configs/sign_posterboard_symbol_test.yaml | 2 +- Assets/Resources/test_configs/spawner_button_test.yaml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Assets/Resources/test_configs/agent_freeze-delay_test.yaml b/Assets/Resources/test_configs/agent_freeze-delay_test.yaml index 01a2d941..e8823f8a 100644 --- a/Assets/Resources/test_configs/agent_freeze-delay_test.yaml +++ b/Assets/Resources/test_configs/agent_freeze-delay_test.yaml @@ -1,5 +1,5 @@ -!ArenaConfig # Testing the freeze delay countdown feature in multiple arenas. +!ArenaConfig arenas: 0: !Arena passMark: 0 diff --git a/Assets/Resources/test_configs/animal_skins_test.yaml b/Assets/Resources/test_configs/animal_skins_test.yaml index 61dec70d..b04d7a63 100644 --- a/Assets/Resources/test_configs/animal_skins_test.yaml +++ b/Assets/Resources/test_configs/animal_skins_test.yaml @@ -1,6 +1,6 @@ -!ArenaConfig # Testing all the animal skins to make sure they are all working correctly. arenas: +!ArenaConfig 0: !Arena passMark: 0 timeLimit: 250 diff --git a/Assets/Resources/test_configs/arenas_multiple_cycling_test.yaml b/Assets/Resources/test_configs/arenas_multiple_cycling_test.yaml index 9ac5c84d..9a706cbd 100644 --- a/Assets/Resources/test_configs/arenas_multiple_cycling_test.yaml +++ b/Assets/Resources/test_configs/arenas_multiple_cycling_test.yaml @@ -1,6 +1,6 @@ -!ArenaConfig # Checking whether the arenas are cycling sequentially and randomly in PLAY mode only. # Also added check to see if arena index values below 0 will be handled correctly (they should be converted to positive and unique index values). +!ArenaConfig arenas: 0: !Arena passMark: 1 diff --git a/Assets/Resources/test_configs/decoy-file-test.yaml b/Assets/Resources/test_configs/decoy-file-test.yaml index 96145215..4184f2fb 100644 --- a/Assets/Resources/test_configs/decoy-file-test.yaml +++ b/Assets/Resources/test_configs/decoy-file-test.yaml @@ -1,5 +1,5 @@ -!ArenaConfig # Testing file for ongoing development. Will be removed once the feature is complete. +!ArenaConfig arenas: 0: !Arena passMark: 0 diff --git a/Assets/Resources/test_configs/every_object_spawn_test.yaml b/Assets/Resources/test_configs/every_object_spawn_test.yaml index 95d9f40e..3680ad9f 100644 --- a/Assets/Resources/test_configs/every_object_spawn_test.yaml +++ b/Assets/Resources/test_configs/every_object_spawn_test.yaml @@ -1,5 +1,5 @@ -!ArenaConfig # Testing to make sure every object can spawn in the arena. !CORE TEST! +!ArenaConfig arenas: 0: !Arena passMark: 0 # The pass mark for the arena. The agent must achieve this score to pass the arena. diff --git a/Assets/Resources/test_configs/global_parameters_test.yaml b/Assets/Resources/test_configs/global_parameters_test.yaml index fd192cc7..8bdac135 100644 --- a/Assets/Resources/test_configs/global_parameters_test.yaml +++ b/Assets/Resources/test_configs/global_parameters_test.yaml @@ -1,5 +1,5 @@ -!ArenaConfig # Testing whether the global parameters are working on the arenas. This is a test for the global parameters, now and for future use. +!ArenaConfig randomizeArenas: false # whether to randomize arenas from the beginning. Default is false. showNotification: false # show/hide the notification box. Default is false. canResetEpisode: true # allow the user to change the perspective. Default is true. diff --git a/Assets/Resources/test_configs/sign_posterboard_symbol_test.yaml b/Assets/Resources/test_configs/sign_posterboard_symbol_test.yaml index 493141ca..67f82757 100644 --- a/Assets/Resources/test_configs/sign_posterboard_symbol_test.yaml +++ b/Assets/Resources/test_configs/sign_posterboard_symbol_test.yaml @@ -1,5 +1,5 @@ -!ArenaConfig # Testing the SignBoard with different symbols and sizes. +!ArenaConfig arenas: 0: !Arena passMark: 0 diff --git a/Assets/Resources/test_configs/spawner_button_test.yaml b/Assets/Resources/test_configs/spawner_button_test.yaml index 5af6c085..af874177 100644 --- a/Assets/Resources/test_configs/spawner_button_test.yaml +++ b/Assets/Resources/test_configs/spawner_button_test.yaml @@ -1,5 +1,5 @@ -!ArenaConfig # Testing the SpawnerButton with different rewards and spawn probabilities. +!ArenaConfig randomizeArenas: false showNotification: false canResetEpisode: true From d785a2cfc80676910a46f401a764dd48945e07d9 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Sun, 23 Jun 2024 15:51:02 +0100 Subject: [PATCH 083/205] cleaned up GITHUB templates for issues minor changes --- .github/ISSUE_TEMPLATE/bug_report.md | 27 ++++++++++------------- .github/ISSUE_TEMPLATE/feature_request.md | 7 ++++-- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index dd84ea78..14c96593 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,5 +1,5 @@ --- -name: Bug report +name: Bug Report about: Create a report to help us improve title: '' labels: '' @@ -7,9 +7,10 @@ assignees: '' --- -**Describe the bug** +**Describe the Bug** A clear and concise description of what the bug is. + **To Reproduce** Steps to reproduce the behavior: 1. Go to '...' @@ -17,22 +18,18 @@ Steps to reproduce the behavior: 3. Scroll down to '....' 4. See error -**Expected behavior** -A clear and concise description of what you expected to happen. -**Screenshots** -If applicable, add screenshots to help explain your problem. +**Expected Behavior** +A clear and concise description of what you expected to happen. **Desktop (please complete the following information):** - - OS: [e.g. iOS] - - Browser [e.g. chrome, safari] - - Version [e.g. 22] + - OS: [e.g. Windows, Linux, macOS] + - Unity Version [e.g. 2021.3.21f1] -**Smartphone (please complete the following information):** - - Device: [e.g. iPhone6] - - OS: [e.g. iOS8.1] - - Browser [e.g. stock browser, safari] - - Version [e.g. 22] -**Additional context** +**Additional Context** Add any other context about the problem here. + + +**Screenshots** +If applicable, add screenshots to help explain your problem. \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index bbcbbe7d..13faf4aa 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,6 +1,6 @@ --- -name: Feature request -about: Suggest an idea for this project +name: Feature Request +about: Suggest an idea for Animal-AI title: '' labels: '' assignees: '' @@ -10,11 +10,14 @@ assignees: '' **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + **Describe the solution you'd like** A clear and concise description of what you want to happen. + **Describe alternatives you've considered** A clear and concise description of any alternative solutions or features you've considered. + **Additional context** Add any other context or screenshots about the feature request here. From 02102043c075a0ea91da504f43aa437f274cdf3e Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Sun, 23 Jun 2024 21:40:22 +0100 Subject: [PATCH 084/205] implemented basic datazone that logs to csv file --- Assets/Scripts/DataZone.cs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/Assets/Scripts/DataZone.cs b/Assets/Scripts/DataZone.cs index 27837c99..d10905fc 100644 --- a/Assets/Scripts/DataZone.cs +++ b/Assets/Scripts/DataZone.cs @@ -1,18 +1,20 @@ -using System.Collections; -using System.Collections.Generic; using UnityEngine; +/// +/// A zone that triggers an event when an agent enters it. It's primary use is to trigger data collection. +/// public class DataZone : Prefab { - // Start is called before the first frame update - void Start() - { - - } + // TODO: Add logic to differentiate between different datazones + // TODO: Implement parameter to specify zone names/sections in yaml file (under the datazones Item) + public delegate void InDataZoneHandler(GameObject zone); + public static event InDataZoneHandler OnInDataZone; - // Update is called once per frame - void Update() + private void OnCollisionEnter(Collision other) { - + if (other.gameObject.CompareTag("agent")) + { + OnInDataZone?.Invoke(gameObject); + } } } From 87ae60dc0c5835aa36d64145e8d8338169f400e3 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Sun, 23 Jun 2024 21:41:19 +0100 Subject: [PATCH 085/205] csv file now collects/logs datazones per timestep current datazone is basic information and generic --- Assets/Scripts/TrainingAgent.cs | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 8f8e1fc0..a37d4147 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -75,9 +75,15 @@ public class TrainingAgent : Agent, IPrefab private bool isFlushing = false; private string lastCollectedRewardType = "None"; private string dispensedRewardType = "None"; + private string wasInDataZone = "No"; private bool wasRewardDispensed = false; private bool wasButtonPressed = false; + private void OnInDataZone(GameObject zone) + { + wasInDataZone = "Agent was in DataZone"; + } + private void OnRewardSpawned(GameObject reward) { wasButtonPressed = true; @@ -113,6 +119,7 @@ public override void Initialize() health = _maxHealth; Spawner_InteractiveButton.RewardSpawned += OnRewardSpawned; + DataZone.OnInDataZone += OnInDataZone; InitialiseCSVProcess(); @@ -165,7 +172,7 @@ private void InitialiseCSVProcess() if (!headerWritten) { writer.WriteLine( - "Episode,Step,Reward,CollectedRewardType,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate,ActionForwardDescription,ActionRotateDescription,IsFrozen,NotificationState,DispensedRewardType,WasRewardDispensed,WasButtonPressed,RaycastObservations,RaycastTags" + "Episode,Step,Reward,CollectedRewardType,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate,ActionForwardDescription,ActionRotateDescription,IsFrozen,NotificationState,DispensedRewardType,WasRewardDispensed,WasButtonPressed,RaycastObservations,RaycastTags,WasInDataZone" ); headerWritten = true; } @@ -194,13 +201,14 @@ private void LogToCSV( bool wasRewardDispensed, bool wasButtonPressed, float[] raycastObservations, - string[] raycastTags + string[] raycastTags, + string wasInDataZone ) { string raycastData = string.Join(",", raycastObservations); string raycastTagsData = string.Join(",", raycastTags); string logEntry = - $"{customEpisodeCount},{StepCount},{reward},{lastCollectedRewardType},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate},{actionForwardDescription},{actionRotateDescription},{isFrozen},{notificationState},{DispensedRewardType},{wasRewardDispensed},{wasButtonPressed},{raycastData},{raycastTagsData}"; + $"{customEpisodeCount},{StepCount},{reward},{lastCollectedRewardType},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate},{actionForwardDescription},{actionRotateDescription},{isFrozen},{notificationState},{DispensedRewardType},{wasRewardDispensed},{wasButtonPressed},{raycastData},{raycastTagsData},{wasInDataZone}"; logQueue.Enqueue(logEntry); lastCollectedRewardType = "None"; } @@ -252,6 +260,7 @@ protected override void OnDisable() } Spawner_InteractiveButton.RewardSpawned -= OnRewardSpawned; + DataZone.OnInDataZone -= OnInDataZone; } public float GetPreviousScore() @@ -343,11 +352,13 @@ public override void CollectObservations(VectorSensor sensor) wasRewardDispensed, wasButtonPressed, raycastObservations, - raycastTags + raycastTags, + wasInDataZone ); dispensedRewardType = "None"; wasRewardDispensed = false; wasButtonPressed = false; + wasInDataZone = "No"; } public override void OnActionReceived(ActionBuffers action) @@ -386,11 +397,13 @@ public override void OnActionReceived(ActionBuffers action) wasRewardDispensed, wasButtonPressed, raycastObservations, - raycastTags + raycastTags, + wasInDataZone ); dispensedRewardType = "None"; wasRewardDispensed = false; wasButtonPressed = false; + wasInDataZone = "No"; UpdateHealth(_rewardPerStep); } @@ -551,7 +564,7 @@ public void UpdateHealth(float updateAmount, bool andCompleteArena = false) } // Handle arena completion or episode ending - // TODO: Debug current pass mark for arena == 0 + // TODO: Debug current pass mark for arena == 0 if (andCompleteArena || _nextUpdateCompleteArena) { _nextUpdateCompleteArena = false; From 0e168978dcf8589f78d8da76490c8e98317f1806 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Fri, 12 Jul 2024 18:15:14 +0300 Subject: [PATCH 086/205] added observationlogs to git.ignore config again --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index e565f2bc..8a5364a5 100644 --- a/.gitignore +++ b/.gitignore @@ -114,3 +114,4 @@ Assets/Prefabs/Other-Unique/SignPosterboard.prefab .plastic/plastic.wktree /ObservationLogs *.csv +/ObservationLogs From d0f2c1d0dc33e225d7f936b34c8fd39ca7577e46 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Fri, 12 Jul 2024 21:41:58 +0300 Subject: [PATCH 087/205] working feature: string param to set datazone ID --- Assets/Scripts/ArenaBuilders.cs | 1485 ++++++++++++++-------------- Assets/Scripts/ArenasParameters.cs | 662 +++++++------ Assets/Scripts/DataZone.cs | 11 +- Assets/Scripts/TrainingAgent.cs | 9 +- Assets/Scripts/YAMLclasses.cs | 2 + 5 files changed, 1094 insertions(+), 1075 deletions(-) diff --git a/Assets/Scripts/ArenaBuilders.cs b/Assets/Scripts/ArenaBuilders.cs index 0ccccc26..0c6fa98f 100644 --- a/Assets/Scripts/ArenaBuilders.cs +++ b/Assets/Scripts/ArenaBuilders.cs @@ -17,740 +17,753 @@ /// namespace ArenaBuilders { - public class ArenaBuilder - { - #region Properties and Fields - - // Arena size - private float _rangeX; - private float _rangeZ; - - // Getters for the arena size (used for spawning objects within the arena bounds in other scripts) - public float ArenaWidth => _rangeX; - public float ArenaDepth => _rangeZ; - - // Arena to which the builder is attached - private Transform _arena; - - // Holder for all spawned objects - private GameObject _spawnedObjectsHolder; - - // Max number of attempts to spawn an object or agent - private int _maxSpawnAttemptsForPrefabs; - private int _maxSpawnAttemptsForAgent; - - // Agent components - private GameObject _agent; - private Collider _agentCollider; - private Rigidbody _agentRigidbody; - - // Total number of good goals instantiated - private List _goodGoalsMultiSpawned; - - // Total number of objects spawned (for UI) - private int _totalObjectsSpawned; - - // The list of Spawnables the ArenaBuilder will attempt to spawn at each reset - [HideInInspector] - public List Spawnables { get; set; } - - #endregion - - #region Arena Constructor - - /// - /// Constructor for the ArenaBuilder class. - /// It initializes the arena, the spawned objects holder, and the maximum spawn attempts for prefabs and the agent. - /// - public ArenaBuilder( - GameObject arenaGameObject, - GameObject spawnedObjectsHolder, - int maxSpawnAttemptsForPrefabs, - int maxSpawnAttemptsForAgent - ) - { - _arena = arenaGameObject.GetComponent(); - Transform spawnArenaTransform = _arena - .FindChildWithTag("spawnArena") - .GetComponent(); - _rangeX = spawnArenaTransform.localScale.x; - _rangeZ = spawnArenaTransform.localScale.z; - _agent = _arena.Find("AAI3Agent").Find("Agent").gameObject; - ; - _agentCollider = _agent.GetComponent(); - _agentRigidbody = _agent.GetComponent(); - _spawnedObjectsHolder = spawnedObjectsHolder; - _maxSpawnAttemptsForPrefabs = maxSpawnAttemptsForPrefabs; - _maxSpawnAttemptsForAgent = maxSpawnAttemptsForAgent; - Spawnables = new List(); - _goodGoalsMultiSpawned = new List(); - } - - #endregion - - #region Arena Builder - - /// - /// Builds the arena by instantiating the Spawnable objects within the arena. - /// - public void Build() - { - _totalObjectsSpawned = 0; - - _goodGoalsMultiSpawned.Clear(); - - GameObject spawnedObjectsHolder = GameObject.Instantiate( - _spawnedObjectsHolder, - _arena.transform, - false - ); - spawnedObjectsHolder.transform.parent = _arena; - - InstantiateSpawnables(spawnedObjectsHolder); - - TrainingAgent agentInstance = UnityEngine.Object.FindObjectOfType(); - if (agentInstance != null && _arena != null) - { - TrainingArena trainingArena = _arena.GetComponent(); - if (trainingArena != null) - { - agentInstance.showNotification = ArenasConfigurations.Instance.showNotification; - } - } - - updateGoodGoalsMulti(); - } - - #endregion - - #region Instantiate and Spawn Objects Methods - - /// - /// Instantiates the Spawnable objects within the arena. - /// - private void InstantiateSpawnables(GameObject spawnedObjectsHolder) - { - Debug.Log("Spawnables has " + Spawnables.Capacity + " entries"); - List agentSpawnablesFromUser = Spawnables - .Where(x => x.gameObject != null && x.gameObject.CompareTag("agent")) - .ToList(); - - // Instantiate the agent first based on its characteristics, then prevent item spawning at the same location; - // ... otherwise, spawn it last to enable more object spawns. - if (agentSpawnablesFromUser.Any()) - { - _agentCollider.enabled = false; - SpawnAgent(agentSpawnablesFromUser[0]); - _agentCollider.enabled = true; - SpawnObjects(spawnedObjectsHolder); - } - else - { - _agentCollider.enabled = false; - SpawnObjects(spawnedObjectsHolder); - SpawnAgent(null); - _agentCollider.enabled = true; - } - } - - /// - /// Spawns the objects within the arena. - /// - private void SpawnObjects(GameObject spawnedObjectsHolder) - { - foreach (Spawnable spawnable in Spawnables) - { - if (spawnable.gameObject != null) - { - if (!spawnable.gameObject.CompareTag("agent")) - { - InstantiateSpawnable(spawnable, spawnedObjectsHolder); - } - } - } - } - - /// - /// InstantiateSpawnable spawns game objects in a game environment. - /// It takes two parameters: a Spawnable object and a GameObject that serves as a holder for the spawned objects. - /// The method instantiates the game object, sets its layer, position, rotation, and scale, and then spawns the game object. - /// The method also sets the color of the game object and assigns a symbol name to the game object's SignBoard component. - /// - private void InstantiateSpawnable(Spawnable spawnable, GameObject spawnedObjectsHolder) - { - // Required parameters - List positions = spawnable.positions; - List rotations = spawnable.rotations; - List sizes = spawnable.sizes; - List colors = spawnable.colors; - - // Optional parameters - List symbolNames = spawnable.symbolNames; - List delays = spawnable.delays; - List initialValues = spawnable.initialValues; - List finalValues = spawnable.finalValues; - List changeRates = spawnable.changeRates; - List spawnCounts = spawnable.spawnCounts; - List spawnColors = spawnable.spawnColors; - List timesBetweenSpawns = spawnable.timesBetweenSpawns; - List ripenTimes = spawnable.ripenTimes; - List doorDelays = spawnable.doorDelays; - List timesBetweenDoorOpens = spawnable.timesBetweenDoorOpens; - List moveDurations = spawnable.moveDurations; - List resetDurations = spawnable.resetDurations; - - // Get the number of elements in the lists - int numberOfPositions = positions.Count; - int numberOfRotations = rotations.Count; - int numberOfSizes = sizes.Count; - int numberOfColors = colors.Count; - int numberOfSymbolNames = optionalCount(symbolNames); - int numberOfDelays = optionalCount(delays); - int numberOfInitialValues = optionalCount(initialValues); - int numberOfFinalValues = optionalCount(finalValues); - int numberOfChangeRates = optionalCount(changeRates); - int numberOfSpawnCounts = optionalCount(spawnCounts); - int numberOfSpawnColors = optionalCount(spawnColors); - int numberOfTimesBetweenSpawns = optionalCount(timesBetweenSpawns); - int numberOfRipenTimes = optionalCount(ripenTimes); - int numberOfDoorDelays = optionalCount(doorDelays); - int numberOfTimesBetweenDoorOpens = optionalCount(timesBetweenDoorOpens); - int numberOfMoveDurations = optionalCount(moveDurations); - int numberOfResetDurations = optionalCount(resetDurations); - - // Get the number of elements in the lists - int[] ns = new int[] - { - numberOfPositions, - numberOfRotations, - numberOfSizes, - numberOfColors, - numberOfSymbolNames, - numberOfDelays, - numberOfInitialValues, - numberOfFinalValues, - numberOfChangeRates, - numberOfSpawnCounts, - numberOfSpawnColors, - numberOfTimesBetweenSpawns, - numberOfRipenTimes, - numberOfDoorDelays, - numberOfTimesBetweenDoorOpens, - numberOfMoveDurations, - numberOfResetDurations - }; - // Get the maximum number of elements in the lists - int n = ns.Max(); - - // Spawn the objects - int k = 0; - do - { - GameObject gameObjectInstance = GameObject.Instantiate( - spawnable.gameObject, - spawnedObjectsHolder.transform, - false - ); - gameObjectInstance.SetLayer(1); - Vector3 position = k < ns[0] ? positions[k] : -Vector3.one; - float rotation = k < ns[1] ? rotations[k] : -1; - Vector3 size = k < ns[2] ? sizes[k] : -Vector3.one; - Vector3 color = k < ns[3] ? colors[k] : -Vector3.one; - - // For optional parameters, use default values if not provided - string symbolName = k < ns[4] ? symbolNames[k] : null; - float delay = k < ns[5] ? delays[k] : 0; - bool tree = (spawnable.name.Contains("Tree")); - bool ripen_or_grow = ( - spawnable.name.StartsWith("Anti") || spawnable.name.StartsWith("Grow") || tree - ); - float initialValue = - k < ns[6] ? initialValues[k] : (tree ? 0.2f : (ripen_or_grow ? 0.5f : 2.5f)); - float finalValue = - k < ns[7] ? finalValues[k] : (tree ? 1f : (ripen_or_grow ? 2.5f : 0.5f)); - float changeRate = k < ns[8] ? changeRates[k] : -0.005f; - int spawnCount = k < ns[9] ? spawnCounts[k] : -1; - Vector3 spawnColor = k < ns[10] ? spawnColors[k] : -Vector3.one; - float timeBetweenSpawns = k < ns[11] ? timesBetweenSpawns[k] : (tree ? 4f : 1.5f); - float ripenTime = k < ns[12] ? ripenTimes[k] : 6f; - float doorDelay = k < ns[13] ? doorDelays[k] : 10f; - float timeBetweenDoorOpens = k < ns[14] ? timesBetweenDoorOpens[k] : -1f; - float moveDuration = k < ns[15] ? moveDurations[k] : 1.0f; - float resetDuration = k < ns[16] ? resetDurations[k] : 1.0f; - float spawnProbability = spawnable.SpawnProbability; - Vector3 rewardSpawnPos = spawnable.rewardSpawnPos; - - // Assign the optional parameters to a dictionary - Dictionary optionals = new Dictionary() - { - { nameof(symbolName), symbolName }, - { nameof(delay), delay }, - { nameof(initialValue), initialValue }, - { nameof(finalValue), finalValue }, - { nameof(changeRate), changeRate }, - { nameof(spawnCount), spawnCount }, - { nameof(spawnColor), spawnColor }, - { nameof(timeBetweenSpawns), timeBetweenSpawns }, - { nameof(ripenTime), ripenTime }, - { nameof(doorDelay), doorDelay }, - { nameof(timeBetweenDoorOpens), timeBetweenDoorOpens }, - { nameof(moveDuration), moveDuration }, - { nameof(resetDuration), resetDuration }, - { nameof(spawnProbability), spawnProbability }, - { "rewardNames", spawnable.RewardNames }, - { "rewardWeights", spawnable.RewardWeights }, - { "rewardSpawnPos", rewardSpawnPos }, - { "maxRewardCounts", spawnable.maxRewardCounts } - }; - - // Determines a suitable position and rotation for the object to spawn - PositionRotation spawnPosRot = SamplePositionRotation( - gameObjectInstance, - _maxSpawnAttemptsForPrefabs, - position, - rotation, - size - ); - - SpawnGameObject(spawnable, gameObjectInstance, spawnPosRot, color, optionals); - _totalObjectsSpawned++; - k++; - } while (k < n); - } - - /// - /// The SpawnGameObject function instantiates a game object with specified properties, sets its position, rotation, and color, assigns it a symbol name if provided, - /// ...adjusts properties of its Spawner_InteractiveButton and GoalSpawner components based on optional parameters, and assigns timing parameters to relevant components. - /// - private void SpawnGameObject( - Spawnable spawnable, - GameObject gameObjectInstance, - PositionRotation spawnLocRot, - Vector3 color, - Dictionary optionals = null - ) - { - if (spawnLocRot != null) - { - gameObjectInstance.transform.localPosition = spawnLocRot.Position; - gameObjectInstance.transform.Rotate(spawnLocRot.Rotation); - gameObjectInstance.SetLayer(0); - gameObjectInstance.GetComponent().SetColor(color); - - if ( - gameObjectInstance.CompareTag("goodGoalMulti") - || gameObjectInstance.CompareTag("goodGoal") - ) - { - _goodGoalsMultiSpawned.Add(gameObjectInstance.GetComponent()); - } - if (optionals != null) - { - if ( - optionals.TryGetValue("symbolName", out var symbolNameValue) - && symbolNameValue is string symbolName - ) - { - AssignSymbolName(gameObjectInstance, symbolName, color); - } - - var spawnerInteractiveButton = - gameObjectInstance.GetComponentInChildren(); - if (spawnerInteractiveButton != null) - { - if ( - optionals.TryGetValue("moveDuration", out var moveDurationValue) - && moveDurationValue is float moveDuration - ) - { - spawnerInteractiveButton.MoveDuration = moveDuration; - } - if ( - optionals.TryGetValue("resetDuration", out var resetDurationValue) - && resetDurationValue is float resetDuration - ) - { - spawnerInteractiveButton.ResetDuration = resetDuration; - } - if ( - optionals.TryGetValue("spawnProbability", out var spawnProbabilityValue) - && spawnProbabilityValue is float spawnProbability - ) - { - spawnerInteractiveButton.SpawnProbability = spawnProbability; - } - if ( - optionals.TryGetValue("rewardNames", out var rewardNamesValue) - && rewardNamesValue is List rewardNames - ) - { - spawnerInteractiveButton.RewardNames = rewardNames; - } - if ( - optionals.TryGetValue("rewardWeights", out var rewardWeightsValue) - && rewardWeightsValue is List rewardWeights - ) - { - spawnerInteractiveButton.RewardWeights = rewardWeights; - } - if ( - optionals.TryGetValue("rewardSpawnPos", out var rewardSpawnPosValue) - && rewardSpawnPosValue is Vector3 rewardSpawnPos - ) - { - spawnerInteractiveButton.RewardSpawnPos = rewardSpawnPos; - } - if ( - optionals.TryGetValue("maxRewardCounts", out var maxRewardCountsValue) - && maxRewardCountsValue is List maxRewardCounts - ) - { - spawnerInteractiveButton.MaxRewardCounts = maxRewardCounts; - } - } - - // Check for optional spawnColor for Spawner objects - if ( - optionals.TryGetValue("spawnColor", out var spawnColorValue) - && spawnColorValue != null - && gameObjectInstance.TryGetComponent(out GoalSpawner GS) - ) - { - GS.SetSpawnColor((Vector3)spawnColorValue); - } - - // Now check all floats relating to timing of changes - // Each float param has a list of "acceptable types" to which it applies - Dictionary> paramValidTypeLookup = new Dictionary< - string, - List - > - { - { - "delay", - new List - { - typeof(DecayGoal), - typeof(SizeChangeGoal), - typeof(GoalSpawner) - } - }, - { - "initialValue", - new List - { - typeof(DecayGoal), - typeof(SizeChangeGoal), - typeof(GoalSpawner) - } - }, - { - "finalValue", - new List - { - typeof(DecayGoal), - typeof(SizeChangeGoal), - typeof(GoalSpawner) - } - }, - { - "changeRate", - new List { typeof(DecayGoal), typeof(SizeChangeGoal) } - }, - { - "spawnCount", - new List { typeof(GoalSpawner) } - }, - { - "timeBetweenSpawns", - new List { typeof(GoalSpawner) } - }, - { - "ripenTime", - new List { typeof(GoalSpawner) } - }, // TreeSpawners only! Ignored o/wise - { - "doorDelay", - new List { typeof(SpawnerStockpiler) } - }, // Dispensers/Containers only! - { - "timeBetweenDoorOpens", - new List { typeof(SpawnerStockpiler) } - }, // Dispensers/Containers only! - }; - float v; - foreach (string paramKey in paramValidTypeLookup.Keys) - { - // Try each valid type that we might be able to assign to - if (optionals[paramKey] != null) - { - foreach (Type U in paramValidTypeLookup[paramKey]) - { - // Check if gameObjectInstance has got the relevant component - if (gameObjectInstance.TryGetComponent(U, out var component)) - { - v = Convert.ToSingle(optionals[paramKey]); - AssignTimingNumber(paramKey, v, component); - } - } - } - } - } - else - { - gameObjectInstance.SetActive(false); - GameObject.Destroy(gameObjectInstance); - } - } - } - - #endregion - - #region Spawn Agent - - /// - /// The SpawnAgent function spawns an agent in a game environment. - /// It takes a Spawnable object as a parameter and spawns the agent at a specified position and rotation. - /// The function also sets the agent's skin and freeze delay. - /// - private void SpawnAgent(Spawnable agentSpawnableFromUser) - { - PositionRotation agentToSpawnPosRot; - Vector3 agentSize = _agent.transform.localScale; - Vector3 position; - float rotation; - string skin; - float freezeDelay; - - position = - (agentSpawnableFromUser == null || !agentSpawnableFromUser.positions.Any()) - ? -Vector3.one - : agentSpawnableFromUser.positions[0]; - rotation = - (agentSpawnableFromUser == null || !agentSpawnableFromUser.rotations.Any()) - ? -1 - : agentSpawnableFromUser.rotations[0]; - - // Extra check for skins because optional param is not always initialised as a List in Spawnable class - if (agentSpawnableFromUser != null && agentSpawnableFromUser.skins == null) - { - agentSpawnableFromUser.skins = new List(); - } - skin = - (agentSpawnableFromUser == null || !agentSpawnableFromUser.skins.Any()) - ? "random" - : agentSpawnableFromUser.skins[0]; - - // Extra check for freeze delay for same reason as above w/skins - if (agentSpawnableFromUser != null && agentSpawnableFromUser.frozenAgentDelays == null) - { - agentSpawnableFromUser.frozenAgentDelays = new List(); - } - freezeDelay = - (agentSpawnableFromUser == null || !agentSpawnableFromUser.frozenAgentDelays.Any()) - ? 0 - : agentSpawnableFromUser.frozenAgentDelays[0]; - - agentToSpawnPosRot = SamplePositionRotation( - _agent, - _maxSpawnAttemptsForAgent, - position, - rotation, - agentSize - ); - - _agentRigidbody.angularVelocity = Vector3.zero; - _agentRigidbody.velocity = Vector3.zero; - _agent.transform.localPosition = agentToSpawnPosRot.Position; - _agent.transform.rotation = Quaternion.Euler(agentToSpawnPosRot.Rotation); - - AnimalSkinManager ASM = _agent.GetComponentInChildren(); - Debug.Log("Setting AnimalSkin with ASM: " + ASM.ToString() + " and skin: " + skin); - ASM.SetAnimalSkin(skin); - _agent.GetComponent().SetFreezeDelay(freezeDelay); - } - - #endregion - - #region Check Position/Rotation and Object Placement Methods - - /// - /// The SamplePositionRotation function samples a position and rotation for a game object to spawn. - /// It takes five parameters: a game object instance, the maximum number of spawn attempts, a position, a rotation, and a size. - /// The function returns a PositionRotation object that contains the position and rotation of the game object to spawn. - /// - private PositionRotation SamplePositionRotation( - GameObject gameObjectInstance, - int maxSpawnAttempt, - Vector3 positionIn, - float rotationY, - Vector3 size - ) - { - Vector3 gameObjectBoundingBox; - Vector3 rotationOut = Vector3.zero; - Vector3 positionOut = Vector3.zero; - IPrefab gameObjectInstanceIPrefab = gameObjectInstance.GetComponent(); - bool canSpawn = false; - int k = 0; - - while (!canSpawn && k < maxSpawnAttempt) - { - gameObjectInstanceIPrefab.SetSize(size); - gameObjectBoundingBox = gameObjectInstance.GetBoundsWithChildren().extents; - - positionOut = gameObjectInstanceIPrefab.GetPosition( - positionIn, - gameObjectBoundingBox, - _rangeX, - _rangeZ - ); - rotationOut = gameObjectInstanceIPrefab.GetRotation(rotationY); - - Collider[] colliders = Physics.OverlapBox( - positionOut + _arena.position, - gameObjectBoundingBox, - Quaternion.Euler(rotationOut), - 1 << 0 - ); - canSpawn = IsSpotFree( - colliders, - gameObjectInstance.CompareTag("agent"), - gameObjectInstance.name.Contains("Zone") - ); - k++; - } - if (canSpawn) - { - return new PositionRotation(positionOut, rotationOut); - } - return null; - } - - /// - /// The IsSpotFree function checks if a spot is free for a game object to spawn. - /// It takes three parameters: an array of colliders, a boolean value indicating if the object is an agent, and a boolean value indicating if the object is a zone. - /// The function returns true if the spot is free; otherwise, it returns false. - /// - private bool IsSpotFree(Collider[] colliders, bool isAgent, bool isZone = false) - { - if (isZone) - return colliders.Length == 0 - || ( - colliders.All( - collider => - collider.isTrigger || !collider.gameObject.CompareTag("arena") - ) && !isAgent - ); - else - return colliders.Length == 0 - || (colliders.All(collider => collider.isTrigger) && !isAgent); - } - - /// - /// The ObjectOutsideOfBounds function checks if a game object is outside of the arena bounds (walls). - /// It takes two parameters: a position and a bounding box. - /// The function returns true if the object is outside of the bounds; otherwise, it returns false. - /// - private bool ObjectOutsideOfBounds(Vector3 position, Vector3 boundingBox) - { - return position.x > boundingBox.x - && position.x < _rangeX - boundingBox.x - && position.z > boundingBox.z - && position.z < _rangeZ - boundingBox.z; - } - - #endregion - - #region Goal Spawner-Logic Methods - - /// - /// Updates the number of goals in the goodGoalsMultiSpawned list. - /// - private void updateGoodGoalsMulti() - { - int numberOfGoals = _goodGoalsMultiSpawned.Count; - foreach (Goal goodGoalMulti in _goodGoalsMultiSpawned) - { - goodGoalMulti.numberOfGoals = numberOfGoals; - } - } - - /// - /// Adds a goal to the goodGoalsMultiSpawned list. - /// - public void AddToGoodGoalsMultiSpawned(Goal ggm) - { - _goodGoalsMultiSpawned.Add(ggm); - updateGoodGoalsMulti(); - } - - /// - /// Adds a goal to the goodGoalsMultiSpawned list as a GameObject. - /// - public void AddToGoodGoalsMultiSpawned(GameObject ggm) - { - _goodGoalsMultiSpawned.Add(ggm.GetComponent()); - updateGoodGoalsMulti(); - } - - #endregion - - #region Other Methods - - /// - /// Returns the number of elements in a list if not null; otherwise, returns 0. - /// - private int optionalCount(List paramList) - { - return (paramList != null) ? paramList.Count : 0; - } - - /// - /// Returns the total number of objects spawned. - /// - public int GetTotalObjectsSpawned() - { - return _totalObjectsSpawned; - } - - /// - /// Assigns a symbol name to a component's SignBoard. - /// - private void AssignSymbolName(GameObject gameObjectInstance, string sName, Vector3 color) - { - SignBoard SP = gameObjectInstance.GetComponent(); - if (SP != null) - { - if (color != new Vector3(-1, -1, -1)) - { - SP.SetColourOverride(color, true); - } - - SP.SetSymbol(sName, true); - Debug.Log("Assigned symbol name: " + sName + " to " + gameObjectInstance.name); - } - else - { - Debug.Log("No SignBoard component found on " + gameObjectInstance.name); - } - } - - - /// - /// Assigns a float value to a component's timing parameter. - /// - private void AssignTimingNumber(string paramName, float value, T component) - { - paramName = paramName[0].ToString().ToUpper() + paramName.Substring(1); - MethodInfo SetMethod = component.GetType().GetMethod("Set" + (paramName)); - - if (SetMethod != null) - { - SetMethod.Invoke(component, new object[] { value }); - } - } - - #endregion - } + public class ArenaBuilder + { + #region Properties and Fields + + // Arena size + private float _rangeX; + private float _rangeZ; + + // Getters for the arena size (used for spawning objects within the arena bounds in other scripts) + public float ArenaWidth => _rangeX; + public float ArenaDepth => _rangeZ; + + // Arena to which the builder is attached + private Transform _arena; + + // Holder for all spawned objects + private GameObject _spawnedObjectsHolder; + + // Max number of attempts to spawn an object or agent + private int _maxSpawnAttemptsForPrefabs; + private int _maxSpawnAttemptsForAgent; + + // Agent components + private GameObject _agent; + private Collider _agentCollider; + private Rigidbody _agentRigidbody; + + // Total number of good goals instantiated + private List _goodGoalsMultiSpawned; + + // Total number of objects spawned (for UI) + private int _totalObjectsSpawned; + + // The list of Spawnables the ArenaBuilder will attempt to spawn at each reset + [HideInInspector] + public List Spawnables { get; set; } + + #endregion + + #region Arena Constructor + + /// + /// Constructor for the ArenaBuilder class. + /// It initializes the arena, the spawned objects holder, and the maximum spawn attempts for prefabs and the agent. + /// + public ArenaBuilder( + GameObject arenaGameObject, + GameObject spawnedObjectsHolder, + int maxSpawnAttemptsForPrefabs, + int maxSpawnAttemptsForAgent + ) + { + _arena = arenaGameObject.GetComponent(); + Transform spawnArenaTransform = _arena + .FindChildWithTag("spawnArena") + .GetComponent(); + _rangeX = spawnArenaTransform.localScale.x; + _rangeZ = spawnArenaTransform.localScale.z; + _agent = _arena.Find("AAI3Agent").Find("Agent").gameObject; + ; + _agentCollider = _agent.GetComponent(); + _agentRigidbody = _agent.GetComponent(); + _spawnedObjectsHolder = spawnedObjectsHolder; + _maxSpawnAttemptsForPrefabs = maxSpawnAttemptsForPrefabs; + _maxSpawnAttemptsForAgent = maxSpawnAttemptsForAgent; + Spawnables = new List(); + _goodGoalsMultiSpawned = new List(); + } + + #endregion + + #region Arena Builder + + /// + /// Builds the arena by instantiating the Spawnable objects within the arena. + /// + public void Build() + { + _totalObjectsSpawned = 0; + + _goodGoalsMultiSpawned.Clear(); + + GameObject spawnedObjectsHolder = GameObject.Instantiate( + _spawnedObjectsHolder, + _arena.transform, + false + ); + spawnedObjectsHolder.transform.parent = _arena; + + InstantiateSpawnables(spawnedObjectsHolder); + + TrainingAgent agentInstance = UnityEngine.Object.FindObjectOfType(); + if (agentInstance != null && _arena != null) + { + TrainingArena trainingArena = _arena.GetComponent(); + if (trainingArena != null) + { + agentInstance.showNotification = ArenasConfigurations.Instance.showNotification; + } + } + + updateGoodGoalsMulti(); + } + + #endregion + + #region Instantiate and Spawn Objects Methods + + /// + /// Instantiates the Spawnable objects within the arena. + /// + private void InstantiateSpawnables(GameObject spawnedObjectsHolder) + { + Debug.Log("Spawnables has " + Spawnables.Capacity + " entries"); + List agentSpawnablesFromUser = Spawnables + .Where(x => x.gameObject != null && x.gameObject.CompareTag("agent")) + .ToList(); + + // Instantiate the agent first based on its characteristics, then prevent item spawning at the same location; + // ... otherwise, spawn it last to enable more object spawns. + if (agentSpawnablesFromUser.Any()) + { + _agentCollider.enabled = false; + SpawnAgent(agentSpawnablesFromUser[0]); + _agentCollider.enabled = true; + SpawnObjects(spawnedObjectsHolder); + } + else + { + _agentCollider.enabled = false; + SpawnObjects(spawnedObjectsHolder); + SpawnAgent(null); + _agentCollider.enabled = true; + } + } + + /// + /// Spawns the objects within the arena. + /// + private void SpawnObjects(GameObject spawnedObjectsHolder) + { + foreach (Spawnable spawnable in Spawnables) + { + if (spawnable.gameObject != null) + { + if (!spawnable.gameObject.CompareTag("agent")) + { + InstantiateSpawnable(spawnable, spawnedObjectsHolder); + } + } + } + } + + /// + /// InstantiateSpawnable spawns game objects in a game environment. + /// It takes two parameters: a Spawnable object and a GameObject that serves as a holder for the spawned objects. + /// The method instantiates the game object, sets its layer, position, rotation, and scale, and then spawns the game object. + /// The method also sets the color of the game object and assigns a symbol name to the game object's SignBoard component. + /// + private void InstantiateSpawnable(Spawnable spawnable, GameObject spawnedObjectsHolder) + { + // Required parameters + List positions = spawnable.positions; + List rotations = spawnable.rotations; + List sizes = spawnable.sizes; + List colors = spawnable.colors; + + // Optional parameters + List symbolNames = spawnable.symbolNames; + List delays = spawnable.delays; + List initialValues = spawnable.initialValues; + List finalValues = spawnable.finalValues; + List changeRates = spawnable.changeRates; + List spawnCounts = spawnable.spawnCounts; + List spawnColors = spawnable.spawnColors; + List timesBetweenSpawns = spawnable.timesBetweenSpawns; + List ripenTimes = spawnable.ripenTimes; + List doorDelays = spawnable.doorDelays; + List timesBetweenDoorOpens = spawnable.timesBetweenDoorOpens; + List moveDurations = spawnable.moveDurations; + List resetDurations = spawnable.resetDurations; + List triggerDataZoneIDs = spawnable.triggerZoneIDs; + + // Get the number of elements in the lists + int numberOfPositions = positions.Count; + int numberOfRotations = rotations.Count; + int numberOfSizes = sizes.Count; + int numberOfColors = colors.Count; + int numberOfSymbolNames = optionalCount(symbolNames); + int numberOfDelays = optionalCount(delays); + int numberOfInitialValues = optionalCount(initialValues); + int numberOfFinalValues = optionalCount(finalValues); + int numberOfChangeRates = optionalCount(changeRates); + int numberOfSpawnCounts = optionalCount(spawnCounts); + int numberOfSpawnColors = optionalCount(spawnColors); + int numberOfTimesBetweenSpawns = optionalCount(timesBetweenSpawns); + int numberOfRipenTimes = optionalCount(ripenTimes); + int numberOfDoorDelays = optionalCount(doorDelays); + int numberOfTimesBetweenDoorOpens = optionalCount(timesBetweenDoorOpens); + int numberOfMoveDurations = optionalCount(moveDurations); + int numberOfResetDurations = optionalCount(resetDurations); + + // Get the number of elements in the lists + int[] ns = new int[] + { + numberOfPositions, + numberOfRotations, + numberOfSizes, + numberOfColors, + numberOfSymbolNames, + numberOfDelays, + numberOfInitialValues, + numberOfFinalValues, + numberOfChangeRates, + numberOfSpawnCounts, + numberOfSpawnColors, + numberOfTimesBetweenSpawns, + numberOfRipenTimes, + numberOfDoorDelays, + numberOfTimesBetweenDoorOpens, + numberOfMoveDurations, + numberOfResetDurations + }; + // Get the maximum number of elements in the lists + int n = ns.Max(); + + // Spawn the objects + int k = 0; + do + { + GameObject gameObjectInstance = GameObject.Instantiate( + spawnable.gameObject, + spawnedObjectsHolder.transform, + false + ); + gameObjectInstance.SetLayer(1); + Vector3 position = k < ns[0] ? positions[k] : -Vector3.one; + float rotation = k < ns[1] ? rotations[k] : -1; + Vector3 size = k < ns[2] ? sizes[k] : -Vector3.one; + Vector3 color = k < ns[3] ? colors[k] : -Vector3.one; + + // For optional parameters, use default values if not provided + string symbolName = k < ns[4] ? symbolNames[k] : null; + float delay = k < ns[5] ? delays[k] : 0; + bool tree = (spawnable.name.Contains("Tree")); + bool ripen_or_grow = ( + spawnable.name.StartsWith("Anti") || spawnable.name.StartsWith("Grow") || tree + ); + float initialValue = + k < ns[6] ? initialValues[k] : (tree ? 0.2f : (ripen_or_grow ? 0.5f : 2.5f)); + float finalValue = + k < ns[7] ? finalValues[k] : (tree ? 1f : (ripen_or_grow ? 2.5f : 0.5f)); + float changeRate = k < ns[8] ? changeRates[k] : -0.005f; + int spawnCount = k < ns[9] ? spawnCounts[k] : -1; + Vector3 spawnColor = k < ns[10] ? spawnColors[k] : -Vector3.one; + float timeBetweenSpawns = k < ns[11] ? timesBetweenSpawns[k] : (tree ? 4f : 1.5f); + float ripenTime = k < ns[12] ? ripenTimes[k] : 6f; + float doorDelay = k < ns[13] ? doorDelays[k] : 10f; + float timeBetweenDoorOpens = k < ns[14] ? timesBetweenDoorOpens[k] : -1f; + float moveDuration = k < ns[15] ? moveDurations[k] : 1.0f; + float resetDuration = k < ns[16] ? resetDurations[k] : 1.0f; + float spawnProbability = spawnable.SpawnProbability; + Vector3 rewardSpawnPos = spawnable.rewardSpawnPos; + + // Assign the optional parameters to a dictionary + Dictionary optionals = new Dictionary() + { + { nameof(symbolName), symbolName }, + { nameof(delay), delay }, + { nameof(initialValue), initialValue }, + { nameof(finalValue), finalValue }, + { nameof(changeRate), changeRate }, + { nameof(spawnCount), spawnCount }, + { nameof(spawnColor), spawnColor }, + { nameof(timeBetweenSpawns), timeBetweenSpawns }, + { nameof(ripenTime), ripenTime }, + { nameof(doorDelay), doorDelay }, + { nameof(timeBetweenDoorOpens), timeBetweenDoorOpens }, + { nameof(moveDuration), moveDuration }, + { nameof(resetDuration), resetDuration }, + { nameof(spawnProbability), spawnProbability }, + { "rewardNames", spawnable.RewardNames }, + { "rewardWeights", spawnable.RewardWeights }, + { "rewardSpawnPos", rewardSpawnPos }, + { "maxRewardCounts", spawnable.maxRewardCounts }, + { "triggerZoneIDs", spawnable.triggerZoneIDs } + }; + + // Determines a suitable position and rotation for the object to spawn + PositionRotation spawnPosRot = SamplePositionRotation( + gameObjectInstance, + _maxSpawnAttemptsForPrefabs, + position, + rotation, + size + ); + + SpawnGameObject(spawnable, gameObjectInstance, spawnPosRot, color, optionals); + _totalObjectsSpawned++; + k++; + } while (k < n); + } + + /// + /// The SpawnGameObject function instantiates a game object with specified properties, sets its position, rotation, and color, assigns it a symbol name if provided, + /// ...adjusts properties of its Spawner_InteractiveButton and GoalSpawner components based on optional parameters, and assigns timing parameters to relevant components. + /// + private void SpawnGameObject( + Spawnable spawnable, + GameObject gameObjectInstance, + PositionRotation spawnLocRot, + Vector3 color, + Dictionary optionals = null + ) + { + if (spawnLocRot != null) + { + gameObjectInstance.transform.localPosition = spawnLocRot.Position; + gameObjectInstance.transform.Rotate(spawnLocRot.Rotation); + gameObjectInstance.SetLayer(0); + gameObjectInstance.GetComponent().SetColor(color); + + if ( + gameObjectInstance.CompareTag("goodGoalMulti") + || gameObjectInstance.CompareTag("goodGoal") + ) + { + _goodGoalsMultiSpawned.Add(gameObjectInstance.GetComponent()); + } + if (optionals != null) + { + if ( + optionals.TryGetValue("symbolName", out var symbolNameValue) + && symbolNameValue is string symbolName + ) + { + AssignSymbolName(gameObjectInstance, symbolName, color); + } + + var spawnerInteractiveButton = + gameObjectInstance.GetComponentInChildren(); + if (spawnerInteractiveButton != null) + { + if ( + optionals.TryGetValue("moveDuration", out var moveDurationValue) + && moveDurationValue is float moveDuration + ) + { + spawnerInteractiveButton.MoveDuration = moveDuration; + } + if ( + optionals.TryGetValue("resetDuration", out var resetDurationValue) + && resetDurationValue is float resetDuration + ) + { + spawnerInteractiveButton.ResetDuration = resetDuration; + } + if ( + optionals.TryGetValue("spawnProbability", out var spawnProbabilityValue) + && spawnProbabilityValue is float spawnProbability + ) + { + spawnerInteractiveButton.SpawnProbability = spawnProbability; + } + if ( + optionals.TryGetValue("rewardNames", out var rewardNamesValue) + && rewardNamesValue is List rewardNames + ) + { + spawnerInteractiveButton.RewardNames = rewardNames; + } + if ( + optionals.TryGetValue("rewardWeights", out var rewardWeightsValue) + && rewardWeightsValue is List rewardWeights + ) + { + spawnerInteractiveButton.RewardWeights = rewardWeights; + } + if ( + optionals.TryGetValue("rewardSpawnPos", out var rewardSpawnPosValue) + && rewardSpawnPosValue is Vector3 rewardSpawnPos + ) + { + spawnerInteractiveButton.RewardSpawnPos = rewardSpawnPos; + } + if ( + optionals.TryGetValue("maxRewardCounts", out var maxRewardCountsValue) + && maxRewardCountsValue is List maxRewardCounts + ) + { + spawnerInteractiveButton.MaxRewardCounts = maxRewardCounts; + } + } + + // Check for optional spawnColor for Spawner objects + if ( + optionals.TryGetValue("spawnColor", out var spawnColorValue) + && spawnColorValue != null + && gameObjectInstance.TryGetComponent(out GoalSpawner GS) + ) + { + GS.SetSpawnColor((Vector3)spawnColorValue); + } + + // Now check all floats relating to timing of changes + // Each float param has a list of "acceptable types" to which it applies + Dictionary> paramValidTypeLookup = new Dictionary< + string, + List + > + { + { + "delay", + new List + { + typeof(DecayGoal), + typeof(SizeChangeGoal), + typeof(GoalSpawner) + } + }, + { + "initialValue", + new List + { + typeof(DecayGoal), + typeof(SizeChangeGoal), + typeof(GoalSpawner) + } + }, + { + "finalValue", + new List + { + typeof(DecayGoal), + typeof(SizeChangeGoal), + typeof(GoalSpawner) + } + }, + { + "changeRate", + new List { typeof(DecayGoal), typeof(SizeChangeGoal) } + }, + { + "spawnCount", + new List { typeof(GoalSpawner) } + }, + { + "timeBetweenSpawns", + new List { typeof(GoalSpawner) } + }, + { + "ripenTime", + new List { typeof(GoalSpawner) } + }, // TreeSpawners only! Ignored o/wise + { + "doorDelay", + new List { typeof(SpawnerStockpiler) } + }, // Dispensers/Containers only! + { + "timeBetweenDoorOpens", + new List { typeof(SpawnerStockpiler) } + }, // Dispensers/Containers only! + }; + float v; + foreach (string paramKey in paramValidTypeLookup.Keys) + { + // Try each valid type that we might be able to assign to + if (optionals[paramKey] != null) + { + foreach (Type U in paramValidTypeLookup[paramKey]) + { + // Check if gameObjectInstance has got the relevant component + if (gameObjectInstance.TryGetComponent(U, out var component)) + { + v = Convert.ToSingle(optionals[paramKey]); + AssignTimingNumber(paramKey, v, component); + } + } + } + } + if ( + gameObjectInstance.CompareTag("DataZone") + && optionals.TryGetValue("triggerZoneIDs", out var triggerZoneIDsValue) + && triggerZoneIDsValue is List triggerZoneIDs + ) + { + DataZone dataZone = gameObjectInstance.GetComponent(); + if (dataZone != null && triggerZoneIDs.Count > 0) + { + dataZone.TriggerZoneID = triggerZoneIDs[0]; + } + } + } + else + { + gameObjectInstance.SetActive(false); + GameObject.Destroy(gameObjectInstance); + } + } + } + + #endregion + + #region Spawn Agent + + /// + /// The SpawnAgent function spawns an agent in a game environment. + /// It takes a Spawnable object as a parameter and spawns the agent at a specified position and rotation. + /// The function also sets the agent's skin and freeze delay. + /// + private void SpawnAgent(Spawnable agentSpawnableFromUser) + { + PositionRotation agentToSpawnPosRot; + Vector3 agentSize = _agent.transform.localScale; + Vector3 position; + float rotation; + string skin; + float freezeDelay; + + position = + (agentSpawnableFromUser == null || !agentSpawnableFromUser.positions.Any()) + ? -Vector3.one + : agentSpawnableFromUser.positions[0]; + rotation = + (agentSpawnableFromUser == null || !agentSpawnableFromUser.rotations.Any()) + ? -1 + : agentSpawnableFromUser.rotations[0]; + + // Extra check for skins because optional param is not always initialised as a List in Spawnable class + if (agentSpawnableFromUser != null && agentSpawnableFromUser.skins == null) + { + agentSpawnableFromUser.skins = new List(); + } + skin = + (agentSpawnableFromUser == null || !agentSpawnableFromUser.skins.Any()) + ? "random" + : agentSpawnableFromUser.skins[0]; + + // Extra check for freeze delay for same reason as above w/skins + if (agentSpawnableFromUser != null && agentSpawnableFromUser.frozenAgentDelays == null) + { + agentSpawnableFromUser.frozenAgentDelays = new List(); + } + freezeDelay = + (agentSpawnableFromUser == null || !agentSpawnableFromUser.frozenAgentDelays.Any()) + ? 0 + : agentSpawnableFromUser.frozenAgentDelays[0]; + + agentToSpawnPosRot = SamplePositionRotation( + _agent, + _maxSpawnAttemptsForAgent, + position, + rotation, + agentSize + ); + + _agentRigidbody.angularVelocity = Vector3.zero; + _agentRigidbody.velocity = Vector3.zero; + _agent.transform.localPosition = agentToSpawnPosRot.Position; + _agent.transform.rotation = Quaternion.Euler(agentToSpawnPosRot.Rotation); + + AnimalSkinManager ASM = _agent.GetComponentInChildren(); + Debug.Log("Setting AnimalSkin with ASM: " + ASM.ToString() + " and skin: " + skin); + ASM.SetAnimalSkin(skin); + _agent.GetComponent().SetFreezeDelay(freezeDelay); + } + + #endregion + + #region Check Position/Rotation and Object Placement Methods + + /// + /// The SamplePositionRotation function samples a position and rotation for a game object to spawn. + /// It takes five parameters: a game object instance, the maximum number of spawn attempts, a position, a rotation, and a size. + /// The function returns a PositionRotation object that contains the position and rotation of the game object to spawn. + /// + private PositionRotation SamplePositionRotation( + GameObject gameObjectInstance, + int maxSpawnAttempt, + Vector3 positionIn, + float rotationY, + Vector3 size + ) + { + Vector3 gameObjectBoundingBox; + Vector3 rotationOut = Vector3.zero; + Vector3 positionOut = Vector3.zero; + IPrefab gameObjectInstanceIPrefab = gameObjectInstance.GetComponent(); + bool canSpawn = false; + int k = 0; + + while (!canSpawn && k < maxSpawnAttempt) + { + gameObjectInstanceIPrefab.SetSize(size); + gameObjectBoundingBox = gameObjectInstance.GetBoundsWithChildren().extents; + + positionOut = gameObjectInstanceIPrefab.GetPosition( + positionIn, + gameObjectBoundingBox, + _rangeX, + _rangeZ + ); + rotationOut = gameObjectInstanceIPrefab.GetRotation(rotationY); + + Collider[] colliders = Physics.OverlapBox( + positionOut + _arena.position, + gameObjectBoundingBox, + Quaternion.Euler(rotationOut), + 1 << 0 + ); + canSpawn = IsSpotFree( + colliders, + gameObjectInstance.CompareTag("agent"), + gameObjectInstance.name.Contains("Zone") + ); + k++; + } + if (canSpawn) + { + return new PositionRotation(positionOut, rotationOut); + } + return null; + } + + /// + /// The IsSpotFree function checks if a spot is free for a game object to spawn. + /// It takes three parameters: an array of colliders, a boolean value indicating if the object is an agent, and a boolean value indicating if the object is a zone. + /// The function returns true if the spot is free; otherwise, it returns false. + /// + private bool IsSpotFree(Collider[] colliders, bool isAgent, bool isZone = false) + { + if (isZone) + return colliders.Length == 0 + || ( + colliders.All( + collider => + collider.isTrigger || !collider.gameObject.CompareTag("arena") + ) && !isAgent + ); + else + return colliders.Length == 0 + || (colliders.All(collider => collider.isTrigger) && !isAgent); + } + + /// + /// The ObjectOutsideOfBounds function checks if a game object is outside of the arena bounds (walls). + /// It takes two parameters: a position and a bounding box. + /// The function returns true if the object is outside of the bounds; otherwise, it returns false. + /// + private bool ObjectOutsideOfBounds(Vector3 position, Vector3 boundingBox) + { + return position.x > boundingBox.x + && position.x < _rangeX - boundingBox.x + && position.z > boundingBox.z + && position.z < _rangeZ - boundingBox.z; + } + + #endregion + + #region Goal Spawner-Logic Methods + + /// + /// Updates the number of goals in the goodGoalsMultiSpawned list. + /// + private void updateGoodGoalsMulti() + { + int numberOfGoals = _goodGoalsMultiSpawned.Count; + foreach (Goal goodGoalMulti in _goodGoalsMultiSpawned) + { + goodGoalMulti.numberOfGoals = numberOfGoals; + } + } + + /// + /// Adds a goal to the goodGoalsMultiSpawned list. + /// + public void AddToGoodGoalsMultiSpawned(Goal ggm) + { + _goodGoalsMultiSpawned.Add(ggm); + updateGoodGoalsMulti(); + } + + /// + /// Adds a goal to the goodGoalsMultiSpawned list as a GameObject. + /// + public void AddToGoodGoalsMultiSpawned(GameObject ggm) + { + _goodGoalsMultiSpawned.Add(ggm.GetComponent()); + updateGoodGoalsMulti(); + } + + #endregion + + #region Other Methods + + /// + /// Returns the number of elements in a list if not null; otherwise, returns 0. + /// + private int optionalCount(List paramList) + { + return (paramList != null) ? paramList.Count : 0; + } + + /// + /// Returns the total number of objects spawned. + /// + public int GetTotalObjectsSpawned() + { + return _totalObjectsSpawned; + } + + /// + /// Assigns a symbol name to a component's SignBoard. + /// + private void AssignSymbolName(GameObject gameObjectInstance, string sName, Vector3 color) + { + SignBoard SP = gameObjectInstance.GetComponent(); + if (SP != null) + { + if (color != new Vector3(-1, -1, -1)) + { + SP.SetColourOverride(color, true); + } + + SP.SetSymbol(sName, true); + Debug.Log("Assigned symbol name: " + sName + " to " + gameObjectInstance.name); + } + else + { + Debug.Log("No SignBoard component found on " + gameObjectInstance.name); + } + } + + /// + /// Assigns a float value to a component's timing parameter. + /// + private void AssignTimingNumber(string paramName, float value, T component) + { + paramName = paramName[0].ToString().ToUpper() + paramName.Substring(1); + MethodInfo SetMethod = component.GetType().GetMethod("Set" + (paramName)); + + if (SetMethod != null) + { + SetMethod.Invoke(component, new object[] { value }); + } + } + + #endregion + } } diff --git a/Assets/Scripts/ArenasParameters.cs b/Assets/Scripts/ArenasParameters.cs index b59b3e04..a0a313ce 100644 --- a/Assets/Scripts/ArenasParameters.cs +++ b/Assets/Scripts/ArenasParameters.cs @@ -11,332 +11,338 @@ /// namespace ArenasParameters { - /// - /// The ListOfPrefabs class is a simple data container that holds a list of GameObject instances and provides a method to access that list. - /// - [System.Serializable] - public class ListOfPrefabs - { - public List allPrefabs; - public List GetList() - { - return allPrefabs; - } - } - - /// - /// The list of prefabs that can be passed as items to spawn in the various arenas. - /// - public class Spawnable - { - public string name = ""; - public GameObject gameObject = null; - public List positions = null; - public List rotations = null; - public List sizes = null; - public List colors = null; - - // ======== EXTRA/OPTIONAL PARAMETERS ======== - - // Spawners/Dispensers/Tree - public List skins = null; - public List symbolNames = null; - public List delays = null; - public List initialValues = null; - public List finalValues = null; - public List changeRates = null; - public List spawnCounts = null; - public List spawnColors = null; - public List timesBetweenSpawns = null; - public List ripenTimes = null; - public List doorDelays = null; - public List timesBetweenDoorOpens = null; - public List frozenAgentDelays = null; - - // SpawnerButton - public List moveDurations = null; - public List resetDurations = null; - public float SpawnProbability { get; private set; } - public List RewardNames { get; private set; } - public List RewardWeights { get; private set; } - public Vector3 rewardSpawnPos { get; private set; } - public List maxRewardCounts { get; private set; } - public Dictionary originalToNewIDMapping = new Dictionary(); - - /// - /// The purpose of this constructor is to initialize the Spawnable object with the properties of the provided GameObject. - /// The name property of the Spawnable object is set to the name of the GameObject, and the gameObject property of the Spawnable object is set to the GameObject itself. - /// - public Spawnable(GameObject obj) - { - name = obj.name; - gameObject = obj; - positions = new List(); - rotations = new List(); - sizes = new List(); - colors = new List(); - } - - /// - /// The purpose of this constructor is to initialize the properties of the Spawnable class with the values from the yamlItem object. - /// - internal Spawnable(YAMLDefs.Item yamlItem) - { - name = yamlItem.name; - positions = yamlItem.positions; - rotations = yamlItem.rotations; - sizes = yamlItem.sizes; - colors = initVec3sFromRGBs(yamlItem.colors); - name = AliasMapper.ResolveAlias(yamlItem.name); - - // ======== EXTRA/OPTIONAL PARAMETERS ======== - - skins = yamlItem.skins; - frozenAgentDelays = yamlItem.frozenAgentDelays; - - delays = yamlItem.delays; - initialValues = yamlItem.initialValues; - finalValues = yamlItem.finalValues; - changeRates = yamlItem.changeRates; - spawnCounts = yamlItem.spawnCounts; - spawnColors = initVec3sFromRGBs(yamlItem.spawnColors); - timesBetweenSpawns = yamlItem.timesBetweenSpawns; - ripenTimes = yamlItem.ripenTimes; - doorDelays = yamlItem.doorDelays; - timesBetweenDoorOpens = yamlItem.timesBetweenDoorOpens; - - symbolNames = yamlItem.symbolNames; - - moveDurations = yamlItem.moveDurations; - resetDurations = yamlItem.resetDurations; - SpawnProbability = yamlItem.spawnProbability; - RewardNames = yamlItem.rewardNames; - RewardWeights = yamlItem.rewardWeights; - rewardSpawnPos = yamlItem.rewardSpawnPos; - maxRewardCounts = yamlItem.maxRewardCounts; - } - - /// - /// The purpose of this method is to initialize a list of Vector3 objects from a list of RGB objects. - /// - internal List initVec3sFromRGBs(List yamlList) - { - List cList = new List(); - foreach (YAMLDefs.RGB c in yamlList) - { - cList.Add(new Vector3(c.r, c.g, c.b)); - } - return cList; - } - } - - /// - /// The ArenaConfiguration class is used to define the configuration of an arena, such as the time limit, the spawnables, and the lights switch. - /// - public class ArenaConfiguration - { - public int TimeLimit = 0; - public List spawnables = new List(); - public LightsSwitch lightsSwitch = new LightsSwitch(); - public bool toUpdate = false; - public string protoString = ""; - public int randomSeed = 0; - public bool mergeNextArena = false; - - public ArenaConfiguration() { } - - /// - /// The purpose of this constructor is to initialize the properties of the ArenaConfiguration class with the values from the yamlArena object. - /// - public ArenaConfiguration(ListOfPrefabs listPrefabs) - { - foreach (GameObject prefab in listPrefabs.allPrefabs) - { - spawnables.Add(new Spawnable(prefab)); - } - TimeLimit = 0; - toUpdate = true; - } - - /// - /// The internal constructor initializes several properties of the ArenaConfiguration object. - /// - internal ArenaConfiguration(YAMLDefs.Arena yamlArena) - { - TimeLimit = yamlArena.timeLimit; - spawnables = new List(); - - foreach (YAMLDefs.Item item in yamlArena.items) - { - spawnables.Add(new Spawnable(item)); - } - - List blackouts = yamlArena.blackouts; - lightsSwitch = new LightsSwitch(TimeLimit, blackouts); - toUpdate = true; - protoString = yamlArena.ToString(); - randomSeed = yamlArena.randomSeed; - this.mergeNextArena = yamlArena.mergeNextArena; - } - - /// - /// The purpose of this method is to associate the GameObject instances with the Spawnable objects. - /// - public void SetGameObject(List listObj) - { - foreach (Spawnable spawn in spawnables) - { - spawn.gameObject = listObj.Find(x => x.name == spawn.name); - } - } - } - - /// - /// ArenaConfigurations is a dictionary of configurations for each arena. - /// - public class ArenasConfigurations - { - public Dictionary configurations; - public int seed; - public static ArenasConfigurations Instance { get; private set; } - public bool randomizeArenas = false; - public bool showNotification { get; set; } = false; - public bool canResetEpisode { get; set; } = true; - public bool canChangePerspective { get; set; } = true; - public int CurrentArenaID { get; set; } = 0; - - /// - /// The purpose of this constructor is to initialize the configurations dictionary. - /// - public ArenasConfigurations() - { - if (Instance != null) - { - throw new Exception("Multiple instances of ArenasConfigurations!"); - } - Instance = this; - - configurations = new Dictionary(); - } - - /// - /// This method is used to get the current arena configuration. - /// - public ArenaConfiguration CurrentArenaConfiguration - { - get - { - return configurations.ContainsKey(CurrentArenaID) - ? configurations[CurrentArenaID] - : null; - } - } - - /// - /// This method is used to add a new arena configuration to the configurations dictionary. - /// - internal void Add(int k, YAMLDefs.Arena yamlConfig) - { - if (!configurations.ContainsKey(k)) - { - configurations.Add(k, new ArenaConfiguration(yamlConfig)); - } - else - { - if (yamlConfig.ToString() != configurations[k].protoString) - { - configurations[k] = new ArenaConfiguration(yamlConfig); - } - } - CurrentArenaID = k; - yamlConfig.SetCurrentPassMark(); - } - - /// - /// This method is used to add additional arenas to the configurations dictionary. - /// - public void AddAdditionalArenas(YAMLDefs.ArenaConfig yamlArenaConfig) - { - foreach (YAMLDefs.Arena arena in yamlArenaConfig.arenas.Values) - { - int i = configurations.Count; - Add(i, arena); - arena.SetCurrentPassMark(); - } - } - - /// - /// This method is used to update the current configurations with the new ones provided in the yamlArenaConfig object. - /// Furthermore, it sets the randomizeArenas, showNotification, canResetEpisode, and canChangePerspective properties of the ArenasConfigurations object. - /// Lastly, it ensures the arena IDs are unique and positive; assigns new IDs if required. - /// - public void UpdateWithYAML(YAMLDefs.ArenaConfig yamlArenaConfig) - { - configurations.Clear(); - List existingIds = new List(); - int nextAvailableId = 0; - - // Iterating over arenas in the order they appear in the YAML, top to bottom. - foreach (KeyValuePair arenaConfiguration in yamlArenaConfig.arenas) - { - int currentID = arenaConfiguration.Key; - - if (existingIds.Contains(currentID) || currentID < 0) - { - Debug.LogWarning( - $"Issue with arenaID: {currentID}. Assigning a new unique ID: {nextAvailableId}." - ); - - // Assign a new unique ID if required. - Add(nextAvailableId, arenaConfiguration.Value); - existingIds.Add(nextAvailableId); - } - else - { - Add(currentID, arenaConfiguration.Value); - existingIds.Add(currentID); - } - - // Adjust the nextAvailableId for future entries. - nextAvailableId = existingIds.Max() + 1; - } - - randomizeArenas = yamlArenaConfig.randomizeArenas; - showNotification = yamlArenaConfig.showNotification; - canResetEpisode = yamlArenaConfig.canResetEpisode; - canChangePerspective = yamlArenaConfig.canChangePerspective; - } - - /// - /// This method handles an event that is triggered when new arena configurations are received. - /// It extracts the YAML data from the event, converts it into an ArenaConfig object, and then updates the current configurations with the new ones. - /// - public void UpdateWithConfigurationsReceived( - object sender, - ArenasParametersEventArgs arenasParametersEvent - ) - { - byte[] arenas = arenasParametersEvent.arenas_yaml; - var YAMLReader = new YAMLDefs.YAMLReader(); - string utfString = Encoding.UTF8.GetString(arenas, 0, arenas.Length); - var parsed = YAMLReader.deserializer.Deserialize(utfString); - UpdateWithYAML(parsed); - } - - /// - /// The purpose of this method is to iterate over each entry in the configurations dictionary and set the toUpdate property of each ArenaConfiguration object to false. - /// - public void SetAllToUpdated() - { - foreach (KeyValuePair configuration in configurations) - { - configuration.Value.toUpdate = false; - } - } - - public void ClearConfigurations() - { - configurations.Clear(); - } - } + /// + /// The ListOfPrefabs class is a simple data container that holds a list of GameObject instances and provides a method to access that list. + /// + [System.Serializable] + public class ListOfPrefabs + { + public List allPrefabs; + + public List GetList() + { + return allPrefabs; + } + } + + /// + /// The list of prefabs that can be passed as items to spawn in the various arenas. + /// + public class Spawnable + { + public string name = ""; + public GameObject gameObject = null; + public List positions = null; + public List rotations = null; + public List sizes = null; + public List colors = null; + + // ======== EXTRA/OPTIONAL PARAMETERS ======== + + // Spawners/Dispensers/Tree + public List skins = null; + public List symbolNames = null; + public List delays = null; + public List initialValues = null; + public List finalValues = null; + public List changeRates = null; + public List spawnCounts = null; + public List spawnColors = null; + public List timesBetweenSpawns = null; + public List ripenTimes = null; + public List doorDelays = null; + public List timesBetweenDoorOpens = null; + public List frozenAgentDelays = null; + + // SpawnerButton + public List moveDurations = null; + public List resetDurations = null; + public float SpawnProbability { get; private set; } + public List RewardNames { get; private set; } + public List RewardWeights { get; private set; } + public Vector3 rewardSpawnPos { get; private set; } + public List maxRewardCounts { get; private set; } + public Dictionary originalToNewIDMapping = new Dictionary(); + + // Trigger/DataZone + public List triggerZoneIDs = null; + + /// + /// The purpose of this constructor is to initialize the Spawnable object with the properties of the provided GameObject. + /// The name property of the Spawnable object is set to the name of the GameObject, and the gameObject property of the Spawnable object is set to the GameObject itself. + /// + public Spawnable(GameObject obj) + { + name = obj.name; + gameObject = obj; + positions = new List(); + rotations = new List(); + sizes = new List(); + colors = new List(); + } + + /// + /// The purpose of this constructor is to initialize the properties of the Spawnable class with the values from the yamlItem object. + /// + internal Spawnable(YAMLDefs.Item yamlItem) + { + name = yamlItem.name; + positions = yamlItem.positions; + rotations = yamlItem.rotations; + sizes = yamlItem.sizes; + colors = initVec3sFromRGBs(yamlItem.colors); + name = AliasMapper.ResolveAlias(yamlItem.name); + + // ======== EXTRA/OPTIONAL PARAMETERS ======== + + skins = yamlItem.skins; + frozenAgentDelays = yamlItem.frozenAgentDelays; + + delays = yamlItem.delays; + initialValues = yamlItem.initialValues; + finalValues = yamlItem.finalValues; + changeRates = yamlItem.changeRates; + spawnCounts = yamlItem.spawnCounts; + spawnColors = initVec3sFromRGBs(yamlItem.spawnColors); + timesBetweenSpawns = yamlItem.timesBetweenSpawns; + ripenTimes = yamlItem.ripenTimes; + doorDelays = yamlItem.doorDelays; + timesBetweenDoorOpens = yamlItem.timesBetweenDoorOpens; + + symbolNames = yamlItem.symbolNames; + + moveDurations = yamlItem.moveDurations; + resetDurations = yamlItem.resetDurations; + SpawnProbability = yamlItem.spawnProbability; + RewardNames = yamlItem.rewardNames; + RewardWeights = yamlItem.rewardWeights; + rewardSpawnPos = yamlItem.rewardSpawnPos; + maxRewardCounts = yamlItem.maxRewardCounts; + + triggerZoneIDs = yamlItem.triggerZoneIDs; + } + + /// + /// The purpose of this method is to initialize a list of Vector3 objects from a list of RGB objects. + /// + internal List initVec3sFromRGBs(List yamlList) + { + List cList = new List(); + foreach (YAMLDefs.RGB c in yamlList) + { + cList.Add(new Vector3(c.r, c.g, c.b)); + } + return cList; + } + } + + /// + /// The ArenaConfiguration class is used to define the configuration of an arena, such as the time limit, the spawnables, and the lights switch. + /// + public class ArenaConfiguration + { + public int TimeLimit = 0; + public List spawnables = new List(); + public LightsSwitch lightsSwitch = new LightsSwitch(); + public bool toUpdate = false; + public string protoString = ""; + public int randomSeed = 0; + public bool mergeNextArena = false; + + public ArenaConfiguration() { } + + /// + /// The purpose of this constructor is to initialize the properties of the ArenaConfiguration class with the values from the yamlArena object. + /// + public ArenaConfiguration(ListOfPrefabs listPrefabs) + { + foreach (GameObject prefab in listPrefabs.allPrefabs) + { + spawnables.Add(new Spawnable(prefab)); + } + TimeLimit = 0; + toUpdate = true; + } + + /// + /// The internal constructor initializes several properties of the ArenaConfiguration object. + /// + internal ArenaConfiguration(YAMLDefs.Arena yamlArena) + { + TimeLimit = yamlArena.timeLimit; + spawnables = new List(); + + foreach (YAMLDefs.Item item in yamlArena.items) + { + spawnables.Add(new Spawnable(item)); + } + + List blackouts = yamlArena.blackouts; + lightsSwitch = new LightsSwitch(TimeLimit, blackouts); + toUpdate = true; + protoString = yamlArena.ToString(); + randomSeed = yamlArena.randomSeed; + this.mergeNextArena = yamlArena.mergeNextArena; + } + + /// + /// The purpose of this method is to associate the GameObject instances with the Spawnable objects. + /// + public void SetGameObject(List listObj) + { + foreach (Spawnable spawn in spawnables) + { + spawn.gameObject = listObj.Find(x => x.name == spawn.name); + } + } + } + + /// + /// ArenaConfigurations is a dictionary of configurations for each arena. + /// + public class ArenasConfigurations + { + public Dictionary configurations; + public int seed; + public static ArenasConfigurations Instance { get; private set; } + public bool randomizeArenas = false; + public bool showNotification { get; set; } = false; + public bool canResetEpisode { get; set; } = true; + public bool canChangePerspective { get; set; } = true; + public int CurrentArenaID { get; set; } = 0; + + /// + /// The purpose of this constructor is to initialize the configurations dictionary. + /// + public ArenasConfigurations() + { + if (Instance != null) + { + throw new Exception("Multiple instances of ArenasConfigurations!"); + } + Instance = this; + + configurations = new Dictionary(); + } + + /// + /// This method is used to get the current arena configuration. + /// + public ArenaConfiguration CurrentArenaConfiguration + { + get + { + return configurations.ContainsKey(CurrentArenaID) + ? configurations[CurrentArenaID] + : null; + } + } + + /// + /// This method is used to add a new arena configuration to the configurations dictionary. + /// + internal void Add(int k, YAMLDefs.Arena yamlConfig) + { + if (!configurations.ContainsKey(k)) + { + configurations.Add(k, new ArenaConfiguration(yamlConfig)); + } + else + { + if (yamlConfig.ToString() != configurations[k].protoString) + { + configurations[k] = new ArenaConfiguration(yamlConfig); + } + } + CurrentArenaID = k; + yamlConfig.SetCurrentPassMark(); + } + + /// + /// This method is used to add additional arenas to the configurations dictionary. + /// + public void AddAdditionalArenas(YAMLDefs.ArenaConfig yamlArenaConfig) + { + foreach (YAMLDefs.Arena arena in yamlArenaConfig.arenas.Values) + { + int i = configurations.Count; + Add(i, arena); + arena.SetCurrentPassMark(); + } + } + + /// + /// This method is used to update the current configurations with the new ones provided in the yamlArenaConfig object. + /// Furthermore, it sets the randomizeArenas, showNotification, canResetEpisode, and canChangePerspective properties of the ArenasConfigurations object. + /// Lastly, it ensures the arena IDs are unique and positive; assigns new IDs if required. + /// + public void UpdateWithYAML(YAMLDefs.ArenaConfig yamlArenaConfig) + { + configurations.Clear(); + List existingIds = new List(); + int nextAvailableId = 0; + + // Iterating over arenas in the order they appear in the YAML, top to bottom. + foreach (KeyValuePair arenaConfiguration in yamlArenaConfig.arenas) + { + int currentID = arenaConfiguration.Key; + + if (existingIds.Contains(currentID) || currentID < 0) + { + Debug.LogWarning( + $"Issue with arenaID: {currentID}. Assigning a new unique ID: {nextAvailableId}." + ); + + // Assign a new unique ID if required. + Add(nextAvailableId, arenaConfiguration.Value); + existingIds.Add(nextAvailableId); + } + else + { + Add(currentID, arenaConfiguration.Value); + existingIds.Add(currentID); + } + + // Adjust the nextAvailableId for future entries. + nextAvailableId = existingIds.Max() + 1; + } + + randomizeArenas = yamlArenaConfig.randomizeArenas; + showNotification = yamlArenaConfig.showNotification; + canResetEpisode = yamlArenaConfig.canResetEpisode; + canChangePerspective = yamlArenaConfig.canChangePerspective; + } + + /// + /// This method handles an event that is triggered when new arena configurations are received. + /// It extracts the YAML data from the event, converts it into an ArenaConfig object, and then updates the current configurations with the new ones. + /// + public void UpdateWithConfigurationsReceived( + object sender, + ArenasParametersEventArgs arenasParametersEvent + ) + { + byte[] arenas = arenasParametersEvent.arenas_yaml; + var YAMLReader = new YAMLDefs.YAMLReader(); + string utfString = Encoding.UTF8.GetString(arenas, 0, arenas.Length); + var parsed = YAMLReader.deserializer.Deserialize(utfString); + UpdateWithYAML(parsed); + } + + /// + /// The purpose of this method is to iterate over each entry in the configurations dictionary and set the toUpdate property of each ArenaConfiguration object to false. + /// + public void SetAllToUpdated() + { + foreach (KeyValuePair configuration in configurations) + { + configuration.Value.toUpdate = false; + } + } + + public void ClearConfigurations() + { + configurations.Clear(); + } + } } diff --git a/Assets/Scripts/DataZone.cs b/Assets/Scripts/DataZone.cs index d10905fc..4bf43d61 100644 --- a/Assets/Scripts/DataZone.cs +++ b/Assets/Scripts/DataZone.cs @@ -1,20 +1,21 @@ using UnityEngine; /// -/// A zone that triggers an event when an agent enters it. It's primary use is to trigger data collection. +/// A zone that triggers an event when an agent enters it. It's primary use is to trigger a log event when an agent enters a trigger/data zone. /// public class DataZone : Prefab { - // TODO: Add logic to differentiate between different datazones - // TODO: Implement parameter to specify zone names/sections in yaml file (under the datazones Item) - public delegate void InDataZoneHandler(GameObject zone); + public delegate void InDataZoneHandler(string TriggerZoneID); public static event InDataZoneHandler OnInDataZone; + public string TriggerZoneID { get; set; } + private void OnCollisionEnter(Collision other) { if (other.gameObject.CompareTag("agent")) { - OnInDataZone?.Invoke(gameObject); + Debug.Log("Agent entered data zone: " + TriggerZoneID); + OnInDataZone?.Invoke(TriggerZoneID); } } } diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index a37d4147..a9164bf6 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -13,9 +13,6 @@ using System.Threading; // TODO: need to check/handle what happens if two dispensed rewards are collected in the same step -// TODO: raycast data is (Observation Stacks) * (1 + 2 * Rays Per Direction) * (Num Detectable Tags + 2) --> corrected calculation -// batched raycasts? (https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Learning-Environment-Design-Agents.md#raycast-observations) -// TODO: clean up the code, remove unnecessary comments, and make sure the code is readable and understandable /// /// The TrainingAgent class is a subclass of the Agent class in the ML-Agents library. @@ -79,9 +76,9 @@ public class TrainingAgent : Agent, IPrefab private bool wasRewardDispensed = false; private bool wasButtonPressed = false; - private void OnInDataZone(GameObject zone) + public void OnInDataZone(string zoneLogString) { - wasInDataZone = "Agent was in DataZone"; + wasInDataZone = "Agent was in DataZone: " + zoneLogString; } private void OnRewardSpawned(GameObject reward) @@ -172,7 +169,7 @@ private void InitialiseCSVProcess() if (!headerWritten) { writer.WriteLine( - "Episode,Step,Reward,CollectedRewardType,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate,ActionForwardDescription,ActionRotateDescription,IsFrozen,NotificationState,DispensedRewardType,WasRewardDispensed,WasButtonPressed,RaycastObservations,RaycastTags,WasInDataZone" + "Episode,Step,Reward,CollectedRewardType,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate,ActionForwardDescription,ActionRotateDescription,IsFrozen?,NotificationState,DispensedRewardType,WasRewardDispensed?,WasButtonPressed?,RaycastObservations,RaycastTags,WasInDataZone?" ); headerWritten = true; } diff --git a/Assets/Scripts/YAMLclasses.cs b/Assets/Scripts/YAMLclasses.cs index e01c8d00..260b4f78 100644 --- a/Assets/Scripts/YAMLclasses.cs +++ b/Assets/Scripts/YAMLclasses.cs @@ -90,6 +90,8 @@ public class Item public List rewardWeights { get; set; } = new List(); public Vector3 rewardSpawnPos { get; set; } = new Vector3(0, 0, 0); public List maxRewardCounts { get; set; } = new List(); + + public List triggerZoneIDs { get; set; } = new List(); } /// From cb2cc3635d421c59ee94bfd39e0935ee4f3a4c01 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 16 Jul 2024 12:31:59 +0300 Subject: [PATCH 088/205] working feature: datazone visibility boolean +++ we can now set the visibility of the datazone via yaml without affecting the functionality of the game object (the collision mechanic works with or without the boolean. + added comments in yamlclasses. for readability on item parameters. --- Assets/Scripts/ArenaBuilders.cs | 31 +++++++++++++++++++++--------- Assets/Scripts/ArenasParameters.cs | 2 ++ Assets/Scripts/DataZone.cs | 12 ++++++++++-- Assets/Scripts/YAMLclasses.cs | 14 ++++++++++---- 4 files changed, 44 insertions(+), 15 deletions(-) diff --git a/Assets/Scripts/ArenaBuilders.cs b/Assets/Scripts/ArenaBuilders.cs index 0c6fa98f..0b2a00fe 100644 --- a/Assets/Scripts/ArenaBuilders.cs +++ b/Assets/Scripts/ArenaBuilders.cs @@ -198,7 +198,8 @@ private void InstantiateSpawnable(Spawnable spawnable, GameObject spawnedObjects List timesBetweenDoorOpens = spawnable.timesBetweenDoorOpens; List moveDurations = spawnable.moveDurations; List resetDurations = spawnable.resetDurations; - List triggerDataZoneIDs = spawnable.triggerZoneIDs; + List triggerZoneIDs = spawnable.triggerZoneIDs ?? new List(); + bool zoneVisibility = spawnable.zoneVisibility; // Get the number of elements in the lists int numberOfPositions = positions.Count; @@ -302,7 +303,8 @@ private void InstantiateSpawnable(Spawnable spawnable, GameObject spawnedObjects { "rewardWeights", spawnable.RewardWeights }, { "rewardSpawnPos", rewardSpawnPos }, { "maxRewardCounts", spawnable.maxRewardCounts }, - { "triggerZoneIDs", spawnable.triggerZoneIDs } + { "triggerZoneIDs", spawnable.triggerZoneIDs }, + { "zoneVisibility", spawnable.zoneVisibility } }; // Determines a suitable position and rotation for the object to spawn @@ -497,16 +499,27 @@ private void SpawnGameObject( } } } - if ( - gameObjectInstance.CompareTag("DataZone") - && optionals.TryGetValue("triggerZoneIDs", out var triggerZoneIDsValue) - && triggerZoneIDsValue is List triggerZoneIDs - ) + if (gameObjectInstance.CompareTag("DataZone")) { DataZone dataZone = gameObjectInstance.GetComponent(); - if (dataZone != null && triggerZoneIDs.Count > 0) + if (dataZone != null) { - dataZone.TriggerZoneID = triggerZoneIDs[0]; + if ( + optionals.TryGetValue("triggerZoneIDs", out var triggerZoneIDsValue) + && triggerZoneIDsValue is List triggerZoneIDs + && triggerZoneIDs.Count > 0 + ) + { + dataZone.TriggerZoneID = triggerZoneIDs[0]; + } + + if ( + optionals.TryGetValue("zoneVisibility", out var zoneVisibilityValue) + && zoneVisibilityValue is bool zoneVisibility + ) + { + dataZone.SetVisibility(zoneVisibility); + } } } } diff --git a/Assets/Scripts/ArenasParameters.cs b/Assets/Scripts/ArenasParameters.cs index a0a313ce..48ad111f 100644 --- a/Assets/Scripts/ArenasParameters.cs +++ b/Assets/Scripts/ArenasParameters.cs @@ -66,6 +66,7 @@ public class Spawnable // Trigger/DataZone public List triggerZoneIDs = null; + public bool zoneVisibility = true; /// /// The purpose of this constructor is to initialize the Spawnable object with the properties of the provided GameObject. @@ -120,6 +121,7 @@ internal Spawnable(YAMLDefs.Item yamlItem) maxRewardCounts = yamlItem.maxRewardCounts; triggerZoneIDs = yamlItem.triggerZoneIDs; + zoneVisibility = yamlItem.zoneVisibility; } /// diff --git a/Assets/Scripts/DataZone.cs b/Assets/Scripts/DataZone.cs index 4bf43d61..eb81db2e 100644 --- a/Assets/Scripts/DataZone.cs +++ b/Assets/Scripts/DataZone.cs @@ -7,14 +7,22 @@ public class DataZone : Prefab { public delegate void InDataZoneHandler(string TriggerZoneID); public static event InDataZoneHandler OnInDataZone; - public string TriggerZoneID { get; set; } + public bool ZoneVisibility { get; set; } = true; + + public void SetVisibility(bool visibility) + { + var renderers = GetComponentsInChildren(); + foreach (var renderer in renderers) + { + renderer.enabled = visibility; + } + } private void OnCollisionEnter(Collision other) { if (other.gameObject.CompareTag("agent")) { - Debug.Log("Agent entered data zone: " + TriggerZoneID); OnInDataZone?.Invoke(TriggerZoneID); } } diff --git a/Assets/Scripts/YAMLclasses.cs b/Assets/Scripts/YAMLclasses.cs index 260b4f78..a64d6b24 100644 --- a/Assets/Scripts/YAMLclasses.cs +++ b/Assets/Scripts/YAMLclasses.cs @@ -55,23 +55,26 @@ public void SetCurrentPassMark() } /// - /// Item class is used to deserialize the item object in the YAML file. + /// Item class is used to deserialize the item object in the YAML file. It contains the settings for the game objects in the arena. + /// Each game object will require the following required and optional parameters in the yaml file under Item tags. /// public class Item { - // REQUIRED PARAMETERS + /* MANDATORY OR REQUIRED PARAMETERS */ public string name { get; set; } = ""; public List positions { get; set; } = new List(); public List rotations { get; set; } = new List(); public List sizes { get; set; } = new List(); public List colors { get; set; } = new List(); - // EXTRA/OPTIONAL PARAMETERS + /* EXTRA OR OPTIONAL PARAMETERS */ public List skins { get; set; } = new List(); public List frozenAgentDelays { get; set; } = new List(); + // SignBoard public List symbolNames { get; set; } = new List(); + // Spawner/Dispensers public List delays { get; set; } = new List(); public List initialValues { get; set; } = new List(); public List finalValues { get; set; } = new List(); @@ -83,6 +86,7 @@ public class Item public List changeRates { get; set; } = new List(); public List ripenTimes { get; set; } = new List(); + // SpawnerButton public List moveDurations { get; set; } = new List(); public List resetDurations { get; set; } = new List(); public float spawnProbability { get; set; } = 1f; @@ -91,7 +95,9 @@ public class Item public Vector3 rewardSpawnPos { get; set; } = new Vector3(0, 0, 0); public List maxRewardCounts { get; set; } = new List(); + // DataZone public List triggerZoneIDs { get; set; } = new List(); + public bool zoneVisibility { get; set; } = true; } /// @@ -129,7 +135,7 @@ public static string ResolveAlias(string name) { if (AliasMap.TryGetValue(name, out string newName)) { - Debug.Log($"Alias found: '{name}' is mapped to '{newName}'"); + Debug.Log($"Alias/old name for game object found. '{name}' is mapped to '{newName}'"); return newName; } return name; From 2f75d0799acfbb8f3a260c33365f396e32c3adbc Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 16 Jul 2024 12:42:20 +0300 Subject: [PATCH 089/205] added code to allow multiple triggers to collisions to datazone gameobjects before it was only once per episode. --- Assets/Scripts/DataZone.cs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/Assets/Scripts/DataZone.cs b/Assets/Scripts/DataZone.cs index eb81db2e..b2cb6db1 100644 --- a/Assets/Scripts/DataZone.cs +++ b/Assets/Scripts/DataZone.cs @@ -1,7 +1,8 @@ using UnityEngine; /// -/// A zone that triggers an event when an agent enters it. It's primary use is to trigger a log event when an agent enters a trigger/data zone. +/// A zone that triggers an event when an agent enters it. +/// It's primary use is to trigger a log event when an agent enters a datazone gameobject. /// public class DataZone : Prefab { @@ -9,6 +10,7 @@ public class DataZone : Prefab public static event InDataZoneHandler OnInDataZone; public string TriggerZoneID { get; set; } public bool ZoneVisibility { get; set; } = true; + public bool isAgentInZone { get; set; } = false; public void SetVisibility(bool visibility) { @@ -21,9 +23,20 @@ public void SetVisibility(bool visibility) private void OnCollisionEnter(Collision other) { - if (other.gameObject.CompareTag("agent")) + if (other.gameObject.CompareTag("agent") && !isAgentInZone) { + isAgentInZone = true; + Debug.Log("Agent entered data zone: " + TriggerZoneID); OnInDataZone?.Invoke(TriggerZoneID); } } + + private void OnCollisionExit(Collision other) + { + if (other.gameObject.CompareTag("agent")) + { + isAgentInZone = false; + Debug.Log("Agent exited data zone: " + TriggerZoneID); + } + } } From 462c4a157c42917cc1b5d993c2fc1339dc95bab4 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 16 Jul 2024 12:51:31 +0300 Subject: [PATCH 090/205] fix for some rewards not having correct tags in unity +added new tags for each unique reward. --- Assets/Prefabs/Rewards/DeathZone.prefab | 2 +- Assets/Prefabs/Rewards/DecayGoal.prefab | 2 +- Assets/Prefabs/Rewards/GrowGoal.prefab | 2 +- Assets/Prefabs/Rewards/RipenGoal.prefab | 2 +- Assets/Prefabs/Rewards/ShrinkGoal.prefab | 2 +- ProjectSettings/TagManager.asset | 4 ++++ 6 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Assets/Prefabs/Rewards/DeathZone.prefab b/Assets/Prefabs/Rewards/DeathZone.prefab index 632d72d0..f83cac1f 100644 --- a/Assets/Prefabs/Rewards/DeathZone.prefab +++ b/Assets/Prefabs/Rewards/DeathZone.prefab @@ -15,7 +15,7 @@ GameObject: - component: {fileID: 3754790313046653982} m_Layer: 0 m_Name: DeathZone - m_TagString: badGoal + m_TagString: DeathZone m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 diff --git a/Assets/Prefabs/Rewards/DecayGoal.prefab b/Assets/Prefabs/Rewards/DecayGoal.prefab index d9bd3a55..9d09b0b0 100644 --- a/Assets/Prefabs/Rewards/DecayGoal.prefab +++ b/Assets/Prefabs/Rewards/DecayGoal.prefab @@ -16,7 +16,7 @@ GameObject: - component: {fileID: 4211236304195966414} m_Layer: 0 m_Name: DecayGoal - m_TagString: goodGoal + m_TagString: DecayGoal m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 diff --git a/Assets/Prefabs/Rewards/GrowGoal.prefab b/Assets/Prefabs/Rewards/GrowGoal.prefab index 1476b65f..7d66f728 100644 --- a/Assets/Prefabs/Rewards/GrowGoal.prefab +++ b/Assets/Prefabs/Rewards/GrowGoal.prefab @@ -16,7 +16,7 @@ GameObject: - component: {fileID: -228958769421370408} m_Layer: 0 m_Name: GrowGoal - m_TagString: goodGoalMulti + m_TagString: GrowGoal m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 diff --git a/Assets/Prefabs/Rewards/RipenGoal.prefab b/Assets/Prefabs/Rewards/RipenGoal.prefab index 29e05973..f4ca93e0 100644 --- a/Assets/Prefabs/Rewards/RipenGoal.prefab +++ b/Assets/Prefabs/Rewards/RipenGoal.prefab @@ -16,7 +16,7 @@ GameObject: - component: {fileID: 4211236304195966414} m_Layer: 0 m_Name: RipenGoal - m_TagString: goodGoal + m_TagString: RipenGoal m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 diff --git a/Assets/Prefabs/Rewards/ShrinkGoal.prefab b/Assets/Prefabs/Rewards/ShrinkGoal.prefab index 9e1425c6..cee09175 100644 --- a/Assets/Prefabs/Rewards/ShrinkGoal.prefab +++ b/Assets/Prefabs/Rewards/ShrinkGoal.prefab @@ -16,7 +16,7 @@ GameObject: - component: {fileID: -228958769421370408} m_Layer: 0 m_Name: ShrinkGoal - m_TagString: goodGoalMulti + m_TagString: ShrinkGoal m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 diff --git a/ProjectSettings/TagManager.asset b/ProjectSettings/TagManager.asset index 74a5dbb0..1425be81 100644 --- a/ProjectSettings/TagManager.asset +++ b/ProjectSettings/TagManager.asset @@ -31,6 +31,10 @@ TagManager: - DecoyGoal - DecoyGoalBounce - DataZone + - RipenGoal + - DecayGoal + - GrowGoal + - ShrinkGoal layers: - Default - TransparentFX From 04630048653e118b0b9c00c02a0a01f0b8c5c4c8 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 16 Jul 2024 13:01:11 +0300 Subject: [PATCH 091/205] added missing valanced gameobjects: ripengoal GREY TO GREEN decaygoal GREEN TO GREY --- Assets/Prefabs/AAI3Arena.prefab | 2 + .../Prefabs/Rewards/DecayGoalEpEnding.prefab | 150 ++++++++++++++++++ .../Rewards/DecayGoalEpEnding.prefab.meta | 7 + .../Prefabs/Rewards/RipenGoalEpEnding.prefab | 150 ++++++++++++++++++ .../Rewards/RipenGoalEpEnding.prefab.meta | 7 + 5 files changed, 316 insertions(+) create mode 100644 Assets/Prefabs/Rewards/DecayGoalEpEnding.prefab create mode 100644 Assets/Prefabs/Rewards/DecayGoalEpEnding.prefab.meta create mode 100644 Assets/Prefabs/Rewards/RipenGoalEpEnding.prefab create mode 100644 Assets/Prefabs/Rewards/RipenGoalEpEnding.prefab.meta diff --git a/Assets/Prefabs/AAI3Arena.prefab b/Assets/Prefabs/AAI3Arena.prefab index 42edea6b..fb1fdd91 100644 --- a/Assets/Prefabs/AAI3Arena.prefab +++ b/Assets/Prefabs/AAI3Arena.prefab @@ -859,6 +859,8 @@ MonoBehaviour: - {fileID: 1323439192758780, guid: 70289c4d2c6d4a94eb4d73531e1a9ce6, type: 3} - {fileID: 8069506010422567580, guid: 2e66c94a6ed25c641ad85c58ce7e981b, type: 3} - {fileID: 7041498159436349378, guid: 00c912a41dbd87a4ba31cad3fe3ec871, type: 3} + - {fileID: 1311020654520240, guid: 4ab9cee937b1d44788ffc287caba796b, type: 3} + - {fileID: 1311020654520240, guid: 6a410b42e9ae8480ca41567b3afb30f0, type: 3} spawnedObjectsHolder: {fileID: 6276814220842007455, guid: ff9a0b038a04e8747a9f95217df0b26f, type: 3} maxSpawnAttemptsForAgent: 100 maxSpawnAttemptsForPrefabs: 20 diff --git a/Assets/Prefabs/Rewards/DecayGoalEpEnding.prefab b/Assets/Prefabs/Rewards/DecayGoalEpEnding.prefab new file mode 100644 index 00000000..6ecaf8de --- /dev/null +++ b/Assets/Prefabs/Rewards/DecayGoalEpEnding.prefab @@ -0,0 +1,150 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1311020654520240 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4472178826336288} + - component: {fileID: 33085984432835760} + - component: {fileID: 135831286041315876} + - component: {fileID: 23446274134440080} + - component: {fileID: 54054735976619294} + - component: {fileID: 4211236304195966414} + m_Layer: 0 + m_Name: DecayGoalEpEnding + m_TagString: DecayGoal + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &4472178826336288 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1311020654520240} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0.5, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &33085984432835760 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1311020654520240} + m_Mesh: {fileID: 6891028187734869254, guid: dcdd37785903db543b1d657afd500d44, type: 3} +--- !u!135 &135831286041315876 +SphereCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1311020654520240} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Radius: 0.5 + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &23446274134440080 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1311020654520240} + 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_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: acce0111776515d409aa313eda8a3a22, type: 2} + - {fileID: 2100000, guid: 47e07f5ec375d874c9ab7bd76cbae9ab, type: 2} + - {fileID: 2100000, guid: f26f4feac4c107246b1ea059f1d49c3c, 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: 1 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!54 &54054735976619294 +Rigidbody: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1311020654520240} + serializedVersion: 2 + m_Mass: 1 + m_Drag: 0 + m_AngularDrag: 0.05 + m_UseGravity: 1 + m_IsKinematic: 0 + m_Interpolate: 0 + m_Constraints: 0 + m_CollisionDetection: 0 +--- !u!114 &4211236304195966414 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1311020654520240} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a73f721d3ddddff4dbcb36d254907321, type: 3} + m_Name: + m_EditorClassIdentifier: + rotationRange: {x: 0, y: 0} + sizeMin: {x: 0, y: 0, z: 0} + sizeMax: {x: 0, y: 0, z: 0} + canRandomizeColor: 1 + ratioSize: {x: 1, y: 1, z: 1} + sizeAdjustment: 0.999 + textureUVOverride: 0 + typicalOrigin: 1 + numberOfGoals: 1 + reward: 2.5 + isMulti: 1 + rewardType: DecayGoalEpEnding + initialReward: 3 + finalReward: 0 + decayRate: -0.005 + initialColour: {r: 0.5028866, g: 0.7454045, b: 0.25015837, a: 1} + finalColour: {r: 0.39215687, g: 0.39215687, b: 0.39215687, a: 1} + flipDecayDirection: 0 + fixedFrameDelay: 150 diff --git a/Assets/Prefabs/Rewards/DecayGoalEpEnding.prefab.meta b/Assets/Prefabs/Rewards/DecayGoalEpEnding.prefab.meta new file mode 100644 index 00000000..362cd720 --- /dev/null +++ b/Assets/Prefabs/Rewards/DecayGoalEpEnding.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 4ab9cee937b1d44788ffc287caba796b +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Prefabs/Rewards/RipenGoalEpEnding.prefab b/Assets/Prefabs/Rewards/RipenGoalEpEnding.prefab new file mode 100644 index 00000000..8726b72c --- /dev/null +++ b/Assets/Prefabs/Rewards/RipenGoalEpEnding.prefab @@ -0,0 +1,150 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1311020654520240 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4472178826336288} + - component: {fileID: 33085984432835760} + - component: {fileID: 135831286041315876} + - component: {fileID: 23446274134440080} + - component: {fileID: 54054735976619294} + - component: {fileID: 4211236304195966414} + m_Layer: 0 + m_Name: RipenGoalEpEnding + m_TagString: RipenGoal + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &4472178826336288 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1311020654520240} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0.5, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &33085984432835760 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1311020654520240} + m_Mesh: {fileID: 6891028187734869254, guid: dcdd37785903db543b1d657afd500d44, type: 3} +--- !u!135 &135831286041315876 +SphereCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1311020654520240} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Radius: 0.5 + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &23446274134440080 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1311020654520240} + 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_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: acce0111776515d409aa313eda8a3a22, type: 2} + - {fileID: 2100000, guid: b992a33971aa7164a9c57db47a3a151a, type: 2} + - {fileID: 2100000, guid: f26f4feac4c107246b1ea059f1d49c3c, 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: 1 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!54 &54054735976619294 +Rigidbody: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1311020654520240} + serializedVersion: 2 + m_Mass: 1 + m_Drag: 0 + m_AngularDrag: 0.05 + m_UseGravity: 1 + m_IsKinematic: 0 + m_Interpolate: 0 + m_Constraints: 0 + m_CollisionDetection: 0 +--- !u!114 &4211236304195966414 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1311020654520240} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a73f721d3ddddff4dbcb36d254907321, type: 3} + m_Name: + m_EditorClassIdentifier: + rotationRange: {x: 0, y: 0} + sizeMin: {x: 0, y: 0, z: 0} + sizeMax: {x: 0, y: 0, z: 0} + canRandomizeColor: 1 + ratioSize: {x: 1, y: 1, z: 1} + sizeAdjustment: 0.999 + textureUVOverride: 0 + typicalOrigin: 1 + numberOfGoals: 1 + reward: 2.5 + isMulti: 1 + rewardType: RipenGoalEpEnding + initialReward: 0 + finalReward: 3 + decayRate: -0.005 + initialColour: {r: 0.39157256, g: 0.39157256, b: 0.39157256, a: 1} + finalColour: {r: 0.5028866, g: 0.7454045, b: 0.25015837, a: 1} + flipDecayDirection: 0 + fixedFrameDelay: 150 diff --git a/Assets/Prefabs/Rewards/RipenGoalEpEnding.prefab.meta b/Assets/Prefabs/Rewards/RipenGoalEpEnding.prefab.meta new file mode 100644 index 00000000..8ae462ed --- /dev/null +++ b/Assets/Prefabs/Rewards/RipenGoalEpEnding.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6a410b42e9ae8480ca41567b3afb30f0 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: From ac78bc25f58eb065545ab4e88d5bd8a222a30779 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 16 Jul 2024 13:01:28 +0300 Subject: [PATCH 092/205] removed todo --- Assets/Scripts/TrainingAgent.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index a9164bf6..5d0ea886 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -12,8 +12,6 @@ using System.Collections.Concurrent; using System.Threading; -// TODO: need to check/handle what happens if two dispensed rewards are collected in the same step - /// /// The TrainingAgent class is a subclass of the Agent class in the ML-Agents library. /// It is used to define the behaviour of the agent in the training environment. From 060531e00a9e308dbce0f2a27e08908e3c104cc1 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 17 Jul 2024 20:11:18 +0300 Subject: [PATCH 093/205] renamed param for datazone from triggerZoneIDs to triggerZoneID (removed plural) --- Assets/Scripts/ArenaBuilders.cs | 6 +++--- Assets/Scripts/ArenasParameters.cs | 4 ++-- Assets/Scripts/YAMLclasses.cs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Assets/Scripts/ArenaBuilders.cs b/Assets/Scripts/ArenaBuilders.cs index 0b2a00fe..7de735a5 100644 --- a/Assets/Scripts/ArenaBuilders.cs +++ b/Assets/Scripts/ArenaBuilders.cs @@ -198,7 +198,7 @@ private void InstantiateSpawnable(Spawnable spawnable, GameObject spawnedObjects List timesBetweenDoorOpens = spawnable.timesBetweenDoorOpens; List moveDurations = spawnable.moveDurations; List resetDurations = spawnable.resetDurations; - List triggerZoneIDs = spawnable.triggerZoneIDs ?? new List(); + List triggerZoneID = spawnable.triggerZoneID; bool zoneVisibility = spawnable.zoneVisibility; // Get the number of elements in the lists @@ -303,7 +303,7 @@ private void InstantiateSpawnable(Spawnable spawnable, GameObject spawnedObjects { "rewardWeights", spawnable.RewardWeights }, { "rewardSpawnPos", rewardSpawnPos }, { "maxRewardCounts", spawnable.maxRewardCounts }, - { "triggerZoneIDs", spawnable.triggerZoneIDs }, + { "triggerZoneID", spawnable.triggerZoneID }, { "zoneVisibility", spawnable.zoneVisibility } }; @@ -505,7 +505,7 @@ private void SpawnGameObject( if (dataZone != null) { if ( - optionals.TryGetValue("triggerZoneIDs", out var triggerZoneIDsValue) + optionals.TryGetValue("triggerZoneID", out var triggerZoneIDsValue) && triggerZoneIDsValue is List triggerZoneIDs && triggerZoneIDs.Count > 0 ) diff --git a/Assets/Scripts/ArenasParameters.cs b/Assets/Scripts/ArenasParameters.cs index 48ad111f..ab817dea 100644 --- a/Assets/Scripts/ArenasParameters.cs +++ b/Assets/Scripts/ArenasParameters.cs @@ -65,7 +65,7 @@ public class Spawnable public Dictionary originalToNewIDMapping = new Dictionary(); // Trigger/DataZone - public List triggerZoneIDs = null; + public List triggerZoneID = null; public bool zoneVisibility = true; /// @@ -120,7 +120,7 @@ internal Spawnable(YAMLDefs.Item yamlItem) rewardSpawnPos = yamlItem.rewardSpawnPos; maxRewardCounts = yamlItem.maxRewardCounts; - triggerZoneIDs = yamlItem.triggerZoneIDs; + triggerZoneID = yamlItem.triggerZoneID; zoneVisibility = yamlItem.zoneVisibility; } diff --git a/Assets/Scripts/YAMLclasses.cs b/Assets/Scripts/YAMLclasses.cs index a64d6b24..a8b5b533 100644 --- a/Assets/Scripts/YAMLclasses.cs +++ b/Assets/Scripts/YAMLclasses.cs @@ -96,7 +96,7 @@ public class Item public List maxRewardCounts { get; set; } = new List(); // DataZone - public List triggerZoneIDs { get; set; } = new List(); + public List triggerZoneID { get; set; } = new List(); public bool zoneVisibility { get; set; } = true; } From 43bee68ab341cc9c90a4ad7b9698a87c5005481b Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 17 Jul 2024 20:20:16 +0300 Subject: [PATCH 094/205] set datazone GO to be able to walk through by the agent changed the interaction settings from colliders to triggers, also set kinematic to true (so the object doesnt fall due to lack of box colliders) Downside is the object has no gravity. --- Assets/Prefabs/DataZone/DataZone.prefab | 4 ++-- Assets/Scripts/DataZone.cs | 20 +++++++++++++++----- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/Assets/Prefabs/DataZone/DataZone.prefab b/Assets/Prefabs/DataZone/DataZone.prefab index 4ab7b6c7..5c9379ce 100644 --- a/Assets/Prefabs/DataZone/DataZone.prefab +++ b/Assets/Prefabs/DataZone/DataZone.prefab @@ -56,7 +56,7 @@ Rigidbody: m_Drag: 0 m_AngularDrag: 0.05 m_UseGravity: 1 - m_IsKinematic: 0 + m_IsKinematic: 1 m_Interpolate: 0 m_Constraints: 0 m_CollisionDetection: 0 @@ -68,7 +68,7 @@ BoxCollider: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 7041498159436349378} m_Material: {fileID: 0} - m_IsTrigger: 0 + m_IsTrigger: 1 m_Enabled: 1 serializedVersion: 2 m_Size: {x: 1, y: 1, z: 1} diff --git a/Assets/Scripts/DataZone.cs b/Assets/Scripts/DataZone.cs index b2cb6db1..10a5aea5 100644 --- a/Assets/Scripts/DataZone.cs +++ b/Assets/Scripts/DataZone.cs @@ -1,7 +1,7 @@ using UnityEngine; /// -/// A zone that triggers an event when an agent enters it. +/// A zone that triggers an event when an agent enters it. /// It's primary use is to trigger a log event when an agent enters a datazone gameobject. /// public class DataZone : Prefab @@ -12,6 +12,16 @@ public class DataZone : Prefab public bool ZoneVisibility { get; set; } = true; public bool isAgentInZone { get; set; } = false; + private void Start() + { + SetVisibility(ZoneVisibility); + var collider = GetComponent(); + if (collider != null) + { + collider.isTrigger = true; + } + } + public void SetVisibility(bool visibility) { var renderers = GetComponentsInChildren(); @@ -21,9 +31,9 @@ public void SetVisibility(bool visibility) } } - private void OnCollisionEnter(Collision other) + private void OnTriggerEnter(Collider other) { - if (other.gameObject.CompareTag("agent") && !isAgentInZone) + if (other.CompareTag("agent") && !isAgentInZone) { isAgentInZone = true; Debug.Log("Agent entered data zone: " + TriggerZoneID); @@ -31,9 +41,9 @@ private void OnCollisionEnter(Collision other) } } - private void OnCollisionExit(Collision other) + private void OnTriggerExit(Collider other) { - if (other.gameObject.CompareTag("agent")) + if (other.CompareTag("agent")) { isAgentInZone = false; Debug.Log("Agent exited data zone: " + TriggerZoneID); From 0fd1183b767f7a647afbc40746d89a5aa25e76d4 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 17 Jul 2024 20:25:49 +0300 Subject: [PATCH 095/205] working feature: datazone agent left datazone msg in .csv --- Assets/Scripts/DataZone.cs | 6 ++++-- Assets/Scripts/TrainingAgent.cs | 7 +++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Assets/Scripts/DataZone.cs b/Assets/Scripts/DataZone.cs index 10a5aea5..1b43c005 100644 --- a/Assets/Scripts/DataZone.cs +++ b/Assets/Scripts/DataZone.cs @@ -6,8 +6,9 @@ /// public class DataZone : Prefab { - public delegate void InDataZoneHandler(string TriggerZoneID); - public static event InDataZoneHandler OnInDataZone; + public delegate void DataZoneHandler(string TriggerZoneID); + public static event DataZoneHandler OnInDataZone; + public static event DataZoneHandler OnOutDataZone; public string TriggerZoneID { get; set; } public bool ZoneVisibility { get; set; } = true; public bool isAgentInZone { get; set; } = false; @@ -47,6 +48,7 @@ private void OnTriggerExit(Collider other) { isAgentInZone = false; Debug.Log("Agent exited data zone: " + TriggerZoneID); + OnOutDataZone?.Invoke(TriggerZoneID); } } } diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 5d0ea886..fc484e30 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -79,6 +79,11 @@ public void OnInDataZone(string zoneLogString) wasInDataZone = "Agent was in DataZone: " + zoneLogString; } + public void OnOutDataZone(string zoneLogString) + { + wasInDataZone = "Agent left DataZone: " + zoneLogString; + } + private void OnRewardSpawned(GameObject reward) { wasButtonPressed = true; @@ -115,6 +120,7 @@ public override void Initialize() Spawner_InteractiveButton.RewardSpawned += OnRewardSpawned; DataZone.OnInDataZone += OnInDataZone; + DataZone.OnOutDataZone += OnOutDataZone; InitialiseCSVProcess(); @@ -256,6 +262,7 @@ protected override void OnDisable() Spawner_InteractiveButton.RewardSpawned -= OnRewardSpawned; DataZone.OnInDataZone -= OnInDataZone; + DataZone.OnOutDataZone -= OnOutDataZone; } public float GetPreviousScore() From 50c03dfb39cde75f6bd17939ff226485ad840973 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 17 Jul 2024 20:27:50 +0300 Subject: [PATCH 096/205] Create datazone-test.yaml core test for datazone feature --- .../Resources/test_configs/datazone-test.yaml | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 Assets/Resources/test_configs/datazone-test.yaml diff --git a/Assets/Resources/test_configs/datazone-test.yaml b/Assets/Resources/test_configs/datazone-test.yaml new file mode 100644 index 00000000..45082df0 --- /dev/null +++ b/Assets/Resources/test_configs/datazone-test.yaml @@ -0,0 +1,20 @@ +# This is a test config file for the DataZone game object. +!ArenaConfig +arenas: + 0: !Arena + passMark: 0 + timeLimit: 100 + items: + - !Item + name: Agent + positions: + - !Vector3 {x: 10, y: 0, z: 20} + rotations: [90] + - !Item + name: DataZone # The name of the game object. + positions: + - !Vector3 {x: 25, y: 0, z: 25} + sizes: + - !Vector3 {x: 5, y: 0, z: 5} + zoneVisibility: true # This is a boolean value that determines whether the zone is visible or not. + triggerZoneID: ["Agent has entered the DataZone 1"] # This is a string value that is used to identify the zone. \ No newline at end of file From 7a5ee9e6f3612766f7a7fb3bd2a3294ca2e8c6b7 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 17 Jul 2024 20:28:06 +0300 Subject: [PATCH 097/205] Update datazone-test.yaml --- Assets/Resources/test_configs/datazone-test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/Resources/test_configs/datazone-test.yaml b/Assets/Resources/test_configs/datazone-test.yaml index 45082df0..2912f5fb 100644 --- a/Assets/Resources/test_configs/datazone-test.yaml +++ b/Assets/Resources/test_configs/datazone-test.yaml @@ -11,7 +11,7 @@ arenas: - !Vector3 {x: 10, y: 0, z: 20} rotations: [90] - !Item - name: DataZone # The name of the game object. + name: DataZone positions: - !Vector3 {x: 25, y: 0, z: 25} sizes: From 5cfeb96c81637fe2a6ff1c2978eb793cb5e86f23 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 17 Jul 2024 20:29:06 +0300 Subject: [PATCH 098/205] Create datazone-test.yaml.meta --- Assets/Resources/test_configs/datazone-test.yaml.meta | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 Assets/Resources/test_configs/datazone-test.yaml.meta diff --git a/Assets/Resources/test_configs/datazone-test.yaml.meta b/Assets/Resources/test_configs/datazone-test.yaml.meta new file mode 100644 index 00000000..791a97ed --- /dev/null +++ b/Assets/Resources/test_configs/datazone-test.yaml.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: eb11f93dcf80e484fb48dfc3dd7c174b +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: From 64e3927a531678f2a37b04d70c207ed27bee2a2e Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 17 Jul 2024 21:25:37 +0300 Subject: [PATCH 099/205] IMPORTANT: Added code to handle if agent position == arena default position (0,0,0). Spotted By Matteo. --- Assets/Scripts/ArenaBuilders.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Assets/Scripts/ArenaBuilders.cs b/Assets/Scripts/ArenaBuilders.cs index 7de735a5..a5b77c97 100644 --- a/Assets/Scripts/ArenaBuilders.cs +++ b/Assets/Scripts/ArenaBuilders.cs @@ -140,6 +140,19 @@ private void InstantiateSpawnables(GameObject spawnedObjectsHolder) if (agentSpawnablesFromUser.Any()) { _agentCollider.enabled = false; + Vector3 agentPosition = agentSpawnablesFromUser[0].positions[0]; + + // Checking if Agent positions do not conflict with Arena default position (0, 0, 0) + if ( + agentPosition == Vector3.zero + || (agentPosition.x == 1 && agentPosition.y == 0 && agentPosition.z == 0) + || (agentPosition.x == 0 && agentPosition.y == 0 && agentPosition.z == 1) + ) + { + agentPosition = new Vector3(1, 0, 1); // Buffer position + agentSpawnablesFromUser[0].positions[0] = agentPosition; + } + SpawnAgent(agentSpawnablesFromUser[0]); _agentCollider.enabled = true; SpawnObjects(spawnedObjectsHolder); From eaa243996c67ccbb9bb415d604f85b9809960a5a Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 17 Jul 2024 21:50:58 +0300 Subject: [PATCH 100/205] removed debug logs --- Assets/Scripts/DataZone.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Assets/Scripts/DataZone.cs b/Assets/Scripts/DataZone.cs index 1b43c005..efff5d77 100644 --- a/Assets/Scripts/DataZone.cs +++ b/Assets/Scripts/DataZone.cs @@ -37,7 +37,6 @@ private void OnTriggerEnter(Collider other) if (other.CompareTag("agent") && !isAgentInZone) { isAgentInZone = true; - Debug.Log("Agent entered data zone: " + TriggerZoneID); OnInDataZone?.Invoke(TriggerZoneID); } } @@ -47,7 +46,6 @@ private void OnTriggerExit(Collider other) if (other.CompareTag("agent")) { isAgentInZone = false; - Debug.Log("Agent exited data zone: " + TriggerZoneID); OnOutDataZone?.Invoke(TriggerZoneID); } } From c45168a5306c900cfb07362bc3a814da15baa06d Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Fri, 19 Jul 2024 17:15:41 +0300 Subject: [PATCH 101/205] minor comments --- Assets/Scripts/ArenasParameters.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Assets/Scripts/ArenasParameters.cs b/Assets/Scripts/ArenasParameters.cs index ab817dea..4c635cec 100644 --- a/Assets/Scripts/ArenasParameters.cs +++ b/Assets/Scripts/ArenasParameters.cs @@ -7,8 +7,11 @@ using YAMLDefs; /// -/// The classes in this file are used to store the parameters for the arenas. +/// The classes in this file are used to store the parameters for the arenas. +/// These parameters are read from a YAML file and used to configure the arenas. /// + +// TODO: Optimize and refactor this script. namespace ArenasParameters { /// @@ -30,6 +33,7 @@ public List GetList() /// public class Spawnable { + // ======== REQUIRED PARAMETERS ======== public string name = ""; public GameObject gameObject = null; public List positions = null; From 2b541c59d936d53122245e9b22fad02de41b9297 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Fri, 19 Jul 2024 17:18:50 +0300 Subject: [PATCH 102/205] added checks for agent pos == 40 for x or z plus added helper method for readability and modularity --- Assets/Scripts/ArenaBuilders.cs | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/Assets/Scripts/ArenaBuilders.cs b/Assets/Scripts/ArenaBuilders.cs index a5b77c97..affd4367 100644 --- a/Assets/Scripts/ArenaBuilders.cs +++ b/Assets/Scripts/ArenaBuilders.cs @@ -15,6 +15,8 @@ /// User-defined or randomized positions, rotations, and scales are supported /// ... with repeated spawn attempts made for random placements until free space is found or the builder moves to the next item. /// + +// TODO: Optimize and refactor the this script. namespace ArenaBuilders { public class ArenaBuilder @@ -140,16 +142,13 @@ private void InstantiateSpawnables(GameObject spawnedObjectsHolder) if (agentSpawnablesFromUser.Any()) { _agentCollider.enabled = false; - Vector3 agentPosition = agentSpawnablesFromUser[0].positions[0]; - // Checking if Agent positions do not conflict with Arena default position (0, 0, 0) - if ( - agentPosition == Vector3.zero - || (agentPosition.x == 1 && agentPosition.y == 0 && agentPosition.z == 0) - || (agentPosition.x == 0 && agentPosition.y == 0 && agentPosition.z == 1) - ) + // Check for problematic positions and adjust if necessary + Vector3 agentPosition = agentSpawnablesFromUser[0].positions[0]; + if (IsProblematicPosition(agentPosition)) { - agentPosition = new Vector3(1, 0, 1); // Buffer position + Debug.LogWarning("Agent position is problematic. Adjusting to (1, 0, 1)"); + agentPosition = new Vector3(1, 0, 1); agentSpawnablesFromUser[0].positions[0] = agentPosition; } @@ -166,6 +165,12 @@ private void InstantiateSpawnables(GameObject spawnedObjectsHolder) } } + // Helper method to check for agent position problems. When arena size can be changed, this method will need to be updated. + private bool IsProblematicPosition(Vector3 position) + { + return position.x == 0 || position.z == 0 || position.x == 40 || position.z == 40; + } + /// /// Spawns the objects within the arena. /// From 68a2c898b9bc58df3602aaedabac3131311ff2fe Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Fri, 19 Jul 2024 17:38:48 +0300 Subject: [PATCH 103/205] IMPORTANT: Combined raycast tags and observed data into single column for readability and compactness. Now using joined strings for readability via helper method. --- Assets/Scripts/TrainingAgent.cs | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index fc484e30..5f666160 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -173,7 +173,7 @@ private void InitialiseCSVProcess() if (!headerWritten) { writer.WriteLine( - "Episode,Step,Reward,CollectedRewardType,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate,ActionForwardDescription,ActionRotateDescription,IsFrozen?,NotificationState,DispensedRewardType,WasRewardDispensed?,WasButtonPressed?,RaycastObservations,RaycastTags,WasInDataZone?" + "Episode,Step,Reward,CollectedRewardType,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate,ActionForwardDescription,ActionRotateDescription,IsFrozen?,NotificationState,DispensedRewardType,WasRewardDispensed?,WasButtonPressed?,CombinedRaycastData,WasInDataZone?" ); headerWritten = true; } @@ -184,6 +184,11 @@ private void InitialiseCSVProcess() } } + private string CombineRaycastData(float[] observations, string[] tags) + { + return string.Join(";", observations.Zip(tags, (obs, tag) => $"{obs}:{tag}")); + } + /// /// Logs the agent's state to a CSV file. This is called every step. The data is stored in a queue and flushed to the file in a separate thread. /// @@ -198,18 +203,15 @@ private void LogToCSV( float reward, string notificationState, int customEpisodeCount, - string DispensedRewardType, + string dispensedRewardType, bool wasRewardDispensed, bool wasButtonPressed, - float[] raycastObservations, - string[] raycastTags, + string combinedRaycastData, string wasInDataZone ) { - string raycastData = string.Join(",", raycastObservations); - string raycastTagsData = string.Join(",", raycastTags); string logEntry = - $"{customEpisodeCount},{StepCount},{reward},{lastCollectedRewardType},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate},{actionForwardDescription},{actionRotateDescription},{isFrozen},{notificationState},{DispensedRewardType},{wasRewardDispensed},{wasButtonPressed},{raycastData},{raycastTagsData},{wasInDataZone}"; + $"{customEpisodeCount},{StepCount},{reward},{lastCollectedRewardType},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate},{actionForwardDescription},{actionRotateDescription},{isFrozen},{notificationState},{dispensedRewardType},{wasRewardDispensed},{wasButtonPressed},{combinedRaycastData},{wasInDataZone}"; logQueue.Enqueue(logEntry); lastCollectedRewardType = "None"; } @@ -339,6 +341,8 @@ public override void CollectObservations(VectorSensor sensor) sensor.AddObservation(observation); } + string combinedRaycastData = CombineRaycastData(raycastObservations, raycastTags); + LogToCSV( localVel, localPos, @@ -353,8 +357,7 @@ public override void CollectObservations(VectorSensor sensor) dispensedRewardType, wasRewardDispensed, wasButtonPressed, - raycastObservations, - raycastTags, + combinedRaycastData, wasInDataZone ); dispensedRewardType = "None"; @@ -380,10 +383,10 @@ public override void OnActionReceived(ActionBuffers action) float reward = GetCumulativeReward(); string notificationState = GetNotificationState(); - // Collect raycast observations and tags directly from the RayPerceptionSensorComponent3D - // TODO: Need to check if this is the correct way to collect raycast observations (float[] raycastObservations, string[] raycastTags) = CollectRaycastObservations(); + string combinedRaycastData = CombineRaycastData(raycastObservations, raycastTags); + LogToCSV( localVel, localPos, @@ -398,8 +401,7 @@ public override void OnActionReceived(ActionBuffers action) dispensedRewardType, wasRewardDispensed, wasButtonPressed, - raycastObservations, - raycastTags, + combinedRaycastData, wasInDataZone ); dispensedRewardType = "None"; From 28dbda6c290a309959d43296a257756017554f82 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Fri, 19 Jul 2024 17:42:03 +0300 Subject: [PATCH 104/205] added TODO --- Assets/Scripts/TrainingAgent.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 5f666160..b51c0e67 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -17,6 +17,8 @@ /// It is used to define the behaviour of the agent in the training environment. /// Actions are currently discrete. 2 branches of 0,1,2, 0,1,2 for forward and rotate respectively. /// + +// TODO: Clean, optimize and refactor the this script. public class TrainingAgent : Agent, IPrefab { [Header("Agent Settings")] From 8f85fffcb7934d7216e0ebb140aabd82f7ab092e Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Mon, 22 Jul 2024 16:46:44 +0300 Subject: [PATCH 105/205] removed UIManager GO no longer needed as not used --- Assets/Scenes/AAI3EnvironmentManager.unity | 51 +--------------------- 1 file changed, 1 insertion(+), 50 deletions(-) diff --git a/Assets/Scenes/AAI3EnvironmentManager.unity b/Assets/Scenes/AAI3EnvironmentManager.unity index 548e3ac2..b3d88cfe 100644 --- a/Assets/Scenes/AAI3EnvironmentManager.unity +++ b/Assets/Scenes/AAI3EnvironmentManager.unity @@ -38,7 +38,7 @@ RenderSettings: m_ReflectionIntensity: 1 m_CustomReflection: {fileID: 0} m_Sun: {fileID: 0} - m_IndirectSpecularColor: {r: 0.21499613, g: 0.2735186, b: 0.35116386, a: 1} + m_IndirectSpecularColor: {r: 0.21499568, g: 0.27351773, b: 0.35116208, a: 1} m_UseRadianceAmbientProbe: 0 --- !u!157 &3 LightmapSettings: @@ -1598,54 +1598,6 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 840957436} m_CullTransparentMesh: 1 ---- !u!1 &938435690 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 938435692} - - component: {fileID: 938435691} - m_Layer: 0 - m_Name: UIManager - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &938435691 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 938435690} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: cd1dba16abaca0e4e83da1bfcfaab486, type: 3} - m_Name: - m_EditorClassIdentifier: - arenaText: {fileID: 544926171} - totalObjectsText: {fileID: 840957438} - environmentManager: {fileID: 462738127} - trainingArena: {fileID: 0} ---- !u!4 &938435692 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 938435690} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 462.28134, y: 283.09988, z: -0.53482056} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_RootOrder: 7 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &997572390 GameObject: m_ObjectHideFlags: 0 @@ -1804,7 +1756,6 @@ MonoBehaviour: m_EditorClassIdentifier: scoreText: {fileID: 1901104414} effectCanvas: {fileID: 59569253} - uiManager: {fileID: 938435691} prevScore: 0 --- !u!4 &1065671192 Transform: From 7e707bfbfb4a1afbf0a487556f122555f6bd8652 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Mon, 22 Jul 2024 22:25:35 +0300 Subject: [PATCH 106/205] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 8a5364a5..22abd6b0 100644 --- a/.gitignore +++ b/.gitignore @@ -115,3 +115,4 @@ Assets/Prefabs/Other-Unique/SignPosterboard.prefab /ObservationLogs *.csv /ObservationLogs +.DS_Store From 209bf8bc16135318e589c10ce45d9240f3313573 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 23 Jul 2024 12:26:55 +0300 Subject: [PATCH 107/205] minor comment change on GO description --- Assets/Resources/test_configs/every_object_spawn_test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/Resources/test_configs/every_object_spawn_test.yaml b/Assets/Resources/test_configs/every_object_spawn_test.yaml index 3680ad9f..0531192a 100644 --- a/Assets/Resources/test_configs/every_object_spawn_test.yaml +++ b/Assets/Resources/test_configs/every_object_spawn_test.yaml @@ -122,7 +122,7 @@ arenas: # VALANCED REWARDS SPAWNERS/DISPENSERS - !Item - name: SpawnerButton # Interactive button that spawns rewards when pressed by the agent. + name: SpawnerButton # Interactive button that spawns rewards when triggered by the agent. positions: - !Vector3 {x: 32, y: 31, z: 30} rotations: [0] From be5e74a40b4364914bd477ecd1f7c3eaf9d1110b Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 23 Jul 2024 19:57:43 +0300 Subject: [PATCH 108/205] added code to track dispenser ids --- Assets/Scripts/Spawners/GoalSpawner.cs | 364 ++++++++++++++----------- 1 file changed, 198 insertions(+), 166 deletions(-) diff --git a/Assets/Scripts/Spawners/GoalSpawner.cs b/Assets/Scripts/Spawners/GoalSpawner.cs index 2d22a7cd..56342cca 100644 --- a/Assets/Scripts/Spawners/GoalSpawner.cs +++ b/Assets/Scripts/Spawners/GoalSpawner.cs @@ -8,170 +8,202 @@ /// public class GoalSpawner : Prefab { - [Header("Spawning Parameters")] - public BallGoal[] spawnObjects; - public float initialSpawnSize; - public float ripenedSpawnSize; - public bool variableSize; - public bool variableSpawnPosition; - public float sphericalSpawnRadius; - public Vector3 defaultSpawnPosition; - public float timeToRipen; // Seconds - public float timeBetweenSpawns; // Seconds - public float delaySeconds; // Seconds - public int spawnCount; // '-1' = infinite spawning - - [ColorUsage(true, true)] - private Color colourOverride; - - // Random Seeds - public int objSpawnSeed = 0; - public int spawnSizeSeed = 0; - - // RNGs - private System.Random[] RNGs = new System.Random[4]; - private enum E { OBJECT = 0, SIZE = 1, ANGLE = 2 } - - private float height; - private ArenaBuilder AB; - private bool spawnsRandomObjects; - - public virtual void Awake() - { - InitializeParameters(); - StartCoroutine(StartSpawning()); - } - - // Initialize spawning parameters and RNGs - private void InitializeParameters() - { - typicalOrigin = false; - sizeMin = sizeMax = Vector3Int.one; - canRandomizeColor = false; - ratioSize = Vector3Int.one; - - height = GetComponent().bounds.size.y; - AB = transform.parent.parent.GetComponent().Builder; - - spawnsRandomObjects = (spawnObjects.Length > 1); - - if (spawnsRandomObjects) - RNGs[(int)E.OBJECT] = new System.Random(objSpawnSeed); - - if (variableSize) - RNGs[(int)E.SIZE] = new System.Random(spawnSizeSeed); - - if (variableSpawnPosition) - RNGs[(int)E.ANGLE] = new System.Random(1); - - if (timeToRipen <= 0) - initialSpawnSize = ripenedSpawnSize; - } - - private IEnumerator StartSpawning() - { - yield return new WaitForSeconds(delaySeconds); - - while (CanStillSpawn()) - { - BallGoal newGoal = SpawnNewGoal(0); - StartCoroutine(ManageSingleSpawnLifeCycle(newGoal, variableSize ? (newGoal.reward - initialSpawnSize) : 0)); - - if (!WillSpawnInfinite()) - spawnCount--; - - yield return new WaitForSeconds(timeBetweenSpawns); - } - } - - private bool CanStillSpawn() - { - return spawnCount != 0; - } - - private bool WillSpawnInfinite() - { - return spawnCount == -1; - } - - public virtual BallGoal SpawnNewGoal(int listID) - { - Vector3 spawnPos = variableSpawnPosition ? CalculateSpawnPosition() : defaultSpawnPosition; - - BallGoal newGoal = (BallGoal)Instantiate(spawnObjects[listID], transform.position + spawnPos, Quaternion.identity); - AB.AddToGoodGoalsMultiSpawned(newGoal); - newGoal.transform.parent = transform; - - if (variableSize) - SetVariableSize(newGoal); - - TrainingAgent agent = FindObjectOfType(); - if (agent != null) - { - agent.RecordDispensedRewardType(newGoal.rewardType); // Track the dispensed reward type - agent.RecordDispensedReward(); // Track if a reward was dispensed (no matter the type) - } - else - { - Debug.LogError("Training Agent not found in the scene."); - } - - return newGoal; - } - - // Calculate spawn position - private Vector3 CalculateSpawnPosition() - { - float phi = (float)(RNGs[(int)E.ANGLE].NextDouble() * 2 * Math.PI); - float theta = (float)((RNGs[(int)E.ANGLE].NextDouble() * 0.6f + 0.2f) * Math.PI); - return defaultSpawnPosition + SphericalToCartesian(sphericalSpawnRadius, theta, phi); - } - - // Set variable size for a goal - private void SetVariableSize(BallGoal goal) - { - float sizeNoise = (float)(RNGs[(int)E.SIZE].NextDouble() - 0.5f) * 0.5f; - goal.sizeMax = Vector3.one * (ripenedSpawnSize + 0.25f); - goal.sizeMin = Vector3.one * (initialSpawnSize - 0.25f); - goal.gameObject.GetComponent().useGravity = false; - goal.gameObject.GetComponent().isKinematic = true; - goal.enabled = true; - } - - // Convert spherical coordinates to cartesian - private Vector3 SphericalToCartesian(float r, float theta, float phi) - { - float sin_theta = Mathf.Sin(theta); - return new Vector3(r * Mathf.Cos(phi) * sin_theta, r * Mathf.Cos(theta), r * Mathf.Sin(phi) * sin_theta); - } - - // Manage the entire life cycle of a spawned object - private IEnumerator ManageSingleSpawnLifeCycle(BallGoal newGoal, float sizeNoise = 0) - { - float dt = 0f; - float newSize; - - while (dt < timeToRipen && newGoal != null) - { - newSize = Mathf.Clamp(Interpolate(0, timeToRipen, dt, initialSpawnSize + sizeNoise, ripenedSpawnSize + sizeNoise), initialSpawnSize, ripenedSpawnSize); - newGoal.SetSize(Vector3.one * newSize); - dt += Time.deltaTime; - yield return null; - } - - if (newGoal != null) - { - newGoal.SetSize(Vector3.one * ripenedSpawnSize); - newGoal.gameObject.GetComponent().useGravity = true; - newGoal.gameObject.GetComponent().isKinematic = false; - } - } - - // Interpolate between two values - public float Interpolate(float tLo, float tHi, float t, float sLo, float sHi) - { - t = Mathf.Clamp(t, tLo, tHi); - float p = (t - tLo) / (tHi - tLo); - return sHi * p + sLo * (1 - p); - } + [Header("Spawning Parameters")] + public BallGoal[] spawnObjects; + public float initialSpawnSize; + public float ripenedSpawnSize; + public bool variableSize; + public bool variableSpawnPosition; + public float sphericalSpawnRadius; + public Vector3 defaultSpawnPosition; + public float timeToRipen; // Seconds + public float timeBetweenSpawns; // Seconds + public float delaySeconds; // Seconds + public int spawnCount; // '-1' = infinite spawning + + [ColorUsage(true, true)] + private Color colourOverride; + + // Random Seeds + public int objSpawnSeed = 0; + public int spawnSizeSeed = 0; + + // RNGs + private System.Random[] RNGs = new System.Random[4]; + + private enum E + { + OBJECT = 0, + SIZE = 1, + ANGLE = 2 + } + + private float height; + private ArenaBuilder AB; + private bool spawnsRandomObjects; + + private static int spawnerCounter = 0; + public int spawnerID; + public Vector3 spawnerPosition; + + public virtual void Awake() + { + InitializeParameters(); + StartCoroutine(StartSpawning()); + spawnerID = ++spawnerCounter; + spawnerPosition = transform.position; + } + + private void InitializeParameters() + { + typicalOrigin = false; + sizeMin = sizeMax = Vector3Int.one; + canRandomizeColor = false; + ratioSize = Vector3Int.one; + + height = GetComponent().bounds.size.y; + AB = transform.parent.parent.GetComponent().Builder; + + spawnsRandomObjects = (spawnObjects.Length > 1); + + if (spawnsRandomObjects) + RNGs[(int)E.OBJECT] = new System.Random(objSpawnSeed); + + if (variableSize) + RNGs[(int)E.SIZE] = new System.Random(spawnSizeSeed); + + if (variableSpawnPosition) + RNGs[(int)E.ANGLE] = new System.Random(1); + + if (timeToRipen <= 0) + initialSpawnSize = ripenedSpawnSize; + } + + private IEnumerator StartSpawning() + { + yield return new WaitForSeconds(delaySeconds); + + while (CanStillSpawn()) + { + BallGoal newGoal = SpawnNewGoal(0); + StartCoroutine( + ManageSingleSpawnLifeCycle( + newGoal, + variableSize ? (newGoal.reward - initialSpawnSize) : 0 + ) + ); + + if (!WillSpawnInfinite()) + spawnCount--; + + yield return new WaitForSeconds(timeBetweenSpawns); + } + } + + private bool CanStillSpawn() + { + return spawnCount != 0; + } + + private bool WillSpawnInfinite() + { + return spawnCount == -1; + } + + public virtual BallGoal SpawnNewGoal(int listID) + { + Vector3 spawnPos = variableSpawnPosition ? CalculateSpawnPosition() : defaultSpawnPosition; + + BallGoal newGoal = (BallGoal)Instantiate( + spawnObjects[listID], + transform.position + spawnPos, + Quaternion.identity + ); + AB.AddToGoodGoalsMultiSpawned(newGoal); + newGoal.transform.parent = transform; + + if (variableSize) + SetVariableSize(newGoal); + + TrainingAgent agent = FindObjectOfType(); + if (agent != null) + { + string combinedSpawnerInfo = + $"SpawnerID:{spawnerID},Position:{transform.position.x},{transform.position.y},{transform.position.z},RewardType:{newGoal.rewardType}"; + agent.RecordSpawnerInfo(combinedSpawnerInfo); + agent.RecordDispensedRewardType(newGoal.rewardType); + agent.RecordDispensedReward(); + } + else + { + Debug.LogError("Training Agent not found in the scene."); + } + + return newGoal; + } + + private Vector3 CalculateSpawnPosition() + { + float phi = (float)(RNGs[(int)E.ANGLE].NextDouble() * 2 * Math.PI); + float theta = (float)((RNGs[(int)E.ANGLE].NextDouble() * 0.6f + 0.2f) * Math.PI); + return defaultSpawnPosition + SphericalToCartesian(sphericalSpawnRadius, theta, phi); + } + + private void SetVariableSize(BallGoal goal) + { + float sizeNoise = (float)(RNGs[(int)E.SIZE].NextDouble() - 0.5f) * 0.5f; + goal.sizeMax = Vector3.one * (ripenedSpawnSize + 0.25f); + goal.sizeMin = Vector3.one * (initialSpawnSize - 0.25f); + goal.gameObject.GetComponent().useGravity = false; + goal.gameObject.GetComponent().isKinematic = true; + goal.enabled = true; + } + + private Vector3 SphericalToCartesian(float r, float theta, float phi) + { + float sin_theta = Mathf.Sin(theta); + return new Vector3( + r * Mathf.Cos(phi) * sin_theta, + r * Mathf.Cos(theta), + r * Mathf.Sin(phi) * sin_theta + ); + } + + private IEnumerator ManageSingleSpawnLifeCycle(BallGoal newGoal, float sizeNoise = 0) + { + float dt = 0f; + float newSize; + + while (dt < timeToRipen && newGoal != null) + { + newSize = Mathf.Clamp( + Interpolate( + 0, + timeToRipen, + dt, + initialSpawnSize + sizeNoise, + ripenedSpawnSize + sizeNoise + ), + initialSpawnSize, + ripenedSpawnSize + ); + newGoal.SetSize(Vector3.one * newSize); + dt += Time.deltaTime; + yield return null; + } + + if (newGoal != null) + { + newGoal.SetSize(Vector3.one * ripenedSpawnSize); + newGoal.gameObject.GetComponent().useGravity = true; + newGoal.gameObject.GetComponent().isKinematic = false; + } + } + + public float Interpolate(float tLo, float tHi, float t, float sLo, float sHi) + { + t = Mathf.Clamp(t, tLo, tHi); + float p = (t - tLo) / (tHi - tLo); + return sHi * p + sLo * (1 - p); + } } From 0901f2012f6116d2d7274a666ba70176decdd583 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 23 Jul 2024 19:58:26 +0300 Subject: [PATCH 109/205] added new column: combined spawner data which includes ID, position of spawn, and reward dispensed (if any). Also works with spawnerbutton --- Assets/Scripts/TrainingAgent.cs | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index b51c0e67..0230b88e 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -75,6 +75,19 @@ public class TrainingAgent : Agent, IPrefab private string wasInDataZone = "No"; private bool wasRewardDispensed = false; private bool wasButtonPressed = false; + private string combinedSpawnerInfo = ""; + + public void RecordSpawnerInfo(string spawnerInfo) + { + if (string.IsNullOrEmpty(combinedSpawnerInfo)) + { + combinedSpawnerInfo = spawnerInfo; + } + else + { + combinedSpawnerInfo += $"|{spawnerInfo}"; + } + } public void OnInDataZone(string zoneLogString) { @@ -175,7 +188,7 @@ private void InitialiseCSVProcess() if (!headerWritten) { writer.WriteLine( - "Episode,Step,Reward,CollectedRewardType,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate,ActionForwardDescription,ActionRotateDescription,IsFrozen?,NotificationState,DispensedRewardType,WasRewardDispensed?,WasButtonPressed?,CombinedRaycastData,WasInDataZone?" + "Episode,Step,Reward,CollectedRewardType,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate,ActionForwardDescription,ActionRotateDescription,IsFrozen?,NotificationState,DispensedRewardType,WasRewardDispensed?,WasButtonPressed?,CombinedRaycastData,WasInDataZone?,CombinedSpawnerInfo" ); headerWritten = true; } @@ -209,11 +222,12 @@ private void LogToCSV( bool wasRewardDispensed, bool wasButtonPressed, string combinedRaycastData, - string wasInDataZone + string wasInDataZone, + string combinedSpawnerInfo ) { string logEntry = - $"{customEpisodeCount},{StepCount},{reward},{lastCollectedRewardType},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate},{actionForwardDescription},{actionRotateDescription},{isFrozen},{notificationState},{dispensedRewardType},{wasRewardDispensed},{wasButtonPressed},{combinedRaycastData},{wasInDataZone}"; + $"{customEpisodeCount},{StepCount},{reward},{lastCollectedRewardType},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate},{actionForwardDescription},{actionRotateDescription},{isFrozen},{notificationState},{dispensedRewardType},{wasRewardDispensed},{wasButtonPressed},{combinedRaycastData},{wasInDataZone},{combinedSpawnerInfo.Replace(",", ";")}"; logQueue.Enqueue(logEntry); lastCollectedRewardType = "None"; } @@ -228,7 +242,7 @@ private void FlushLogQueue() writer.WriteLine(logEntry); } writer.Flush(); - Debug.Log("Flushed log queue to CSV file."); + Debug.Log("Flush initiated. Flushed log queue to CSV file."); } /// @@ -360,12 +374,14 @@ public override void CollectObservations(VectorSensor sensor) wasRewardDispensed, wasButtonPressed, combinedRaycastData, - wasInDataZone + wasInDataZone, + combinedSpawnerInfo // Pass the combined spawner info ); dispensedRewardType = "None"; wasRewardDispensed = false; wasButtonPressed = false; wasInDataZone = "No"; + combinedSpawnerInfo = ""; // Reset after logging } public override void OnActionReceived(ActionBuffers action) @@ -404,12 +420,14 @@ public override void OnActionReceived(ActionBuffers action) wasRewardDispensed, wasButtonPressed, combinedRaycastData, - wasInDataZone + wasInDataZone, + combinedSpawnerInfo ); dispensedRewardType = "None"; wasRewardDispensed = false; wasButtonPressed = false; wasInDataZone = "No"; + combinedSpawnerInfo = ""; // Reset after logging UpdateHealth(_rewardPerStep); } From b714bb5ce9a37a24b64850955b1861b2a3f885ce Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 23 Jul 2024 20:08:02 +0300 Subject: [PATCH 110/205] removed debug log --- Assets/Scripts/ArenaBuilders.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Assets/Scripts/ArenaBuilders.cs b/Assets/Scripts/ArenaBuilders.cs index affd4367..a6f5fa6a 100644 --- a/Assets/Scripts/ArenaBuilders.cs +++ b/Assets/Scripts/ArenaBuilders.cs @@ -610,7 +610,6 @@ private void SpawnAgent(Spawnable agentSpawnableFromUser) _agent.transform.rotation = Quaternion.Euler(agentToSpawnPosRot.Rotation); AnimalSkinManager ASM = _agent.GetComponentInChildren(); - Debug.Log("Setting AnimalSkin with ASM: " + ASM.ToString() + " and skin: " + skin); ASM.SetAnimalSkin(skin); _agent.GetComponent().SetFreezeDelay(freezeDelay); } From ecf64ad355455298cef862a8d06631446e1868d2 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 23 Jul 2024 20:09:37 +0300 Subject: [PATCH 111/205] removed debug logs --- Assets/Scripts/AAI3EnvironmentManager.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Assets/Scripts/AAI3EnvironmentManager.cs b/Assets/Scripts/AAI3EnvironmentManager.cs index dcc4bbb3..67b66e13 100644 --- a/Assets/Scripts/AAI3EnvironmentManager.cs +++ b/Assets/Scripts/AAI3EnvironmentManager.cs @@ -81,7 +81,6 @@ public void Awake() int decisionPeriod = environmentParameters.TryGetValue("decisionPeriod", out paramValue) ? paramValue : defaultDecisionPeriod; - Debug.Log("Set playermode to " + playerMode); if (Application.isEditor) { @@ -263,7 +262,6 @@ private Dictionary RetrieveEnvironmentParameters() { Dictionary environmentParameters = new Dictionary(); string[] args = System.Environment.GetCommandLineArgs(); - Debug.Log("Command Line Args: " + String.Join(" ", args)); for (int i = 0; i < args.Length; i++) { From 5705c136f8801508df66ff2092df2a9008ca1ea1 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 23 Jul 2024 20:15:11 +0300 Subject: [PATCH 112/205] updated script to log counter and return spawnerbutton details the yaml positions and unity positions have a discrepancy (unity has physics calculations which deviate a bit from yaml coordinates, a few decimal points so a minor problem) --- .../Spawners/Spawner_InteractiveButton.cs | 534 +++++++++--------- 1 file changed, 277 insertions(+), 257 deletions(-) diff --git a/Assets/Scripts/Spawners/Spawner_InteractiveButton.cs b/Assets/Scripts/Spawners/Spawner_InteractiveButton.cs index 11fe70dd..34c32fab 100644 --- a/Assets/Scripts/Spawners/Spawner_InteractiveButton.cs +++ b/Assets/Scripts/Spawners/Spawner_InteractiveButton.cs @@ -5,264 +5,284 @@ using ArenaBuilders; /// -/// Spawns a reward when interacted with. The reward is chosen from a list of rewards with weights. +/// Spawns a reward when interacted with. The reward is chosen from a list of rewards with weights and spawn probabilities. +/// The reward can be spawned at a fixed position or randomly within the arena bounds. /// public class Spawner_InteractiveButton : MonoBehaviour { - public List RewardNames { get; set; } - public List RewardWeights { get; set; } - public List Rewards { get; set; } - public Vector3 RewardSpawnPos { get; set; } - public List MaxRewardCounts { get; set; } - public int ButtonPressCount { get; private set; } - public GameObject LastSpawnedReward { get; private set; } - public float SpawnProbability { get; set; } = 1f; - private List rewardWeights; - public Dictionary RewardSpawnCounts { get; private set; } = - new Dictionary(); - private bool IsMoving = false; - private float lastInteractionTime; - private float totalInteractionInterval = 0f; - private float _moveDuration; - private float _resetDuration; - - private ArenaBuilder arenaBuilder; - public delegate void OnRewardSpawned(GameObject reward); - public static event OnRewardSpawned RewardSpawned; - - [SerializeField] - private GameObject childObjectToMove; - - [SerializeField] - private Vector3 moveOffset; - - [SerializeField] - private Transform rewardSpawnPoint; - - public float MoveDuration - { - get { return _moveDuration; } - set { _moveDuration = value; } - } - public float ResetDuration - { - get { return _resetDuration; } - set { _resetDuration = value; } - } - - void Start() - { - lastInteractionTime = Time.time; - - if (RewardNames != null && RewardNames.Count > 0) - { - Rewards = RewardNames - .Select(name => - { - GameObject reward = Resources.Load(name); - if (reward == null) - { - Debug.LogError($"Failed to load reward: {name}"); - } - return reward; - }) - .ToList(); - } - - rewardWeights = RewardWeights; - } - - private void OnTriggerEnter(Collider other) - { - if (other.CompareTag("agent")) - { - if (IsMoving) - { - return; - } - - ButtonPressCount++; - StartCoroutine(MoveAndReset()); - RewardSpawned?.Invoke(null); - } - } - - public bool MoveToTarget(Vector3 origin, Vector3 target, float startTime, float duration) - { - float t = (Time.time - startTime) / duration; - childObjectToMove.transform.position = Vector3.Lerp(origin, target, t); - return Time.time < startTime + duration; - } - - public IEnumerator MoveAndReset() - { - IsMoving = true; - - Vector3 originalPosition = childObjectToMove.transform.position; - Vector3 movementDirection = -transform.forward * moveOffset.x; // Use parent object's negative local Z axis - Vector3 targetPosition = originalPosition + movementDirection; - float startTime = Time.time; - - while (MoveToTarget(originalPosition, targetPosition, startTime, MoveDuration)) - { - yield return null; - } - childObjectToMove.transform.position = targetPosition; - - startTime = Time.time; - while (MoveToTarget(targetPosition, originalPosition, startTime, ResetDuration)) - { - yield return null; - } - childObjectToMove.transform.position = originalPosition; - - SpawnReward(); - - IsMoving = false; - } - - private GameObject ChooseReward() - { - if (Rewards == null || rewardWeights == null || Rewards.Count != rewardWeights.Count) - { - Debug.LogError("Invalid rewards or reward weights setup."); - return null; - } - - float totalWeight = rewardWeights.Sum(); - float randomNumber = Random.Range(0, totalWeight - float.Epsilon); - float cumulativeWeight = 0; - - for (int i = 0; i < Rewards.Count; i++) - { - cumulativeWeight += rewardWeights[i]; - if (randomNumber <= cumulativeWeight) - { - return Rewards[i]; - } - } - - // If no reward is selected within the loop (which should not happen), return the last reward - return Rewards[Rewards.Count - 1]; - } - - private void SpawnReward() - { - GameObject rewardToSpawn = ChooseReward(); - - if (rewardToSpawn == null) - { - Debug.LogError("Failed to choose a reward to spawn."); - return; - } - - int rewardIndex = Rewards.IndexOf(rewardToSpawn); - if (rewardIndex == -1) - { - Debug.LogError("Chosen reward is not in the Rewards list."); - return; - } - - if (rewardIndex < MaxRewardCounts.Count) - { - Debug.Log( - "Max allowed spawns for " + rewardToSpawn.name + ": " + MaxRewardCounts[rewardIndex] - ); - } - else - { - Debug.Log("No max spawn count set for " + rewardToSpawn.name); - } - - if ( - MaxRewardCounts != null - && rewardIndex < MaxRewardCounts.Count - && MaxRewardCounts[rewardIndex] != -1 - ) - { - if ( - RewardSpawnCounts.TryGetValue(rewardToSpawn, out var count) - && count >= MaxRewardCounts[rewardIndex] - ) - { - Debug.Log("Max reward count reached for reward: " + rewardToSpawn.name); - return; - } - } - - if (Rewards == null || Rewards.Count == 0) - { - Debug.LogError("No rewards are set to be spawned."); - return; - } - - if (Random.value <= SpawnProbability) - { - Vector3 spawnPosition = rewardSpawnPoint.position; - - if (RewardSpawnPos != Vector3.zero) - { - spawnPosition = RewardSpawnPos; - } - // Otherwise, random spawning. - else - { - float arenaWidth = arenaBuilder.ArenaWidth; - float arenaDepth = arenaBuilder.ArenaDepth; - - // Randomly generate a spawn position within the bounds of the arena, as defined by Arenabuilders.cs. - spawnPosition = new Vector3( - Random.Range(0, arenaWidth), - 0, - Random.Range(0, arenaDepth) - ); - } - // Check for randomization flags for x and z axes - if (RewardSpawnPos.x == -1) - { - spawnPosition.x = Random.Range(0, arenaBuilder.ArenaWidth); - } - - if (RewardSpawnPos.y == -1) - { - spawnPosition.y = Random.Range(0, 50); - Debug.Log("Randomized y: " + spawnPosition.y); - } - else - { - spawnPosition.y = RewardSpawnPos.y; - Debug.Log("Set y to: " + spawnPosition.y); - } - - if (RewardSpawnPos.z == -1) - { - spawnPosition.z = Random.Range(0, arenaBuilder.ArenaDepth); - } - - LastSpawnedReward = Instantiate(rewardToSpawn, spawnPosition, Quaternion.identity); - - if (RewardSpawnCounts.TryGetValue(rewardToSpawn, out var count)) - { - RewardSpawnCounts[rewardToSpawn] = count + 1; - } - else - { - RewardSpawnCounts[rewardToSpawn] = 1; - } - - float currentInteractionTime = Time.time; - totalInteractionInterval += currentInteractionTime - lastInteractionTime; - lastInteractionTime = currentInteractionTime; - - RewardSpawned?.Invoke(LastSpawnedReward); - } - } - - public float GetAverageInteractionInterval() - { - if (ButtonPressCount == 0) - return 0; - - return totalInteractionInterval / ButtonPressCount; - } + public List RewardNames { get; set; } + public List RewardWeights { get; set; } + public List Rewards { get; set; } + public Vector3 RewardSpawnPos { get; set; } + public List MaxRewardCounts { get; set; } + public int ButtonPressCount { get; private set; } + public GameObject LastSpawnedReward { get; private set; } + public float SpawnProbability { get; set; } = 1f; + private List rewardWeights; + public Dictionary RewardSpawnCounts { get; private set; } = + new Dictionary(); + private bool IsMoving = false; + private float lastInteractionTime; + private float totalInteractionInterval = 0f; + private float _moveDuration; + private float _resetDuration; + + private ArenaBuilder arenaBuilder; + public delegate void OnRewardSpawned(GameObject reward); + public static event OnRewardSpawned RewardSpawned; + + [SerializeField] + private GameObject childObjectToMove; + + [SerializeField] + private Vector3 moveOffset; + + [SerializeField] + private Transform rewardSpawnPoint; + + private static int spawnerCounter = 0; + public int spawnerID; + private Vector3 initialPosition; + + public float MoveDuration + { + get { return _moveDuration; } + set { _moveDuration = value; } + } + public float ResetDuration + { + get { return _resetDuration; } + set { _resetDuration = value; } + } + + void Start() + { + spawnerID = ++spawnerCounter; + lastInteractionTime = Time.time; + + if (RewardNames != null && RewardNames.Count > 0) + { + Rewards = RewardNames + .Select(name => + { + GameObject reward = Resources.Load(name); + if (reward == null) + { + Debug.LogError($"Failed to load reward: {name}"); + } + return reward; + }) + .ToList(); + } + + rewardWeights = RewardWeights; + initialPosition = transform.position; + } + + private void OnTriggerEnter(Collider other) + { + if (other.CompareTag("agent")) + { + if (IsMoving) + { + return; + } + + ButtonPressCount++; + StartCoroutine(MoveAndReset()); + } + } + + public bool MoveToTarget(Vector3 origin, Vector3 target, float startTime, float duration) + { + float t = (Time.time - startTime) / duration; + childObjectToMove.transform.position = Vector3.Lerp(origin, target, t); + return Time.time < startTime + duration; + } + + public IEnumerator MoveAndReset() + { + IsMoving = true; + + Vector3 originalPosition = childObjectToMove.transform.position; + Vector3 movementDirection = -transform.forward * moveOffset.x; // Use parent object's negative local Z axis + Vector3 targetPosition = originalPosition + movementDirection; + float startTime = Time.time; + + while (MoveToTarget(originalPosition, targetPosition, startTime, MoveDuration)) + { + yield return null; + } + childObjectToMove.transform.position = targetPosition; + + startTime = Time.time; + while (MoveToTarget(targetPosition, originalPosition, startTime, ResetDuration)) + { + yield return null; + } + childObjectToMove.transform.position = originalPosition; + + SpawnReward(); + + TrainingAgent agent = FindObjectOfType(); + if (agent != null) + { + Vector3 spawnerPos = initialPosition; + string rewardType = + LastSpawnedReward != null ? LastSpawnedReward.name.Replace("(Clone)", "") : "None"; + string spawnerInfo = + $"SpawnerButtonID:{spawnerID}, Position:{spawnerPos.x},{spawnerPos.y},{spawnerPos.z}, RewardType:{rewardType}"; + Debug.Log($"Logging SpawnerButton Info: {spawnerInfo}"); + agent.RecordSpawnerInfo(spawnerInfo); + } + else + { + Debug.LogError("Training Agent not found in the scene."); + } + + IsMoving = false; + } + + private GameObject ChooseReward() + { + if (Rewards == null || rewardWeights == null || Rewards.Count != rewardWeights.Count) + { + Debug.LogError("Invalid rewards or reward weights setup."); + return null; + } + + float totalWeight = rewardWeights.Sum(); + float randomNumber = Random.Range(0, totalWeight - float.Epsilon); + float cumulativeWeight = 0; + + for (int i = 0; i < Rewards.Count; i++) + { + cumulativeWeight += rewardWeights[i]; + if (randomNumber <= cumulativeWeight) + { + return Rewards[i]; + } + } + + // If no reward is selected within the loop (which should not happen), return the last reward + return Rewards[Rewards.Count - 1]; + } + + private void SpawnReward() + { + GameObject rewardToSpawn = ChooseReward(); + + if (rewardToSpawn == null) + { + Debug.LogError("Failed to choose a reward to spawn."); + return; + } + + int rewardIndex = Rewards.IndexOf(rewardToSpawn); + if (rewardIndex == -1) + { + Debug.LogError("Chosen reward is not in the Rewards list."); + return; + } + + if (rewardIndex < MaxRewardCounts.Count) + { + Debug.Log( + "Max allowed spawns for " + rewardToSpawn.name + ": " + MaxRewardCounts[rewardIndex] + ); + } + else + { + Debug.Log("No max spawn count set for " + rewardToSpawn.name); + } + + if ( + MaxRewardCounts != null + && rewardIndex < MaxRewardCounts.Count + && MaxRewardCounts[rewardIndex] != -1 + ) + { + if ( + RewardSpawnCounts.TryGetValue(rewardToSpawn, out var count) + && count >= MaxRewardCounts[rewardIndex] + ) + { + Debug.Log("Max reward count reached for reward: " + rewardToSpawn.name); + return; + } + } + + if (Rewards == null || Rewards.Count == 0) + { + Debug.LogError("No rewards are set to be spawned."); + return; + } + + if (Random.value <= SpawnProbability) + { + Vector3 spawnPosition = rewardSpawnPoint.position; + + if (RewardSpawnPos != Vector3.zero) + { + spawnPosition = RewardSpawnPos; + } + // Otherwise, random spawning. + else + { + float arenaWidth = arenaBuilder.ArenaWidth; + float arenaDepth = arenaBuilder.ArenaDepth; + + // Randomly generate a spawn position within the bounds of the arena, as defined by Arenabuilders.cs. + spawnPosition = new Vector3( + Random.Range(0, arenaWidth), + 0, + Random.Range(0, arenaDepth) + ); + } + // Check for randomization flags for x and z axes + if (RewardSpawnPos.x == -1) + { + spawnPosition.x = Random.Range(0, arenaBuilder.ArenaWidth); + } + + if (RewardSpawnPos.y == -1) + { + spawnPosition.y = Random.Range(0, 50); + } + else + { + spawnPosition.y = RewardSpawnPos.y; + } + + if (RewardSpawnPos.z == -1) + { + spawnPosition.z = Random.Range(0, arenaBuilder.ArenaDepth); + } + + LastSpawnedReward = Instantiate(rewardToSpawn, spawnPosition, Quaternion.identity); + + if (RewardSpawnCounts.TryGetValue(rewardToSpawn, out var count)) + { + RewardSpawnCounts[rewardToSpawn] = count + 1; + } + else + { + RewardSpawnCounts[rewardToSpawn] = 1; + } + + float currentInteractionTime = Time.time; + totalInteractionInterval += currentInteractionTime - lastInteractionTime; + lastInteractionTime = currentInteractionTime; + + RewardSpawned?.Invoke(LastSpawnedReward); + } + } + + public float GetAverageInteractionInterval() + { + if (ButtonPressCount == 0) + return 0; + + return totalInteractionInterval / ButtonPressCount; + } } From 6869f97e0c82cb19d8fad657b9fcc9e682e4a979 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 24 Jul 2024 11:58:32 +0300 Subject: [PATCH 113/205] added frozenAgentDelays param to example yaml for completeness --- Assets/Resources/test_configs/every_object_spawn_test.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Assets/Resources/test_configs/every_object_spawn_test.yaml b/Assets/Resources/test_configs/every_object_spawn_test.yaml index 0531192a..a7d91da9 100644 --- a/Assets/Resources/test_configs/every_object_spawn_test.yaml +++ b/Assets/Resources/test_configs/every_object_spawn_test.yaml @@ -10,6 +10,7 @@ arenas: positions: - !Vector3 {x: 2, y: 1, z: 2} # The position of the item. This is a Vector3 object with x, y, and z coordinates. Leave values for random spawning. rotations: [0] # The rotations of the items. It can be in any angle but default is 0 degrees. + frozenAgentDelays: [1] # The time in seconds the agent will be frozen at the start of the arena. This is useful for delayed start scenarios. # IMMOVABLE OBJECTS (Note: RAMP is immovable but has a special tag of "ramp" for the agent to detect). From 9de705c7df4a92e4a52a04015f64085b2c1f67ea Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 24 Jul 2024 11:59:11 +0300 Subject: [PATCH 114/205] changed isFrozen param name to WasAgentFrozen in .csv file for coherency --- Assets/Scripts/TrainingAgent.cs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 0230b88e..f7bfddbe 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -124,6 +124,11 @@ public void SetYamlFileName(string fileName) yamlFileName = fileName; } + private string CombineRaycastData(float[] observations, string[] tags) + { + return string.Join(";", observations.Zip(tags, (obs, tag) => $"{obs}:{tag}")); + } + public override void Initialize() { _arena = GetComponentInParent(); @@ -188,7 +193,7 @@ private void InitialiseCSVProcess() if (!headerWritten) { writer.WriteLine( - "Episode,Step,Reward,CollectedRewardType,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate,ActionForwardDescription,ActionRotateDescription,IsFrozen?,NotificationState,DispensedRewardType,WasRewardDispensed?,WasButtonPressed?,CombinedRaycastData,WasInDataZone?,CombinedSpawnerInfo" + "Episode,Step,Reward,CollectedRewardType,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate,ActionForwardDescription,ActionRotateDescription,WasAgentFrozen?,NotificationState,DispensedRewardType,WasRewardDispensed?,WasButtonPressed?,CombinedRaycastData,WasInDataZone?,CombinedSpawnerInfo" ); headerWritten = true; } @@ -199,11 +204,6 @@ private void InitialiseCSVProcess() } } - private string CombineRaycastData(float[] observations, string[] tags) - { - return string.Join(";", observations.Zip(tags, (obs, tag) => $"{obs}:{tag}")); - } - /// /// Logs the agent's state to a CSV file. This is called every step. The data is stored in a queue and flushed to the file in a separate thread. /// @@ -214,7 +214,7 @@ private void LogToCSV( int lastActionRotate, string actionForwardDescription, string actionRotateDescription, - bool isFrozen, + bool wasAgentFrozen, float reward, string notificationState, int customEpisodeCount, @@ -227,7 +227,7 @@ string combinedSpawnerInfo ) { string logEntry = - $"{customEpisodeCount},{StepCount},{reward},{lastCollectedRewardType},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate},{actionForwardDescription},{actionRotateDescription},{isFrozen},{notificationState},{dispensedRewardType},{wasRewardDispensed},{wasButtonPressed},{combinedRaycastData},{wasInDataZone},{combinedSpawnerInfo.Replace(",", ";")}"; + $"{customEpisodeCount},{StepCount},{reward},{lastCollectedRewardType},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate},{actionForwardDescription},{actionRotateDescription},{wasAgentFrozen},{notificationState},{dispensedRewardType},{wasRewardDispensed},{wasButtonPressed},{combinedRaycastData},{wasInDataZone},{combinedSpawnerInfo.Replace(",", ";")}"; logQueue.Enqueue(logEntry); lastCollectedRewardType = "None"; } @@ -345,7 +345,7 @@ public override void CollectObservations(VectorSensor sensor) sensor.AddObservation(health); Vector3 localVel = transform.InverseTransformDirection(_rigidBody.velocity); Vector3 localPos = transform.position; - bool isFrozen = IsFrozen(); + bool wasAgentFrozen = IsFrozen(); string actionForwardDescription = DescribeActionForward(lastActionForward); string actionRotateDescription = DescribeActionRotate(lastActionRotate); float reward = GetCumulativeReward(); @@ -366,7 +366,7 @@ public override void CollectObservations(VectorSensor sensor) lastActionRotate, actionForwardDescription, actionRotateDescription, - isFrozen, + wasAgentFrozen, reward, notificationState, customEpisodeCount, @@ -395,7 +395,7 @@ public override void OnActionReceived(ActionBuffers action) Vector3 localVel = transform.InverseTransformDirection(_rigidBody.velocity); Vector3 localPos = transform.position; - bool isFrozen = IsFrozen(); + bool wasAgentFrozen = IsFrozen(); string actionForwardDescription = DescribeActionForward(lastActionForward); string actionRotateDescription = DescribeActionRotate(lastActionRotate); float reward = GetCumulativeReward(); @@ -412,7 +412,7 @@ public override void OnActionReceived(ActionBuffers action) lastActionRotate, actionForwardDescription, actionRotateDescription, - isFrozen, + wasAgentFrozen, reward, notificationState, customEpisodeCount, From 7615d36d8a92d9bcef54d55f93ac66fe5d5eabac Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 24 Jul 2024 12:00:06 +0300 Subject: [PATCH 115/205] minor change in output log --- Assets/Scripts/Spawners/GoalSpawner.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/Scripts/Spawners/GoalSpawner.cs b/Assets/Scripts/Spawners/GoalSpawner.cs index 56342cca..cc8ecb8e 100644 --- a/Assets/Scripts/Spawners/GoalSpawner.cs +++ b/Assets/Scripts/Spawners/GoalSpawner.cs @@ -129,7 +129,7 @@ public virtual BallGoal SpawnNewGoal(int listID) if (agent != null) { string combinedSpawnerInfo = - $"SpawnerID:{spawnerID},Position:{transform.position.x},{transform.position.y},{transform.position.z},RewardType:{newGoal.rewardType}"; + $"SpawnerID:{spawnerID}, Position:{transform.position.x},{transform.position.y},{transform.position.z}, RewardType:{newGoal.rewardType}"; agent.RecordSpawnerInfo(combinedSpawnerInfo); agent.RecordDispensedRewardType(newGoal.rewardType); agent.RecordDispensedReward(); From baa30d89e45d27115063bb029aa28403c4b53d6a Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 24 Jul 2024 21:33:45 +0300 Subject: [PATCH 116/205] combined columns: action and rotation columns with their descriptions for a better representation and compact view. --- Assets/Scripts/TrainingAgent.cs | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index f7bfddbe..16457fd3 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -193,7 +193,7 @@ private void InitialiseCSVProcess() if (!headerWritten) { writer.WriteLine( - "Episode,Step,Reward,CollectedRewardType,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForward,ActionRotate,ActionForwardDescription,ActionRotateDescription,WasAgentFrozen?,NotificationState,DispensedRewardType,WasRewardDispensed?,WasButtonPressed?,CombinedRaycastData,WasInDataZone?,CombinedSpawnerInfo" + "Episode,Step,Reward,CollectedRewardType,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForwardWithDescription,ActionRotateWithDescription,WasAgentFrozen?,NotificationState,DispensedRewardType,WasRewardDispensed?,WasButtonPressed?,CombinedRaycastData,WasInDataZone?,CombinedSpawnerInfo" ); headerWritten = true; } @@ -210,10 +210,8 @@ private void InitialiseCSVProcess() private void LogToCSV( Vector3 velocity, Vector3 position, - int lastActionForward, - int lastActionRotate, - string actionForwardDescription, - string actionRotateDescription, + string actionForwardWithDescription, + string actionRotateWithDescription, bool wasAgentFrozen, float reward, string notificationState, @@ -227,7 +225,7 @@ string combinedSpawnerInfo ) { string logEntry = - $"{customEpisodeCount},{StepCount},{reward},{lastCollectedRewardType},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{lastActionForward},{lastActionRotate},{actionForwardDescription},{actionRotateDescription},{wasAgentFrozen},{notificationState},{dispensedRewardType},{wasRewardDispensed},{wasButtonPressed},{combinedRaycastData},{wasInDataZone},{combinedSpawnerInfo.Replace(",", ";")}"; + $"{customEpisodeCount},{StepCount},{reward},{lastCollectedRewardType},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{actionForwardWithDescription},{actionRotateWithDescription},{wasAgentFrozen},{notificationState},{dispensedRewardType},{wasRewardDispensed},{wasButtonPressed},{combinedRaycastData},{wasInDataZone},{combinedSpawnerInfo.Replace(",", ";")}"; logQueue.Enqueue(logEntry); lastCollectedRewardType = "None"; } @@ -348,6 +346,8 @@ public override void CollectObservations(VectorSensor sensor) bool wasAgentFrozen = IsFrozen(); string actionForwardDescription = DescribeActionForward(lastActionForward); string actionRotateDescription = DescribeActionRotate(lastActionRotate); + string actionForwardWithDescription = $"{lastActionForward} ({actionForwardDescription})"; + string actionRotateWithDescription = $"{lastActionRotate} ({actionRotateDescription})"; float reward = GetCumulativeReward(); string notificationState = GetNotificationState(); @@ -362,10 +362,8 @@ public override void CollectObservations(VectorSensor sensor) LogToCSV( localVel, localPos, - lastActionForward, - lastActionRotate, - actionForwardDescription, - actionRotateDescription, + actionForwardWithDescription, + actionRotateWithDescription, wasAgentFrozen, reward, notificationState, @@ -375,13 +373,13 @@ public override void CollectObservations(VectorSensor sensor) wasButtonPressed, combinedRaycastData, wasInDataZone, - combinedSpawnerInfo // Pass the combined spawner info + combinedSpawnerInfo ); dispensedRewardType = "None"; wasRewardDispensed = false; wasButtonPressed = false; wasInDataZone = "No"; - combinedSpawnerInfo = ""; // Reset after logging + combinedSpawnerInfo = ""; } public override void OnActionReceived(ActionBuffers action) @@ -398,6 +396,8 @@ public override void OnActionReceived(ActionBuffers action) bool wasAgentFrozen = IsFrozen(); string actionForwardDescription = DescribeActionForward(lastActionForward); string actionRotateDescription = DescribeActionRotate(lastActionRotate); + string actionForwardWithDescription = $"{lastActionForward} ({actionForwardDescription})"; + string actionRotateWithDescription = $"{lastActionRotate} ({actionRotateDescription})"; float reward = GetCumulativeReward(); string notificationState = GetNotificationState(); @@ -408,10 +408,8 @@ public override void OnActionReceived(ActionBuffers action) LogToCSV( localVel, localPos, - lastActionForward, - lastActionRotate, - actionForwardDescription, - actionRotateDescription, + actionForwardWithDescription, + actionRotateWithDescription, wasAgentFrozen, reward, notificationState, @@ -427,7 +425,7 @@ public override void OnActionReceived(ActionBuffers action) wasRewardDispensed = false; wasButtonPressed = false; wasInDataZone = "No"; - combinedSpawnerInfo = ""; // Reset after logging + combinedSpawnerInfo = ""; UpdateHealth(_rewardPerStep); } From b7c6730f9ecd9ea4944f883c0aa5bf5687ae2aba Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 24 Jul 2024 21:45:08 +0300 Subject: [PATCH 117/205] minor column header changes: renamed wasButtonPressed to wasSpawnerButtonTriggered and wasInDatazone to wasAgentInDataZone for a more informative and strict column headers --- Assets/Scripts/TrainingAgent.cs | 35 +++++++++++++++++---------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 16457fd3..d8823228 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -72,9 +72,9 @@ public class TrainingAgent : Agent, IPrefab private bool isFlushing = false; private string lastCollectedRewardType = "None"; private string dispensedRewardType = "None"; - private string wasInDataZone = "No"; + private string wasAgentInDataZone = "No"; private bool wasRewardDispensed = false; - private bool wasButtonPressed = false; + private bool wasSpawnerButtonTriggered = false; private string combinedSpawnerInfo = ""; public void RecordSpawnerInfo(string spawnerInfo) @@ -91,17 +91,17 @@ public void RecordSpawnerInfo(string spawnerInfo) public void OnInDataZone(string zoneLogString) { - wasInDataZone = "Agent was in DataZone: " + zoneLogString; + wasAgentInDataZone = "Agent was in DataZone: " + zoneLogString; } public void OnOutDataZone(string zoneLogString) { - wasInDataZone = "Agent left DataZone: " + zoneLogString; + wasAgentInDataZone = "Agent left DataZone: " + zoneLogString; } private void OnRewardSpawned(GameObject reward) { - wasButtonPressed = true; + wasSpawnerButtonTriggered = true; } public void RecordDispensedReward() @@ -193,7 +193,7 @@ private void InitialiseCSVProcess() if (!headerWritten) { writer.WriteLine( - "Episode,Step,Reward,CollectedRewardType,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForwardWithDescription,ActionRotateWithDescription,WasAgentFrozen?,NotificationState,DispensedRewardType,WasRewardDispensed?,WasButtonPressed?,CombinedRaycastData,WasInDataZone?,CombinedSpawnerInfo" + "Episode,Step,Reward,CollectedRewardType,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForwardWithDescription,ActionRotateWithDescription,WasAgentFrozen?,NotificationState,DispensedRewardType,WasRewardDispensed?,WasSpawnerButtonTriggered?,CombinedRaycastData,WasAgentInDatazone?,CombinedSpawnerInfo" ); headerWritten = true; } @@ -218,14 +218,14 @@ private void LogToCSV( int customEpisodeCount, string dispensedRewardType, bool wasRewardDispensed, - bool wasButtonPressed, + bool wasSpawnerButtonTriggered, string combinedRaycastData, - string wasInDataZone, + string wasAgentInDataZone, string combinedSpawnerInfo ) { string logEntry = - $"{customEpisodeCount},{StepCount},{reward},{lastCollectedRewardType},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{actionForwardWithDescription},{actionRotateWithDescription},{wasAgentFrozen},{notificationState},{dispensedRewardType},{wasRewardDispensed},{wasButtonPressed},{combinedRaycastData},{wasInDataZone},{combinedSpawnerInfo.Replace(",", ";")}"; + $"{customEpisodeCount},{StepCount},{reward},{lastCollectedRewardType},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{actionForwardWithDescription},{actionRotateWithDescription},{wasAgentFrozen},{notificationState},{dispensedRewardType},{wasRewardDispensed},{wasSpawnerButtonTriggered},{combinedRaycastData},{wasAgentInDataZone},{combinedSpawnerInfo.Replace(",", ";")}"; logQueue.Enqueue(logEntry); lastCollectedRewardType = "None"; } @@ -370,15 +370,15 @@ public override void CollectObservations(VectorSensor sensor) customEpisodeCount, dispensedRewardType, wasRewardDispensed, - wasButtonPressed, + wasSpawnerButtonTriggered, combinedRaycastData, - wasInDataZone, + wasAgentInDataZone, combinedSpawnerInfo ); dispensedRewardType = "None"; wasRewardDispensed = false; - wasButtonPressed = false; - wasInDataZone = "No"; + wasSpawnerButtonTriggered = false; + wasAgentInDataZone = "No"; combinedSpawnerInfo = ""; } @@ -386,6 +386,7 @@ public override void OnActionReceived(ActionBuffers action) { lastActionForward = Mathf.FloorToInt(action.DiscreteActions[0]); lastActionRotate = Mathf.FloorToInt(action.DiscreteActions[1]); + if (!IsFrozen()) { MoveAgent(lastActionForward, lastActionRotate); @@ -416,15 +417,15 @@ public override void OnActionReceived(ActionBuffers action) customEpisodeCount, dispensedRewardType, wasRewardDispensed, - wasButtonPressed, + wasSpawnerButtonTriggered, combinedRaycastData, - wasInDataZone, + wasAgentInDataZone, combinedSpawnerInfo ); dispensedRewardType = "None"; wasRewardDispensed = false; - wasButtonPressed = false; - wasInDataZone = "No"; + wasSpawnerButtonTriggered = false; + wasAgentInDataZone = "No"; combinedSpawnerInfo = ""; UpdateHealth(_rewardPerStep); From 13f7004758670377f42983bbb2a7f99cc1a8138b Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 24 Jul 2024 21:49:53 +0300 Subject: [PATCH 118/205] minor comments clean up --- Assets/Scripts/TrainingAgent.cs | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index d8823228..d58cf0aa 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -172,10 +172,8 @@ private void InitialiseCSVProcess() basePath = Path.GetDirectoryName(Application.dataPath); } - // Folder for the CSV logs string directoryPath = Path.Combine(basePath, "ObservationLogs"); - // Simple check to see if the directory exists, if not create it if (!Directory.Exists(directoryPath)) { Directory.CreateDirectory(directoryPath); @@ -259,13 +257,14 @@ private void StartFlushThread() FlushLogQueue(); isFlushing = false; } - Thread.Sleep(100); // polls every 100ms to check if the queue is full. This is to prevent the thread from running continuously and hogging resources. + Thread.Sleep(100); // polls every 100ms to check if the queue is full to prevent the thread from running continuously and hogging resources } }).Start(); } /// - /// OnDisable is called when the training session is stopped form mlagents. It closes the CSV file and flushes the log queue at whatever the current size is. + /// OnDisable is called when the training session is stopped form mlagents. + /// It closes the CSV file and flushes the log queue at whatever the current size is. /// protected override void OnDisable() { @@ -546,6 +545,7 @@ public override void Heuristic(in ActionBuffers actionsOut) public void UpdateHealthNextStep(float updateAmount, bool andCompleteArena = false) { /* + IMPORTANT! ML-Agents doesn't guarantee behaviour if an episode ends outside of OnActionReceived Therefore we queue any health updates to happen on the next action step. */ @@ -558,7 +558,6 @@ Therefore we queue any health updates to happen on the next action step. public void UpdateHealth(float updateAmount, bool andCompleteArena = false) { - // Update the health of the agent and reset any queued updates if (!IsFrozen()) { health += 100 * updateAmount; @@ -596,9 +595,6 @@ public void UpdateHealth(float updateAmount, bool andCompleteArena = false) bool proceedToNext = Arena.CurrentPassMark == 0 || cumulativeReward >= Arena.CurrentPassMark; - Debug.Log( - $"Proceed to next arena: {proceedToNext}, Merge next arena: {_arena.mergeNextArena}" - ); if (proceedToNext) { @@ -663,7 +659,6 @@ public override void OnEpisodeBegin() health = _maxHealth; SetFreezeDelay(GetFreezeDelay()); - Debug.Log("Agent state reset in OnEpisodeBegin."); } public void AddExtraReward(float rewardFactor) @@ -715,9 +710,6 @@ void OnCollisionExit(Collision collision) //PREFAB INTERFACE FOR THE AGENT //****************************** - /// - /// Sets the colour and size of the agent. Not used in this implementation. - /// public void SetColor(Vector3 color) { } public void SetSize(Vector3 scale) { } @@ -748,7 +740,7 @@ float rangeZ } /// - /// If rotationY set to < 0 change to random rotation. + /// If rotationY set to < 0, then change to random rotation. /// public virtual Vector3 GetRotation(float rotationY) { From 2c27aa9af3022a4fd5b57f4ff527d8a3f0b93559 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 24 Jul 2024 21:53:38 +0300 Subject: [PATCH 119/205] added datazone item to ZONES section --- .../test_configs/every_object_spawn_test.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Assets/Resources/test_configs/every_object_spawn_test.yaml b/Assets/Resources/test_configs/every_object_spawn_test.yaml index a7d91da9..a7b29b7f 100644 --- a/Assets/Resources/test_configs/every_object_spawn_test.yaml +++ b/Assets/Resources/test_configs/every_object_spawn_test.yaml @@ -5,6 +5,7 @@ arenas: passMark: 0 # The pass mark for the arena. The agent must achieve this score to pass the arena. timeLimit: 250 # The time limit for the arena in seconds. In other words, the time limit for the agent to complete the task (the arena resets after this time). items: # This line indicates the start of the items list +# AGENT - !Item name: Agent # Note that the agent will always be spawned first regardless of its position in the configuration. positions: @@ -266,6 +267,7 @@ arenas: - !Vector3 {x: 1, y: 1, z: 1} # ZONES + - !Item name: HotZone positions: @@ -280,3 +282,13 @@ arenas: sizes: - !Vector3 {x: 1, y: 1, z: 1} + - !Item + name: DataZone + positions: + - !Vector3 {x: 20, y: 0, z: 20} + sizes: + - !Vector3 {x: 5, y: 0, z: 5} + zoneVisibility: true # Whether the zone is visible or not. If false, the zone will be invisible. True by default + triggerZoneID: ["Agent entered Datazone located in the center of the arena."] # The message that will be displayed when the agent enters the zone. + + From a06ea1deba7a793012113bfc6ee848c20150c75b Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Thu, 25 Jul 2024 00:25:20 +0300 Subject: [PATCH 120/205] IMPORTANT reordered columns and tidied code discovered that the 1st step is duplicated so removed call to logtocsv method from collectobservations method (now only called from onactionreceived method) to fix this. --- Assets/Scripts/TrainingAgent.cs | 74 ++++++++++++++++----------------- 1 file changed, 35 insertions(+), 39 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index d58cf0aa..4c1cf7b1 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -191,7 +191,7 @@ private void InitialiseCSVProcess() if (!headerWritten) { writer.WriteLine( - "Episode,Step,Reward,CollectedRewardType,Health,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForwardWithDescription,ActionRotateWithDescription,WasAgentFrozen?,NotificationState,DispensedRewardType,WasRewardDispensed?,WasSpawnerButtonTriggered?,CombinedRaycastData,WasAgentInDatazone?,CombinedSpawnerInfo" + "Episode,Step,Health,Reward,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForwardWithDescription,ActionRotateWithDescription,WasAgentFrozen?,NotificationState,CollectedRewardType,DispensedRewardType,WasRewardDispensed?,WasButtonPressed?,CombinedSpawnerInfo,WasAgentInDataZone?,CombinedRaycastData" ); headerWritten = true; } @@ -210,22 +210,46 @@ private void LogToCSV( Vector3 position, string actionForwardWithDescription, string actionRotateWithDescription, - bool wasAgentFrozen, + string wasAgentFrozen, float reward, string notificationState, int customEpisodeCount, string dispensedRewardType, bool wasRewardDispensed, bool wasSpawnerButtonTriggered, - string combinedRaycastData, + string combinedSpawnerInfo, string wasAgentInDataZone, - string combinedSpawnerInfo + string combinedRaycastData ) { - string logEntry = - $"{customEpisodeCount},{StepCount},{reward},{lastCollectedRewardType},{health},{velocity.x},{velocity.y},{velocity.z},{position.x},{position.y},{position.z},{actionForwardWithDescription},{actionRotateWithDescription},{wasAgentFrozen},{notificationState},{dispensedRewardType},{wasRewardDispensed},{wasSpawnerButtonTriggered},{combinedRaycastData},{wasAgentInDataZone},{combinedSpawnerInfo.Replace(",", ";")}"; + string logEntry = string.Format( + "{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14},{15},{16},{17},{18},{19},{20}", + customEpisodeCount, + StepCount, + health, + reward, + velocity.x, + velocity.y, + velocity.z, + position.x, + position.y, + position.z, + actionForwardWithDescription, + actionRotateWithDescription, + wasAgentFrozen, + notificationState, + lastCollectedRewardType, + dispensedRewardType, + wasRewardDispensed ? "Yes" : "No", + wasSpawnerButtonTriggered ? "Yes" : "No", + combinedSpawnerInfo.Replace(",", ";"), + wasAgentInDataZone, + combinedRaycastData + ); + logQueue.Enqueue(logEntry); lastCollectedRewardType = "None"; + Debug.Log($"Logging from {nameof(OnEpisodeBegin)} at Step {StepCount}"); } /// @@ -349,36 +373,8 @@ public override void CollectObservations(VectorSensor sensor) string actionRotateWithDescription = $"{lastActionRotate} ({actionRotateDescription})"; float reward = GetCumulativeReward(); string notificationState = GetNotificationState(); - (float[] raycastObservations, string[] raycastTags) = CollectRaycastObservations(); - foreach (float observation in raycastObservations) - { - sensor.AddObservation(observation); - } - string combinedRaycastData = CombineRaycastData(raycastObservations, raycastTags); - - LogToCSV( - localVel, - localPos, - actionForwardWithDescription, - actionRotateWithDescription, - wasAgentFrozen, - reward, - notificationState, - customEpisodeCount, - dispensedRewardType, - wasRewardDispensed, - wasSpawnerButtonTriggered, - combinedRaycastData, - wasAgentInDataZone, - combinedSpawnerInfo - ); - dispensedRewardType = "None"; - wasRewardDispensed = false; - wasSpawnerButtonTriggered = false; - wasAgentInDataZone = "No"; - combinedSpawnerInfo = ""; } public override void OnActionReceived(ActionBuffers action) @@ -402,7 +398,6 @@ public override void OnActionReceived(ActionBuffers action) string notificationState = GetNotificationState(); (float[] raycastObservations, string[] raycastTags) = CollectRaycastObservations(); - string combinedRaycastData = CombineRaycastData(raycastObservations, raycastTags); LogToCSV( @@ -410,22 +405,23 @@ public override void OnActionReceived(ActionBuffers action) localPos, actionForwardWithDescription, actionRotateWithDescription, - wasAgentFrozen, + wasAgentFrozen ? "Yes" : "No", reward, notificationState, customEpisodeCount, dispensedRewardType, wasRewardDispensed, wasSpawnerButtonTriggered, - combinedRaycastData, + combinedSpawnerInfo, wasAgentInDataZone, - combinedSpawnerInfo + combinedRaycastData ); + dispensedRewardType = "None"; wasRewardDispensed = false; wasSpawnerButtonTriggered = false; wasAgentInDataZone = "No"; - combinedSpawnerInfo = ""; + combinedSpawnerInfo = "N/A"; UpdateHealth(_rewardPerStep); } From 3529474f4d2b98247d3d42541fe7a8294d171325 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Thu, 25 Jul 2024 00:26:14 +0300 Subject: [PATCH 121/205] added todos --- Assets/Scripts/TrainingAgent.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 4c1cf7b1..dd05dac3 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -19,6 +19,9 @@ /// // TODO: Clean, optimize and refactor the this script. + +// TODO: rework flushing method +// TODO: rework when total collected goals statement is displayed (currently sporadic) public class TrainingAgent : Agent, IPrefab { [Header("Agent Settings")] From b20ce0711c8c6758736974dcfb91fc5a1e651c5f Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Thu, 25 Jul 2024 00:26:42 +0300 Subject: [PATCH 122/205] Update TrainingAgent.cs --- Assets/Scripts/TrainingAgent.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index dd05dac3..78f8cdda 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -22,6 +22,7 @@ // TODO: rework flushing method // TODO: rework when total collected goals statement is displayed (currently sporadic) +// TODO: test each column works and confirm expected data public class TrainingAgent : Agent, IPrefab { [Header("Agent Settings")] From f03c0539c19e09bdb57c80b5deee90520c80490c Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Thu, 25 Jul 2024 16:56:30 +0300 Subject: [PATCH 123/205] IMPORTANT: Updated code to better handle threading and logging to .csv file. Before it was sort of unpredictably flushing to .csv file. now, there is a lock implemented which avoids multiple threads and flushes occuring. Also, good to note is that an episode lasts 501 steps exactly. This is also reflected in the batch (buffersize) so now each episode's data is flushed in sync with the episode duration (101 time-frames). Also removed a while loop which i think used too much cpu without needing it (now mor eefficient). --- Assets/Scripts/TrainingAgent.cs | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 78f8cdda..d749e9a5 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -72,7 +72,7 @@ public class TrainingAgent : Agent, IPrefab private string yamlFileName; private int customEpisodeCount = 0; private ConcurrentQueue logQueue = new ConcurrentQueue(); - private const int bufferSize = 150; /* Corresponds to rows in the CSV file to keep in memory before flushing to disk */ + private const int bufferSize = 101; /* Corresponds to rows in the CSV file to keep in memory before flushing to disk */ private bool isFlushing = false; private string lastCollectedRewardType = "None"; private string dispensedRewardType = "None"; @@ -81,6 +81,8 @@ public class TrainingAgent : Agent, IPrefab private bool wasSpawnerButtonTriggered = false; private string combinedSpawnerInfo = ""; + private AutoResetEvent flushEvent = new AutoResetEvent(false); + public void RecordSpawnerInfo(string spawnerInfo) { if (string.IsNullOrEmpty(combinedSpawnerInfo)) @@ -195,7 +197,7 @@ private void InitialiseCSVProcess() if (!headerWritten) { writer.WriteLine( - "Episode,Step,Health,Reward,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForwardWithDescription,ActionRotateWithDescription,WasAgentFrozen?,NotificationState,CollectedRewardType,DispensedRewardType,WasRewardDispensed?,WasButtonPressed?,CombinedSpawnerInfo,WasAgentInDataZone?,CombinedRaycastData" + "Episode,Step,Health,Reward,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForwardWithDescription,ActionRotateWithDescription,WasAgentFrozen?,NotificationShown?,CollectedRewardType,DispensedRewardType,WasRewardDispensed?,WasSpawnerButtonTriggered?,CombinedSpawnerInfo,WasAgentInDataZone?,CombinedRaycastData" ); headerWritten = true; } @@ -253,7 +255,11 @@ string combinedRaycastData logQueue.Enqueue(logEntry); lastCollectedRewardType = "None"; - Debug.Log($"Logging from {nameof(OnEpisodeBegin)} at Step {StepCount}"); + + if (logQueue.Count >= bufferSize) + { + flushEvent.Set(); + } } /// @@ -261,12 +267,15 @@ string combinedRaycastData /// private void FlushLogQueue() { - while (logQueue.TryDequeue(out var logEntry)) + lock (logQueue) { - writer.WriteLine(logEntry); + while (logQueue.TryDequeue(out var logEntry)) + { + writer.WriteLine(logEntry); + } + writer.Flush(); + Debug.Log("Flushed log queue to CSV file."); } - writer.Flush(); - Debug.Log("Flush initiated. Flushed log queue to CSV file."); } /// @@ -279,13 +288,13 @@ private void StartFlushThread() { while (true) { + flushEvent.WaitOne(); // Wait until signaled if (logQueue.Count >= bufferSize && !isFlushing) { isFlushing = true; FlushLogQueue(); isFlushing = false; } - Thread.Sleep(100); // polls every 100ms to check if the queue is full to prevent the thread from running continuously and hogging resources } }).Start(); } @@ -299,7 +308,7 @@ protected override void OnDisable() base.OnDisable(); if (writer != null) { - FlushLogQueue(); // Ensures all buffered data is written to the file before closing (important for builds) + FlushLogQueue(); // Ensures all buffered data is written to the file before closing writer.Close(); } @@ -425,7 +434,7 @@ public override void OnActionReceived(ActionBuffers action) wasRewardDispensed = false; wasSpawnerButtonTriggered = false; wasAgentInDataZone = "No"; - combinedSpawnerInfo = "N/A"; + combinedSpawnerInfo = ""; UpdateHealth(_rewardPerStep); } From 89452b2f57d810f7844aa54aae6e8a700a1e584e Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Thu, 25 Jul 2024 16:59:32 +0300 Subject: [PATCH 124/205] added call to flush data to .csv when episode ends as a backup procedure so no data is left out. --- Assets/Scripts/TrainingAgent.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index d749e9a5..793bc2d1 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -643,6 +643,7 @@ IEnumerator EndEpisodeAfterDelay() NotificationManager.Instance.HideNotification(); EndEpisode(); + FlushLogQueue(); } public override void OnEpisodeBegin() From 10fd61f3e4b7649398007239a795d685c8033d99 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Thu, 25 Jul 2024 17:01:07 +0300 Subject: [PATCH 125/205] minor changes --- Assets/Scripts/TrainingAgent.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 793bc2d1..823e2418 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -19,9 +19,6 @@ /// // TODO: Clean, optimize and refactor the this script. - -// TODO: rework flushing method -// TODO: rework when total collected goals statement is displayed (currently sporadic) // TODO: test each column works and confirm expected data public class TrainingAgent : Agent, IPrefab { @@ -209,7 +206,8 @@ private void InitialiseCSVProcess() } /// - /// Logs the agent's state to a CSV file. This is called every step. The data is stored in a queue and flushed to the file in a separate thread. + /// Logs the agent's state to a CSV file. This is called every step. + /// The data is stored in a queue and flushed to the file in a separate thread. /// private void LogToCSV( Vector3 velocity, @@ -648,9 +646,9 @@ IEnumerator EndEpisodeAfterDelay() public override void OnEpisodeBegin() { - if (!_arena.IsFirstArenaReset) // Don't log for the first initialization of the arena + if (!_arena.IsFirstArenaReset) { - writer.WriteLine($"Number of Goals Collected: {numberOfGoalsCollected}"); + writer.WriteLine($"Goals Collected: {numberOfGoalsCollected}"); writer.Flush(); } From 30dbdfa009fce9cf0d0ea722f098b1386813ab6b Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Thu, 25 Jul 2024 17:03:16 +0300 Subject: [PATCH 126/205] minor comment changes --- Assets/Scripts/TrainingAgent.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 823e2418..63f28624 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -482,7 +482,7 @@ private void MoveAgent(int actionForward, int actionRotate) { if (IsFrozen()) { - // If the agent is frozen, stop all movement and rotation + /* If the agent is frozen, stop all movement and rotation */ _rigidBody.velocity = Vector3.zero; _rigidBody.angularVelocity = Vector3.zero; return; @@ -575,7 +575,7 @@ public void UpdateHealth(float updateAmount, bool andCompleteArena = false) _currentScore = GetCumulativeReward(); - // Ensure health does not exceed maximum limits + /* Ensure health does not exceed maximum limits */ if (health > _maxHealth) { health = _maxHealth; @@ -592,7 +592,6 @@ public void UpdateHealth(float updateAmount, bool andCompleteArena = false) return; } - // Handle arena completion or episode ending // TODO: Debug current pass mark for arena == 0 if (andCompleteArena || _nextUpdateCompleteArena) { From 81c990f7371ff71d3fe94eead5f8b0c8aaa8d560 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Thu, 25 Jul 2024 17:08:56 +0300 Subject: [PATCH 127/205] minor comment changes --- Assets/Scripts/TrainingAgent.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 63f28624..a2675bc7 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -14,12 +14,9 @@ /// /// The TrainingAgent class is a subclass of the Agent class in the ML-Agents library. -/// It is used to define the behaviour of the agent in the training environment. /// Actions are currently discrete. 2 branches of 0,1,2, 0,1,2 for forward and rotate respectively. /// -// TODO: Clean, optimize and refactor the this script. -// TODO: test each column works and confirm expected data public class TrainingAgent : Agent, IPrefab { [Header("Agent Settings")] From cf5fefd796c83553ccc15fb37ba32197c0c9fdb1 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Thu, 25 Jul 2024 17:10:43 +0300 Subject: [PATCH 128/205] redundant comment removed --- Assets/Scripts/TrainingAgent.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index a2675bc7..d31e163d 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -601,7 +601,6 @@ public void UpdateHealth(float updateAmount, bool andCompleteArena = false) if (proceedToNext) { - // If the next arena is merged, load that without ending the episode if (_arena.mergeNextArena) { _arena.LoadNextArena(); From a4593e58d2beb93da9ce93db59762fa793640693 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Thu, 25 Jul 2024 18:01:02 +0300 Subject: [PATCH 129/205] minor output to .csv file format on data --- Assets/Scripts/Spawners/GoalSpawner.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/Scripts/Spawners/GoalSpawner.cs b/Assets/Scripts/Spawners/GoalSpawner.cs index cc8ecb8e..76ebd66f 100644 --- a/Assets/Scripts/Spawners/GoalSpawner.cs +++ b/Assets/Scripts/Spawners/GoalSpawner.cs @@ -129,7 +129,7 @@ public virtual BallGoal SpawnNewGoal(int listID) if (agent != null) { string combinedSpawnerInfo = - $"SpawnerID:{spawnerID}, Position:{transform.position.x},{transform.position.y},{transform.position.z}, RewardType:{newGoal.rewardType}"; + $" SpawnerID:{spawnerID}, Position:{transform.position.x},{transform.position.y},{transform.position.z}, RewardType:{newGoal.rewardType}"; agent.RecordSpawnerInfo(combinedSpawnerInfo); agent.RecordDispensedRewardType(newGoal.rewardType); agent.RecordDispensedReward(); From 86cb3f87f3f4252dbceca221c4ab48d4a77a2220 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Thu, 25 Jul 2024 20:55:29 +0300 Subject: [PATCH 130/205] added TODO --- Assets/Scripts/ArenaBuilders.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Assets/Scripts/ArenaBuilders.cs b/Assets/Scripts/ArenaBuilders.cs index a6f5fa6a..945b642d 100644 --- a/Assets/Scripts/ArenaBuilders.cs +++ b/Assets/Scripts/ArenaBuilders.cs @@ -17,6 +17,7 @@ /// // TODO: Optimize and refactor the this script. +// TODO: Overhaul object spawn and agent spawn logic for a more unified and central implementation (for all objects, inc. agent) namespace ArenaBuilders { public class ArenaBuilder From 72e6ac55a657fea5013e08c31ea20a364296be35 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Fri, 26 Jul 2024 00:16:38 +0300 Subject: [PATCH 131/205] added new column: active camera perspective --- Assets/Scripts/PlayerControls.cs | 287 +++++++++++++++++-------------- Assets/Scripts/TrainingAgent.cs | 19 +- 2 files changed, 171 insertions(+), 135 deletions(-) diff --git a/Assets/Scripts/PlayerControls.cs b/Assets/Scripts/PlayerControls.cs index 2a1929f2..92b56f03 100644 --- a/Assets/Scripts/PlayerControls.cs +++ b/Assets/Scripts/PlayerControls.cs @@ -10,133 +10,162 @@ /// public class PlayerControls : MonoBehaviour { - [Header("Camera Settings")] - private Camera[] cameras = new Camera[3]; - public int cameraID => activeCameraIndex; - private int activeCameraIndex = 0; - private bool camerasInitialized = false; - - [Header("UI Components")] - public TMP_Text scoreText; - public Canvas effectCanvas; - - [Header("Gameplay Settings")] - private bool canResetEpisode = true; - private bool canChangePerspective = true; - - [Header("External References")] - private ScreenshotCamera screenshotCam; - private TrainingAgent agent; - private ArenasConfigurations arenasConfigurations; - - [Header("Score Settings")] - public float prevScore = 0; - - public Camera getActiveCam() - { - return cameras[activeCameraIndex]; - } - - private void Start() - { - InitializeCanvas(); - LoadCamerasAndAgent(); - LoadConfigurationSettings(); - InitializeCameras(); - } - - private void Update() - { - if (!camerasInitialized) - { - Debug.LogError("Cameras not initialized properly."); - return; - } - - HandleInput(); - UpdateScoreText(); - } - - private void InitializeCanvas() - { - effectCanvas.renderMode = RenderMode.ScreenSpaceCamera; - } - - private void LoadCamerasAndAgent() - { - screenshotCam = FindObjectOfType(); - cameras[0] = GameObject.FindGameObjectWithTag("MainCamera").GetComponent(); - cameras[1] = GameObject.FindGameObjectWithTag("agent").transform.Find("AgentCamMid").GetComponent(); - cameras[2] = GameObject.FindGameObjectWithTag("camBase").GetComponent(); - agent = GameObject.FindGameObjectWithTag("agent").GetComponent(); - } - - private void LoadConfigurationSettings() - { - arenasConfigurations = ArenasConfigurations.Instance; - canResetEpisode = arenasConfigurations?.canResetEpisode ?? true; - canChangePerspective = arenasConfigurations?.canChangePerspective ?? true; - } - - private void InitializeCameras() - { - if (screenshotCam == null || agent == null || cameras[0] == null || cameras[1] == null || cameras[2] == null) - { - Debug.LogError("One or more essential components (Cameras, Agent, ScreenshotCam) were not found."); - return; - } - - activeCameraIndex = canChangePerspective ? 0 : 2; // If can't change perspectives, use the 3rd person camera - Debug.Log($"Initializing Cameras. Can Change Perspective: {canChangePerspective}, Active Camera Index: {activeCameraIndex}"); - - SetActiveCamera(activeCameraIndex); - camerasInitialized = true; - } - - private void HandleInput() - { - if (canChangePerspective && Input.GetKeyDown(KeyCode.C)) - { - CycleCamera(); - } - if (canResetEpisode && Input.GetKeyDown(KeyCode.R)) - { - agent.EndEpisode(); - } - if (Input.GetKeyDown(KeyCode.Q)) - { - Application.Quit(); - } - if (Input.GetKeyDown(KeyCode.P)) - { - screenshotCam.Activate(); - } - } - - private void UpdateScoreText() - { - if (agent != null && scoreText != null) - { - scoreText.text = $"Previous Reward: {agent.GetPreviousScore():0.000}\n" + - $"Current Reward: {agent.GetCumulativeReward():0.000}"; - } - } - - private void CycleCamera() - { - cameras[activeCameraIndex].enabled = false; - activeCameraIndex = (activeCameraIndex + 1) % cameras.Length; - SetActiveCamera(activeCameraIndex); - } - - private void SetActiveCamera(int index) - { - for (int i = 0; i < cameras.Length; i++) - { - cameras[i].enabled = (i == index); - } - effectCanvas.worldCamera = cameras[index]; - effectCanvas.planeDistance = index == 1 ? 0.02f : 0.31f; - } - + [Header("Camera Settings")] + private Camera[] cameras = new Camera[3]; + public int cameraID => activeCameraIndex; + private int activeCameraIndex = 0; + private bool camerasInitialized = false; + + [Header("UI Components")] + public TMP_Text scoreText; + public Canvas effectCanvas; + + [Header("Gameplay Settings")] + private bool canResetEpisode = true; + private bool canChangePerspective = true; + + [Header("External References")] + private ScreenshotCamera screenshotCam; + private TrainingAgent agent; + private ArenasConfigurations arenasConfigurations; + + [Header("Score Settings")] + public float prevScore = 0; + + public string GetActiveCameraDescription() + { + return activeCameraIndex switch + { + 0 => "0 (First-Person)", + 1 => "1 (Third-Person)", + 2 => "2 (Bird's Eye)", + _ => $"{activeCameraIndex} (unknown)" + }; + } + + public Camera getActiveCam() + { + return cameras[activeCameraIndex]; + } + + public int GetActiveCameraIndex() + { + return activeCameraIndex; + } + + private void Start() + { + InitializeCanvas(); + LoadCamerasAndAgent(); + LoadConfigurationSettings(); + InitializeCameras(); + } + + private void Update() + { + if (!camerasInitialized) + { + Debug.LogError("Cameras not initialized properly."); + return; + } + + HandleInput(); + UpdateScoreText(); + } + + private void InitializeCanvas() + { + effectCanvas.renderMode = RenderMode.ScreenSpaceCamera; + } + + private void LoadCamerasAndAgent() + { + screenshotCam = FindObjectOfType(); + cameras[0] = GameObject.FindGameObjectWithTag("MainCamera").GetComponent(); + cameras[1] = GameObject + .FindGameObjectWithTag("agent") + .transform.Find("AgentCamMid") + .GetComponent(); + cameras[2] = GameObject.FindGameObjectWithTag("camBase").GetComponent(); + agent = GameObject.FindGameObjectWithTag("agent").GetComponent(); + } + + private void LoadConfigurationSettings() + { + arenasConfigurations = ArenasConfigurations.Instance; + canResetEpisode = arenasConfigurations?.canResetEpisode ?? true; + canChangePerspective = arenasConfigurations?.canChangePerspective ?? true; + } + + private void InitializeCameras() + { + if ( + screenshotCam == null + || agent == null + || cameras[0] == null + || cameras[1] == null + || cameras[2] == null + ) + { + Debug.LogError( + "One or more essential components (Cameras, Agent, ScreenshotCam) were not found." + ); + return; + } + + activeCameraIndex = canChangePerspective ? 0 : 2; // If can't change perspectives, use the 3rd person camera + Debug.Log( + $"Initializing Cameras. Can Change Perspective: {canChangePerspective}, Active Camera Index: {activeCameraIndex}" + ); + + SetActiveCamera(activeCameraIndex); + camerasInitialized = true; + } + + private void HandleInput() + { + if (canChangePerspective && Input.GetKeyDown(KeyCode.C)) + { + CycleCamera(); + } + if (canResetEpisode && Input.GetKeyDown(KeyCode.R)) + { + agent.EndEpisode(); + } + if (Input.GetKeyDown(KeyCode.Q)) + { + Application.Quit(); + } + if (Input.GetKeyDown(KeyCode.P)) + { + screenshotCam.Activate(); + } + } + + private void UpdateScoreText() + { + if (agent != null && scoreText != null) + { + scoreText.text = + $"Previous Reward: {agent.GetPreviousScore():0.000}\n" + + $"Current Reward: {agent.GetCumulativeReward():0.000}"; + } + } + + private void CycleCamera() + { + cameras[activeCameraIndex].enabled = false; + activeCameraIndex = (activeCameraIndex + 1) % cameras.Length; + SetActiveCamera(activeCameraIndex); + } + + private void SetActiveCamera(int index) + { + for (int i = 0; i < cameras.Length; i++) + { + cameras[i].enabled = (i == index); + } + effectCanvas.worldCamera = cameras[index]; + effectCanvas.planeDistance = index == 1 ? 0.02f : 0.31f; + } } diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index d31e163d..4f894e87 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -59,6 +59,9 @@ public class TrainingAgent : Agent, IPrefab private TrainingArena _arena; private bool _isCountdownActive = false; + [Header("External References")] + public PlayerControls playerControls; + [Header("CSV Logging")] public string csvFilePath = ""; private StreamWriter writer; @@ -74,7 +77,6 @@ public class TrainingAgent : Agent, IPrefab private bool wasRewardDispensed = false; private bool wasSpawnerButtonTriggered = false; private string combinedSpawnerInfo = ""; - private AutoResetEvent flushEvent = new AutoResetEvent(false); public void RecordSpawnerInfo(string spawnerInfo) @@ -142,6 +144,8 @@ public override void Initialize() DataZone.OnInDataZone += OnInDataZone; DataZone.OnOutDataZone += OnOutDataZone; + playerControls = GameObject.FindObjectOfType(); + InitialiseCSVProcess(); if (!Application.isEditor) @@ -191,7 +195,7 @@ private void InitialiseCSVProcess() if (!headerWritten) { writer.WriteLine( - "Episode,Step,Health,Reward,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForwardWithDescription,ActionRotateWithDescription,WasAgentFrozen?,NotificationShown?,CollectedRewardType,DispensedRewardType,WasRewardDispensed?,WasSpawnerButtonTriggered?,CombinedSpawnerInfo,WasAgentInDataZone?,CombinedRaycastData" + "Episode,Step,Health,Reward,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForwardWithDescription,ActionRotateWithDescription,WasAgentFrozen?,NotificationShown?,CollectedRewardType,DispensedRewardType,WasRewardDispensed?,WasSpawnerButtonTriggered?,CombinedSpawnerInfo,WasAgentInDataZone?,CombinedRaycastData,ActiveCamera" ); headerWritten = true; } @@ -220,11 +224,12 @@ private void LogToCSV( bool wasSpawnerButtonTriggered, string combinedSpawnerInfo, string wasAgentInDataZone, - string combinedRaycastData + string combinedRaycastData, + string activeCameraDescription ) { string logEntry = string.Format( - "{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14},{15},{16},{17},{18},{19},{20}", + "{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14},{15},{16},{17},{18},{19},{20},{21}", customEpisodeCount, StepCount, health, @@ -245,7 +250,8 @@ string combinedRaycastData wasSpawnerButtonTriggered ? "Yes" : "No", combinedSpawnerInfo.Replace(",", ";"), wasAgentInDataZone, - combinedRaycastData + combinedRaycastData, + activeCameraDescription ); logQueue.Enqueue(logEntry); @@ -422,7 +428,8 @@ public override void OnActionReceived(ActionBuffers action) wasSpawnerButtonTriggered, combinedSpawnerInfo, wasAgentInDataZone, - combinedRaycastData + combinedRaycastData, + playerControls.GetActiveCameraDescription() ); dispensedRewardType = "None"; From 3175c26c1ed36be4c9a2d6e82c6c26ac45601df0 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Fri, 26 Jul 2024 15:38:35 +0300 Subject: [PATCH 132/205] Routine Project Cleanup on Scripts Minor comments cleanup or reformatting to scripts for cleaner and more readable code. --- Assets/Scripts/AnimalSkinManager.cs | 1 + Assets/Scripts/ArenasParameters.cs | 2 +- Assets/Scripts/ArenasParametersEventArgs.cs | 3 +- Assets/Scripts/ArenasParametersSideChannel.cs | 84 +++--- Assets/Scripts/CameraCollision.cs | 63 +++-- Assets/Scripts/CameraFollow.cs | 26 +- Assets/Scripts/CollisionImpulseTracker.cs | 27 +- Assets/Scripts/ComputeScaleRatios.cs | 26 +- Assets/Scripts/Fade.cs | 82 +++--- Assets/Scripts/FlashingImage.cs | 69 ++--- Assets/Scripts/Grounded.cs | 12 +- Assets/Scripts/Holders.cs | 63 +++-- Assets/Scripts/Lights.cs | 173 ++++++------ Assets/Scripts/NotificationManager.cs | 229 ++++++++-------- Assets/Scripts/PlayerControls.cs | 2 +- Assets/Scripts/Prefab.cs | 7 +- Assets/Scripts/PrefabsInterface.cs | 14 +- Assets/Scripts/Rewards/BallGoal.cs | 9 +- Assets/Scripts/Rewards/DeathZone.cs | 10 +- Assets/Scripts/Rewards/DecayGoal.cs | 6 +- Assets/Scripts/Rewards/Goal.cs | 110 ++++---- Assets/Scripts/Rewards/SizeChangeGoal.cs | 5 +- Assets/Scripts/ScreenshotCamera.cs | 120 +++++---- Assets/Scripts/Spawners/GoalSpawner.cs | 12 +- Assets/Scripts/Spawners/SpawnerStockpiler.cs | 11 +- .../Spawners/Spawner_InteractiveButton.cs | 11 +- Assets/Scripts/TrainingAgent.cs | 16 +- Assets/Scripts/TrainingArena.cs | 18 +- Assets/Scripts/UnityEngineExtensions.cs | 2 +- Assets/Scripts/YAMLclasses.cs | 246 +++++++++--------- 30 files changed, 730 insertions(+), 729 deletions(-) diff --git a/Assets/Scripts/AnimalSkinManager.cs b/Assets/Scripts/AnimalSkinManager.cs index c3a655f2..7c3f4fea 100644 --- a/Assets/Scripts/AnimalSkinManager.cs +++ b/Assets/Scripts/AnimalSkinManager.cs @@ -14,6 +14,7 @@ public class AnimalSkinManager : MonoBehaviour { [Header("Animal Skins Settings")] public const int AnimalCount = 3; + [Range(0, AnimalCount - 1)] public int AnimalSkinID; public string[] AnimalNames = new string[AnimalCount]; diff --git a/Assets/Scripts/ArenasParameters.cs b/Assets/Scripts/ArenasParameters.cs index 4c635cec..9941d01b 100644 --- a/Assets/Scripts/ArenasParameters.cs +++ b/Assets/Scripts/ArenasParameters.cs @@ -7,7 +7,7 @@ using YAMLDefs; /// -/// The classes in this file are used to store the parameters for the arenas. +/// The classes in this file are used to store the parameters for the arenas. /// These parameters are read from a YAML file and used to configure the arenas. /// diff --git a/Assets/Scripts/ArenasParametersEventArgs.cs b/Assets/Scripts/ArenasParametersEventArgs.cs index 875c85e6..3bf2d6a6 100644 --- a/Assets/Scripts/ArenasParametersEventArgs.cs +++ b/Assets/Scripts/ArenasParametersEventArgs.cs @@ -9,6 +9,7 @@ public class ArenasParametersEventArgs : EventArgs { public byte[] arenas_yaml { get; set; } public string yamlFileName { get; set; } - public ArenasParametersEventArgs() { } // Empty constructor + + public ArenasParametersEventArgs() { } /* Empty constructor for ArenasParametersEventArgs */ } } diff --git a/Assets/Scripts/ArenasParametersSideChannel.cs b/Assets/Scripts/ArenasParametersSideChannel.cs index cb80e561..f4b58a39 100644 --- a/Assets/Scripts/ArenasParametersSideChannel.cs +++ b/Assets/Scripts/ArenasParametersSideChannel.cs @@ -8,52 +8,52 @@ /// public class ArenasParametersSideChannel : SideChannel { - public string CurrentYamlFileName { get; private set; } // Store the current YAML file name + public string CurrentYamlFileName { get; private set; } - /// - /// Initializes a new instance of the ArenasParametersSideChannel class. - /// - public ArenasParametersSideChannel() - { - ChannelId = new Guid("9c36c837-cad5-498a-b675-bc19c9370072"); - } + /// + /// Initializes a new instance of the ArenasParametersSideChannel class. + /// + public ArenasParametersSideChannel() + { + ChannelId = new Guid("9c36c837-cad5-498a-b675-bc19c9370072"); + } - /// - /// This method is called when a message is received from the Unity. - /// - protected override void OnMessageReceived(IncomingMessage msg) - { - string fileName = msg.ReadString(); - byte[] yamlData = msg.GetRawBytes(); + /// + /// This method is called when a message is received from the Unity. + /// + protected override void OnMessageReceived(IncomingMessage msg) + { + string fileName = msg.ReadString(); + byte[] yamlData = msg.GetRawBytes(); - Debug.Log($"Received YAML file name: {fileName}"); - CurrentYamlFileName = fileName; + Debug.Log($"Received YAML file name: {fileName}"); + CurrentYamlFileName = fileName; - // Create the event args including the file name and the YAML data - ArenasParametersEventArgs args = new ArenasParametersEventArgs - { - arenas_yaml = yamlData, - yamlFileName = fileName - }; - OnArenasParametersReceived(args); - } + /* Create the event args including the file name and the YAML data */ + ArenasParametersEventArgs args = new ArenasParametersEventArgs + { + arenas_yaml = yamlData, + yamlFileName = fileName + }; + OnArenasParametersReceived(args); + } - /// - /// This method is called when the arenas parameters are received. - /// - protected virtual void OnArenasParametersReceived( - ArenasParametersEventArgs arenasParametersEvent - ) - { - EventHandler handler = NewArenasParametersReceived; - if (handler != null) - { - handler(this, arenasParametersEvent); - } - } + /// + /// This method is called when the arenas parameters are received. + /// + protected virtual void OnArenasParametersReceived( + ArenasParametersEventArgs arenasParametersEvent + ) + { + EventHandler handler = NewArenasParametersReceived; + if (handler != null) + { + handler(this, arenasParametersEvent); + } + } - /// - /// This event is triggered when new arenas parameters are received. - /// - public EventHandler NewArenasParametersReceived; + /// + /// This event is triggered when new arenas parameters are received. + /// + public EventHandler NewArenasParametersReceived; } diff --git a/Assets/Scripts/CameraCollision.cs b/Assets/Scripts/CameraCollision.cs index 4f23965b..f6aa4e4d 100644 --- a/Assets/Scripts/CameraCollision.cs +++ b/Assets/Scripts/CameraCollision.cs @@ -5,39 +5,38 @@ /// public class CameraCollision : MonoBehaviour { - [Header("Camera Collision Settings")] - public float minDistance = 1.0f; - public float maxDistance = 4.0f; - public float smooth = 10.0f; - Vector3 dollyDir; - public Vector3 dollyDistAdjusted; - public float distance; + [Header("Camera Collision Settings")] + public float minDistance = 1.0f; + public float maxDistance = 4.0f; + public float smooth = 10.0f; + Vector3 dollyDir; + public Vector3 dollyDistAdjusted; + public float distance; - void Awake() - { - dollyDir = transform.localPosition.normalized; - distance = transform.localPosition.magnitude; - } + void Awake() + { + dollyDir = transform.localPosition.normalized; + distance = transform.localPosition.magnitude; + } - void Update() - { - Vector3 desiredCameraPos = transform.parent.TransformPoint(dollyDir * maxDistance); - RaycastHit hit; + void Update() + { + Vector3 desiredCameraPos = transform.parent.TransformPoint(dollyDir * maxDistance); + RaycastHit hit; - if (Physics.Linecast(transform.parent.position, desiredCameraPos, out hit)) - { - distance = Mathf.Clamp(hit.distance * 0.9f, minDistance, maxDistance); - } - else - { - distance = maxDistance; - } + if (Physics.Linecast(transform.parent.position, desiredCameraPos, out hit)) + { + distance = Mathf.Clamp(hit.distance * 0.9f, minDistance, maxDistance); + } + else + { + distance = maxDistance; + } - transform.localPosition = Vector3.Lerp( - transform.localPosition, - dollyDir * distance, - Time.deltaTime * smooth - ); - } - -} \ No newline at end of file + transform.localPosition = Vector3.Lerp( + transform.localPosition, + dollyDir * distance, + Time.deltaTime * smooth + ); + } +} diff --git a/Assets/Scripts/CameraFollow.cs b/Assets/Scripts/CameraFollow.cs index 739cae2d..0be15f9d 100644 --- a/Assets/Scripts/CameraFollow.cs +++ b/Assets/Scripts/CameraFollow.cs @@ -1,22 +1,22 @@ using UnityEngine; /// -/// This class is used to make the camera follow the player. +/// This class is used to make the camera follow the player. It is attached to the camera object. /// public class CameraFollow : MonoBehaviour { - [Header("Followed Object")] - public GameObject followObj; + [Header("Followed Object")] + public GameObject followObj; - void Start() - { - transform.position = followObj.transform.position; - transform.rotation = followObj.transform.rotation; - } + void Start() + { + transform.position = followObj.transform.position; + transform.rotation = followObj.transform.rotation; + } - void Update() - { - transform.position = followObj.transform.position; - transform.rotation = followObj.transform.rotation; - } + void Update() + { + transform.position = followObj.transform.position; + transform.rotation = followObj.transform.rotation; + } } diff --git a/Assets/Scripts/CollisionImpulseTracker.cs b/Assets/Scripts/CollisionImpulseTracker.cs index 9f080cad..436f9a06 100644 --- a/Assets/Scripts/CollisionImpulseTracker.cs +++ b/Assets/Scripts/CollisionImpulseTracker.cs @@ -5,21 +5,20 @@ /// public class CollisionImpulseTracker : MonoBehaviour { - [Tooltip("Tracks the cumulative impulse magnitude from collisions this frame.")] - public float impulseMagnitude; + public float impulseMagnitude; - private void FixedUpdate() - { - impulseMagnitude = 0; - } + private void FixedUpdate() + { + impulseMagnitude = 0; + } - private void OnCollisionEnter(Collision col) - { - impulseMagnitude += col.impulse.magnitude; - } + private void OnCollisionEnter(Collision col) + { + impulseMagnitude += col.impulse.magnitude; + } - private void OnCollisionStay(Collision col) - { - impulseMagnitude += col.impulse.magnitude; - } + private void OnCollisionStay(Collision col) + { + impulseMagnitude += col.impulse.magnitude; + } } diff --git a/Assets/Scripts/ComputeScaleRatios.cs b/Assets/Scripts/ComputeScaleRatios.cs index 8fd9458c..b17a3f56 100644 --- a/Assets/Scripts/ComputeScaleRatios.cs +++ b/Assets/Scripts/ComputeScaleRatios.cs @@ -6,20 +6,18 @@ /// public class ComputeScaleRatios : MonoBehaviour { - void Start() - { - // Compute the real size of the object including its children - Vector3 sizeReal = gameObject.GetBoundsWithChildren().extents * 2; - Vector3 scaleReal = transform.localScale; + void Start() + { + /* Compute the real size of the object including its children */ + Vector3 sizeReal = gameObject.GetBoundsWithChildren().extents * 2; + Vector3 scaleReal = transform.localScale; - // Initialize ratioSize with scaleReal to handle potential division by zero - Vector3 ratioSize = scaleReal; + /* Initialize ratioSize with scaleReal to handle potential division by zero */ + Vector3 ratioSize = scaleReal; - // Ensure we're not dividing by zero - ratioSize.x = sizeReal.x != 0 ? scaleReal.x / sizeReal.x : 0; - ratioSize.y = sizeReal.y != 0 ? scaleReal.y / sizeReal.y : 0; - ratioSize.z = sizeReal.z != 0 ? scaleReal.z / sizeReal.z : 0; - - Debug.Log($"===== Object {gameObject.name} Scale Ratios ======\nX: {ratioSize.x:F8}\nY: {ratioSize.y:F8}\nZ: {ratioSize.z:F8}\n=================================="); - } + /* Ensure we're not dividing by zero */ + ratioSize.x = sizeReal.x != 0 ? scaleReal.x / sizeReal.x : 0; + ratioSize.y = sizeReal.y != 0 ? scaleReal.y / sizeReal.y : 0; + ratioSize.z = sizeReal.z != 0 ? scaleReal.z / sizeReal.z : 0; + } } diff --git a/Assets/Scripts/Fade.cs b/Assets/Scripts/Fade.cs index ade88ac2..64605551 100644 --- a/Assets/Scripts/Fade.cs +++ b/Assets/Scripts/Fade.cs @@ -7,49 +7,49 @@ /// public class Fade : MonoBehaviour { - [Header("Fade Settings")] - public float fadeSpeed = 0.25f; - private int _fadeDirection = -1; - private Image _image; - private bool _play; + [Header("Fade Settings")] + public float fadeSpeed = 0.25f; + private int _fadeDirection = -1; + private Image _image; + private bool _play; - void Awake() - { - var envManager = FindObjectOfType(); - _play = envManager ? envManager.PlayerMode : false; - _image = GetComponentInChildren(); - ResetFade(); - } + void Awake() + { + var envManager = FindObjectOfType(); + _play = envManager ? envManager.PlayerMode : false; + _image = GetComponentInChildren(); + ResetFade(); + } - public void ResetFade() - { - _fadeDirection = -1; - _image.color = new Color(0, 0, 0, 0); - } + public void ResetFade() + { + _fadeDirection = -1; + _image.color = new Color(0, 0, 0, 0); + } - public void StartFade() - { - StopAllCoroutines(); - _fadeDirection *= -1; - if (_play) - { - StartCoroutine(FadeOutEnum()); - } - else - { - _image.color = _fadeDirection < 0 ? new Color(0, 0, 0, 0) : new Color(0, 0, 0, 1); - } - } + public void StartFade() + { + StopAllCoroutines(); + _fadeDirection *= -1; + if (_play) + { + StartCoroutine(FadeOutEnum()); + } + else + { + _image.color = _fadeDirection < 0 ? new Color(0, 0, 0, 0) : new Color(0, 0, 0, 1); + } + } - IEnumerator FadeOutEnum() - { - int localFadeDirection = _fadeDirection; - float alpha = _image.color.a; - while (localFadeDirection == _fadeDirection && alpha <= 1 && alpha >= 0) - { - alpha += _fadeDirection * Time.deltaTime * fadeSpeed; - _image.color = new Color(0, 0, 0, Mathf.Clamp(alpha, 0, 1)); - yield return null; - } - } + IEnumerator FadeOutEnum() + { + int localFadeDirection = _fadeDirection; + float alpha = _image.color.a; + while (localFadeDirection == _fadeDirection && alpha <= 1 && alpha >= 0) + { + alpha += _fadeDirection * Time.deltaTime * fadeSpeed; + _image.color = new Color(0, 0, 0, Mathf.Clamp(alpha, 0, 1)); + yield return null; + } + } } diff --git a/Assets/Scripts/FlashingImage.cs b/Assets/Scripts/FlashingImage.cs index 664afe0b..2d56d961 100644 --- a/Assets/Scripts/FlashingImage.cs +++ b/Assets/Scripts/FlashingImage.cs @@ -2,43 +2,48 @@ using UnityEngine.UI; /// -/// Manages the flashing of an image. +/// Manages the flashing of an image. The image will flash on and off at a specified speed. /// public class FlashingImage : MonoBehaviour { - [Header("Flashing Settings")] - public Image imageToFlash; - public float flashSpeed = 1.0f; - private float flashTimer = 0.0f; - private bool isFlashing = true; // Starting with false will flash image immediately + [Header("Flashing Settings")] + public Image imageToFlash; + public float flashSpeed = 1.0f; + private float flashTimer = 0.0f; + private bool isFlashing = true; /* Starting with false will flash image immediately */ - void Update() - { - if (isFlashing) - { - flashTimer += Time.deltaTime * flashSpeed; - float alpha = (Mathf.Sin(flashTimer) + 1) / 2; // Ranges from 0 to 1 - SetImageAlpha(alpha); - } - } + void Update() + { + if (isFlashing) + { + flashTimer += Time.deltaTime * flashSpeed; + float alpha = (Mathf.Sin(flashTimer) + 1) / 2; /* Ranges from 0 to 1 */ + SetImageAlpha(alpha); + } + } - private void SetImageAlpha(float alpha) - { - if (imageToFlash != null) - { - imageToFlash.color = new Color(imageToFlash.color.r, imageToFlash.color.g, imageToFlash.color.b, alpha); - } - } + private void SetImageAlpha(float alpha) + { + if (imageToFlash != null) + { + imageToFlash.color = new Color( + imageToFlash.color.r, + imageToFlash.color.g, + imageToFlash.color.b, + alpha + ); + } + } - public void StartFlashing() - { - isFlashing = true; - flashTimer = 0.0f; - } + public void StartFlashing() + { + isFlashing = true; + flashTimer = 0.0f; + } - public void StopFlashing() - { - isFlashing = false; - SetImageAlpha(1); // Ensures the image is fully visible when not flashing - } + public void StopFlashing() + { + isFlashing = false; + SetImageAlpha(1); /* Ensures the image is fully visible when not flashing */ + } } diff --git a/Assets/Scripts/Grounded.cs b/Assets/Scripts/Grounded.cs index 196e7a88..b1a47f0a 100644 --- a/Assets/Scripts/Grounded.cs +++ b/Assets/Scripts/Grounded.cs @@ -1,12 +1,10 @@ - - /// -/// Represents the ground in the environment. This class is used to adjust the y position of the ground. +/// Represents the ground in the environment. This class is used to adjust the y (axis) position of the ground. /// public class Grounded : Prefab { - protected override float AdjustY(float yIn) - { - return 0; - } + protected override float AdjustY(float yIn) + { + return 0; + } } diff --git a/Assets/Scripts/Holders.cs b/Assets/Scripts/Holders.cs index b31fa6bb..a2a4ac73 100644 --- a/Assets/Scripts/Holders.cs +++ b/Assets/Scripts/Holders.cs @@ -3,43 +3,42 @@ using System.Linq; /// -/// Facilitates the management and retrieval of Fade components associated with a collection of GameObjects, black screens. +/// Facilitates the management and retrieval of Fade components associated with a collection of GameObjects, black screens. /// namespace Holders { - class PositionRotation - { - public Vector3 Position { get; } - public Vector3 Rotation { get; } + class PositionRotation + { + public Vector3 Position { get; } + public Vector3 Rotation { get; } - public PositionRotation(Vector3 position, Vector3 rotation) - { - Position = position; - Rotation = rotation; - } - } + public PositionRotation(Vector3 position, Vector3 rotation) + { + Position = position; + Rotation = rotation; + } + } - [System.Serializable] - public class ListOfBlackScreens - { - public List allBlackScreens; + [System.Serializable] + public class ListOfBlackScreens + { + public List allBlackScreens; - public List GetFades() - { - // Safety check - if (allBlackScreens == null) - { - Debug.LogWarning("List of black screens is null."); - return new List(); - } + public List GetFades() + { + if (allBlackScreens == null) + { + Debug.LogWarning("List of black screens is null."); + return new List(); + } - // Use LINQ to get Fade components from allBlackScreens - return ( - from blackScreen in allBlackScreens - let fadeComponent = blackScreen.GetComponentInChildren() - where fadeComponent != null - select fadeComponent - ).ToList(); - } - } + /* Use LINQ to get Fade components from allBlackScreens: */ + return ( + from blackScreen in allBlackScreens + let fadeComponent = blackScreen.GetComponentInChildren() + where fadeComponent != null + select fadeComponent + ).ToList(); + } + } } diff --git a/Assets/Scripts/Lights.cs b/Assets/Scripts/Lights.cs index d6700c7c..f8c49305 100644 --- a/Assets/Scripts/Lights.cs +++ b/Assets/Scripts/Lights.cs @@ -7,89 +7,92 @@ /// namespace Lights { - public class InfiniteEnumerator : IEnumerator - { - private int _initialValue; - private int _currentValue; - - public InfiniteEnumerator(int initialValue = 0) - { - _initialValue = initialValue; - _currentValue = 0; - } - - public bool MoveNext() - { - _currentValue += _initialValue; - return true; - } - - public void Reset() - { - _currentValue = 0; - } - - public int Current => _currentValue; - - object IEnumerator.Current => Current; - - public void Dispose() { } - } - - public class LightsSwitch - { - private int _episodeLength; - private bool _lightStatus = true; - private List _blackouts; - private IEnumerator _blackoutsEnum; - private int _nextFrameSwitch = -1; - - public LightsSwitch(int episodeLength = 0, List blackouts = null) - { - if (episodeLength < 0) - throw new ArgumentException("Episode length cannot be negative."); - - _episodeLength = episodeLength; - _blackouts = blackouts ?? new List(); - - if (_blackouts.Count > 0) - { - foreach (var blackout in _blackouts) - { - if (blackout < 0 || blackout >= _episodeLength) - throw new ArgumentException("Blackout interval is invalid."); - } - - _blackouts.Sort(); - - _blackoutsEnum = _blackouts[0] < 0 ? new InfiniteEnumerator(-_blackouts[0]) : _blackouts.GetEnumerator(); - } - else - { - _blackoutsEnum = _blackouts.GetEnumerator(); - } - - Reset(); - } - - public void Reset() - { - _lightStatus = true; - _blackoutsEnum.Reset(); - _nextFrameSwitch = _blackoutsEnum.MoveNext() ? _blackoutsEnum.Current : -1; - } - - public bool LightStatus(int step, int agentDecisionInterval) - { - if (step < 0 || agentDecisionInterval <= 0) - throw new ArgumentException("Step and agent decision interval must be positive."); - - if (step == _nextFrameSwitch * agentDecisionInterval) - { - _lightStatus = !_lightStatus; - _nextFrameSwitch = _blackoutsEnum.MoveNext() ? _blackoutsEnum.Current : -1; - } - return _lightStatus; - } - } + public class InfiniteEnumerator : IEnumerator + { + private int _initialValue; + private int _currentValue; + + public InfiniteEnumerator(int initialValue = 0) + { + _initialValue = initialValue; + _currentValue = 0; + } + + public bool MoveNext() + { + _currentValue += _initialValue; + return true; + } + + public void Reset() + { + _currentValue = 0; + } + + public int Current => _currentValue; + + object IEnumerator.Current => Current; + + public void Dispose() { } + } + + public class LightsSwitch + { + private int _episodeLength; + private bool _lightStatus = true; + private List _blackouts; + private IEnumerator _blackoutsEnum; + private int _nextFrameSwitch = -1; + + public LightsSwitch(int episodeLength = 0, List blackouts = null) + { + if (episodeLength < 0) + throw new ArgumentException("Episode length cannot be negative."); + + _episodeLength = episodeLength; + _blackouts = blackouts ?? new List(); + + if (_blackouts.Count > 0) + { + foreach (var blackout in _blackouts) + { + if (blackout < 0 || blackout >= _episodeLength) + throw new ArgumentException("Blackout interval is invalid."); + } + + _blackouts.Sort(); + + _blackoutsEnum = + _blackouts[0] < 0 + ? new InfiniteEnumerator(-_blackouts[0]) + : _blackouts.GetEnumerator(); + } + else + { + _blackoutsEnum = _blackouts.GetEnumerator(); + } + + Reset(); + } + + public void Reset() + { + _lightStatus = true; + _blackoutsEnum.Reset(); + _nextFrameSwitch = _blackoutsEnum.MoveNext() ? _blackoutsEnum.Current : -1; + } + + public bool LightStatus(int step, int agentDecisionInterval) + { + if (step < 0 || agentDecisionInterval <= 0) + throw new ArgumentException("Step and agent decision interval must be positive."); + + if (step == _nextFrameSwitch * agentDecisionInterval) + { + _lightStatus = !_lightStatus; + _nextFrameSwitch = _blackoutsEnum.MoveNext() ? _blackoutsEnum.Current : -1; + } + return _lightStatus; + } + } } diff --git a/Assets/Scripts/NotificationManager.cs b/Assets/Scripts/NotificationManager.cs index 8a2a1932..228f0005 100644 --- a/Assets/Scripts/NotificationManager.cs +++ b/Assets/Scripts/NotificationManager.cs @@ -7,119 +7,118 @@ /// public class NotificationManager : MonoBehaviour { - [Header("Notification Settings")] - public Image notificationBackgroundImage; - public Image successGradientBorderImage; - public Image failureGradientBorderImage; - - [Header("GIF Settings")] - public Sprite[] successFrames; - public Sprite[] failureFrames; - public float frameRate = 0.1f; - private int currentFrame = 0; - - private Coroutine gifCoroutine; - private string currentNotificationState = "None"; - - public TrainingAgent trainingAgent; - public GameObject notificationPanel; - public static NotificationManager Instance; - - void Start() - { - LoadFrames(); - trainingAgent = FindObjectOfType(); - HideNotification(); - } - - void LoadFrames() - { - successFrames = Resources.LoadAll("happyGIF"); - failureFrames = Resources.LoadAll("sadGIF"); - } - - private void Awake() - { - SingletonCheck(); - } - - void SingletonCheck() - { - if (Instance == null) - { - Instance = this; - DontDestroyOnLoad(gameObject); - } - else - { - Destroy(gameObject); - } - } - - public void ShowSuccessNotification() - { - Debug.Log("Showing Success Notification"); - ShowNotification(true); - trainingAgent.FreezeAgent(true); - currentNotificationState = "Success"; - } - - public void ShowFailureNotification() - { - Debug.Log("Showing Failure Notification"); - ShowNotification(false); - trainingAgent.FreezeAgent(true); - currentNotificationState = "Failure"; - } - - private void ShowNotification(bool isSuccess) - { - Sprite[] framesToShow = isSuccess ? successFrames : failureFrames; - Image gradientBorderToShow = isSuccess ? successGradientBorderImage : failureGradientBorderImage; - - notificationPanel.SetActive(true); - successGradientBorderImage.gameObject.SetActive(isSuccess); - failureGradientBorderImage.gameObject.SetActive(!isSuccess); - - StopPreviousAnimation(); - - gifCoroutine = StartCoroutine(AnimateSprite(framesToShow)); - } - - void StopPreviousAnimation() - { - if (gifCoroutine != null) - { - StopCoroutine(gifCoroutine); - } - } - - public void HideNotification() - { - Debug.Log("Hiding Notification"); - notificationPanel.SetActive(false); - successGradientBorderImage.gameObject.SetActive(false); - failureGradientBorderImage.gameObject.SetActive(false); - - StopPreviousAnimation(); - - currentFrame = 0; - trainingAgent.FreezeAgent(false); - currentNotificationState = "None"; - } - - public string GetCurrentNotificationState() - { - return currentNotificationState; - } - - IEnumerator AnimateSprite(Sprite[] animationFrames) - { - while (true) - { - notificationBackgroundImage.sprite = animationFrames[currentFrame]; - currentFrame = (currentFrame + 1) % animationFrames.Length; - yield return new WaitForSeconds(frameRate); - } - } + [Header("Notification Settings")] + public Image notificationBackgroundImage; + public Image successGradientBorderImage; + public Image failureGradientBorderImage; + + [Header("GIF Settings")] + public Sprite[] successFrames; + public Sprite[] failureFrames; + public float frameRate = 0.1f; + private int currentFrame = 0; + + private Coroutine gifCoroutine; + private string currentNotificationState = "None"; + + public TrainingAgent trainingAgent; + public GameObject notificationPanel; + public static NotificationManager Instance; + + void Start() + { + LoadFrames(); + trainingAgent = FindObjectOfType(); + HideNotification(); + } + + void LoadFrames() + { + successFrames = Resources.LoadAll("happyGIF"); + failureFrames = Resources.LoadAll("sadGIF"); + } + + private void Awake() + { + SingletonCheck(); + } + + void SingletonCheck() + { + if (Instance == null) + { + Instance = this; + DontDestroyOnLoad(gameObject); + } + else + { + Destroy(gameObject); + } + } + + public void ShowSuccessNotification() + { + ShowNotification(true); + trainingAgent.FreezeAgent(true); + currentNotificationState = "Success"; + } + + public void ShowFailureNotification() + { + ShowNotification(false); + trainingAgent.FreezeAgent(true); + currentNotificationState = "Failure"; + } + + private void ShowNotification(bool isSuccess) + { + Sprite[] framesToShow = isSuccess ? successFrames : failureFrames; + Image gradientBorderToShow = isSuccess + ? successGradientBorderImage + : failureGradientBorderImage; + + notificationPanel.SetActive(true); + successGradientBorderImage.gameObject.SetActive(isSuccess); + failureGradientBorderImage.gameObject.SetActive(!isSuccess); + + StopPreviousAnimation(); + + gifCoroutine = StartCoroutine(AnimateSprite(framesToShow)); + } + + void StopPreviousAnimation() + { + if (gifCoroutine != null) + { + StopCoroutine(gifCoroutine); + } + } + + public void HideNotification() + { + notificationPanel.SetActive(false); + successGradientBorderImage.gameObject.SetActive(false); + failureGradientBorderImage.gameObject.SetActive(false); + + StopPreviousAnimation(); + + currentFrame = 0; + trainingAgent.FreezeAgent(false); + currentNotificationState = "None"; + } + + public string GetCurrentNotificationState() + { + return currentNotificationState; + } + + IEnumerator AnimateSprite(Sprite[] animationFrames) + { + while (true) + { + notificationBackgroundImage.sprite = animationFrames[currentFrame]; + currentFrame = (currentFrame + 1) % animationFrames.Length; + yield return new WaitForSeconds(frameRate); + } + } } diff --git a/Assets/Scripts/PlayerControls.cs b/Assets/Scripts/PlayerControls.cs index 92b56f03..4768b0c0 100644 --- a/Assets/Scripts/PlayerControls.cs +++ b/Assets/Scripts/PlayerControls.cs @@ -113,7 +113,7 @@ private void InitializeCameras() return; } - activeCameraIndex = canChangePerspective ? 0 : 2; // If can't change perspectives, use the 3rd person camera + activeCameraIndex = canChangePerspective ? 0 : 2; /* If can't change perspectives, use the bird's-eye camera */ Debug.Log( $"Initializing Cameras. Can Change Perspective: {canChangePerspective}, Active Camera Index: {activeCameraIndex}" ); diff --git a/Assets/Scripts/Prefab.cs b/Assets/Scripts/Prefab.cs index c0db40f4..310f0650 100644 --- a/Assets/Scripts/Prefab.cs +++ b/Assets/Scripts/Prefab.cs @@ -20,7 +20,7 @@ public class Prefab : MonoBehaviour, IPrefab public float sizeAdjustment = 0.999f; [Header("Texture Parameters")] - // To scale textures on dynamically-sized objects: + /* To scale textures on dynamically-sized objects */ public bool textureUVOverride = false; public bool typicalOrigin = true; protected float _height; @@ -42,7 +42,7 @@ public virtual void SetColor(Vector3 color) foreach (Renderer r in GetComponentsInChildren()) { if ( - r.material.GetFloat("_Surface") != 1 /*=Transparent*/ + r.material.GetFloat("_Surface") != 1 /* meaning 'Transparent' */ ) r.material.color = newColor; } @@ -116,8 +116,7 @@ protected virtual void RescaleUVs(bool child = false, GameObject childOverride = MF.sharedMesh = Instantiate(MF.mesh); Mesh MESH = MF.sharedMesh; - Transform T = /*(child) ? transform.parent :*/ - transform; + Transform T = transform; Vector2[] uvs = new Vector2[MESH.uv.Length]; Dictionary uvStretchLookup = new Dictionary diff --git a/Assets/Scripts/PrefabsInterface.cs b/Assets/Scripts/PrefabsInterface.cs index 19bd31b7..c370c0d7 100644 --- a/Assets/Scripts/PrefabsInterface.cs +++ b/Assets/Scripts/PrefabsInterface.cs @@ -4,11 +4,11 @@ /// Prefab Interface for the Prefab class. namespace PrefabInterface { - public interface IPrefab - { - void SetSize(Vector3 size); - void SetColor(Vector3 color); - Vector3 GetRotation(float rotationY); - Vector3 GetPosition(Vector3 position, Vector3 boundingBox, float rangeX, float rangeZ); - } + public interface IPrefab + { + void SetSize(Vector3 size); + void SetColor(Vector3 color); + Vector3 GetRotation(float rotationY); + Vector3 GetPosition(Vector3 position, Vector3 boundingBox, float rangeX, float rangeZ); + } } diff --git a/Assets/Scripts/Rewards/BallGoal.cs b/Assets/Scripts/Rewards/BallGoal.cs index 4822f20b..c4de9759 100644 --- a/Assets/Scripts/Rewards/BallGoal.cs +++ b/Assets/Scripts/Rewards/BallGoal.cs @@ -7,25 +7,24 @@ /// public class BallGoal : Goal { - // Adjusts the size of the goal within specified limits public override void SetSize(Vector3 size) { - // Clip size to within specified limits + /* Clip size to within specified limits */ Vector3 clippedSize = Vector3.Max(sizeMin, Vector3.Min(sizeMax, size)) * sizeAdjustment; - // If any size component is negative, choose a random size + /* If any size component is negative, choose a random size */ if (size.x < 0 || size.y < 0 || size.z < 0) { float randomSize = Random.Range(sizeMin.x, sizeMax.x); clippedSize = Vector3.one * randomSize; } - // Set height and scale of the goal + /* Set height and scale of the goal */ float scaledSize = clippedSize.x * ratioSize.x; _height = scaledSize; transform.localScale = new Vector3(scaledSize, scaledSize, scaledSize); - // Update reward based on size + /* Update reward based on size */ reward = Math.Sign(reward) * scaledSize; } } diff --git a/Assets/Scripts/Rewards/DeathZone.cs b/Assets/Scripts/Rewards/DeathZone.cs index 1fea54b6..526f60aa 100644 --- a/Assets/Scripts/Rewards/DeathZone.cs +++ b/Assets/Scripts/Rewards/DeathZone.cs @@ -5,10 +5,9 @@ /// public class DeathZone : Goal { - // Adjusts the size of the death zone within specified limits public override void SetSize(Vector3 size) { - // Clip size to within specified limits + /* Clip size to within specified limits */ Vector3 clippedSize = Vector3.Max(sizeMin, Vector3.Min(sizeMax, size)) * sizeAdjustment; // Adjust individual size components if any are negative @@ -16,7 +15,7 @@ public override void SetSize(Vector3 size) float sizeY = size.y < 0 ? Random.Range(sizeMin.y, sizeMax.y) : clippedSize.y; float sizeZ = size.z < 0 ? Random.Range(sizeMin.z, sizeMax.z) : clippedSize.z; - // Set height and scale of the death zone + /* Set height and scale of the deathzone */ _height = sizeY; transform.localScale = new Vector3( sizeX * ratioSize.x, @@ -24,13 +23,12 @@ public override void SetSize(Vector3 size) sizeZ * ratioSize.z ); - // Set object scale for shader effects + /* Set object scale for shader effects */ GetComponent().material.SetVector("_ObjScale", new Vector3(sizeX, sizeY, sizeZ)); } - // Adjusts the Y position of the death zone protected override float AdjustY(float yIn) { - return -0.15f; // Adjust Y position by a fixed value + return -0.15f; } } diff --git a/Assets/Scripts/Rewards/DecayGoal.cs b/Assets/Scripts/Rewards/DecayGoal.cs index 4d4dfdae..f59318a0 100644 --- a/Assets/Scripts/Rewards/DecayGoal.cs +++ b/Assets/Scripts/Rewards/DecayGoal.cs @@ -20,7 +20,7 @@ public class DecayGoal : BallGoal public Color finalColour; public bool flipDecayDirection = false; - public int fixedFrameDelay = 150; // Controls how long the goal waits before starting to decay + public int fixedFrameDelay = 150; /* Controls how long the goal waits before starting to decay */ private Material _basemat; private Material _radialmat; @@ -51,7 +51,7 @@ public override void SetFinalValue(float v) public override void SetDelay(float v) { fixedFrameDelay = Mathf.RoundToInt(v); - delayCounter = fixedFrameDelay; // Reset delay counter to new value + delayCounter = fixedFrameDelay; /* Reset delay counter to new value */ } private void CheckIfNeedToFlip() @@ -87,8 +87,8 @@ void Start() SetSize((flipDecayDirection ? finalReward : initialReward) * Vector3.one); CheckIfNeedToFlip(); - delayCounter = fixedFrameDelay; + delayCounter = fixedFrameDelay; tag = "goodGoalMulti"; reward = initialReward; diff --git a/Assets/Scripts/Rewards/Goal.cs b/Assets/Scripts/Rewards/Goal.cs index c1b7c8f0..f85c04d9 100644 --- a/Assets/Scripts/Rewards/Goal.cs +++ b/Assets/Scripts/Rewards/Goal.cs @@ -5,63 +5,61 @@ /// public class Goal : Prefab { - [Header("Goal Settings")] - public int numberOfGoals = 1; - public float reward = 1; - public bool isMulti = false; - public string rewardType = "None"; // None or a color name (a placeholder for now) + [Header("Goal Settings")] + public int numberOfGoals = 1; + public float reward = 1; + public bool isMulti = false; + public string rewardType = "None"; /* Reward types as strings */ - void Awake() - { - canRandomizeColor = false; - } + void Awake() + { + canRandomizeColor = false; + } - public virtual void OnTriggerEnter(Collider other) - { - if (other.gameObject.CompareTag("agent")) - { - TrainingAgent agent = other.GetComponent(); - if (agent != null) - { - agent.RecordRewardType(rewardType); // Important to record the reward type before logging to .csv file - agent.UpdateHealth(reward, true); - } - } - } + public virtual void OnTriggerEnter(Collider other) + { + if (other.gameObject.CompareTag("agent")) + { + TrainingAgent agent = other.GetComponent(); + if (agent != null) + { + agent.RecordRewardType(rewardType); + agent.UpdateHealth(reward, true); + } + } + } - public virtual void OnCollisionEnter(Collision collision) - { - if (collision.gameObject.CompareTag("agent")) - { - TrainingAgent agent = collision.gameObject.GetComponent(); - if (agent != null) - { - agent.RecordRewardType(rewardType); - if (!isMulti) - { - agent.UpdateHealth(reward, true); - Debug.Log($"OnCollisionEnter: Reward type {rewardType} recorded for agent."); - } - else - { - agent.numberOfGoalsCollected++; - if (agent.numberOfGoalsCollected >= numberOfGoals) - { - agent.UpdateHealth(reward, true); - Debug.Log($"OnCollisionEnter (Multi): Reward type {rewardType} recorded for agent."); - } - else - { - agent.UpdateHealth(reward); - } - gameObject.SetActive(false); - Object.Destroy(gameObject); - } - } - else - { - Debug.LogError("Agent not found in the collision object."); - } - } - } + public virtual void OnCollisionEnter(Collision collision) + { + if (collision.gameObject.CompareTag("agent")) + { + TrainingAgent agent = collision.gameObject.GetComponent(); + if (agent != null) + { + agent.RecordRewardType(rewardType); + if (!isMulti) + { + agent.UpdateHealth(reward, true); + } + else + { + agent.numberOfGoalsCollected++; + if (agent.numberOfGoalsCollected >= numberOfGoals) + { + agent.UpdateHealth(reward, true); + } + else + { + agent.UpdateHealth(reward); + } + gameObject.SetActive(false); + Object.Destroy(gameObject); + } + } + else + { + Debug.LogError("Agent not found in the collision object."); + } + } + } } diff --git a/Assets/Scripts/Rewards/SizeChangeGoal.cs b/Assets/Scripts/Rewards/SizeChangeGoal.cs index 571a362f..d866b1d1 100644 --- a/Assets/Scripts/Rewards/SizeChangeGoal.cs +++ b/Assets/Scripts/Rewards/SizeChangeGoal.cs @@ -16,6 +16,7 @@ public enum InterpolationMethod Constant, Linear } + [Header("Interpolation Method")] public InterpolationMethod interpolationMethod; public bool rewardSizeTracking = true; @@ -106,11 +107,11 @@ private void FixedUpdate() if (!finishedSizeChange && freeToGrow) { - if ((int)interpolationMethod == 0) /*Constant*/ + if ((int)interpolationMethod == 0) /* Constant */ { SetSize((_height + sizeChangeRate) * Vector3.one); } - else if ((int)interpolationMethod > 0) /*Polynomial*/ + else if ((int)interpolationMethod > 0) /* Polynomial */ { PolyInterpolationUpdate(); } diff --git a/Assets/Scripts/ScreenshotCamera.cs b/Assets/Scripts/ScreenshotCamera.cs index 69b84f79..34dabd43 100644 --- a/Assets/Scripts/ScreenshotCamera.cs +++ b/Assets/Scripts/ScreenshotCamera.cs @@ -7,65 +7,81 @@ [RequireComponent(typeof(Camera))] public class ScreenshotCamera : MonoBehaviour { - [Header("Screenshot Settings")] - public int fileCounter = 0; - public RenderTexture renderTexture; - public string filePath = "Screenshots"; - public string fileName = "capture"; - private Camera screenshotCam; - public bool testMode = false; + [Header("Screenshot Settings")] + public int fileCounter = 0; + public RenderTexture renderTexture; + public string filePath = "Screenshots"; + public string fileName = "capture"; + private Camera screenshotCam; + public bool testMode = false; - private void Awake() - { - screenshotCam = GetComponent(); - InitializeRenderTexture(); - } + private void Awake() + { + screenshotCam = GetComponent(); + InitializeRenderTexture(); + } - private void InitializeRenderTexture() - { - if (!testMode && renderTexture != null) - { - screenshotCam.targetTexture = new RenderTexture(renderTexture.width, renderTexture.height, renderTexture.depth, renderTexture.format, RenderTextureReadWrite.sRGB); - } - else - { - Debug.LogWarning("RenderTexture is not assigned or in Test Mode."); - } - } + private void InitializeRenderTexture() + { + if (!testMode && renderTexture != null) + { + screenshotCam.targetTexture = new RenderTexture( + renderTexture.width, + renderTexture.height, + renderTexture.depth, + renderTexture.format, + RenderTextureReadWrite.sRGB + ); + } + else + { + Debug.LogWarning("RenderTexture is not assigned or in Test Mode."); + } + } - public void Activate(bool enable = true) - { - screenshotCam.enabled = enable; - } + public void Activate(bool enable = true) + { + screenshotCam.enabled = enable; + } - private void LateUpdate() - { - if (screenshotCam.enabled && !testMode) - { - CaptureScreenshot(); - Activate(false); // Deactivate the camera after capturing to prevent multiple captures. - } - } + private void LateUpdate() + { + if (screenshotCam.enabled && !testMode) + { + CaptureScreenshot(); + Activate(false); // Deactivate the camera after capturing to prevent multiple captures. + } + } - private void CaptureScreenshot() - { - screenshotCam.Render(); - RenderTexture.active = screenshotCam.targetTexture; + private void CaptureScreenshot() + { + screenshotCam.Render(); + RenderTexture.active = screenshotCam.targetTexture; - Texture2D image = new Texture2D(screenshotCam.targetTexture.width, screenshotCam.targetTexture.height, TextureFormat.RGB24, false); - image.ReadPixels(new Rect(0, 0, screenshotCam.targetTexture.width, screenshotCam.targetTexture.height), 0, 0); - image.Apply(); - byte[] bytes = image.EncodeToPNG(); - Destroy(image); // Free the image from memory after encoding. + Texture2D image = new Texture2D( + screenshotCam.targetTexture.width, + screenshotCam.targetTexture.height, + TextureFormat.RGB24, + false + ); + image.ReadPixels( + new Rect(0, 0, screenshotCam.targetTexture.width, screenshotCam.targetTexture.height), + 0, + 0 + ); + image.Apply(); + byte[] bytes = image.EncodeToPNG(); + Destroy(image); - string directoryPath = Path.Combine(Application.persistentDataPath, filePath); - Directory.CreateDirectory(directoryPath); // Ensure the directory exists. + string directoryPath = Path.Combine(Application.persistentDataPath, filePath); + Directory.CreateDirectory(directoryPath); - string formattedFileName = $"{fileName}{fileCounter}_{System.DateTime.Now:dd-MM_HH-mm-ss}.png"; - string fullPath = Path.Combine(directoryPath, formattedFileName); + string formattedFileName = + $"{fileName}{fileCounter}_{System.DateTime.Now:dd-MM_HH-mm-ss}.png"; + string fullPath = Path.Combine(directoryPath, formattedFileName); - File.WriteAllBytes(fullPath, bytes); - Debug.Log($"Screenshot saved to {fullPath}"); - fileCounter++; - } + File.WriteAllBytes(fullPath, bytes); + Debug.Log($"Screenshot saved to {fullPath}"); + fileCounter++; + } } diff --git a/Assets/Scripts/Spawners/GoalSpawner.cs b/Assets/Scripts/Spawners/GoalSpawner.cs index 76ebd66f..06c084f0 100644 --- a/Assets/Scripts/Spawners/GoalSpawner.cs +++ b/Assets/Scripts/Spawners/GoalSpawner.cs @@ -16,19 +16,19 @@ public class GoalSpawner : Prefab public bool variableSpawnPosition; public float sphericalSpawnRadius; public Vector3 defaultSpawnPosition; - public float timeToRipen; // Seconds - public float timeBetweenSpawns; // Seconds - public float delaySeconds; // Seconds - public int spawnCount; // '-1' = infinite spawning + public float timeToRipen; /* Seconds */ + public float timeBetweenSpawns; /* Seconds */ + public float delaySeconds; /* Seconds */ + public int spawnCount; [ColorUsage(true, true)] private Color colourOverride; - // Random Seeds + /* Random Seeds */ public int objSpawnSeed = 0; public int spawnSizeSeed = 0; - // RNGs + /* Random Number Generators (RNGs) */ private System.Random[] RNGs = new System.Random[4]; private enum E diff --git a/Assets/Scripts/Spawners/SpawnerStockpiler.cs b/Assets/Scripts/Spawners/SpawnerStockpiler.cs index de840e34..6c6207f8 100644 --- a/Assets/Scripts/Spawners/SpawnerStockpiler.cs +++ b/Assets/Scripts/Spawners/SpawnerStockpiler.cs @@ -10,7 +10,7 @@ public class SpawnerStockpiler : GoalSpawner { [Header("Stockpiling Settings")] public bool isStockpiling = true; - public int doorOpenDelay = -1; // '-1' means "open indefinitely" + public int doorOpenDelay = -1; /* '-1' means "open indefinitely" */ public bool isDoorOpenInfinite = false; public float timeUntilDoorOpens = 1.5f; public float timeUntilDoorCloses = 1.5f; @@ -60,7 +60,9 @@ private void InitializeVariables() canRandomizeColor = true; } - // Door control coroutine + /// + /// Manages the door's opening and closing animations. + /// private IEnumerator ManageDoor(bool includeInitDelay = true, bool isDoorOpening = true) { if (includeInitDelay) @@ -118,7 +120,6 @@ private void FixedUpdate() } } - // Check if there is space to materialize a new goal private bool FreeToMaterialize(float radius, BallGoal goal = null) { Collider[] sphereCheck = Physics.OverlapSphere( @@ -136,7 +137,9 @@ private bool FreeToMaterialize(float radius, BallGoal goal = null) return true; } - // Physically materialize or dematerialize a spawned goal + /// + /// Physically materialize or dematerialize a spawned goal. + /// private void ChangeImmaterialStorage(BallGoal goal, bool isMaterializing) { goal.GetComponent().enabled = isMaterializing; diff --git a/Assets/Scripts/Spawners/Spawner_InteractiveButton.cs b/Assets/Scripts/Spawners/Spawner_InteractiveButton.cs index 34c32fab..e7bd6091 100644 --- a/Assets/Scripts/Spawners/Spawner_InteractiveButton.cs +++ b/Assets/Scripts/Spawners/Spawner_InteractiveButton.cs @@ -105,7 +105,7 @@ public IEnumerator MoveAndReset() IsMoving = true; Vector3 originalPosition = childObjectToMove.transform.position; - Vector3 movementDirection = -transform.forward * moveOffset.x; // Use parent object's negative local Z axis + Vector3 movementDirection = -transform.forward * moveOffset.x; /* Use parent object's negative local Z axis */ Vector3 targetPosition = originalPosition + movementDirection; float startTime = Time.time; @@ -164,7 +164,7 @@ private GameObject ChooseReward() } } - // If no reward is selected within the loop (which should not happen), return the last reward + /* If no reward is selected within the loop (which should not happen), return the last reward */ return Rewards[Rewards.Count - 1]; } @@ -226,20 +226,19 @@ private void SpawnReward() { spawnPosition = RewardSpawnPos; } - // Otherwise, random spawning. - else + else /* Randomize spawn position within the arena bounds */ { float arenaWidth = arenaBuilder.ArenaWidth; float arenaDepth = arenaBuilder.ArenaDepth; - // Randomly generate a spawn position within the bounds of the arena, as defined by Arenabuilders.cs. + /* Randomly generate a spawn position within the bounds of the arena, as defined by Arenabuilders.cs. */ spawnPosition = new Vector3( Random.Range(0, arenaWidth), 0, Random.Range(0, arenaDepth) ); } - // Check for randomization flags for x and z axes + if (RewardSpawnPos.x == -1) { spawnPosition.x = Random.Range(0, arenaBuilder.ArenaWidth); diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 4f894e87..abe7978b 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -162,28 +162,29 @@ public override void Initialize() private void InitialiseCSVProcess() { - // Base path for the logs to be stored + /* Base path for the logs to be stored */ string basePath; if (Application.isEditor) { - // The root directory is the parent of the Assets folder + /* The root directory is the parent of the Assets folder */ basePath = Path.GetFullPath(Path.Combine(Application.dataPath, "..")); } else { - // Important! For builds, use the parent of the directory where the executable resides + /* Important! For builds, use the parent of the directory where the executable resides */ basePath = Path.GetDirectoryName(Application.dataPath); } - string directoryPath = Path.Combine(basePath, "ObservationLogs"); + string directoryPath = Path.Combine(basePath, "ObservationLogs"); /* Directory to store the logs under folder "ObservationLogs" */ if (!Directory.Exists(directoryPath)) { Directory.CreateDirectory(directoryPath); } - // Generate a filename with the YAML file name and a date stamp to prevent overwriting. TODO: Extract YAML name from side channel message + /* Generate a filename with the YAML file name and a date stamp to prevent overwriting. */ + // TODO: Extract YAML name from side channel message. string dateTimeString = DateTime.Now.ToString("dd-MM-yy_HHmm"); string filename = $"Observations_{yamlFileName}_{dateTimeString}.csv"; csvFilePath = Path.Combine(directoryPath, filename); @@ -281,7 +282,6 @@ private void FlushLogQueue() /// /// Starts a thread that checks if the log queue is full and flushes it to the CSV file if it is. - // WARNING: im not sure if this is the best way to handle this, but it works for now /// private void StartFlushThread() { @@ -289,7 +289,7 @@ private void StartFlushThread() { while (true) { - flushEvent.WaitOne(); // Wait until signaled + flushEvent.WaitOne(); if (logQueue.Count >= bufferSize && !isFlushing) { isFlushing = true; @@ -309,7 +309,7 @@ protected override void OnDisable() base.OnDisable(); if (writer != null) { - FlushLogQueue(); // Ensures all buffered data is written to the file before closing + FlushLogQueue(); /* Flush any remaining logs in the queue */ writer.Close(); } diff --git a/Assets/Scripts/TrainingArena.cs b/Assets/Scripts/TrainingArena.cs index ccc5055f..1fde26d8 100644 --- a/Assets/Scripts/TrainingArena.cs +++ b/Assets/Scripts/TrainingArena.cs @@ -135,8 +135,7 @@ public void ResetArena() CleanUpSpawnedObjects(); SetNextArenaID(); - - // Load the new configuration + ArenaConfiguration newConfiguration = _environmentManager.GetConfiguration(arenaID); ApplyNewArenaConfiguration(newConfiguration); @@ -148,7 +147,6 @@ public void ResetArena() public void LoadNextArena() { - // TrainingArena must have reset() called at first to initialise arenaID if (isFirstArenaReset) { throw new InvalidOperationException("LoadNextArena called before first reset"); @@ -161,7 +159,6 @@ public void LoadNextArena() ArenaConfiguration newConfiguration = _environmentManager.GetConfiguration(arenaID); - // Checks if its final arena in config file and if mergeNextArena is set to true, throws an exception int totalArenas = _environmentManager.GetTotalArenas(); if (arenaID == totalArenas - 1 && newConfiguration.mergeNextArena) { @@ -218,7 +215,6 @@ private void SetNextArenaID() private int ChooseRandomArenaID(int totalArenas) { - // Populate the list of merged arenas if needed if (_mergedArenas == null) { _mergedArenas = GetMergedArenas(); @@ -265,9 +261,6 @@ private void NotifyArenaChange() _environmentManager.TriggerArenaChangeEvent(arenaID, _environmentManager.GetTotalArenas()); } - /// - /// Destroys all spawned rewards in the arena. - /// private void CleanupRewards() { foreach (var reward in spawnedRewards) @@ -277,9 +270,6 @@ private void CleanupRewards() spawnedRewards.Clear(); } - /// - /// Updates the light status in the arena based on the current step count. - /// public void UpdateLigthStatus() { int stepCount = _agent.StepCount; @@ -297,17 +287,11 @@ public void UpdateLigthStatus() } } - /// - /// Returns the total number of spawned objects in the arena. - /// public int GetTotalSpawnedObjects() { return spawnedObjectsHolder.transform.childCount; } - /// - /// Callback for when a reward is spawned in the arena. - /// private void OnRewardSpawned(GameObject reward) { spawnedRewards.Add(reward); diff --git a/Assets/Scripts/UnityEngineExtensions.cs b/Assets/Scripts/UnityEngineExtensions.cs index 563a1267..e211d66f 100644 --- a/Assets/Scripts/UnityEngineExtensions.cs +++ b/Assets/Scripts/UnityEngineExtensions.cs @@ -30,7 +30,7 @@ public static GameObject FindChildWithTag(this Transform parent, string tag) return child.gameObject; } } - return null; // Return null if no child is found with the tag + return null; } } diff --git a/Assets/Scripts/YAMLclasses.cs b/Assets/Scripts/YAMLclasses.cs index a8b5b533..bc86aacb 100644 --- a/Assets/Scripts/YAMLclasses.cs +++ b/Assets/Scripts/YAMLclasses.cs @@ -7,138 +7,140 @@ /// namespace YAMLDefs { - /// - /// YAMLReader class is used to read YAML files. It uses YamlDotNet library to deserialize YAML files. - /// - public class YAMLReader - { - public YamlDotNet.Serialization.IDeserializer deserializer = new DeserializerBuilder() - .WithTagMapping("!ArenaConfig", typeof(YAMLDefs.ArenaConfig)) - .WithTagMapping("!Arena", typeof(YAMLDefs.Arena)) - .WithTagMapping("!Item", typeof(YAMLDefs.Item)) - .WithTagMapping("!Vector3", typeof(Vector3)) - .WithTagMapping("!RGB", typeof(YAMLDefs.RGB)) - //.IgnoreUnmatchedProperties() TODO: research this and it's implications. - .Build(); - } + /// + /// YAMLReader class is used to read YAML files. It uses YamlDotNet library to deserialize YAML files. + /// + public class YAMLReader + { + public YamlDotNet.Serialization.IDeserializer deserializer = new DeserializerBuilder() + .WithTagMapping("!ArenaConfig", typeof(YAMLDefs.ArenaConfig)) + .WithTagMapping("!Arena", typeof(YAMLDefs.Arena)) + .WithTagMapping("!Item", typeof(YAMLDefs.Item)) + .WithTagMapping("!Vector3", typeof(Vector3)) + .WithTagMapping("!RGB", typeof(YAMLDefs.RGB)) + //.IgnoreUnmatchedProperties() TODO: research this and it's implications. + .Build(); + } - /// - /// ArenaConfig class is used to deserialize the root object of the YAML file. It contains a dictionary of arenas and some global settings. - /// - public class ArenaConfig - { - public IDictionary arenas { get; set; } - public bool randomizeArenas { get; set; } = false; - public bool showNotification { get; set; } = false; - public bool canResetEpisode { get; set; } = true; - public bool canChangePerspective { get; set; } = true; - } + /// + /// ArenaConfig class is used to deserialize the root object of the YAML file. It contains a dictionary of arenas and some global settings. + /// + public class ArenaConfig + { + public IDictionary arenas { get; set; } + public bool randomizeArenas { get; set; } = false; + public bool showNotification { get; set; } = false; + public bool canResetEpisode { get; set; } = true; + public bool canChangePerspective { get; set; } = true; + } - /// - /// Arena class is used to deserialize the arena object in the YAML file. It contains the settings for the arena --> "local" settings. - /// - public class Arena - { - public int timeLimit { get; set; } = 0; - public List items { get; set; } = new List(); - public float passMark { get; set; } = 0; - public static float CurrentPassMark { get; private set; } + /// + /// Arena class is used to deserialize the arena object in the YAML file. It contains the settings for the arena --> "local" settings. + /// + public class Arena + { + public int timeLimit { get; set; } = 0; + public List items { get; set; } = new List(); + public float passMark { get; set; } = 0; + public static float CurrentPassMark { get; private set; } - public void SetCurrentPassMark() - { - CurrentPassMark = passMark; - } + public void SetCurrentPassMark() + { + CurrentPassMark = passMark; + } - public List blackouts { get; set; } = new List(); - public int randomSeed { get; set; } = 0; - public bool mergeNextArena { get; set; } = false; - } + public List blackouts { get; set; } = new List(); + public int randomSeed { get; set; } = 0; + public bool mergeNextArena { get; set; } = false; + } - /// - /// Item class is used to deserialize the item object in the YAML file. It contains the settings for the game objects in the arena. - /// Each game object will require the following required and optional parameters in the yaml file under Item tags. - /// - public class Item - { - /* MANDATORY OR REQUIRED PARAMETERS */ - public string name { get; set; } = ""; - public List positions { get; set; } = new List(); - public List rotations { get; set; } = new List(); - public List sizes { get; set; } = new List(); - public List colors { get; set; } = new List(); + /// + /// Item class is used to deserialize the item object in the YAML file. It contains the settings for the game objects in the arena. + /// Each game object will require the following required and optional parameters in the yaml file under Item tags. + /// + public class Item + { + /* MANDATORY OR REQUIRED PARAMETERS */ + public string name { get; set; } = ""; + public List positions { get; set; } = new List(); + public List rotations { get; set; } = new List(); + public List sizes { get; set; } = new List(); + public List colors { get; set; } = new List(); - /* EXTRA OR OPTIONAL PARAMETERS */ - public List skins { get; set; } = new List(); - public List frozenAgentDelays { get; set; } = new List(); + /* EXTRA OR OPTIONAL PARAMETERS */ + public List skins { get; set; } = new List(); + public List frozenAgentDelays { get; set; } = new List(); - // SignBoard - public List symbolNames { get; set; } = new List(); + // SignBoard + public List symbolNames { get; set; } = new List(); - // Spawner/Dispensers - public List delays { get; set; } = new List(); - public List initialValues { get; set; } = new List(); - public List finalValues { get; set; } = new List(); - public List spawnCounts { get; set; } = new List(); - public List spawnColors { get; set; } = new List(); - public List timesBetweenSpawns { get; set; } = new List(); - public List doorDelays { get; set; } = new List(); - public List timesBetweenDoorOpens { get; set; } = new List(); - public List changeRates { get; set; } = new List(); - public List ripenTimes { get; set; } = new List(); + // Spawner/Dispensers + public List delays { get; set; } = new List(); + public List initialValues { get; set; } = new List(); + public List finalValues { get; set; } = new List(); + public List spawnCounts { get; set; } = new List(); + public List spawnColors { get; set; } = new List(); + public List timesBetweenSpawns { get; set; } = new List(); + public List doorDelays { get; set; } = new List(); + public List timesBetweenDoorOpens { get; set; } = new List(); + public List changeRates { get; set; } = new List(); + public List ripenTimes { get; set; } = new List(); - // SpawnerButton - public List moveDurations { get; set; } = new List(); - public List resetDurations { get; set; } = new List(); - public float spawnProbability { get; set; } = 1f; - public List rewardNames { get; set; } = new List(); - public List rewardWeights { get; set; } = new List(); - public Vector3 rewardSpawnPos { get; set; } = new Vector3(0, 0, 0); - public List maxRewardCounts { get; set; } = new List(); - - // DataZone - public List triggerZoneID { get; set; } = new List(); - public bool zoneVisibility { get; set; } = true; - } + // SpawnerButton + public List moveDurations { get; set; } = new List(); + public List resetDurations { get; set; } = new List(); + public float spawnProbability { get; set; } = 1f; + public List rewardNames { get; set; } = new List(); + public List rewardWeights { get; set; } = new List(); + public Vector3 rewardSpawnPos { get; set; } = new Vector3(0, 0, 0); + public List maxRewardCounts { get; set; } = new List(); - /// - /// RGB class is used to deserialize the RGB object in the YAML file, such as colors for the game objects. - public class RGB - { - public float r { get; set; } = 0; - public float g { get; set; } = 0; - public float b { get; set; } = 0; - } + // DataZone + public List triggerZoneID { get; set; } = new List(); + public bool zoneVisibility { get; set; } = true; + } - /// - /// AliasMapper class is used to map the old names of the game objects to the new names. This is used to maintain compatibility with the old YAML files. - /// - public static class AliasMapper - { - private static readonly Dictionary AliasMap = new Dictionary - { - { "Cardbox1", "LightBlock" }, - { "Cardbox2", "HeavyBlock" }, - { "LObject", "LBlock" }, - { "LObject2", "JBlock" }, - { "UObject", "UBlock" }, - { "AntiDecayGoal", "RipenGoal" }, - { "SpawnerDispenser", "SpawnerDispenserTall" }, - { "SpawnerContainer", "SpawnerContainerShort" }, - { "SignPosterboard", "SignBoard" }, - { "Pillar-Button", "SpawnerButton" }, - }; + /// + /// RGB class is used to deserialize the RGB object in the YAML file, such as colors for the game objects. + public class RGB + { + public float r { get; set; } = 0; + public float g { get; set; } = 0; + public float b { get; set; } = 0; + } - /// - /// ResolveAlias method is used to resolve the alias of the game object name for backwards-compatibility. - /// - public static string ResolveAlias(string name) - { - if (AliasMap.TryGetValue(name, out string newName)) - { - Debug.Log($"Alias/old name for game object found. '{name}' is mapped to '{newName}'"); - return newName; - } - return name; - } - } + /// + /// AliasMapper class is used to map the old names of the game objects to the new names. This is used to maintain compatibility with the old YAML files. + /// + public static class AliasMapper + { + private static readonly Dictionary AliasMap = new Dictionary + { + { "Cardbox1", "LightBlock" }, + { "Cardbox2", "HeavyBlock" }, + { "LObject", "LBlock" }, + { "LObject2", "JBlock" }, + { "UObject", "UBlock" }, + { "AntiDecayGoal", "RipenGoal" }, + { "SpawnerDispenser", "SpawnerDispenserTall" }, + { "SpawnerContainer", "SpawnerContainerShort" }, + { "SignPosterboard", "SignBoard" }, + { "Pillar-Button", "SpawnerButton" }, + }; + + /// + /// ResolveAlias method is used to resolve the alias of the game object name for backwards-compatibility. + /// + public static string ResolveAlias(string name) + { + if (AliasMap.TryGetValue(name, out string newName)) + { + Debug.Log( + $"Alias/old name for game object found. '{name}' is mapped to '{newName}'" + ); + return newName; + } + return name; + } + } } From fff8daa79cd0d392a9c9502cf3beb079b997c262 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Fri, 26 Jul 2024 20:54:58 +0300 Subject: [PATCH 133/205] reordered columns: moved activecamera column in .csv to 2nd to last. --- Assets/Scripts/TrainingAgent.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index abe7978b..e6d19959 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -196,7 +196,7 @@ private void InitialiseCSVProcess() if (!headerWritten) { writer.WriteLine( - "Episode,Step,Health,Reward,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForwardWithDescription,ActionRotateWithDescription,WasAgentFrozen?,NotificationShown?,CollectedRewardType,DispensedRewardType,WasRewardDispensed?,WasSpawnerButtonTriggered?,CombinedSpawnerInfo,WasAgentInDataZone?,CombinedRaycastData,ActiveCamera" + "Episode,Step,Health,Reward,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForwardWithDescription,ActionRotateWithDescription,WasAgentFrozen?,NotificationShown?,CollectedRewardType,DispensedRewardType,WasRewardDispensed?,WasSpawnerButtonTriggered?,CombinedSpawnerInfo,WasAgentInDataZone?,ActiveCamera,CombinedRaycastData" ); headerWritten = true; } @@ -225,8 +225,8 @@ private void LogToCSV( bool wasSpawnerButtonTriggered, string combinedSpawnerInfo, string wasAgentInDataZone, - string combinedRaycastData, - string activeCameraDescription + string activeCameraDescription, + string combinedRaycastData ) { string logEntry = string.Format( @@ -251,8 +251,8 @@ string activeCameraDescription wasSpawnerButtonTriggered ? "Yes" : "No", combinedSpawnerInfo.Replace(",", ";"), wasAgentInDataZone, - combinedRaycastData, - activeCameraDescription + activeCameraDescription, + combinedRaycastData ); logQueue.Enqueue(logEntry); @@ -428,8 +428,8 @@ public override void OnActionReceived(ActionBuffers action) wasSpawnerButtonTriggered, combinedSpawnerInfo, wasAgentInDataZone, - combinedRaycastData, - playerControls.GetActiveCameraDescription() + playerControls.GetActiveCameraDescription(), + combinedRaycastData ); dispensedRewardType = "None"; From 73894e9d73dc7d8e08ee73a25c7a95fb61e9c8bf Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Fri, 26 Jul 2024 21:34:40 +0300 Subject: [PATCH 134/205] minor comment reformat --- Assets/Scripts/TrainingAgent.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index e6d19959..378461c9 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -176,7 +176,8 @@ private void InitialiseCSVProcess() basePath = Path.GetDirectoryName(Application.dataPath); } - string directoryPath = Path.Combine(basePath, "ObservationLogs"); /* Directory to store the logs under folder "ObservationLogs" */ + /* Directory to store the logs under folder "ObservationLogs" */ + string directoryPath = Path.Combine(basePath, "ObservationLogs"); if (!Directory.Exists(directoryPath)) { From 222749df5e83756c7f7391d06d90cab8e9ecd7c5 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Sat, 27 Jul 2024 14:31:46 +0300 Subject: [PATCH 135/205] Update TrainingAgent.cs --- Assets/Scripts/TrainingAgent.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 378461c9..accb0dff 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -66,7 +66,6 @@ public class TrainingAgent : Agent, IPrefab public string csvFilePath = ""; private StreamWriter writer; private bool headerWritten = false; - private string yamlFileName; private int customEpisodeCount = 0; private ConcurrentQueue logQueue = new ConcurrentQueue(); private const int bufferSize = 101; /* Corresponds to rows in the CSV file to keep in memory before flushing to disk */ @@ -77,6 +76,8 @@ public class TrainingAgent : Agent, IPrefab private bool wasRewardDispensed = false; private bool wasSpawnerButtonTriggered = false; private string combinedSpawnerInfo = ""; + + private string yamlFileName; private AutoResetEvent flushEvent = new AutoResetEvent(false); public void RecordSpawnerInfo(string spawnerInfo) From 06d4c9f19186a99cd4c99e6f2d307dea2902c76c Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Sat, 27 Jul 2024 14:44:12 +0300 Subject: [PATCH 136/205] Update TrainingAgent.cs --- Assets/Scripts/TrainingAgent.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index accb0dff..0a13226e 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -179,12 +179,11 @@ private void InitialiseCSVProcess() /* Directory to store the logs under folder "ObservationLogs" */ string directoryPath = Path.Combine(basePath, "ObservationLogs"); - if (!Directory.Exists(directoryPath)) { Directory.CreateDirectory(directoryPath); } - + /* Generate a filename with the YAML file name and a date stamp to prevent overwriting. */ // TODO: Extract YAML name from side channel message. string dateTimeString = DateTime.Now.ToString("dd-MM-yy_HHmm"); From 91ca87e0c14a278b843cf84123e8e9dcb7625232 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Sat, 27 Jul 2024 14:50:10 +0300 Subject: [PATCH 137/205] moved methods and grouped them relatively --- Assets/Scripts/TrainingAgent.cs | 317 ++++++++++++++++---------------- 1 file changed, 160 insertions(+), 157 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 0a13226e..79dd3f8c 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -132,6 +132,9 @@ private string CombineRaycastData(float[] observations, string[] tags) return string.Join(";", observations.Zip(tags, (obs, tag) => $"{obs}:{tag}")); } + /// + /// Initialize is called when the training session is started from mlagents. It sets up the agent's initial state. + /// public override void Initialize() { _arena = GetComponentInParent(); @@ -161,146 +164,6 @@ public override void Initialize() StartFlushThread(); } - private void InitialiseCSVProcess() - { - /* Base path for the logs to be stored */ - string basePath; - - if (Application.isEditor) - { - /* The root directory is the parent of the Assets folder */ - basePath = Path.GetFullPath(Path.Combine(Application.dataPath, "..")); - } - else - { - /* Important! For builds, use the parent of the directory where the executable resides */ - basePath = Path.GetDirectoryName(Application.dataPath); - } - - /* Directory to store the logs under folder "ObservationLogs" */ - string directoryPath = Path.Combine(basePath, "ObservationLogs"); - if (!Directory.Exists(directoryPath)) - { - Directory.CreateDirectory(directoryPath); - } - - /* Generate a filename with the YAML file name and a date stamp to prevent overwriting. */ - // TODO: Extract YAML name from side channel message. - string dateTimeString = DateTime.Now.ToString("dd-MM-yy_HHmm"); - string filename = $"Observations_{yamlFileName}_{dateTimeString}.csv"; - csvFilePath = Path.Combine(directoryPath, filename); - - writer = new StreamWriter(csvFilePath, true); - - if (!File.Exists(csvFilePath) || new FileInfo(csvFilePath).Length == 0) - { - if (!headerWritten) - { - writer.WriteLine( - "Episode,Step,Health,Reward,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForwardWithDescription,ActionRotateWithDescription,WasAgentFrozen?,NotificationShown?,CollectedRewardType,DispensedRewardType,WasRewardDispensed?,WasSpawnerButtonTriggered?,CombinedSpawnerInfo,WasAgentInDataZone?,ActiveCamera,CombinedRaycastData" - ); - headerWritten = true; - } - else - { - Debug.LogError("Header/Columns already written to CSV file."); - } - } - } - - /// - /// Logs the agent's state to a CSV file. This is called every step. - /// The data is stored in a queue and flushed to the file in a separate thread. - /// - private void LogToCSV( - Vector3 velocity, - Vector3 position, - string actionForwardWithDescription, - string actionRotateWithDescription, - string wasAgentFrozen, - float reward, - string notificationState, - int customEpisodeCount, - string dispensedRewardType, - bool wasRewardDispensed, - bool wasSpawnerButtonTriggered, - string combinedSpawnerInfo, - string wasAgentInDataZone, - string activeCameraDescription, - string combinedRaycastData - ) - { - string logEntry = string.Format( - "{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14},{15},{16},{17},{18},{19},{20},{21}", - customEpisodeCount, - StepCount, - health, - reward, - velocity.x, - velocity.y, - velocity.z, - position.x, - position.y, - position.z, - actionForwardWithDescription, - actionRotateWithDescription, - wasAgentFrozen, - notificationState, - lastCollectedRewardType, - dispensedRewardType, - wasRewardDispensed ? "Yes" : "No", - wasSpawnerButtonTriggered ? "Yes" : "No", - combinedSpawnerInfo.Replace(",", ";"), - wasAgentInDataZone, - activeCameraDescription, - combinedRaycastData - ); - - logQueue.Enqueue(logEntry); - lastCollectedRewardType = "None"; - - if (logQueue.Count >= bufferSize) - { - flushEvent.Set(); - } - } - - /// - /// Flushes the log queue to the CSV file. This is called in a separate thread to prevent the main thread from being blocked. - /// - private void FlushLogQueue() - { - lock (logQueue) - { - while (logQueue.TryDequeue(out var logEntry)) - { - writer.WriteLine(logEntry); - } - writer.Flush(); - Debug.Log("Flushed log queue to CSV file."); - } - } - - /// - /// Starts a thread that checks if the log queue is full and flushes it to the CSV file if it is. - /// - private void StartFlushThread() - { - new Thread(() => - { - while (true) - { - flushEvent.WaitOne(); - if (logQueue.Count >= bufferSize && !isFlushing) - { - isFlushing = true; - FlushLogQueue(); - isFlushing = false; - } - } - }).Start(); - } - /// /// OnDisable is called when the training session is stopped form mlagents. /// It closes the CSV file and flushes the log queue at whatever the current size is. @@ -319,6 +182,11 @@ protected override void OnDisable() DataZone.OnOutDataZone -= OnOutDataZone; } + public void AddExtraReward(float rewardFactor) + { + UpdateHealth(Math.Min(rewardFactor * _rewardPerStep, -0.001f)); + } + public float GetPreviousScore() { return _previousScore; @@ -376,6 +244,25 @@ private string GetNotificationState() return NotificationManager.Instance.GetCurrentNotificationState(); } + private (float[] hitFractions, string[] hitTags) CollectRaycastObservations() + { + RayPerceptionSensorComponent3D rayPerception = + GetComponent(); + if (rayPerception == null) + { + return (new float[0], new string[0]); + } + + var rayPerceptionInput = rayPerception.GetRayPerceptionInput(); + var rayPerceptionOutput = RayPerceptionSensor.Perceive(rayPerceptionInput); + float[] hitFractions = rayPerceptionOutput.RayOutputs.Select(r => r.HitFraction).ToArray(); + string[] hitTags = rayPerceptionOutput.RayOutputs + .Select(r => r.HitGameObject?.tag ?? "None") + .ToArray(); + + return (hitFractions, hitTags); + } + public override void CollectObservations(VectorSensor sensor) { sensor.AddObservation(health); @@ -442,23 +329,144 @@ public override void OnActionReceived(ActionBuffers action) UpdateHealth(_rewardPerStep); } - private (float[] hitFractions, string[] hitTags) CollectRaycastObservations() + private void InitialiseCSVProcess() { - RayPerceptionSensorComponent3D rayPerception = - GetComponent(); - if (rayPerception == null) + /* Base path for the logs to be stored */ + string basePath; + + if (Application.isEditor) { - return (new float[0], new string[0]); + /* The root directory is the parent of the Assets folder */ + basePath = Path.GetFullPath(Path.Combine(Application.dataPath, "..")); + } + else + { + /* Important! For builds, use the parent of the directory where the executable resides */ + basePath = Path.GetDirectoryName(Application.dataPath); } - var rayPerceptionInput = rayPerception.GetRayPerceptionInput(); - var rayPerceptionOutput = RayPerceptionSensor.Perceive(rayPerceptionInput); - float[] hitFractions = rayPerceptionOutput.RayOutputs.Select(r => r.HitFraction).ToArray(); - string[] hitTags = rayPerceptionOutput.RayOutputs - .Select(r => r.HitGameObject?.tag ?? "None") - .ToArray(); + /* Directory to store the logs under folder "ObservationLogs" */ + string directoryPath = Path.Combine(basePath, "ObservationLogs"); + if (!Directory.Exists(directoryPath)) + { + Directory.CreateDirectory(directoryPath); + } - return (hitFractions, hitTags); + /* Generate a filename with the YAML file name and a date stamp to prevent overwriting. */ + // TODO: Extract YAML name from side channel message. + string dateTimeString = DateTime.Now.ToString("dd-MM-yy_HHmm"); + string filename = $"Observations_{yamlFileName}_{dateTimeString}.csv"; + csvFilePath = Path.Combine(directoryPath, filename); + + writer = new StreamWriter(csvFilePath, true); + + if (!File.Exists(csvFilePath) || new FileInfo(csvFilePath).Length == 0) + { + if (!headerWritten) + { + writer.WriteLine( + "Episode,Step,Health,Reward,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForwardWithDescription,ActionRotateWithDescription,WasAgentFrozen?,NotificationShown?,CollectedRewardType,DispensedRewardType,WasRewardDispensed?,WasSpawnerButtonTriggered?,CombinedSpawnerInfo,WasAgentInDataZone?,ActiveCamera,CombinedRaycastData" + ); + headerWritten = true; + } + else + { + Debug.LogError("Header/Columns already written to CSV file."); + } + } + } + + /// + /// Logs the agent's state to a CSV file. This is called every step. + /// The data is stored in a queue and flushed to the file in a separate thread. + /// + private void LogToCSV( + Vector3 velocity, + Vector3 position, + string actionForwardWithDescription, + string actionRotateWithDescription, + string wasAgentFrozen, + float reward, + string notificationState, + int customEpisodeCount, + string dispensedRewardType, + bool wasRewardDispensed, + bool wasSpawnerButtonTriggered, + string combinedSpawnerInfo, + string wasAgentInDataZone, + string activeCameraDescription, + string combinedRaycastData + ) + { + string logEntry = string.Format( + "{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14},{15},{16},{17},{18},{19},{20},{21}", + customEpisodeCount, + StepCount, + health, + reward, + velocity.x, + velocity.y, + velocity.z, + position.x, + position.y, + position.z, + actionForwardWithDescription, + actionRotateWithDescription, + wasAgentFrozen, + notificationState, + lastCollectedRewardType, + dispensedRewardType, + wasRewardDispensed ? "Yes" : "No", + wasSpawnerButtonTriggered ? "Yes" : "No", + combinedSpawnerInfo.Replace(",", ";"), + wasAgentInDataZone, + activeCameraDescription, + combinedRaycastData + ); + + logQueue.Enqueue(logEntry); + lastCollectedRewardType = "None"; + + if (logQueue.Count >= bufferSize) + { + flushEvent.Set(); + } + } + + /// + /// Flushes the log queue to the CSV file. This is called in a separate thread to prevent the main thread from being blocked. + /// + private void FlushLogQueue() + { + lock (logQueue) + { + while (logQueue.TryDequeue(out var logEntry)) + { + writer.WriteLine(logEntry); + } + writer.Flush(); + Debug.Log("Flushed log queue to CSV file."); + } + } + + /// + /// Starts a thread that checks if the log queue is full and flushes it to the CSV file if it is. + /// + private void StartFlushThread() + { + new Thread(() => + { + while (true) + { + flushEvent.WaitOne(); + if (logQueue.Count >= bufferSize && !isFlushing) + { + isFlushing = true; + FlushLogQueue(); + isFlushing = false; + } + } + }).Start(); } private string DescribeActionForward(int actionForward) @@ -672,11 +680,6 @@ public override void OnEpisodeBegin() SetFreezeDelay(GetFreezeDelay()); } - public void AddExtraReward(float rewardFactor) - { - UpdateHealth(Math.Min(rewardFactor * _rewardPerStep, -0.001f)); - } - private void EpisodeDebugLogs() { Debug.Log("Episode Begin"); From ea5041842cfd109e12beb7d1dc9bda046b21ca61 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Sat, 27 Jul 2024 15:02:53 +0300 Subject: [PATCH 138/205] reordered columns for logical grouping was: CollectedRewardType,DispensedRewardType,WasRewardDispensed? now: WasRewardDispensed?,DispensedRewardType,CollectedRewardType --- Assets/Scripts/TrainingAgent.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 79dd3f8c..5d47b991 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -311,8 +311,9 @@ public override void OnActionReceived(ActionBuffers action) reward, notificationState, customEpisodeCount, - dispensedRewardType, wasRewardDispensed, + dispensedRewardType, + lastCollectedRewardType, wasSpawnerButtonTriggered, combinedSpawnerInfo, wasAgentInDataZone, @@ -365,7 +366,7 @@ private void InitialiseCSVProcess() if (!headerWritten) { writer.WriteLine( - "Episode,Step,Health,Reward,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForwardWithDescription,ActionRotateWithDescription,WasAgentFrozen?,NotificationShown?,CollectedRewardType,DispensedRewardType,WasRewardDispensed?,WasSpawnerButtonTriggered?,CombinedSpawnerInfo,WasAgentInDataZone?,ActiveCamera,CombinedRaycastData" + "Episode,Step,Health,Reward,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForwardWithDescription,ActionRotateWithDescription,WasAgentFrozen?,NotificationShown?,WasRewardDispensed?,DispensedRewardType,CollectedRewardType,WasSpawnerButtonTriggered?,CombinedSpawnerInfo,WasAgentInDataZone?,ActiveCamera,CombinedRaycastData" ); headerWritten = true; } @@ -389,8 +390,9 @@ private void LogToCSV( float reward, string notificationState, int customEpisodeCount, - string dispensedRewardType, bool wasRewardDispensed, + string dispensedRewardType, + string lastCollectedRewardType, bool wasSpawnerButtonTriggered, string combinedSpawnerInfo, string wasAgentInDataZone, @@ -414,9 +416,9 @@ string combinedRaycastData actionRotateWithDescription, wasAgentFrozen, notificationState, - lastCollectedRewardType, - dispensedRewardType, wasRewardDispensed ? "Yes" : "No", + dispensedRewardType, + lastCollectedRewardType, wasSpawnerButtonTriggered ? "Yes" : "No", combinedSpawnerInfo.Replace(",", ";"), wasAgentInDataZone, From 74363a38b51b80c716b5175fae35720a4eb1b0fc Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Sat, 27 Jul 2024 15:10:31 +0300 Subject: [PATCH 139/205] removed debug log as redundant --- Assets/Scripts/ScreenshotCamera.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Assets/Scripts/ScreenshotCamera.cs b/Assets/Scripts/ScreenshotCamera.cs index 34dabd43..f527c939 100644 --- a/Assets/Scripts/ScreenshotCamera.cs +++ b/Assets/Scripts/ScreenshotCamera.cs @@ -49,7 +49,7 @@ private void LateUpdate() if (screenshotCam.enabled && !testMode) { CaptureScreenshot(); - Activate(false); // Deactivate the camera after capturing to prevent multiple captures. + Activate(false); /* Deactivate the camera after capturing to prevent multiple captures */ } } @@ -81,7 +81,6 @@ private void CaptureScreenshot() string fullPath = Path.Combine(directoryPath, formattedFileName); File.WriteAllBytes(fullPath, bytes); - Debug.Log($"Screenshot saved to {fullPath}"); fileCounter++; } } From 619ab0efab982120bc6b751aafd82c2a270fdfa3 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Sat, 27 Jul 2024 15:18:59 +0300 Subject: [PATCH 140/205] added safety checks to prevent unnecessary .csv file creation --- Assets/Scripts/TrainingAgent.cs | 117 +++++++++++++++++++++----------- 1 file changed, 76 insertions(+), 41 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 5d47b991..1826d493 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -79,6 +79,7 @@ public class TrainingAgent : Agent, IPrefab private string yamlFileName; private AutoResetEvent flushEvent = new AutoResetEvent(false); + private bool errorOccurred = false; public void RecordSpawnerInfo(string spawnerInfo) { @@ -150,7 +151,15 @@ public override void Initialize() playerControls = GameObject.FindObjectOfType(); - InitialiseCSVProcess(); + try + { + InitialiseCSVProcess(); + } + catch (Exception ex) + { + Debug.LogError("Failed to initialize CSV process: " + ex.Message); + errorOccurred = true; + } if (!Application.isEditor) { @@ -332,49 +341,57 @@ public override void OnActionReceived(ActionBuffers action) private void InitialiseCSVProcess() { - /* Base path for the logs to be stored */ - string basePath; - - if (Application.isEditor) + try { - /* The root directory is the parent of the Assets folder */ - basePath = Path.GetFullPath(Path.Combine(Application.dataPath, "..")); - } - else - { - /* Important! For builds, use the parent of the directory where the executable resides */ - basePath = Path.GetDirectoryName(Application.dataPath); - } + /* Base path for the logs to be stored */ + string basePath; - /* Directory to store the logs under folder "ObservationLogs" */ - string directoryPath = Path.Combine(basePath, "ObservationLogs"); - if (!Directory.Exists(directoryPath)) - { - Directory.CreateDirectory(directoryPath); - } - - /* Generate a filename with the YAML file name and a date stamp to prevent overwriting. */ - // TODO: Extract YAML name from side channel message. - string dateTimeString = DateTime.Now.ToString("dd-MM-yy_HHmm"); - string filename = $"Observations_{yamlFileName}_{dateTimeString}.csv"; - csvFilePath = Path.Combine(directoryPath, filename); - - writer = new StreamWriter(csvFilePath, true); - - if (!File.Exists(csvFilePath) || new FileInfo(csvFilePath).Length == 0) - { - if (!headerWritten) + if (Application.isEditor) { - writer.WriteLine( - "Episode,Step,Health,Reward,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForwardWithDescription,ActionRotateWithDescription,WasAgentFrozen?,NotificationShown?,WasRewardDispensed?,DispensedRewardType,CollectedRewardType,WasSpawnerButtonTriggered?,CombinedSpawnerInfo,WasAgentInDataZone?,ActiveCamera,CombinedRaycastData" - ); - headerWritten = true; + /* The root directory is the parent of the Assets folder */ + basePath = Path.GetFullPath(Path.Combine(Application.dataPath, "..")); } else { - Debug.LogError("Header/Columns already written to CSV file."); + /* Important! For builds, use the parent of the directory where the executable resides */ + basePath = Path.GetDirectoryName(Application.dataPath); + } + + /* Directory to store the logs under folder "ObservationLogs" */ + string directoryPath = Path.Combine(basePath, "ObservationLogs"); + if (!Directory.Exists(directoryPath)) + { + Directory.CreateDirectory(directoryPath); + } + + /* Generate a filename with the YAML file name and a date stamp to prevent overwriting. */ + // TODO: Extract YAML name from side channel message. + string dateTimeString = DateTime.Now.ToString("dd-MM-yy_HHmm"); + string filename = $"Observations_{yamlFileName}_{dateTimeString}.csv"; + csvFilePath = Path.Combine(directoryPath, filename); + + writer = new StreamWriter(csvFilePath, true); + + if (!File.Exists(csvFilePath) || new FileInfo(csvFilePath).Length == 0) + { + if (!headerWritten) + { + writer.WriteLine( + "Episode,Step,Health,Reward,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForwardWithDescription,ActionRotateWithDescription,WasAgentFrozen?,NotificationShown?,WasRewardDispensed?,DispensedRewardType,CollectedRewardType,WasSpawnerButtonTriggered?,CombinedSpawnerInfo,WasAgentInDataZone?,ActiveCamera,CombinedRaycastData" + ); + headerWritten = true; + } + else + { + Debug.LogError("Header/Columns already written to CSV file."); + } } } + catch (Exception ex) + { + Debug.LogError("Failed to initialize CSV process: " + ex.Message); + errorOccurred = true; + } } /// @@ -400,6 +417,11 @@ private void LogToCSV( string combinedRaycastData ) { + if (errorOccurred) + { + return; + } + string logEntry = string.Format( "{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14},{15},{16},{17},{18},{19},{20},{21}", customEpisodeCount, @@ -440,14 +462,27 @@ string combinedRaycastData /// private void FlushLogQueue() { - lock (logQueue) + if (errorOccurred) + { + return; + } + + try { - while (logQueue.TryDequeue(out var logEntry)) + lock (logQueue) { - writer.WriteLine(logEntry); + while (logQueue.TryDequeue(out var logEntry)) + { + writer.WriteLine(logEntry); + } + writer.Flush(); + Debug.Log("Flushed log queue to CSV file."); } - writer.Flush(); - Debug.Log("Flushed log queue to CSV file."); + } + catch (Exception ex) + { + Debug.LogError("Failed to flush log queue: " + ex.Message); + errorOccurred = true; } } From 1f3d879d869a9d6ba5784fdc6fa365592cc458fe Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Sat, 27 Jul 2024 15:33:01 +0300 Subject: [PATCH 141/205] fixed bug where: first row of combinedSpawnerInfo had missing entry. Fixed by setting default value to N/A and checking if row is null or empty. --- Assets/Scripts/TrainingAgent.cs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 1826d493..a4b8dbd0 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -75,7 +75,7 @@ public class TrainingAgent : Agent, IPrefab private string wasAgentInDataZone = "No"; private bool wasRewardDispensed = false; private bool wasSpawnerButtonTriggered = false; - private string combinedSpawnerInfo = ""; + private string combinedSpawnerInfo = "N/A"; private string yamlFileName; private AutoResetEvent flushEvent = new AutoResetEvent(false); @@ -83,14 +83,22 @@ public class TrainingAgent : Agent, IPrefab public void RecordSpawnerInfo(string spawnerInfo) { - if (string.IsNullOrEmpty(combinedSpawnerInfo)) + if (string.IsNullOrEmpty(spawnerInfo)) { - combinedSpawnerInfo = spawnerInfo; + combinedSpawnerInfo = "N/A"; } else { - combinedSpawnerInfo += $"|{spawnerInfo}"; + if (combinedSpawnerInfo == "N/A") + { + combinedSpawnerInfo = spawnerInfo; + } + else + { + combinedSpawnerInfo += $"|{spawnerInfo}"; + } } + Debug.Log($"Recorded Spawner Info: {combinedSpawnerInfo}"); } public void OnInDataZone(string zoneLogString) @@ -334,7 +342,7 @@ public override void OnActionReceived(ActionBuffers action) wasRewardDispensed = false; wasSpawnerButtonTriggered = false; wasAgentInDataZone = "No"; - combinedSpawnerInfo = ""; + combinedSpawnerInfo = "N/A"; UpdateHealth(_rewardPerStep); } From 53220203dc57d0204f4d2235e43767c696342785 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Sun, 28 Jul 2024 22:00:05 +0300 Subject: [PATCH 142/205] Revert "added safety checks to prevent unnecessary .csv file creation" This reverts commit 619ab0efab982120bc6b751aafd82c2a270fdfa3. --- Assets/Scripts/TrainingAgent.cs | 117 +++++++++++--------------------- 1 file changed, 41 insertions(+), 76 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index a4b8dbd0..0510a360 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -79,7 +79,6 @@ public class TrainingAgent : Agent, IPrefab private string yamlFileName; private AutoResetEvent flushEvent = new AutoResetEvent(false); - private bool errorOccurred = false; public void RecordSpawnerInfo(string spawnerInfo) { @@ -159,15 +158,7 @@ public override void Initialize() playerControls = GameObject.FindObjectOfType(); - try - { - InitialiseCSVProcess(); - } - catch (Exception ex) - { - Debug.LogError("Failed to initialize CSV process: " + ex.Message); - errorOccurred = true; - } + InitialiseCSVProcess(); if (!Application.isEditor) { @@ -349,56 +340,48 @@ public override void OnActionReceived(ActionBuffers action) private void InitialiseCSVProcess() { - try - { - /* Base path for the logs to be stored */ - string basePath; + /* Base path for the logs to be stored */ + string basePath; - if (Application.isEditor) - { - /* The root directory is the parent of the Assets folder */ - basePath = Path.GetFullPath(Path.Combine(Application.dataPath, "..")); - } - else - { - /* Important! For builds, use the parent of the directory where the executable resides */ - basePath = Path.GetDirectoryName(Application.dataPath); - } + if (Application.isEditor) + { + /* The root directory is the parent of the Assets folder */ + basePath = Path.GetFullPath(Path.Combine(Application.dataPath, "..")); + } + else + { + /* Important! For builds, use the parent of the directory where the executable resides */ + basePath = Path.GetDirectoryName(Application.dataPath); + } - /* Directory to store the logs under folder "ObservationLogs" */ - string directoryPath = Path.Combine(basePath, "ObservationLogs"); - if (!Directory.Exists(directoryPath)) - { - Directory.CreateDirectory(directoryPath); - } + /* Directory to store the logs under folder "ObservationLogs" */ + string directoryPath = Path.Combine(basePath, "ObservationLogs"); + if (!Directory.Exists(directoryPath)) + { + Directory.CreateDirectory(directoryPath); + } - /* Generate a filename with the YAML file name and a date stamp to prevent overwriting. */ - // TODO: Extract YAML name from side channel message. - string dateTimeString = DateTime.Now.ToString("dd-MM-yy_HHmm"); - string filename = $"Observations_{yamlFileName}_{dateTimeString}.csv"; - csvFilePath = Path.Combine(directoryPath, filename); + /* Generate a filename with the YAML file name and a date stamp to prevent overwriting. */ + // TODO: Extract YAML name from side channel message. + string dateTimeString = DateTime.Now.ToString("dd-MM-yy_HHmm"); + string filename = $"Observations_{yamlFileName}_{dateTimeString}.csv"; + csvFilePath = Path.Combine(directoryPath, filename); - writer = new StreamWriter(csvFilePath, true); + writer = new StreamWriter(csvFilePath, true); - if (!File.Exists(csvFilePath) || new FileInfo(csvFilePath).Length == 0) + if (!File.Exists(csvFilePath) || new FileInfo(csvFilePath).Length == 0) + { + if (!headerWritten) { - if (!headerWritten) - { - writer.WriteLine( - "Episode,Step,Health,Reward,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForwardWithDescription,ActionRotateWithDescription,WasAgentFrozen?,NotificationShown?,WasRewardDispensed?,DispensedRewardType,CollectedRewardType,WasSpawnerButtonTriggered?,CombinedSpawnerInfo,WasAgentInDataZone?,ActiveCamera,CombinedRaycastData" - ); - headerWritten = true; - } - else - { - Debug.LogError("Header/Columns already written to CSV file."); - } + writer.WriteLine( + "Episode,Step,Health,Reward,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForwardWithDescription,ActionRotateWithDescription,WasAgentFrozen?,NotificationShown?,WasRewardDispensed?,DispensedRewardType,CollectedRewardType,WasSpawnerButtonTriggered?,CombinedSpawnerInfo,WasAgentInDataZone?,ActiveCamera,CombinedRaycastData" + ); + headerWritten = true; + } + else + { + Debug.LogError("Header/Columns already written to CSV file."); } - } - catch (Exception ex) - { - Debug.LogError("Failed to initialize CSV process: " + ex.Message); - errorOccurred = true; } } @@ -425,11 +408,6 @@ private void LogToCSV( string combinedRaycastData ) { - if (errorOccurred) - { - return; - } - string logEntry = string.Format( "{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14},{15},{16},{17},{18},{19},{20},{21}", customEpisodeCount, @@ -470,27 +448,14 @@ string combinedRaycastData /// private void FlushLogQueue() { - if (errorOccurred) - { - return; - } - - try + lock (logQueue) { - lock (logQueue) + while (logQueue.TryDequeue(out var logEntry)) { - while (logQueue.TryDequeue(out var logEntry)) - { - writer.WriteLine(logEntry); - } - writer.Flush(); - Debug.Log("Flushed log queue to CSV file."); + writer.WriteLine(logEntry); } - } - catch (Exception ex) - { - Debug.LogError("Failed to flush log queue: " + ex.Message); - errorOccurred = true; + writer.Flush(); + Debug.Log("Flushed log queue to CSV file."); } } From d94119ea679b888e14b9dbcf858a803d5289f04e Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 30 Jul 2024 15:24:35 +0300 Subject: [PATCH 143/205] minor header change: notificationShown? --> wasNotificationShown? for coherency --- Assets/Scripts/TrainingAgent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 0510a360..dc33dab8 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -374,7 +374,7 @@ private void InitialiseCSVProcess() if (!headerWritten) { writer.WriteLine( - "Episode,Step,Health,Reward,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForwardWithDescription,ActionRotateWithDescription,WasAgentFrozen?,NotificationShown?,WasRewardDispensed?,DispensedRewardType,CollectedRewardType,WasSpawnerButtonTriggered?,CombinedSpawnerInfo,WasAgentInDataZone?,ActiveCamera,CombinedRaycastData" + "Episode,Step,Health,Reward,XVelocity,YVelocity,ZVelocity,XPosition,YPosition,ZPosition,ActionForwardWithDescription,ActionRotateWithDescription,WasAgentFrozen?,WasNotificationShown?,WasRewardDispensed?,DispensedRewardType,CollectedRewardType,WasSpawnerButtonTriggered?,CombinedSpawnerInfo,WasAgentInDataZone?,ActiveCamera,CombinedRaycastData" ); headerWritten = true; } From 1da91a797fff6253a484a92b377e7abfe2db8b88 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 30 Jul 2024 16:28:35 +0300 Subject: [PATCH 144/205] added important todo --- Assets/Scripts/TrainingAgent.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index dc33dab8..47b6b192 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -17,6 +17,11 @@ /// Actions are currently discrete. 2 branches of 0,1,2, 0,1,2 for forward and rotate respectively. /// + +// TODO: Use thread pooling to reduce overhead of creating new threads: +// https://medium.com/@lexitrainerph/c-threading-from-basic-to-advanced-84927e502a38 + + public class TrainingAgent : Agent, IPrefab { [Header("Agent Settings")] From a5d42f350c8b8d7a31fef98c8bdddf796b13e479 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 30 Jul 2024 16:51:00 +0300 Subject: [PATCH 145/205] ok so: So far there doesnt seem to be a bottleneck anymore as im handling the threads more gracefully (in general but more importantly during training) and using a thread lock mechanism to make sure the threads are controlled. Also, the batched and framecountered approach seems to be working well as im no longer getting fps lags during training. this was the case as collectobservations is called every frame (by mlagents) and because were calling logtocsv() every method, this was causing a major bottleneck in CPU resources. Now, i need to make sure that the data is logged (flushed) right before training ends or another appropriate implementation as the .csv file was empty in my tests. This suggests the data cant be flushed in time. --- Assets/Scripts/TrainingAgent.cs | 107 ++++++++++++++++++++++++++------ 1 file changed, 87 insertions(+), 20 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 47b6b192..147460b8 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -18,7 +18,7 @@ /// -// TODO: Use thread pooling to reduce overhead of creating new threads: +// TODO: Use thread pooling to reduce overhead of creating new threads: // https://medium.com/@lexitrainerph/c-threading-from-basic-to-advanced-84927e502a38 @@ -85,6 +85,12 @@ public class TrainingAgent : Agent, IPrefab private string yamlFileName; private AutoResetEvent flushEvent = new AutoResetEvent(false); + private Thread flushThread; + private bool threadRunning = true; + private int logBatchSize = 10; // Log every 10 frames + private int frameCounter = 0; + private int halfLogCounter = 0; + public void RecordSpawnerInfo(string spawnerInfo) { if (string.IsNullOrEmpty(spawnerInfo)) @@ -184,6 +190,14 @@ public override void Initialize() protected override void OnDisable() { base.OnDisable(); + threadRunning = false; // Signal the flush thread to stop + flushEvent.Set(); // Ensure the thread is not stuck in WaitOne() + + if (flushThread != null && flushThread.IsAlive) + { + flushThread.Join(); // Wait for the thread to finish + } + if (writer != null) { FlushLogQueue(); /* Flush any remaining logs in the queue */ @@ -290,6 +304,59 @@ public override void CollectObservations(VectorSensor sensor) string notificationState = GetNotificationState(); (float[] raycastObservations, string[] raycastTags) = CollectRaycastObservations(); string combinedRaycastData = CombineRaycastData(raycastObservations, raycastTags); + + frameCounter++; + if (frameCounter >= logBatchSize) + { + frameCounter = 0; + + if (halfLogCounter == 0) + { + // Collect first half of the data + localVel = transform.InverseTransformDirection(_rigidBody.velocity); + localPos = transform.position; + wasAgentFrozen = IsFrozen(); + actionForwardWithDescription = + $"{lastActionForward} ({DescribeActionForward(lastActionForward)})"; + actionRotateWithDescription = + $"{lastActionRotate} ({DescribeActionRotate(lastActionRotate)})"; + reward = GetCumulativeReward(); + notificationState = GetNotificationState(); + (raycastObservations, raycastTags) = CollectRaycastObservations(); + combinedRaycastData = CombineRaycastData(raycastObservations, raycastTags); + } + else + { + // Log the second half of the data + LogToCSV( + localVel, + localPos, + actionForwardWithDescription, + actionRotateWithDescription, + wasAgentFrozen ? "Yes" : "No", + reward, + notificationState, + customEpisodeCount, + wasRewardDispensed, + dispensedRewardType, + lastCollectedRewardType, + wasSpawnerButtonTriggered, + combinedSpawnerInfo, + wasAgentInDataZone, + playerControls.GetActiveCameraDescription(), + combinedRaycastData + ); + + // Reset these flags after logging + dispensedRewardType = "None"; + wasRewardDispensed = false; + wasSpawnerButtonTriggered = false; + wasAgentInDataZone = "No"; + combinedSpawnerInfo = "N/A"; + } + + halfLogCounter = 1 - halfLogCounter; // Toggle between 0 and 1 + } } public override void OnActionReceived(ActionBuffers action) @@ -451,27 +518,11 @@ string combinedRaycastData /// /// Flushes the log queue to the CSV file. This is called in a separate thread to prevent the main thread from being blocked. /// - private void FlushLogQueue() - { - lock (logQueue) - { - while (logQueue.TryDequeue(out var logEntry)) - { - writer.WriteLine(logEntry); - } - writer.Flush(); - Debug.Log("Flushed log queue to CSV file."); - } - } - - /// - /// Starts a thread that checks if the log queue is full and flushes it to the CSV file if it is. - /// private void StartFlushThread() { - new Thread(() => + flushThread = new Thread(() => { - while (true) + while (threadRunning) { flushEvent.WaitOne(); if (logQueue.Count >= bufferSize && !isFlushing) @@ -481,7 +532,23 @@ private void StartFlushThread() isFlushing = false; } } - }).Start(); + // Ensure any remaining logs are flushed before exiting the thread + FlushLogQueue(); + }); + flushThread.Start(); + } + + private void FlushLogQueue() + { + lock (writer) + { + while (logQueue.TryDequeue(out var logEntry)) + { + writer.WriteLine(logEntry); + } + writer.Flush(); + Debug.Log("Flushed log queue to CSV file."); + } } private string DescribeActionForward(int actionForward) From 1606d854094e2130c04a5f5198c041a13058425d Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 30 Jul 2024 22:31:19 +0300 Subject: [PATCH 146/205] implemented locking and safety to flushing data also put down code to grant permissions to create,write and read across all three operating systems (unified approach) --- Assets/Scripts/TrainingAgent.cs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 147460b8..e013e3b5 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -439,7 +439,9 @@ private void InitialiseCSVProcess() string filename = $"Observations_{yamlFileName}_{dateTimeString}.csv"; csvFilePath = Path.Combine(directoryPath, filename); - writer = new StreamWriter(csvFilePath, true); + writer = new StreamWriter( + new FileStream(csvFilePath, FileMode.Create, FileAccess.Write, FileShare.Read) + ); if (!File.Exists(csvFilePath) || new FileInfo(csvFilePath).Length == 0) { @@ -532,7 +534,6 @@ private void StartFlushThread() isFlushing = false; } } - // Ensure any remaining logs are flushed before exiting the thread FlushLogQueue(); }); flushThread.Start(); @@ -540,14 +541,21 @@ private void StartFlushThread() private void FlushLogQueue() { - lock (writer) + try { - while (logQueue.TryDequeue(out var logEntry)) + lock (logQueue) { - writer.WriteLine(logEntry); + while (logQueue.TryDequeue(out var logEntry)) + { + writer.WriteLine(logEntry); + } + writer.Flush(); + Debug.Log("Flushed log queue to CSV file."); } - writer.Flush(); - Debug.Log("Flushed log queue to CSV file."); + } + catch (Exception ex) + { + Debug.LogError("Failed to flush log queue: " + ex.Message); } } From 18fb9b8ee952a68be11f650b773f07608ca42f3e Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 30 Jul 2024 22:52:32 +0300 Subject: [PATCH 147/205] minor changes to code format --- Assets/Scripts/TrainingAgent.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index e013e3b5..6d7788c2 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -81,16 +81,15 @@ public class TrainingAgent : Agent, IPrefab private bool wasRewardDispensed = false; private bool wasSpawnerButtonTriggered = false; private string combinedSpawnerInfo = "N/A"; - - private string yamlFileName; private AutoResetEvent flushEvent = new AutoResetEvent(false); - private Thread flushThread; private bool threadRunning = true; - private int logBatchSize = 10; // Log every 10 frames + private int logBatchSize = 101; /* Log every 10 frames to CSV file */ private int frameCounter = 0; private int halfLogCounter = 0; + private string yamlFileName; + public void RecordSpawnerInfo(string spawnerInfo) { if (string.IsNullOrEmpty(spawnerInfo)) From 8323fbff7548205245af7e0b9d9f7651b4452534 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Fri, 2 Aug 2024 22:31:54 +0100 Subject: [PATCH 148/205] added todo for spawnerbutton.cs --- Assets/Scripts/Spawners/Spawner_InteractiveButton.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Assets/Scripts/Spawners/Spawner_InteractiveButton.cs b/Assets/Scripts/Spawners/Spawner_InteractiveButton.cs index e7bd6091..5cdcaa42 100644 --- a/Assets/Scripts/Spawners/Spawner_InteractiveButton.cs +++ b/Assets/Scripts/Spawners/Spawner_InteractiveButton.cs @@ -8,6 +8,8 @@ /// Spawns a reward when interacted with. The reward is chosen from a list of rewards with weights and spawn probabilities. /// The reward can be spawned at a fixed position or randomly within the arena bounds. /// + +// TODO: add checks to ensure that the reward spawn position and parent GO is within the arena bounds. public class Spawner_InteractiveButton : MonoBehaviour { public List RewardNames { get; set; } From f55f1224bef109a2efee60926f5448062b70b1d2 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Mon, 5 Aug 2024 15:08:28 +0100 Subject: [PATCH 149/205] added safety checks to playercontrols.cs --- Assets/Scripts/PlayerControls.cs | 41 ++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/Assets/Scripts/PlayerControls.cs b/Assets/Scripts/PlayerControls.cs index 4768b0c0..4b2e555e 100644 --- a/Assets/Scripts/PlayerControls.cs +++ b/Assets/Scripts/PlayerControls.cs @@ -55,6 +55,7 @@ public int GetActiveCameraIndex() private void Start() { + Debug.Log("PlayerControls: Start method called."); InitializeCanvas(); LoadCamerasAndAgent(); LoadConfigurationSettings(); @@ -75,26 +76,52 @@ private void Update() private void InitializeCanvas() { + if (effectCanvas == null) + { + Debug.LogError("Effect Canvas is null."); + return; + } effectCanvas.renderMode = RenderMode.ScreenSpaceCamera; } private void LoadCamerasAndAgent() { screenshotCam = FindObjectOfType(); - cameras[0] = GameObject.FindGameObjectWithTag("MainCamera").GetComponent(); + if (screenshotCam == null) + { + Debug.LogError("ScreenshotCamera not found."); + } + + cameras[0] = GameObject.FindGameObjectWithTag("MainCamera")?.GetComponent(); cameras[1] = GameObject .FindGameObjectWithTag("agent") - .transform.Find("AgentCamMid") - .GetComponent(); - cameras[2] = GameObject.FindGameObjectWithTag("camBase").GetComponent(); - agent = GameObject.FindGameObjectWithTag("agent").GetComponent(); + ?.transform.Find("AgentCamMid") + ?.GetComponent(); + cameras[2] = GameObject.FindGameObjectWithTag("camBase")?.GetComponent(); + agent = GameObject.FindGameObjectWithTag("agent")?.GetComponent(); + + if (cameras[0] == null || cameras[1] == null || cameras[2] == null) + { + Debug.LogError("One or more cameras not found."); + } + if (agent == null) + { + Debug.LogError("TrainingAgent not found."); + } } private void LoadConfigurationSettings() { arenasConfigurations = ArenasConfigurations.Instance; - canResetEpisode = arenasConfigurations?.canResetEpisode ?? true; - canChangePerspective = arenasConfigurations?.canChangePerspective ?? true; + if (arenasConfigurations != null) + { + canResetEpisode = arenasConfigurations.canResetEpisode; + canChangePerspective = arenasConfigurations.canChangePerspective; + } + else + { + Debug.LogError("ArenasConfigurations instance not found."); + } } private void InitializeCameras() From 5a4be5f54c6c6179ec7a7bc0905c954df44831d9 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Mon, 5 Aug 2024 15:28:42 +0100 Subject: [PATCH 150/205] Revert "added safety checks to playercontrols.cs" This reverts commit f55f1224bef109a2efee60926f5448062b70b1d2. --- Assets/Scripts/PlayerControls.cs | 41 ++++++-------------------------- 1 file changed, 7 insertions(+), 34 deletions(-) diff --git a/Assets/Scripts/PlayerControls.cs b/Assets/Scripts/PlayerControls.cs index 4b2e555e..4768b0c0 100644 --- a/Assets/Scripts/PlayerControls.cs +++ b/Assets/Scripts/PlayerControls.cs @@ -55,7 +55,6 @@ public int GetActiveCameraIndex() private void Start() { - Debug.Log("PlayerControls: Start method called."); InitializeCanvas(); LoadCamerasAndAgent(); LoadConfigurationSettings(); @@ -76,52 +75,26 @@ private void Update() private void InitializeCanvas() { - if (effectCanvas == null) - { - Debug.LogError("Effect Canvas is null."); - return; - } effectCanvas.renderMode = RenderMode.ScreenSpaceCamera; } private void LoadCamerasAndAgent() { screenshotCam = FindObjectOfType(); - if (screenshotCam == null) - { - Debug.LogError("ScreenshotCamera not found."); - } - - cameras[0] = GameObject.FindGameObjectWithTag("MainCamera")?.GetComponent(); + cameras[0] = GameObject.FindGameObjectWithTag("MainCamera").GetComponent(); cameras[1] = GameObject .FindGameObjectWithTag("agent") - ?.transform.Find("AgentCamMid") - ?.GetComponent(); - cameras[2] = GameObject.FindGameObjectWithTag("camBase")?.GetComponent(); - agent = GameObject.FindGameObjectWithTag("agent")?.GetComponent(); - - if (cameras[0] == null || cameras[1] == null || cameras[2] == null) - { - Debug.LogError("One or more cameras not found."); - } - if (agent == null) - { - Debug.LogError("TrainingAgent not found."); - } + .transform.Find("AgentCamMid") + .GetComponent(); + cameras[2] = GameObject.FindGameObjectWithTag("camBase").GetComponent(); + agent = GameObject.FindGameObjectWithTag("agent").GetComponent(); } private void LoadConfigurationSettings() { arenasConfigurations = ArenasConfigurations.Instance; - if (arenasConfigurations != null) - { - canResetEpisode = arenasConfigurations.canResetEpisode; - canChangePerspective = arenasConfigurations.canChangePerspective; - } - else - { - Debug.LogError("ArenasConfigurations instance not found."); - } + canResetEpisode = arenasConfigurations?.canResetEpisode ?? true; + canChangePerspective = arenasConfigurations?.canChangePerspective ?? true; } private void InitializeCameras() From 56a334b224f41e7e75a39d57d1b9303d3ca07c75 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Fri, 9 Aug 2024 14:32:08 +0100 Subject: [PATCH 151/205] removed yamlfile name-specific code redundant --- Assets/Scripts/TrainingAgent.cs | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 6d7788c2..887cacf5 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -88,8 +88,6 @@ public class TrainingAgent : Agent, IPrefab private int frameCounter = 0; private int halfLogCounter = 0; - private string yamlFileName; - public void RecordSpawnerInfo(string spawnerInfo) { if (string.IsNullOrEmpty(spawnerInfo)) @@ -140,11 +138,6 @@ public void RecordDispensedRewardType(string type) dispensedRewardType = type; } - public void SetYamlFileName(string fileName) - { - yamlFileName = fileName; - } - private string CombineRaycastData(float[] observations, string[] tags) { return string.Join(";", observations.Zip(tags, (obs, tag) => $"{obs}:{tag}")); @@ -169,16 +162,6 @@ public override void Initialize() playerControls = GameObject.FindObjectOfType(); InitialiseCSVProcess(); - - if (!Application.isEditor) - { - AAI3EnvironmentManager envManager = FindObjectOfType(); - if (envManager != null) - { - SetYamlFileName(envManager.GetCurrentYamlFileName()); - } - } - StartFlushThread(); } @@ -435,7 +418,7 @@ private void InitialiseCSVProcess() /* Generate a filename with the YAML file name and a date stamp to prevent overwriting. */ // TODO: Extract YAML name from side channel message. string dateTimeString = DateTime.Now.ToString("dd-MM-yy_HHmm"); - string filename = $"Observations_{yamlFileName}_{dateTimeString}.csv"; + string filename = $"Observations_{dateTimeString}.csv"; csvFilePath = Path.Combine(directoryPath, filename); writer = new StreamWriter( From 58be510db9824b50f95d86db3616a9a9f79d9d77 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Fri, 9 Aug 2024 14:36:10 +0100 Subject: [PATCH 152/205] added sensors to add to observation for agent decsion making --- Assets/Scripts/TrainingAgent.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 887cacf5..c88a56f4 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -276,8 +276,11 @@ public override void CollectObservations(VectorSensor sensor) { sensor.AddObservation(health); Vector3 localVel = transform.InverseTransformDirection(_rigidBody.velocity); + sensor.AddObservation(localVel); Vector3 localPos = transform.position; + sensor.AddObservation(localPos); bool wasAgentFrozen = IsFrozen(); + string actionForwardDescription = DescribeActionForward(lastActionForward); string actionRotateDescription = DescribeActionRotate(lastActionRotate); string actionForwardWithDescription = $"{lastActionForward} ({actionForwardDescription})"; From cd330adbd0e87eea0e9adde5279827077d796edb Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Fri, 9 Aug 2024 15:34:23 +0100 Subject: [PATCH 153/205] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 22abd6b0..60c63485 100644 --- a/.gitignore +++ b/.gitignore @@ -116,3 +116,4 @@ Assets/Prefabs/Other-Unique/SignPosterboard.prefab *.csv /ObservationLogs .DS_Store +Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Anton SDF.asset From 335fb8e1d6b488b922d4bdbecb1d08cf55173232 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Fri, 9 Aug 2024 15:38:24 +0100 Subject: [PATCH 154/205] fixed background error: when training mode activates, the playercontrols GO is null. to fix this, a local and more flexible method was implemented to get the active camera under the same namespace. Also called updatehealth() from collectobservations() to log frame by framea gent health during training. --- Assets/Scripts/TrainingAgent.cs | 117 ++++++++++++++++++-------------- 1 file changed, 65 insertions(+), 52 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index c88a56f4..a92719c4 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -280,7 +280,7 @@ public override void CollectObservations(VectorSensor sensor) Vector3 localPos = transform.position; sensor.AddObservation(localPos); bool wasAgentFrozen = IsFrozen(); - + string actionForwardDescription = DescribeActionForward(lastActionForward); string actionRotateDescription = DescribeActionRotate(lastActionRotate); string actionForwardWithDescription = $"{lastActionForward} ({actionForwardDescription})"; @@ -289,59 +289,34 @@ public override void CollectObservations(VectorSensor sensor) string notificationState = GetNotificationState(); (float[] raycastObservations, string[] raycastTags) = CollectRaycastObservations(); string combinedRaycastData = CombineRaycastData(raycastObservations, raycastTags); + string playerControlsDescription = GetActiveCameraDescription(); - frameCounter++; - if (frameCounter >= logBatchSize) - { - frameCounter = 0; - - if (halfLogCounter == 0) - { - // Collect first half of the data - localVel = transform.InverseTransformDirection(_rigidBody.velocity); - localPos = transform.position; - wasAgentFrozen = IsFrozen(); - actionForwardWithDescription = - $"{lastActionForward} ({DescribeActionForward(lastActionForward)})"; - actionRotateWithDescription = - $"{lastActionRotate} ({DescribeActionRotate(lastActionRotate)})"; - reward = GetCumulativeReward(); - notificationState = GetNotificationState(); - (raycastObservations, raycastTags) = CollectRaycastObservations(); - combinedRaycastData = CombineRaycastData(raycastObservations, raycastTags); - } - else - { - // Log the second half of the data - LogToCSV( - localVel, - localPos, - actionForwardWithDescription, - actionRotateWithDescription, - wasAgentFrozen ? "Yes" : "No", - reward, - notificationState, - customEpisodeCount, - wasRewardDispensed, - dispensedRewardType, - lastCollectedRewardType, - wasSpawnerButtonTriggered, - combinedSpawnerInfo, - wasAgentInDataZone, - playerControls.GetActiveCameraDescription(), - combinedRaycastData - ); + LogToCSV( + localVel, + localPos, + actionForwardWithDescription, + actionRotateWithDescription, + wasAgentFrozen ? "Yes" : "No", + reward, + notificationState, + customEpisodeCount, + wasRewardDispensed, + dispensedRewardType, + lastCollectedRewardType, + wasSpawnerButtonTriggered, + combinedSpawnerInfo, + wasAgentInDataZone, + playerControlsDescription, + combinedRaycastData + ); - // Reset these flags after logging - dispensedRewardType = "None"; - wasRewardDispensed = false; - wasSpawnerButtonTriggered = false; - wasAgentInDataZone = "No"; - combinedSpawnerInfo = "N/A"; - } + dispensedRewardType = "None"; + wasRewardDispensed = false; + wasSpawnerButtonTriggered = false; + wasAgentInDataZone = "No"; + combinedSpawnerInfo = "N/A"; - halfLogCounter = 1 - halfLogCounter; // Toggle between 0 and 1 - } + UpdateHealth(_rewardPerStep); } public override void OnActionReceived(ActionBuffers action) @@ -366,6 +341,7 @@ public override void OnActionReceived(ActionBuffers action) (float[] raycastObservations, string[] raycastTags) = CollectRaycastObservations(); string combinedRaycastData = CombineRaycastData(raycastObservations, raycastTags); + string playerControlsDescription = GetActiveCameraDescription(); LogToCSV( localVel, @@ -382,7 +358,7 @@ public override void OnActionReceived(ActionBuffers action) wasSpawnerButtonTriggered, combinedSpawnerInfo, wasAgentInDataZone, - playerControls.GetActiveCameraDescription(), + playerControlsDescription, combinedRaycastData ); @@ -395,6 +371,43 @@ public override void OnActionReceived(ActionBuffers action) UpdateHealth(_rewardPerStep); } + private string GetActiveCameraDescription() + { + if (playerControls != null) + { + return playerControls.GetActiveCameraDescription(); + } + else + { + /* Fallback to using the main camera or predefined logic if playerControls is not present */ + Camera activeCamera = Camera.main; + + if (activeCamera != null) + { + if (activeCamera.CompareTag("MainCamera")) + { + return "0 (First-Person)"; + } + else if (activeCamera.CompareTag("AgentCamMid")) + { + return "1 (Third-Person)"; + } + else if (activeCamera.CompareTag("camBase")) + { + return "2 (Bird's Eye)"; + } + else + { + return $"{activeCamera.name} (unknown)"; + } + } + else + { + return "No Active Camera"; + } + } + } + private void InitialiseCSVProcess() { /* Base path for the logs to be stored */ From 8f24c0ad1f66fe38fcfa43734c1b67e294c3fec2 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Fri, 9 Aug 2024 19:11:42 +0100 Subject: [PATCH 155/205] removed redundant vars --- Assets/Scripts/TrainingAgent.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index a92719c4..494f821b 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -84,9 +84,6 @@ public class TrainingAgent : Agent, IPrefab private AutoResetEvent flushEvent = new AutoResetEvent(false); private Thread flushThread; private bool threadRunning = true; - private int logBatchSize = 101; /* Log every 10 frames to CSV file */ - private int frameCounter = 0; - private int halfLogCounter = 0; public void RecordSpawnerInfo(string spawnerInfo) { From 418af67a6e5a5eb69d411a77f0f514840d0731b4 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Fri, 9 Aug 2024 19:41:55 +0100 Subject: [PATCH 156/205] important change: implemented thread pooling - a more efficient and automatic process of running threads: https://medium.com/@lexitrainerph/c-threading-from-basic-to-advanced-84927e502a38 Also minor comment additions and typo fixes. --- Assets/Scripts/TrainingAgent.cs | 36 ++++++++++----------------------- 1 file changed, 11 insertions(+), 25 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 494f821b..a1cb6a6d 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -16,12 +16,6 @@ /// The TrainingAgent class is a subclass of the Agent class in the ML-Agents library. /// Actions are currently discrete. 2 branches of 0,1,2, 0,1,2 for forward and rotate respectively. /// - - -// TODO: Use thread pooling to reduce overhead of creating new threads: -// https://medium.com/@lexitrainerph/c-threading-from-basic-to-advanced-84927e502a38 - - public class TrainingAgent : Agent, IPrefab { [Header("Agent Settings")] @@ -75,15 +69,14 @@ public class TrainingAgent : Agent, IPrefab private ConcurrentQueue logQueue = new ConcurrentQueue(); private const int bufferSize = 101; /* Corresponds to rows in the CSV file to keep in memory before flushing to disk */ private bool isFlushing = false; + private AutoResetEvent flushEvent = new AutoResetEvent(false); + private bool threadRunning = true; private string lastCollectedRewardType = "None"; private string dispensedRewardType = "None"; private string wasAgentInDataZone = "No"; private bool wasRewardDispensed = false; private bool wasSpawnerButtonTriggered = false; private string combinedSpawnerInfo = "N/A"; - private AutoResetEvent flushEvent = new AutoResetEvent(false); - private Thread flushThread; - private bool threadRunning = true; public void RecordSpawnerInfo(string spawnerInfo) { @@ -141,7 +134,7 @@ private string CombineRaycastData(float[] observations, string[] tags) } /// - /// Initialize is called when the training session is started from mlagents. It sets up the agent's initial state. + /// Initialize is called when the training session is started from ml-agents. It sets up the agent's initial state. /// public override void Initialize() { @@ -163,24 +156,20 @@ public override void Initialize() } /// - /// OnDisable is called when the training session is stopped form mlagents. - /// It closes the CSV file and flushes the log queue at whatever the current size is. + /// OnDisable is called when the training session is stopped from ml-agents. + /// It closes the CSV file and flushes the log queue (what's left to flush). /// protected override void OnDisable() { - base.OnDisable(); - threadRunning = false; // Signal the flush thread to stop - flushEvent.Set(); // Ensure the thread is not stuck in WaitOne() - - if (flushThread != null && flushThread.IsAlive) - { - flushThread.Join(); // Wait for the thread to finish - } + base.OnDisable(); /* Call the base class method */ + threadRunning = false; /* Signal the flush thread to stop */ + flushEvent.Set(); /* Ensure the thread is not stuck in WaitOne() */ if (writer != null) { + writer.WriteLine($"Goals Collected: {numberOfGoalsCollected}"); FlushLogQueue(); /* Flush any remaining logs in the queue */ - writer.Close(); + writer.Close(); /* Close the writer */ } Spawner_InteractiveButton.RewardSpawned -= OnRewardSpawned; @@ -429,7 +418,6 @@ private void InitialiseCSVProcess() } /* Generate a filename with the YAML file name and a date stamp to prevent overwriting. */ - // TODO: Extract YAML name from side channel message. string dateTimeString = DateTime.Now.ToString("dd-MM-yy_HHmm"); string filename = $"Observations_{dateTimeString}.csv"; csvFilePath = Path.Combine(directoryPath, filename); @@ -517,7 +505,7 @@ string combinedRaycastData /// private void StartFlushThread() { - flushThread = new Thread(() => + ThreadPool.QueueUserWorkItem(state => { while (threadRunning) { @@ -531,7 +519,6 @@ private void StartFlushThread() } FlushLogQueue(); }); - flushThread.Start(); } private void FlushLogQueue() @@ -690,7 +677,6 @@ public void UpdateHealth(float updateAmount, bool andCompleteArena = false) return; } - // TODO: Debug current pass mark for arena == 0 if (andCompleteArena || _nextUpdateCompleteArena) { _nextUpdateCompleteArena = false; From 33d0df7b21c864becbb77ff157d44bb197291f64 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Fri, 9 Aug 2024 19:42:41 +0100 Subject: [PATCH 157/205] minor comment change --- Assets/Resources/test_configs/decoy-file-test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/Resources/test_configs/decoy-file-test.yaml b/Assets/Resources/test_configs/decoy-file-test.yaml index 4184f2fb..4d8a3534 100644 --- a/Assets/Resources/test_configs/decoy-file-test.yaml +++ b/Assets/Resources/test_configs/decoy-file-test.yaml @@ -1,4 +1,4 @@ -# Testing file for ongoing development. Will be removed once the feature is complete. +# Testing file for ongoing development. !ArenaConfig arenas: 0: !Arena From 9ed1b9c49afc8733e1cda29a01fbf017f05c0027 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Fri, 9 Aug 2024 20:57:53 +0100 Subject: [PATCH 158/205] added ability to run unity tests built in now we can run tests via automation! also moved progressbar.cs to main scripts folder for unity/coherence. --- .../{ProgressBar => Scripts}/ProgressBar.cs | 0 .../ProgressBar.cs.meta | 0 Assets/Scripts/Scripts.asmdef | 26 ++++++++++++++ .../Scripts.asmdef.meta} | 2 +- Assets/Tests/EditMode.meta | 8 +++++ Assets/Tests/EditMode/EditMode.asmdef | 15 ++++++++ Assets/Tests/EditMode/EditMode.asmdef.meta | 7 ++++ Assets/Tests/Playmode.meta | 8 +++++ Assets/Tests/Playmode/Playmode.asmdef | 25 +++++++++++++ Assets/Tests/Playmode/Playmode.asmdef.meta | 7 ++++ Assets/Tests/Tests.asmdef | 35 ------------------- 11 files changed, 97 insertions(+), 36 deletions(-) rename Assets/{ProgressBar => Scripts}/ProgressBar.cs (100%) rename Assets/{ProgressBar => Scripts}/ProgressBar.cs.meta (100%) create mode 100644 Assets/Scripts/Scripts.asmdef rename Assets/{Tests/Tests.asmdef.meta => Scripts/Scripts.asmdef.meta} (76%) create mode 100644 Assets/Tests/EditMode.meta create mode 100644 Assets/Tests/EditMode/EditMode.asmdef create mode 100644 Assets/Tests/EditMode/EditMode.asmdef.meta create mode 100644 Assets/Tests/Playmode.meta create mode 100644 Assets/Tests/Playmode/Playmode.asmdef create mode 100644 Assets/Tests/Playmode/Playmode.asmdef.meta delete mode 100644 Assets/Tests/Tests.asmdef diff --git a/Assets/ProgressBar/ProgressBar.cs b/Assets/Scripts/ProgressBar.cs similarity index 100% rename from Assets/ProgressBar/ProgressBar.cs rename to Assets/Scripts/ProgressBar.cs diff --git a/Assets/ProgressBar/ProgressBar.cs.meta b/Assets/Scripts/ProgressBar.cs.meta similarity index 100% rename from Assets/ProgressBar/ProgressBar.cs.meta rename to Assets/Scripts/ProgressBar.cs.meta diff --git a/Assets/Scripts/Scripts.asmdef b/Assets/Scripts/Scripts.asmdef new file mode 100644 index 00000000..dd40bb4d --- /dev/null +++ b/Assets/Scripts/Scripts.asmdef @@ -0,0 +1,26 @@ +{ + "name": "Scripts", + "rootNamespace": "", + "references": [ + "GUID:6055be8ebefd69e48b49212b09b47b2f", + "GUID:b3f49edfedc855a48aa1a9e5d3cba438", + "GUID:85e0054f8e64b47309646d35f8851f81", + "GUID:61c5b659adf544b4baf3eef86248e13a", + "GUID:42675ddec8c314cf08d17ee0f6f5e5a5", + "GUID:57f6004a925b546cd94e94ed518e275d", + "GUID:38254a2538c8f42fb9f2057d17fd0e70", + "GUID:917f332e7ad944428f0246683188de8f", + "GUID:d29014db7ebcd4cf4a14f537fbf02110", + "GUID:daaa01096d9848a38185ee08fa7321c0", + "GUID:c23d1189efdcccd43ba976c73f20fa1d" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Assets/Tests/Tests.asmdef.meta b/Assets/Scripts/Scripts.asmdef.meta similarity index 76% rename from Assets/Tests/Tests.asmdef.meta rename to Assets/Scripts/Scripts.asmdef.meta index 81917d55..6f3e43f2 100644 --- a/Assets/Tests/Tests.asmdef.meta +++ b/Assets/Scripts/Scripts.asmdef.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 1a6896342468a407799c6e7173c6d614 +guid: 06038f19ef4684f92b0c535d763a0f46 AssemblyDefinitionImporter: externalObjects: {} userData: diff --git a/Assets/Tests/EditMode.meta b/Assets/Tests/EditMode.meta new file mode 100644 index 00000000..bed64e6b --- /dev/null +++ b/Assets/Tests/EditMode.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 751fae9e9cac74129965b05efd263251 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Tests/EditMode/EditMode.asmdef b/Assets/Tests/EditMode/EditMode.asmdef new file mode 100644 index 00000000..cd0cd676 --- /dev/null +++ b/Assets/Tests/EditMode/EditMode.asmdef @@ -0,0 +1,15 @@ +{ + "name": "EditMode", + "optionalUnityReferences": [ + "TestAssemblies", + "UnityEngine.TestRunner", + "UnityEditor.TestRunner", + "Scripts", + "Unity.ML-Agents", + "YamlDotNet", + "Unity.TextMeshPro" + ], + "includePlatforms": [ + "Editor" + ] +} \ No newline at end of file diff --git a/Assets/Tests/EditMode/EditMode.asmdef.meta b/Assets/Tests/EditMode/EditMode.asmdef.meta new file mode 100644 index 00000000..0bd66ee6 --- /dev/null +++ b/Assets/Tests/EditMode/EditMode.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: d9b040d557adc4f829a77282bc6ce5bb +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Tests/Playmode.meta b/Assets/Tests/Playmode.meta new file mode 100644 index 00000000..d3e5aedf --- /dev/null +++ b/Assets/Tests/Playmode.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 77a209d1e13114ab79b82ff3664de5e2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Tests/Playmode/Playmode.asmdef b/Assets/Tests/Playmode/Playmode.asmdef new file mode 100644 index 00000000..b9dfe57a --- /dev/null +++ b/Assets/Tests/Playmode/Playmode.asmdef @@ -0,0 +1,25 @@ +{ + "name": "Playmode", + "rootNamespace": "", + "references": [ + "UnityEngine.TestRunner", + "UnityEditor.TestRunner", + "Scripts", + "Unity.ML-Agents", + "YamlDotNet", + "Unity.TextMeshPro" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": true, + "precompiledReferences": [ + "nunit.framework.dll" + ], + "autoReferenced": true, + "defineConstraints": [ + "UNITY_INCLUDE_TESTS" + ], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Assets/Tests/Playmode/Playmode.asmdef.meta b/Assets/Tests/Playmode/Playmode.asmdef.meta new file mode 100644 index 00000000..9f066a9e --- /dev/null +++ b/Assets/Tests/Playmode/Playmode.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c23922a282de1478480d5d94544ea291 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Tests/Tests.asmdef b/Assets/Tests/Tests.asmdef deleted file mode 100644 index b064308f..00000000 --- a/Assets/Tests/Tests.asmdef +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "Tests", - "rootNamespace": "", - "references": [ - "UnityEngine.TestRunner", - "UnityEditor.TestRunner", - "Unity.ML-Agents", - "Unity.ML-Agents.CommunicatorObjects", - "Unity.ML-Agents.Editor", - "Unity.ML-Agents.Editor.Tests", - "Unity.ML-Agents.Editor.Tests.PublicAPI", - "Unity.ML-Agents.Runtime.Sensor.Tests", - "Unity.ML-Agents.Runtime.Tests", - "Unity.ML-Agents.Runtime.Utils.Tests" - ], - "includePlatforms": [], - "excludePlatforms": [ - "LinuxStandalone64", - "CloudRendering", - "macOSStandalone", - "WindowsStandalone32", - "WindowsStandalone64" - ], - "allowUnsafeCode": false, - "overrideReferences": true, - "precompiledReferences": [ - "nunit.framework.dll" - ], - "autoReferenced": false, - "defineConstraints": [ - "UNITY_INCLUDE_TESTS" - ], - "versionDefines": [], - "noEngineReferences": false -} \ No newline at end of file From 9c34a482a4d8a6b8a3b1a9fa6a482aba0a42ed24 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Fri, 9 Aug 2024 21:17:32 +0100 Subject: [PATCH 159/205] found and fixed bug where: sometimes there would be multiple rows with the same data and/or step values. Simply added a check to see if the preceding row had identical values - if not, log, if yes, skip that row. Unlikely that the same row will have the absolute identical values in every column as a note. --- Assets/Scripts/TrainingAgent.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index a1cb6a6d..10a20721 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -77,6 +77,7 @@ public class TrainingAgent : Agent, IPrefab private bool wasRewardDispensed = false; private bool wasSpawnerButtonTriggered = false; private string combinedSpawnerInfo = "N/A"; + private int _lastLoggedStep = -1; public void RecordSpawnerInfo(string spawnerInfo) { @@ -465,6 +466,11 @@ private void LogToCSV( string combinedRaycastData ) { + /* Check if the current step has already been logged */ + if (StepCount == _lastLoggedStep) + { + return; + } string logEntry = string.Format( "{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14},{15},{16},{17},{18},{19},{20},{21}", customEpisodeCount, @@ -494,6 +500,8 @@ string combinedRaycastData logQueue.Enqueue(logEntry); lastCollectedRewardType = "None"; + _lastLoggedStep = StepCount; + if (logQueue.Count >= bufferSize) { flushEvent.Set(); @@ -728,6 +736,8 @@ IEnumerator EndEpisodeAfterDelay() public override void OnEpisodeBegin() { + _lastLoggedStep = -1; + if (!_arena.IsFirstArenaReset) { writer.WriteLine($"Goals Collected: {numberOfGoalsCollected}"); From 9511687899d8674ad4b0b32019ead40e014424f5 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Mon, 12 Aug 2024 11:03:54 +0100 Subject: [PATCH 160/205] Fixed potential error in fade.cs where image is null but is not handled gracefully. --- Assets/Scripts/Fade.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Assets/Scripts/Fade.cs b/Assets/Scripts/Fade.cs index 64605551..44e8b78d 100644 --- a/Assets/Scripts/Fade.cs +++ b/Assets/Scripts/Fade.cs @@ -29,8 +29,15 @@ public void ResetFade() public void StartFade() { + if (_image == null) + { + Debug.LogWarning("No image assigned to fade."); + return; + } + StopAllCoroutines(); _fadeDirection *= -1; + if (_play) { StartCoroutine(FadeOutEnum()); From d8acef17f3d20e7fe4906c7c1a8c34d3fbb7e6a8 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Mon, 12 Aug 2024 11:14:10 +0100 Subject: [PATCH 161/205] added null/reference checks for sanity --- Assets/Scripts/CameraFollow.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Assets/Scripts/CameraFollow.cs b/Assets/Scripts/CameraFollow.cs index 0be15f9d..5aa25b39 100644 --- a/Assets/Scripts/CameraFollow.cs +++ b/Assets/Scripts/CameraFollow.cs @@ -10,12 +10,22 @@ public class CameraFollow : MonoBehaviour void Start() { + if (followObj == null) + { + throw new MissingReferenceException("The followObj is not assigned."); + } + transform.position = followObj.transform.position; transform.rotation = followObj.transform.rotation; } void Update() { + if (followObj == null) + { + throw new MissingReferenceException("The followObj is not assigned."); + } + transform.position = followObj.transform.position; transform.rotation = followObj.transform.rotation; } From e948a52f70930ab178577d618fea3fca9e39bf18 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Mon, 12 Aug 2024 12:11:13 +0100 Subject: [PATCH 162/205] fixed bug where collecobservations() was ending episode prematurely --- Assets/Scripts/TrainingAgent.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 10a20721..573873d6 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -302,8 +302,6 @@ public override void CollectObservations(VectorSensor sensor) wasSpawnerButtonTriggered = false; wasAgentInDataZone = "No"; combinedSpawnerInfo = "N/A"; - - UpdateHealth(_rewardPerStep); } public override void OnActionReceived(ActionBuffers action) From b4f31b8e1a08a8a098d2157100ee510da5dad55e Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Mon, 12 Aug 2024 13:58:39 +0100 Subject: [PATCH 163/205] added tests to automate properly old tests, but now organised into edit and play modes. --- Assets/Tests/EditMode/EditMode.asmdef | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/Assets/Tests/EditMode/EditMode.asmdef b/Assets/Tests/EditMode/EditMode.asmdef index cd0cd676..b058af1f 100644 --- a/Assets/Tests/EditMode/EditMode.asmdef +++ b/Assets/Tests/EditMode/EditMode.asmdef @@ -1,7 +1,7 @@ { "name": "EditMode", - "optionalUnityReferences": [ - "TestAssemblies", + "rootNamespace": "", + "references": [ "UnityEngine.TestRunner", "UnityEditor.TestRunner", "Scripts", @@ -11,5 +11,17 @@ ], "includePlatforms": [ "Editor" - ] + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": true, + "precompiledReferences": [ + "nunit.framework.dll" + ], + "autoReferenced": false, + "defineConstraints": [ + "UNITY_INCLUDE_TESTS" + ], + "versionDefines": [], + "noEngineReferences": false } \ No newline at end of file From 76232b209de48e8311ea2e45153c125163254826 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Mon, 12 Aug 2024 13:58:56 +0100 Subject: [PATCH 164/205] Tests dump --- Assets/Tests/EditMode/FadeTests.cs | 90 ++++++++++++++++++ Assets/Tests/EditMode/FadeTests.cs.meta | 11 +++ Assets/Tests/EditMode/FlashingImageTests.cs | 63 +++++++++++++ .../Tests/EditMode/FlashingImageTests.cs.meta | 11 +++ Assets/Tests/EditMode/GroundedTests.cs | 53 +++++++++++ Assets/Tests/EditMode/GroundedTests.cs.meta | 11 +++ Assets/Tests/EditMode/LightSwitchTests.cs | 94 +++++++++++++++++++ .../Tests/EditMode/LightSwitchTests.cs.meta | 11 +++ .../Tests/EditMode/ListOfBlackScreensTests.cs | 75 +++++++++++++++ .../EditMode/ListOfBlackScreensTests.cs.meta | 11 +++ 10 files changed, 430 insertions(+) create mode 100644 Assets/Tests/EditMode/FadeTests.cs create mode 100644 Assets/Tests/EditMode/FadeTests.cs.meta create mode 100644 Assets/Tests/EditMode/FlashingImageTests.cs create mode 100644 Assets/Tests/EditMode/FlashingImageTests.cs.meta create mode 100644 Assets/Tests/EditMode/GroundedTests.cs create mode 100644 Assets/Tests/EditMode/GroundedTests.cs.meta create mode 100644 Assets/Tests/EditMode/LightSwitchTests.cs create mode 100644 Assets/Tests/EditMode/LightSwitchTests.cs.meta create mode 100644 Assets/Tests/EditMode/ListOfBlackScreensTests.cs create mode 100644 Assets/Tests/EditMode/ListOfBlackScreensTests.cs.meta diff --git a/Assets/Tests/EditMode/FadeTests.cs b/Assets/Tests/EditMode/FadeTests.cs new file mode 100644 index 00000000..2fb676c2 --- /dev/null +++ b/Assets/Tests/EditMode/FadeTests.cs @@ -0,0 +1,90 @@ +using System.Collections; +using NUnit.Framework; +using UnityEngine; +using UnityEngine.TestTools; +using UnityEngine.UI; + +/// +/// Tests for the Fade class. +/// +public class FadeTests +{ + private GameObject gameObject; + private Fade fade; + private Image image; + + [SetUp] + public void SetUp() + { + gameObject = new GameObject("TestObject"); + fade = gameObject.AddComponent(); + + GameObject imageObject = new GameObject("TestImage"); + imageObject.AddComponent(); + image = imageObject.AddComponent(); + image.transform.SetParent(gameObject.transform, false); + + SetPrivateField(fade, "_image", image); + fade.fadeSpeed = 1.0f; + } + + [TearDown] + public void TearDown() + { + Object.DestroyImmediate(gameObject); + } + + [Test] + public void ResetFade_ShouldSetAlphaToZero() + { + fade.ResetFade(); + Assert.AreEqual(0f, image.color.a); + } + + [Test] + public void StartFade_ShouldSetAlphaBasedOnFadeDirection() + { + fade.ResetFade(); + fade.StartFade(); + + Assert.AreEqual(1f, image.color.a); + + fade.StartFade(); + Assert.AreEqual(0f, image.color.a); + } + + [UnityTest] + [UnityPlatform( + RuntimePlatform.OSXPlayer, + RuntimePlatform.WindowsPlayer, + RuntimePlatform.LinuxPlayer + )] + public IEnumerator FadeOutEnum_ShouldChangeAlphaOverTime() + { + fade.StartFade(); + + float initialAlpha = image.color.a; + + yield return new WaitForSeconds(0.5f); + + Assert.AreNotEqual(initialAlpha, image.color.a); + } + + [Test] + public void StartFade_ShouldHandleNullImageGracefully() + { + SetPrivateField(fade, "_image", null); + + Assert.DoesNotThrow(() => fade.StartFade()); + } + + private void SetPrivateField(object obj, string fieldName, object value) + { + var field = obj.GetType() + .GetField( + fieldName, + System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance + ); + field.SetValue(obj, value); + } +} diff --git a/Assets/Tests/EditMode/FadeTests.cs.meta b/Assets/Tests/EditMode/FadeTests.cs.meta new file mode 100644 index 00000000..f26aa401 --- /dev/null +++ b/Assets/Tests/EditMode/FadeTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dacad70125c0845bab3e68415b3235bd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Tests/EditMode/FlashingImageTests.cs b/Assets/Tests/EditMode/FlashingImageTests.cs new file mode 100644 index 00000000..8ed39d2b --- /dev/null +++ b/Assets/Tests/EditMode/FlashingImageTests.cs @@ -0,0 +1,63 @@ +using NUnit.Framework; +using UnityEngine; +using UnityEngine.UI; + +/// +/// Tests for the FlashingImage class. +/// +public class FlashingImageTests +{ + private GameObject gameObject; + private FlashingImage flashingImage; + private Image image; + + [SetUp] + public void SetUp() + { + gameObject = new GameObject(); + flashingImage = gameObject.AddComponent(); + image = gameObject.AddComponent(); + flashingImage.imageToFlash = image; + } + + [TearDown] + public void TearDown() + { + Object.DestroyImmediate(gameObject); + } + + [Test] + public void StartFlashing_ShouldResetFlashTimer() + { + flashingImage.StartFlashing(); + + // Note: Inferring it's working correctly here by checking the flashTimer value. + // (expecting no exceptions or errors) + Assert.DoesNotThrow(() => flashingImage.StartFlashing()); + } + + [Test] + public void StopFlashing_ShouldSetImageAlphaToOne() + { + flashingImage.StopFlashing(); + + Assert.AreEqual(1f, flashingImage.imageToFlash.color.a); + } + + [Test] + public void SetImageAlpha_ShouldChangeImageAlpha() + { + flashingImage.StartFlashing(); + flashingImage.StopFlashing(); + + Assert.AreEqual(1f, flashingImage.imageToFlash.color.a); + } + + [Test] + public void StopFlashing_WhenImageIsNull_ShouldNotThrowError() + { + flashingImage.imageToFlash = null; + + Assert.DoesNotThrow(() => flashingImage.StopFlashing()); + } +} diff --git a/Assets/Tests/EditMode/FlashingImageTests.cs.meta b/Assets/Tests/EditMode/FlashingImageTests.cs.meta new file mode 100644 index 00000000..1ac7c30f --- /dev/null +++ b/Assets/Tests/EditMode/FlashingImageTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 44deb97a447c14c7aa017c76bd0bef6e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Tests/EditMode/GroundedTests.cs b/Assets/Tests/EditMode/GroundedTests.cs new file mode 100644 index 00000000..f830f703 --- /dev/null +++ b/Assets/Tests/EditMode/GroundedTests.cs @@ -0,0 +1,53 @@ +using NUnit.Framework; +using UnityEngine; + +/// +/// Tests for the Grounded class. +/// +public class GroundedTests +{ + private GameObject gameObject; + private TestableGrounded grounded; + + private class TestableGrounded : Grounded + { + public float InvokeAdjustY(float yIn) + { + return AdjustY(yIn); + } + } + + [SetUp] + public void SetUp() + { + gameObject = new GameObject(); + grounded = gameObject.AddComponent(); + } + + [TearDown] + public void TearDown() + { + Object.DestroyImmediate(gameObject); + } + + [Test] + public void AdjustY_ShouldAlwaysReturnZero() + { + float result = grounded.InvokeAdjustY(5f); + Assert.AreEqual(0f, result); + } + + [Test] + public void AdjustY_ShouldReturnZeroForNegativeValues() + { + float result = grounded.InvokeAdjustY(-10f); + Assert.AreEqual(0f, result); + } + + [Test] + public void AdjustY_ShouldReturnZeroForZeroInput() + { + float result = grounded.InvokeAdjustY(0f); + Assert.AreEqual(0f, result); + } +} diff --git a/Assets/Tests/EditMode/GroundedTests.cs.meta b/Assets/Tests/EditMode/GroundedTests.cs.meta new file mode 100644 index 00000000..b555c05e --- /dev/null +++ b/Assets/Tests/EditMode/GroundedTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 62e0c0fb7881542eb80014ac41b46ae4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Tests/EditMode/LightSwitchTests.cs b/Assets/Tests/EditMode/LightSwitchTests.cs new file mode 100644 index 00000000..43fb8284 --- /dev/null +++ b/Assets/Tests/EditMode/LightSwitchTests.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; +using NUnit.Framework; +using Lights; + +/// +/// Tests for the Lights (blackout feature) class. +/// +public class LightsSwitchTests +{ + [Test] + public void IncrementValueOnMoveNext() + { + int initialValue = 3; + var enumerator = new InfiniteEnumerator(initialValue); + + enumerator.MoveNext(); + int currentValue = enumerator.Current; + + Assert.AreEqual(initialValue, currentValue); + } + + [Test] + public void ResetEnumeratorToZero() + { + int initialValue = 5; + var enumerator = new InfiniteEnumerator(initialValue); + enumerator.MoveNext(); + + enumerator.Reset(); + int currentValue = enumerator.Current; + + Assert.AreEqual(0, currentValue); + } + + [Test] + public void KeepIncrementingOnMultipleMoveNext() + { + int initialValue = 2; + var enumerator = new InfiniteEnumerator(initialValue); + + enumerator.MoveNext(); + Assert.AreEqual(2, enumerator.Current); + + enumerator.MoveNext(); + Assert.AreEqual(4, enumerator.Current); + + enumerator.MoveNext(); + Assert.AreEqual(6, enumerator.Current); + } + + [Test] + public void ThrowExceptionForNegativeEpisodeLength() + { + Assert.Throws(() => new LightsSwitch(-1, new List { 1 })); + } + + [Test] + public void ThrowExceptionForInvalidBlackoutInterval() + { + Assert.Throws(() => new LightsSwitch(5, new List { -1, 6 })); + } + + [Test] + public void ReturnTrueIfNoBlackouts() + { + var lightsSwitch = new LightsSwitch(10, new List()); + + bool lightStatus = lightsSwitch.LightStatus(0, 1); + + Assert.IsTrue(lightStatus); + } + + [Test] + public void HandleMultipleBlackoutsProperly() + { + var blackouts = new List { 1, 2, 3 }; + var lightsSwitch = new LightsSwitch(10, blackouts); + + Assert.IsTrue(lightsSwitch.LightStatus(0, 1)); + Assert.IsFalse(lightsSwitch.LightStatus(1, 1)); + Assert.IsTrue(lightsSwitch.LightStatus(2, 1)); + Assert.IsFalse(lightsSwitch.LightStatus(3, 1)); + } + + [Test] + public void ThrowExceptionForInvalidStepOrAgentDecisionInterval() + { + var lightsSwitch = new LightsSwitch(10, new List { 1 }); + + Assert.Throws(() => lightsSwitch.LightStatus(-1, 1)); + Assert.Throws(() => lightsSwitch.LightStatus(1, 0)); + } +} diff --git a/Assets/Tests/EditMode/LightSwitchTests.cs.meta b/Assets/Tests/EditMode/LightSwitchTests.cs.meta new file mode 100644 index 00000000..a67ba028 --- /dev/null +++ b/Assets/Tests/EditMode/LightSwitchTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 181a1f1d9123445dc94d207274734ed5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Tests/EditMode/ListOfBlackScreensTests.cs b/Assets/Tests/EditMode/ListOfBlackScreensTests.cs new file mode 100644 index 00000000..88213e00 --- /dev/null +++ b/Assets/Tests/EditMode/ListOfBlackScreensTests.cs @@ -0,0 +1,75 @@ +using System.Collections.Generic; +using NUnit.Framework; +using UnityEngine; +using Holders; + +/// +/// Tests for the Holders class. +/// +public class ListOfBlackScreensTests +{ + [Test] + public void GetFades_ShouldReturnEmptyList_WhenAllBlackScreensIsNull() + { + var listOfBlackScreens = new ListOfBlackScreens { allBlackScreens = null }; + + var fades = listOfBlackScreens.GetFades(); + + Assert.IsNotNull(fades); + Assert.AreEqual(0, fades.Count); + } + + [Test] + public void GetFades_ShouldReturnEmptyList_WhenAllBlackScreensIsEmpty() + { + var listOfBlackScreens = new ListOfBlackScreens + { + allBlackScreens = new List() + }; + + var fades = listOfBlackScreens.GetFades(); + + Assert.IsNotNull(fades); + Assert.AreEqual(0, fades.Count); + } + + [Test] + public void GetFades_ShouldReturnOnlyNonNullFadeComponents() + { + var fadeObject1 = new GameObject(); + fadeObject1.AddComponent(); + + var fadeObject2 = new GameObject(); + + var fadeObject3 = new GameObject(); + fadeObject3.AddComponent(); + + var listOfBlackScreens = new ListOfBlackScreens + { + allBlackScreens = new List { fadeObject1, fadeObject2, fadeObject3 } + }; + + var fades = listOfBlackScreens.GetFades(); + + Assert.AreEqual(2, fades.Count); + Assert.Contains(fadeObject1.GetComponent(), fades); + Assert.Contains(fadeObject3.GetComponent(), fades); + } + + [Test] + public void GetFades_ShouldReturnEmptyList_WhenNoFadeComponentsAreFound() + { + var noFadeObject1 = new GameObject(); + var noFadeObject2 = new GameObject(); + + var listOfBlackScreens = new ListOfBlackScreens + { + allBlackScreens = new List { noFadeObject1, noFadeObject2 } + }; + + var fades = listOfBlackScreens.GetFades(); + + Assert.IsNotNull(fades); + Assert.AreEqual(0, fades.Count); + } +} diff --git a/Assets/Tests/EditMode/ListOfBlackScreensTests.cs.meta b/Assets/Tests/EditMode/ListOfBlackScreensTests.cs.meta new file mode 100644 index 00000000..165a63c3 --- /dev/null +++ b/Assets/Tests/EditMode/ListOfBlackScreensTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 75ffd545a574b4fbfbfad66ebb92cd4d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 08d91ee7e699c862ccdf24fb81cab335802c7396 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Mon, 12 Aug 2024 14:18:53 +0100 Subject: [PATCH 165/205] old test suite dump --- Assets/Tests/EditMode/BallGoalTests.cs | 105 ++++++++++++++++++++ Assets/Tests/EditMode/BallGoalTests.cs.meta | 11 ++ 2 files changed, 116 insertions(+) create mode 100644 Assets/Tests/EditMode/BallGoalTests.cs create mode 100644 Assets/Tests/EditMode/BallGoalTests.cs.meta diff --git a/Assets/Tests/EditMode/BallGoalTests.cs b/Assets/Tests/EditMode/BallGoalTests.cs new file mode 100644 index 00000000..9469107c --- /dev/null +++ b/Assets/Tests/EditMode/BallGoalTests.cs @@ -0,0 +1,105 @@ +using NUnit.Framework; +using UnityEngine; + +/// +/// Tests for the BallGoal class. +/// +public class BallGoalTests +{ + private BallGoal ballGoal; + private GameObject testObject; + + [SetUp] + public void Setup() + { + testObject = new GameObject("BallGoal"); + ballGoal = testObject.AddComponent(); + + ballGoal.sizeMin = Vector3.one * 1.0f; + ballGoal.sizeMax = Vector3.one * 3.0f; + ballGoal.sizeAdjustment = 1.0f; + ballGoal.ratioSize = Vector3.one; + } + + [TearDown] + public void Teardown() + { + if (testObject != null) + { + Object.DestroyImmediate(testObject); + } + } + + [Test] + public void TestSetSize_WithinLimits() + { + Vector3 testSize = new Vector3(2.0f, 2.0f, 2.0f); + ballGoal.SetSize(testSize); + + Assert.AreEqual( + testSize, + ballGoal.transform.localScale, + "The size should be set correctly within the limits." + ); + Assert.AreEqual( + 2.0f, + ballGoal.reward, + "The reward should be adjusted according to the size." + ); + } + + [Test] + public void TestSetSize_Clipping() + { + Vector3 testSize = new Vector3(4.0f, 4.0f, 4.0f); /* Size exceeding the maximum */ + ballGoal.SetSize(testSize); + + Vector3 expectedSize = ballGoal.sizeMax; + Assert.AreEqual( + expectedSize, + ballGoal.transform.localScale, + "The size should be clipped to the maximum allowed size." + ); + Assert.AreEqual(3.0f, ballGoal.reward, "The reward should correspond to the clipped size."); + } + + [Test] + public void TestSetSize_NegativeSize() + { + Vector3 testSize = new Vector3(-1.0f, -1.0f, -1.0f); /* Negative size components */ + ballGoal.SetSize(testSize); + + float randomSize = ballGoal.transform.localScale.x; + Assert.IsTrue( + randomSize >= ballGoal.sizeMin.x && randomSize <= ballGoal.sizeMax.x, + "The size should be set to a random value within the limits." + ); + Assert.AreEqual( + randomSize, + ballGoal.reward, + "The reward should match the randomly selected size." + ); + } + + [Test] + public void TestSetSize_WithSizeAdjustment() + { + ballGoal.sizeAdjustment = 2.0f; + Vector3 testSize = new Vector3(1.5f, 1.5f, 1.5f); + ballGoal.SetSize(testSize); + + Vector3 expectedSize = testSize * 2.0f; + expectedSize = Vector3.Min(expectedSize, ballGoal.sizeMax); + + Assert.AreEqual( + expectedSize, + ballGoal.transform.localScale, + "The size should be adjusted correctly." + ); + Assert.AreEqual( + expectedSize.x, + ballGoal.reward, + "The reward should be adjusted according to the scaled size." + ); + } +} diff --git a/Assets/Tests/EditMode/BallGoalTests.cs.meta b/Assets/Tests/EditMode/BallGoalTests.cs.meta new file mode 100644 index 00000000..5609943e --- /dev/null +++ b/Assets/Tests/EditMode/BallGoalTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0d3ed863fd5394901ad9f379b47ad0a8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From c2facf50a6b5b7b2671fff11cd4b9bcea6258ef7 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Mon, 12 Aug 2024 14:52:51 +0100 Subject: [PATCH 166/205] added grace checks for taking screenshots and saving file --- Assets/Scripts/ScreenshotCamera.cs | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/Assets/Scripts/ScreenshotCamera.cs b/Assets/Scripts/ScreenshotCamera.cs index f527c939..73e3d2c0 100644 --- a/Assets/Scripts/ScreenshotCamera.cs +++ b/Assets/Scripts/ScreenshotCamera.cs @@ -2,7 +2,7 @@ using UnityEngine; /// -/// Captures screenshots from a camera and saves them to the device's storage. +/// Captures screenshots from the main camera and saves them to the device's storage. /// [RequireComponent(typeof(Camera))] public class ScreenshotCamera : MonoBehaviour @@ -18,6 +18,11 @@ public class ScreenshotCamera : MonoBehaviour private void Awake() { screenshotCam = GetComponent(); + if (screenshotCam == null) + { + Debug.LogError("Camera component is missing from the GameObject."); + return; + } InitializeRenderTexture(); } @@ -41,6 +46,11 @@ private void InitializeRenderTexture() public void Activate(bool enable = true) { + if (screenshotCam == null) + { + Debug.LogError("Screenshot Camera is not assigned."); + return; + } screenshotCam.enabled = enable; } @@ -49,12 +59,24 @@ private void LateUpdate() if (screenshotCam.enabled && !testMode) { CaptureScreenshot(); - Activate(false); /* Deactivate the camera after capturing to prevent multiple captures */ + Activate(false); } } private void CaptureScreenshot() { + if (screenshotCam == null) + { + Debug.LogError("Screenshot Camera is not assigned."); + return; + } + + if (screenshotCam.targetTexture == null) + { + Debug.LogError("No RenderTexture assigned to the Camera."); + return; + } + screenshotCam.Render(); RenderTexture.active = screenshotCam.targetTexture; From 285a36086730193f9492409159adf69518a7e0c3 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Mon, 12 Aug 2024 14:53:13 +0100 Subject: [PATCH 167/205] screenshotcamera feature test file dump --- .../Playmode/ScreenshotCameraPlayModeTests.cs | 79 +++++++++++++++++++ .../ScreenshotCameraPlayModeTests.cs.meta | 11 +++ 2 files changed, 90 insertions(+) create mode 100644 Assets/Tests/Playmode/ScreenshotCameraPlayModeTests.cs create mode 100644 Assets/Tests/Playmode/ScreenshotCameraPlayModeTests.cs.meta diff --git a/Assets/Tests/Playmode/ScreenshotCameraPlayModeTests.cs b/Assets/Tests/Playmode/ScreenshotCameraPlayModeTests.cs new file mode 100644 index 00000000..20cffd81 --- /dev/null +++ b/Assets/Tests/Playmode/ScreenshotCameraPlayModeTests.cs @@ -0,0 +1,79 @@ +using System.Collections; +using System.IO; +using NUnit.Framework; +using UnityEngine; +using UnityEngine.TestTools; + +/// +/// Tests for the ScreenshotCamera feature in Play Mode. +/// +public class ScreenshotCameraPlayModeTests +{ + private GameObject cameraObject; + private ScreenshotCamera screenshotCamera; + private RenderTexture renderTexture; + + [SetUp] + public void SetUp() + { + cameraObject = new GameObject("TestCamera"); + Camera camera = cameraObject.AddComponent(); + screenshotCamera = cameraObject.AddComponent(); + + renderTexture = new RenderTexture(256, 256, 24); + screenshotCamera.renderTexture = renderTexture; + camera.targetTexture = renderTexture; + + screenshotCamera.filePath = "TestScreenshots"; + screenshotCamera.fileName = "test_capture"; + screenshotCamera.testMode = false; /* Ensure test mode is off for actual rendering */ + + screenshotCamera.Activate(true); + } + + [TearDown] + public void TearDown() + { + if (cameraObject != null) + { + Object.DestroyImmediate(cameraObject); + } + + if (renderTexture != null) + { + renderTexture.Release(); + Object.DestroyImmediate(renderTexture); + } + + string directoryPath = Path.Combine( + Application.persistentDataPath, + screenshotCamera.filePath + ); + if (Directory.Exists(directoryPath)) + { + Directory.Delete(directoryPath, true); + } + } + + [UnityTest] + public IEnumerator ScreenshotCamera_CaptureScreenshot_CreatesFile() + { + screenshotCamera.Activate(true); + yield return new WaitForEndOfFrame(); + + screenshotCamera.Activate(false); + + string directoryPath = Path.Combine( + Application.persistentDataPath, + screenshotCamera.filePath + ); + Assert.IsTrue(Directory.Exists(directoryPath), "Screenshot directory was not created."); + + string[] files = Directory.GetFiles(directoryPath); + Assert.IsTrue(files.Length > 0, "No screenshot files were created."); + + /* Just checking here that the file is a PNG image. Not a requirement but still... */ + string filePath = files[0]; + Assert.IsTrue(filePath.EndsWith(".png"), "Captured file is not a PNG image."); + } +} diff --git a/Assets/Tests/Playmode/ScreenshotCameraPlayModeTests.cs.meta b/Assets/Tests/Playmode/ScreenshotCameraPlayModeTests.cs.meta new file mode 100644 index 00000000..eee93c1c --- /dev/null +++ b/Assets/Tests/Playmode/ScreenshotCameraPlayModeTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 24bb68eda8f1d4d699b44879d5e53c1d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 7a9b51bba5d2a2016d7f874d125b9fc669b2ca0f Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 13 Aug 2024 09:06:13 +0100 Subject: [PATCH 168/205] exposed method to public for tests --- Assets/Scripts/AnimalSkinManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/Scripts/AnimalSkinManager.cs b/Assets/Scripts/AnimalSkinManager.cs index 7c3f4fea..193178b8 100644 --- a/Assets/Scripts/AnimalSkinManager.cs +++ b/Assets/Scripts/AnimalSkinManager.cs @@ -62,7 +62,7 @@ public void SetAnimalSkin(string skinName) } } - void SetAnimalSkin(int skinID) + public void SetAnimalSkin(int skinID) { if (skinID >= 0 && skinID < AnimalCount) { From 1b47baf43a68fd791a7c2d216d7613c8b9e577c8 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 13 Aug 2024 09:19:37 +0100 Subject: [PATCH 169/205] updated code to use unity start for reliable initialisation logic --- Assets/Scripts/AnimalSkinManager.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Assets/Scripts/AnimalSkinManager.cs b/Assets/Scripts/AnimalSkinManager.cs index 193178b8..3724039d 100644 --- a/Assets/Scripts/AnimalSkinManager.cs +++ b/Assets/Scripts/AnimalSkinManager.cs @@ -27,7 +27,12 @@ public class AnimalSkinManager : MonoBehaviour private MeshRenderer meshRenderer; private MeshFilter meshFilter; - void Awake() + void Start() + { + Initialize(); + } + + public void Initialize() { meshRenderer = GetComponent(); meshFilter = GetComponent(); From d1ad8983fd09692235551bb3e0cde6a9859f73cb Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 13 Aug 2024 09:23:00 +0100 Subject: [PATCH 170/205] added new tests for checking animal skins are correctly set --- .../Tests/Playmode/AnimalSkinManagerTests.cs | 163 ++++++++++++++++++ .../Playmode/AnimalSkinManagerTests.cs.meta | 11 ++ 2 files changed, 174 insertions(+) create mode 100644 Assets/Tests/Playmode/AnimalSkinManagerTests.cs create mode 100644 Assets/Tests/Playmode/AnimalSkinManagerTests.cs.meta diff --git a/Assets/Tests/Playmode/AnimalSkinManagerTests.cs b/Assets/Tests/Playmode/AnimalSkinManagerTests.cs new file mode 100644 index 00000000..d964a8e7 --- /dev/null +++ b/Assets/Tests/Playmode/AnimalSkinManagerTests.cs @@ -0,0 +1,163 @@ +using NUnit.Framework; +using System.Collections; +using UnityEngine; +using UnityEngine.TestTools; + +/// +/// Tests for the AnimalSkinManager class. +/// +public class AnimalSkinManagerTests +{ + private GameObject testObject; + private AnimalSkinManager skinManager; + + [SetUp] + public void SetUp() + { + testObject = new GameObject(); + testObject.AddComponent(); + testObject.AddComponent(); + skinManager = testObject.AddComponent(); + + skinManager.AnimalNames = new string[] { "pig", "panda", "hedgehog" }; + skinManager.AnimalMeshes = new Mesh[] + { + /* Meshes for the animals, currently manually creating but should be in a loop in future maintenance */ + new Mesh(), + new Mesh(), + new Mesh() + }; + + skinManager.AnimalMaterials = new MultiDimArray[] + { + new MultiDimArray + { + array = new Material[] { new Material(Shader.Find("Standard")) } + }, + new MultiDimArray + { + array = new Material[] { new Material(Shader.Find("Standard")) } + }, + new MultiDimArray + { + array = new Material[] { new Material(Shader.Find("Standard")) } + } + }; + } + + [TearDown] + public void TearDown() + { + Object.Destroy(testObject); + } + + [UnityTest] + public IEnumerator Initialization_InitializesCorrectly() + { + var actualMaterials = skinManager.GetComponent().materials; + + Assert.AreEqual( + skinManager.AnimalMaterials[0].array[0].shader, + actualMaterials[0].shader, + "Shaders do not match" + ); + Assert.AreEqual( + skinManager.AnimalMaterials[0].array[0].color, + actualMaterials[0].color, + "Colors do not match" + ); + Assert.AreEqual( + skinManager.AnimalMaterials[0].array[0].mainTexture, + actualMaterials[0].mainTexture, + "Main textures do not match" + ); + + yield return null; + } + + [UnityTest] + public IEnumerator SetAnimalSkin_ByName_ChangesSkin() + { + skinManager.SetAnimalSkin("panda"); + + var actualMaterials = skinManager.GetComponent().materials; + + /* Compare the properties of the materials (equals that of the shader materials in the Agent's skins section) */ + Assert.AreEqual( + skinManager.AnimalMaterials[1].array[0].shader, + actualMaterials[0].shader, + "Shaders do not match" + ); + Assert.AreEqual( + skinManager.AnimalMaterials[1].array[0].color, + actualMaterials[0].color, + "Colors do not match" + ); + Assert.AreEqual( + skinManager.AnimalMaterials[1].array[0].mainTexture, + actualMaterials[0].mainTexture, + "Main textures do not match" + ); + + yield return null; + } + + [UnityTest] + public IEnumerator SetAnimalSkin_ByID_ChangesSkin() + { + skinManager.SetAnimalSkin(2); + + var actualMaterials = skinManager.GetComponent().materials; + + /* Compare the properties of the materials (equals that of the shader materials in the Agent's skins section) */ + Assert.AreEqual( + skinManager.AnimalMaterials[2].array[0].shader, + actualMaterials[0].shader, + "Shaders do not match" + ); + Assert.AreEqual( + skinManager.AnimalMaterials[2].array[0].color, + actualMaterials[0].color, + "Colors do not match" + ); + Assert.AreEqual( + skinManager.AnimalMaterials[2].array[0].mainTexture, + actualMaterials[0].mainTexture, + "Main textures do not match" + ); + + yield return null; + } + + [UnityTest] + public IEnumerator SetAnimalSkin_InvalidName_SelectsRandomSkin() + { + skinManager.SetAnimalSkin("InvalidName"); + + var actualMaterials = skinManager.GetComponent().materials; + + /* Check if the ID is valid and the materials are correctly applied */ + Assert.IsTrue( + skinManager.AnimalSkinID >= 0 + && skinManager.AnimalSkinID < AnimalSkinManager.AnimalCount, + "AnimalSkinID is out of range" + ); + Assert.AreEqual( + skinManager.AnimalMaterials[skinManager.AnimalSkinID].array[0].shader, + actualMaterials[0].shader, + "Shaders do not match" + ); + Assert.AreEqual( + skinManager.AnimalMaterials[skinManager.AnimalSkinID].array[0].color, + actualMaterials[0].color, + "Colors do not match" + ); + Assert.AreEqual( + skinManager.AnimalMaterials[skinManager.AnimalSkinID].array[0].mainTexture, + actualMaterials[0].mainTexture, + "Main textures do not match" + ); + + yield return null; + } +} diff --git a/Assets/Tests/Playmode/AnimalSkinManagerTests.cs.meta b/Assets/Tests/Playmode/AnimalSkinManagerTests.cs.meta new file mode 100644 index 00000000..75e453a2 --- /dev/null +++ b/Assets/Tests/Playmode/AnimalSkinManagerTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1501979d9c4fd430dae135c0a58dd208 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 3ca155bb14eb8d2cafb98b0933b964df1e9128c1 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 13 Aug 2024 17:11:55 +0100 Subject: [PATCH 171/205] updating method access for testing Also added new tests for decaygoal.cs. --- Assets/Scripts/Rewards/DecayGoal.cs | 21 ++-- Assets/Tests/Playmode/DecayGoalTests.cs | 114 +++++++++++++++++++ Assets/Tests/Playmode/DecayGoalTests.cs.meta | 11 ++ 3 files changed, 137 insertions(+), 9 deletions(-) create mode 100644 Assets/Tests/Playmode/DecayGoalTests.cs create mode 100644 Assets/Tests/Playmode/DecayGoalTests.cs.meta diff --git a/Assets/Scripts/Rewards/DecayGoal.cs b/Assets/Scripts/Rewards/DecayGoal.cs index f59318a0..07cb284c 100644 --- a/Assets/Scripts/Rewards/DecayGoal.cs +++ b/Assets/Scripts/Rewards/DecayGoal.cs @@ -24,11 +24,11 @@ public class DecayGoal : BallGoal private Material _basemat; private Material _radialmat; - private bool isDecaying = false; + public bool isDecaying = false; private float decayWidth; private float loAlpha = 0.11f; private float hiAlpha = 0.35f; - private int delayCounter; + public int delayCounter; public override void SetChangeRate(float v) { @@ -54,7 +54,7 @@ public override void SetDelay(float v) delayCounter = fixedFrameDelay; /* Reset delay counter to new value */ } - private void CheckIfNeedToFlip() + public void CheckIfNeedToFlip() { if (flipDecayDirection ? decayRate < 0 : decayRate > 0) { @@ -142,7 +142,7 @@ void SetEpisodeEnds(bool shouldEpisodeEnd) isMulti = !shouldEpisodeEnd; } - private bool HasFinalDecayBeenReached() + public bool HasFinalDecayBeenReached() { return flipDecayDirection ? reward >= finalReward : reward <= finalReward; } @@ -152,13 +152,16 @@ private bool StillInInitDecayState() return flipDecayDirection ? reward <= initialReward : reward >= initialReward; } - void UpdateGoal(float rate = -0.001f) + public void UpdateGoal(float rate = -0.001f) { + if (!isDecaying) + return; + UpdateValue(rate); UpdateColour(GetProportion(reward)); } - private void UpdateValue(float rate) + public void UpdateValue(float rate) { reward = Mathf.Clamp( reward + rate, @@ -167,7 +170,7 @@ private void UpdateValue(float rate) ); } - private void UpdateColour(float p) + public void UpdateColour(float p) { p = Mathf.Clamp(p, 0, 1); @@ -190,7 +193,7 @@ float GetProportion(float r) : (flipDecayDirection ? 1 : 0); } - void StartDecay(bool reset = false) + public void StartDecay(bool reset = false) { isDecaying = true; if (reset) @@ -199,7 +202,7 @@ void StartDecay(bool reset = false) } } - void StopDecay(bool reset = false) + public void StopDecay(bool reset = false) { isDecaying = false; if (reset) diff --git a/Assets/Tests/Playmode/DecayGoalTests.cs b/Assets/Tests/Playmode/DecayGoalTests.cs new file mode 100644 index 00000000..ddc6dc0f --- /dev/null +++ b/Assets/Tests/Playmode/DecayGoalTests.cs @@ -0,0 +1,114 @@ +using NUnit.Framework; +using UnityEngine; +using UnityEngine.TestTools; +using System.Collections; + +/// +/// Tests for the DecayGoal class. +/// +public class DecayGoalTests +{ + private GameObject _goalObject; + private DecayGoal _decayGoal; + + [SetUp] + public void SetUp() + { + _goalObject = new GameObject("DecayGoal"); + + var meshRenderer = _goalObject.AddComponent(); + + meshRenderer.materials = new Material[3]; + + _decayGoal = _goalObject.AddComponent(); + + /* Set initial values */ + _decayGoal.initialReward = 5.0f; + _decayGoal.finalReward = 0.0f; + _decayGoal.decayRate = -0.1f; + _decayGoal.initialColour = Color.green; + _decayGoal.finalColour = Color.red; + _decayGoal.fixedFrameDelay = 0; + } + + [TearDown] + public void TearDown() + { + Object.Destroy(_goalObject); + } + + [UnityTest] + public IEnumerator TestDecayOverTime() + { + yield return new WaitForSeconds(_decayGoal.fixedFrameDelay * Time.fixedDeltaTime); + + _decayGoal.isDecaying = true; + + for (int i = 0; i < 50; i++) + { + yield return new WaitForFixedUpdate(); + _decayGoal.UpdateGoal(_decayGoal.decayRate); + } + + Assert.Less(_decayGoal.reward, _decayGoal.initialReward); + Assert.GreaterOrEqual(_decayGoal.reward, _decayGoal.finalReward); + } + + [UnityTest] + public IEnumerator TestFinalDecayReached() + { + _decayGoal.isDecaying = true; + + while (!_decayGoal.HasFinalDecayBeenReached()) + { + yield return new WaitForFixedUpdate(); + _decayGoal.UpdateGoal(_decayGoal.decayRate); + } + + Assert.AreEqual(_decayGoal.reward, _decayGoal.finalReward); + } + + [UnityTest] + public IEnumerator TestStopDecay() + { + _decayGoal.initialReward = 1.0f; + _decayGoal.finalReward = 0.0f; + _decayGoal.decayRate = -0.01f; + + _decayGoal.StartDecay(); + + for (int i = 0; i < 50; i++) + { + yield return new WaitForFixedUpdate(); + } + + float rewardBeforeStopping = _decayGoal.reward; + Debug.Log("Reward before stopping decay: " + rewardBeforeStopping); + + _decayGoal.StopDecay(); + + /* Record the reward immediately after stopping decay */ + float rewardAfterStopping = _decayGoal.reward; + Debug.Log("Reward after stopping decay: " + rewardAfterStopping); + + for (int i = 0; i < 50; i++) + { + yield return new WaitForFixedUpdate(); + } + + /* Final reward should be the same as when decay was stopped */ + float finalReward = _decayGoal.reward; + Debug.Log("Final reward after additional updates: " + finalReward); + + Assert.AreEqual( + rewardBeforeStopping, + rewardAfterStopping, + "Reward should not change immediately after stopping decay" + ); + Assert.AreEqual( + rewardAfterStopping, + finalReward, + "Reward should remain constant after decay is stopped" + ); + } +} diff --git a/Assets/Tests/Playmode/DecayGoalTests.cs.meta b/Assets/Tests/Playmode/DecayGoalTests.cs.meta new file mode 100644 index 00000000..b26acd40 --- /dev/null +++ b/Assets/Tests/Playmode/DecayGoalTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: df95c7abd67644059883b682a7ae2657 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 73d57a125856927438db5244a9a55f700da0d34b Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 13 Aug 2024 17:32:19 +0100 Subject: [PATCH 172/205] added tests for deathzone GO --- Assets/Tests/Playmode/DeathZoneTests.cs | 109 +++++++++++++++++++ Assets/Tests/Playmode/DeathZoneTests.cs.meta | 11 ++ 2 files changed, 120 insertions(+) create mode 100644 Assets/Tests/Playmode/DeathZoneTests.cs create mode 100644 Assets/Tests/Playmode/DeathZoneTests.cs.meta diff --git a/Assets/Tests/Playmode/DeathZoneTests.cs b/Assets/Tests/Playmode/DeathZoneTests.cs new file mode 100644 index 00000000..89fd242c --- /dev/null +++ b/Assets/Tests/Playmode/DeathZoneTests.cs @@ -0,0 +1,109 @@ +using NUnit.Framework; +using UnityEngine; +using UnityEngine.TestTools; + +/// +/// Tests for the DeathZone class. +/// +public class DeathZoneTests +{ + private GameObject _deathZoneObject; + private DeathZone _deathZone; + + [SetUp] + public void SetUp() + { + _deathZoneObject = new GameObject("DeathZone"); + + _deathZoneObject.AddComponent(); + _deathZoneObject.AddComponent(); + + _deathZone = _deathZoneObject.AddComponent(); + + _deathZone.sizeMin = new Vector3(1, 1, 1); + _deathZone.sizeMax = new Vector3(10, 10, 10); + _deathZone.sizeAdjustment = 1.0f; + _deathZone.ratioSize = Vector3.one; + } + + [TearDown] + public void TearDown() + { + Object.Destroy(_deathZoneObject); + } + + [Test] + public void TestSetSizeWithinLimits() + { + Vector3 size = new Vector3(5, 5, 5); + _deathZone.SetSize(size); + + /* Check if the scale is set correctly within limits */ + Assert.AreEqual(size, _deathZoneObject.transform.localScale); + } + + [Test] + public void TestSetSizeClipsToMinMax() + { + Vector3 size = new Vector3(15, 15, 15); /* Here, size is above sizeMax */ + _deathZone.SetSize(size); + + /* Expected size should be clipped to sizeMax */ + Vector3 expectedSize = _deathZone.sizeMax; + Assert.AreEqual(expectedSize, _deathZoneObject.transform.localScale); + + size = new Vector3(0.5f, 0.5f, 0.5f); /* Below sizeMin */ + _deathZone.SetSize(size); + + /* Expected size should be clipped to sizeMin */ + expectedSize = _deathZone.sizeMin; + Assert.AreEqual(expectedSize, _deathZoneObject.transform.localScale); + } + + [Test] + public void TestSetSizeWithNegativeValues() + { + Vector3 size = new Vector3(-1, -1, -1); + _deathZone.SetSize(size); + + Assert.GreaterOrEqual(_deathZoneObject.transform.localScale.x, _deathZone.sizeMin.x); + Assert.LessOrEqual(_deathZoneObject.transform.localScale.x, _deathZone.sizeMax.x); + Assert.GreaterOrEqual(_deathZoneObject.transform.localScale.y, _deathZone.sizeMin.y); + Assert.LessOrEqual(_deathZoneObject.transform.localScale.y, _deathZone.sizeMax.y); + Assert.GreaterOrEqual(_deathZoneObject.transform.localScale.z, _deathZone.sizeMin.z); + Assert.LessOrEqual(_deathZoneObject.transform.localScale.z, _deathZone.sizeMax.z); + } + + [Test] + public void TestAdjustY() + { + var deathZoneObject = new GameObject("DeathZone"); + var deathZone = deathZoneObject.AddComponent(); + + float adjustedY = deathZone.TestAdjustY(1.0f); + + Assert.AreEqual(-0.15f, adjustedY); + } + + [Test] + public void TestShaderScaleSet() + { + Vector3 size = new Vector3(5, 5, 5); + _deathZoneObject.AddComponent(); + _deathZone.SetSize(size); + + Vector3 shaderScale = _deathZoneObject + .GetComponent() + .material.GetVector("_ObjScale"); + Assert.AreEqual(size, shaderScale); + } +} + +public class TestableDeathZone : DeathZone +{ + /* Expose AdjustY method for testing. One implementation I found (could be other, better ones) */ + public float TestAdjustY(float y) + { + return AdjustY(y); + } +} diff --git a/Assets/Tests/Playmode/DeathZoneTests.cs.meta b/Assets/Tests/Playmode/DeathZoneTests.cs.meta new file mode 100644 index 00000000..999bc137 --- /dev/null +++ b/Assets/Tests/Playmode/DeathZoneTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 14e3c1601e9f54190b32426de4c82a3a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 65971b90289daa7cbca0ff4ae1be26c94a1ee513 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 13 Aug 2024 18:50:04 +0100 Subject: [PATCH 173/205] test dump for cameracollisions.cs --- .../Playmode/CameraCollisionPlayModeTests.cs | 57 +++++++++++++++++++ .../CameraCollisionPlayModeTests.cs.meta | 11 ++++ 2 files changed, 68 insertions(+) create mode 100644 Assets/Tests/Playmode/CameraCollisionPlayModeTests.cs create mode 100644 Assets/Tests/Playmode/CameraCollisionPlayModeTests.cs.meta diff --git a/Assets/Tests/Playmode/CameraCollisionPlayModeTests.cs b/Assets/Tests/Playmode/CameraCollisionPlayModeTests.cs new file mode 100644 index 00000000..08b43e3b --- /dev/null +++ b/Assets/Tests/Playmode/CameraCollisionPlayModeTests.cs @@ -0,0 +1,57 @@ +using UnityEngine; +using UnityEngine.TestTools; +using NUnit.Framework; +using System.Collections; + +/// +/// Tests for the CameraCollision class. +/// +public class CameraCollisionPlayModeTests +{ + private GameObject _cameraObject; + private CameraCollision _cameraCollision; + private GameObject _cameraParent; + + [SetUp] + public void SetUp() + { + _cameraParent = new GameObject("CameraParent"); + _cameraObject = new GameObject("Camera"); + + _cameraObject.transform.SetParent(_cameraParent.transform); + _cameraObject.transform.localPosition = new Vector3(0, 0, 4); + + _cameraCollision = _cameraObject.AddComponent(); + _cameraCollision.minDistance = 1.0f; + _cameraCollision.maxDistance = 4.0f; + _cameraCollision.smooth = 100.0f; + } + + [UnityTest] + public IEnumerator CameraMovesCloserOnCollision() + { + var blockObject = GameObject.CreatePrimitive(PrimitiveType.Cube); + blockObject.transform.position = new Vector3(0, 0, 2.5f); + + /* Rotate the parent to align with the dollyDir (might be necessary) */ + _cameraParent.transform.rotation = Quaternion.identity; + + yield return new WaitForSeconds(0.5f); /* Give time for the camera to potentially move */ + + Assert.Less(_cameraCollision.distance, 4.0f, "Camera did not move closer after collision."); + } + + [UnityTest] + public IEnumerator CameraMaintainsMaxDistanceWithoutCollision() + { + yield return new WaitForSeconds(0.1f); /* Give time for the camera to potentially move (if it does, it should reset) */ + Assert.AreEqual(_cameraCollision.maxDistance, _cameraCollision.distance); + } + + [TearDown] + public void TearDown() + { + Object.Destroy(_cameraObject); + Object.Destroy(_cameraParent); + } +} diff --git a/Assets/Tests/Playmode/CameraCollisionPlayModeTests.cs.meta b/Assets/Tests/Playmode/CameraCollisionPlayModeTests.cs.meta new file mode 100644 index 00000000..61043a0b --- /dev/null +++ b/Assets/Tests/Playmode/CameraCollisionPlayModeTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7da459ed4b5434144998811841a06306 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 169e4fed74a2dafcb75f529181fbd05054ed6ccb Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 13 Aug 2024 18:56:42 +0100 Subject: [PATCH 174/205] dump old tests for camerafollow.cs after adjustment --- .../Playmode/CameraFollowPlayModeTests.cs | 66 +++++++++++++++++++ .../CameraFollowPlayModeTests.cs.meta | 11 ++++ 2 files changed, 77 insertions(+) create mode 100644 Assets/Tests/Playmode/CameraFollowPlayModeTests.cs create mode 100644 Assets/Tests/Playmode/CameraFollowPlayModeTests.cs.meta diff --git a/Assets/Tests/Playmode/CameraFollowPlayModeTests.cs b/Assets/Tests/Playmode/CameraFollowPlayModeTests.cs new file mode 100644 index 00000000..732f9e18 --- /dev/null +++ b/Assets/Tests/Playmode/CameraFollowPlayModeTests.cs @@ -0,0 +1,66 @@ +using UnityEngine; +using UnityEngine.TestTools; +using NUnit.Framework; +using System.Collections; + +/// +/// Tests for the CameraFollow class. +/// +public class CameraFollowPlayModeTests +{ + private GameObject _cameraObject; + private CameraFollow _cameraFollow; + private GameObject _followedObject; + + [SetUp] + public void SetUp() + { + _cameraObject = new GameObject("Camera"); + _cameraFollow = _cameraObject.AddComponent(); + + _followedObject = new GameObject("FollowedObject"); + _followedObject.transform.position = new Vector3(5, 5, 5); + _followedObject.transform.rotation = Quaternion.Euler(45, 45, 45); + + _cameraFollow.followObj = _followedObject; + } + + [UnityTest] + public IEnumerator CameraFollowsObjectPositionAndRotation() + { + yield return null; + + Assert.AreEqual( + _followedObject.transform.position, + _cameraObject.transform.position, + "Camera did not match the followed object's position." + ); + Assert.AreEqual( + _followedObject.transform.rotation, + _cameraObject.transform.rotation, + "Camera did not match the followed object's rotation." + ); + } + + [UnityTest] + public IEnumerator CameraThrowsExceptionWhenFollowObjIsNull() + { + _cameraFollow.followObj = null; + + LogAssert.Expect( + LogType.Exception, + "MissingReferenceException: The followObj is not assigned." + ); + + yield return null; + + /* Note: the test will pass if the expected exception is thrown */ + } + + [TearDown] + public void TearDown() + { + Object.Destroy(_cameraObject); + Object.Destroy(_followedObject); + } +} diff --git a/Assets/Tests/Playmode/CameraFollowPlayModeTests.cs.meta b/Assets/Tests/Playmode/CameraFollowPlayModeTests.cs.meta new file mode 100644 index 00000000..6e3d9392 --- /dev/null +++ b/Assets/Tests/Playmode/CameraFollowPlayModeTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3227615670f534526b14924c1b46a7da +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 8a00fe48c14c31ac17f8599cf296fb7876c79f40 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 13 Aug 2024 19:06:47 +0100 Subject: [PATCH 175/205] updated code to handle division by 0 case --- Assets/Scripts/ComputeScaleRatios.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Assets/Scripts/ComputeScaleRatios.cs b/Assets/Scripts/ComputeScaleRatios.cs index b17a3f56..ff3ae8e9 100644 --- a/Assets/Scripts/ComputeScaleRatios.cs +++ b/Assets/Scripts/ComputeScaleRatios.cs @@ -15,9 +15,9 @@ void Start() /* Initialize ratioSize with scaleReal to handle potential division by zero */ Vector3 ratioSize = scaleReal; - /* Ensure we're not dividing by zero */ - ratioSize.x = sizeReal.x != 0 ? scaleReal.x / sizeReal.x : 0; - ratioSize.y = sizeReal.y != 0 ? scaleReal.y / sizeReal.y : 0; - ratioSize.z = sizeReal.z != 0 ? scaleReal.z / sizeReal.z : 0; + /* Ensuring we're not dividing by zero, and handling cases where size is zero */ + ratioSize.x = sizeReal.x != 0 ? scaleReal.x / sizeReal.x : float.PositiveInfinity; + ratioSize.y = sizeReal.y != 0 ? scaleReal.y / sizeReal.y : float.PositiveInfinity; + ratioSize.z = sizeReal.z != 0 ? scaleReal.z / sizeReal.z : float.PositiveInfinity; } } From 7a71dd1f42bf687ff930c6281238f0daba41b276 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 13 Aug 2024 19:09:53 +0100 Subject: [PATCH 176/205] adjusted tests for computing scale ratios and dumping tests to unity --- .../ComputeScaleRatiosPlayModeTests.cs | 80 +++++++++++++++++++ .../ComputeScaleRatiosPlayModeTests.cs.meta | 11 +++ 2 files changed, 91 insertions(+) create mode 100644 Assets/Tests/Playmode/ComputeScaleRatiosPlayModeTests.cs create mode 100644 Assets/Tests/Playmode/ComputeScaleRatiosPlayModeTests.cs.meta diff --git a/Assets/Tests/Playmode/ComputeScaleRatiosPlayModeTests.cs b/Assets/Tests/Playmode/ComputeScaleRatiosPlayModeTests.cs new file mode 100644 index 00000000..12b665d6 --- /dev/null +++ b/Assets/Tests/Playmode/ComputeScaleRatiosPlayModeTests.cs @@ -0,0 +1,80 @@ +using UnityEngine; +using UnityEngine.TestTools; +using NUnit.Framework; +using System.Collections; + +/// +/// Tests for the ComputeScaleRatios class. +/// +public class ComputeScaleRatiosPlayModeTests +{ + private GameObject _parentObject; + private ComputeScaleRatios _computeScaleRatios; + private GameObject _childObject; + + [SetUp] + public void SetUp() + { + _parentObject = new GameObject("ParentObject"); + _parentObject.transform.localScale = new Vector3(2, 2, 2); + + var meshFilter = _parentObject.AddComponent(); + meshFilter.mesh = GameObject + .CreatePrimitive(PrimitiveType.Cube) + .GetComponent() + .mesh; + _parentObject.AddComponent(); + + _childObject = GameObject.CreatePrimitive(PrimitiveType.Cube); + _childObject.transform.SetParent(_parentObject.transform); + _childObject.transform.localScale = new Vector3(1, 1, 1); + _childObject.transform.localPosition = Vector3.zero; + + _computeScaleRatios = _parentObject.AddComponent(); + } + + [UnityTest] + public IEnumerator ComputesScaleRatiosCorrectly() + { + yield return null; + + /* Calculate expected ratio values */ + Vector3 expectedSizeReal = _parentObject.GetComponent().bounds.size; + Vector3 expectedScaleReal = _parentObject.transform.localScale; + Vector3 expectedRatioSize = new Vector3( + expectedSizeReal.x != 0 + ? expectedScaleReal.x / expectedSizeReal.x + : float.PositiveInfinity, + expectedSizeReal.y != 0 + ? expectedScaleReal.y / expectedSizeReal.y + : float.PositiveInfinity, + expectedSizeReal.z != 0 + ? expectedScaleReal.z / expectedSizeReal.z + : float.PositiveInfinity + ); + + // A few assertions... + Assert.AreEqual( + expectedRatioSize.x, + expectedScaleReal.x / expectedSizeReal.x, + "Ratio X was not computed correctly." + ); + Assert.AreEqual( + expectedRatioSize.y, + expectedScaleReal.y / expectedSizeReal.y, + "Ratio Y was not computed correctly." + ); + Assert.AreEqual( + expectedRatioSize.z, + expectedScaleReal.z / expectedSizeReal.z, + "Ratio Z was not computed correctly." + ); + } + + [TearDown] + public void TearDown() + { + Object.Destroy(_parentObject); + Object.Destroy(_childObject); + } +} diff --git a/Assets/Tests/Playmode/ComputeScaleRatiosPlayModeTests.cs.meta b/Assets/Tests/Playmode/ComputeScaleRatiosPlayModeTests.cs.meta new file mode 100644 index 00000000..28f696b7 --- /dev/null +++ b/Assets/Tests/Playmode/ComputeScaleRatiosPlayModeTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 92bb4d0cbfbd34eff8fefae9433f379b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 530e03f6798e8b5a4f5e06d5dd9bc7d07864c833 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 13 Aug 2024 19:27:00 +0100 Subject: [PATCH 177/205] Old test dump (prefab.cs) added a few more test units --- Assets/Tests/Playmode/PrefabPlayModeTests.cs | 104 ++++++++++++++++++ .../Playmode/PrefabPlayModeTests.cs.meta | 11 ++ 2 files changed, 115 insertions(+) create mode 100644 Assets/Tests/Playmode/PrefabPlayModeTests.cs create mode 100644 Assets/Tests/Playmode/PrefabPlayModeTests.cs.meta diff --git a/Assets/Tests/Playmode/PrefabPlayModeTests.cs b/Assets/Tests/Playmode/PrefabPlayModeTests.cs new file mode 100644 index 00000000..f9ee6627 --- /dev/null +++ b/Assets/Tests/Playmode/PrefabPlayModeTests.cs @@ -0,0 +1,104 @@ +using UnityEngine; +using UnityEngine.TestTools; +using NUnit.Framework; +using System.Collections; + +/// +/// Tests for the Prefab class. +/// +public class PrefabPlayModeTests +{ + private GameObject _prefabObject; + private Prefab _prefab; + + [SetUp] + public void SetUp() + { + _prefabObject = new GameObject("TestPrefab"); + _prefab = _prefabObject.AddComponent(); + + _prefabObject.AddComponent(); + _prefabObject.AddComponent(); + + /* Default parameters */ + _prefab.sizeMin = new Vector3(1, 1, 1); + _prefab.sizeMax = new Vector3(5, 5, 5); + _prefab.ratioSize = new Vector3(1, 1, 1); + _prefab.rotationRange = new Vector2(0, 360); + _prefab.canRandomizeColor = true; + _prefab.sizeAdjustment = 0.999f; + } + + [UnityTest] + public IEnumerator SetColor_AppliesCorrectColor() + { + Vector3 testColor = new Vector3(255, 0, 0); + _prefab.SetColor(testColor); + + Color appliedColor = _prefabObject.GetComponent().material.color; + + Assert.AreEqual(new Color(1f, 0f, 0f, 1f), appliedColor); + yield return null; + } + + [UnityTest] + public IEnumerator SetSize_AppliesCorrectSize() + { + Vector3 testSize = new Vector3(3, 3, 3); + _prefab.SetSize(testSize); + + /* IMPORTANT ASSERTION: assert that the size was applied correctly, taking ratioSize and sizeAdjustment into account */ + Vector3 expectedSize = new Vector3(3, 3, 3) * _prefab.sizeAdjustment; + Assert.AreEqual(expectedSize, _prefabObject.transform.localScale); + yield return null; + } + + [UnityTest] + public IEnumerator GetRotation_ReturnsCorrectRotation() + { + float testRotationY = 45f; + Vector3 rotation = _prefab.GetRotation(testRotationY); + + Assert.AreEqual(new Vector3(0, 45f, 0), rotation); + yield return null; + } + + [UnityTest] + public IEnumerator SetDelay_LogsCorrectValue() + { + LogAssert.Expect(LogType.Log, "Void SetDelay(Single) activated in Prefab with value 5"); + + _prefab.SetDelay(5f); + yield return null; + } + + [UnityTest] + public IEnumerator SetInitialValue_LogsCorrectValue() + { + LogAssert.Expect( + LogType.Log, + "Void SetInitialValue(Single) activated in Prefab with value 10" + ); + + _prefab.SetInitialValue(10f); + yield return null; + } + + [UnityTest] + public IEnumerator SetFinalValue_LogsCorrectValue() + { + LogAssert.Expect( + LogType.Log, + "Void SetFinalValue(Single) activated in Prefab with value 15" + ); + + _prefab.SetFinalValue(15f); + yield return null; + } + + [TearDown] + public void TearDown() + { + Object.Destroy(_prefabObject); + } +} diff --git a/Assets/Tests/Playmode/PrefabPlayModeTests.cs.meta b/Assets/Tests/Playmode/PrefabPlayModeTests.cs.meta new file mode 100644 index 00000000..5de47d34 --- /dev/null +++ b/Assets/Tests/Playmode/PrefabPlayModeTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4a887797d10b342b7b5056568f2adae0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 50aa0d8ad3c73deea1ab90b1a506225122bc3f05 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Tue, 13 Aug 2024 19:33:29 +0100 Subject: [PATCH 178/205] removed instances and references to yaml file name var no longer going to be implemented --- Assets/Scripts/AAI3EnvironmentManager.cs | 5 ----- Assets/Scripts/ArenasParametersSideChannel.cs | 12 +----------- Assets/Scripts/TrainingAgent.cs | 2 +- 3 files changed, 2 insertions(+), 17 deletions(-) diff --git a/Assets/Scripts/AAI3EnvironmentManager.cs b/Assets/Scripts/AAI3EnvironmentManager.cs index 67b66e13..7fee8983 100644 --- a/Assets/Scripts/AAI3EnvironmentManager.cs +++ b/Assets/Scripts/AAI3EnvironmentManager.cs @@ -149,11 +149,6 @@ public void Awake() _instantiatedArena._agent.gameObject.SetActive(true); } - public string GetCurrentYamlFileName() - { - return _arenasParametersSideChannel.CurrentYamlFileName; - } - private void InitialiseSideChannel() { _arenasConfigurations = new ArenasConfigurations(); diff --git a/Assets/Scripts/ArenasParametersSideChannel.cs b/Assets/Scripts/ArenasParametersSideChannel.cs index f4b58a39..ec727f04 100644 --- a/Assets/Scripts/ArenasParametersSideChannel.cs +++ b/Assets/Scripts/ArenasParametersSideChannel.cs @@ -8,8 +8,6 @@ /// public class ArenasParametersSideChannel : SideChannel { - public string CurrentYamlFileName { get; private set; } - /// /// Initializes a new instance of the ArenasParametersSideChannel class. /// @@ -23,18 +21,10 @@ public ArenasParametersSideChannel() /// protected override void OnMessageReceived(IncomingMessage msg) { - string fileName = msg.ReadString(); byte[] yamlData = msg.GetRawBytes(); - Debug.Log($"Received YAML file name: {fileName}"); - CurrentYamlFileName = fileName; - /* Create the event args including the file name and the YAML data */ - ArenasParametersEventArgs args = new ArenasParametersEventArgs - { - arenas_yaml = yamlData, - yamlFileName = fileName - }; + ArenasParametersEventArgs args = new ArenasParametersEventArgs { arenas_yaml = yamlData, }; OnArenasParametersReceived(args); } diff --git a/Assets/Scripts/TrainingAgent.cs b/Assets/Scripts/TrainingAgent.cs index 573873d6..62b7f7e1 100644 --- a/Assets/Scripts/TrainingAgent.cs +++ b/Assets/Scripts/TrainingAgent.cs @@ -416,7 +416,7 @@ private void InitialiseCSVProcess() Directory.CreateDirectory(directoryPath); } - /* Generate a filename with the YAML file name and a date stamp to prevent overwriting. */ + /* Generate a filename with a date stamp to prevent overwriting */ string dateTimeString = DateTime.Now.ToString("dd-MM-yy_HHmm"); string filename = $"Observations_{dateTimeString}.csv"; csvFilePath = Path.Combine(directoryPath, filename); From a6c7aaf693ba97c000b76758f9531d99345a20f4 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 14 Aug 2024 12:32:59 +0100 Subject: [PATCH 179/205] updated minor packages in unity --- Packages/manifest.json | 10 +++++----- Packages/packages-lock.json | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Packages/manifest.json b/Packages/manifest.json index 09e0cb0f..a1eeaeef 100644 --- a/Packages/manifest.json +++ b/Packages/manifest.json @@ -1,15 +1,15 @@ { "dependencies": { "com.unity.collab-proxy": "2.1.0", - "com.unity.ide.rider": "3.0.18", - "com.unity.ide.visualstudio": "2.0.17", + "com.unity.ide.rider": "3.0.31", + "com.unity.ide.visualstudio": "2.0.22", "com.unity.ide.vscode": "1.2.5", "com.unity.ml-agents": "2.3.0-exp.3", - "com.unity.recorder": "3.0.3", + "com.unity.recorder": "3.0.4", "com.unity.render-pipelines.universal": "12.1.10", "com.unity.test-framework": "1.1.33", - "com.unity.textmeshpro": "3.0.6", - "com.unity.timeline": "1.6.4", + "com.unity.textmeshpro": "3.0.9", + "com.unity.timeline": "1.6.5", "com.unity.toolchain.linux-x86_64": "0.1.18-preview", "com.unity.toolchain.win-x86_64-linux-x86_64": "0.1.19-preview", "com.unity.ugui": "1.0.0", diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json index c0a3275b..25e67563 100644 --- a/Packages/packages-lock.json +++ b/Packages/packages-lock.json @@ -35,7 +35,7 @@ "url": "https://packages.unity.com" }, "com.unity.ide.rider": { - "version": "3.0.18", + "version": "3.0.31", "depth": 0, "source": "registry", "dependencies": { @@ -44,7 +44,7 @@ "url": "https://packages.unity.com" }, "com.unity.ide.visualstudio": { - "version": "2.0.17", + "version": "2.0.22", "depth": 0, "source": "registry", "dependencies": { @@ -78,7 +78,7 @@ "url": "https://packages.unity.com" }, "com.unity.recorder": { - "version": "3.0.3", + "version": "3.0.4", "depth": 0, "source": "registry", "dependencies": { @@ -151,7 +151,7 @@ "url": "https://packages.unity.com" }, "com.unity.textmeshpro": { - "version": "3.0.6", + "version": "3.0.9", "depth": 0, "source": "registry", "dependencies": { @@ -160,7 +160,7 @@ "url": "https://packages.unity.com" }, "com.unity.timeline": { - "version": "1.6.4", + "version": "1.6.5", "depth": 0, "source": "registry", "dependencies": { From 28f5cdfd11038e7cf300b65d6e052f1981412d45 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 14 Aug 2024 13:39:37 +0100 Subject: [PATCH 180/205] written new tests for sizechangegoal.cs needs more test units though... --- Assets/Scripts/Rewards/SizeChangeGoal.cs | 2 +- Assets/Tests/Playmode/SizeChangeGoalTests.cs | 55 +++++++++++++++++++ .../Playmode/SizeChangeGoalTests.cs.meta | 11 ++++ 3 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 Assets/Tests/Playmode/SizeChangeGoalTests.cs create mode 100644 Assets/Tests/Playmode/SizeChangeGoalTests.cs.meta diff --git a/Assets/Scripts/Rewards/SizeChangeGoal.cs b/Assets/Scripts/Rewards/SizeChangeGoal.cs index d866b1d1..59dbd06d 100644 --- a/Assets/Scripts/Rewards/SizeChangeGoal.cs +++ b/Assets/Scripts/Rewards/SizeChangeGoal.cs @@ -36,7 +36,7 @@ private void Awake() InitializeValues(); } - private void InitializeValues() + public void InitializeValues() { delayCounter = fixedFrameDelay; initialSize = Mathf.Clamp(initialSize, 0, sizeMax.x); diff --git a/Assets/Tests/Playmode/SizeChangeGoalTests.cs b/Assets/Tests/Playmode/SizeChangeGoalTests.cs new file mode 100644 index 00000000..1b58ccf6 --- /dev/null +++ b/Assets/Tests/Playmode/SizeChangeGoalTests.cs @@ -0,0 +1,55 @@ +using System.Collections; +using NUnit.Framework; +using UnityEngine; +using UnityEngine.TestTools; + +/// +/// Tests for the SizeChangeGoal class. +/// Note: needs more tests to cover all cases. +/// +public class SizeChangeGoalTests +{ + private GameObject gameObject; + private SizeChangeGoal sizeChangeGoal; + + [SetUp] + public void Setup() + { + gameObject = new GameObject(); + sizeChangeGoal = gameObject.AddComponent(); + + sizeChangeGoal.initialSize = 5f; + sizeChangeGoal.finalSize = 1f; + sizeChangeGoal.sizeChangeRate = -0.1f; + + sizeChangeGoal.sizeMin = new Vector3(1f, 1f, 1f); + sizeChangeGoal.sizeMax = new Vector3(5f, 5f, 5f); + + sizeChangeGoal.fixedFrameDelay = 5; + + sizeChangeGoal.InitializeValues(); + sizeChangeGoal.SetSize(sizeChangeGoal.initialSize * Vector3.one); + } + + [TearDown] + public void Teardown() + { + Object.Destroy(sizeChangeGoal); + Object.Destroy(gameObject); + Debug.Log("SizeChangeGoal destroyed"); + } + + [UnityTest] + public IEnumerator VerifySizeChangeOverTime() + { + yield return new WaitForSeconds(0.1f); + + yield return new WaitForSeconds(1.5f); + + Assert.Less( + sizeChangeGoal.transform.localScale.x, + 5f, + "Scale should have decreased after delayCounter reached zero." + ); + } +} diff --git a/Assets/Tests/Playmode/SizeChangeGoalTests.cs.meta b/Assets/Tests/Playmode/SizeChangeGoalTests.cs.meta new file mode 100644 index 00000000..f716f071 --- /dev/null +++ b/Assets/Tests/Playmode/SizeChangeGoalTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c481594355ea44d22b698afc0ac05c20 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From e41a8a037a892f0c2223af78dd1dfc3dd506fdf1 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 14 Aug 2024 13:50:10 +0100 Subject: [PATCH 181/205] added initial test on yaml reader. --- Assets/Tests/EditMode/YAMLReaderTests.cs | 19 +++++++++++++++++++ Assets/Tests/EditMode/YAMLReaderTests.cs.meta | 11 +++++++++++ 2 files changed, 30 insertions(+) create mode 100644 Assets/Tests/EditMode/YAMLReaderTests.cs create mode 100644 Assets/Tests/EditMode/YAMLReaderTests.cs.meta diff --git a/Assets/Tests/EditMode/YAMLReaderTests.cs b/Assets/Tests/EditMode/YAMLReaderTests.cs new file mode 100644 index 00000000..6307f24a --- /dev/null +++ b/Assets/Tests/EditMode/YAMLReaderTests.cs @@ -0,0 +1,19 @@ +using NUnit.Framework; +using UnityEngine; +using YAMLDefs; +using System.Collections.Generic; + +/// +/// Tests for the YAMLReader class. +/// Currently only tests the Setup method. +/// +public class YAMLReaderTests +{ + private YAMLReader yamlReader; + + [SetUp] + public void Setup() + { + yamlReader = new YAMLReader(); + } +} diff --git a/Assets/Tests/EditMode/YAMLReaderTests.cs.meta b/Assets/Tests/EditMode/YAMLReaderTests.cs.meta new file mode 100644 index 00000000..a6330d2e --- /dev/null +++ b/Assets/Tests/EditMode/YAMLReaderTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c54cd5810d2614a8eaccf008260a3e31 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From c6001966270f63611230d447eec702e72ba9ba7b Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 14 Aug 2024 15:02:07 +0100 Subject: [PATCH 182/205] added full list of tests --- Assets/Tests/EditMode/YAMLReaderTests.cs | 275 ++++++++++++++++++++++- 1 file changed, 273 insertions(+), 2 deletions(-) diff --git a/Assets/Tests/EditMode/YAMLReaderTests.cs b/Assets/Tests/EditMode/YAMLReaderTests.cs index 6307f24a..14eeccee 100644 --- a/Assets/Tests/EditMode/YAMLReaderTests.cs +++ b/Assets/Tests/EditMode/YAMLReaderTests.cs @@ -4,8 +4,7 @@ using System.Collections.Generic; /// -/// Tests for the YAMLReader class. -/// Currently only tests the Setup method. +/// Tests for the YAMLReader class. These tests are comprehensive and cover a wide range of scenarios. /// public class YAMLReaderTests { @@ -16,4 +15,276 @@ public void Setup() { yamlReader = new YAMLReader(); } + + [Test] + public void DeserializeArenaConfig_WithEmptyItemsList_DeserializesCorrectly() + { + string yaml = + @" + !ArenaConfig + arenas: + 0: !Arena + passMark: 0.5 + timeLimit: 120"; + + ArenaConfig arenaConfig = yamlReader.deserializer.Deserialize(yaml); + + Assert.NotNull(arenaConfig); + Assert.AreEqual(1, arenaConfig.arenas.Count, "There should be 1 arena in the config."); + + Arena arena = arenaConfig.arenas[0]; + Assert.AreEqual(0.5f, arena.passMark, "Pass mark should be 0.5."); + Assert.AreEqual(120, arena.timeLimit, "Time limit should be 120."); + Assert.AreEqual(0, arena.items.Count, "There should be no items in this arena."); + } + + [Test] + public void DeserializeArenaConfig_WithMultipleItemsAndProperties_DeserializesCorrectly() + { + string yaml = + @" + !ArenaConfig + arenas: + 0: !Arena + passMark: 0.75 + timeLimit: 150 + items: + - !Item + name: ComplexItem + positions: + - !Vector3 {x: 10, y: 20, z: 30} + rotations: [45, 90] + sizes: + - !Vector3 {x: 2, y: 2, z: 2} + colors: + - !RGB {r: 0.5, g: 0.5, b: 0.5} + - !Item + name: SimpleItem + positions: + - !Vector3 {x: 5, y: 5, z: 5} + sizes: + - !Vector3 {x: 1, y: 1, z: 1} + colors: + - !RGB {r: 1, g: 0, b: 0}"; + + ArenaConfig arenaConfig = yamlReader.deserializer.Deserialize(yaml); + + Assert.NotNull(arenaConfig); + Assert.AreEqual(1, arenaConfig.arenas.Count, "There should be 1 arena in the config."); + + Arena arena = arenaConfig.arenas[0]; + Assert.AreEqual(0.75f, arena.passMark, "Pass mark should be 0.75."); + Assert.AreEqual(150, arena.timeLimit, "Time limit should be 150."); + Assert.AreEqual(2, arena.items.Count, "There should be 2 items in this arena."); + + Item complexItem = arena.items[0]; + Assert.AreEqual("ComplexItem", complexItem.name); + Assert.AreEqual(new Vector3(10, 20, 30), complexItem.positions[0]); + Assert.AreEqual(2, complexItem.rotations.Count); + Assert.AreEqual(45f, complexItem.rotations[0]); + Assert.AreEqual(90f, complexItem.rotations[1]); + Assert.AreEqual(new Vector3(2, 2, 2), complexItem.sizes[0]); + Assert.AreEqual( + new Color(0.5f, 0.5f, 0.5f), + new Color(complexItem.colors[0].r, complexItem.colors[0].g, complexItem.colors[0].b) + ); + + Item simpleItem = arena.items[1]; + Assert.AreEqual("SimpleItem", simpleItem.name); + Assert.AreEqual(new Vector3(5, 5, 5), simpleItem.positions[0]); + Assert.AreEqual(new Vector3(1, 1, 1), simpleItem.sizes[0]); + Assert.AreEqual( + new Color(1f, 0f, 0f), + new Color(simpleItem.colors[0].r, simpleItem.colors[0].g, simpleItem.colors[0].b) + ); + } + + [Test] + public void DeserializeArenaConfig_WithMissingOptionalFields_HandlesGracefully() + { + string yaml = + @" + !ArenaConfig + arenas: + 0: !Arena + timeLimit: 200 + items: + - !Item + name: TestItem + positions: + - !Vector3 {x: 1, y: 1, z: 1}"; + + ArenaConfig arenaConfig = yamlReader.deserializer.Deserialize(yaml); + + Assert.NotNull(arenaConfig); + Assert.AreEqual(1, arenaConfig.arenas.Count, "There should be 1 arena in the config."); + + Arena arena = arenaConfig.arenas[0]; + Assert.AreEqual(200, arena.timeLimit, "Time limit should be 200."); + Assert.AreEqual(1, arena.items.Count, "There should be 1 item in this arena."); + + Item testItem = arena.items[0]; + Assert.AreEqual("TestItem", testItem.name); + Assert.AreEqual(new Vector3(1, 1, 1), testItem.positions[0]); + + Assert.AreEqual(0, testItem.rotations.Count, "Rotations list should be empty."); + Assert.AreEqual(0, testItem.sizes.Count, "Sizes list should be empty."); + Assert.AreEqual(0, testItem.colors.Count, "Colors list should be empty."); + Assert.AreEqual(0, testItem.skins.Count, "Skins list should be empty."); + Assert.AreEqual(0, testItem.symbolNames.Count, "Symbol names list should be empty."); + } + + [Test] + public void DeserializeArenaConfig_WithInvalidYaml_ThrowsException() + { + string yaml = + @" + !ArenaConfig + arenas: + 0: !Arena + timeLimit: 100 + items: + - !Item + name: InvalidItem + positions: + - !Vector3 {x: 10, y: 0 z: 20} # Missing comma in Vector3"; + + /* Expecting a SemanticErrorException due to invalid YAML content */ + Assert.Throws(() => + { + yamlReader.deserializer.Deserialize(yaml); + }); + } + + [Test] + public void DeserializeArenaConfig_WithAliasMapping_CorrectlyResolvesAliases() + { + string yaml = + @" + !ArenaConfig + arenas: + 0: !Arena + items: + - !Item + name: Cardbox1 + positions: + - !Vector3 {x: 10, y: 0, z: 20}"; + + ArenaConfig arenaConfig = yamlReader.deserializer.Deserialize(yaml); + + Assert.NotNull(arenaConfig); + Assert.AreEqual(1, arenaConfig.arenas.Count, "There should be 1 arena in the config."); + + Arena arena = arenaConfig.arenas[0]; + Assert.AreEqual(1, arena.items.Count, "There should be 1 item in this arena."); + + Item mappedItem = arena.items[0]; + Assert.AreEqual( + "LightBlock", + AliasMapper.ResolveAlias(mappedItem.name), + "Alias should be resolved to 'LightBlock'." + ); + } + + [Test] + public void DeserializeArenaConfig_WithEmptyArenaList_DeserializesCorrectly() + { + /* YAML input with no arenas */ + string yaml = + @" + !ArenaConfig + arenas: {}"; + + ArenaConfig arenaConfig = yamlReader.deserializer.Deserialize(yaml); + + Assert.NotNull(arenaConfig); + Assert.AreEqual(0, arenaConfig.arenas.Count, "There should be no arenas in the config."); + } + + [Test] + public void DeserializeArenaConfig_WithCustomColorValues_DeserializesCorrectly() + { + string yaml = + @" + !ArenaConfig + arenas: + 0: !Arena + items: + - !Item + name: ColorItem + positions: + - !Vector3 {x: 10, y: 0, z: 10} + colors: + - !RGB {r: 0.2, g: 0.4, b: 0.6}"; + + ArenaConfig arenaConfig = yamlReader.deserializer.Deserialize(yaml); + + Assert.NotNull(arenaConfig); + Assert.AreEqual(1, arenaConfig.arenas.Count, "There should be 1 arena in the config."); + + Arena arena = arenaConfig.arenas[0]; + Assert.AreEqual(1, arena.items.Count, "There should be 1 item in this arena."); + + Item colorItem = arena.items[0]; + Assert.AreEqual("ColorItem", colorItem.name); + Assert.AreEqual( + new Color(0.2f, 0.4f, 0.6f), + new Color(colorItem.colors[0].r, colorItem.colors[0].g, colorItem.colors[0].b), + "RGB color should be correctly deserialized." + ); + } + + [Test] + public void DeserializeArenaConfig_WithMultipleArenasAndSharedItems_DeserializesCorrectly() + { + string yaml = + @" + !ArenaConfig + arenas: + 0: !Arena + passMark: 0.5 + timeLimit: 100 + items: + - !Item + name: Goal + positions: + - !Vector3 {x: 15, y: 0, z: 15} + sizes: + - !Vector3 {x: 3, y: 3, z: 3} + 1: !Arena + passMark: 0.75 + timeLimit: 200 + items: + - !Item + name: Goal + positions: + - !Vector3 {x: 20, y: 0, z: 20} + sizes: + - !Vector3 {x: 5, y: 5, z: 5}"; + + ArenaConfig arenaConfig = yamlReader.deserializer.Deserialize(yaml); + + Assert.NotNull(arenaConfig); + Assert.AreEqual(2, arenaConfig.arenas.Count, "There should be 2 arenas in the config."); + + Arena arena0 = arenaConfig.arenas[0]; + Assert.AreEqual(0.5f, arena0.passMark, "Pass mark for Arena 0 should be 0.5."); + Assert.AreEqual(100, arena0.timeLimit, "Time limit for Arena 0 should be 100."); + Assert.AreEqual(1, arena0.items.Count, "Arena 0 should have 1 item."); + + Item goalItem0 = arena0.items[0]; + Assert.AreEqual("Goal", goalItem0.name); + Assert.AreEqual(new Vector3(15, 0, 15), goalItem0.positions[0]); + Assert.AreEqual(new Vector3(3, 3, 3), goalItem0.sizes[0]); + + Arena arena1 = arenaConfig.arenas[1]; + Assert.AreEqual(0.75f, arena1.passMark, "Pass mark for Arena 1 should be 0.75."); + Assert.AreEqual(200, arena1.timeLimit, "Time limit for Arena 1 should be 200."); + Assert.AreEqual(1, arena1.items.Count, "Arena 1 should have 1 item."); + + Item goalItem1 = arena1.items[0]; + Assert.AreEqual("Goal", goalItem1.name); + Assert.AreEqual(new Vector3(20, 0, 20), goalItem1.positions[0]); + Assert.AreEqual(new Vector3(5, 5, 5), goalItem1.sizes[0]); + } } From ef15dea46b75a5d9847b4366b23835775aa249fe Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Wed, 14 Aug 2024 17:56:15 +0100 Subject: [PATCH 183/205] added tests for checking sidechannel comms --- .../ArenasParametersSideChannelTests.cs | 53 +++++++++++++++++++ .../ArenasParametersSideChannelTests.cs.meta | 11 ++++ 2 files changed, 64 insertions(+) create mode 100644 Assets/Tests/EditMode/ArenasParametersSideChannelTests.cs create mode 100644 Assets/Tests/EditMode/ArenasParametersSideChannelTests.cs.meta diff --git a/Assets/Tests/EditMode/ArenasParametersSideChannelTests.cs b/Assets/Tests/EditMode/ArenasParametersSideChannelTests.cs new file mode 100644 index 00000000..f2ddf69a --- /dev/null +++ b/Assets/Tests/EditMode/ArenasParametersSideChannelTests.cs @@ -0,0 +1,53 @@ +using NUnit.Framework; +using Unity.MLAgents.SideChannels; +using ArenasParameters; +using System; +using UnityEngine; + +/// +/// Tests for the ArenasParametersSideChannel class. +/// +public class ArenasParametersSideChannelTests +{ + private TestableArenasParametersSideChannel sideChannel; + private bool eventTriggered; + private ArenasParametersEventArgs receivedArgs; + + [SetUp] + public void Setup() + { + sideChannel = new TestableArenasParametersSideChannel(); + + sideChannel.NewArenasParametersReceived += (sender, args) => + { + eventTriggered = true; + receivedArgs = args; + }; + } + + [Test] + public void ArenasParametersSideChannel_OnMessageReceived_TriggersEvent() + { + byte[] mockYamlData = new byte[] { 1, 2, 3, 4 }; /* Basic byte array */ + var incomingMessage = new IncomingMessage(mockYamlData); + + sideChannel.TestOnMessageReceived(incomingMessage); + + Assert.IsTrue(eventTriggered, "Event was not triggered"); + + Assert.AreEqual( + mockYamlData, + receivedArgs.arenas_yaml, + "The received YAML data does not match the expected data" + ); + } + + /* Subclass to expose the protected OnMessageReceived method */ + private class TestableArenasParametersSideChannel : ArenasParametersSideChannel + { + public void TestOnMessageReceived(IncomingMessage msg) + { + OnMessageReceived(msg); + } + } +} diff --git a/Assets/Tests/EditMode/ArenasParametersSideChannelTests.cs.meta b/Assets/Tests/EditMode/ArenasParametersSideChannelTests.cs.meta new file mode 100644 index 00000000..dd86d42c --- /dev/null +++ b/Assets/Tests/EditMode/ArenasParametersSideChannelTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 08ed07dc0f59e4f1a93846eff8b9fb7c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 6cdefdfdf4d9ccd580c3bae67bb66f32f7b63f7b Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Thu, 15 Aug 2024 15:48:03 +0100 Subject: [PATCH 184/205] added tests for AAIEnvironmentManager.cs initial batch, needs more tests to cover all functionalities. --- .../EditMode/AAI3EnvironmentManagerTests.cs | 92 +++++++++++++++++++ .../AAI3EnvironmentManagerTests.cs.meta | 11 +++ 2 files changed, 103 insertions(+) create mode 100644 Assets/Tests/EditMode/AAI3EnvironmentManagerTests.cs create mode 100644 Assets/Tests/EditMode/AAI3EnvironmentManagerTests.cs.meta diff --git a/Assets/Tests/EditMode/AAI3EnvironmentManagerTests.cs b/Assets/Tests/EditMode/AAI3EnvironmentManagerTests.cs new file mode 100644 index 00000000..1f0d6c3d --- /dev/null +++ b/Assets/Tests/EditMode/AAI3EnvironmentManagerTests.cs @@ -0,0 +1,92 @@ +using NUnit.Framework; +using UnityEngine; +using UnityEngine.TestTools; +using System.Collections.Generic; +using Unity.MLAgents; +using Unity.MLAgents.Sensors; +using Unity.MLAgents.SideChannels; +using Unity.MLAgents.Policies; + +/// +/// Tests for the AAI3EnvironmentManager class. +/// +[TestFixture] +public class AAI3EnvironmentManagerTests +{ + private GameObject _gameObject; + private AAI3EnvironmentManager _environmentManager; + private TrainingArena _trainingArena; + private Agent _agent; + private DecisionRequester _decisionRequester; + private RayPerceptionSensorComponent3D _raySensor; + private CameraSensorComponent _cameraSensor; + private BehaviorParameters _behaviorParameters; + private Canvas _canvas; + + [SetUp] + public void SetUp() + { + _gameObject = new GameObject(); + _environmentManager = _gameObject.AddComponent(); + + _trainingArena = new GameObject().AddComponent(); + _agent = new GameObject().AddComponent(); + _decisionRequester = _agent.gameObject.AddComponent(); + _raySensor = _agent.gameObject.AddComponent(); + _cameraSensor = _agent.gameObject.AddComponent(); + _behaviorParameters = _agent.gameObject.AddComponent(); + _canvas = new GameObject().AddComponent(); + + _environmentManager.arena = _trainingArena.gameObject; + _environmentManager.uiCanvas = _canvas.gameObject; + _environmentManager.playerControls = new GameObject(); + } + + + [Test] + public void AAI3EnvironmentManager_RetrieveEnvironmentParameters_WorksCorrectly() + { + string[] args = { "--playerMode", "1", "--useCamera", "1", "--resolution", "84" }; + var parameters = _environmentManager.RetrieveEnvironmentParameters(args); + Assert.IsTrue(parameters.ContainsKey("playerMode")); + Assert.AreEqual("1", parameters["playerMode"].ToString()); + Assert.AreEqual("1", parameters["useCamera"].ToString()); + Assert.AreEqual("84", parameters["resolution"].ToString()); + } + + [Test] + public void AAI3EnvironmentManager_RetrieveEnvironmentParameters_HandlesMissingArgs() + { + string[] args = { "--playerMode", "1" }; + var parameters = _environmentManager.RetrieveEnvironmentParameters(args); + Assert.IsTrue(parameters.ContainsKey("playerMode")); + Assert.AreEqual("1", parameters["playerMode"].ToString()); + Assert.IsFalse(parameters.ContainsKey("useCamera")); + Assert.IsFalse(parameters.ContainsKey("resolution")); + } + + [Test] + public void AAI3EnvironmentManager_ChangeResolution_HandlesDifferentResolutions() + { + _environmentManager.ChangeResolution(_cameraSensor, 256, 256, false); + Assert.AreEqual(256, _cameraSensor.Width); + Assert.AreEqual(256, _cameraSensor.Height); + Assert.IsFalse(_cameraSensor.Grayscale); + } + + [Test] + public void AAI3EnvironmentManager_ChangeRayCasts_WorksCorrectly() + { + _environmentManager.ChangeRayCasts(_raySensor, 4, 90); + Assert.AreEqual(4, _raySensor.RaysPerDirection); + Assert.AreEqual(90, _raySensor.MaxRayDegrees); + } + + [Test] + public void AAI3EnvironmentManager_ChangeRayCasts_HandlesDifferentSettings() + { + _environmentManager.ChangeRayCasts(_raySensor, 8, 180); + Assert.AreEqual(8, _raySensor.RaysPerDirection); + Assert.AreEqual(180, _raySensor.MaxRayDegrees); + } +} diff --git a/Assets/Tests/EditMode/AAI3EnvironmentManagerTests.cs.meta b/Assets/Tests/EditMode/AAI3EnvironmentManagerTests.cs.meta new file mode 100644 index 00000000..77bd4b41 --- /dev/null +++ b/Assets/Tests/EditMode/AAI3EnvironmentManagerTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a18d4edd9d21f42c0aef3153fbb03972 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 8d12abfc44510cc63a36d54f00a0f527ede0c3d5 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Thu, 15 Aug 2024 18:17:17 +0100 Subject: [PATCH 185/205] added further test units more incoming... --- .../EditMode/AAI3EnvironmentManagerTests.cs | 60 ++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/Assets/Tests/EditMode/AAI3EnvironmentManagerTests.cs b/Assets/Tests/EditMode/AAI3EnvironmentManagerTests.cs index 1f0d6c3d..64dee996 100644 --- a/Assets/Tests/EditMode/AAI3EnvironmentManagerTests.cs +++ b/Assets/Tests/EditMode/AAI3EnvironmentManagerTests.cs @@ -6,6 +6,7 @@ using Unity.MLAgents.Sensors; using Unity.MLAgents.SideChannels; using Unity.MLAgents.Policies; +using ArenasParameters; /// /// Tests for the AAI3EnvironmentManager class. @@ -40,8 +41,9 @@ public void SetUp() _environmentManager.arena = _trainingArena.gameObject; _environmentManager.uiCanvas = _canvas.gameObject; _environmentManager.playerControls = new GameObject(); - } + _environmentManager._arenasConfigurations = new ArenasConfigurations(); + } [Test] public void AAI3EnvironmentManager_RetrieveEnvironmentParameters_WorksCorrectly() @@ -89,4 +91,60 @@ public void AAI3EnvironmentManager_ChangeRayCasts_HandlesDifferentSettings() Assert.AreEqual(8, _raySensor.RaysPerDirection); Assert.AreEqual(180, _raySensor.MaxRayDegrees); } + + [Test] + public void AAI3EnvironmentManager_InstantiateArenas_CreatesArenaInstance() + { + _environmentManager.InstantiateArenas(); + Assert.IsNotNull(_environmentManager.arena); + Assert.IsInstanceOf(_environmentManager.arena.GetComponent()); + } + + [Test] + public void AAI3EnvironmentManager_LoadYAMLFileInEditor_WarnsIfConfigFileIsEmpty() + { + _environmentManager.configFile = string.Empty; + LogAssert.Expect(LogType.Warning, "Config file path is null or empty."); + _environmentManager.LoadYAMLFileInEditor(); + } + + [Test] + public void AAI3EnvironmentManager_LoadYAMLFileInEditor_HandlesMissingFile() + { + _environmentManager.configFile = "NonExistentFile"; + LogAssert.Expect( + LogType.Warning, + "YAML file 'NonExistentFile' could not be found or loaded." + ); + _environmentManager.LoadYAMLFileInEditor(); + } + + [Test] + public void AAI3EnvironmentManager_GetConfiguration_ThrowsExceptionWhenArenaIDNotFound() + { + Assert.Throws(() => _environmentManager.GetConfiguration(999)); + } + + [Test] + public void AAI3EnvironmentManager_GetConfiguration_ReturnsCorrectConfiguration() + { + var config = new ArenaConfiguration(); + _environmentManager.AddConfiguration(1, config); + var retrievedConfig = _environmentManager.GetConfiguration(1); + Assert.AreSame(config, retrievedConfig); + } + + [Test] + public void AAI3EnvironmentManager_TriggerArenaChangeEvent_InvokesEventCorrectly() + { + bool eventTriggered = false; + AAI3EnvironmentManager.OnArenaChanged += (currentArenaIndex, totalArenas) => + eventTriggered = true; + + _environmentManager.TriggerArenaChangeEvent(0, 1); + Assert.IsTrue(eventTriggered); + + AAI3EnvironmentManager.OnArenaChanged -= (currentArenaIndex, totalArenas) => + eventTriggered = true; + } } From 787b7a59a566a6a2ae03ce3085806e4dd6ede5a2 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Thu, 15 Aug 2024 18:27:22 +0100 Subject: [PATCH 186/205] added the rest of the test units after analysis --- .../EditMode/AAI3EnvironmentManagerTests.cs | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/Assets/Tests/EditMode/AAI3EnvironmentManagerTests.cs b/Assets/Tests/EditMode/AAI3EnvironmentManagerTests.cs index 64dee996..b045bb84 100644 --- a/Assets/Tests/EditMode/AAI3EnvironmentManagerTests.cs +++ b/Assets/Tests/EditMode/AAI3EnvironmentManagerTests.cs @@ -7,6 +7,7 @@ using Unity.MLAgents.SideChannels; using Unity.MLAgents.Policies; using ArenasParameters; +using YamlDotNet.Serialization; /// /// Tests for the AAI3EnvironmentManager class. @@ -45,6 +46,59 @@ public void SetUp() _environmentManager._arenasConfigurations = new ArenasConfigurations(); } + [Test] + public void AAI3EnvironmentManager_RetrieveEnvironmentParameters_HandlesInvalidArgsGracefully() + { + string[] args = { "--invalidArgument", "someValue" }; + var parameters = _environmentManager.RetrieveEnvironmentParameters(args); + + Assert.IsFalse(parameters.ContainsKey("invalidArgument")); + } + + [Test] + public void AAI3EnvironmentManager_GetTotalArenas_ReturnsCorrectCount() + { + _environmentManager.AddConfiguration(0, new ArenaConfiguration()); + _environmentManager.AddConfiguration(1, new ArenaConfiguration()); + + int totalArenas = _environmentManager.GetTotalArenas(); + Assert.AreEqual(2, totalArenas); + } + + [Test] + public void AAI3EnvironmentManager_LoadYAMLFileInEditor_LoadsValidYAML() + { + _environmentManager.configFile = "test_configs/decoy-file-test"; /* File should exist and be in resources folder */ + _environmentManager.LoadYAMLFileInEditor(); + + Assert.IsTrue(_environmentManager.GetTotalArenas() > 0); + } + + [Test] + public void AAI3EnvironmentManager_InstantiateArenas_CreatesMultipleArenas() + { + _environmentManager.InstantiateArenas(); + + Assert.IsNotNull(_environmentManager.arena); + Assert.IsInstanceOf(_environmentManager.arena.GetComponent()); + } + + [Test] + public void AAI3EnvironmentManager_OnDestroy_UnregistersSideChannel() + { + _environmentManager.InitialiseSideChannel(); + _environmentManager.OnDestroy(); + + Assert.Pass("Side channel unregistered without exceptions."); + } + + [Test] + public void AAI3EnvironmentManager_InitialiseSideChannel_CorrectlyInitializesSideChannel() + { + _environmentManager.InitialiseSideChannel(); + Assert.IsNotNull(_environmentManager.ArenasParametersSideChannel); + } + [Test] public void AAI3EnvironmentManager_RetrieveEnvironmentParameters_WorksCorrectly() { @@ -147,4 +201,20 @@ public void AAI3EnvironmentManager_TriggerArenaChangeEvent_InvokesEventCorrectly AAI3EnvironmentManager.OnArenaChanged -= (currentArenaIndex, totalArenas) => eventTriggered = true; } + + [TearDown] + public void TearDown() + { + if (_environmentManager != null && _environmentManager.ArenasParametersSideChannel != null) + { + SideChannelManager.UnregisterSideChannel( + _environmentManager.ArenasParametersSideChannel + ); + } + + GameObject.DestroyImmediate(_gameObject); + GameObject.DestroyImmediate(_trainingArena.gameObject); + GameObject.DestroyImmediate(_agent.gameObject); + GameObject.DestroyImmediate(_canvas.gameObject); + } } From b91697391845132803fbb89d77b9f4190a4966e9 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Thu, 15 Aug 2024 18:35:54 +0100 Subject: [PATCH 187/205] Improved arena config instance management Also made some methods public for testing access (across scripts). Also removed some method comments as redundancy Also added safety checks in some areas --- Assets/Scripts/AAI3EnvironmentManager.cs | 87 +++++++++++++----------- Assets/Scripts/ArenaBuilders.cs | 19 ++++-- Assets/Scripts/ArenasParameters.cs | 35 ---------- Assets/Scripts/PlayerControls.cs | 15 +++- Assets/Scripts/TrainingArena.cs | 25 ++++++- 5 files changed, 97 insertions(+), 84 deletions(-) diff --git a/Assets/Scripts/AAI3EnvironmentManager.cs b/Assets/Scripts/AAI3EnvironmentManager.cs index 7fee8983..35691434 100644 --- a/Assets/Scripts/AAI3EnvironmentManager.cs +++ b/Assets/Scripts/AAI3EnvironmentManager.cs @@ -9,23 +9,23 @@ using Unity.MLAgents.Policies; /// -/// Manages the environment settings and configurations for the AAI project. +/// Manages the environment settings and configurations, including the arena, player controls, and UI canvas. /// public class AAI3EnvironmentManager : MonoBehaviour { [Header("Arena Settings")] [SerializeField] - private GameObject arena; + public GameObject arena; [SerializeField] - private GameObject uiCanvas; + public GameObject uiCanvas; [SerializeField] - private GameObject playerControls; + public GameObject playerControls; [Header("Configuration File")] [SerializeField] - private string configFile = ""; + public string configFile = ""; [Header("Resolution Settings")] [SerializeField] @@ -48,15 +48,16 @@ public class AAI3EnvironmentManager : MonoBehaviour public bool PlayerMode { get; private set; } = true; - private ArenasConfigurations _arenasConfigurations; + public ArenasConfigurations _arenasConfigurations; private TrainingArena _instantiatedArena; private ArenasParametersSideChannel _arenasParametersSideChannel; + public ArenasParametersSideChannel ArenasParametersSideChannel => _arenasParametersSideChannel; public static event Action OnArenaChanged; - #region Initialisation Methods public void Awake() { + _arenasConfigurations = new ArenasConfigurations(); InitialiseSideChannel(); Dictionary environmentParameters = RetrieveEnvironmentParameters(); @@ -149,23 +150,42 @@ public void Awake() _instantiatedArena._agent.gameObject.SetActive(true); } - private void InitialiseSideChannel() + public void InitialiseSideChannel() { - _arenasConfigurations = new ArenasConfigurations(); - _arenasParametersSideChannel = new ArenasParametersSideChannel(); - _arenasParametersSideChannel.NewArenasParametersReceived += - _arenasConfigurations.UpdateWithConfigurationsReceived; - SideChannelManager.RegisterSideChannel(_arenasParametersSideChannel); + if (_arenasParametersSideChannel != null) + { + try + { + SideChannelManager.UnregisterSideChannel(_arenasParametersSideChannel); + } + catch (Exception ex) + { + Debug.LogWarning($"Failed to unregister existing side channel: {ex.Message}"); + } + } + + try + { + _arenasParametersSideChannel = new ArenasParametersSideChannel(); + _arenasParametersSideChannel.NewArenasParametersReceived += + _arenasConfigurations.UpdateWithConfigurationsReceived; + SideChannelManager.RegisterSideChannel(_arenasParametersSideChannel); + } + catch (Exception ex) + { + Debug.LogError($"Failed to initialize or register the side channel: {ex.Message}"); + throw; + } } - private void InstantiateArenas() + public void InstantiateArenas() { GameObject arenaInst = Instantiate(arena, new Vector3(0f, 0f, 0f), Quaternion.identity); _instantiatedArena = arenaInst.GetComponent(); _instantiatedArena.arenaID = 0; } - private void LoadYAMLFileInEditor() + public void LoadYAMLFileInEditor() { if (string.IsNullOrWhiteSpace(configFile)) { @@ -204,10 +224,6 @@ private void LoadYAMLFileInEditor() } } - #endregion - - #region Public Getter/Setter Methods - public void TriggerArenaChangeEvent(int currentArenaIndex, int totalArenas) { OnArenaChanged?.Invoke(currentArenaIndex, totalArenas); @@ -228,10 +244,12 @@ public int GetTotalArenas() return _arenasConfigurations.configurations.Count; } - #endregion + public ArenasConfigurations GetArenasConfigurations() + { + return _arenasConfigurations; + } - #region Environment Configuration Methods - private void ChangeRayCasts( + public void ChangeRayCasts( RayPerceptionSensorComponent3D raySensor, int no_raycasts, int max_degrees @@ -241,7 +259,7 @@ int max_degrees raySensor.MaxRayDegrees = max_degrees; } - private void ChangeResolution( + public void ChangeResolution( CameraSensorComponent cameraSensor, int cameraWidth, int cameraHeight, @@ -253,10 +271,13 @@ bool grayscale cameraSensor.Grayscale = grayscale; } - private Dictionary RetrieveEnvironmentParameters() + public Dictionary RetrieveEnvironmentParameters(string[] args = null) { Dictionary environmentParameters = new Dictionary(); - string[] args = System.Environment.GetCommandLineArgs(); + if (args == null) + { + args = System.Environment.GetCommandLineArgs(); + } for (int i = 0; i < args.Length; i++) { @@ -303,10 +324,6 @@ private Dictionary RetrieveEnvironmentParameters() return environmentParameters; } - #endregion - - #region Configuration Management Methods - public ArenaConfiguration GetConfiguration(int arenaID) { ArenaConfiguration returnConfiguration; @@ -322,13 +339,9 @@ public void AddConfiguration(int arenaID, ArenaConfiguration arenaConfiguration) _arenasConfigurations.configurations.Add(arenaID, arenaConfiguration); } - #endregion - - #region Other Methods - public void OnDestroy() { - if (Academy.IsInitialized) + if (Academy.IsInitialized && _arenasParametersSideChannel != null) { SideChannelManager.UnregisterSideChannel(_arenasParametersSideChannel); } @@ -363,16 +376,10 @@ int rayMaxDegrees ); } - #endregion - - #region Read Stream - public static byte[] ReadFully(Stream stream) { using var ms = new MemoryStream(); stream.CopyTo(ms); return ms.ToArray(); } - - #endregion } diff --git a/Assets/Scripts/ArenaBuilders.cs b/Assets/Scripts/ArenaBuilders.cs index 945b642d..51376645 100644 --- a/Assets/Scripts/ArenaBuilders.cs +++ b/Assets/Scripts/ArenaBuilders.cs @@ -57,6 +57,8 @@ public class ArenaBuilder [HideInInspector] public List Spawnables { get; set; } + private AAI3EnvironmentManager _environmentManager; + #endregion #region Arena Constructor @@ -107,17 +109,26 @@ public void Build() _arena.transform, false ); + if (spawnedObjectsHolder == null || _arena == null) + { + Debug.LogError("SpawnedObjectsHolder or Arena is not initialized."); + return; + } spawnedObjectsHolder.transform.parent = _arena; InstantiateSpawnables(spawnedObjectsHolder); TrainingAgent agentInstance = UnityEngine.Object.FindObjectOfType(); - if (agentInstance != null && _arena != null) + if (agentInstance != null && _environmentManager != null) { - TrainingArena trainingArena = _arena.GetComponent(); - if (trainingArena != null) + var arenasConfigurations = _environmentManager.GetArenasConfigurations(); + if (arenasConfigurations != null) + { + agentInstance.showNotification = arenasConfigurations.showNotification; + } + else { - agentInstance.showNotification = ArenasConfigurations.Instance.showNotification; + Debug.LogError("ArenasConfigurations is not initialized."); } } diff --git a/Assets/Scripts/ArenasParameters.cs b/Assets/Scripts/ArenasParameters.cs index 9941d01b..29be45cd 100644 --- a/Assets/Scripts/ArenasParameters.cs +++ b/Assets/Scripts/ArenasParameters.cs @@ -210,30 +210,17 @@ public class ArenasConfigurations { public Dictionary configurations; public int seed; - public static ArenasConfigurations Instance { get; private set; } public bool randomizeArenas = false; public bool showNotification { get; set; } = false; public bool canResetEpisode { get; set; } = true; public bool canChangePerspective { get; set; } = true; public int CurrentArenaID { get; set; } = 0; - /// - /// The purpose of this constructor is to initialize the configurations dictionary. - /// public ArenasConfigurations() { - if (Instance != null) - { - throw new Exception("Multiple instances of ArenasConfigurations!"); - } - Instance = this; - configurations = new Dictionary(); } - /// - /// This method is used to get the current arena configuration. - /// public ArenaConfiguration CurrentArenaConfiguration { get @@ -244,9 +231,6 @@ public ArenaConfiguration CurrentArenaConfiguration } } - /// - /// This method is used to add a new arena configuration to the configurations dictionary. - /// internal void Add(int k, YAMLDefs.Arena yamlConfig) { if (!configurations.ContainsKey(k)) @@ -264,9 +248,6 @@ internal void Add(int k, YAMLDefs.Arena yamlConfig) yamlConfig.SetCurrentPassMark(); } - /// - /// This method is used to add additional arenas to the configurations dictionary. - /// public void AddAdditionalArenas(YAMLDefs.ArenaConfig yamlArenaConfig) { foreach (YAMLDefs.Arena arena in yamlArenaConfig.arenas.Values) @@ -277,18 +258,12 @@ public void AddAdditionalArenas(YAMLDefs.ArenaConfig yamlArenaConfig) } } - /// - /// This method is used to update the current configurations with the new ones provided in the yamlArenaConfig object. - /// Furthermore, it sets the randomizeArenas, showNotification, canResetEpisode, and canChangePerspective properties of the ArenasConfigurations object. - /// Lastly, it ensures the arena IDs are unique and positive; assigns new IDs if required. - /// public void UpdateWithYAML(YAMLDefs.ArenaConfig yamlArenaConfig) { configurations.Clear(); List existingIds = new List(); int nextAvailableId = 0; - // Iterating over arenas in the order they appear in the YAML, top to bottom. foreach (KeyValuePair arenaConfiguration in yamlArenaConfig.arenas) { int currentID = arenaConfiguration.Key; @@ -298,8 +273,6 @@ public void UpdateWithYAML(YAMLDefs.ArenaConfig yamlArenaConfig) Debug.LogWarning( $"Issue with arenaID: {currentID}. Assigning a new unique ID: {nextAvailableId}." ); - - // Assign a new unique ID if required. Add(nextAvailableId, arenaConfiguration.Value); existingIds.Add(nextAvailableId); } @@ -309,7 +282,6 @@ public void UpdateWithYAML(YAMLDefs.ArenaConfig yamlArenaConfig) existingIds.Add(currentID); } - // Adjust the nextAvailableId for future entries. nextAvailableId = existingIds.Max() + 1; } @@ -319,10 +291,6 @@ public void UpdateWithYAML(YAMLDefs.ArenaConfig yamlArenaConfig) canChangePerspective = yamlArenaConfig.canChangePerspective; } - /// - /// This method handles an event that is triggered when new arena configurations are received. - /// It extracts the YAML data from the event, converts it into an ArenaConfig object, and then updates the current configurations with the new ones. - /// public void UpdateWithConfigurationsReceived( object sender, ArenasParametersEventArgs arenasParametersEvent @@ -335,9 +303,6 @@ ArenasParametersEventArgs arenasParametersEvent UpdateWithYAML(parsed); } - /// - /// The purpose of this method is to iterate over each entry in the configurations dictionary and set the toUpdate property of each ArenaConfiguration object to false. - /// public void SetAllToUpdated() { foreach (KeyValuePair configuration in configurations) diff --git a/Assets/Scripts/PlayerControls.cs b/Assets/Scripts/PlayerControls.cs index 4768b0c0..d0d849b4 100644 --- a/Assets/Scripts/PlayerControls.cs +++ b/Assets/Scripts/PlayerControls.cs @@ -28,6 +28,7 @@ public class PlayerControls : MonoBehaviour private ScreenshotCamera screenshotCam; private TrainingAgent agent; private ArenasConfigurations arenasConfigurations; + private AAI3EnvironmentManager environmentManager; [Header("Score Settings")] public float prevScore = 0; @@ -88,13 +89,21 @@ private void LoadCamerasAndAgent() .GetComponent(); cameras[2] = GameObject.FindGameObjectWithTag("camBase").GetComponent(); agent = GameObject.FindGameObjectWithTag("agent").GetComponent(); + environmentManager = FindObjectOfType(); } private void LoadConfigurationSettings() { - arenasConfigurations = ArenasConfigurations.Instance; - canResetEpisode = arenasConfigurations?.canResetEpisode ?? true; - canChangePerspective = arenasConfigurations?.canChangePerspective ?? true; + if (environmentManager != null) + { + arenasConfigurations = environmentManager.GetArenasConfigurations(); + canResetEpisode = arenasConfigurations?.canResetEpisode ?? true; + canChangePerspective = arenasConfigurations?.canChangePerspective ?? true; + } + else + { + Debug.LogError("Environment Manager not found. Using default settings."); + } } private void InitializeCameras() diff --git a/Assets/Scripts/TrainingArena.cs b/Assets/Scripts/TrainingArena.cs index 1fde26d8..f834c813 100644 --- a/Assets/Scripts/TrainingArena.cs +++ b/Assets/Scripts/TrainingArena.cs @@ -95,6 +95,10 @@ private void InitializeArenaComponents() maxSpawnAttemptsForAgent ); _environmentManager = GameObject.FindObjectOfType(); + if (_environmentManager == null) + { + Debug.LogError("AAI3EnvironmentManager is not found in the scene."); + } _agent = FindObjectsOfType(true)[0]; _agentDecisionInterval = _agent.GetComponentInChildren().DecisionPeriod; _fades = blackScreens.GetFades(); @@ -135,7 +139,7 @@ public void ResetArena() CleanUpSpawnedObjects(); SetNextArenaID(); - + ArenaConfiguration newConfiguration = _environmentManager.GetConfiguration(arenaID); ApplyNewArenaConfiguration(newConfiguration); @@ -240,8 +244,25 @@ private int ChooseRandomArenaID(int totalArenas) */ private void ApplyNewArenaConfiguration(ArenaConfiguration newConfiguration) { + if (_environmentManager == null) + { + Debug.LogError("Environment Manager is null in ApplyNewArenaConfiguration."); + return; + } + _arenaConfiguration = newConfiguration; - _agent.showNotification = ArenasConfigurations.Instance.showNotification; + var arenasConfigurations = _environmentManager.GetArenasConfigurations(); + if (arenasConfigurations != null) + { + _agent.showNotification = arenasConfigurations.showNotification; + } + else + { + Debug.LogError( + "ArenasConfigurations is not initialized in ApplyNewArenaConfiguration." + ); + } + _arenaConfiguration.SetGameObject(prefabs.GetList()); _builder.Spawnables = _arenaConfiguration.spawnables; _arenaConfiguration.toUpdate = false; From d8b505e9cf8e3df361a91222d6ab3d0ecc7d87a8 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Thu, 15 Aug 2024 18:43:45 +0100 Subject: [PATCH 188/205] updated script to remove redundant comments --- Assets/Scripts/ArenasParameters.cs | 41 ++++-------------------------- 1 file changed, 5 insertions(+), 36 deletions(-) diff --git a/Assets/Scripts/ArenasParameters.cs b/Assets/Scripts/ArenasParameters.cs index 29be45cd..c53e9bdd 100644 --- a/Assets/Scripts/ArenasParameters.cs +++ b/Assets/Scripts/ArenasParameters.cs @@ -10,13 +10,8 @@ /// The classes in this file are used to store the parameters for the arenas. /// These parameters are read from a YAML file and used to configure the arenas. /// - -// TODO: Optimize and refactor this script. namespace ArenasParameters { - /// - /// The ListOfPrefabs class is a simple data container that holds a list of GameObject instances and provides a method to access that list. - /// [System.Serializable] public class ListOfPrefabs { @@ -28,9 +23,6 @@ public List GetList() } } - /// - /// The list of prefabs that can be passed as items to spawn in the various arenas. - /// public class Spawnable { // ======== REQUIRED PARAMETERS ======== @@ -72,10 +64,6 @@ public class Spawnable public List triggerZoneID = null; public bool zoneVisibility = true; - /// - /// The purpose of this constructor is to initialize the Spawnable object with the properties of the provided GameObject. - /// The name property of the Spawnable object is set to the name of the GameObject, and the gameObject property of the Spawnable object is set to the GameObject itself. - /// public Spawnable(GameObject obj) { name = obj.name; @@ -86,9 +74,6 @@ public Spawnable(GameObject obj) colors = new List(); } - /// - /// The purpose of this constructor is to initialize the properties of the Spawnable class with the values from the yamlItem object. - /// internal Spawnable(YAMLDefs.Item yamlItem) { name = yamlItem.name; @@ -98,8 +83,6 @@ internal Spawnable(YAMLDefs.Item yamlItem) colors = initVec3sFromRGBs(yamlItem.colors); name = AliasMapper.ResolveAlias(yamlItem.name); - // ======== EXTRA/OPTIONAL PARAMETERS ======== - skins = yamlItem.skins; frozenAgentDelays = yamlItem.frozenAgentDelays; @@ -128,9 +111,6 @@ internal Spawnable(YAMLDefs.Item yamlItem) zoneVisibility = yamlItem.zoneVisibility; } - /// - /// The purpose of this method is to initialize a list of Vector3 objects from a list of RGB objects. - /// internal List initVec3sFromRGBs(List yamlList) { List cList = new List(); @@ -142,9 +122,6 @@ internal List initVec3sFromRGBs(List yamlList) } } - /// - /// The ArenaConfiguration class is used to define the configuration of an arena, such as the time limit, the spawnables, and the lights switch. - /// public class ArenaConfiguration { public int TimeLimit = 0; @@ -157,9 +134,6 @@ public class ArenaConfiguration public ArenaConfiguration() { } - /// - /// The purpose of this constructor is to initialize the properties of the ArenaConfiguration class with the values from the yamlArena object. - /// public ArenaConfiguration(ListOfPrefabs listPrefabs) { foreach (GameObject prefab in listPrefabs.allPrefabs) @@ -170,9 +144,6 @@ public ArenaConfiguration(ListOfPrefabs listPrefabs) toUpdate = true; } - /// - /// The internal constructor initializes several properties of the ArenaConfiguration object. - /// internal ArenaConfiguration(YAMLDefs.Arena yamlArena) { TimeLimit = yamlArena.timeLimit; @@ -191,9 +162,6 @@ internal ArenaConfiguration(YAMLDefs.Arena yamlArena) this.mergeNextArena = yamlArena.mergeNextArena; } - /// - /// The purpose of this method is to associate the GameObject instances with the Spawnable objects. - /// public void SetGameObject(List listObj) { foreach (Spawnable spawn in spawnables) @@ -203,11 +171,12 @@ public void SetGameObject(List listObj) } } - /// - /// ArenaConfigurations is a dictionary of configurations for each arena. - /// public class ArenasConfigurations { + /* + The configurations dictionary is used to store the configurations for each arena. + The key is the arena ID and the value is the ArenaConfiguration object. + */ public Dictionary configurations; public int seed; public bool randomizeArenas = false; @@ -231,7 +200,7 @@ public ArenaConfiguration CurrentArenaConfiguration } } - internal void Add(int k, YAMLDefs.Arena yamlConfig) + public void Add(int k, YAMLDefs.Arena yamlConfig) { if (!configurations.ContainsKey(k)) { From e08d028846223a130ba76a00cea0131c67a7d678 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Thu, 15 Aug 2024 18:47:21 +0100 Subject: [PATCH 189/205] added tests for arenasparameters.cs --- .../Tests/EditMode/ArenasParametersTests.cs | 148 ++++++++++++++++++ .../EditMode/ArenasParametersTests.cs.meta | 11 ++ 2 files changed, 159 insertions(+) create mode 100644 Assets/Tests/EditMode/ArenasParametersTests.cs create mode 100644 Assets/Tests/EditMode/ArenasParametersTests.cs.meta diff --git a/Assets/Tests/EditMode/ArenasParametersTests.cs b/Assets/Tests/EditMode/ArenasParametersTests.cs new file mode 100644 index 00000000..2bc5879b --- /dev/null +++ b/Assets/Tests/EditMode/ArenasParametersTests.cs @@ -0,0 +1,148 @@ +using NUnit.Framework; +using System.Collections.Generic; +using UnityEngine; +using ArenasParameters; +using YAMLDefs; + +/// +/// Tests for the classes in the ArenasParameters class. +/// +[TestFixture] +public class ArenasParametersTests +{ + private ListOfPrefabs _listOfPrefabs; + private GameObject _testGameObject; + private Spawnable _spawnable; + private ArenaConfiguration _arenaConfiguration; + private ArenasConfigurations _arenasConfigurations; + + [SetUp] + public void SetUp() + { + _testGameObject = new GameObject("TestObject"); + _listOfPrefabs = new ListOfPrefabs + { + allPrefabs = new List { _testGameObject } + }; + + _spawnable = new Spawnable(_testGameObject); + + _arenaConfiguration = new ArenaConfiguration(_listOfPrefabs); + + _arenasConfigurations = new ArenasConfigurations(); + } + + [TearDown] + public void TearDown() + { + GameObject.DestroyImmediate(_testGameObject); + } + + [Test] + public void ListOfPrefabs_GetList_ReturnsCorrectList() + { + List prefabsList = _listOfPrefabs.GetList(); + Assert.AreEqual(1, prefabsList.Count); + Assert.AreSame(_testGameObject, prefabsList[0]); + } + + [Test] + public void Spawnable_Constructor_InitializesCorrectly() + { + Assert.AreEqual(_testGameObject.name, _spawnable.name); + Assert.AreSame(_testGameObject, _spawnable.gameObject); + Assert.IsNotNull(_spawnable.positions); + Assert.IsNotNull(_spawnable.rotations); + Assert.IsNotNull(_spawnable.sizes); + Assert.IsNotNull(_spawnable.colors); + } + + [Test] + public void ArenaConfiguration_Constructor_InitializesCorrectly() + { + Assert.AreEqual(1, _arenaConfiguration.spawnables.Count); + Assert.AreEqual(_testGameObject.name, _arenaConfiguration.spawnables[0].name); + Assert.AreEqual(0, _arenaConfiguration.TimeLimit); + } + + [Test] + public void ArenaConfiguration_SetGameObject_AssignsCorrectGameObject() + { + _arenaConfiguration.SetGameObject(_listOfPrefabs.GetList()); + Assert.AreSame(_testGameObject, _arenaConfiguration.spawnables[0].gameObject); + } + + [Test] + public void ArenasConfigurations_Add_AddsConfigurationCorrectly() + { + YAMLDefs.Arena yamlArena = new YAMLDefs.Arena(); + _arenasConfigurations.Add(0, yamlArena); + + Assert.AreEqual(1, _arenasConfigurations.configurations.Count); + Assert.AreEqual(0, _arenasConfigurations.CurrentArenaID); + Assert.AreEqual(yamlArena.ToString(), _arenasConfigurations.configurations[0].protoString); + } + + [Test] + public void ArenasConfigurations_UpdateWithYAML_UpdatesCorrectly() + { + YAMLDefs.ArenaConfig yamlConfig = new YAMLDefs.ArenaConfig + { + arenas = new Dictionary + { + { 0, new YAMLDefs.Arena() }, + { 1, new YAMLDefs.Arena() } + }, + randomizeArenas = true, + showNotification = true, + canResetEpisode = false, + canChangePerspective = false + }; + + _arenasConfigurations.UpdateWithYAML(yamlConfig); + + Assert.AreEqual(2, _arenasConfigurations.configurations.Count); + Assert.IsTrue(_arenasConfigurations.randomizeArenas); + Assert.IsTrue(_arenasConfigurations.showNotification); + Assert.IsFalse(_arenasConfigurations.canResetEpisode); + Assert.IsFalse(_arenasConfigurations.canChangePerspective); + } + + [Test] + public void ArenasConfigurations_ClearConfigurations_ClearsAllConfigurations() + { + YAMLDefs.Arena yamlArena = new YAMLDefs.Arena(); + _arenasConfigurations.Add(0, yamlArena); + Assert.AreEqual(1, _arenasConfigurations.configurations.Count); + + _arenasConfigurations.ClearConfigurations(); + Assert.AreEqual(0, _arenasConfigurations.configurations.Count); + } + + [Test] + public void ArenasConfigurations_SetAllToUpdated_SetsAllToUpdateFalse() + { + YAMLDefs.Arena yamlArena = new YAMLDefs.Arena(); + _arenasConfigurations.Add(0, yamlArena); + _arenasConfigurations.configurations[0].toUpdate = true; + + _arenasConfigurations.SetAllToUpdated(); + Assert.IsFalse(_arenasConfigurations.configurations[0].toUpdate); + } + + [Test] + public void ArenasConfigurations_CurrentArenaConfiguration_ReturnsNullIfNotSet() + { + Assert.IsNull(_arenasConfigurations.CurrentArenaConfiguration); + } + + [Test] + public void ArenasConfigurations_CurrentArenaConfiguration_ReturnsCorrectConfiguration() + { + YAMLDefs.Arena yamlArena = new YAMLDefs.Arena(); + _arenasConfigurations.Add(0, yamlArena); + _arenasConfigurations.CurrentArenaID = 0; + + Assert.IsNotNull(_arenasConfigurations.CurrentArenaConfiguration); + } +} diff --git a/Assets/Tests/EditMode/ArenasParametersTests.cs.meta b/Assets/Tests/EditMode/ArenasParametersTests.cs.meta new file mode 100644 index 00000000..b9c3c408 --- /dev/null +++ b/Assets/Tests/EditMode/ArenasParametersTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 76304b9c3e7ce49d2a4c27c96241a31a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From df42a7c330f3c200bdd4f9f401d1dda82d8e0448 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Thu, 15 Aug 2024 19:24:46 +0100 Subject: [PATCH 190/205] refactored arenabuilders.cs for readability Removed redundant comments where necessary. --- Assets/Scripts/ArenaBuilders.cs | 136 ++------------------------------ 1 file changed, 7 insertions(+), 129 deletions(-) diff --git a/Assets/Scripts/ArenaBuilders.cs b/Assets/Scripts/ArenaBuilders.cs index 51376645..a80b2ed6 100644 --- a/Assets/Scripts/ArenaBuilders.cs +++ b/Assets/Scripts/ArenaBuilders.cs @@ -15,58 +15,29 @@ /// User-defined or randomized positions, rotations, and scales are supported /// ... with repeated spawn attempts made for random placements until free space is found or the builder moves to the next item. /// - -// TODO: Optimize and refactor the this script. -// TODO: Overhaul object spawn and agent spawn logic for a more unified and central implementation (for all objects, inc. agent) +/// TODO: Overhaul object spawn and agent spawn logic for a more unified and central implementation (for all objects, inc. agent) namespace ArenaBuilders { public class ArenaBuilder { - #region Properties and Fields - - // Arena size private float _rangeX; private float _rangeZ; - - // Getters for the arena size (used for spawning objects within the arena bounds in other scripts) public float ArenaWidth => _rangeX; public float ArenaDepth => _rangeZ; - - // Arena to which the builder is attached private Transform _arena; - - // Holder for all spawned objects private GameObject _spawnedObjectsHolder; - - // Max number of attempts to spawn an object or agent - private int _maxSpawnAttemptsForPrefabs; - private int _maxSpawnAttemptsForAgent; - - // Agent components + public int _maxSpawnAttemptsForPrefabs; + public int _maxSpawnAttemptsForAgent; private GameObject _agent; private Collider _agentCollider; private Rigidbody _agentRigidbody; - - // Total number of good goals instantiated private List _goodGoalsMultiSpawned; - - // Total number of objects spawned (for UI) private int _totalObjectsSpawned; + private AAI3EnvironmentManager _environmentManager; - // The list of Spawnables the ArenaBuilder will attempt to spawn at each reset [HideInInspector] public List Spawnables { get; set; } - private AAI3EnvironmentManager _environmentManager; - - #endregion - - #region Arena Constructor - - /// - /// Constructor for the ArenaBuilder class. - /// It initializes the arena, the spawned objects holder, and the maximum spawn attempts for prefabs and the agent. - /// public ArenaBuilder( GameObject arenaGameObject, GameObject spawnedObjectsHolder, @@ -91,13 +62,6 @@ int maxSpawnAttemptsForAgent _goodGoalsMultiSpawned = new List(); } - #endregion - - #region Arena Builder - - /// - /// Builds the arena by instantiating the Spawnable objects within the arena. - /// public void Build() { _totalObjectsSpawned = 0; @@ -135,13 +99,6 @@ public void Build() updateGoodGoalsMulti(); } - #endregion - - #region Instantiate and Spawn Objects Methods - - /// - /// Instantiates the Spawnable objects within the arena. - /// private void InstantiateSpawnables(GameObject spawnedObjectsHolder) { Debug.Log("Spawnables has " + Spawnables.Capacity + " entries"); @@ -149,8 +106,6 @@ private void InstantiateSpawnables(GameObject spawnedObjectsHolder) .Where(x => x.gameObject != null && x.gameObject.CompareTag("agent")) .ToList(); - // Instantiate the agent first based on its characteristics, then prevent item spawning at the same location; - // ... otherwise, spawn it last to enable more object spawns. if (agentSpawnablesFromUser.Any()) { _agentCollider.enabled = false; @@ -177,15 +132,11 @@ private void InstantiateSpawnables(GameObject spawnedObjectsHolder) } } - // Helper method to check for agent position problems. When arena size can be changed, this method will need to be updated. private bool IsProblematicPosition(Vector3 position) { return position.x == 0 || position.z == 0 || position.x == 40 || position.z == 40; } - /// - /// Spawns the objects within the arena. - /// private void SpawnObjects(GameObject spawnedObjectsHolder) { foreach (Spawnable spawnable in Spawnables) @@ -200,12 +151,6 @@ private void SpawnObjects(GameObject spawnedObjectsHolder) } } - /// - /// InstantiateSpawnable spawns game objects in a game environment. - /// It takes two parameters: a Spawnable object and a GameObject that serves as a holder for the spawned objects. - /// The method instantiates the game object, sets its layer, position, rotation, and scale, and then spawns the game object. - /// The method also sets the color of the game object and assigns a symbol name to the game object's SignBoard component. - /// private void InstantiateSpawnable(Spawnable spawnable, GameObject spawnedObjectsHolder) { // Required parameters @@ -274,7 +219,6 @@ private void InstantiateSpawnable(Spawnable spawnable, GameObject spawnedObjects // Get the maximum number of elements in the lists int n = ns.Max(); - // Spawn the objects int k = 0; do { @@ -352,10 +296,6 @@ private void InstantiateSpawnable(Spawnable spawnable, GameObject spawnedObjects } while (k < n); } - /// - /// The SpawnGameObject function instantiates a game object with specified properties, sets its position, rotation, and color, assigns it a symbol name if provided, - /// ...adjusts properties of its Spawner_InteractiveButton and GoalSpawner components based on optional parameters, and assigns timing parameters to relevant components. - /// private void SpawnGameObject( Spawnable spawnable, GameObject gameObjectInstance, @@ -453,7 +393,6 @@ private void SpawnGameObject( GS.SetSpawnColor((Vector3)spawnColorValue); } - // Now check all floats relating to timing of changes // Each float param has a list of "acceptable types" to which it applies Dictionary> paramValidTypeLookup = new Dictionary< string, @@ -502,25 +441,23 @@ private void SpawnGameObject( { "ripenTime", new List { typeof(GoalSpawner) } - }, // TreeSpawners only! Ignored o/wise + }, { "doorDelay", new List { typeof(SpawnerStockpiler) } - }, // Dispensers/Containers only! + }, { "timeBetweenDoorOpens", new List { typeof(SpawnerStockpiler) } - }, // Dispensers/Containers only! + }, }; float v; foreach (string paramKey in paramValidTypeLookup.Keys) { - // Try each valid type that we might be able to assign to if (optionals[paramKey] != null) { foreach (Type U in paramValidTypeLookup[paramKey]) { - // Check if gameObjectInstance has got the relevant component if (gameObjectInstance.TryGetComponent(U, out var component)) { v = Convert.ToSingle(optionals[paramKey]); @@ -561,15 +498,6 @@ private void SpawnGameObject( } } - #endregion - - #region Spawn Agent - - /// - /// The SpawnAgent function spawns an agent in a game environment. - /// It takes a Spawnable object as a parameter and spawns the agent at a specified position and rotation. - /// The function also sets the agent's skin and freeze delay. - /// private void SpawnAgent(Spawnable agentSpawnableFromUser) { PositionRotation agentToSpawnPosRot; @@ -626,15 +554,6 @@ private void SpawnAgent(Spawnable agentSpawnableFromUser) _agent.GetComponent().SetFreezeDelay(freezeDelay); } - #endregion - - #region Check Position/Rotation and Object Placement Methods - - /// - /// The SamplePositionRotation function samples a position and rotation for a game object to spawn. - /// It takes five parameters: a game object instance, the maximum number of spawn attempts, a position, a rotation, and a size. - /// The function returns a PositionRotation object that contains the position and rotation of the game object to spawn. - /// private PositionRotation SamplePositionRotation( GameObject gameObjectInstance, int maxSpawnAttempt, @@ -683,11 +602,6 @@ Vector3 size return null; } - /// - /// The IsSpotFree function checks if a spot is free for a game object to spawn. - /// It takes three parameters: an array of colliders, a boolean value indicating if the object is an agent, and a boolean value indicating if the object is a zone. - /// The function returns true if the spot is free; otherwise, it returns false. - /// private bool IsSpotFree(Collider[] colliders, bool isAgent, bool isZone = false) { if (isZone) @@ -703,11 +617,6 @@ private bool IsSpotFree(Collider[] colliders, bool isAgent, bool isZone = false) || (colliders.All(collider => collider.isTrigger) && !isAgent); } - /// - /// The ObjectOutsideOfBounds function checks if a game object is outside of the arena bounds (walls). - /// It takes two parameters: a position and a bounding box. - /// The function returns true if the object is outside of the bounds; otherwise, it returns false. - /// private bool ObjectOutsideOfBounds(Vector3 position, Vector3 boundingBox) { return position.x > boundingBox.x @@ -716,13 +625,6 @@ private bool ObjectOutsideOfBounds(Vector3 position, Vector3 boundingBox) && position.z < _rangeZ - boundingBox.z; } - #endregion - - #region Goal Spawner-Logic Methods - - /// - /// Updates the number of goals in the goodGoalsMultiSpawned list. - /// private void updateGoodGoalsMulti() { int numberOfGoals = _goodGoalsMultiSpawned.Count; @@ -732,47 +634,28 @@ private void updateGoodGoalsMulti() } } - /// - /// Adds a goal to the goodGoalsMultiSpawned list. - /// public void AddToGoodGoalsMultiSpawned(Goal ggm) { _goodGoalsMultiSpawned.Add(ggm); updateGoodGoalsMulti(); } - /// - /// Adds a goal to the goodGoalsMultiSpawned list as a GameObject. - /// public void AddToGoodGoalsMultiSpawned(GameObject ggm) { _goodGoalsMultiSpawned.Add(ggm.GetComponent()); updateGoodGoalsMulti(); } - #endregion - - #region Other Methods - - /// - /// Returns the number of elements in a list if not null; otherwise, returns 0. - /// private int optionalCount(List paramList) { return (paramList != null) ? paramList.Count : 0; } - /// - /// Returns the total number of objects spawned. - /// public int GetTotalObjectsSpawned() { return _totalObjectsSpawned; } - /// - /// Assigns a symbol name to a component's SignBoard. - /// private void AssignSymbolName(GameObject gameObjectInstance, string sName, Vector3 color) { SignBoard SP = gameObjectInstance.GetComponent(); @@ -792,9 +675,6 @@ private void AssignSymbolName(GameObject gameObjectInstance, string sName, Vecto } } - /// - /// Assigns a float value to a component's timing parameter. - /// private void AssignTimingNumber(string paramName, float value, T component) { paramName = paramName[0].ToString().ToUpper() + paramName.Substring(1); @@ -805,7 +685,5 @@ private void AssignTimingNumber(string paramName, float value, T component) SetMethod.Invoke(component, new object[] { value }); } } - - #endregion } } From 4aa5beca914be979b10af7beea7c2c9771c31a1a Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Thu, 15 Aug 2024 19:30:37 +0100 Subject: [PATCH 191/205] removed outlier semicolon in code semicolons are syntactically valid in c# --- Assets/Scripts/ArenaBuilders.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/Scripts/ArenaBuilders.cs b/Assets/Scripts/ArenaBuilders.cs index a80b2ed6..167a740a 100644 --- a/Assets/Scripts/ArenaBuilders.cs +++ b/Assets/Scripts/ArenaBuilders.cs @@ -52,7 +52,7 @@ int maxSpawnAttemptsForAgent _rangeX = spawnArenaTransform.localScale.x; _rangeZ = spawnArenaTransform.localScale.z; _agent = _arena.Find("AAI3Agent").Find("Agent").gameObject; - ; + _agentCollider = _agent.GetComponent(); _agentRigidbody = _agent.GetComponent(); _spawnedObjectsHolder = spawnedObjectsHolder; From 9b19b1f9552c59626f946c98970b76e97e35f281 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Thu, 15 Aug 2024 19:32:59 +0100 Subject: [PATCH 192/205] added half of tests for arenabuilder.cs the rest will be in play mode for actual functionality during runtime. --- .../EditMode/ArenaBuilderEditModeTests.cs | 82 +++++++++++++++++++ .../ArenaBuilderEditModeTests.cs.meta | 11 +++ 2 files changed, 93 insertions(+) create mode 100644 Assets/Tests/EditMode/ArenaBuilderEditModeTests.cs create mode 100644 Assets/Tests/EditMode/ArenaBuilderEditModeTests.cs.meta diff --git a/Assets/Tests/EditMode/ArenaBuilderEditModeTests.cs b/Assets/Tests/EditMode/ArenaBuilderEditModeTests.cs new file mode 100644 index 00000000..a3edeca0 --- /dev/null +++ b/Assets/Tests/EditMode/ArenaBuilderEditModeTests.cs @@ -0,0 +1,82 @@ +using NUnit.Framework; +using UnityEngine; +using ArenaBuilders; +using System; +using ArenasParameters; + +/// +/// Tests for the ArenaBuilder class. Contains half of the tests for the ArenaBuilder class. +/// +public class ArenaBuilderEditModeTests +{ + private GameObject _arenaGameObject; + private GameObject _spawnedObjectsHolder; + private ArenaBuilder _arenaBuilder; + + [SetUp] + public void Setup() + { + _arenaGameObject = new GameObject("Arena"); + var spawnArena = new GameObject("spawnArena"); + spawnArena.tag = "spawnArena"; + spawnArena.transform.localScale = new Vector3(10, 1, 20); + spawnArena.transform.parent = _arenaGameObject.transform; + + var agent = new GameObject("Agent"); + agent.AddComponent(); + agent.AddComponent(); + var aai3Agent = new GameObject("AAI3Agent"); + agent.transform.parent = aai3Agent.transform; + aai3Agent.transform.parent = _arenaGameObject.transform; + + _spawnedObjectsHolder = new GameObject("SpawnedObjectsHolder"); + + _arenaBuilder = new ArenaBuilder( + _arenaGameObject, + _spawnedObjectsHolder, + maxSpawnAttemptsForPrefabs: 10, + maxSpawnAttemptsForAgent: 5 + ); + + var spawnableObject = new GameObject("SpawnableObject"); + + _arenaBuilder.Spawnables.Add(new Spawnable(spawnableObject)); + + Debug.Log("Setup completed"); + Debug.Log($"_arenaGameObject: {_arenaGameObject}"); + Debug.Log($"_spawnedObjectsHolder: {_spawnedObjectsHolder}"); + Debug.Log($"_arenaBuilder: {_arenaBuilder}"); + Debug.Log($"Spawnables count: {_arenaBuilder.Spawnables.Count}"); + } + + [Test] + public void ArenaDepth_ShouldBeInitializedCorrectly() + { + float expectedDepth = 20; + + Assert.IsNotNull(_arenaGameObject, "_arenaGameObject is null"); + Assert.IsNotNull(_spawnedObjectsHolder, "_spawnedObjectsHolder is null"); + Assert.IsNotNull(_arenaBuilder, "_arenaBuilder is null"); + Assert.IsTrue(_arenaBuilder.Spawnables.Count > 0, "Spawnables list is empty"); + } + + [Test] + public void ArenaDepth_ShouldReturnCorrectValue() + { + float expectedDepth = 20; + + float actualDepth = _arenaBuilder.ArenaDepth; + + Assert.AreEqual(expectedDepth, actualDepth); + } + + [Test] + public void MaxSpawnAttemptsForPrefabs_ShouldBeInitializedCorrectly() + { + int expectedMaxSpawnAttempts = 10; + + int actualMaxSpawnAttempts = _arenaBuilder._maxSpawnAttemptsForPrefabs; + + Assert.AreEqual(expectedMaxSpawnAttempts, actualMaxSpawnAttempts); + } +} diff --git a/Assets/Tests/EditMode/ArenaBuilderEditModeTests.cs.meta b/Assets/Tests/EditMode/ArenaBuilderEditModeTests.cs.meta new file mode 100644 index 00000000..a6a8a164 --- /dev/null +++ b/Assets/Tests/EditMode/ArenaBuilderEditModeTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6c0bba89623e84bc7b44f21c416397bd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 338af8690c17e05e7a596a5f570b5b43421566b0 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Thu, 15 Aug 2024 19:38:25 +0100 Subject: [PATCH 193/205] old test script dump modified for play mode --- Assets/Tests/Playmode/BallGoalBounceTests.cs | 87 +++++++++++++++++++ .../Playmode/BallGoalBounceTests.cs.meta | 11 +++ 2 files changed, 98 insertions(+) create mode 100644 Assets/Tests/Playmode/BallGoalBounceTests.cs create mode 100644 Assets/Tests/Playmode/BallGoalBounceTests.cs.meta diff --git a/Assets/Tests/Playmode/BallGoalBounceTests.cs b/Assets/Tests/Playmode/BallGoalBounceTests.cs new file mode 100644 index 00000000..0f585605 --- /dev/null +++ b/Assets/Tests/Playmode/BallGoalBounceTests.cs @@ -0,0 +1,87 @@ +using UnityEngine; +using UnityEngine.TestTools; +using NUnit.Framework; +using System.Collections; + +/// +/// Tests for the BallGoalBounce class. +/// +public class BallGoalBounceTests : MonoBehaviour +{ + private GameObject _ballGameObject; + private BallGoalBounce _ballGoalBounce; + private Rigidbody _rBody; + + [SetUp] + public void Setup() + { + _ballGameObject = new GameObject("Ball"); + _rBody = _ballGameObject.AddComponent(); + _ballGoalBounce = _ballGameObject.AddComponent(); + + _ballGoalBounce.forceToApply = 10f; + _ballGoalBounce.maximumVelocity = 15f; + } + + [UnityTest] + public IEnumerator BallGoalBounce_ForceIsAppliedOnStart() + { + yield return null; + + Assert.IsTrue( + _rBody.velocity.magnitude > 0, + "Rigidbody should have velocity after force is applied." + ); + } + + [UnityTest] + public IEnumerator BallGoalBounce_VelocityDoesNotExceedMaximumVelocity() + { + yield return new WaitForSeconds(0.1f); + + Assert.LessOrEqual( + _rBody.velocity.magnitude, + _ballGoalBounce.maximumVelocity, + "Rigidbody velocity should not exceed the maximum velocity." + ); + } + + [UnityTest] + public IEnumerator BallGoalBounce_RigidbodyIsInitialized() + { + yield return null; + + Assert.IsNotNull(_rBody, "Rigidbody should be initialized."); + Assert.AreEqual( + _rBody, + _ballGoalBounce.GetComponent(), + "Rigidbody should be correctly assigned." + ); + } + + [UnityTest] + public IEnumerator BallGoalBounce_ForceDirectionIsForward() + { + yield return null; + + // XZ directions only, no need to check Y + Vector3 expectedDirectionXZ = new Vector3( + _ballGameObject.transform.forward.x, + 0, + _ballGameObject.transform.forward.z + ).normalized; + Vector3 actualDirectionXZ = new Vector3(_rBody.velocity.x, 0, _rBody.velocity.z).normalized; + + Assert.AreEqual( + expectedDirectionXZ, + actualDirectionXZ, + "Force should be applied in the forward direction in the XZ plane." + ); + } + + [TearDown] + public void Teardown() + { + GameObject.Destroy(_ballGameObject); + } +} diff --git a/Assets/Tests/Playmode/BallGoalBounceTests.cs.meta b/Assets/Tests/Playmode/BallGoalBounceTests.cs.meta new file mode 100644 index 00000000..230f7475 --- /dev/null +++ b/Assets/Tests/Playmode/BallGoalBounceTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bc1cedd866ff54bc1a312dde611c04c6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 16d024e413744013be3f1b2afc83d362d0305971 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Thu, 15 Aug 2024 19:39:44 +0100 Subject: [PATCH 194/205] minor typo fix --- Assets/Scripts/Rewards/BallGoalBounce.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Assets/Scripts/Rewards/BallGoalBounce.cs b/Assets/Scripts/Rewards/BallGoalBounce.cs index 16307b5e..5819931f 100644 --- a/Assets/Scripts/Rewards/BallGoalBounce.cs +++ b/Assets/Scripts/Rewards/BallGoalBounce.cs @@ -2,6 +2,7 @@ /// /// A BallGoal that bounces the ball depending on the forceToApply and maximumVelocity parameters. +/// public class BallGoalBounce : BallGoal { [Header("Bounce Settings")] From 4a2ce57b3ff495b2b8ecacbf64fdccebe407b7af Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Thu, 15 Aug 2024 20:39:17 +0100 Subject: [PATCH 195/205] minor code fix --- Assets/Tests/EditMode/ArenaBuilderEditModeTests.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Assets/Tests/EditMode/ArenaBuilderEditModeTests.cs b/Assets/Tests/EditMode/ArenaBuilderEditModeTests.cs index a3edeca0..1dde3a5a 100644 --- a/Assets/Tests/EditMode/ArenaBuilderEditModeTests.cs +++ b/Assets/Tests/EditMode/ArenaBuilderEditModeTests.cs @@ -52,8 +52,6 @@ public void Setup() [Test] public void ArenaDepth_ShouldBeInitializedCorrectly() { - float expectedDepth = 20; - Assert.IsNotNull(_arenaGameObject, "_arenaGameObject is null"); Assert.IsNotNull(_spawnedObjectsHolder, "_spawnedObjectsHolder is null"); Assert.IsNotNull(_arenaBuilder, "_arenaBuilder is null"); From 94cef1aa4c8144cfd8d8b12eac06e22929a73d04 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Thu, 15 Aug 2024 21:10:27 +0100 Subject: [PATCH 196/205] installed NuGet for external package installation installing Moq and/or NSubstitute for additional testing capabilities (mocking) --- Assets/NuGet.config | 18 ++++++++++++++++++ Assets/NuGet.config.meta | 23 +++++++++++++++++++++++ Assets/Packages.meta | 8 ++++++++ Assets/packages.config | 2 ++ Assets/packages.config.meta | 23 +++++++++++++++++++++++ Packages/manifest.json | 1 + Packages/packages-lock.json | 7 +++++++ 7 files changed, 82 insertions(+) create mode 100644 Assets/NuGet.config create mode 100644 Assets/NuGet.config.meta create mode 100644 Assets/Packages.meta create mode 100644 Assets/packages.config create mode 100644 Assets/packages.config.meta diff --git a/Assets/NuGet.config b/Assets/NuGet.config new file mode 100644 index 00000000..0c083882 --- /dev/null +++ b/Assets/NuGet.config @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Assets/NuGet.config.meta b/Assets/NuGet.config.meta new file mode 100644 index 00000000..6bb433b0 --- /dev/null +++ b/Assets/NuGet.config.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: 4c03ced04def442739ac3bc72230631f +labels: +- NuGetForUnity +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages.meta b/Assets/Packages.meta new file mode 100644 index 00000000..6b3de99d --- /dev/null +++ b/Assets/Packages.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4503759626e3a4441ad556fa0f9a6b7b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/packages.config b/Assets/packages.config new file mode 100644 index 00000000..3299dfcf --- /dev/null +++ b/Assets/packages.config @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Assets/packages.config.meta b/Assets/packages.config.meta new file mode 100644 index 00000000..f617de66 --- /dev/null +++ b/Assets/packages.config.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: 1ef0f99920d9747f892633a1f8ca633d +labels: +- NuGetForUnity +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/manifest.json b/Packages/manifest.json index a1eeaeef..53650a55 100644 --- a/Packages/manifest.json +++ b/Packages/manifest.json @@ -1,5 +1,6 @@ { "dependencies": { + "com.github-glitchenzo.nugetforunity": "https://github.com/GlitchEnzo/NuGetForUnity.git?path=/src/NuGetForUnity", "com.unity.collab-proxy": "2.1.0", "com.unity.ide.rider": "3.0.31", "com.unity.ide.visualstudio": "2.0.22", diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json index 25e67563..94e60b30 100644 --- a/Packages/packages-lock.json +++ b/Packages/packages-lock.json @@ -1,5 +1,12 @@ { "dependencies": { + "com.github-glitchenzo.nugetforunity": { + "version": "https://github.com/GlitchEnzo/NuGetForUnity.git?path=/src/NuGetForUnity", + "depth": 0, + "source": "git", + "dependencies": {}, + "hash": "90fa6db024148d466fe738f58fd4263c7267346b" + }, "com.unity.barracuda": { "version": "3.0.0", "depth": 1, From 19bed32c41f60f8dd8c713133be9de8e3983e1f1 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Thu, 15 Aug 2024 22:24:21 +0100 Subject: [PATCH 197/205] simplified fulldecaygoal.cs principle method from feedback from tests. --- Assets/Scripts/Rewards/FullDecayGoal.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Assets/Scripts/Rewards/FullDecayGoal.cs b/Assets/Scripts/Rewards/FullDecayGoal.cs index c825169d..05537b07 100644 --- a/Assets/Scripts/Rewards/FullDecayGoal.cs +++ b/Assets/Scripts/Rewards/FullDecayGoal.cs @@ -31,9 +31,9 @@ public class FullDecayGoal : BallGoal public float decayRate = -0.001f; public bool flipDecayDirection = false; - private Material _mat; - private bool isDecaying = false; - private float middleDecayProportion; + public Material _mat; + public bool isDecaying = false; + public float middleDecayProportion; private float decayWidth; void Awake() @@ -83,7 +83,7 @@ void Awake() StartDecay(); } - void StartDecay(bool reset = false) + public void StartDecay(bool reset = false) { isDecaying = true; if (reset) @@ -92,7 +92,7 @@ void StartDecay(bool reset = false) } } - void StopDecay(bool reset = false) + public void StopDecay(bool reset = false) { isDecaying = false; if (reset) @@ -127,7 +127,7 @@ bool IsBadGoal() return useBadEpisodeEndThreshold && reward <= badRewardEndThreshold; } - void FixedUpdate() + public void FixedUpdate() { if (IsGoodGoal() || IsBadGoal()) { @@ -220,7 +220,7 @@ private void UpdateColour(float p) } } - float GetProportion(float r) + public float GetProportion(float r) { return (r - Mathf.Min(initialReward, finalReward)) / decayWidth; } From 4d1687e9342edaa19e53f57c6662d3692e7bbef9 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Thu, 15 Aug 2024 22:30:27 +0100 Subject: [PATCH 198/205] fixed a bug where colors wre not updating properly --- Assets/Scripts/Rewards/FullDecayGoal.cs | 37 ++++++++----------------- 1 file changed, 11 insertions(+), 26 deletions(-) diff --git a/Assets/Scripts/Rewards/FullDecayGoal.cs b/Assets/Scripts/Rewards/FullDecayGoal.cs index 05537b07..9e83457d 100644 --- a/Assets/Scripts/Rewards/FullDecayGoal.cs +++ b/Assets/Scripts/Rewards/FullDecayGoal.cs @@ -181,43 +181,28 @@ private void UpdateValue(float rate) ); } - private void UpdateColour(float p) + public void UpdateColour(float p) { - if (p != Mathf.Clamp(p, 0, 1)) - { - Debug.Log("UpdateColour passed a bad proprtion! Clamping . . ."); - p = Mathf.Clamp(p, 0, 1); - } + p = Mathf.Clamp(p, 0f, 1f); + + Color targetColor; if (useMiddle && p < middleDecayProportion) { - p = (p / middleDecayProportion); - _mat.SetColor( - "_EmissionColor", - p * neutralColour - + (1 - p) * badColour - + (0.5f - Mathf.Abs(p - 0.5f)) * Color.white * 0.1f - ); + p = p / middleDecayProportion; + targetColor = Color.Lerp(badColour, neutralColour, p); } else if (useMiddle) { - p = ((p - middleDecayProportion) / (1 - middleDecayProportion)); - _mat.SetColor( - "_EmissionColor", - p * goodColour - + (1 - p) * neutralColour - + (0.5f - Mathf.Abs(p - 0.5f)) * Color.white * 0.1f - ); + p = (p - middleDecayProportion) / (1 - middleDecayProportion); + targetColor = Color.Lerp(neutralColour, goodColour, p); } else { - _mat.SetColor( - "_EmissionColor", - p * goodColour - + (1 - p) * badColour - + (0.5f - Mathf.Abs(p - 0.5f)) * Color.white * 0.1f - ); + targetColor = Color.Lerp(badColour, goodColour, p); } + + _mat.SetColor("_EmissionColor", targetColor); } public float GetProportion(float r) From 1f367e65b9bbee11fbe53bf4485cd414a37043f6 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Thu, 15 Aug 2024 22:31:15 +0100 Subject: [PATCH 199/205] added tests for fulldecaygoal.cs playmode tests --- .../Playmode/FullDecayGoalPlayModeTests.cs | 119 ++++++++++++++++++ .../FullDecayGoalPlayModeTests.cs.meta | 11 ++ 2 files changed, 130 insertions(+) create mode 100644 Assets/Tests/Playmode/FullDecayGoalPlayModeTests.cs create mode 100644 Assets/Tests/Playmode/FullDecayGoalPlayModeTests.cs.meta diff --git a/Assets/Tests/Playmode/FullDecayGoalPlayModeTests.cs b/Assets/Tests/Playmode/FullDecayGoalPlayModeTests.cs new file mode 100644 index 00000000..16c07292 --- /dev/null +++ b/Assets/Tests/Playmode/FullDecayGoalPlayModeTests.cs @@ -0,0 +1,119 @@ +using UnityEngine; +using UnityEngine.TestTools; +using NUnit.Framework; +using System.Collections; + +/// +/// Tests for the FullDecayGoal class. +/// +public class FullDecayGoalPlayModeTests +{ + private GameObject _goalObject; + private FullDecayGoal _fullDecayGoal; + + [UnitySetUp] + public IEnumerator Setup() + { + _goalObject = new GameObject("FullDecayGoal"); + + _goalObject.AddComponent(); + _goalObject.AddComponent(); + _fullDecayGoal = _goalObject.AddComponent(); + + _fullDecayGoal.initialReward = 10f; + _fullDecayGoal.finalReward = 0f; + _fullDecayGoal.decayRate = -0.1f; + + _fullDecayGoal.StartDecay(reset: true); + + yield return null; + } + + [UnityTest] + public IEnumerator DecayBehavior_ShouldDecayRewardOverTime() + { + float initialReward = _fullDecayGoal.reward; + _fullDecayGoal.StartDecay(reset: true); + yield return new WaitForSeconds(1.0f); + Assert.Less(_fullDecayGoal.reward, initialReward, "Reward did not decay over time."); + } + + [UnityTest] + public IEnumerator EpisodeEndCondition_ShouldSetCorrectly() + { + _fullDecayGoal.useGoodEpisodeEndThreshold = true; + _fullDecayGoal.goodRewardEndThreshold = 7f; + + _fullDecayGoal.reward = 8f; + _fullDecayGoal.FixedUpdate(); + Assert.IsFalse(_fullDecayGoal.isMulti, "Episode should have ended."); + + yield return null; + } + + [UnityTest] + public IEnumerator StartDecay_ShouldBeginDecay() + { + _fullDecayGoal.StartDecay(reset: true); + Assert.IsTrue(_fullDecayGoal.isDecaying, "Decay did not start."); + yield return null; + } + + [UnityTest] + public IEnumerator StopDecay_ShouldStopDecay() + { + _fullDecayGoal.StartDecay(); + _fullDecayGoal.StopDecay(reset: true); + Assert.IsFalse(_fullDecayGoal.isDecaying, "Decay did not stop."); + Assert.AreEqual( + _fullDecayGoal.reward, + _fullDecayGoal.finalReward, + "Reward did not reset to final reward." + ); + yield return null; + } + + [UnityTest] + public IEnumerator ColorUpdate_ShouldUpdateColorBasedOnReward() + { + float p = 0.25f; + _fullDecayGoal.UpdateColour(p); + + Color expectedColor; + if (_fullDecayGoal.useMiddle && p < _fullDecayGoal.middleDecayProportion) + { + p = p / _fullDecayGoal.middleDecayProportion; + expectedColor = Color.Lerp(_fullDecayGoal.badColour, _fullDecayGoal.neutralColour, p); + } + else if (_fullDecayGoal.useMiddle) + { + p = + (p - _fullDecayGoal.middleDecayProportion) + / (1 - _fullDecayGoal.middleDecayProportion); + expectedColor = Color.Lerp(_fullDecayGoal.neutralColour, _fullDecayGoal.goodColour, p); + } + else + { + expectedColor = Color.Lerp(_fullDecayGoal.badColour, _fullDecayGoal.goodColour, p); + } + + Color actualColor = _fullDecayGoal + .GetComponent() + .material.GetColor("_EmissionColor"); + + Assert.IsTrue( + AreColorsEqualWithTolerance(expectedColor, actualColor, 0.01f), + $"Color did not update correctly based on reward. Expected: {expectedColor}, But was: {actualColor}" + ); + + yield return null; + } + + private bool AreColorsEqualWithTolerance(Color color1, Color color2, float tolerance) + { + return Mathf.Abs(color1.r - color2.r) < tolerance + && Mathf.Abs(color1.g - color2.g) < tolerance + && Mathf.Abs(color1.b - color2.b) < tolerance + && Mathf.Abs(color1.a - color2.a) < tolerance; + } +} diff --git a/Assets/Tests/Playmode/FullDecayGoalPlayModeTests.cs.meta b/Assets/Tests/Playmode/FullDecayGoalPlayModeTests.cs.meta new file mode 100644 index 00000000..d69c0553 --- /dev/null +++ b/Assets/Tests/Playmode/FullDecayGoalPlayModeTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 13e88aeb500fb41719f2d451dfb528b5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 99e51c93e1514f2f80c4622621e7b9cb5cf1dd4d Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Fri, 16 Aug 2024 11:00:19 +0100 Subject: [PATCH 200/205] fixed a bug where the force would not apply in time ...to ballgoalbounce objects. Added an update method to be called by unity directly. Error fixed and test case updated. --- Assets/Scripts/Rewards/BallGoalBounce.cs | 16 ++++++++++++---- Assets/Tests/Playmode/BallGoalBounceTests.cs | 6 ++++-- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/Assets/Scripts/Rewards/BallGoalBounce.cs b/Assets/Scripts/Rewards/BallGoalBounce.cs index 5819931f..43be61ba 100644 --- a/Assets/Scripts/Rewards/BallGoalBounce.cs +++ b/Assets/Scripts/Rewards/BallGoalBounce.cs @@ -14,10 +14,18 @@ public class BallGoalBounce : BallGoal void Start() { rBody = GetComponent(); + if (rBody != null) + { + rBody.AddForce(transform.forward * forceToApply, ForceMode.Impulse); + } + } - rBody.AddForce( - forceToApply * transform.forward * Time.fixedDeltaTime, - ForceMode.VelocityChange - ); + void Update() + { + /* Cap the velocity to the maximum velocity */ + if (rBody != null && rBody.velocity.magnitude > maximumVelocity) + { + rBody.velocity = rBody.velocity.normalized * maximumVelocity; + } } } diff --git a/Assets/Tests/Playmode/BallGoalBounceTests.cs b/Assets/Tests/Playmode/BallGoalBounceTests.cs index 0f585605..c7c36169 100644 --- a/Assets/Tests/Playmode/BallGoalBounceTests.cs +++ b/Assets/Tests/Playmode/BallGoalBounceTests.cs @@ -6,7 +6,7 @@ /// /// Tests for the BallGoalBounce class. /// -public class BallGoalBounceTests : MonoBehaviour +public class BallGoalBounceTests { private GameObject _ballGameObject; private BallGoalBounce _ballGoalBounce; @@ -62,9 +62,11 @@ public IEnumerator BallGoalBounce_RigidbodyIsInitialized() [UnityTest] public IEnumerator BallGoalBounce_ForceDirectionIsForward() { + /* Wait for the next fixed update to ensure the force is applied */ + yield return new WaitForFixedUpdate(); yield return null; - // XZ directions only, no need to check Y + /* XZ directions only, no need to check Y */ Vector3 expectedDirectionXZ = new Vector3( _ballGameObject.transform.forward.x, 0, From 2cf2b592ccc39cc2021bb2b7e3d434b2d6bfb318 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Fri, 16 Aug 2024 12:51:20 +0100 Subject: [PATCH 201/205] minor reformat --- Assets/Resources/test_configs/every_object_spawn_test.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Assets/Resources/test_configs/every_object_spawn_test.yaml b/Assets/Resources/test_configs/every_object_spawn_test.yaml index a7b29b7f..75372eed 100644 --- a/Assets/Resources/test_configs/every_object_spawn_test.yaml +++ b/Assets/Resources/test_configs/every_object_spawn_test.yaml @@ -189,6 +189,7 @@ arenas: - !Vector3 {x: 35, y: 15, z: 9} sizes: - !Vector3 {x: 1, y: 1, z: 1} + - !Item name: GoodGoalBounce positions: From da58497c08698d4abf9de2ad2a7e626a6ce454d3 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Fri, 16 Aug 2024 13:00:57 +0100 Subject: [PATCH 202/205] fixed misplaced masses on movable objects: The objects now have increased masses to reflect their purposes. J/L/U Blocks: 180 Light/Heavy Blocks: 220/440 --- Assets/Prefabs/Moveable/HeavyBlock.prefab | 4 ++-- Assets/Prefabs/Moveable/JBlock.prefab | 4 ++-- Assets/Prefabs/Moveable/LBlock.prefab | 4 ++-- Assets/Prefabs/Moveable/LightBlock.prefab | 4 ++-- Assets/Prefabs/Moveable/UBlock.prefab | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Assets/Prefabs/Moveable/HeavyBlock.prefab b/Assets/Prefabs/Moveable/HeavyBlock.prefab index b4a0e0b6..40c63a9f 100644 --- a/Assets/Prefabs/Moveable/HeavyBlock.prefab +++ b/Assets/Prefabs/Moveable/HeavyBlock.prefab @@ -108,7 +108,7 @@ Rigidbody: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 100000} serializedVersion: 2 - m_Mass: 2 + m_Mass: 420 m_Drag: 0 m_AngularDrag: 0.05 m_UseGravity: 1 @@ -133,6 +133,6 @@ MonoBehaviour: sizeMax: {x: 10, y: 10, z: 10} canRandomizeColor: 0 ratioSize: {x: 1, y: 1, z: 1} - sizeAdjustement: 0.999 + sizeAdjustment: 0.999 textureUVOverride: 0 typicalOrigin: 1 diff --git a/Assets/Prefabs/Moveable/JBlock.prefab b/Assets/Prefabs/Moveable/JBlock.prefab index b1629375..dacf97a5 100644 --- a/Assets/Prefabs/Moveable/JBlock.prefab +++ b/Assets/Prefabs/Moveable/JBlock.prefab @@ -52,7 +52,7 @@ Rigidbody: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 2677753433345384935} serializedVersion: 2 - m_Mass: 1.5 + m_Mass: 180 m_Drag: 0 m_AngularDrag: 0.05 m_UseGravity: 1 @@ -132,6 +132,6 @@ MonoBehaviour: sizeMax: {x: 5, y: 2, z: 20} canRandomizeColor: 0 ratioSize: {x: 0.3, y: 1, z: 0.1} - sizeAdjustement: 0.999 + sizeAdjustment: 0.999 textureUVOverride: 0 typicalOrigin: 1 diff --git a/Assets/Prefabs/Moveable/LBlock.prefab b/Assets/Prefabs/Moveable/LBlock.prefab index 8be2d89d..74f74b10 100644 --- a/Assets/Prefabs/Moveable/LBlock.prefab +++ b/Assets/Prefabs/Moveable/LBlock.prefab @@ -94,7 +94,7 @@ Rigidbody: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1667824677047789405} serializedVersion: 2 - m_Mass: 1.5 + m_Mass: 180 m_Drag: 0 m_AngularDrag: 0.05 m_UseGravity: 1 @@ -132,6 +132,6 @@ MonoBehaviour: sizeMax: {x: 5, y: 2, z: 20} canRandomizeColor: 0 ratioSize: {x: 0.3, y: 1, z: 0.1} - sizeAdjustement: 0.999 + sizeAdjustment: 0.999 textureUVOverride: 0 typicalOrigin: 1 diff --git a/Assets/Prefabs/Moveable/LightBlock.prefab b/Assets/Prefabs/Moveable/LightBlock.prefab index bf8e4efe..e23695c5 100644 --- a/Assets/Prefabs/Moveable/LightBlock.prefab +++ b/Assets/Prefabs/Moveable/LightBlock.prefab @@ -108,7 +108,7 @@ Rigidbody: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 100000} serializedVersion: 2 - m_Mass: 1 + m_Mass: 220 m_Drag: 0 m_AngularDrag: 0.05 m_UseGravity: 1 @@ -133,6 +133,6 @@ MonoBehaviour: sizeMax: {x: 10, y: 10, z: 10} canRandomizeColor: 0 ratioSize: {x: 1, y: 1, z: 1} - sizeAdjustement: 0.999 + sizeAdjustment: 0.999 textureUVOverride: 0 typicalOrigin: 1 diff --git a/Assets/Prefabs/Moveable/UBlock.prefab b/Assets/Prefabs/Moveable/UBlock.prefab index fba46b59..08dbdb02 100644 --- a/Assets/Prefabs/Moveable/UBlock.prefab +++ b/Assets/Prefabs/Moveable/UBlock.prefab @@ -107,7 +107,7 @@ Rigidbody: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 6620029679494263603} serializedVersion: 2 - m_Mass: 1.5 + m_Mass: 180 m_Drag: 0 m_AngularDrag: 0.05 m_UseGravity: 1 @@ -132,6 +132,6 @@ MonoBehaviour: sizeMax: {x: 5, y: 2, z: 20} canRandomizeColor: 0 ratioSize: {x: 0.3, y: 1, z: 0.1} - sizeAdjustement: 0.999 + sizeAdjustment: 0.999 textureUVOverride: 0 typicalOrigin: 1 From 6bacc1b87d2ab3ba3df868e2ca63c757bcbe2714 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Fri, 16 Aug 2024 13:15:12 +0100 Subject: [PATCH 203/205] Fixed object collider issues The original colliders set to these objects were partially setup. They are now complete. Fixes the issues where the agent would go through the object's part where no collider was set (i.e., corners of the UBlock). --- Assets/Prefabs/Moveable/JBlock.prefab | 42 +++++++++++++------- Assets/Prefabs/Moveable/LBlock.prefab | 42 +++++++++++++------- Assets/Prefabs/Moveable/UBlock.prefab | 56 ++++++++++++++++++++------- 3 files changed, 98 insertions(+), 42 deletions(-) diff --git a/Assets/Prefabs/Moveable/JBlock.prefab b/Assets/Prefabs/Moveable/JBlock.prefab index dacf97a5..aff26adb 100644 --- a/Assets/Prefabs/Moveable/JBlock.prefab +++ b/Assets/Prefabs/Moveable/JBlock.prefab @@ -12,8 +12,9 @@ GameObject: - component: {fileID: 2906799365264366119} - component: {fileID: 6046221030157881141} - component: {fileID: 771830132221317487} - - component: {fileID: 2929563314707697068} - component: {fileID: 4489711801502536768} + - component: {fileID: 6191250875533515990} + - component: {fileID: 5107927406425999282} m_Layer: 0 m_Name: JBlock m_TagString: Movable @@ -102,19 +103,6 @@ MeshRenderer: m_SortingLayer: 0 m_SortingOrder: 0 m_AdditionalVertexStreams: {fileID: 0} ---- !u!65 &2929563314707697068 -BoxCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2677753433345384935} - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_Enabled: 1 - serializedVersion: 2 - m_Size: {x: 1, y: 1.0000001, z: 10} - m_Center: {x: 0, y: 0, z: 0} --- !u!114 &4489711801502536768 MonoBehaviour: m_ObjectHideFlags: 0 @@ -135,3 +123,29 @@ MonoBehaviour: sizeAdjustment: 0.999 textureUVOverride: 0 typicalOrigin: 1 +--- !u!65 &6191250875533515990 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2677753433345384935} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 0.9913508, y: 1.0648708, z: 11.000003} + m_Center: {x: 0.016484648, y: -0.03243506, z: -0.5} +--- !u!65 &5107927406425999282 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2677753433345384935} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 2.0218654, y: 1.0000005, z: 0.990793} + m_Center: {x: -1.4890985, y: 0.00000011920929, z: -5.5046062} diff --git a/Assets/Prefabs/Moveable/LBlock.prefab b/Assets/Prefabs/Moveable/LBlock.prefab index 74f74b10..6726c075 100644 --- a/Assets/Prefabs/Moveable/LBlock.prefab +++ b/Assets/Prefabs/Moveable/LBlock.prefab @@ -12,8 +12,9 @@ GameObject: - component: {fileID: 3667777653325770547} - component: {fileID: 8227840235879712070} - component: {fileID: 7053897899704093071} - - component: {fileID: 2477514626128410859} - component: {fileID: 883459942026187514} + - component: {fileID: 5412319763096046578} + - component: {fileID: 1244654332007024094} m_Layer: 0 m_Name: LBlock m_TagString: Movable @@ -102,19 +103,6 @@ Rigidbody: m_Interpolate: 0 m_Constraints: 0 m_CollisionDetection: 0 ---- !u!65 &2477514626128410859 -BoxCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1667824677047789405} - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_Enabled: 1 - serializedVersion: 2 - m_Size: {x: 1, y: 1.0000001, z: 10} - m_Center: {x: 0, y: 0, z: 0} --- !u!114 &883459942026187514 MonoBehaviour: m_ObjectHideFlags: 0 @@ -135,3 +123,29 @@ MonoBehaviour: sizeAdjustment: 0.999 textureUVOverride: 0 typicalOrigin: 1 +--- !u!65 &5412319763096046578 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1667824677047789405} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 0.96518517, y: 1.0000001, z: 11.000003} + m_Center: {x: -0.017407402, y: 0, z: -0.5} +--- !u!65 &1244654332007024094 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1667824677047789405} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 2.021222, y: 1.0000001, z: 0.9552109} + m_Center: {x: 1.4894192, y: 0, z: -5.522398} diff --git a/Assets/Prefabs/Moveable/UBlock.prefab b/Assets/Prefabs/Moveable/UBlock.prefab index 08dbdb02..19b244cb 100644 --- a/Assets/Prefabs/Moveable/UBlock.prefab +++ b/Assets/Prefabs/Moveable/UBlock.prefab @@ -11,9 +11,11 @@ GameObject: - component: {fileID: 1400055329670901477} - component: {fileID: 4797399803017511704} - component: {fileID: 3702795677584233617} - - component: {fileID: 6545415511165062603} - component: {fileID: 3251078423981891041} - component: {fileID: 4663744031587436180} + - component: {fileID: 4099879433487610999} + - component: {fileID: 696870783357043904} + - component: {fileID: 6974275105700984726} m_Layer: 0 m_Name: UBlock m_TagString: Movable @@ -86,19 +88,6 @@ MeshRenderer: m_SortingLayer: 0 m_SortingOrder: 0 m_AdditionalVertexStreams: {fileID: 0} ---- !u!65 &6545415511165062603 -BoxCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 6620029679494263603} - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_Enabled: 1 - serializedVersion: 2 - m_Size: {x: 1, y: 1, z: 10} - m_Center: {x: 0, y: 0, z: 0} --- !u!54 &3251078423981891041 Rigidbody: m_ObjectHideFlags: 0 @@ -135,3 +124,42 @@ MonoBehaviour: sizeAdjustment: 0.999 textureUVOverride: 0 typicalOrigin: 1 +--- !u!65 &4099879433487610999 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6620029679494263603} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1.0029163, y: 1.0000001, z: 12.000003} + m_Center: {x: 0.001457572, y: 0, z: -1.3877788e-17} +--- !u!65 &696870783357043904 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6620029679494263603} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1.9954269, y: 1.0000001, z: 1.0014155} + m_Center: {x: 1.5023204, y: 0, z: -5.499296} +--- !u!65 &6974275105700984726 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6620029679494263603} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 2.003068, y: 1.0000001, z: 0.99136424} + m_Center: {x: 1.5130353, y: 0, z: 5.5043273} From 6cbc219db7c6a40b977a1f19848c0a45312f57a0 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Fri, 16 Aug 2024 13:20:49 +0100 Subject: [PATCH 204/205] increased datazone mass to 180 for better physics handling --- Assets/Prefabs/DataZone/DataZone.prefab | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/Prefabs/DataZone/DataZone.prefab b/Assets/Prefabs/DataZone/DataZone.prefab index 5c9379ce..fa335833 100644 --- a/Assets/Prefabs/DataZone/DataZone.prefab +++ b/Assets/Prefabs/DataZone/DataZone.prefab @@ -52,7 +52,7 @@ Rigidbody: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 7041498159436349378} serializedVersion: 2 - m_Mass: 1 + m_Mass: 180 m_Drag: 0 m_AngularDrag: 0.05 m_UseGravity: 1 From 594c7f3e8a94242b97bb5da9526e6308d0a2a939 Mon Sep 17 00:00:00 2001 From: Ibrahim Alhas <65875290+alhasacademy96@users.noreply.github.com> Date: Fri, 16 Aug 2024 14:16:33 +0100 Subject: [PATCH 205/205] removed redundant method comments for less clutter --- Assets/Scripts/ArenasParametersSideChannel.cs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/Assets/Scripts/ArenasParametersSideChannel.cs b/Assets/Scripts/ArenasParametersSideChannel.cs index ec727f04..e6b4e044 100644 --- a/Assets/Scripts/ArenasParametersSideChannel.cs +++ b/Assets/Scripts/ArenasParametersSideChannel.cs @@ -16,21 +16,15 @@ public ArenasParametersSideChannel() ChannelId = new Guid("9c36c837-cad5-498a-b675-bc19c9370072"); } - /// - /// This method is called when a message is received from the Unity. - /// protected override void OnMessageReceived(IncomingMessage msg) { byte[] yamlData = msg.GetRawBytes(); - /* Create the event args including the file name and the YAML data */ + /* Create the event args and the YAML data */ ArenasParametersEventArgs args = new ArenasParametersEventArgs { arenas_yaml = yamlData, }; OnArenasParametersReceived(args); } - /// - /// This method is called when the arenas parameters are received. - /// protected virtual void OnArenasParametersReceived( ArenasParametersEventArgs arenasParametersEvent )