From d2c9cde1d2a74855fcbfe17711d8475ddbe5fca4 Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Sat, 13 Jun 2020 15:23:52 -0400 Subject: [PATCH 01/34] Fix double event call, jankily --- GamecraftModdingAPI/Events/MenuActivatedPatch.cs | 1 + .../Events/SimpleEventHandlerEngine.cs | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/GamecraftModdingAPI/Events/MenuActivatedPatch.cs b/GamecraftModdingAPI/Events/MenuActivatedPatch.cs index 2b66a05..4237faa 100644 --- a/GamecraftModdingAPI/Events/MenuActivatedPatch.cs +++ b/GamecraftModdingAPI/Events/MenuActivatedPatch.cs @@ -31,6 +31,7 @@ namespace GamecraftModdingAPI.Events { firstLoad = false; FullGameFields.Init(__instance); + //Application.Application.SetFullGameCompositionRoot(__instance); Logging.Log("Dispatching App Init event"); EventManager.GetEventEmitter("GamecraftModdingAPIApplicationInitializedEventEmitter").Emit(); } diff --git a/GamecraftModdingAPI/Events/SimpleEventHandlerEngine.cs b/GamecraftModdingAPI/Events/SimpleEventHandlerEngine.cs index 133ad29..18314d9 100644 --- a/GamecraftModdingAPI/Events/SimpleEventHandlerEngine.cs +++ b/GamecraftModdingAPI/Events/SimpleEventHandlerEngine.cs @@ -20,6 +20,10 @@ namespace GamecraftModdingAPI.Events private bool isActivated = false; + private bool jankActivateFix = false; + + private bool jankDestroyFix = false; + private readonly Action onActivated; private readonly Action onDestroyed; @@ -32,6 +36,8 @@ namespace GamecraftModdingAPI.Events { if (entityView.type.Equals(this.type)) { + jankActivateFix = !jankActivateFix; + if (jankActivateFix) return; isActivated = true; onActivatedInvokeCatchError(entitiesDB); } @@ -51,12 +57,19 @@ namespace GamecraftModdingAPI.Events } } + public void Deactivate() + { + isActivated = false; + } + public void Ready() { } public void Remove(ref ModEventEntityStruct entityView, EGID egid) { if (entityView.type.Equals(this.type) && isActivated) { + jankDestroyFix = !jankDestroyFix; + if (jankDestroyFix) return; isActivated = false; onDestroyedInvokeCatchError(entitiesDB); } From 0d17a1b509a8017c83892db1c6ac0e71e11541da Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Sat, 13 Jun 2020 16:19:12 -0400 Subject: [PATCH 02/34] Update project references --- .../GamecraftModdingAPI.csproj | 539 ++++++++++-------- 1 file changed, 292 insertions(+), 247 deletions(-) diff --git a/GamecraftModdingAPI/GamecraftModdingAPI.csproj b/GamecraftModdingAPI/GamecraftModdingAPI.csproj index d8d84fe..0fdbcfd 100644 --- a/GamecraftModdingAPI/GamecraftModdingAPI.csproj +++ b/GamecraftModdingAPI/GamecraftModdingAPI.csproj @@ -25,6 +25,7 @@ + @@ -43,10 +44,6 @@ ..\ref\Gamecraft_Data\Managed\Unity.Burst.Unsafe.dll ..\..\ref\Gamecraft_Data\Managed\Unity.Burst.Unsafe.dll - - ..\ref\Gamecraft_Data\Managed\Facepunch.Steamworks.Win64.dll - ..\..\ref\Gamecraft_Data\Managed\Facepunch.Steamworks.Win64.dll - ..\ref\Gamecraft_Data\Managed\Rewired_Core.dll ..\..\ref\Gamecraft_Data\Managed\Rewired_Core.dll @@ -59,249 +56,9 @@ ..\ref\Gamecraft_Data\Managed\mscorlib.dll ..\..\ref\Gamecraft_Data\Managed\mscorlib.dll - - ..\ref\Gamecraft_Data\Managed\Newtonsoft.Json.dll - ..\..\ref\Gamecraft_Data\Managed\Newtonsoft.Json.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.AccessibilityModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.AccessibilityModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.AIModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.AIModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.AndroidJNIModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.AndroidJNIModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.AnimationModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.AnimationModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.ARModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.ARModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.AssetBundleModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.AssetBundleModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.AudioModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.AudioModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.ClothModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.ClothModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.ClusterInputModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.ClusterInputModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.ClusterRendererModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.ClusterRendererModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.CoreModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.CoreModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.CrashReportingModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.CrashReportingModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.DirectorModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.DirectorModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.DSPGraphModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.DSPGraphModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.GameCenterModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.GameCenterModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.GridModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.GridModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.HotReloadModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.HotReloadModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.ImageConversionModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.ImageConversionModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.IMGUIModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.IMGUIModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.InputLegacyModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.InputLegacyModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.InputModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.InputModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.JSONSerializeModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.JSONSerializeModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.LocalizationModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.LocalizationModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.ParticleSystemModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.ParticleSystemModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.PerformanceReportingModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.PerformanceReportingModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.Physics2DModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.Physics2DModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.PhysicsModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.PhysicsModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.ProfilerModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.ProfilerModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.ScreenCaptureModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.ScreenCaptureModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.SharedInternalsModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.SharedInternalsModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.SpriteMaskModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.SpriteMaskModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.SpriteShapeModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.SpriteShapeModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.StreamingModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.StreamingModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.SubstanceModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.SubstanceModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.SubsystemsModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.SubsystemsModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.TerrainModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.TerrainModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.TerrainPhysicsModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.TerrainPhysicsModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.TextCoreModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.TextCoreModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.TextRenderingModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.TextRenderingModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.TilemapModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.TilemapModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.TLSModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.TLSModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.UIElementsModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.UIElementsModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.UIModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.UIModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.UmbraModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.UmbraModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.UNETModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.UNETModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.UnityAnalyticsModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityAnalyticsModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.UnityConnectModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityConnectModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.UnityTestProtocolModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityTestProtocolModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestAssetBundleModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestAssetBundleModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestAudioModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestAudioModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestTextureModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestTextureModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestWWWModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestWWWModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.VehiclesModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.VehiclesModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.VFXModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.VFXModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.VideoModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.VideoModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.VRModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.VRModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.WindModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.WindModule.dll - - - ..\ref\Gamecraft_Data\Managed\UnityEngine.XRModule.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.XRModule.dll + + ..\ref\Gamecraft_Data\Managed\Accessibility.dll + ..\..\ref\Gamecraft_Data\Managed\Accessibility.dll ..\ref\Gamecraft_Data\Managed\Analytics.dll @@ -343,6 +100,10 @@ ..\ref\Gamecraft_Data\Managed\DDNA.dll ..\..\ref\Gamecraft_Data\Managed\DDNA.dll + + ..\ref\Gamecraft_Data\Managed\Facepunch.Steamworks.Win64.dll + ..\..\ref\Gamecraft_Data\Managed\Facepunch.Steamworks.Win64.dll + ..\ref\Gamecraft_Data\Managed\FMOD.dll ..\..\ref\Gamecraft_Data\Managed\FMOD.dll @@ -351,10 +112,18 @@ ..\ref\Gamecraft_Data\Managed\FullGame.dll ..\..\ref\Gamecraft_Data\Managed\FullGame.dll + + ..\ref\Gamecraft_Data\Managed\Gamecraft.AudioBlocks.dll + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.AudioBlocks.dll + ..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.ConsoleBlock.dll ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.ConsoleBlock.dll + + ..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.DamagingSurfaceBlock.dll + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.DamagingSurfaceBlock.dll + ..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.GenericPhysicsBlocks.dll ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.GenericPhysicsBlocks.dll @@ -363,6 +132,10 @@ ..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.LogicBlock.dll ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.LogicBlock.dll + + ..\ref\Gamecraft_Data\Managed\GameCraft.Blocks.ProjectileBlock.dll + ..\..\ref\Gamecraft_Data\Managed\GameCraft.Blocks.ProjectileBlock.dll + ..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.TimerBlock.dll ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.TimerBlock.dll @@ -407,6 +180,14 @@ ..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.WorldSpaceGuis.dll ..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.WorldSpaceGuis.dll + + ..\ref\Gamecraft_Data\Managed\Gamecraft.Music.dll + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Music.dll + + + ..\ref\Gamecraft_Data\Managed\Gamecraft.PerformanceWarnings.dll + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.PerformanceWarnings.dll + ..\ref\Gamecraft_Data\Managed\Gamecraft.Tweaks.dll ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Tweaks.dll @@ -415,6 +196,10 @@ ..\ref\Gamecraft_Data\Managed\Gamecraft.Tweaks.Mockup.dll ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Tweaks.Mockup.dll + + ..\ref\Gamecraft_Data\Managed\Gamecraft.VisualEffects.dll + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.VisualEffects.dll + ..\ref\Gamecraft_Data\Managed\Gamecraft.Wires.dll ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Wires.dll @@ -455,10 +240,26 @@ ..\ref\Gamecraft_Data\Managed\MultiplayerTest.dll ..\..\ref\Gamecraft_Data\Managed\MultiplayerTest.dll + + ..\ref\Gamecraft_Data\Managed\netstandard.dll + ..\..\ref\Gamecraft_Data\Managed\netstandard.dll + + + ..\ref\Gamecraft_Data\Managed\Newtonsoft.Json.dll + ..\..\ref\Gamecraft_Data\Managed\Newtonsoft.Json.dll + + + ..\ref\Gamecraft_Data\Managed\Novell.Directory.Ldap.dll + ..\..\ref\Gamecraft_Data\Managed\Novell.Directory.Ldap.dll + ..\ref\Gamecraft_Data\Managed\RCX.ScreenshotTaker.dll ..\..\ref\Gamecraft_Data\Managed\RCX.ScreenshotTaker.dll + + ..\ref\Gamecraft_Data\Managed\RobocraftECS.dll + ..\..\ref\Gamecraft_Data\Managed\RobocraftECS.dll + ..\ref\Gamecraft_Data\Managed\RobocraftX.AccountPreferences.dll ..\..\ref\Gamecraft_Data\Managed\RobocraftX.AccountPreferences.dll @@ -655,6 +456,10 @@ ..\ref\Gamecraft_Data\Managed\Unity.Addressables.dll ..\..\ref\Gamecraft_Data\Managed\Unity.Addressables.dll + + ..\ref\Gamecraft_Data\Managed\Unity.Build.SlimPlayerRuntime.dll + ..\..\ref\Gamecraft_Data\Managed\Unity.Build.SlimPlayerRuntime.dll + ..\ref\Gamecraft_Data\Managed\Unity.Burst.dll ..\..\ref\Gamecraft_Data\Managed\Unity.Burst.dll @@ -775,10 +580,250 @@ ..\ref\Gamecraft_Data\Managed\Unity.Transforms.Hybrid.dll ..\..\ref\Gamecraft_Data\Managed\Unity.Transforms.Hybrid.dll + + ..\ref\Gamecraft_Data\Managed\UnityEngine.AccessibilityModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.AccessibilityModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.AIModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.AIModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.AndroidJNIModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.AndroidJNIModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.AnimationModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.AnimationModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.ARModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.ARModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.AssetBundleModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.AssetBundleModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.AudioModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.AudioModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.ClothModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.ClothModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.ClusterInputModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.ClusterInputModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.ClusterRendererModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.ClusterRendererModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.CoreModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.CoreModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.CrashReportingModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.CrashReportingModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.DirectorModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.DirectorModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.DSPGraphModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.DSPGraphModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.GameCenterModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.GameCenterModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.GridModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.GridModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.HotReloadModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.HotReloadModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.ImageConversionModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.ImageConversionModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.IMGUIModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.IMGUIModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.InputLegacyModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.InputLegacyModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.InputModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.InputModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.JSONSerializeModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.JSONSerializeModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.LocalizationModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.LocalizationModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.ParticleSystemModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.ParticleSystemModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.PerformanceReportingModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.PerformanceReportingModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.Physics2DModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.Physics2DModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.PhysicsModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.PhysicsModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.ProfilerModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.ProfilerModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.ScreenCaptureModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.ScreenCaptureModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.SharedInternalsModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.SharedInternalsModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.SpriteMaskModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.SpriteMaskModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.SpriteShapeModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.SpriteShapeModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.StreamingModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.StreamingModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.SubstanceModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.SubstanceModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.SubsystemsModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.SubsystemsModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.TerrainModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.TerrainModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.TerrainPhysicsModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.TerrainPhysicsModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.TextCoreModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.TextCoreModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.TextRenderingModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.TextRenderingModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.TilemapModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.TilemapModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.TLSModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.TLSModule.dll + ..\ref\Gamecraft_Data\Managed\UnityEngine.UI.dll ..\..\ref\Gamecraft_Data\Managed\UnityEngine.UI.dll + + ..\ref\Gamecraft_Data\Managed\UnityEngine.UIElementsModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.UIElementsModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.UIModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.UIModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.UmbraModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.UmbraModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.UNETModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.UNETModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.UnityAnalyticsModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityAnalyticsModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.UnityConnectModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityConnectModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.UnityTestProtocolModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityTestProtocolModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestAssetBundleModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestAssetBundleModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestAudioModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestAudioModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestTextureModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestTextureModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestWWWModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.UnityWebRequestWWWModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.VehiclesModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.VehiclesModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.VFXModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.VFXModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.VideoModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.VideoModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.VRModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.VRModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.WindModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.WindModule.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.XRModule.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.XRModule.dll + ..\ref\Gamecraft_Data\Managed\uREPL.dll ..\..\ref\Gamecraft_Data\Managed\uREPL.dll From c912f3ba64d16ca9c37ccbe5c3c97ac05e77ece3 Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Wed, 17 Jun 2020 21:04:08 -0400 Subject: [PATCH 03/34] Add Client and Game OOP features (undocumented) --- GamecraftModdingAPI/App/AppCallbacksTest.cs | 31 ++ GamecraftModdingAPI/App/AppEngine.cs | 63 ++++ GamecraftModdingAPI/App/AppExceptions.cs | 42 +++ GamecraftModdingAPI/App/Client.cs | 49 +++ GamecraftModdingAPI/App/Game.cs | 331 ++++++++++++++++++ .../App/GameBuildSimEventEngine.cs | 48 +++ GamecraftModdingAPI/App/GameGameEngine.cs | 80 +++++ GamecraftModdingAPI/App/GameMenuEngine.cs | 128 +++++++ GamecraftModdingAPI/App/StateSyncRegPatch.cs | 26 ++ GamecraftModdingAPI/Main.cs | 2 + GamecraftModdingAPI/Utility/FullGameFields.cs | 10 +- 11 files changed, 809 insertions(+), 1 deletion(-) create mode 100644 GamecraftModdingAPI/App/AppCallbacksTest.cs create mode 100644 GamecraftModdingAPI/App/AppEngine.cs create mode 100644 GamecraftModdingAPI/App/AppExceptions.cs create mode 100644 GamecraftModdingAPI/App/Client.cs create mode 100644 GamecraftModdingAPI/App/Game.cs create mode 100644 GamecraftModdingAPI/App/GameBuildSimEventEngine.cs create mode 100644 GamecraftModdingAPI/App/GameGameEngine.cs create mode 100644 GamecraftModdingAPI/App/GameMenuEngine.cs create mode 100644 GamecraftModdingAPI/App/StateSyncRegPatch.cs diff --git a/GamecraftModdingAPI/App/AppCallbacksTest.cs b/GamecraftModdingAPI/App/AppCallbacksTest.cs new file mode 100644 index 0000000..0c2987b --- /dev/null +++ b/GamecraftModdingAPI/App/AppCallbacksTest.cs @@ -0,0 +1,31 @@ +using System; + +using GamecraftModdingAPI.Tests; + +namespace GamecraftModdingAPI.App +{ +#if TEST + [APITestClass] + public static class AppCallbacksTest + { + [APITestStartUp] + public static void StartUp() + { + // this could be split into 6 separate test cases + Game.Enter += Assert.CallsBack("GameEnter"); + Game.Exit += Assert.CallsBack("GameExit"); + Game.Simulate += Assert.CallsBack("GameSimulate"); + Game.Edit += Assert.CallsBack("GameEdit"); + Client.EnterMenu += Assert.CallsBack("MenuEnter"); + Client.ExitMenu += Assert.CallsBack("MenuExit"); + } + + [APITestCase(TestType.Game)] + public static void Test() + { + // the test is actually completely implemented in StartUp() + // this is here just so it looks less weird (not required) + } + } +#endif +} diff --git a/GamecraftModdingAPI/App/AppEngine.cs b/GamecraftModdingAPI/App/AppEngine.cs new file mode 100644 index 0000000..4f20b7e --- /dev/null +++ b/GamecraftModdingAPI/App/AppEngine.cs @@ -0,0 +1,63 @@ +using System; + +using RobocraftX.GUI.MyGamesScreen; +using RobocraftX.GUI; +using Svelto.ECS; + +using GamecraftModdingAPI.Engines; +using GamecraftModdingAPI.Utility; + +namespace GamecraftModdingAPI.App +{ + public class AppEngine : IFactoryEngine + { + public event EventHandler EnterMenu; + + public event EventHandler ExitMenu; + + public IEntityFactory Factory { set; private get; } + + public string Name => "GamecraftModdingAPIAppEngine"; + + public bool isRemovable => false; + + public EntitiesDB entitiesDB { set; private get; } + + public void Dispose() + { + IsInMenu = false; + ExceptionUtil.InvokeEvent(ExitMenu, this, new MenuEventArgs { }); + } + + public void Ready() + { + IsInMenu = true; + ExceptionUtil.InvokeEvent(EnterMenu, this, new MenuEventArgs { }); + } + + // app functionality + + public bool IsInMenu + { + get; + private set; + } = false; + + public Game[] GetMyGames() + { + EntityCollection mgsevs = entitiesDB.QueryEntities(MyGamesScreenExclusiveGroups.MyGames); + Game[] games = new Game[mgsevs.count]; + for (int i = 0; i < mgsevs.count; i++) + { + Utility.Logging.MetaDebugLog($"Found game named {mgsevs[i].GameName}"); + games[i] = new Game(mgsevs[i].ID); + } + return games; + } + } + + public struct MenuEventArgs + { + + } +} diff --git a/GamecraftModdingAPI/App/AppExceptions.cs b/GamecraftModdingAPI/App/AppExceptions.cs new file mode 100644 index 0000000..2e67695 --- /dev/null +++ b/GamecraftModdingAPI/App/AppExceptions.cs @@ -0,0 +1,42 @@ +using System; +using System.Runtime.Serialization; + +namespace GamecraftModdingAPI.App +{ + public class AppException : GamecraftModdingAPIException + { + public AppException() + { + } + + public AppException(string message) : base(message) + { + } + + public AppException(string message, Exception innerException) : base(message, innerException) + { + } + } + + public class AppStateException : AppException + { + public AppStateException() + { + } + + public AppStateException(string message) : base(message) + { + } + } + + public class GameNotFoundException : AppException + { + public GameNotFoundException() + { + } + + public GameNotFoundException(string message) : base(message) + { + } + } +} diff --git a/GamecraftModdingAPI/App/Client.cs b/GamecraftModdingAPI/App/Client.cs new file mode 100644 index 0000000..2f1f005 --- /dev/null +++ b/GamecraftModdingAPI/App/Client.cs @@ -0,0 +1,49 @@ +using System; + +using UnityEngine; + +using GamecraftModdingAPI.Utility; + +namespace GamecraftModdingAPI.App +{ + public class Client + { + protected static AppEngine appEngine = new AppEngine(); + + public static event EventHandler EnterMenu + { + add => appEngine.EnterMenu += value; + remove => appEngine.EnterMenu -= value; + } + + public static event EventHandler ExitMenu + { + add => appEngine.ExitMenu += value; + remove => appEngine.ExitMenu -= value; + } + + public string Version + { + get => Application.version; + } + + public string UnityVersion + { + get => Application.unityVersion; + } + + public Game[] MyGames + { + get + { + if (!appEngine.IsInMenu) return new Game[0]; + return appEngine.GetMyGames(); + } + } + + internal static void Init() + { + MenuEngineManager.AddMenuEngine(appEngine); + } + } +} diff --git a/GamecraftModdingAPI/App/Game.cs b/GamecraftModdingAPI/App/Game.cs new file mode 100644 index 0000000..0d31abf --- /dev/null +++ b/GamecraftModdingAPI/App/Game.cs @@ -0,0 +1,331 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +using RobocraftX.Common; +using RobocraftX.GUI.MyGamesScreen; +using RobocraftX.StateSync; +using Svelto.ECS; + +using GamecraftModdingAPI.Tasks; +using GamecraftModdingAPI.Utility; +// TODO: exceptions + +namespace GamecraftModdingAPI.App +{ + public class Game + { + protected static GameGameEngine gameEngine = new GameGameEngine(); + protected static GameMenuEngine menuEngine = new GameMenuEngine(); + protected static DebugInterfaceEngine debugOverlayEngine = new DebugInterfaceEngine(); + protected static GameBuildSimEventEngine buildSimEventEngine = new GameBuildSimEventEngine(); + + private List debugIds = new List(); + + private bool menuMode = true; + private bool hasId = false; + + public Game(uint id) : this(new EGID(id, MyGamesScreenExclusiveGroups.MyGames)) + { + } + + public Game(EGID id) + { + this.Id = id.entityID; + this.EGID = id; + this.hasId = true; + menuMode = true; + if (!VerifyMode()) throw new AppStateException("Game cannot be created while not in a game nor in a menu (is the game in a loading screen?)"); + } + + public Game() + { + menuMode = false; + if (!VerifyMode()) throw new AppStateException("Game cannot be created while not in a game nor in a menu (is the game in a loading screen?)"); + if (menuEngine.IsInMenu) throw new GameNotFoundException("Game not found."); + } + + public static Game CurrentGame() + { + return new Game(); + } + + public static Game NewGame() + { + if (!menuEngine.IsInMenu) throw new AppStateException("New Game cannot be created while not in a menu."); + uint nextId = menuEngine.HighestID() + 1; + EGID egid = new EGID(nextId, MyGamesScreenExclusiveGroups.MyGames); + menuEngine.CreateMyGame(egid); + return new Game(egid); + } + + public static event EventHandler Simulate + { + add => buildSimEventEngine.SimulationMode += value; + remove => buildSimEventEngine.SimulationMode -= value; + } + + public static event EventHandler Edit + { + add => buildSimEventEngine.BuildMode += value; + remove => buildSimEventEngine.BuildMode -= value; + } + + public static event EventHandler Enter + { + add => gameEngine.EnterGame += value; + remove => gameEngine.EnterGame -= value; + } + + public static event EventHandler Exit + { + add => gameEngine.ExitGame += value; + remove => gameEngine.ExitGame -= value; + } + + public uint Id + { + get; + private set; + } + + public EGID EGID + { + get; + private set; + } + + public bool MenuItem + { + get => menuMode && hasId; + } + + public string Name + { + get + { + if (!VerifyMode()) return null; + if (menuMode) return menuEngine.GetGameInfo(EGID).GameName; + return GameMode.SaveGameDetails.Name; + } + + set + { + if (!VerifyMode()) return; + if (menuMode) + { + menuEngine.SetGameName(EGID, value); + } + else + { + GameMode.SaveGameDetails.Name = value; + } + } + } + + public string Description + { + get + { + if (!VerifyMode()) return null; + if (menuMode) return menuEngine.GetGameInfo(EGID).GameDescription; + return ""; + } + + set + { + if (!VerifyMode()) return; + if (menuMode) + { + menuEngine.SetGameDescription(EGID, value); + } + else + { + // No description exists in-game + } + } + } + + public string Path + { + get + { + if (!VerifyMode()) return null; + if (menuMode) return menuEngine.GetGameInfo(EGID).SavedGamePath; + return GameMode.SaveGameDetails.Folder; + } + + set + { + if (!VerifyMode()) return; + if (menuMode) + { + menuEngine.GetGameInfo(EGID).SavedGamePath.Set(value); + } + else + { + // this likely breaks things + GameMode.SaveGameDetails = new SaveGameDetails(GameMode.SaveGameDetails.Name, value, GameMode.SaveGameDetails.WorkshopId); + } + } + } + + public ulong WorkshopId + { + get + { + if (!VerifyMode()) return 0uL; + if (menuMode) return 0uL; // MyGames don't have workshop IDs + return GameMode.SaveGameDetails.WorkshopId; + } + + set + { + VerifyMode(); + if (menuMode) + { + // MyGames don't have workshop IDs + // menuEngine.GetGameInfo(EGID).GameName.Set(value); + } + else + { + // this likely breaks things + GameMode.SaveGameDetails = new SaveGameDetails(GameMode.SaveGameDetails.Name, GameMode.SaveGameDetails.Folder, value); + } + } + } + + public bool IsSimulating + { + get + { + if (!VerifyMode()) return false; + return !menuMode && gameEngine.IsTimeRunningMode(); + } + + set + { + if (!VerifyMode()) return; + if (!menuMode && gameEngine.IsTimeRunningMode() != value) + gameEngine.ToggleTimeMode(); + } + } + + public bool IsTimeRunning + { + get => IsSimulating; + + set + { + IsSimulating = value; + } + } + + public bool IsTimeStopped + { + get + { + if (!VerifyMode()) return false; + return !menuMode && gameEngine.IsTimeStoppedMode(); + } + + set + { + if (!VerifyMode()) return; + if (!menuMode && gameEngine.IsTimeStoppedMode() != value) + gameEngine.ToggleTimeMode(); + } + } + + public void ToggleTimeMode() + { + if (!VerifyMode()) return; + if (menuMode || !gameEngine.IsInGame) + { + throw new AppStateException("Game menu item cannot toggle it's time mode"); + } + gameEngine.ToggleTimeMode(); + } + + public void EnterGame() + { + if (!VerifyMode()) return; + if (!hasId) + { + throw new GameNotFoundException("Game has an invalid ID"); + } + ISchedulable task = new Once(() => { menuEngine.EnterGame(EGID); this.menuMode = false; }); + Scheduler.Schedule(task); + } + + public void ExitGame() + { + if (!VerifyMode()) return; + if (menuMode) + { + throw new GameNotFoundException("Cannot exit game using menu ID"); + } + ISchedulable task = new Once(() => { gameEngine.ExitCurrentGame(); this.menuMode = true; }); + Scheduler.Schedule(task); + } + + public void AddDebugInfo(string id, Func contentGetter) + { + if (!VerifyMode()) return; + if (menuMode) + { + throw new GameNotFoundException("Game object references a menu item but AddDebugInfo only works on the currently-loaded game"); + } + debugOverlayEngine.SetInfo(id, contentGetter); + debugIds.Add(id); + } + + public bool RemoveDebugInfo(string id) + { + if (!VerifyMode()) return false; + if (menuMode) + { + throw new GameNotFoundException("Game object references a menu item but RemoveDebugInfo only works on the currently-loaded game"); + } + if (!debugIds.Contains(id)) return false; + debugOverlayEngine.RemoveInfo(id); + return debugIds.Remove(id); + } + + ~Game() + { + foreach (string id in debugIds) + { + debugOverlayEngine.RemoveInfo(id); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool VerifyMode() + { + if (menuMode && (!menuEngine.IsInMenu || gameEngine.IsInGame)) + { + // either game loading or API is broken + return false; + } + if (!menuMode && (menuEngine.IsInMenu || !gameEngine.IsInGame)) + { + // either game loading or API is broken + return false; + } + return true; + } + + internal static void Init() + { + GameEngineManager.AddGameEngine(gameEngine); + GameEngineManager.AddGameEngine(debugOverlayEngine); + MenuEngineManager.AddMenuEngine(menuEngine); + } + + internal static void InitDeterministic(StateSyncRegistrationHelper stateSyncReg) + { + stateSyncReg.AddDeterministicEngine(buildSimEventEngine); + } + } +} diff --git a/GamecraftModdingAPI/App/GameBuildSimEventEngine.cs b/GamecraftModdingAPI/App/GameBuildSimEventEngine.cs new file mode 100644 index 0000000..b4bc049 --- /dev/null +++ b/GamecraftModdingAPI/App/GameBuildSimEventEngine.cs @@ -0,0 +1,48 @@ +using System; + +using RobocraftX.Common; +using RobocraftX.StateSync; +using Svelto.ECS; +using Unity.Jobs; + +using GamecraftModdingAPI.Engines; +using GamecraftModdingAPI.Utility; + +namespace GamecraftModdingAPI.App +{ + public class GameBuildSimEventEngine : IApiEngine, IUnorderedInitializeOnTimeRunningModeEntered, IUnorderedInitializeOnTimeStoppedModeEntered + { + public event EventHandler SimulationMode; + + public event EventHandler BuildMode; + + public string Name => "GamecraftModdingAPIBuildSimEventGameEngine"; + + public bool isRemovable => false; + + public EntitiesDB entitiesDB { set; private get; } + + public void Dispose() { } + + public void Ready() { } + + public JobHandle OnInitializeTimeRunningMode() + { + ExceptionUtil.InvokeEvent(SimulationMode, this, new GameEventArgs { GameName = GameMode.SaveGameDetails.Name, GamePath = GameMode.SaveGameDetails.Folder }); + return default(JobHandle); + } + + public JobHandle OnInitializeTimeStoppedMode() + { + ExceptionUtil.InvokeEvent(BuildMode, this, new GameEventArgs { GameName = GameMode.SaveGameDetails.Name, GamePath = GameMode.SaveGameDetails.Folder }); + return default(JobHandle); + } + } + + public struct GameEventArgs + { + public string GameName; + + public string GamePath; + } +} diff --git a/GamecraftModdingAPI/App/GameGameEngine.cs b/GamecraftModdingAPI/App/GameGameEngine.cs new file mode 100644 index 0000000..9253af2 --- /dev/null +++ b/GamecraftModdingAPI/App/GameGameEngine.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using HarmonyLib; + +using RobocraftX; +using RobocraftX.Common; +using RobocraftX.Schedulers; +using RobocraftX.SimulationModeState; +using Svelto.ECS; +using Svelto.Tasks; +using Svelto.Tasks.Lean; + +using GamecraftModdingAPI.Engines; +using GamecraftModdingAPI.Utility; + +namespace GamecraftModdingAPI.App +{ + public class GameGameEngine : IApiEngine + { + public event EventHandler EnterGame; + + public event EventHandler ExitGame; + + public string Name => "GamecraftModdingAPIGameInfoMenuEngine"; + + public bool isRemovable => false; + + public EntitiesDB entitiesDB { set; private get; } + + public void Dispose() + { + ExceptionUtil.InvokeEvent(ExitGame, this, new GameEventArgs { GameName = GameMode.SaveGameDetails.Name, GamePath = GameMode.SaveGameDetails.Folder }); + IsInGame = false; + } + + public void Ready() + { + ExceptionUtil.InvokeEvent(EnterGame, this, new GameEventArgs { GameName = GameMode.SaveGameDetails.Name, GamePath = GameMode.SaveGameDetails.Folder }); + IsInGame = true; + } + + // game functionality + + public bool IsInGame + { + get; + private set; + } = false; + + public void ExitCurrentGame() + { + ExitCurrentGameAsync().RunOn(Lean.EveryFrameStepRunner_RUNS_IN_TIME_STOPPED_AND_RUNNING); + } + + public IEnumerator ExitCurrentGameAsync() + { + /* + while (Lean.EveryFrameStepRunner_RUNS_IN_TIME_STOPPED_AND_RUNNING.isStopping) { yield return Yield.It; } + AccessTools.Method(typeof(FullGameCompositionRoot), "SwitchToMenu").Invoke(FullGameFields.Instance, new object[0]);*/ + yield return Yield.It; + entitiesDB.QueryEntity(CommonExclusiveGroups.GameSceneEGID).WantsToQuit = true; + entitiesDB.PublishEntityChange(CommonExclusiveGroups.GameSceneEGID); + } + + public bool IsTimeRunningMode() + { + return TimeRunningModeUtil.IsTimeRunningMode(entitiesDB); + } + + public bool IsTimeStoppedMode() + { + return TimeRunningModeUtil.IsTimeStoppedMode(entitiesDB); + } + + public void ToggleTimeMode() + { + TimeRunningModeUtil.ToggleTimeRunningState(entitiesDB); + } + } +} diff --git a/GamecraftModdingAPI/App/GameMenuEngine.cs b/GamecraftModdingAPI/App/GameMenuEngine.cs new file mode 100644 index 0000000..fc2c35f --- /dev/null +++ b/GamecraftModdingAPI/App/GameMenuEngine.cs @@ -0,0 +1,128 @@ +using System; +using HarmonyLib; + +using RobocraftX; +using RobocraftX.Common; +using RobocraftX.GUI; +using RobocraftX.GUI.MyGamesScreen; +using Svelto.ECS; +using Svelto.ECS.Experimental; + +using GamecraftModdingAPI.Engines; +using GamecraftModdingAPI.Utility; + +namespace GamecraftModdingAPI.App +{ + public class GameMenuEngine : IFactoryEngine + { + public IEntityFactory Factory { set; private get; } + + public string Name => "GamecraftModdingAPIGameInfoGameEngine"; + + public bool isRemovable => false; + + public EntitiesDB entitiesDB { set; private get; } + + public void Dispose() + { + IsInMenu = false; + } + + public void Ready() + { + IsInMenu = true; + } + + // game functionality + + public bool IsInMenu + { + get; + private set; + } = false; + + public bool CreateMyGame(EGID id, string path = "", uint thumbnailId = 0, string gameName = "", string creatorName = "", string description = "", long createdDate = 0L) + { + EntityComponentInitializer eci = Factory.BuildEntity(id); + eci.Init(new MyGameDataEntityStruct + { + SavedGamePath = new ECSString(path), + ThumbnailId = thumbnailId, + GameName = new ECSString(gameName), + CreatorName = new ECSString(creatorName), + GameDescription = new ECSString(description), + CreatedDate = createdDate, + }); + // entitiesDB.PublishEntityChange(id); // this will always fail + return true; + } + + public uint HighestID() + { + EntityCollection games = entitiesDB.QueryEntities(MyGamesScreenExclusiveGroups.MyGames); + uint max = 0; + for (int i = 0; i < games.count; i++) + { + if (games[i].ID.entityID > max) + { + max = games[i].ID.entityID; + } + } + return max; + } + + public bool EnterGame(EGID id) + { + if (!ExistsGameInfo(id)) return false; + ref MyGameDataEntityStruct mgdes = ref GetGameInfo(id); + return EnterGame(mgdes.GameName, mgdes.SavedGamePath); + } + + public bool EnterGame(string gameName, string path, ulong workshopId = 0uL, bool autoEnterSim = false) + { + GameMode.CurrentMode = autoEnterSim ? RCXMode.Play : RCXMode.Build; + GameMode.SaveGameDetails = new SaveGameDetails(gameName, path, workshopId); + // the private FullGameCompositionRoot.SwitchToGame() method gets passed to menu items for this reason + AccessTools.Method(typeof(FullGameCompositionRoot), "SwitchToGame").Invoke(FullGameFields.Instance, new object[0]); + return true; + } + + public bool SetGameName(EGID id, string name) + { + if (!ExistsGameInfo(id)) return false; + GetGameInfo(id).GameName.Set(name); + GetGameViewInfo(id).MyGamesSlotComponent.GameName = StringUtil.SanitiseString(name); + return true; + } + + public bool SetGameDescription(EGID id, string name) + { + if (!ExistsGameInfo(id)) return false; + GetGameInfo(id).GameDescription.Set(name); + GetGameViewInfo(id).MyGamesSlotComponent.GameDescription = StringUtil.SanitiseString(name); + return true; + } + + public bool ExistsGameInfo(EGID id) + { + return entitiesDB.Exists(id); + } + + public ref MyGameDataEntityStruct GetGameInfo(EGID id) + { + return ref GetComponent(id); + } + + public ref MyGamesSlotEntityViewStruct GetGameViewInfo(EGID id) + { + return ref GetComponent(new EGID(id.entityID, MyGamesScreenExclusiveGroups.GameSlotGuiEntities)); + } + + public ref T GetComponent(EGID id) where T: struct, IEntityComponent + { + return ref entitiesDB.QueryEntity(id); + } + } + + internal class MyGameDataEntityDescriptor_DamnItFJWhyDidYouMakeThisInternal : GenericEntityDescriptor { } +} diff --git a/GamecraftModdingAPI/App/StateSyncRegPatch.cs b/GamecraftModdingAPI/App/StateSyncRegPatch.cs new file mode 100644 index 0000000..9c2ce68 --- /dev/null +++ b/GamecraftModdingAPI/App/StateSyncRegPatch.cs @@ -0,0 +1,26 @@ +using System; +using System.Reflection; + +using RobocraftX.CR.MainGame; +using RobocraftX.StateSync; + +using HarmonyLib; + +namespace GamecraftModdingAPI.App +{ + [HarmonyPatch] + class StateSyncRegPatch + { + public static void Postfix(StateSyncRegistrationHelper stateSyncReg) + { + // register sim/build events engines + Game.InitDeterministic(stateSyncReg); + } + + [HarmonyTargetMethod] + public static MethodBase Target() + { + return AccessTools.Method(typeof(MainGameCompositionRoot), "DeterministicCompose").MakeGenericMethod(typeof(object)); + } + } +} diff --git a/GamecraftModdingAPI/Main.cs b/GamecraftModdingAPI/Main.cs index bea58e1..aa80e2a 100644 --- a/GamecraftModdingAPI/Main.cs +++ b/GamecraftModdingAPI/Main.cs @@ -72,6 +72,8 @@ namespace GamecraftModdingAPI Block.Init(); GameClient.Init(); AsyncUtils.Init(); + GamecraftModdingAPI.App.Client.Init(); + GamecraftModdingAPI.App.Game.Init(); Logging.MetaLog($"{currentAssembly.GetName().Name} v{currentAssembly.GetName().Version} initialized"); } diff --git a/GamecraftModdingAPI/Utility/FullGameFields.cs b/GamecraftModdingAPI/Utility/FullGameFields.cs index 5291d4a..8fd8895 100644 --- a/GamecraftModdingAPI/Utility/FullGameFields.cs +++ b/GamecraftModdingAPI/Utility/FullGameFields.cs @@ -25,8 +25,15 @@ namespace GamecraftModdingAPI.Utility /// public static class FullGameFields { + public static FullGameCompositionRoot Instance + { + private set; + get; + } = null; + public static MultiplayerInitParameters _multiplayerParams - { get + { + get { return (MultiplayerInitParameters)fgcr?.Field("_multiplayerParams").GetValue(); } @@ -157,6 +164,7 @@ namespace GamecraftModdingAPI.Utility public static void Init(FullGameCompositionRoot instance) { fgcr = new Traverse(instance); + FullGameFields.Instance = instance; } } } From 78122ee445917a8d0cc87cb67c21db024cd6e57b Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Wed, 17 Jun 2020 21:04:40 -0400 Subject: [PATCH 04/34] Add automatic testing functionality --- GamecraftModdingAPI.sln | 3 + .../GamecraftModdingAPI.csproj | 406 +++++++++++++++++- .../Tests/APITestAttributes.cs | 45 ++ GamecraftModdingAPI/Tests/Assert.cs | 64 +++ .../Tests/GamecraftModdingAPIPluginTest.cs | 150 ++++--- GamecraftModdingAPI/Tests/TestRoot.cs | 247 +++++++++++ GamecraftModdingAPI/Tests/TestTest.cs | 52 +++ 7 files changed, 903 insertions(+), 64 deletions(-) create mode 100644 GamecraftModdingAPI/Tests/APITestAttributes.cs create mode 100644 GamecraftModdingAPI/Tests/Assert.cs create mode 100644 GamecraftModdingAPI/Tests/TestRoot.cs create mode 100644 GamecraftModdingAPI/Tests/TestTest.cs diff --git a/GamecraftModdingAPI.sln b/GamecraftModdingAPI.sln index ff9fc7f..6482776 100644 --- a/GamecraftModdingAPI.sln +++ b/GamecraftModdingAPI.sln @@ -9,12 +9,15 @@ Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU + Test|Any CPU = Test|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {7FD5A7D8-4F3E-426A-B07D-7DC70442A4DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7FD5A7D8-4F3E-426A-B07D-7DC70442A4DF}.Debug|Any CPU.Build.0 = Debug|Any CPU {7FD5A7D8-4F3E-426A-B07D-7DC70442A4DF}.Release|Any CPU.ActiveCfg = Release|Any CPU {7FD5A7D8-4F3E-426A-B07D-7DC70442A4DF}.Release|Any CPU.Build.0 = Release|Any CPU + {7FD5A7D8-4F3E-426A-B07D-7DC70442A4DF}.Test|Any CPU.ActiveCfg = Test|Any CPU + {7FD5A7D8-4F3E-426A-B07D-7DC70442A4DF}.Test|Any CPU.Build.0 = Test|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/GamecraftModdingAPI/GamecraftModdingAPI.csproj b/GamecraftModdingAPI/GamecraftModdingAPI.csproj index 0fdbcfd..c78272a 100644 --- a/GamecraftModdingAPI/GamecraftModdingAPI.csproj +++ b/GamecraftModdingAPI/GamecraftModdingAPI.csproj @@ -1,5 +1,4 @@ - - + net472 true @@ -14,19 +13,403 @@ + + DEBUG;TEST;TRACE + + + ..\..\ref\Gamecraft_Data\Managed\Analytics.dll + + + ..\..\ref\Gamecraft_Data\Managed\Assembly-CSharp-firstpass.dll + + + ..\..\ref\Gamecraft_Data\Managed\Assembly-CSharp.dll + + + ..\..\ref\Gamecraft_Data\Managed\Authentication.dll + + + ..\..\ref\Gamecraft_Data\Managed\BlockEntityFactory.dll + + + ..\..\ref\Gamecraft_Data\Managed\Blocks.HUDFeedbackBlocks.dll + + + ..\..\ref\Gamecraft_Data\Managed\ClusterToWireConversion.Mock.dll + + + ..\..\ref\Gamecraft_Data\Managed\CommandLine.dll + + + ..\..\ref\Gamecraft_Data\Managed\DataLoader.dll + + + ..\..\ref\Gamecraft_Data\Managed\DDNA.dll + + + ..\..\ref\Gamecraft_Data\Managed\FMOD.dll + + + ..\..\ref\Gamecraft_Data\Managed\FullGame.dll + + + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.AudioBlocks.dll + + + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.ConsoleBlock.dll + + + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.DamagingSurfaceBlock.dll + + + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.GenericPhysicsBlocks.dll + + + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.LogicBlock.dll + + + ..\..\ref\Gamecraft_Data\Managed\GameCraft.Blocks.ProjectileBlock.dll + + + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.TimerBlock.dll + + + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.CharacterVulnerability.dll + + + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.CharacterVulnerabilityGui.dll + + + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Effects.dll + + + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.ConsoleBlock.dll + + + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.GraphicsScreen.dll + + + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.HUDFeedbackBlocks.dll + + + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.Tweaks.dll + + + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.Wires.dll + + + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.Wires.Mockup.dll + + + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.WorldSpaceGuis.dll + + + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Music.dll + + + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.PerformanceWarnings.dll + + + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Tweaks.dll + + + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Tweaks.Mockup.dll + + + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.VisualEffects.dll + + + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Wires.dll + + + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Wires.Input.dll + + + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Wires.Mockup.dll + + + ..\..\ref\Gamecraft_Data\Managed\GameState.dll + + + ..\..\ref\Gamecraft_Data\Managed\GPUInstancer.dll + + + ..\..\ref\Gamecraft_Data\Managed\Havok.Physics.dll + + + ..\..\ref\Gamecraft_Data\Managed\Havok.Physics.Hybrid.dll + + + ..\..\ref\Gamecraft_Data\Managed\LZ4.dll + + + ..\..\ref\Gamecraft_Data\Managed\MultiplayerNetworking.dll + + + ..\..\ref\Gamecraft_Data\Managed\MultiplayerTest.dll + + + ..\..\ref\Gamecraft_Data\Managed\RCX.ScreenshotTaker.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftECS.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.AccountPreferences.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.Blocks.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.Blocks.Ghost.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.Blocks.Triggers.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.Building.BoxSelect.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.Building.Jobs.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.Character.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.ClusterToWireConversion.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.Common.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.ControlsScreen.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.Crosshair.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.FrontEnd.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.GUI.BlockLabel.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.GUI.DebugDisplay.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.GUI.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.GUI.RemoveBlock.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.GUI.ScaleGhost.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.GUIs.WorkshopPrefabs.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.Input.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.MachineEditor.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.MainGame.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.MainSimulation.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.MockCharacter.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.Multiplayer.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.Multiplayer.NetworkEntityStream.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.MultiplayerInput.dll + + + ..\..\ref\Gamecraft_Data\Managed\Robocraftx.ObjectIdBlocks.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.Party.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.PartyGui.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.Physics.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.PilotSeat.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.Player.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.Rendering.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.Rendering.Mock.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.SaveAndLoad.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.SaveGameDialog.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.Serializers.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.Services.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.SignalHandling.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX.StateSync.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX_SpawnPoints.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocraftX_TextBlock.dll + + + ..\..\ref\Gamecraft_Data\Managed\RobocratX.SimulationCompositionRoot.dll + + + ..\..\ref\Gamecraft_Data\Managed\StringFormatter.dll + + + ..\..\ref\Gamecraft_Data\Managed\Svelto.Common_3.dll + + + ..\..\ref\Gamecraft_Data\Managed\Svelto.ECS.dll + + + ..\..\ref\Gamecraft_Data\Managed\Svelto.Services.dll + + + ..\..\ref\Gamecraft_Data\Managed\Svelto.Tasks.dll + + + ..\..\ref\Gamecraft_Data\Managed\Unity.Addressables.dll + + + ..\..\ref\Gamecraft_Data\Managed\Unity.Build.SlimPlayerRuntime.dll + + + ..\..\ref\Gamecraft_Data\Managed\Unity.Burst.dll + + + ..\..\ref\Gamecraft_Data\Managed\Unity.Collections.dll + + + ..\..\ref\Gamecraft_Data\Managed\Unity.Deformations.dll + + + ..\..\ref\Gamecraft_Data\Managed\Unity.Entities.dll + + + ..\..\ref\Gamecraft_Data\Managed\Unity.Entities.Hybrid.dll + + + ..\..\ref\Gamecraft_Data\Managed\Unity.Jobs.dll + + + ..\..\ref\Gamecraft_Data\Managed\Unity.Mathematics.dll + + + ..\..\ref\Gamecraft_Data\Managed\Unity.Mathematics.Extensions.dll + + + ..\..\ref\Gamecraft_Data\Managed\Unity.Mathematics.Extensions.Hybrid.dll + + + ..\..\ref\Gamecraft_Data\Managed\Unity.Physics.dll + + + ..\..\ref\Gamecraft_Data\Managed\Unity.Physics.Hybrid.dll + + + ..\..\ref\Gamecraft_Data\Managed\Unity.Platforms.Common.dll + + + ..\..\ref\Gamecraft_Data\Managed\Unity.Postprocessing.Runtime.dll + + + ..\..\ref\Gamecraft_Data\Managed\Unity.Properties.dll + + + ..\..\ref\Gamecraft_Data\Managed\Unity.Properties.Reflection.dll + + + ..\..\ref\Gamecraft_Data\Managed\Unity.Properties.UI.dll + + + ..\..\ref\Gamecraft_Data\Managed\Unity.RenderPipeline.Universal.ShaderLibrary.dll + + + ..\..\ref\Gamecraft_Data\Managed\Unity.RenderPipelines.Core.Runtime.dll + + + ..\..\ref\Gamecraft_Data\Managed\Unity.RenderPipelines.Core.ShaderLibrary.dll + + + ..\..\ref\Gamecraft_Data\Managed\Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary.dll + + + ..\..\ref\Gamecraft_Data\Managed\Unity.RenderPipelines.Universal.Runtime.dll + + + ..\..\ref\Gamecraft_Data\Managed\Unity.RenderPipelines.Universal.Shaders.dll + + + ..\..\ref\Gamecraft_Data\Managed\Unity.ResourceManager.dll + + + ..\..\ref\Gamecraft_Data\Managed\Unity.Scenes.Hybrid.dll + + + ..\..\ref\Gamecraft_Data\Managed\Unity.ScriptableBuildPipeline.dll + + + ..\..\ref\Gamecraft_Data\Managed\Unity.Serialization.dll + + + ..\..\ref\Gamecraft_Data\Managed\Unity.TextMeshPro.dll + + + ..\..\ref\Gamecraft_Data\Managed\Unity.Timeline.dll + + + ..\..\ref\Gamecraft_Data\Managed\Unity.Transforms.dll + + + ..\..\ref\Gamecraft_Data\Managed\Unity.Transforms.Hybrid.dll + + + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.UI.dll + + + ..\..\ref\Gamecraft_Data\Managed\uREPL.dll + + + ..\..\ref\Gamecraft_Data\Managed\VisualProfiler.dll + - - - - - - - + ..\ref\Gamecraft_Data\Managed\IllusionInjector.dll @@ -833,6 +1216,5 @@ ..\..\ref\Gamecraft_Data\Managed\VisualProfiler.dll - - - + + \ No newline at end of file diff --git a/GamecraftModdingAPI/Tests/APITestAttributes.cs b/GamecraftModdingAPI/Tests/APITestAttributes.cs new file mode 100644 index 0000000..8506a56 --- /dev/null +++ b/GamecraftModdingAPI/Tests/APITestAttributes.cs @@ -0,0 +1,45 @@ +using System; +namespace GamecraftModdingAPI.Tests +{ + public enum TestType + { + Menu, + Game, + SimulationMode, + EditMode, + } + + [AttributeUsage(AttributeTargets.Class)] + public class APITestClassAttribute : Attribute + { + internal string Name; + + public APITestClassAttribute(string name = "") + { + this.Name = name; + } + } + + [AttributeUsage(AttributeTargets.Method)] + public class APITestCaseAttribute : Attribute + { + internal TestType TestType; + + public APITestCaseAttribute(TestType testType) + { + this.TestType = testType; + } + } + + [AttributeUsage(AttributeTargets.Method)] + public class APITestStartUpAttribute : Attribute + { + + } + + [AttributeUsage(AttributeTargets.Method)] + public class APITestTearDownAttribute : Attribute + { + + } +} diff --git a/GamecraftModdingAPI/Tests/Assert.cs b/GamecraftModdingAPI/Tests/Assert.cs new file mode 100644 index 0000000..fb03013 --- /dev/null +++ b/GamecraftModdingAPI/Tests/Assert.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Concurrent; +using System.IO; +using System.Runtime.CompilerServices; + +namespace GamecraftModdingAPI.Tests +{ + public static class Assert + { + private static StreamWriter logFile = null; + + private static ConcurrentDictionary callbacks = new ConcurrentDictionary(); + + private const string PASS = "SUCCESS: "; + + private const string FAIL = "FAILURE: "; + + private const string WARN = "WARNING: "; + + private const string INFO = "DEBUG: "; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Log(string msg, string end = "\n") + { + if (logFile == null) openTestLog(); + logFile.Write(msg + end); + logFile.Flush(); + } + + public static EventHandler CallsBack(string eventName, string eventMsg = null) + { + if (eventMsg == null) eventMsg = $"expected callback to {eventName} but it never occurred..."; + callbacks[eventName] = eventMsg; + + return (sender, args) => + { + string value = null; + if (!callbacks.TryRemove(eventName, out value)) { Log(WARN + $"callback to {eventName} occurred again or a related error occurred... (Received '{args.ToString()}' from '{(sender == null ? (string)sender : sender.ToString())}')"); } + Log(PASS + $"callback to {eventName} occurred... (Received '{args.ToString()}' from '{(sender == null ? (string)sender : sender.ToString())}')"); + TestRoot.TestsPassed = true; + }; + } + + internal static void CallsComplete() + { + foreach(string key in callbacks.Keys) + { + Log(FAIL + callbacks[key]); + TestRoot.TestsPassed = false; + } + } + + internal static void CloseLog() + { + if (logFile != null) logFile.Close(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void openTestLog() + { + logFile = File.CreateText(TestRoot.ReportFile); + } + } +} diff --git a/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs b/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs index dc07e1e..fa65ebb 100644 --- a/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs +++ b/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs @@ -48,11 +48,11 @@ namespace GamecraftModdingAPI.Tests GamecraftModdingAPI.Main.Shutdown(); } - public void OnApplicationStart() - { + public void OnApplicationStart() + { FileLog.Reset(); Harmony.DEBUG = true; - GamecraftModdingAPI.Main.Init(); + GamecraftModdingAPI.Main.Init(); Logging.MetaDebugLog($"Version group id {(uint)ApiExclusiveGroups.versionGroup}"); // in case Steam is not installed/running // this will crash the game slightly later during startup @@ -62,7 +62,7 @@ namespace GamecraftModdingAPI.Tests // disable some Gamecraft analytics //AnalyticsDisablerPatch.DisableAnalytics = true; // disable background music - Logging.MetaDebugLog("Audio Mixers: "+string.Join(",", AudioTools.GetMixers())); + Logging.MetaDebugLog("Audio Mixers: " + string.Join(",", AudioTools.GetMixers())); //AudioTools.SetVolume(0.0f, "Music"); // The game now sets this from settings again after this is called :( //Utility.VersionTracking.Enable();//(very) unstable @@ -76,60 +76,68 @@ namespace GamecraftModdingAPI.Tests HandlerBuilder.Builder("menuact API debug") .Handle(EventType.Menu) - .OnActivation(() => { Logging.Log("Menu Activated event!"); }) + .OnActivation(() => { Logging.Log("Menu Activated event!"); }) .OnDestruction(() => { Logging.Log("Menu Destroyed event!"); }) .Build(); HandlerBuilder.Builder("menuswitch API debug") - .Handle(EventType.MenuSwitchedTo) - .OnActivation(() => { Logging.Log("Menu Switched To event!"); }) - .Build(); + .Handle(EventType.MenuSwitchedTo) + .OnActivation(() => { Logging.Log("Menu Switched To event!"); }) + .Build(); HandlerBuilder.Builder("gameact API debug") - .Handle(EventType.Menu) - .OnActivation(() => { Logging.Log("Game Activated event!"); }) - .OnDestruction(() => { Logging.Log("Game Destroyed event!"); }) - .Build(); + .Handle(EventType.Menu) + .OnActivation(() => { Logging.Log("Game Activated event!"); }) + .OnDestruction(() => { Logging.Log("Game Destroyed event!"); }) + .Build(); HandlerBuilder.Builder("gamerel API debug") - .Handle(EventType.GameReloaded) - .OnActivation(() => { Logging.Log("Game Reloaded event!"); }) - .Build(); + .Handle(EventType.GameReloaded) + .OnActivation(() => { Logging.Log("Game Reloaded event!"); }) + .Build(); HandlerBuilder.Builder("gameswitch API debug") - .Handle(EventType.GameSwitchedTo) - .OnActivation(() => { Logging.Log("Game Switched To event!"); }) - .Build(); + .Handle(EventType.GameSwitchedTo) + .OnActivation(() => { Logging.Log("Game Switched To event!"); }) + .Build(); HandlerBuilder.Builder("simulationswitch API debug") - .Handle(EventType.SimulationSwitchedTo) - .OnActivation(() => { Logging.Log("Game Mode Simulation Switched To event!"); }) - .Build(); + .Handle(EventType.SimulationSwitchedTo) + .OnActivation(() => { Logging.Log("Game Mode Simulation Switched To event!"); }) + .Build(); HandlerBuilder.Builder("buildswitch API debug") - .Handle(EventType.BuildSwitchedTo) - .OnActivation(() => { Logging.Log("Game Mode Build Switched To event!"); }) - .Build(); + .Handle(EventType.BuildSwitchedTo) + .OnActivation(() => { Logging.Log("Game Mode Build Switched To event!"); }) + .Build(); HandlerBuilder.Builder("menu activated API error thrower test") .Handle(EventType.Menu) .OnActivation(() => { throw new Exception("Event Handler always throws an exception!"); }) .Build(); - // debug/test commands + /*HandlerBuilder.Builder("enter game from menu test") + .Handle(EventType.Menu) + .OnActivation(() => + { + Tasks.Scheduler.Schedule(new Tasks.Repeatable(enterGame, shouldRetry, 0.2f)); + }) + .Build();*/ + + // debug/test commands if (Dependency.Hell("ExtraCommands")) { CommandBuilder.Builder() - .Name("Exit") - .Description("Close Gamecraft immediately, without any prompts") - .Action(() => { UnityEngine.Application.Quit(); }) - .Build(); - + .Name("Exit") + .Description("Close Gamecraft immediately, without any prompts") + .Action(() => { UnityEngine.Application.Quit(); }) + .Build(); + CommandBuilder.Builder() - .Name("SetFOV") - .Description("Set the player camera's field of view") - .Action((float d) => { UnityEngine.Camera.main.fieldOfView = d; }) - .Build(); + .Name("SetFOV") + .Description("Set the player camera's field of view") + .Action((float d) => { UnityEngine.Camera.main.fieldOfView = d; }) + .Build(); CommandBuilder.Builder() .Name("MoveLastBlock") @@ -144,14 +152,14 @@ namespace GamecraftModdingAPI.Tests }).Build(); CommandBuilder.Builder() - .Name("PlaceAluminium") - .Description("Place a block of aluminium at the given coordinates") - .Action((float x, float y, float z) => - { - var block = Block.PlaceNew(BlockIDs.AluminiumCube, new float3(x, y, z)); - Logging.CommandLog("Block placed with type: " + block.Type); - }) - .Build(); + .Name("PlaceAluminium") + .Description("Place a block of aluminium at the given coordinates") + .Action((float x, float y, float z) => + { + var block = Block.PlaceNew(BlockIDs.AluminiumCube, new float3(x, y, z)); + Logging.CommandLog("Block placed with type: " + block.Type); + }) + .Build(); CommandBuilder.Builder() .Name("PlaceAluminiumLots") @@ -161,8 +169,8 @@ namespace GamecraftModdingAPI.Tests Logging.CommandLog("Starting..."); var sw = Stopwatch.StartNew(); for (int i = 0; i < 100; i++) - for (int j = 0; j < 100; j++) - Block.PlaceNew(BlockIDs.AluminiumCube, new float3(x + i, y, z + j)); + for (int j = 0; j < 100; j++) + Block.PlaceNew(BlockIDs.AluminiumCube, new float3(x + i, y, z + j)); //Block.Sync(); sw.Stop(); Logging.CommandLog("Finished in " + sw.ElapsedMilliseconds + "ms"); @@ -171,10 +179,10 @@ namespace GamecraftModdingAPI.Tests //With Sync(): 1135ms //Without Sync(): 134ms //Async: 348 794ms, doesn't freeze game - //Without Sync() but wait for submission: 530ms - //With Sync() at the end: 380ms + //Without Sync() but wait for submission: 530ms + //With Sync() at the end: 380ms - Block b = null; + Block b = null; CommandBuilder.Builder("moveBlockInSim", "Run in build mode first while looking at a block, then in sim to move it up") .Action(() => { @@ -204,7 +212,7 @@ namespace GamecraftModdingAPI.Tests return; } new Player(PlayerType.Local).GetBlockLookedAt().Color = - new BlockColor {Color = color}; + new BlockColor { Color = color }; Logging.CommandLog("Colored block to " + color); }).Build(); @@ -230,7 +238,7 @@ namespace GamecraftModdingAPI.Tests Block.Removed += (sender, args) => Logging.MetaDebugLog("Removed block " + args.Type + " with ID " + args.ID); - /* + /* CommandManager.AddCommand(new SimpleCustomCommandEngine((float d) => { UnityEngine.Camera.main.fieldOfView = d; }, "SetFOV", "Set the player camera's field of view")); CommandManager.AddCommand(new SimpleCustomCommandEngine( @@ -274,8 +282,8 @@ namespace GamecraftModdingAPI.Tests */ } - // dependency test - if (Dependency.Hell("GamecraftScripting", new Version("0.0.1.0"))) + // dependency test + if (Dependency.Hell("GamecraftScripting", new Version("0.0.1.0"))) { Logging.LogWarning("You're in GamecraftScripting dependency hell"); } @@ -283,7 +291,11 @@ namespace GamecraftModdingAPI.Tests { Logging.Log("Compatible GamecraftScripting detected"); } - } + +#if TEST + TestRoot.RunTests(); +#endif + } private string modsString; private string InstalledMods() @@ -295,6 +307,40 @@ namespace GamecraftModdingAPI.Tests return modsString = sb.ToString(); } + private bool retry = true; + + private bool shouldRetry() + { + return retry; + } + + private void enterGame() + { + App.Client app = new App.Client(); + App.Game[] myGames = app.MyGames; + Logging.MetaDebugLog($"MyGames count {myGames.Length}"); + if (myGames.Length != 0) + { + Logging.MetaDebugLog($"MyGames[0] EGID {myGames[0].EGID}"); + retry = false; + try + { + //myGames[0].Description = "test msg pls ignore"; // make sure game exists first + Logging.MetaDebugLog($"Entering game {myGames[0].Name}"); + myGames[0].EnterGame(); + } + catch (Exception e) + { + Logging.MetaDebugLog($"Failed to enter game; exception: {e}"); + retry = true; + } + } + else + { + Logging.MetaDebugLog("MyGames not populated yet :("); + } + } + public void OnFixedUpdate() { } public void OnLateUpdate() { } diff --git a/GamecraftModdingAPI/Tests/TestRoot.cs b/GamecraftModdingAPI/Tests/TestRoot.cs new file mode 100644 index 0000000..167173f --- /dev/null +++ b/GamecraftModdingAPI/Tests/TestRoot.cs @@ -0,0 +1,247 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; +using System.Linq; // welcome to the dark side + +using Svelto.Tasks; +using Svelto.Tasks.Lean; +using Svelto.Tasks.Enumerators; +using UnityEngine; + +using GamecraftModdingAPI.App; +using GamecraftModdingAPI.Tasks; +using GamecraftModdingAPI.Utility; + +namespace GamecraftModdingAPI.Tests +{ + public static class TestRoot + { + public static bool AutoShutdown = true; + + public const string ReportFile = "GamecraftModdingAPI_tests.log"; + + private static bool _testsPassed = false; + + private static uint _testsCount = 0; + + private static uint _testsCountPassed = 0; + + private static uint _testsCountFailed = 0; + + private static string state = "StartingUp"; + + private static Stopwatch timer; + + private static List testTypes = null; + + public static bool TestsPassed + { + get => _testsPassed; + set + { + _testsPassed = _testsPassed && value; + _testsCount++; + if (value) + { + _testsCountPassed++; + } + else + { + _testsCountFailed++; + } + } + } + + private static void StartUp() + { + // init + timer = Stopwatch.StartNew(); + _testsPassed = true; + _testsCount = 0; + _testsCountPassed = 0; + _testsCountFailed = 0; + // flow control + Game.Enter += (sender, args) => { GameTests().RunOn(RobocraftX.Schedulers.Lean.EveryFrameStepRunner_RUNS_IN_TIME_STOPPED_AND_RUNNING); }; + Game.Exit += (s, a) => state = "ReturningFromGame"; + Client.EnterMenu += (sender, args) => + { + if (state == "EnteringMenu") + { + MenuTests().RunOn(Scheduler.leanRunner); + state = "EnteringGame"; + } + if (state == "ReturningFromGame") + { + TearDown().RunOn(Scheduler.leanRunner); + state = "ShuttingDown"; + } + }; + // init tests here + foreach (Type t in testTypes) + { + foreach (MethodBase m in t.GetMethods()) + { + if (m.GetCustomAttribute() != null) + { + m.Invoke(null, new object[0]); + } + } + } + state = "EnteringMenu"; + } + + private static IEnumerator MenuTests() + { + yield return Yield.It; + // menu tests + foreach (Type t in testTypes) + { + foreach (MethodBase m in t.GetMethods()) + { + APITestCaseAttribute a = m.GetCustomAttribute(); + if (a != null && a.TestType == TestType.Menu) + { + m.Invoke(null, new object[0]); + yield return Yield.It; + } + } + } + // load game + yield return GoToGameTests().Continue(); + } + + private static IEnumerator GoToGameTests() + { + Client app = new Client(); + int oldLength = 0; + while (app.MyGames.Length == 0 || oldLength != app.MyGames.Length) + { + oldLength = app.MyGames.Length; + yield return new WaitForSecondsEnumerator(1).Continue(); + } + yield return Yield.It; + app.MyGames[0].EnterGame(); + // returning from a new game without saving will hard lock GC (it's an invalid state) + //Game newGame = Game.NewGame(); + //yield return new WaitForSecondsEnumerator(5).Continue(); // wait for sync + //newGame.EnterGame(); + } + + private static IEnumerator GameTests() + { + yield return Yield.It; + Game currentGame = Game.CurrentGame(); + // in-game tests + yield return new WaitForSecondsEnumerator(5).Continue(); // wait for game to finish loading + foreach (Type t in testTypes) + { + foreach (MethodBase m in t.GetMethods()) + { + APITestCaseAttribute a = m.GetCustomAttribute(); + if (a != null && a.TestType == TestType.Game) + { + m.Invoke(null, new object[0]); + yield return Yield.It; + } + } + } + currentGame.ToggleTimeMode(); + yield return new WaitForSecondsEnumerator(5).Continue(); + // simulation tests + foreach (Type t in testTypes) + { + foreach (MethodBase m in t.GetMethods()) + { + APITestCaseAttribute a = m.GetCustomAttribute(); + if (a != null && a.TestType == TestType.SimulationMode) + { + m.Invoke(null, new object[0]); + yield return Yield.It; + } + } + } + currentGame.ToggleTimeMode(); + yield return new WaitForSecondsEnumerator(5).Continue(); + // build tests + foreach (Type t in testTypes) + { + foreach (MethodBase m in t.GetMethods()) + { + APITestCaseAttribute a = m.GetCustomAttribute(); + if (a != null && a.TestType == TestType.EditMode) + { + m.Invoke(null, new object[0]); + yield return Yield.It; + } + } + } + // exit game + yield return new WaitForSecondsEnumerator(5).Continue(); + yield return ReturnToMenu().Continue(); + } + + private static IEnumerator ReturnToMenu() + { + Logging.MetaLog("Returning to main menu"); + yield return Yield.It; + Game.CurrentGame().ExitGame(); + } + + private static IEnumerator TearDown() + { + yield return new WaitForSecondsEnumerator(5).Continue(); + Logging.MetaLog("Tearing down test run"); + // dispose tests here + foreach (Type t in testTypes) + { + foreach (MethodBase m in t.GetMethods()) + { + if (m.GetCustomAttribute() != null) + { + m.Invoke(null, new object[0]); + yield return Yield.It; + } + } + } + // finish up + Assert.CallsComplete(); + timer.Stop(); + string verdict = _testsPassed ? "--- PASSED :) ---" : "--- FAILED :( ---"; + Assert.Log($"VERDICT: {verdict} ({_testsCountPassed}/{_testsCountFailed}/{_testsCount} P/F/T in {timer.ElapsedMilliseconds}ms)"); + yield return Yield.It; + // end game + Logging.MetaLog("Completed test run: " + verdict); + yield return Yield.It; + Assert.CloseLog(); + if (AutoShutdown) Application.Quit(); + } + + private static void FindTests(Assembly asm) + { + testTypes = new List(); + foreach (Type t in asm.GetTypes()) + { + if (t.GetCustomAttribute() != null) + { + testTypes.Add(t); + } + } + } + + public static void RunTests(Assembly asm = null) + { + if (asm == null) asm = Assembly.GetExecutingAssembly(); + FindTests(asm); + Logging.MetaLog("Starting test run"); + // log metadata + Assert.Log($"Unity {Application.unityVersion}"); + Assert.Log($"Gamecraft {Application.version}"); + Assert.Log($"GamecraftModdingAPI {Assembly.GetExecutingAssembly().GetName().Version}"); + Assert.Log($"Testing {asm.GetName().Name} {asm.GetName().Version}"); + Assert.Log($"START: --- {DateTime.Now.ToString()} --- ({testTypes.Count} tests classes detected)"); + StartUp(); + Logging.MetaLog("Test StartUp complete"); + } + } +} diff --git a/GamecraftModdingAPI/Tests/TestTest.cs b/GamecraftModdingAPI/Tests/TestTest.cs new file mode 100644 index 0000000..02eeda0 --- /dev/null +++ b/GamecraftModdingAPI/Tests/TestTest.cs @@ -0,0 +1,52 @@ +using System; + +using System.Reflection; + +using HarmonyLib; + +namespace GamecraftModdingAPI.Tests +{ +#if TEST + /// + /// Test test test. + /// + [APITestClass] + public static class TestTest + { + public static event EventHandler StartUp; + + public static event EventHandler Test; + + public static event EventHandler TearDown; + + [APITestStartUp] + public static void Init() + { + StartUp += Assert.CallsBack("TestStartUp"); + Test += Assert.CallsBack("TestCase"); + TearDown += Assert.CallsBack("TestTearDown"); + StartUp(null, default(TestEventArgs)); + } + + [APITestCase(TestType.Menu)] + public static void RunTest() + { + Test(null, default(TestEventArgs)); + } + + [APITestTearDown] + public static void End() + { + TearDown(null, default(TestEventArgs)); + } + } + + public struct TestEventArgs + { + public override string ToString() + { + return "TestEventArgs{}"; + } + } +#endif +} From 0019b7c0734292cf12718bf0523333fbd61780e5 Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Mon, 22 Jun 2020 12:04:21 -0400 Subject: [PATCH 05/34] Version bump to v1.3.0 --- .../GamecraftModdingAPI.csproj | 389 +----------------- doxygen.conf | 2 +- 2 files changed, 2 insertions(+), 389 deletions(-) diff --git a/GamecraftModdingAPI/GamecraftModdingAPI.csproj b/GamecraftModdingAPI/GamecraftModdingAPI.csproj index c78272a..199eed6 100644 --- a/GamecraftModdingAPI/GamecraftModdingAPI.csproj +++ b/GamecraftModdingAPI/GamecraftModdingAPI.csproj @@ -2,7 +2,7 @@ net472 true - 1.2.0 + 1.3.0 Exmods GNU General Public Licence 3+ https://git.exmods.org/modtainers/GamecraftModdingAPI @@ -21,393 +21,6 @@ - - ..\..\ref\Gamecraft_Data\Managed\Analytics.dll - - - ..\..\ref\Gamecraft_Data\Managed\Assembly-CSharp-firstpass.dll - - - ..\..\ref\Gamecraft_Data\Managed\Assembly-CSharp.dll - - - ..\..\ref\Gamecraft_Data\Managed\Authentication.dll - - - ..\..\ref\Gamecraft_Data\Managed\BlockEntityFactory.dll - - - ..\..\ref\Gamecraft_Data\Managed\Blocks.HUDFeedbackBlocks.dll - - - ..\..\ref\Gamecraft_Data\Managed\ClusterToWireConversion.Mock.dll - - - ..\..\ref\Gamecraft_Data\Managed\CommandLine.dll - - - ..\..\ref\Gamecraft_Data\Managed\DataLoader.dll - - - ..\..\ref\Gamecraft_Data\Managed\DDNA.dll - - - ..\..\ref\Gamecraft_Data\Managed\FMOD.dll - - - ..\..\ref\Gamecraft_Data\Managed\FullGame.dll - - - ..\..\ref\Gamecraft_Data\Managed\Gamecraft.AudioBlocks.dll - - - ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.ConsoleBlock.dll - - - ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.DamagingSurfaceBlock.dll - - - ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.GenericPhysicsBlocks.dll - - - ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.LogicBlock.dll - - - ..\..\ref\Gamecraft_Data\Managed\GameCraft.Blocks.ProjectileBlock.dll - - - ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.TimerBlock.dll - - - ..\..\ref\Gamecraft_Data\Managed\Gamecraft.CharacterVulnerability.dll - - - ..\..\ref\Gamecraft_Data\Managed\Gamecraft.CharacterVulnerabilityGui.dll - - - ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Effects.dll - - - ..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.ConsoleBlock.dll - - - ..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.GraphicsScreen.dll - - - ..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.HUDFeedbackBlocks.dll - - - ..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.Tweaks.dll - - - ..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.Wires.dll - - - ..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.Wires.Mockup.dll - - - ..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.WorldSpaceGuis.dll - - - ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Music.dll - - - ..\..\ref\Gamecraft_Data\Managed\Gamecraft.PerformanceWarnings.dll - - - ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Tweaks.dll - - - ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Tweaks.Mockup.dll - - - ..\..\ref\Gamecraft_Data\Managed\Gamecraft.VisualEffects.dll - - - ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Wires.dll - - - ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Wires.Input.dll - - - ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Wires.Mockup.dll - - - ..\..\ref\Gamecraft_Data\Managed\GameState.dll - - - ..\..\ref\Gamecraft_Data\Managed\GPUInstancer.dll - - - ..\..\ref\Gamecraft_Data\Managed\Havok.Physics.dll - - - ..\..\ref\Gamecraft_Data\Managed\Havok.Physics.Hybrid.dll - - - ..\..\ref\Gamecraft_Data\Managed\LZ4.dll - - - ..\..\ref\Gamecraft_Data\Managed\MultiplayerNetworking.dll - - - ..\..\ref\Gamecraft_Data\Managed\MultiplayerTest.dll - - - ..\..\ref\Gamecraft_Data\Managed\RCX.ScreenshotTaker.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftECS.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.AccountPreferences.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.Blocks.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.Blocks.Ghost.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.Blocks.Triggers.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.Building.BoxSelect.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.Building.Jobs.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.Character.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.ClusterToWireConversion.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.Common.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.ControlsScreen.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.Crosshair.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.FrontEnd.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.GUI.BlockLabel.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.GUI.DebugDisplay.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.GUI.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.GUI.RemoveBlock.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.GUI.ScaleGhost.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.GUIs.WorkshopPrefabs.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.Input.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.MachineEditor.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.MainGame.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.MainSimulation.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.MockCharacter.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.Multiplayer.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.Multiplayer.NetworkEntityStream.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.MultiplayerInput.dll - - - ..\..\ref\Gamecraft_Data\Managed\Robocraftx.ObjectIdBlocks.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.Party.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.PartyGui.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.Physics.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.PilotSeat.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.Player.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.Rendering.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.Rendering.Mock.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.SaveAndLoad.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.SaveGameDialog.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.Serializers.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.Services.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.SignalHandling.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX.StateSync.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX_SpawnPoints.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocraftX_TextBlock.dll - - - ..\..\ref\Gamecraft_Data\Managed\RobocratX.SimulationCompositionRoot.dll - - - ..\..\ref\Gamecraft_Data\Managed\StringFormatter.dll - - - ..\..\ref\Gamecraft_Data\Managed\Svelto.Common_3.dll - - - ..\..\ref\Gamecraft_Data\Managed\Svelto.ECS.dll - - - ..\..\ref\Gamecraft_Data\Managed\Svelto.Services.dll - - - ..\..\ref\Gamecraft_Data\Managed\Svelto.Tasks.dll - - - ..\..\ref\Gamecraft_Data\Managed\Unity.Addressables.dll - - - ..\..\ref\Gamecraft_Data\Managed\Unity.Build.SlimPlayerRuntime.dll - - - ..\..\ref\Gamecraft_Data\Managed\Unity.Burst.dll - - - ..\..\ref\Gamecraft_Data\Managed\Unity.Collections.dll - - - ..\..\ref\Gamecraft_Data\Managed\Unity.Deformations.dll - - - ..\..\ref\Gamecraft_Data\Managed\Unity.Entities.dll - - - ..\..\ref\Gamecraft_Data\Managed\Unity.Entities.Hybrid.dll - - - ..\..\ref\Gamecraft_Data\Managed\Unity.Jobs.dll - - - ..\..\ref\Gamecraft_Data\Managed\Unity.Mathematics.dll - - - ..\..\ref\Gamecraft_Data\Managed\Unity.Mathematics.Extensions.dll - - - ..\..\ref\Gamecraft_Data\Managed\Unity.Mathematics.Extensions.Hybrid.dll - - - ..\..\ref\Gamecraft_Data\Managed\Unity.Physics.dll - - - ..\..\ref\Gamecraft_Data\Managed\Unity.Physics.Hybrid.dll - - - ..\..\ref\Gamecraft_Data\Managed\Unity.Platforms.Common.dll - - - ..\..\ref\Gamecraft_Data\Managed\Unity.Postprocessing.Runtime.dll - - - ..\..\ref\Gamecraft_Data\Managed\Unity.Properties.dll - - - ..\..\ref\Gamecraft_Data\Managed\Unity.Properties.Reflection.dll - - - ..\..\ref\Gamecraft_Data\Managed\Unity.Properties.UI.dll - - - ..\..\ref\Gamecraft_Data\Managed\Unity.RenderPipeline.Universal.ShaderLibrary.dll - - - ..\..\ref\Gamecraft_Data\Managed\Unity.RenderPipelines.Core.Runtime.dll - - - ..\..\ref\Gamecraft_Data\Managed\Unity.RenderPipelines.Core.ShaderLibrary.dll - - - ..\..\ref\Gamecraft_Data\Managed\Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary.dll - - - ..\..\ref\Gamecraft_Data\Managed\Unity.RenderPipelines.Universal.Runtime.dll - - - ..\..\ref\Gamecraft_Data\Managed\Unity.RenderPipelines.Universal.Shaders.dll - - - ..\..\ref\Gamecraft_Data\Managed\Unity.ResourceManager.dll - - - ..\..\ref\Gamecraft_Data\Managed\Unity.Scenes.Hybrid.dll - - - ..\..\ref\Gamecraft_Data\Managed\Unity.ScriptableBuildPipeline.dll - - - ..\..\ref\Gamecraft_Data\Managed\Unity.Serialization.dll - - - ..\..\ref\Gamecraft_Data\Managed\Unity.TextMeshPro.dll - - - ..\..\ref\Gamecraft_Data\Managed\Unity.Timeline.dll - - - ..\..\ref\Gamecraft_Data\Managed\Unity.Transforms.dll - - - ..\..\ref\Gamecraft_Data\Managed\Unity.Transforms.Hybrid.dll - - - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.UI.dll - - - ..\..\ref\Gamecraft_Data\Managed\uREPL.dll - - - ..\..\ref\Gamecraft_Data\Managed\VisualProfiler.dll - diff --git a/doxygen.conf b/doxygen.conf index 19df3c4..d587ecd 100644 --- a/doxygen.conf +++ b/doxygen.conf @@ -38,7 +38,7 @@ PROJECT_NAME = "GamecraftModdingAPI" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = "v1.2.0" +PROJECT_NUMBER = "v1.3.0" # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a From 189c3ca2a5a545d6cf48f43e3aee791b063cbca0 Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Tue, 23 Jun 2020 13:49:42 -0400 Subject: [PATCH 06/34] Document App and Test additions (+ minor tweaks) --- GamecraftModdingAPI/App/AppCallbacksTest.cs | 4 + GamecraftModdingAPI/App/Client.cs | 24 ++++ GamecraftModdingAPI/App/Game.cs | 130 +++++++++++++++++- GamecraftModdingAPI/App/GameGameEngine.cs | 21 ++- GamecraftModdingAPI/Player.cs | 9 ++ GamecraftModdingAPI/Players/PlayerEngine.cs | 24 +++- .../Tests/APITestAttributes.cs | 20 +++ GamecraftModdingAPI/Tests/Assert.cs | 18 +++ GamecraftModdingAPI/Tests/TestRoot.cs | 7 + 9 files changed, 249 insertions(+), 8 deletions(-) diff --git a/GamecraftModdingAPI/App/AppCallbacksTest.cs b/GamecraftModdingAPI/App/AppCallbacksTest.cs index 0c2987b..041ac50 100644 --- a/GamecraftModdingAPI/App/AppCallbacksTest.cs +++ b/GamecraftModdingAPI/App/AppCallbacksTest.cs @@ -5,6 +5,10 @@ using GamecraftModdingAPI.Tests; namespace GamecraftModdingAPI.App { #if TEST + /// + /// App callbacks tests. + /// Only available in TEST builds. + /// [APITestClass] public static class AppCallbacksTest { diff --git a/GamecraftModdingAPI/App/Client.cs b/GamecraftModdingAPI/App/Client.cs index 2f1f005..e95d9f3 100644 --- a/GamecraftModdingAPI/App/Client.cs +++ b/GamecraftModdingAPI/App/Client.cs @@ -6,32 +6,56 @@ using GamecraftModdingAPI.Utility; namespace GamecraftModdingAPI.App { + /// + /// The Gamecraft application that is running this code right now. + /// public class Client { + // extensible engine protected static AppEngine appEngine = new AppEngine(); + /// + /// An event that fires whenever the main menu is loaded. + /// public static event EventHandler EnterMenu { add => appEngine.EnterMenu += value; remove => appEngine.EnterMenu -= value; } + /// + /// An event that fire whenever the main menu is exited. + /// public static event EventHandler ExitMenu { add => appEngine.ExitMenu += value; remove => appEngine.ExitMenu -= value; } + /// + /// Gamecraft build version string. + /// Usually this is in the form YYYY.mm.DD.HH.MM.SS + /// + /// The version. public string Version { get => Application.version; } + /// + /// Unity version string. + /// + /// The unity version. public string UnityVersion { get => Application.unityVersion; } + /// + /// Game saves currently visible in the menu. + /// These take a second to completely populate after the EnterMenu event fires. + /// + /// My games. public Game[] MyGames { get diff --git a/GamecraftModdingAPI/App/Game.cs b/GamecraftModdingAPI/App/Game.cs index 0d31abf..3fd4900 100644 --- a/GamecraftModdingAPI/App/Game.cs +++ b/GamecraftModdingAPI/App/Game.cs @@ -9,12 +9,17 @@ using Svelto.ECS; using GamecraftModdingAPI.Tasks; using GamecraftModdingAPI.Utility; -// TODO: exceptions namespace GamecraftModdingAPI.App { + /// + /// An in-game save. + /// This can be a menu item for a local save or the currently loaded save. + /// Support for Steam Workshop coming soon (hopefully). + /// public class Game { + // extensible engines protected static GameGameEngine gameEngine = new GameGameEngine(); protected static GameMenuEngine menuEngine = new GameMenuEngine(); protected static DebugInterfaceEngine debugOverlayEngine = new DebugInterfaceEngine(); @@ -25,10 +30,18 @@ namespace GamecraftModdingAPI.App private bool menuMode = true; private bool hasId = false; + /// + /// Initializes a new instance of the class. + /// + /// Menu identifier. public Game(uint id) : this(new EGID(id, MyGamesScreenExclusiveGroups.MyGames)) { } + /// + /// Initializes a new instance of the class. + /// + /// Menu identifier. public Game(EGID id) { this.Id = id.entityID; @@ -38,6 +51,10 @@ namespace GamecraftModdingAPI.App if (!VerifyMode()) throw new AppStateException("Game cannot be created while not in a game nor in a menu (is the game in a loading screen?)"); } + /// + /// Initializes a new instance of the class without id. + /// This is assumed to be the current game. + /// public Game() { menuMode = false; @@ -45,11 +62,21 @@ namespace GamecraftModdingAPI.App if (menuEngine.IsInMenu) throw new GameNotFoundException("Game not found."); } + /// + /// Returns the currently loaded game. + /// If in a menu, manipulating the returned object may not work as intended. + /// + /// The current game. public static Game CurrentGame() { return new Game(); } + /// + /// Creates a new game and adds it to the menu. + /// If not in a menu, this will throw AppStateException. + /// + /// The new game. public static Game NewGame() { if (!menuEngine.IsInMenu) throw new AppStateException("New Game cannot be created while not in a menu."); @@ -59,47 +86,77 @@ namespace GamecraftModdingAPI.App return new Game(egid); } + /// + /// An event that fires whenever a game is switched to simulation mode (time running mode). + /// public static event EventHandler Simulate { add => buildSimEventEngine.SimulationMode += value; remove => buildSimEventEngine.SimulationMode -= value; } + /// + /// An event that fires whenever a game is switched to edit mode (time stopped mode). + /// This does not fire when a game is loaded. + /// public static event EventHandler Edit { add => buildSimEventEngine.BuildMode += value; remove => buildSimEventEngine.BuildMode -= value; } + /// + /// An event that fires right after a game is completely loaded. + /// public static event EventHandler Enter { add => gameEngine.EnterGame += value; remove => gameEngine.EnterGame -= value; } + /// + /// An event that fires right before a game returns to the main menu. + /// At this point, Gamecraft is transitioning state so many things are invalid/unstable here. + /// public static event EventHandler Exit { add => gameEngine.ExitGame += value; remove => gameEngine.ExitGame -= value; } + /// + /// The game's unique menu identifier. + /// + /// The identifier. public uint Id { get; private set; } + /// + /// The game's unique menu EGID. + /// + /// The egid. public EGID EGID { get; private set; } + /// + /// Whether the game is a (valid) menu item. + /// + /// true if menu item; otherwise, false. public bool MenuItem { get => menuMode && hasId; } + /// + /// The game's name. + /// + /// The name. public string Name { get @@ -123,6 +180,10 @@ namespace GamecraftModdingAPI.App } } + /// + /// The game's description. + /// + /// The description. public string Description { get @@ -146,6 +207,10 @@ namespace GamecraftModdingAPI.App } } + /// + /// The path to the game's save folder. + /// + /// The path. public string Path { get @@ -170,6 +235,11 @@ namespace GamecraftModdingAPI.App } } + /// + /// The Steam Workshop Id of the game save. + /// In most cases this is invalid and returns 0, so this can be ignored. + /// + /// The workshop identifier. public ulong WorkshopId { get @@ -195,6 +265,10 @@ namespace GamecraftModdingAPI.App } } + /// + /// Whether the game is in simulation mode. + /// + /// true if is simulating; otherwise, false. public bool IsSimulating { get @@ -211,6 +285,11 @@ namespace GamecraftModdingAPI.App } } + /// + /// Whether the game is in time-running mode. + /// Alias of IsSimulating. + /// + /// true if is time running; otherwise, false. public bool IsTimeRunning { get => IsSimulating; @@ -221,6 +300,10 @@ namespace GamecraftModdingAPI.App } } + /// + /// Whether the game is in time-stopped mode. + /// + /// true if is time stopped; otherwise, false. public bool IsTimeStopped { get @@ -237,6 +320,9 @@ namespace GamecraftModdingAPI.App } } + /// + /// Toggles the time mode. + /// public void ToggleTimeMode() { if (!VerifyMode()) return; @@ -247,6 +333,11 @@ namespace GamecraftModdingAPI.App gameEngine.ToggleTimeMode(); } + /// + /// Load the game save. + /// This happens asynchronously, so when this method returns the game not loaded yet. + /// Use the Game.Enter event to perform operations after the game has completely loaded. + /// public void EnterGame() { if (!VerifyMode()) return; @@ -258,17 +349,43 @@ namespace GamecraftModdingAPI.App Scheduler.Schedule(task); } - public void ExitGame() + /// + /// Return to the menu. + /// Part of this always happens asynchronously, so when this method returns the game has not exited yet. + /// Use the Client.EnterMenu event to perform operations after the game has completely exited. + /// + /// If set to true, do this async. + public void ExitGame(bool async = false) { if (!VerifyMode()) return; if (menuMode) { throw new GameNotFoundException("Cannot exit game using menu ID"); } - ISchedulable task = new Once(() => { gameEngine.ExitCurrentGame(); this.menuMode = true; }); - Scheduler.Schedule(task); + gameEngine.ExitCurrentGame(async); + this.menuMode = true; } + /// + /// Saves the game. + /// Part of this happens asynchronously, so when this method returns the game has not been saved yet. + /// + public void SaveGame() + { + if (!VerifyMode()) return; + if (menuMode) + { + throw new GameNotFoundException("Cannot save game using menu ID"); + } + gameEngine.SaveCurrentGame(); + } + + /// + /// Add information to the in-game debug display. + /// When this object is garbage collected, this debug info is automatically removed. + /// + /// Debug info identifier. + /// Content getter. public void AddDebugInfo(string id, Func contentGetter) { if (!VerifyMode()) return; @@ -280,6 +397,11 @@ namespace GamecraftModdingAPI.App debugIds.Add(id); } + /// + /// Remove information from the in-game debug display. + /// + /// true, if debug info was removed, false otherwise. + /// Debug info identifier. public bool RemoveDebugInfo(string id) { if (!VerifyMode()) return false; diff --git a/GamecraftModdingAPI/App/GameGameEngine.cs b/GamecraftModdingAPI/App/GameGameEngine.cs index 9253af2..d46eb32 100644 --- a/GamecraftModdingAPI/App/GameGameEngine.cs +++ b/GamecraftModdingAPI/App/GameGameEngine.cs @@ -47,9 +47,18 @@ namespace GamecraftModdingAPI.App private set; } = false; - public void ExitCurrentGame() + public void ExitCurrentGame(bool async = false) { - ExitCurrentGameAsync().RunOn(Lean.EveryFrameStepRunner_RUNS_IN_TIME_STOPPED_AND_RUNNING); + if (async) + { + ExitCurrentGameAsync().RunOn(Lean.EveryFrameStepRunner_RUNS_IN_TIME_STOPPED_AND_RUNNING); + } + else + { + entitiesDB.QueryEntity(CommonExclusiveGroups.GameSceneEGID).WantsToQuit = true; + entitiesDB.PublishEntityChange(CommonExclusiveGroups.GameSceneEGID); + } + } public IEnumerator ExitCurrentGameAsync() @@ -62,6 +71,14 @@ namespace GamecraftModdingAPI.App entitiesDB.PublishEntityChange(CommonExclusiveGroups.GameSceneEGID); } + public void SaveCurrentGame() + { + ref GameSceneEntityStruct gses = ref entitiesDB.QueryEntity(CommonExclusiveGroups.GameSceneEGID); + gses.LoadAfterSaving = false; + gses.SaveNow = true; + entitiesDB.PublishEntityChange(CommonExclusiveGroups.GameSceneEGID); + } + public bool IsTimeRunningMode() { return TimeRunningModeUtil.IsTimeRunningMode(entitiesDB); diff --git a/GamecraftModdingAPI/Player.cs b/GamecraftModdingAPI/Player.cs index efb381e..3d80e7b 100644 --- a/GamecraftModdingAPI/Player.cs +++ b/GamecraftModdingAPI/Player.cs @@ -45,6 +45,15 @@ namespace GamecraftModdingAPI return playerEngine.ExistsById(player); } + /// + /// The amount of Players in the current game. + /// + /// The count. + public static uint Count() + { + return playerEngine.GetAllPlayerCount(); + } + /// /// Initializes a new instance of the class. /// diff --git a/GamecraftModdingAPI/Players/PlayerEngine.cs b/GamecraftModdingAPI/Players/PlayerEngine.cs index 2bb29a7..1bcce50 100644 --- a/GamecraftModdingAPI/Players/PlayerEngine.cs +++ b/GamecraftModdingAPI/Players/PlayerEngine.cs @@ -65,6 +65,26 @@ namespace GamecraftModdingAPI.Players return uint.MaxValue; } + public uint GetAllPlayerCount() + { + uint count = 0; + foreach (ExclusiveGroupStruct eg in PlayersExclusiveGroups.AllPlayers) + { + count += entitiesDB.Count(eg); + } + return count; + } + + public uint GetLocalPlayerCount() + { + return entitiesDB.Count(PlayersExclusiveGroups.LocalPlayers); + } + + public uint GetRemotePlayerCount() + { + return entitiesDB.Count(PlayersExclusiveGroups.RemotePlayers); + } + public bool ExistsById(uint playerId) { return entitiesDB.Exists(playerId, PlayersExclusiveGroups.LocalPlayers) @@ -109,7 +129,7 @@ namespace GamecraftModdingAPI.Players { return ((Quaternion) rbes.rotation).eulerAngles; } - return default; + return default(float3); } public bool SetRotation(uint playerId, float3 value) @@ -174,7 +194,7 @@ namespace GamecraftModdingAPI.Players { return rbes.physicsMass; } - return default; + return default(PhysicsMass); } public bool SetInverseMass(uint playerId, float inverseMass) diff --git a/GamecraftModdingAPI/Tests/APITestAttributes.cs b/GamecraftModdingAPI/Tests/APITestAttributes.cs index 8506a56..cf9da49 100644 --- a/GamecraftModdingAPI/Tests/APITestAttributes.cs +++ b/GamecraftModdingAPI/Tests/APITestAttributes.cs @@ -1,6 +1,10 @@ using System; namespace GamecraftModdingAPI.Tests { + /// + /// Test type. + /// When provided to APITestCaseAttribute, this dictates when the test case is called. + /// public enum TestType { Menu, @@ -9,6 +13,10 @@ namespace GamecraftModdingAPI.Tests EditMode, } + /// + /// API Test Class attribute. + /// Classes without this attribute will be ignored when searching for test cases. + /// [AttributeUsage(AttributeTargets.Class)] public class APITestClassAttribute : Attribute { @@ -20,6 +28,10 @@ namespace GamecraftModdingAPI.Tests } } + /// + /// API Test Case attribute. + /// Static methods with this attribute will be called when the API test system is running. + /// [AttributeUsage(AttributeTargets.Method)] public class APITestCaseAttribute : Attribute { @@ -31,12 +43,20 @@ namespace GamecraftModdingAPI.Tests } } + /// + /// API Test StartUp attribute. + /// Static methods with this attribute will be called before any test case is run by the API test system. + /// [AttributeUsage(AttributeTargets.Method)] public class APITestStartUpAttribute : Attribute { } + /// + /// API Test TearDown attribute. + /// Static methods with this attribute will be called after all API test system test cases have completed (failed or succeeded). + /// [AttributeUsage(AttributeTargets.Method)] public class APITestTearDownAttribute : Attribute { diff --git a/GamecraftModdingAPI/Tests/Assert.cs b/GamecraftModdingAPI/Tests/Assert.cs index fb03013..d888f45 100644 --- a/GamecraftModdingAPI/Tests/Assert.cs +++ b/GamecraftModdingAPI/Tests/Assert.cs @@ -5,6 +5,9 @@ using System.Runtime.CompilerServices; namespace GamecraftModdingAPI.Tests { + /// + /// API test system assertion utilities. + /// public static class Assert { private static StreamWriter logFile = null; @@ -19,6 +22,11 @@ namespace GamecraftModdingAPI.Tests private const string INFO = "DEBUG: "; + /// + /// Log a message to the test log. + /// + /// Message. + /// Message ending. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Log(string msg, string end = "\n") { @@ -27,6 +35,16 @@ namespace GamecraftModdingAPI.Tests logFile.Flush(); } + /// + /// Asserts that the event receives a callback... eventually. + /// Add the eventhandler returned by this method to the relevant event. + /// This does not assert that the callback happens under that event's intended circumstances. + /// Add another event handler to assert specific circumstance requirements. + /// + /// The callback event handler. + /// Event name. + /// Event error message. + /// The event handler callback argument object. public static EventHandler CallsBack(string eventName, string eventMsg = null) { if (eventMsg == null) eventMsg = $"expected callback to {eventName} but it never occurred..."; diff --git a/GamecraftModdingAPI/Tests/TestRoot.cs b/GamecraftModdingAPI/Tests/TestRoot.cs index 167173f..99f77b7 100644 --- a/GamecraftModdingAPI/Tests/TestRoot.cs +++ b/GamecraftModdingAPI/Tests/TestRoot.cs @@ -15,6 +15,9 @@ using GamecraftModdingAPI.Utility; namespace GamecraftModdingAPI.Tests { + /// + /// API test system root class. + /// public static class TestRoot { public static bool AutoShutdown = true; @@ -229,6 +232,10 @@ namespace GamecraftModdingAPI.Tests } } + /// + /// Runs the tests. + /// + /// Assembly to search for tests. When set to null, this uses the GamecraftModdingAPI assembly. public static void RunTests(Assembly asm = null) { if (asm == null) asm = Assembly.GetExecutingAssembly(); From b6a5074fd2344e15a374a8d65235befe2f35b118 Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Fri, 26 Jun 2020 19:37:58 -0400 Subject: [PATCH 07/34] Add some state info and save method --- GamecraftModdingAPI/App/Client.cs | 9 ++++++++ GamecraftModdingAPI/App/Game.cs | 24 +++++++++++++++++++ GamecraftModdingAPI/App/GameGameEngine.cs | 28 +++++++++++++++++++++++ 3 files changed, 61 insertions(+) diff --git a/GamecraftModdingAPI/App/Client.cs b/GamecraftModdingAPI/App/Client.cs index e95d9f3..fbe960e 100644 --- a/GamecraftModdingAPI/App/Client.cs +++ b/GamecraftModdingAPI/App/Client.cs @@ -65,6 +65,15 @@ namespace GamecraftModdingAPI.App } } + /// + /// Whether Gamecraft is in the Main Menu + /// + /// true if in menu; false when loading or in a game. + public bool InMenu + { + get => appEngine.IsInMenu; + } + internal static void Init() { MenuEngineManager.AddMenuEngine(appEngine); diff --git a/GamecraftModdingAPI/App/Game.cs b/GamecraftModdingAPI/App/Game.cs index 3fd4900..d6a4eff 100644 --- a/GamecraftModdingAPI/App/Game.cs +++ b/GamecraftModdingAPI/App/Game.cs @@ -7,6 +7,8 @@ using RobocraftX.GUI.MyGamesScreen; using RobocraftX.StateSync; using Svelto.ECS; +using GamecraftModdingAPI; +using GamecraftModdingAPI.Blocks; using GamecraftModdingAPI.Tasks; using GamecraftModdingAPI.Utility; @@ -414,6 +416,28 @@ namespace GamecraftModdingAPI.App return debugIds.Remove(id); } + /// + /// Gets the blocks in the game. + /// This returns null when in a loading state, and throws AppStateException when in menu. + /// + /// The blocks in game. + /// The block to search for. BlockIDs.Invalid will return all blocks. + public Block[] GetBlocksInGame(BlockIDs filter = BlockIDs.Invalid) + { + if (!VerifyMode()) return null; + if (menuMode) + { + throw new AppStateException("Game object references a menu item but GetBlocksInGame only works on the currently-loaded game"); + } + EGID[] blockEGIDs = gameEngine.GetAllBlocksInGame(filter); + Block[] blocks = new Block[blockEGIDs.Length]; + for (int b = 0; b < blockEGIDs.Length; b++) + { + blocks[b] = new Block(blockEGIDs[b]); + } + return blocks; + } + ~Game() { foreach (string id in debugIds) diff --git a/GamecraftModdingAPI/App/GameGameEngine.cs b/GamecraftModdingAPI/App/GameGameEngine.cs index d46eb32..cbb1c79 100644 --- a/GamecraftModdingAPI/App/GameGameEngine.cs +++ b/GamecraftModdingAPI/App/GameGameEngine.cs @@ -10,6 +10,7 @@ using Svelto.ECS; using Svelto.Tasks; using Svelto.Tasks.Lean; +using GamecraftModdingAPI.Blocks; using GamecraftModdingAPI.Engines; using GamecraftModdingAPI.Utility; @@ -93,5 +94,32 @@ namespace GamecraftModdingAPI.App { TimeRunningModeUtil.ToggleTimeRunningState(entitiesDB); } + + public EGID[] GetAllBlocksInGame(BlockIDs filter = BlockIDs.Invalid) + { + EntityCollection blocks = entitiesDB.QueryEntities(CommonExclusiveGroups.OWNED_BLOCKS_GROUP); + if (filter == BlockIDs.Invalid) + { + EGID[] blockEGIDs = new EGID[blocks.count]; + for (uint b = 0; b < blocks.count; b++) + { + blockEGIDs[b] = blocks[b].ID; + } + return blockEGIDs; + } + else + { + uint dbidFilter = (uint)filter; + List blockEGIDs = new List(); + for (uint b = 0; b < blocks.count; b++) + { + if (blocks[b].DBID == dbidFilter) + { + blockEGIDs.Add(blocks[b].ID); + } + } + return blockEGIDs.ToArray(); + } + } } } From 60f231f939210485e9d258fd6da8d318f49deec8 Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Tue, 30 Jun 2020 20:43:14 -0400 Subject: [PATCH 08/34] Add standard asserts --- GamecraftModdingAPI/Tests/Assert.cs | 158 ++++++++++++++++++++++++++ GamecraftModdingAPI/Tests/TestRoot.cs | 54 ++++++++- 2 files changed, 206 insertions(+), 6 deletions(-) diff --git a/GamecraftModdingAPI/Tests/Assert.cs b/GamecraftModdingAPI/Tests/Assert.cs index d888f45..eec9c5c 100644 --- a/GamecraftModdingAPI/Tests/Assert.cs +++ b/GamecraftModdingAPI/Tests/Assert.cs @@ -3,6 +3,8 @@ using System.Collections.Concurrent; using System.IO; using System.Runtime.CompilerServices; +using Unity.Mathematics; + namespace GamecraftModdingAPI.Tests { /// @@ -59,6 +61,162 @@ namespace GamecraftModdingAPI.Tests }; } + public static bool NotNull(T obj, string err = null, string success = null) + { + if (err == null) err = $"{nameof(T)} object was null."; + if (success == null) success = $"{nameof(T)} '{obj}' not null"; + if (obj == null) + { + Log(FAIL + err); + TestRoot.TestsPassed = false; + return false; + } + else + { + Log(PASS + success); + TestRoot.TestsPassed = true; + return true; + } + } + + public static bool Equal(T obj1, T obj2, string err = null, string success = null) + { + if (err == null) err = $"{nameof(T)} '{obj1}' is not equal to '{obj2}'."; + if (success == null) success = $"{nameof(T)} '{obj1}' is equal to '{obj2}'."; + if (obj1 == null && obj2 == null) + { + // pass + Log(PASS + success); + TestRoot.TestsPassed = true; + return true; + } + else if (!(obj1 == null && obj2 == null) && obj1.Equals(obj2) && obj2.Equals(obj1)) + { + // pass + Log(PASS + success); + TestRoot.TestsPassed = true; + return true; + } + else if (obj1 != null && (obj1 != null && !obj1.Equals(obj2))) + { + // pass + Log(PASS + success); + TestRoot.TestsPassed = true; + return true; + } + else if (obj2 != null && !obj2.Equals(obj1)) + { + // pass + Log(PASS + success); + TestRoot.TestsPassed = true; + return true; + } + else + { + // fail + Log(FAIL + err); + TestRoot.TestsPassed = false; + return false; + } + } + + public static bool Errorless(Action tryThis, string err = null, string success = null) + { + if (err == null) err = $"{tryThis} raised an exception: "; + if (success == null) success = $"{tryThis} completed without raising an exception."; + try + { + tryThis(); + } + catch (Exception e) + { + Log(FAIL + err + e); + TestRoot.TestsPassed = false; + return false; + } + TestRoot.TestsPassed = true; + Log(PASS + success); + return true; + } + + public static bool CloseTo(float a, float b, string err = null, string success = null, float delta = float.Epsilon) + { + if (err == null) err = $"{a} is not within {delta} of {b}."; + if (success == null) success = $"{a} is close enough to {b}."; + if (Math.Abs(a - b) > delta) + { + Log(FAIL + err); + TestRoot.TestsPassed = false; + return false; + } + else + { + TestRoot.TestsPassed = true; + Log(PASS + success); + return true; + } + } + + public static bool CloseTo(double a, double b, string err = null, string success = null, double delta = double.Epsilon) + { + if (err == null) err = $"{a} is not within {delta} of {b}."; + if (success == null) success = $"{a} is close enough to {b}."; + if (Math.Abs(a - b) > delta) + { + Log(FAIL + err); + TestRoot.TestsPassed = false; + return false; + } + else + { + TestRoot.TestsPassed = true; + Log(PASS + success); + return true; + } + } + + public static bool CloseTo(float3 a, float3 b, string err = null, string success = null, float delta = float.Epsilon) + { + if (err == null) err = $"{a} is not within {delta} of {b} in every direction."; + if (success == null) success = $"{a} is close enough to {b}."; + bool xClose = CloseTo(a.x, b.x, err, success, delta); + bool yClose = CloseTo(a.y, b.y, err, success, delta); + bool zClose = CloseTo(a.z, b.z, err, success, delta); + if (xClose && yClose && zClose) + { + //TestRoot.TestsPassed = true; + //Log(PASS + success); + return true; + } + else + { + //Log(FAIL + err); + //TestRoot.TestsPassed = false; + return false; + } + } + + public static void Fail(string msg = null) + { + if (msg == null) msg = $"Manual test failure with no message provided."; + Log(FAIL + msg); + TestRoot.TestsPassed = false; + } + + public static void Pass(string msg = null) + { + if (msg == null) msg = $"Manual test pass with no message provided."; + Log(PASS + msg); + TestRoot.TestsPassed = true; + } + + public static void Warn(string msg = null) + { + if (msg == null) msg = $"Manual test warning with no message provided."; + Log(WARN + msg); + TestRoot.TestsPassed = true; + } + internal static void CallsComplete() { foreach(string key in callbacks.Keys) diff --git a/GamecraftModdingAPI/Tests/TestRoot.cs b/GamecraftModdingAPI/Tests/TestRoot.cs index 99f77b7..4e9da73 100644 --- a/GamecraftModdingAPI/Tests/TestRoot.cs +++ b/GamecraftModdingAPI/Tests/TestRoot.cs @@ -87,7 +87,14 @@ namespace GamecraftModdingAPI.Tests { if (m.GetCustomAttribute() != null) { - m.Invoke(null, new object[0]); + try + { + m.Invoke(null, new object[0]); + } + catch (Exception e) + { + Assert.Fail($"Start up method '{m}' raised an exception: {e.ToString()}"); + } } } } @@ -105,7 +112,14 @@ namespace GamecraftModdingAPI.Tests APITestCaseAttribute a = m.GetCustomAttribute(); if (a != null && a.TestType == TestType.Menu) { - m.Invoke(null, new object[0]); + try + { + m.Invoke(null, new object[0]); + } + catch (Exception e) + { + Assert.Fail($"Menu test '{m}' raised an exception: {e.ToString()}"); + } yield return Yield.It; } } @@ -144,7 +158,14 @@ namespace GamecraftModdingAPI.Tests APITestCaseAttribute a = m.GetCustomAttribute(); if (a != null && a.TestType == TestType.Game) { - m.Invoke(null, new object[0]); + try + { + m.Invoke(null, new object[0]); + } + catch (Exception e) + { + Assert.Fail($"Game test '{m}' raised an exception: {e.ToString()}"); + } yield return Yield.It; } } @@ -159,7 +180,14 @@ namespace GamecraftModdingAPI.Tests APITestCaseAttribute a = m.GetCustomAttribute(); if (a != null && a.TestType == TestType.SimulationMode) { - m.Invoke(null, new object[0]); + try + { + m.Invoke(null, new object[0]); + } + catch (Exception e) + { + Assert.Fail($"Simulation test '{m}' raised an exception: {e.ToString()}"); + } yield return Yield.It; } } @@ -174,7 +202,14 @@ namespace GamecraftModdingAPI.Tests APITestCaseAttribute a = m.GetCustomAttribute(); if (a != null && a.TestType == TestType.EditMode) { - m.Invoke(null, new object[0]); + try + { + m.Invoke(null, new object[0]); + } + catch (Exception e) + { + Assert.Fail($"Build test '{m}' raised an exception: {e.ToString()}"); + } yield return Yield.It; } } @@ -202,7 +237,14 @@ namespace GamecraftModdingAPI.Tests { if (m.GetCustomAttribute() != null) { - m.Invoke(null, new object[0]); + try + { + m.Invoke(null, new object[0]); + } + catch (Exception e) + { + Assert.Warn($"Tear down method '{m}' raised an exception: {e.ToString()}"); + } yield return Yield.It; } } From b376133d2877721a96e390f432cd009840addf85 Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Tue, 30 Jun 2020 20:43:45 -0400 Subject: [PATCH 09/34] Create some test cases for blocks --- GamecraftModdingAPI/Blocks/BlockTests.cs | 74 ++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 GamecraftModdingAPI/Blocks/BlockTests.cs diff --git a/GamecraftModdingAPI/Blocks/BlockTests.cs b/GamecraftModdingAPI/Blocks/BlockTests.cs new file mode 100644 index 0000000..8fb40be --- /dev/null +++ b/GamecraftModdingAPI/Blocks/BlockTests.cs @@ -0,0 +1,74 @@ +using System; + +using GamecraftModdingAPI; +using GamecraftModdingAPI.Tests; + +namespace GamecraftModdingAPI.Blocks +{ +#if TEST + [APITestClass] + public static class BlockTests + { + [APITestCase(TestType.EditMode)] + public static void TestPlaceNew() + { + Block newBlock = Block.PlaceNew(BlockIDs.AluminiumCube, Unity.Mathematics.float3.zero); + Assert.NotNull(newBlock.Id, "Newly placed block is missing Id. This should be populated when the block is placed.", "Newly placed block Id is not null, block successfully placed."); + } + + [APITestCase(TestType.EditMode)] + public static void TestSync() + { + Block newBlock = Block.PlaceNew(BlockIDs.AluminiumCube, Unity.Mathematics.float3.zero + 2); + if (!Assert.CloseTo(newBlock.Position, (Unity.Mathematics.float3.zero + 2), $"Newly placed block at {newBlock.Position} is expected at {Unity.Mathematics.float3.zero + 2}.", "Newly placed block position matches.")) return; + Assert.Equal(newBlock.Exists, true, "Newly placed block does not exist, possibly because Sync() skipped/missed/failed.", "Newly placed block exists, Sync() successful."); + } + + [APITestCase(TestType.EditMode)] + public static void TestTextBlock() + { + Block newBlock = Block.PlaceNew(BlockIDs.TextBlock, Unity.Mathematics.float3.zero + 1); + TextBlock textBlock = null; // Note: the assignment operation is a lambda, which slightly confuses the compiler + Assert.Errorless(() => { textBlock = newBlock.Specialise(); }, "Block.Specialize() raised an exception: ", "Block.Specialize() completed without issue."); + if (!Assert.NotNull(textBlock, "Block.Specialize() returned null, possibly because it failed silently.", "Specialized TextBlock is not null.")) return; + if (!Assert.NotNull(textBlock.Text, "TextBlock.Text is null, possibly because it failed silently.", "TextBlock.Text is not null.")) return; + if (!Assert.NotNull(textBlock.TextBlockId, "TextBlock.TextBlockId is null, possibly because it failed silently.", "TextBlock.TextBlockId is not null.")) return; + } + + [APITestCase(TestType.EditMode)] + public static void TestMotor() + { + Block newBlock = Block.PlaceNew(BlockIDs.MotorS, Unity.Mathematics.float3.zero + 1); + Motor b = null; // Note: the assignment operation is a lambda, which slightly confuses the compiler + Assert.Errorless(() => { b = newBlock.Specialise(); }, "Block.Specialize() raised an exception: ", "Block.Specialize() completed without issue."); + if (!Assert.NotNull(b, "Block.Specialize() returned null, possibly because it failed silently.", "Specialized Motor is not null.")) return; + if (!Assert.CloseTo(b.Torque, 75f, $"Motor.Torque {b.Torque} does not equal default value, possibly because it failed silently.", "Motor.Torque close enough to default.")) return; + if (!Assert.CloseTo(b.TopSpeed, 30f, $"Motor.TopSpeed {b.TopSpeed} does not equal default value, possibly because it failed silently.", "Motor.Torque is close enough to default.")) return; + if (!Assert.Equal(b.Reverse, false, $"Motor.Reverse {b.Reverse} does not equal default value, possibly because it failed silently.", "Motor.Reverse is default.")) return; + } + + [APITestCase(TestType.EditMode)] + public static void TestPiston() + { + Block newBlock = Block.PlaceNew(BlockIDs.PneumaticPiston, Unity.Mathematics.float3.zero + 1); + Piston b = null; // Note: the assignment operation is a lambda, which slightly confuses the compiler + Assert.Errorless(() => { b = newBlock.Specialise(); }, "Block.Specialize() raised an exception: ", "Block.Specialize() completed without issue."); + if (!Assert.NotNull(b, "Block.Specialize() returned null, possibly because it failed silently.", "Specialized Piston is not null.")) return; + if (!Assert.CloseTo(b.MaximumExtension, 1.01f, $"Piston.MaximumExtension {b.MaximumExtension} does not equal default value, possibly because it failed silently.", "Piston.MaximumExtension is close enough to default.")) return; + if (!Assert.CloseTo(b.MaximumForce, 750f, $"Piston.MaximumForce {b.MaximumForce} does not equal default value, possibly because it failed silently.", "Piston.MaximumForce is close enough to default.")) return; + } + + [APITestCase(TestType.EditMode)] + public static void TestServo() + { + Block newBlock = Block.PlaceNew(BlockIDs.ServoAxle, Unity.Mathematics.float3.zero + 1); + Servo b = null; // Note: the assignment operation is a lambda, which slightly confuses the compiler + Assert.Errorless(() => { b = newBlock.Specialise(); }, "Block.Specialize() raised an exception: ", "Block.Specialize() completed without issue."); + if (!Assert.NotNull(b, "Block.Specialize() returned null, possibly because it failed silently.", "Specialized Servo is not null.")) return; + if (!Assert.CloseTo(b.MaximumAngle, 180f, $"Servo.MaximumAngle {b.MaximumAngle} does not equal default value, possibly because it failed silently.", "Servo.MaximumAngle is close enough to default.")) return; + if (!Assert.CloseTo(b.MinimumAngle, -180f, $"Servo.MinimumAngle {b.MinimumAngle} does not equal default value, possibly because it failed silently.", "Servo.MinimumAngle is close enough to default.")) return; + if (!Assert.CloseTo(b.MaximumForce, 750f, $"Servo.MaximumForce {b.MaximumForce} does not equal default value, possibly because it failed silently.", "Servo.MaximumForce is close enough to default.")) return; + } + } +#endif +} From 6f589f1744887e669961f98bfa3e2026334a41a0 Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Wed, 1 Jul 2020 13:43:56 -0400 Subject: [PATCH 10/34] Create Player tests --- GamecraftModdingAPI/Blocks/BlockTests.cs | 3 ++ GamecraftModdingAPI/Player.cs | 2 +- GamecraftModdingAPI/Players/PlayerEngine.cs | 30 +++++++++++++++ GamecraftModdingAPI/Players/PlayerTests.cs | 42 +++++++++++++++++++++ 4 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 GamecraftModdingAPI/Players/PlayerTests.cs diff --git a/GamecraftModdingAPI/Blocks/BlockTests.cs b/GamecraftModdingAPI/Blocks/BlockTests.cs index 8fb40be..418fa43 100644 --- a/GamecraftModdingAPI/Blocks/BlockTests.cs +++ b/GamecraftModdingAPI/Blocks/BlockTests.cs @@ -6,6 +6,9 @@ using GamecraftModdingAPI.Tests; namespace GamecraftModdingAPI.Blocks { #if TEST + /// + /// Block test cases. Not accessible in release versions. + /// [APITestClass] public static class BlockTests { diff --git a/GamecraftModdingAPI/Player.cs b/GamecraftModdingAPI/Player.cs index 3d80e7b..cff13ff 100644 --- a/GamecraftModdingAPI/Player.cs +++ b/GamecraftModdingAPI/Player.cs @@ -413,7 +413,7 @@ namespace GamecraftModdingAPI // internal methods - public static void Init() + internal static void Init() { Utility.GameEngineManager.AddGameEngine(playerEngine); } diff --git a/GamecraftModdingAPI/Players/PlayerEngine.cs b/GamecraftModdingAPI/Players/PlayerEngine.cs index 1bcce50..d30993c 100644 --- a/GamecraftModdingAPI/Players/PlayerEngine.cs +++ b/GamecraftModdingAPI/Players/PlayerEngine.cs @@ -67,6 +67,7 @@ namespace GamecraftModdingAPI.Players public uint GetAllPlayerCount() { + if (entitiesDB == null) return 0; uint count = 0; foreach (ExclusiveGroupStruct eg in PlayersExclusiveGroups.AllPlayers) { @@ -77,22 +78,26 @@ namespace GamecraftModdingAPI.Players public uint GetLocalPlayerCount() { + if (entitiesDB == null) return 0; return entitiesDB.Count(PlayersExclusiveGroups.LocalPlayers); } public uint GetRemotePlayerCount() { + if (entitiesDB == null) return 0; return entitiesDB.Count(PlayersExclusiveGroups.RemotePlayers); } public bool ExistsById(uint playerId) { + if (entitiesDB == null) return false; return entitiesDB.Exists(playerId, PlayersExclusiveGroups.LocalPlayers) || entitiesDB.Exists(playerId, PlayersExclusiveGroups.RemotePlayers); } public float3 GetLocation(uint playerId) { + if (entitiesDB == null) return float3.zero; ref var rbes = ref GetCharacterStruct(playerId, out bool exists); if (exists) { @@ -103,6 +108,7 @@ namespace GamecraftModdingAPI.Players public bool SetLocation(uint playerId, float3 location, bool exitSeat = true) { + if (entitiesDB == null) return false; var characterGroups = CharacterExclusiveGroups.AllCharacters; for (int i = 0; i < characterGroups.count; i++) { @@ -124,6 +130,7 @@ namespace GamecraftModdingAPI.Players public float3 GetRotation(uint playerId) { + if (entitiesDB == null) return float3.zero; ref var rbes = ref GetCharacterStruct(playerId, out bool exists); if (exists) { @@ -134,6 +141,7 @@ namespace GamecraftModdingAPI.Players public bool SetRotation(uint playerId, float3 value) { + if (entitiesDB == null) return false; ref var rbes = ref GetCharacterStruct(playerId, out bool exists); if (exists) { @@ -147,6 +155,7 @@ namespace GamecraftModdingAPI.Players public float3 GetLinearVelocity(uint playerId) { + if (entitiesDB == null) return float3.zero; ref var rbes = ref GetCharacterStruct(playerId, out bool exists); if (exists) { @@ -157,6 +166,7 @@ namespace GamecraftModdingAPI.Players public bool SetLinearVelocity(uint playerId, float3 value) { + if (entitiesDB == null) return false; ref var rbes = ref GetCharacterStruct(playerId, out bool exists); if (exists) { @@ -168,6 +178,7 @@ namespace GamecraftModdingAPI.Players public float3 GetAngularVelocity(uint playerId) { + if (entitiesDB == null) return float3.zero; ref var rbes = ref GetCharacterStruct(playerId, out bool exists); if (exists) { @@ -178,6 +189,7 @@ namespace GamecraftModdingAPI.Players public bool SetAngularVelocity(uint playerId, float3 value) { + if (entitiesDB == null) return false; ref var rbes = ref GetCharacterStruct(playerId, out bool exists); if (exists) { @@ -189,6 +201,7 @@ namespace GamecraftModdingAPI.Players public PhysicsMass GetMass(uint playerId) { + if (entitiesDB == null) return default(PhysicsMass); ref var rbes = ref GetCharacterStruct(playerId, out bool exists); if (exists) { @@ -199,6 +212,7 @@ namespace GamecraftModdingAPI.Players public bool SetInverseMass(uint playerId, float inverseMass) { + if (entitiesDB == null) return false; ref var rbes = ref GetCharacterStruct(playerId, out bool exists); if (exists) { @@ -210,6 +224,7 @@ namespace GamecraftModdingAPI.Players public float? GetLastPingTime(uint playerId, PlayerType type) { + if (entitiesDB == null) return null; EGID egid = new EGID(playerId, PlayerGroupFromEnum(type)); if (entitiesDB.Exists(egid)) { @@ -220,6 +235,7 @@ namespace GamecraftModdingAPI.Players public float GetInitialHealth(uint playerId) { + if (entitiesDB == null) return 0; ref var c = ref GetCharacterStruct(playerId, out bool exists); if (exists) { @@ -230,6 +246,7 @@ namespace GamecraftModdingAPI.Players public bool SetInitialHealth(uint playerId, float val) { + if (entitiesDB == null) return false; ref var c = ref GetCharacterStruct(playerId, out bool exists); if (exists) { @@ -241,6 +258,7 @@ namespace GamecraftModdingAPI.Players public float GetCurrentHealth(uint playerId) { + if (entitiesDB == null) return 0; ref var c = ref GetCharacterStruct(playerId, out bool exists); if (exists) { @@ -251,6 +269,7 @@ namespace GamecraftModdingAPI.Players public bool SetCurrentHealth(uint playerId, float val) { + if (entitiesDB == null) return false; ref var c = ref GetCharacterStruct(playerId, out bool exists); if (exists) { @@ -262,6 +281,7 @@ namespace GamecraftModdingAPI.Players public bool DamagePlayer(uint playerId, float amount) { + if (entitiesDB == null) return false; Factory.BuildEntity( new EGID(CharacterVulnerabilityExclusiveGroups.NextDamageEntityId, CharacterVulnerabilityExclusiveGroups.CharacterDamageExclusiveGroup) ).Init(new DamageEntityStruct @@ -274,6 +294,7 @@ namespace GamecraftModdingAPI.Players public bool GetDamageable(uint playerId) { + if (entitiesDB == null) return false; ref var c = ref GetCharacterStruct(playerId, out bool exists); if (exists) { @@ -284,6 +305,7 @@ namespace GamecraftModdingAPI.Players public bool SetDamageable(uint playerId, bool val) { + if (entitiesDB == null) return false; ref var ches = ref GetCharacterStruct(playerId, out bool exists); if (exists) { @@ -296,6 +318,7 @@ namespace GamecraftModdingAPI.Players public uint GetInitialLives(uint playerId) { + if (entitiesDB == null) return 0; ref var c = ref GetCharacterStruct(playerId, out bool exists); if (exists) { @@ -306,6 +329,7 @@ namespace GamecraftModdingAPI.Players public bool SetInitialLives(uint playerId, uint val) { + if (entitiesDB == null) return false; ref var c = ref GetCharacterStruct(playerId, out bool exists); if (exists) { @@ -317,6 +341,7 @@ namespace GamecraftModdingAPI.Players public uint GetCurrentLives(uint playerId) { + if (entitiesDB == null) return 0; ref var c = ref GetCharacterStruct(playerId, out bool exists); if (exists) { @@ -327,6 +352,7 @@ namespace GamecraftModdingAPI.Players public bool SetCurrentLives(uint playerId, uint val) { + if (entitiesDB == null) return false; ref var c = ref GetCharacterStruct(playerId, out bool exists); if (exists) { @@ -338,6 +364,7 @@ namespace GamecraftModdingAPI.Players public bool GetGameOverScreen(uint playerId) { + if (entitiesDB == null) return false; ref var c = ref GetCharacterStruct(playerId, out bool exists); if (exists) { @@ -348,11 +375,13 @@ namespace GamecraftModdingAPI.Players public bool IsDead(uint playerId) { + if (entitiesDB == null) return true; return entitiesDB.Exists(playerId, CharacterExclusiveGroups.DeadCharacters); } public int GetSelectedBlock(uint playerId) { + if (entitiesDB == null) return 0; ref var c = ref GetCharacterStruct(playerId, out bool exists); if (exists) { @@ -363,6 +392,7 @@ namespace GamecraftModdingAPI.Players public byte GetSelectedColor(uint playerId) { + if (entitiesDB == null) return 0; ref var c = ref GetCharacterStruct(playerId, out bool exists); if (exists) { diff --git a/GamecraftModdingAPI/Players/PlayerTests.cs b/GamecraftModdingAPI/Players/PlayerTests.cs new file mode 100644 index 0000000..1af7992 --- /dev/null +++ b/GamecraftModdingAPI/Players/PlayerTests.cs @@ -0,0 +1,42 @@ +using System; + +using Unity.Mathematics; + +using GamecraftModdingAPI; +using GamecraftModdingAPI.Tests; + +namespace GamecraftModdingAPI.Players +{ +#if TEST + /// + /// Player test cases. Not accessible in release versions. + /// + [APITestClass] + public static class PlayerTests + { + [APITestCase(TestType.EditMode)] + public static void ExistsTest() + { + if (!Assert.Equal(Player.Exists(PlayerType.Local), true, "Local player does not exist.", "Local player detected.")) return; + Assert.Equal(Player.Count(), 1u, "Player.Count() is not one, possibly because it failed silently.", "Player count is one for single player game."); + } + + [APITestCase(TestType.EditMode)] + public static void PositionTest() + { + Player p = new Player(PlayerType.Local); + if (!Assert.Errorless(() => { p.Teleport(0, 0, 0, relative: false); }, "Player.Teleport(origin) errored: ", "Player teleported to origin successfully.")) return; + if (!Assert.CloseTo(p.Position, float3.zero, "Player is not close to origin despite being teleported there.", "Player.Position is at origin.")) return; + if (!Assert.Errorless(() => { p.Position = float3.zero + 1; }, "Player.Position = origin+1 errored: ", "Player moved to origin+1.")) return; + Assert.CloseTo(p.Position, float3.zero + 1, "Player is not close to origin+1 despite being teleported there.", "Player.Position is at origin+1."); + } + + [APITestCase(TestType.Menu)] + public static void InvalidStateTest() + { + if (!Assert.Errorless(() => { Player.Count(); }, "Player.Count() errored in menu.", "Player.Count() succeeded in menu.")) return; + Assert.Equal(Player.Count(), 0u, "Player.Count() is not zero in menu.", "Player count is zero in menu as expected."); + } + } +#endif +} From f403feb298ff9b6f8d385069229ca79700a0a477 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 11 Jul 2020 00:30:58 +0200 Subject: [PATCH 11/34] Update to Gamecraft 2020.06.17.08.41 (preview) Removed BlockIdentifiers.OWNED_BLOCKS as the original got replaced with an array Added the correct group for each supported functional block Removed EntityFactory property from IEntitySerializer as it is provided on deserialization --- .../App/GameBuildSimEventEngine.cs | 8 +++--- GamecraftModdingAPI/App/GameGameEngine.cs | 28 ++++++++----------- GamecraftModdingAPI/Block.cs | 12 ++++---- GamecraftModdingAPI/Blocks/BlockEngine.cs | 25 +++++++++-------- .../Blocks/BlockIdentifiers.cs | 8 +++--- GamecraftModdingAPI/Blocks/ConsoleBlock.cs | 3 +- GamecraftModdingAPI/Blocks/Motor.cs | 3 +- GamecraftModdingAPI/Blocks/MovementEngine.cs | 16 +++++------ .../Blocks/ObjectIdentifier.cs | 3 +- GamecraftModdingAPI/Blocks/Piston.cs | 3 +- GamecraftModdingAPI/Blocks/PlacementEngine.cs | 19 ++----------- GamecraftModdingAPI/Blocks/RotationEngine.cs | 16 +++++------ GamecraftModdingAPI/Blocks/Servo.cs | 3 +- GamecraftModdingAPI/Blocks/SignalEngine.cs | 22 +++++---------- GamecraftModdingAPI/Blocks/SpawnPoint.cs | 3 +- GamecraftModdingAPI/Blocks/TextBlock.cs | 3 +- GamecraftModdingAPI/Blocks/Timer.cs | 3 +- .../Events/GameStateBuildEmitterEngine.cs | 4 +-- .../GameStateSimulationEmitterEngine.cs | 4 +-- .../GamecraftModdingAPI.csproj | 4 --- .../Persistence/IEntitySerializer.cs | 8 +----- .../Persistence/SerializerManager.cs | 3 -- .../Persistence/SimpleEntitySerializer.cs | 6 ++-- GamecraftModdingAPI/Player.cs | 4 +-- GamecraftModdingAPI/Players/PlayerEngine.cs | 8 +++--- 25 files changed, 93 insertions(+), 126 deletions(-) diff --git a/GamecraftModdingAPI/App/GameBuildSimEventEngine.cs b/GamecraftModdingAPI/App/GameBuildSimEventEngine.cs index b4bc049..4c9a536 100644 --- a/GamecraftModdingAPI/App/GameBuildSimEventEngine.cs +++ b/GamecraftModdingAPI/App/GameBuildSimEventEngine.cs @@ -26,16 +26,16 @@ namespace GamecraftModdingAPI.App public void Ready() { } - public JobHandle OnInitializeTimeRunningMode() + public JobHandle OnInitializeTimeRunningMode(JobHandle inputDeps) { ExceptionUtil.InvokeEvent(SimulationMode, this, new GameEventArgs { GameName = GameMode.SaveGameDetails.Name, GamePath = GameMode.SaveGameDetails.Folder }); - return default(JobHandle); + return inputDeps; } - public JobHandle OnInitializeTimeStoppedMode() + public JobHandle OnInitializeTimeStoppedMode(JobHandle inputDeps) { ExceptionUtil.InvokeEvent(BuildMode, this, new GameEventArgs { GameName = GameMode.SaveGameDetails.Name, GamePath = GameMode.SaveGameDetails.Folder }); - return default(JobHandle); + return inputDeps; } } diff --git a/GamecraftModdingAPI/App/GameGameEngine.cs b/GamecraftModdingAPI/App/GameGameEngine.cs index cbb1c79..a616df5 100644 --- a/GamecraftModdingAPI/App/GameGameEngine.cs +++ b/GamecraftModdingAPI/App/GameGameEngine.cs @@ -97,28 +97,22 @@ namespace GamecraftModdingAPI.App public EGID[] GetAllBlocksInGame(BlockIDs filter = BlockIDs.Invalid) { - EntityCollection blocks = entitiesDB.QueryEntities(CommonExclusiveGroups.OWNED_BLOCKS_GROUP); + var allBlocks = entitiesDB.QueryEntities(); + List blockEGIDs = new List(); if (filter == BlockIDs.Invalid) { - EGID[] blockEGIDs = new EGID[blocks.count]; - for (uint b = 0; b < blocks.count; b++) - { - blockEGIDs[b] = blocks[b].ID; - } - return blockEGIDs; + foreach (var (blocks, _) in allBlocks) + foreach (var block in blocks) + blockEGIDs.Add(block.ID); + return blockEGIDs.ToArray(); } else { - uint dbidFilter = (uint)filter; - List blockEGIDs = new List(); - for (uint b = 0; b < blocks.count; b++) - { - if (blocks[b].DBID == dbidFilter) - { - blockEGIDs.Add(blocks[b].ID); - } - } - return blockEGIDs.ToArray(); + foreach (var (blocks, _) in allBlocks) + foreach (var block in blocks) + if (block.DBID == (ulong) filter) + blockEGIDs.Add(block.ID); + return blockEGIDs.ToArray(); } } } diff --git a/GamecraftModdingAPI/Block.cs b/GamecraftModdingAPI/Block.cs index f97c57c..939d16c 100644 --- a/GamecraftModdingAPI/Block.cs +++ b/GamecraftModdingAPI/Block.cs @@ -135,8 +135,8 @@ namespace GamecraftModdingAPI Id = id; } - public Block(uint id) : this(new EGID(id, CommonExclusiveGroups.OWNED_BLOCKS_GROUP)) - { + public Block(uint id) : this(new EGID(id, CommonExclusiveGroups.BUILD_STANDARD_BLOCK_GROUP)) + { //TODO: Figure out the block group based on the id } public EGID Id { get; } @@ -147,10 +147,10 @@ namespace GamecraftModdingAPI /// public float3 Position { - get => Exists ? MovementEngine.GetPosition(Id.entityID) : float3.zero; + get => Exists ? MovementEngine.GetPosition(Id) : float3.zero; set { - if (Exists) MovementEngine.MoveBlock(Id.entityID, value); + if (Exists) MovementEngine.MoveBlock(Id, value); } } @@ -159,10 +159,10 @@ namespace GamecraftModdingAPI /// public float3 Rotation { - get => Exists ? RotationEngine.GetRotation(Id.entityID) : float3.zero; + get => Exists ? RotationEngine.GetRotation(Id) : float3.zero; set { - if (Exists) RotationEngine.RotateBlock(Id.entityID, value); + if (Exists) RotationEngine.RotateBlock(Id, value); } } diff --git a/GamecraftModdingAPI/Blocks/BlockEngine.cs b/GamecraftModdingAPI/Blocks/BlockEngine.cs index 3473106..4a90de7 100644 --- a/GamecraftModdingAPI/Blocks/BlockEngine.cs +++ b/GamecraftModdingAPI/Blocks/BlockEngine.cs @@ -38,14 +38,15 @@ namespace GamecraftModdingAPI.Blocks public Block[] GetConnectedBlocks(EGID blockID) { if (!BlockExists(blockID)) return new Block[0]; - Stack cubeStack = new Stack(); - FasterList cubes = new FasterList(10); - var coll = entitiesDB.QueryEntities(CommonExclusiveGroups - .OWNED_BLOCKS_GROUP); - for (int i = 0; i < coll.count; i++) - coll[i].isProcessed = false; + Stack cubeStack = new Stack(); + FasterList cubes = new FasterList(10); + var coll = entitiesDB.QueryEntities(); + foreach (var (ecoll, _) in coll) + foreach (ref var conn in ecoll) + conn.isProcessed = false; - ConnectedCubesUtility.TreeTraversal.GetConnectedCubes(entitiesDB, blockID.entityID, cubeStack, cubes, (in GridConnectionsEntityStruct g) => { return false; }); + ConnectedCubesUtility.TreeTraversal.GetConnectedCubes(entitiesDB, blockID, cubeStack, cubes, + (in GridConnectionsEntityStruct g) => { return false; }); var ret = new Block[cubes.count]; for (int i = 0; i < cubes.count; i++) @@ -125,10 +126,10 @@ namespace GamecraftModdingAPI.Blocks public SimBody[] GetSimBodiesFromID(byte id) { var ret = new FasterList(4); - if (!entitiesDB.HasAny(CommonExclusiveGroups.OWNED_BLOCKS_GROUP)) + if (!entitiesDB.HasAny(CommonExclusiveGroups.BUILD_OBJID_BLOCK_GROUP)) return new SimBody[0]; - var oids = entitiesDB.QueryEntities(CommonExclusiveGroups.OWNED_BLOCKS_GROUP); - var connections = entitiesDB.QueryMappedEntities(CommonExclusiveGroups.OWNED_BLOCKS_GROUP); + var oids = entitiesDB.QueryEntities(CommonExclusiveGroups.BUILD_OBJID_BLOCK_GROUP); + var connections = entitiesDB.QueryMappedEntities(CommonExclusiveGroups.BUILD_OBJID_BLOCK_GROUP); foreach (ref ObjectIdEntityStruct oid in oids) { if (oid.objectId != id) continue; @@ -147,9 +148,9 @@ namespace GamecraftModdingAPI.Blocks public ObjectIdentifier[] GetObjectIDsFromID(byte id, bool sim) { var ret = new FasterList(4); - if (!entitiesDB.HasAny(CommonExclusiveGroups.OWNED_BLOCKS_GROUP)) + if (!entitiesDB.HasAny(CommonExclusiveGroups.BUILD_OBJID_BLOCK_GROUP)) return new ObjectIdentifier[0]; - var oids = entitiesDB.QueryEntities(CommonExclusiveGroups.OWNED_BLOCKS_GROUP); + var oids = entitiesDB.QueryEntities(CommonExclusiveGroups.BUILD_OBJID_BLOCK_GROUP); foreach (ref ObjectIdEntityStruct oid in oids) if (sim ? oid.simObjectId == id : oid.objectId == id) ret.Add(new ObjectIdentifier(oid.ID)); diff --git a/GamecraftModdingAPI/Blocks/BlockIdentifiers.cs b/GamecraftModdingAPI/Blocks/BlockIdentifiers.cs index eb479c0..0c3222b 100644 --- a/GamecraftModdingAPI/Blocks/BlockIdentifiers.cs +++ b/GamecraftModdingAPI/Blocks/BlockIdentifiers.cs @@ -12,8 +12,8 @@ namespace GamecraftModdingAPI.Blocks { /// /// Blocks placed by the player - /// - public static ExclusiveGroup OWNED_BLOCKS { get { return CommonExclusiveGroups.OWNED_BLOCKS_GROUP; } } + /// - TODO + //public static ExclusiveGroup OWNED_BLOCKS { get { return CommonExclusiveGroups.REAL_BLOCKS_GROUPS_DON_T_USE_IN_NEW_CODE; } } /// /// Extra parts used in functional blocks @@ -23,7 +23,7 @@ namespace GamecraftModdingAPI.Blocks /// /// Blocks which are disabled in Simulation mode /// - public static ExclusiveGroup SIM_BLOCKS_DISABLED { get { return CommonExclusiveGroups.BLOCKS_DISABLED_IN_SIM_GROUP; } } + public static ExclusiveGroup SIM_BLOCKS_DISABLED { get { return CommonExclusiveGroups.DISABLED_JOINTS_IN_SIM_GROUP; } } //public static ExclusiveGroup SPAWN_POINTS { get { return CommonExclusiveGroups.SPAWN_POINTS_GROUP; } } @@ -34,7 +34,7 @@ namespace GamecraftModdingAPI.Blocks /// public static uint LatestBlockID { get - { + { //Need the private field as the property increments itself return ((uint) AccessTools.Field(typeof(CommonExclusiveGroups), "_nextBlockEntityID").GetValue(null)) - 1; } } diff --git a/GamecraftModdingAPI/Blocks/ConsoleBlock.cs b/GamecraftModdingAPI/Blocks/ConsoleBlock.cs index 173b3f6..6d4217d 100644 --- a/GamecraftModdingAPI/Blocks/ConsoleBlock.cs +++ b/GamecraftModdingAPI/Blocks/ConsoleBlock.cs @@ -1,6 +1,7 @@ using System; using RobocraftX.Blocks; +using RobocraftX.Common; using Svelto.ECS; using Unity.Mathematics; @@ -33,7 +34,7 @@ namespace GamecraftModdingAPI.Blocks } } - public ConsoleBlock(uint id): base(id) + public ConsoleBlock(uint id): base(new EGID(id, CommonExclusiveGroups.BUILD_CONSOLE_BLOCK_GROUP)) { if (!BlockEngine.GetBlockInfoExists(this.Id)) { diff --git a/GamecraftModdingAPI/Blocks/Motor.cs b/GamecraftModdingAPI/Blocks/Motor.cs index c900f10..55f3649 100644 --- a/GamecraftModdingAPI/Blocks/Motor.cs +++ b/GamecraftModdingAPI/Blocks/Motor.cs @@ -1,6 +1,7 @@ using System; using RobocraftX.Blocks; +using RobocraftX.Common; using Svelto.ECS; using Unity.Mathematics; @@ -41,7 +42,7 @@ namespace GamecraftModdingAPI.Blocks } } - public Motor(uint id) : base(id) + public Motor(uint id): base(new EGID(id, CommonExclusiveGroups.BUILD_MOTOR_BLOCK_GROUP)) { if (!BlockEngine.GetBlockInfoExists(this.Id)) { diff --git a/GamecraftModdingAPI/Blocks/MovementEngine.cs b/GamecraftModdingAPI/Blocks/MovementEngine.cs index a887763..0ff119a 100644 --- a/GamecraftModdingAPI/Blocks/MovementEngine.cs +++ b/GamecraftModdingAPI/Blocks/MovementEngine.cs @@ -35,12 +35,12 @@ namespace GamecraftModdingAPI.Blocks // implementations for Movement static class - public float3 MoveBlock(uint blockID, float3 vector) + public float3 MoveBlock(EGID blockID, float3 vector) { - ref PositionEntityStruct posStruct = ref this.entitiesDB.QueryEntity(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP); - ref GridRotationStruct gridStruct = ref this.entitiesDB.QueryEntity(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP); - ref LocalTransformEntityStruct transStruct = ref this.entitiesDB.QueryEntity(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP); - ref UECSPhysicsEntityStruct phyStruct = ref this.entitiesDB.QueryEntity(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP); + ref PositionEntityStruct posStruct = ref this.entitiesDB.QueryEntity(blockID); + ref GridRotationStruct gridStruct = ref this.entitiesDB.QueryEntity(blockID); + ref LocalTransformEntityStruct transStruct = ref this.entitiesDB.QueryEntity(blockID); + ref UECSPhysicsEntityStruct phyStruct = ref this.entitiesDB.QueryEntity(blockID); // main (persistent) position posStruct.position = vector; // placement grid position @@ -52,13 +52,13 @@ namespace GamecraftModdingAPI.Blocks { Value = posStruct.position }); - entitiesDB.QueryEntity(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP).isProcessed = false; + entitiesDB.QueryEntity(blockID).isProcessed = false; return posStruct.position; } - public float3 GetPosition(uint blockID) + public float3 GetPosition(EGID blockID) { - ref PositionEntityStruct posStruct = ref this.entitiesDB.QueryEntity(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP); + ref PositionEntityStruct posStruct = ref this.entitiesDB.QueryEntity(blockID); return posStruct.position; } } diff --git a/GamecraftModdingAPI/Blocks/ObjectIdentifier.cs b/GamecraftModdingAPI/Blocks/ObjectIdentifier.cs index 6357053..9af96c2 100644 --- a/GamecraftModdingAPI/Blocks/ObjectIdentifier.cs +++ b/GamecraftModdingAPI/Blocks/ObjectIdentifier.cs @@ -1,4 +1,5 @@ using Gamecraft.Wires; +using RobocraftX.Common; using Svelto.ECS; namespace GamecraftModdingAPI.Blocks @@ -13,7 +14,7 @@ namespace GamecraftModdingAPI.Blocks } } - public ObjectIdentifier(uint id) : base(id) + public ObjectIdentifier(uint id) : base(new EGID(id, CommonExclusiveGroups.BUILD_OBJID_BLOCK_GROUP)) { if (!BlockEngine.GetBlockInfoExists(Id)) { diff --git a/GamecraftModdingAPI/Blocks/Piston.cs b/GamecraftModdingAPI/Blocks/Piston.cs index 00ad273..b96a806 100644 --- a/GamecraftModdingAPI/Blocks/Piston.cs +++ b/GamecraftModdingAPI/Blocks/Piston.cs @@ -5,6 +5,7 @@ using Svelto.ECS; using Unity.Mathematics; using GamecraftModdingAPI.Utility; +using RobocraftX.Common; namespace GamecraftModdingAPI.Blocks { @@ -41,7 +42,7 @@ namespace GamecraftModdingAPI.Blocks } } - public Piston(uint id) : base(id) + public Piston(uint id) : base(new EGID(id, CommonExclusiveGroups.BUILD_PISTON_BLOCK_GROUP)) { if (!BlockEngine.GetBlockInfoExists(this.Id)) { diff --git a/GamecraftModdingAPI/Blocks/PlacementEngine.cs b/GamecraftModdingAPI/Blocks/PlacementEngine.cs index 35f0a92..2297d90 100644 --- a/GamecraftModdingAPI/Blocks/PlacementEngine.cs +++ b/GamecraftModdingAPI/Blocks/PlacementEngine.cs @@ -66,8 +66,6 @@ namespace GamecraftModdingAPI.Blocks RotationEntityStruct rotation = new RotationEntityStruct {rotation = rotQ}; GridRotationStruct gridRotation = new GridRotationStruct {position = position, rotation = rotQ}; - CubeCategoryStruct category = new CubeCategoryStruct - {category = CubeCategory.General, type = CubeType.Block}; DBEntityStruct dbEntity = new DBEntityStruct {DBID = dbid}; BlockPlacementScaleEntityStruct placementScale = new BlockPlacementScaleEntityStruct { @@ -76,21 +74,10 @@ namespace GamecraftModdingAPI.Blocks unitSnapOffset = 0, isUsingUnitSize = true }; EquippedColourStruct colour = new EquippedColourStruct {indexInPalette = color}; - EGID newBlockID; - switch (category.category) - { - case CubeCategory.SpawnPoint: - case CubeCategory.BuildingSpawnPoint: - newBlockID = MachineEditingGroups.NewUncheckedBlockEGID; - break; - default: - newBlockID = MachineEditingGroups.NewBlockID; - break; - } EntityComponentInitializer structInitializer = - _blockEntityFactory.Build(newBlockID, dbid); //The ghost block index is only used for triggers + _blockEntityFactory.Build(CommonExclusiveGroups.nextBlockEntityID, dbid); //The ghost block index is only used for triggers if (colour.indexInPalette != byte.MaxValue) structInitializer.Init(new ColourParameterEntityStruct { @@ -117,10 +104,10 @@ namespace GamecraftModdingAPI.Blocks PrimaryRotationUtility.InitialisePrimaryDirection(rotation.rotation, ref structInitializer); EGID playerEGID = new EGID(playerId, CharacterExclusiveGroups.OnFootGroup); ref PickedBlockExtraDataStruct pickedBlock = ref entitiesDB.QueryEntity(playerEGID); - pickedBlock.placedBlockEntityID = playerEGID; + pickedBlock.placedBlockEntityID = structInitializer.EGID; pickedBlock.placedBlockWasAPickedBlock = false; Block.BlockEngine.Synced = false; // Block entities will need to be submitted before properties can be used - return newBlockID; + return structInitializer.EGID; } public string Name { get; } = "GamecraftModdingAPIPlacementGameEngine"; diff --git a/GamecraftModdingAPI/Blocks/RotationEngine.cs b/GamecraftModdingAPI/Blocks/RotationEngine.cs index 88c43d2..e9cd1ef 100644 --- a/GamecraftModdingAPI/Blocks/RotationEngine.cs +++ b/GamecraftModdingAPI/Blocks/RotationEngine.cs @@ -35,12 +35,12 @@ namespace GamecraftModdingAPI.Blocks // implementations for Rotation static class - public float3 RotateBlock(uint blockID, Vector3 vector) + public float3 RotateBlock(EGID blockID, Vector3 vector) { - ref RotationEntityStruct rotStruct = ref this.entitiesDB.QueryEntity(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP); - ref GridRotationStruct gridStruct = ref this.entitiesDB.QueryEntity(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP); - ref LocalTransformEntityStruct transStruct = ref this.entitiesDB.QueryEntity(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP); - ref UECSPhysicsEntityStruct phyStruct = ref this.entitiesDB.QueryEntity(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP); + ref RotationEntityStruct rotStruct = ref this.entitiesDB.QueryEntity(blockID); + ref GridRotationStruct gridStruct = ref this.entitiesDB.QueryEntity(blockID); + ref LocalTransformEntityStruct transStruct = ref this.entitiesDB.QueryEntity(blockID); + ref UECSPhysicsEntityStruct phyStruct = ref this.entitiesDB.QueryEntity(blockID); // main (persistent) position Quaternion newRotation = (Quaternion)rotStruct.rotation; newRotation.eulerAngles += vector; @@ -58,14 +58,14 @@ namespace GamecraftModdingAPI.Blocks { Value = rotStruct.rotation }); - entitiesDB.QueryEntity(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP).isProcessed = false; + entitiesDB.QueryEntity(blockID).isProcessed = false; return ((Quaternion)rotStruct.rotation).eulerAngles; } - public float3 GetRotation(uint blockID) + public float3 GetRotation(EGID blockID) { - ref RotationEntityStruct rotStruct = ref entitiesDB.QueryEntity(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP); + ref RotationEntityStruct rotStruct = ref entitiesDB.QueryEntity(blockID); return ((Quaternion) rotStruct.rotation).eulerAngles; } } diff --git a/GamecraftModdingAPI/Blocks/Servo.cs b/GamecraftModdingAPI/Blocks/Servo.cs index 9a66e3b..ef7225b 100644 --- a/GamecraftModdingAPI/Blocks/Servo.cs +++ b/GamecraftModdingAPI/Blocks/Servo.cs @@ -1,6 +1,7 @@ using System; using RobocraftX.Blocks; +using RobocraftX.Common; using Svelto.ECS; using Unity.Mathematics; @@ -41,7 +42,7 @@ namespace GamecraftModdingAPI.Blocks } } - public Servo(uint id) : base(id) + public Servo(uint id) : base(new EGID(id, CommonExclusiveGroups.BUILD_SERVO_BLOCK_GROUP)) { if (!BlockEngine.GetBlockInfoExists(this.Id)) { diff --git a/GamecraftModdingAPI/Blocks/SignalEngine.cs b/GamecraftModdingAPI/Blocks/SignalEngine.cs index b36e708..13a0b3b 100644 --- a/GamecraftModdingAPI/Blocks/SignalEngine.cs +++ b/GamecraftModdingAPI/Blocks/SignalEngine.cs @@ -1,4 +1,5 @@ using Svelto.ECS; +using Svelto.DataStructures; using Gamecraft.Wires; using GamecraftModdingAPI.Engines; @@ -166,21 +167,12 @@ namespace GamecraftModdingAPI.Blocks } public EGID[] GetElectricBlocks() - { - uint count = entitiesDB.Count(BlockIdentifiers.OWNED_BLOCKS) + entitiesDB.Count(BlockIdentifiers.FUNCTIONAL_BLOCK_PARTS); - uint i = 0; - EGID[] res = new EGID[count]; - foreach (ref BlockPortsStruct s in entitiesDB.QueryEntities(BlockIdentifiers.OWNED_BLOCKS)) - { - res[i] = s.ID; - i++; - } - foreach (ref BlockPortsStruct s in entitiesDB.QueryEntities(BlockIdentifiers.FUNCTIONAL_BLOCK_PARTS)) - { - res[i] = s.ID; - i++; - } - return res; + { + var res = new FasterList(); + foreach (var (coll, _) in entitiesDB.QueryEntities()) + foreach (ref BlockPortsStruct s in coll) + res.Add(s.ID); + return res.ToArray(); } private EntityCollection GetSignalStruct(uint signalID, out uint index, bool input = true) diff --git a/GamecraftModdingAPI/Blocks/SpawnPoint.cs b/GamecraftModdingAPI/Blocks/SpawnPoint.cs index bb3e7f4..65ef750 100644 --- a/GamecraftModdingAPI/Blocks/SpawnPoint.cs +++ b/GamecraftModdingAPI/Blocks/SpawnPoint.cs @@ -1,6 +1,7 @@ using System; using RobocraftX.Blocks; +using RobocraftX.Common; using Gamecraft.CharacterVulnerability; using Svelto.ECS; using Unity.Mathematics; @@ -43,7 +44,7 @@ namespace GamecraftModdingAPI.Blocks } } - public SpawnPoint(uint id) : base(id) + public SpawnPoint(uint id) : base(new EGID(id, CommonExclusiveGroups.BUILD_SPAWNPOINT_BLOCK_GROUP)) { if (!BlockEngine.GetBlockInfoExists(this.Id)) { diff --git a/GamecraftModdingAPI/Blocks/TextBlock.cs b/GamecraftModdingAPI/Blocks/TextBlock.cs index 92f8116..c1a9344 100644 --- a/GamecraftModdingAPI/Blocks/TextBlock.cs +++ b/GamecraftModdingAPI/Blocks/TextBlock.cs @@ -1,6 +1,7 @@ using System; using Gamecraft.Blocks.GUI; +using RobocraftX.Common; using Svelto.ECS; using Unity.Mathematics; @@ -34,7 +35,7 @@ namespace GamecraftModdingAPI.Blocks } } - public TextBlock(uint id) : base(id) + public TextBlock(uint id) : base(new EGID(id, CommonExclusiveGroups.BUILD_TEXT_BLOCK_GROUP)) { if (!BlockEngine.GetBlockInfoExists(this.Id)) { diff --git a/GamecraftModdingAPI/Blocks/Timer.cs b/GamecraftModdingAPI/Blocks/Timer.cs index d26620e..0e7f744 100644 --- a/GamecraftModdingAPI/Blocks/Timer.cs +++ b/GamecraftModdingAPI/Blocks/Timer.cs @@ -1,6 +1,7 @@ using System; using RobocraftX.Blocks; +using RobocraftX.Common; using Gamecraft.Blocks.TimerBlock; using Svelto.ECS; using Unity.Mathematics; @@ -37,7 +38,7 @@ namespace GamecraftModdingAPI.Blocks } } - public Timer(uint id) : base(id) + public Timer(uint id) : base(new EGID(id, CommonExclusiveGroups.BUILD_TIMER_BLOCK_GROUP)) { if (!BlockEngine.GetBlockInfoExists(this.Id)) { diff --git a/GamecraftModdingAPI/Events/GameStateBuildEmitterEngine.cs b/GamecraftModdingAPI/Events/GameStateBuildEmitterEngine.cs index ed89812..a12433a 100644 --- a/GamecraftModdingAPI/Events/GameStateBuildEmitterEngine.cs +++ b/GamecraftModdingAPI/Events/GameStateBuildEmitterEngine.cs @@ -43,10 +43,10 @@ namespace GamecraftModdingAPI.Events } } - public JobHandle OnInitializeTimeStoppedMode() + public JobHandle OnInitializeTimeStoppedMode(JobHandle inputDeps) { Emit(); - return default(JobHandle); + return inputDeps; } public void Ready() { } diff --git a/GamecraftModdingAPI/Events/GameStateSimulationEmitterEngine.cs b/GamecraftModdingAPI/Events/GameStateSimulationEmitterEngine.cs index 165e7c5..5689db9 100644 --- a/GamecraftModdingAPI/Events/GameStateSimulationEmitterEngine.cs +++ b/GamecraftModdingAPI/Events/GameStateSimulationEmitterEngine.cs @@ -42,10 +42,10 @@ namespace GamecraftModdingAPI.Events } } - public JobHandle OnInitializeTimeRunningMode() + public JobHandle OnInitializeTimeRunningMode(JobHandle inputDeps) { Emit(); - return default(JobHandle); + return inputDeps; } public void Ready() { } diff --git a/GamecraftModdingAPI/GamecraftModdingAPI.csproj b/GamecraftModdingAPI/GamecraftModdingAPI.csproj index 199eed6..29cc08f 100644 --- a/GamecraftModdingAPI/GamecraftModdingAPI.csproj +++ b/GamecraftModdingAPI/GamecraftModdingAPI.csproj @@ -80,10 +80,6 @@ ..\ref\Gamecraft_Data\Managed\Blocks.HUDFeedbackBlocks.dll ..\..\ref\Gamecraft_Data\Managed\Blocks.HUDFeedbackBlocks.dll - - ..\ref\Gamecraft_Data\Managed\ClusterToWireConversion.Mock.dll - ..\..\ref\Gamecraft_Data\Managed\ClusterToWireConversion.Mock.dll - ..\ref\Gamecraft_Data\Managed\CommandLine.dll ..\..\ref\Gamecraft_Data\Managed\CommandLine.dll diff --git a/GamecraftModdingAPI/Persistence/IEntitySerializer.cs b/GamecraftModdingAPI/Persistence/IEntitySerializer.cs index a060f3c..5c4fb85 100644 --- a/GamecraftModdingAPI/Persistence/IEntitySerializer.cs +++ b/GamecraftModdingAPI/Persistence/IEntitySerializer.cs @@ -12,13 +12,7 @@ namespace GamecraftModdingAPI.Persistence /// public interface IEntitySerializer : IDeserializationFactory, IQueryingEntitiesEngine { - /// - /// The entity factory used for creating entities and entity components. - /// - /// The entity factory. - IEntityFactory EntityFactory { set; } - - /// + /// /// Serialize the entities. /// /// Whether serialization was successful. diff --git a/GamecraftModdingAPI/Persistence/SerializerManager.cs b/GamecraftModdingAPI/Persistence/SerializerManager.cs index 0584834..161662b 100644 --- a/GamecraftModdingAPI/Persistence/SerializerManager.cs +++ b/GamecraftModdingAPI/Persistence/SerializerManager.cs @@ -29,7 +29,6 @@ namespace GamecraftModdingAPI.Persistence _registrations[name] = (IEntitySerialization ies) => { ies.RegisterSerializationFactory(serializer); }; if (_lastEnginesRoot != null) { - serializer.EntityFactory = _lastEnginesRoot.GenerateEntityFactory(); _registrations[name].Invoke(_lastEnginesRoot.GenerateEntitySerializer()); _lastEnginesRoot.AddEngine(serializer); } @@ -63,12 +62,10 @@ namespace GamecraftModdingAPI.Persistence public static void RegisterSerializers(EnginesRoot enginesRoot) { _lastEnginesRoot = enginesRoot; - IEntityFactory factory = enginesRoot.GenerateEntityFactory(); IEntitySerialization ies = enginesRoot.GenerateEntitySerializer(); foreach (string key in _serializers.Keys) { Logging.MetaDebugLog($"Registering IEntitySerializer for {key}"); - _serializers[key].EntityFactory = factory; _registrations[key].Invoke(ies); enginesRoot.AddEngine(_serializers[key]); } diff --git a/GamecraftModdingAPI/Persistence/SimpleEntitySerializer.cs b/GamecraftModdingAPI/Persistence/SimpleEntitySerializer.cs index 1048edb..3e136ae 100644 --- a/GamecraftModdingAPI/Persistence/SimpleEntitySerializer.cs +++ b/GamecraftModdingAPI/Persistence/SimpleEntitySerializer.cs @@ -21,13 +21,11 @@ namespace GamecraftModdingAPI.Persistence protected int serializationType; - public IEntityFactory EntityFactory { set; protected get; } - public EntitiesDB entitiesDB { set; protected get; } - public EntityComponentInitializer BuildDeserializedEntity(EGID egid, ISerializationData serializationData, ISerializableEntityDescriptor entityDescriptor, int serializationType, IEntitySerialization entitySerialization) + public EntityComponentInitializer BuildDeserializedEntity(EGID egid, ISerializationData serializationData, ISerializableEntityDescriptor entityDescriptor, int serializationType, IEntitySerialization entitySerialization, IEntityFactory factory, bool enginesRootIsDeserializationOnly) { - EntityComponentInitializer esi = EntityFactory.BuildEntity(egid); + EntityComponentInitializer esi = factory.BuildEntity(egid); entitySerialization.DeserializeEntityComponents(serializationData, entityDescriptor, ref esi, serializationType); return esi; } diff --git a/GamecraftModdingAPI/Player.cs b/GamecraftModdingAPI/Player.cs index cff13ff..40dd385 100644 --- a/GamecraftModdingAPI/Player.cs +++ b/GamecraftModdingAPI/Player.cs @@ -51,7 +51,7 @@ namespace GamecraftModdingAPI /// The count. public static uint Count() { - return playerEngine.GetAllPlayerCount(); + return (uint) playerEngine.GetAllPlayerCount(); } /// @@ -357,7 +357,7 @@ namespace GamecraftModdingAPI public Block GetBlockLookedAt(float maxDistance = -1f) { var egid = playerEngine.GetThingLookedAt(Id, maxDistance); - return egid.HasValue && egid.Value.groupID == CommonExclusiveGroups.OWNED_BLOCKS_GROUP + return egid.HasValue && egid.Value.groupID != CommonExclusiveGroups.SIMULATION_BODIES_GROUP ? new Block(egid.Value) : null; } diff --git a/GamecraftModdingAPI/Players/PlayerEngine.cs b/GamecraftModdingAPI/Players/PlayerEngine.cs index d30993c..805ae21 100644 --- a/GamecraftModdingAPI/Players/PlayerEngine.cs +++ b/GamecraftModdingAPI/Players/PlayerEngine.cs @@ -65,10 +65,10 @@ namespace GamecraftModdingAPI.Players return uint.MaxValue; } - public uint GetAllPlayerCount() + public long GetAllPlayerCount() { if (entitiesDB == null) return 0; - uint count = 0; + long count = 0; foreach (ExclusiveGroupStruct eg in PlayersExclusiveGroups.AllPlayers) { count += entitiesDB.Count(eg); @@ -76,13 +76,13 @@ namespace GamecraftModdingAPI.Players return count; } - public uint GetLocalPlayerCount() + public long GetLocalPlayerCount() { if (entitiesDB == null) return 0; return entitiesDB.Count(PlayersExclusiveGroups.LocalPlayers); } - public uint GetRemotePlayerCount() + public long GetRemotePlayerCount() { if (entitiesDB == null) return 0; return entitiesDB.Count(PlayersExclusiveGroups.RemotePlayers); From aa0aefd41b4b1bbf1adb55bc1850d6f1e5baf5d3 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 11 Jul 2020 02:26:36 +0200 Subject: [PATCH 12/34] Find block when group is unknown --- GamecraftModdingAPI/Block.cs | 10 ++++++++-- GamecraftModdingAPI/Blocks/BlockEngine.cs | 12 ++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/GamecraftModdingAPI/Block.cs b/GamecraftModdingAPI/Block.cs index 939d16c..16a0c81 100644 --- a/GamecraftModdingAPI/Block.cs +++ b/GamecraftModdingAPI/Block.cs @@ -135,8 +135,14 @@ namespace GamecraftModdingAPI Id = id; } - public Block(uint id) : this(new EGID(id, CommonExclusiveGroups.BUILD_STANDARD_BLOCK_GROUP)) - { //TODO: Figure out the block group based on the id + /// + /// This overload searches for the correct group the block is in. + /// It will throw an exception if the block doesn't exist. + /// Use the EGID constructor where possible or subclasses of Block as those specify the group. + /// + public Block(uint id) + { + Id = BlockEngine.FindBlockEGID(id) ?? throw new BlockTypeException("Could not find the appropriate group for the block. The block probably doesn't exist or hasn't been submitted."); } public EGID Id { get; } diff --git a/GamecraftModdingAPI/Blocks/BlockEngine.cs b/GamecraftModdingAPI/Blocks/BlockEngine.cs index 4a90de7..81a1630 100644 --- a/GamecraftModdingAPI/Blocks/BlockEngine.cs +++ b/GamecraftModdingAPI/Blocks/BlockEngine.cs @@ -171,6 +171,18 @@ namespace GamecraftModdingAPI.Blocks return list.ToArray(); } + public EGID? FindBlockEGID(uint id) + { + var groups = entitiesDB.FindGroups(); + foreach (ExclusiveGroupStruct group in groups) + { + if (entitiesDB.Exists(id, group)) + return new EGID(id, group); + } + + return null; + } + /// /// Synchronize newly created entity components with entities DB. /// This forces a partial game tick, so it may be slow. From 421faf7167cf2d4942e295a797bb52f92c91ae1f Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Sun, 19 Jul 2020 12:43:06 -0400 Subject: [PATCH 13/34] Improve dev info in README --- README.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1955de0..fd3bf5a 100644 --- a/README.md +++ b/README.md @@ -10,10 +10,16 @@ This means your code won't break when the GamecraftModdingAPI or Gamecraft updat For more info, please check out the [official documentation](https://mod.exmods.org). -For more support, join the ExMods [Discord](https://discord.gg/xjnFxQV). +For more support, join the ExMods [Discord](https://discord.exmods.org). ## Installation -[Please follow the official mod installation guide](https://www.exmods.org/guides/install.html) +[Please follow the official mod installation guide](https://www.exmods.org/guides/install.html) or use GCMM. + +## Development +To get started, create a symbolic link called `ref` in the root of the project, or one folder higher, linking to the Gamecraft install folder. +This will allow your IDE to resolve references to Gamecraft files for building and IDE tools. + +GamecraftModdingAPI version numbers follow the [Semantic Versioning guidelines](https://semver.org/). ## External Libraries GamecraftModdingAPI includes [Harmony](https://github.com/pardeike/Harmony) to modify the behaviour of existing Gamecraft code. @@ -21,4 +27,5 @@ GamecraftModdingAPI includes [Harmony](https://github.com/pardeike/Harmony) to m # Disclaimer This API is an unofficial modification of Gamecraft software, and is not endorsed or supported by FreeJam or Gamecraft. The GamecraftModdingAPI developer(s) claim no rights on the Gamecraft code referenced within this project. +All code contained in this project is licensed under the [GNU Public License v3](https://git.exmods.org/modtainers/GamecraftModdingAPI/src/branch/master/LICENSE). From 926d968eed33e5ec8c18e423299ca0ca7c23e4c2 Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Sun, 19 Jul 2020 16:39:35 -0400 Subject: [PATCH 14/34] Add sfx block support --- GamecraftModdingAPI/Blocks/BlockTests.cs | 18 +++ GamecraftModdingAPI/Blocks/MusicBlock.cs | 157 +++++++++++++++++++++++ GamecraftModdingAPI/Tests/TestRoot.cs | 7 +- 3 files changed, 178 insertions(+), 4 deletions(-) create mode 100644 GamecraftModdingAPI/Blocks/MusicBlock.cs diff --git a/GamecraftModdingAPI/Blocks/BlockTests.cs b/GamecraftModdingAPI/Blocks/BlockTests.cs index 418fa43..ed42024 100644 --- a/GamecraftModdingAPI/Blocks/BlockTests.cs +++ b/GamecraftModdingAPI/Blocks/BlockTests.cs @@ -1,5 +1,7 @@ using System; +using Gamecraft.Wires; + using GamecraftModdingAPI; using GamecraftModdingAPI.Tests; @@ -72,6 +74,22 @@ namespace GamecraftModdingAPI.Blocks if (!Assert.CloseTo(b.MinimumAngle, -180f, $"Servo.MinimumAngle {b.MinimumAngle} does not equal default value, possibly because it failed silently.", "Servo.MinimumAngle is close enough to default.")) return; if (!Assert.CloseTo(b.MaximumForce, 750f, $"Servo.MaximumForce {b.MaximumForce} does not equal default value, possibly because it failed silently.", "Servo.MaximumForce is close enough to default.")) return; } + + [APITestCase(TestType.EditMode)] + public static void TestMusicBlock() + { + Block newBlock = Block.PlaceNew(BlockIDs.MusicBlock, Unity.Mathematics.float3.zero + 2); + MusicBlock b = null; // Note: the assignment operation is a lambda, which slightly confuses the compiler + Assert.Errorless(() => { b = newBlock.Specialise(); }, "Block.Specialize() raised an exception: ", "Block.Specialize() completed without issue."); + if (!Assert.NotNull(b, "Block.Specialize() returned null, possibly because it failed silently.", "Specialized MusicBlock is not null.")) return; + if (!Assert.CloseTo(b.Volume, 100f, $"MusicBlock.Volume {b.Volume} does not equal default value, possibly because it failed silently.", "MusicBlock.Volume is close enough to default.")) return; + if (!Assert.Equal(b.TrackIndex, 0, $"MusicBlock.TrackIndex {b.TrackIndex} does not equal default value, possibly because it failed silently.", "MusicBlock.TrackIndex is equal to default.")) return; + b.IsPlaying = true; // play sfx + if (!Assert.Equal(b.IsPlaying, true, $"MusicBlock.IsPlaying {b.IsPlaying} does not equal default value, possibly because it failed silently.", "MusicBlock.IsPlaying is set properly.")) return; + if (!Assert.Equal(b.ChannelType, ChannelType.Character, $"MusicBlock.ChannelType {b.ChannelType} does not equal default value, possibly because it failed silently.", "MusicBlock.ChannelType is equal to default.")) return; + //Assert.Log(b.Track.ToString()); + if (!Assert.Equal(b.Track.ToString(), new Guid("3237ff8f-f5f2-4f84-8144-496ca280f8c0").ToString(), $"MusicBlock.Track {b.Track} does not equal default value, possibly because it failed silently.", "MusicBlock.Track is equal to default.")) return; + } } #endif } diff --git a/GamecraftModdingAPI/Blocks/MusicBlock.cs b/GamecraftModdingAPI/Blocks/MusicBlock.cs new file mode 100644 index 0000000..a7f862e --- /dev/null +++ b/GamecraftModdingAPI/Blocks/MusicBlock.cs @@ -0,0 +1,157 @@ +using System; + +using FMOD.Studio; +using FMODUnity; +using Gamecraft.Wires; +using RobocraftX.Blocks; +using Svelto.ECS; +using Unity.Mathematics; + +using GamecraftModdingAPI; +using GamecraftModdingAPI.Utility; + +namespace GamecraftModdingAPI.Blocks +{ + public class MusicBlock : Block + { + public static MusicBlock PlaceNew(float3 position, + float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0, + int uscale = 1, float3 scale = default, Player player = null) + { + if (PlacementEngine.IsInGame && GameState.IsBuildMode()) + { + EGID id = PlacementEngine.PlaceBlock(BlockIDs.MusicBlock, color, darkness, + position, uscale, scale, player, rotation); + return new MusicBlock(id); + } + + return null; + } + + public MusicBlock(EGID id) : base(id) + { + if (!BlockEngine.GetBlockInfoExists(this.Id)) + { + throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); + } + } + + public MusicBlock(uint id) : base(id) + { + if (!BlockEngine.GetBlockInfoExists(this.Id)) + { + throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); + } + } + + public byte TrackIndex + { + get + { + return BlockEngine.GetBlockInfo(Id).trackIndx; + } + + set + { + ref MusicBlockDataEntityStruct msdes = ref BlockEngine.GetBlockInfo(Id); + msdes.trackIndx = value; + } + } + + public Guid Track + { + get + { + ref MusicBlockDataEntityStruct msdes = ref BlockEngine.GetBlockInfo(Id); + return msdes.fmod2DEventPaths.Get(msdes.trackIndx); + } + + set + { + ref MusicBlockDataEntityStruct msdes = ref BlockEngine.GetBlockInfo(Id); + for (byte i = 0; i < msdes.fmod2DEventPaths.Count(); i++) + { + Guid track = msdes.fmod2DEventPaths.Get(i); + if (track == value) + { + msdes.trackIndx = i; + break; + } + } + } + } + + public Guid[] Tracks + { + get + { + ref MusicBlockDataEntityStruct msdes = ref BlockEngine.GetBlockInfo(Id); + Guid[] tracks = new Guid[msdes.fmod2DEventPaths.Count()]; + for (byte i = 0; i < tracks.Length; i++) + { + tracks[i] = msdes.fmod2DEventPaths.Get(i); + } + return tracks; + } + } + + public float Volume + { + get + { + return BlockEngine.GetBlockInfo(Id).tweakableVolume; + } + + set + { + ref MusicBlockDataEntityStruct msdes = ref BlockEngine.GetBlockInfo(Id); + msdes.tweakableVolume = value; + } + } + + public ChannelType ChannelType + { + get + { + return (ChannelType)BlockEngine.GetBlockInfo(Id).channelType; + } + + set + { + ref MusicBlockDataEntityStruct msdes = ref BlockEngine.GetBlockInfo(Id); + msdes.channelType = (byte)value; + } + } + + public bool IsPlaying + { + get + { + return BlockEngine.GetBlockInfo(Id).isPlaying; + } + + set + { + ref MusicBlockDataEntityStruct msdes = ref BlockEngine.GetBlockInfo(Id); + if (msdes.isPlaying == value) return; + if (value) + { + // start playing + EventInstance inst = RuntimeManager.CreateInstance(msdes.fmod2DEventPaths.Get(msdes.trackIndx)); + inst.setVolume(msdes.tweakableVolume / 100f); + inst.start(); + msdes.eventHandle = inst.handle; + } + else + { + // stop playing + EventInstance inst = default(EventInstance); + inst.handle = msdes.eventHandle; + inst.stop(FMOD.Studio.STOP_MODE.ALLOWFADEOUT); + inst.release(); + } + msdes.isPlaying = value; + } + } + } +} \ No newline at end of file diff --git a/GamecraftModdingAPI/Tests/TestRoot.cs b/GamecraftModdingAPI/Tests/TestRoot.cs index 4e9da73..f39169e 100644 --- a/GamecraftModdingAPI/Tests/TestRoot.cs +++ b/GamecraftModdingAPI/Tests/TestRoot.cs @@ -139,10 +139,9 @@ namespace GamecraftModdingAPI.Tests } yield return Yield.It; app.MyGames[0].EnterGame(); - // returning from a new game without saving will hard lock GC (it's an invalid state) - //Game newGame = Game.NewGame(); - //yield return new WaitForSecondsEnumerator(5).Continue(); // wait for sync - //newGame.EnterGame(); + /*Game newGame = Game.NewGame(); + yield return new WaitForSecondsEnumerator(5).Continue(); // wait for sync + newGame.EnterGame();*/ } private static IEnumerator GameTests() From ea8a9184bc96bab234cd49540672419a4a03bbea Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Sun, 19 Jul 2020 20:05:01 -0400 Subject: [PATCH 15/34] Add popup UI method to Client --- GamecraftModdingAPI/App/Client.cs | 77 ++++++++++++++++++++++ GamecraftModdingAPI/App/ClientAlertTest.cs | 59 +++++++++++++++++ GamecraftModdingAPI/App/UserPrompts.cs | 27 ++++++++ 3 files changed, 163 insertions(+) create mode 100644 GamecraftModdingAPI/App/ClientAlertTest.cs create mode 100644 GamecraftModdingAPI/App/UserPrompts.cs diff --git a/GamecraftModdingAPI/App/Client.cs b/GamecraftModdingAPI/App/Client.cs index fbe960e..ca5dcfa 100644 --- a/GamecraftModdingAPI/App/Client.cs +++ b/GamecraftModdingAPI/App/Client.cs @@ -1,8 +1,12 @@ using System; +using System.Reflection; +using HarmonyLib; +using RobocraftX.Services; using UnityEngine; using GamecraftModdingAPI.Utility; +using RobocraftX.Common; namespace GamecraftModdingAPI.App { @@ -14,6 +18,12 @@ namespace GamecraftModdingAPI.App // extensible engine protected static AppEngine appEngine = new AppEngine(); + protected static Func ErrorHandlerInstanceGetter; + + protected static Action EnqueueError; + + protected static Action HandleErrorClosed; + /// /// An event that fires whenever the main menu is loaded. /// @@ -74,9 +84,76 @@ namespace GamecraftModdingAPI.App get => appEngine.IsInMenu; } + /// + /// Open a popup which prompts the user to click a button. + /// This reuses Gamecraft's error dialog popup + /// + /// The popup to display. Use an instance of SingleChoicePrompt or DualChoicePrompt. + public void PromptUser(Error popup) + { + // if the stuff wasn't mostly set to internal, this would be written as: + // RobocraftX.Services.ErrorHandler.Instance.EqueueError(error); + object errorHandlerInstance = ErrorHandlerInstanceGetter(); + EnqueueError(errorHandlerInstance, popup); + } + + // TODO + /*public void CloseCurrentPrompt() + { + // RobocraftX.Services.ErrorHandler.Instance.HandlePopupClosed(); + // FIXME: this is a call that is also called when closing, not the actual closing action itself (so it doesn't work) + object errorHandlerInstance = ErrorHandlerInstanceGetter(); + HandleErrorClosed(errorHandlerInstance); + }*/ + internal static void Init() { + // this would have been so much simpler if this didn't involve a bunch of internal fields & classes + Type errorHandler = AccessTools.TypeByName("RobocraftX.Services.ErrorHandler"); + Type errorHandle = AccessTools.TypeByName("RobocraftX.Services.ErrorHandle"); + ErrorHandlerInstanceGetter = (Func) AccessTools.Method("GamecraftModdingAPI.App.Client:GenInstanceGetter") + .MakeGenericMethod(errorHandler) + .Invoke(null, new object[0]); + EnqueueError = (Action) AccessTools.Method("GamecraftModdingAPI.App.Client:GenEnqueueError") + .MakeGenericMethod(errorHandler, errorHandle) + .Invoke(null, new object[0]); + /*HandleErrorClosed = (Action) AccessTools.Method("GamecraftModdingAPI.App.Client:GenHandlePopupClosed") + .MakeGenericMethod(errorHandler) + .Invoke(null, new object[0]);*/ + // register engines MenuEngineManager.AddMenuEngine(appEngine); } + + // Creating delegates once is faster than reflection every time + // Admittedly, this way is more difficult to code and less readable + private static Func GenInstanceGetter() + { + Type errorHandler = AccessTools.TypeByName("RobocraftX.Services.ErrorHandler"); + MethodInfo instance = AccessTools.PropertyGetter(errorHandler, "Instance"); + Func getterSimple = (Func) Delegate.CreateDelegate(typeof(Func), null, instance); + Func getterCasted = () => (object) getterSimple(); + return getterCasted; + } + + private static Action GenEnqueueError() + { + Type errorHandler = AccessTools.TypeByName("RobocraftX.Services.ErrorHandler"); + MethodInfo enqueueError = AccessTools.Method(errorHandler, "EnqueueError"); + Func enqueueSimple = + (Func) Delegate.CreateDelegate(typeof(Func), enqueueError); + Action enqueueCasted = + (object instance, Error error) => { enqueueSimple((T) instance, error); }; + return enqueueCasted; + } + + private static Action GenHandlePopupClosed() + { + Type errorHandler = AccessTools.TypeByName("RobocraftX.Services.ErrorHandler"); + MethodInfo handlePopupClosed = AccessTools.Method(errorHandler, "HandlePopupClosed"); + Action handleSimple = + (Action) Delegate.CreateDelegate(typeof(Action), handlePopupClosed); + Action handleCasted = (object instance) => handleSimple((T) instance); + return handleCasted; + } } } diff --git a/GamecraftModdingAPI/App/ClientAlertTest.cs b/GamecraftModdingAPI/App/ClientAlertTest.cs new file mode 100644 index 0000000..23ced76 --- /dev/null +++ b/GamecraftModdingAPI/App/ClientAlertTest.cs @@ -0,0 +1,59 @@ +using System; +using HarmonyLib; + +using RobocraftX.Services; + +using GamecraftModdingAPI.Tests; + +namespace GamecraftModdingAPI.App +{ +#if TEST + /// + /// Client popups tests. + /// Only available in TEST builds. + /// + [APITestClass] + public static class ClientAlertTest + { + private static DualChoicePrompt popup2 = null; + + private static SingleChoicePrompt popup1 = null; + + [APITestStartUp] + public static void StartUp2() + { + popup2 = new DualChoicePrompt("This is a test double-button popup", + "The cake is a lie", + "lmao", + () => { }, + "kek", + () => { }); + } + + [APITestStartUp] + public static void StartUp1() + { + popup1 = new SingleChoicePrompt("The cake is a lie", + "This is a test single-button popup", + "qwertyuiop", + () => { }); + } + + [APITestCase(TestType.Menu)] + public static void TestPopUp2() + { + Client c = new Client(); + c.PromptUser(popup2); + //c.CloseCurrentPrompt(); + } + + [APITestCase(TestType.Menu)] + public static void TestPopUp1() + { + Client c = new Client(); + c.PromptUser(popup1); + //c.CloseCurrentPrompt(); + } + } +#endif +} \ No newline at end of file diff --git a/GamecraftModdingAPI/App/UserPrompts.cs b/GamecraftModdingAPI/App/UserPrompts.cs new file mode 100644 index 0000000..26a9395 --- /dev/null +++ b/GamecraftModdingAPI/App/UserPrompts.cs @@ -0,0 +1,27 @@ +using System; +using HarmonyLib; + +using RobocraftX.Services; + +namespace GamecraftModdingAPI.App +{ + public class DualChoicePrompt : MultiChoiceError + { + public DualChoicePrompt(string errorMessage, string title, string firstButtonText, Action firstButtonAction, string secondButtonText, Action secondButtonAction) : base(errorMessage, firstButtonText, firstButtonAction, secondButtonText, secondButtonAction) + { + // internal readonly field smh + new Traverse(this).Field("Title").Value = title; + } + } + + public class SingleChoicePrompt : SingleChoiceError + { + public SingleChoicePrompt(string errorMessage, string buttonText, Action buttonClickAction) : base(errorMessage, buttonText, buttonClickAction) + { + } + + public SingleChoicePrompt(string titleText, string errorMessage, string buttonText, Action buttonClickAction) : base(titleText, errorMessage, buttonText, buttonClickAction) + { + } + } +} \ No newline at end of file From 89d32956d950e1eb08ac9c3844ec96c748108eaf Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Mon, 13 Jul 2020 21:55:48 +0200 Subject: [PATCH 16/34] Automatically invoke the correct block constructor And store delegates of dynamic methods invoking constructors Tested with the automated tests --- GamecraftModdingAPI/Block.cs | 107 +++++++++++++----- GamecraftModdingAPI/Blocks/BlockTests.cs | 3 +- GamecraftModdingAPI/Blocks/ConsoleBlock.cs | 30 ++--- GamecraftModdingAPI/Blocks/Motor.cs | 23 ---- GamecraftModdingAPI/Blocks/Piston.cs | 25 +--- GamecraftModdingAPI/Blocks/Servo.cs | 23 ---- GamecraftModdingAPI/Blocks/SignalingBlock.cs | 19 ---- GamecraftModdingAPI/Blocks/SpawnPoint.cs | 25 +--- GamecraftModdingAPI/Blocks/TextBlock.cs | 15 --- GamecraftModdingAPI/Blocks/Timer.cs | 17 --- .../Tests/GamecraftModdingAPIPluginTest.cs | 22 ++++ 11 files changed, 114 insertions(+), 195 deletions(-) diff --git a/GamecraftModdingAPI/Block.cs b/GamecraftModdingAPI/Block.cs index 16a0c81..673ef49 100644 --- a/GamecraftModdingAPI/Block.cs +++ b/GamecraftModdingAPI/Block.cs @@ -1,6 +1,7 @@ using System; -using System.Reflection; -using System.Threading.Tasks; +using System.Collections.Generic; +using System.Linq; +using System.Reflection.Emit; using Svelto.ECS; using Svelto.ECS.EntityStructs; @@ -67,10 +68,6 @@ namespace GamecraftModdingAPI /// Place a new block at the given position. If scaled, position means the center of the block. The default block size is 0.2 in terms of position. /// Place blocks next to each other to connect them. /// The placed block will be a complete block with a placement grid and collision which will be saved along with the game. - /// - /// This method waits for the block to be constructed in the game which may take a significant amount of time. - /// Only use this to place a single block. - /// For placing multiple blocks, use PlaceNew() then AsyncUtils.WaitForSubmission() when done with placing blocks. /// /// The block's type /// The block's color @@ -81,23 +78,15 @@ namespace GamecraftModdingAPI /// The block's non-uniform scale - 0 means is used /// The player who placed the block /// The placed block or null if failed - public static async Task PlaceNewAsync(BlockIDs block, float3 position, + public static T PlaceNew(BlockIDs block, float3 position, float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0, - int uscale = 1, float3 scale = default, Player player = null) + int uscale = 1, float3 scale = default, Player player = null) where T : Block { if (PlacementEngine.IsInGame && GameState.IsBuildMode()) { - try - { - var ret = new Block(PlacementEngine.PlaceBlock(block, color, darkness, - position, uscale, scale, player, rotation)); - await AsyncUtils.WaitForSubmission(); - return ret; - } - catch (Exception e) - { - Logging.MetaDebugLog(e); - } + var egid = PlacementEngine.PlaceBlock(block, color, darkness, + position, uscale, scale, player, rotation); + return New(egid.entityID, egid.groupID); } return null; @@ -109,7 +98,7 @@ namespace GamecraftModdingAPI /// The block object public static Block GetLastPlacedBlock() { - return new Block(BlockIdentifiers.LatestBlockID); + return New(BlockIdentifiers.LatestBlockID); } /// @@ -130,6 +119,75 @@ namespace GamecraftModdingAPI remove => BlockEventsEngine.Removed -= value; } + private static Dictionary> initializers = new Dictionary>(); + + private static Dictionary typeToGroup = + new Dictionary + { + {typeof(ConsoleBlock), new[] {CommonExclusiveGroups.BUILD_CONSOLE_BLOCK_GROUP}}, + {typeof(Motor), new[] {CommonExclusiveGroups.BUILD_MOTOR_BLOCK_GROUP}}, + {typeof(Piston), new[] {CommonExclusiveGroups.BUILD_PISTON_BLOCK_GROUP}}, + {typeof(Servo), new[] {CommonExclusiveGroups.BUILD_SERVO_BLOCK_GROUP}}, + { + typeof(SpawnPoint), + new[] + { + CommonExclusiveGroups.BUILD_SPAWNPOINT_BLOCK_GROUP, + CommonExclusiveGroups.BUILD_BUILDINGSPAWN_BLOCK_GROUP + } + }, + {typeof(TextBlock), new[] {CommonExclusiveGroups.BUILD_TEXT_BLOCK_GROUP}}, + {typeof(Timer), new[] {CommonExclusiveGroups.BUILD_TIMER_BLOCK_GROUP}} + }; + + private static T New(uint id, ExclusiveGroupStruct? group = null) where T : Block + { + var type = typeof(T); + EGID egid; + if (!group.HasValue) + { + if (typeToGroup.TryGetValue(type, out var gr) && gr.Length == 1) + egid = new EGID(id, gr[0]); + else + egid = BlockEngine.FindBlockEGID(id) ?? throw new BlockTypeException("Could not find block group!"); + } + else + { + egid = new EGID(id, group.Value); + if (typeToGroup.TryGetValue(type, out var gr) + && gr.All(egs => egs != group.Value)) //If this subclass has a specific group, then use that - so Block should still work + throw new BlockTypeException($"Incompatible block type! Type {type.Name} belongs to group {gr.Select(g => g.ToString()).Aggregate((a, b) => a + ", " + b)} instead of {group.Value}"); + } + + if (initializers.TryGetValue(type, out var func)) + { + var bl = (T) func(egid); + return bl; + } + + //https://stackoverflow.com/a/10593806/2703239 + var ctor = type.GetConstructor(new[] {typeof(EGID)}); + if (ctor == null) + throw new MissingMethodException("There is no constructor with an EGID parameter for this object"); + DynamicMethod dynamic = new DynamicMethod(string.Empty, + type, + new[] {typeof(EGID)}, + type); + ILGenerator il = dynamic.GetILGenerator(); + + il.DeclareLocal(type); + il.Emit(OpCodes.Ldarg_0); //Load EGID and pass to constructor + il.Emit(OpCodes.Newobj, ctor); //Call constructor + il.Emit(OpCodes.Stloc_0); + il.Emit(OpCodes.Ldloc_0); + il.Emit(OpCodes.Ret); + + func = (Func) dynamic.CreateDelegate(typeof(Func)); + initializers.Add(type, func); + var block = (T) func(egid); + return block; + } + public Block(EGID id) { Id = id; @@ -344,12 +402,9 @@ namespace GamecraftModdingAPI // C# can't cast to a child of Block unless the object was originally that child type // And C# doesn't let me make implicit cast operators for child types // So thanks to Microsoft, we've got this horrible implementation using reflection - ConstructorInfo ctor = typeof(T).GetConstructor(types: new System.Type[] { typeof(EGID) }); - if (ctor == null) - { - throw new BlockSpecializationException("Specialized block constructor does not accept an EGID"); - } - return (T)ctor.Invoke(new object[] { Id }); + + //Lets improve that using delegates + return New(Id.entityID, Id.groupID); } #if DEBUG diff --git a/GamecraftModdingAPI/Blocks/BlockTests.cs b/GamecraftModdingAPI/Blocks/BlockTests.cs index ed42024..3b66f28 100644 --- a/GamecraftModdingAPI/Blocks/BlockTests.cs +++ b/GamecraftModdingAPI/Blocks/BlockTests.cs @@ -32,9 +32,8 @@ namespace GamecraftModdingAPI.Blocks [APITestCase(TestType.EditMode)] public static void TestTextBlock() { - Block newBlock = Block.PlaceNew(BlockIDs.TextBlock, Unity.Mathematics.float3.zero + 1); TextBlock textBlock = null; // Note: the assignment operation is a lambda, which slightly confuses the compiler - Assert.Errorless(() => { textBlock = newBlock.Specialise(); }, "Block.Specialize() raised an exception: ", "Block.Specialize() completed without issue."); + Assert.Errorless(() => { textBlock = Block.PlaceNew(BlockIDs.TextBlock, Unity.Mathematics.float3.zero + 1); }, "Block.PlaceNew() raised an exception: ", "Block.PlaceNew() completed without issue."); if (!Assert.NotNull(textBlock, "Block.Specialize() returned null, possibly because it failed silently.", "Specialized TextBlock is not null.")) return; if (!Assert.NotNull(textBlock.Text, "TextBlock.Text is null, possibly because it failed silently.", "TextBlock.Text is not null.")) return; if (!Assert.NotNull(textBlock.TextBlockId, "TextBlock.TextBlockId is null, possibly because it failed silently.", "TextBlock.TextBlockId is not null.")) return; diff --git a/GamecraftModdingAPI/Blocks/ConsoleBlock.cs b/GamecraftModdingAPI/Blocks/ConsoleBlock.cs index 6d4217d..e132029 100644 --- a/GamecraftModdingAPI/Blocks/ConsoleBlock.cs +++ b/GamecraftModdingAPI/Blocks/ConsoleBlock.cs @@ -12,33 +12,19 @@ namespace GamecraftModdingAPI.Blocks { public class ConsoleBlock : Block { - public static ConsoleBlock PlaceNew(float3 position, - float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0, - int uscale = 1, float3 scale = default, Player player = null) + public ConsoleBlock(EGID id): base(id) { - if (PlacementEngine.IsInGame && GameState.IsBuildMode()) - { - EGID id = PlacementEngine.PlaceBlock(BlockIDs.ConsoleBlock, color, darkness, - position, uscale, scale, player, rotation); - return new ConsoleBlock(id); - } - - return null; + if (!BlockEngine.GetBlockInfoExists(this.Id)) + { + throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); + } } - public ConsoleBlock(EGID id): base(id) + public ConsoleBlock(uint id): base(new EGID(id, CommonExclusiveGroups.BUILD_CONSOLE_BLOCK_GROUP)) { - if (!BlockEngine.GetBlockInfoExists(this.Id)) - { - throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); - } - } - - public ConsoleBlock(uint id): base(new EGID(id, CommonExclusiveGroups.BUILD_CONSOLE_BLOCK_GROUP)) - { - if (!BlockEngine.GetBlockInfoExists(this.Id)) + if (!BlockEngine.GetBlockInfoExists(this.Id)) { - throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); + throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); } } diff --git a/GamecraftModdingAPI/Blocks/Motor.cs b/GamecraftModdingAPI/Blocks/Motor.cs index 55f3649..fde2920 100644 --- a/GamecraftModdingAPI/Blocks/Motor.cs +++ b/GamecraftModdingAPI/Blocks/Motor.cs @@ -11,29 +11,6 @@ namespace GamecraftModdingAPI.Blocks { public class Motor : Block { - /// - /// Places a new motor. - /// Any valid motor type is accepted. - /// This re-implements Block.PlaceNew(...) - /// - public static new Motor PlaceNew(BlockIDs block, float3 position, - float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0, - int uscale = 1, float3 scale = default, Player player = null) - { - if (!(block == BlockIDs.MotorS || block == BlockIDs.MotorM)) - { - throw new BlockTypeException($"Block is not a {typeof(Motor).Name} block"); - } - if (PlacementEngine.IsInGame && GameState.IsBuildMode()) - { - EGID id = PlacementEngine.PlaceBlock(block, color, darkness, - position, uscale, scale, player, rotation); - return new Motor(id); - } - - return null; - } - public Motor(EGID id) : base(id) { if (!BlockEngine.GetBlockInfoExists(this.Id)) diff --git a/GamecraftModdingAPI/Blocks/Piston.cs b/GamecraftModdingAPI/Blocks/Piston.cs index b96a806..2586b60 100644 --- a/GamecraftModdingAPI/Blocks/Piston.cs +++ b/GamecraftModdingAPI/Blocks/Piston.cs @@ -11,30 +11,7 @@ namespace GamecraftModdingAPI.Blocks { public class Piston : Block { - /// - /// Places a new piston. - /// Any valid piston type is accepted. - /// This re-implements Block.PlaceNew(...) - /// - public static new Piston PlaceNew(BlockIDs block, float3 position, - float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0, - int uscale = 1, float3 scale = default, Player player = null) - { - if (!(block == BlockIDs.ServoPiston || block == BlockIDs.StepperPiston || block == BlockIDs.PneumaticPiston)) - { - throw new BlockTypeException($"Block is not a {typeof(Piston).Name} block"); - } - if (PlacementEngine.IsInGame && GameState.IsBuildMode()) - { - EGID id = PlacementEngine.PlaceBlock(block, color, darkness, - position, uscale, scale, player, rotation); - return new Piston(id); - } - - return null; - } - - public Piston(EGID id) : base(id) + public Piston(EGID id) : base(id) { if (!BlockEngine.GetBlockInfoExists(this.Id)) { diff --git a/GamecraftModdingAPI/Blocks/Servo.cs b/GamecraftModdingAPI/Blocks/Servo.cs index ef7225b..c4b57fb 100644 --- a/GamecraftModdingAPI/Blocks/Servo.cs +++ b/GamecraftModdingAPI/Blocks/Servo.cs @@ -11,29 +11,6 @@ namespace GamecraftModdingAPI.Blocks { public class Servo : Block { - /// - /// Places a new servo. - /// Any valid servo type is accepted. - /// This re-implements Block.PlaceNew(...) - /// - public static new Servo PlaceNew(BlockIDs block, float3 position, - float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0, - int uscale = 1, float3 scale = default, Player player = null) - { - if (!(block == BlockIDs.ServoAxle || block == BlockIDs.ServoHinge || block == BlockIDs.ServoPiston)) - { - throw new BlockTypeException($"Block is not a {nameof(Servo)} block"); - } - if (PlacementEngine.IsInGame && GameState.IsBuildMode()) - { - EGID id = PlacementEngine.PlaceBlock(block, color, darkness, - position, uscale, scale, player, rotation); - return new Servo(id); - } - - return null; - } - public Servo(EGID id) : base(id) { if (!BlockEngine.GetBlockInfoExists(this.Id)) diff --git a/GamecraftModdingAPI/Blocks/SignalingBlock.cs b/GamecraftModdingAPI/Blocks/SignalingBlock.cs index f8006f6..8a62d64 100644 --- a/GamecraftModdingAPI/Blocks/SignalingBlock.cs +++ b/GamecraftModdingAPI/Blocks/SignalingBlock.cs @@ -14,25 +14,6 @@ namespace GamecraftModdingAPI.Blocks /// public class SignalingBlock : Block { - /// - /// Places a new signaling block. - /// Any valid functional block type with IO ports will work. - /// This re-implements Block.PlaceNew(...) - /// - public static new SignalingBlock PlaceNew(BlockIDs block, float3 position, - float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0, - int uscale = 1, float3 scale = default, Player player = null) - { - if (PlacementEngine.IsInGame && GameState.IsBuildMode()) - { - EGID id = PlacementEngine.PlaceBlock(block, color, darkness, - position, uscale, scale, player, rotation); - return new SignalingBlock(id); - } - - return null; - } - public SignalingBlock(EGID id) : base(id) { if (!BlockEngine.GetBlockInfoExists(this.Id)) diff --git a/GamecraftModdingAPI/Blocks/SpawnPoint.cs b/GamecraftModdingAPI/Blocks/SpawnPoint.cs index 65ef750..4419e38 100644 --- a/GamecraftModdingAPI/Blocks/SpawnPoint.cs +++ b/GamecraftModdingAPI/Blocks/SpawnPoint.cs @@ -13,30 +13,7 @@ namespace GamecraftModdingAPI.Blocks { public class SpawnPoint : Block { - /// - /// Places a new spawn point. - /// Any valid spawn block type is accepted. - /// This re-implements Block.PlaceNew(...) - /// - public static new SpawnPoint PlaceNew(BlockIDs block, float3 position, - float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0, - int uscale = 1, float3 scale = default, Player player = null) - { - if (!(block == BlockIDs.LargeSpawn || block == BlockIDs.SmallSpawn || block == BlockIDs.MediumSpawn || block == BlockIDs.PlayerSpawn)) - { - throw new BlockTypeException($"Block is not a {nameof(SpawnPoint)} block"); - } - if (PlacementEngine.IsInGame && GameState.IsBuildMode()) - { - EGID id = PlacementEngine.PlaceBlock(block, color, darkness, - position, uscale, scale, player, rotation); - return new SpawnPoint(id); - } - - return null; - } - - public SpawnPoint(EGID id) : base(id) + public SpawnPoint(EGID id) : base(id) { if (!BlockEngine.GetBlockInfoExists(this.Id)) { diff --git a/GamecraftModdingAPI/Blocks/TextBlock.cs b/GamecraftModdingAPI/Blocks/TextBlock.cs index c1a9344..94cf212 100644 --- a/GamecraftModdingAPI/Blocks/TextBlock.cs +++ b/GamecraftModdingAPI/Blocks/TextBlock.cs @@ -12,21 +12,6 @@ namespace GamecraftModdingAPI.Blocks { public class TextBlock : Block { - - public static TextBlock PlaceNew(float3 position, - float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0, - int uscale = 1, float3 scale = default, Player player = null) - { - if (PlacementEngine.IsInGame && GameState.IsBuildMode()) - { - EGID id = PlacementEngine.PlaceBlock(BlockIDs.TextBlock, color, darkness, - position, uscale, scale, player, rotation); - return new TextBlock(id); - } - - return null; - } - public TextBlock(EGID id) : base(id) { if (!BlockEngine.GetBlockInfoExists(this.Id)) diff --git a/GamecraftModdingAPI/Blocks/Timer.cs b/GamecraftModdingAPI/Blocks/Timer.cs index 0e7f744..2acab5b 100644 --- a/GamecraftModdingAPI/Blocks/Timer.cs +++ b/GamecraftModdingAPI/Blocks/Timer.cs @@ -13,23 +13,6 @@ namespace GamecraftModdingAPI.Blocks { public class Timer : Block { - /// - /// Places a new timer block. - /// - public static Timer PlaceNew(float3 position, - float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0, - int uscale = 1, float3 scale = default, Player player = null) - { - if (PlacementEngine.IsInGame && GameState.IsBuildMode()) - { - EGID id = PlacementEngine.PlaceBlock(BlockIDs.Timer, color, darkness, - position, uscale, scale, player, rotation); - return new Timer(id); - } - - return null; - } - public Timer(EGID id) : base(id) { if (!BlockEngine.GetBlockInfoExists(this.Id)) diff --git a/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs b/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs index fa65ebb..d5cf714 100644 --- a/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs +++ b/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs @@ -232,6 +232,28 @@ namespace GamecraftModdingAPI.Tests } }).Build(); + CommandBuilder.Builder() + .Name("PlaceConsole") + .Description("Place a bunch of console block with a given text") + .Action((float x, float y, float z) => + { + Stopwatch sw = new Stopwatch(); + sw.Start(); + for (int i = 0; i < 100; i++) + { + for (int j = 0; j < 100; j++) + { + var block = Block.PlaceNew(BlockIDs.ConsoleBlock, + new float3(x + i, y, z + j)); + block.Command = "test_command"; + } + } + + sw.Stop(); + Logging.CommandLog($"Blocks placed in {sw.ElapsedMilliseconds} ms"); + }) + .Build(); + GameClient.SetDebugInfo("InstalledMods", InstalledMods); Block.Placed += (sender, args) => Logging.MetaDebugLog("Placed block " + args.Type + " with ID " + args.ID); From 7336fe8353057a0cfe0b792528b90ed7cc955b0a Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 15 Jul 2020 21:58:24 +0200 Subject: [PATCH 17/34] Add support for initializing blocks with properties Newly created blocks use the initializer to set properties, allowing the user to set per-block properties --- GamecraftModdingAPI/Block.cs | 76 ++++++++-------- GamecraftModdingAPI/Blocks/BlockEngine.cs | 89 +++++++------------ GamecraftModdingAPI/Blocks/BlockEngineInit.cs | 46 ++++++++++ .../Blocks/BlockEventsEngine.cs | 52 ++++++++++- GamecraftModdingAPI/Blocks/BlockIDs.cs | 2 +- GamecraftModdingAPI/Blocks/ConsoleBlock.cs | 40 ++++----- GamecraftModdingAPI/Blocks/Motor.cs | 23 ++--- .../Blocks/ObjectIdentifier.cs | 19 ++-- GamecraftModdingAPI/Blocks/Piston.cs | 23 ++--- GamecraftModdingAPI/Blocks/PlacementEngine.cs | 9 +- GamecraftModdingAPI/Blocks/Servo.cs | 48 ++++------ GamecraftModdingAPI/Blocks/SignalingBlock.cs | 27 ++---- GamecraftModdingAPI/Blocks/SpawnPoint.cs | 64 +++++-------- GamecraftModdingAPI/Blocks/TextBlock.cs | 53 +++++------ GamecraftModdingAPI/Blocks/Timer.cs | 68 +++++--------- 15 files changed, 301 insertions(+), 338 deletions(-) create mode 100644 GamecraftModdingAPI/Blocks/BlockEngineInit.cs diff --git a/GamecraftModdingAPI/Block.cs b/GamecraftModdingAPI/Block.cs index 673ef49..c3e0393 100644 --- a/GamecraftModdingAPI/Block.cs +++ b/GamecraftModdingAPI/Block.cs @@ -55,13 +55,7 @@ namespace GamecraftModdingAPI float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0, int uscale = 1, float3 scale = default, Player player = null) { - if (PlacementEngine.IsInGame && GameState.IsBuildMode()) - { - return new Block(PlacementEngine.PlaceBlock(block, color, darkness, - position, uscale, scale, player, rotation)); - } - - return null; + return PlaceNew(block, position, rotation, color, darkness, uscale, scale, player); } /// @@ -85,8 +79,10 @@ namespace GamecraftModdingAPI if (PlacementEngine.IsInGame && GameState.IsBuildMode()) { var egid = PlacementEngine.PlaceBlock(block, color, darkness, - position, uscale, scale, player, rotation); - return New(egid.entityID, egid.groupID); + position, uscale, scale, player, rotation, out var initializer); + var bl = New(egid.entityID, egid.groupID); + bl.InitData.Group = BlockEngine.InitGroup(initializer); + return bl; } return null; @@ -205,6 +201,8 @@ namespace GamecraftModdingAPI public EGID Id { get; } + internal BlockEngine.BlockInitData InitData; + /// /// The block's current position or zero if the block no longer exists. /// A block is 0.2 wide by default in terms of position. @@ -236,12 +234,11 @@ namespace GamecraftModdingAPI /// public float3 Scale { - get => BlockEngine.GetBlockInfo(Id).scale; + get => BlockEngine.GetBlockInfo(this, (ScalingEntityStruct st) => st.scale); set { + BlockEngine.SetBlockInfo(this, (ref ScalingEntityStruct st, float3 val) => st.scale = val, value); if (!Exists) return; //UpdateCollision needs the block to exist - ref var scaling = ref BlockEngine.GetBlockInfo(Id); - scaling.scale = value; ScalingEngine.UpdateCollision(Id); } } @@ -252,11 +249,11 @@ namespace GamecraftModdingAPI /// public int UniformScale { - get => BlockEngine.GetBlockInfo(Id).scaleFactor; + get => BlockEngine.GetBlockInfo(this, (UniformBlockScaleEntityStruct st) => st.scaleFactor); set { - ref var scaleStruct = ref BlockEngine.GetBlockInfo(Id); - scaleStruct.scaleFactor = value; + BlockEngine.SetBlockInfo(this, (ref UniformBlockScaleEntityStruct st, int val) => st.scaleFactor = val, + value); Scale = new float3(value, value, value); } } @@ -268,8 +265,7 @@ namespace GamecraftModdingAPI { get { - var id = (BlockIDs) BlockEngine.GetBlockInfo(Id, out var exists).DBID; - return exists ? id : BlockIDs.Invalid; + return BlockEngine.GetBlockInfo(this, (DBEntityStruct st) => (BlockIDs) st.DBID, BlockIDs.Invalid); } } @@ -280,17 +276,19 @@ namespace GamecraftModdingAPI { get { - byte index = BlockEngine.GetBlockInfo(Id, out var exists).indexInPalette; - if (!exists) index = byte.MaxValue; + byte index = BlockEngine.GetBlockInfo(this, (ColourParameterEntityStruct st) => st.indexInPalette, + byte.MaxValue); return new BlockColor(index); } set { - ref var color = ref BlockEngine.GetBlockInfo(Id); - color.indexInPalette = (byte)(value.Color + value.Darkness * 10); - color.overridePaletteColour = false; - color.needsUpdate = true; - BlockEngine.SetBlockColorFromPalette(ref color); + BlockEngine.SetBlockInfo(this, (ref ColourParameterEntityStruct color, BlockColor val) => + { + color.indexInPalette = (byte) (val.Color + val.Darkness * 10); + color.overridePaletteColour = false; + color.needsUpdate = true; + BlockEngine.SetBlockColorFromPalette(ref color); + }, value); } } @@ -299,27 +297,31 @@ namespace GamecraftModdingAPI /// public float4 CustomColor { - get => BlockEngine.GetBlockInfo(Id).overriddenColour; + get => BlockEngine.GetBlockInfo(this, (ColourParameterEntityStruct st) => st.overriddenColour); set { - ref var color = ref BlockEngine.GetBlockInfo(Id); - color.overriddenColour = value; - color.overridePaletteColour = true; - color.needsUpdate = true; + BlockEngine.SetBlockInfo(this, (ref ColourParameterEntityStruct color, float4 val) => + { + color.overriddenColour = val; + color.overridePaletteColour = true; + color.needsUpdate = true; + }, value); } } /// - /// The short text displayed on the block if applicable, or null. + /// The text displayed on the block if applicable, or null. /// Setting it is temporary to the session, it won't be saved. /// public string Label { - get => BlockEngine.GetBlockInfo(Id).textLabelComponent?.text; + get => BlockEngine.GetBlockInfo(this, (TextLabelEntityViewStruct st) => st.textLabelComponent?.text); set { - ref var text = ref BlockEngine.GetBlockInfo(Id); - if (text.textLabelComponent != null) text.textLabelComponent.text = value; + BlockEngine.SetBlockInfo(this, (ref TextLabelEntityViewStruct text, string val) => + { + if (text.textLabelComponent != null) text.textLabelComponent.text = val; + }, value); } } @@ -346,8 +348,8 @@ namespace GamecraftModdingAPI /// The SimBody of the cluster or null if the block doesn't exist. public SimBody GetSimBody() { - uint id = BlockEngine.GetBlockInfo(Id, out var exists).machineRigidBodyId; - return exists ? new SimBody(id) : null; + return BlockEngine.GetBlockInfo(this, + (GridConnectionsEntityStruct st) => new SimBody(st.machineRigidBodyId)); } public override string ToString() @@ -404,7 +406,9 @@ namespace GamecraftModdingAPI // So thanks to Microsoft, we've got this horrible implementation using reflection //Lets improve that using delegates - return New(Id.entityID, Id.groupID); + var block = New(Id.entityID, Id.groupID); + block.InitData = this.InitData; + return block; } #if DEBUG diff --git a/GamecraftModdingAPI/Blocks/BlockEngine.cs b/GamecraftModdingAPI/Blocks/BlockEngine.cs index 81a1630..d6f4907 100644 --- a/GamecraftModdingAPI/Blocks/BlockEngine.cs +++ b/GamecraftModdingAPI/Blocks/BlockEngine.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using Gamecraft.Wires; @@ -10,14 +11,13 @@ using Svelto.DataStructures; using Svelto.ECS; using GamecraftModdingAPI.Engines; -using GamecraftModdingAPI.Utility; namespace GamecraftModdingAPI.Blocks { /// /// Engine for executing general block actions /// - public class BlockEngine : IApiEngine + public partial class BlockEngine : IApiEngine { public string Name { get; } = "GamecraftModdingAPIBlockGameEngine"; @@ -61,66 +61,54 @@ namespace GamecraftModdingAPI.Blocks color.paletteColour = paletteEntry.Colour; } - /// - /// Get a struct of a block. Can be used to set properties. - /// Returns a default value if not found. - /// - /// The block's ID - /// The struct to query - /// An editable reference to the struct public ref T GetBlockInfo(EGID blockID) where T : struct, IEntityComponent { - if (!Synced) - { - Sync(); - Synced = true; - } if (entitiesDB.Exists(blockID)) return ref entitiesDB.QueryEntity(blockID); T[] structHolder = new T[1]; //Create something that can be referenced return ref structHolder[0]; //Gets a default value automatically } - /// - /// Get a struct of a block. Can be used to set properties. - /// Returns a default value if not found. - /// - /// The block's ID - /// Whether the specified struct exists for the block - /// The struct to query - /// An editable reference to the struct - public ref T GetBlockInfo(EGID blockID, out bool exists) where T : struct, IEntityComponent + public U GetBlockInfo(Block block, Func getter, + U def = default) where T : struct, IEntityComponent { - if (!Synced) + if (entitiesDB.Exists(block.Id)) + return getter(entitiesDB.QueryEntity(block.Id)); + if (block.InitData.Group == null) return def; + var initializer = new EntityComponentInitializer(block.Id, block.InitData.Group); + if (initializer.Has()) + return getter(initializer.Get()); + return def; + } + + public delegate void Setter(ref T component, U value) where T : struct, IEntityComponent; + + public void SetBlockInfo(Block block, Setter setter, U value) where T : struct, IEntityComponent + { + if (entitiesDB.Exists(block.Id)) + setter(ref entitiesDB.QueryEntity(block.Id), value); + if (block.InitData.Group != null) { - Sync(); - Synced = true; + var initializer = new EntityComponentInitializer(block.Id, block.InitData.Group); + ref T structRef = ref (new T[1])[0]; //A reference for a default value for struct + setter(ref structRef, value); + initializer.Init(structRef); } - exists = entitiesDB.Exists(blockID); - if (exists) - return ref entitiesDB.QueryEntity(blockID); - T[] structHolder = new T[1]; - return ref structHolder[0]; } - public bool BlockExists(EGID id) + public bool BlockExists(EGID blockID) { - if (!Synced) - { - Sync(); - Synced = true; - } - return entitiesDB.Exists(id); + return entitiesDB.Exists(blockID); } - public bool GetBlockInfoExists(EGID blockID) where T : struct, IEntityComponent + public bool GetBlockInfoExists(Block block) where T : struct, IEntityComponent { - if (!Synced) - { - Sync(); - Synced = true; - } - return entitiesDB.Exists(blockID); + if (entitiesDB.Exists(block.Id)) + return true; + if (block.InitData.Group == null) + return false; + var init = new EntityComponentInitializer(block.Id, block.InitData.Group); + return init.Has(); } public SimBody[] GetSimBodiesFromID(byte id) @@ -183,17 +171,6 @@ namespace GamecraftModdingAPI.Blocks return null; } - /// - /// Synchronize newly created entity components with entities DB. - /// This forces a partial game tick, so it may be slow. - /// This also has the potential to make Gamecraft unstable. - /// Use this sparingly. - /// - private static void Sync() - { - DeterministicStepCompositionRootPatch.SubmitEntitiesNow(); - } - #if DEBUG public EntitiesDB GetEntitiesDB() { diff --git a/GamecraftModdingAPI/Blocks/BlockEngineInit.cs b/GamecraftModdingAPI/Blocks/BlockEngineInit.cs new file mode 100644 index 0000000..4be9a98 --- /dev/null +++ b/GamecraftModdingAPI/Blocks/BlockEngineInit.cs @@ -0,0 +1,46 @@ +using System; +using System.Linq.Expressions; + +using Svelto.DataStructures; +using Svelto.ECS; +using Svelto.ECS.Internal; + +namespace GamecraftModdingAPI.Blocks +{ + public partial class BlockEngine + { + internal struct BlockInitData + { + public FasterDictionary, ITypeSafeDictionary> Group; + } + + internal delegate FasterDictionary, ITypeSafeDictionary> GetInitGroup( + EntityComponentInitializer initializer); + + internal GetInitGroup InitGroup = CreateAccessor("_group"); + + //https://stackoverflow.com/questions/55878525/unit-testing-ref-structs-with-private-fields-via-reflection + internal static TDelegate CreateAccessor(string memberName) where TDelegate : Delegate + { + var invokeMethod = typeof(TDelegate).GetMethod("Invoke"); + if (invokeMethod == null) + throw new InvalidOperationException($"{typeof(TDelegate)} signature could not be determined."); + + var delegateParameters = invokeMethod.GetParameters(); + if (delegateParameters.Length != 1) + throw new InvalidOperationException("Delegate must have a single parameter."); + + var paramType = delegateParameters[0].ParameterType; + + var objParam = Expression.Parameter(paramType, "obj"); + var memberExpr = Expression.PropertyOrField(objParam, memberName); + Expression returnExpr = memberExpr; + if (invokeMethod.ReturnType != memberExpr.Type) + returnExpr = Expression.ConvertChecked(memberExpr, invokeMethod.ReturnType); + + var lambda = + Expression.Lambda(returnExpr, $"Access{paramType.Name}_{memberName}", new[] {objParam}); + return lambda.Compile(); + } + } +} \ No newline at end of file diff --git a/GamecraftModdingAPI/Blocks/BlockEventsEngine.cs b/GamecraftModdingAPI/Blocks/BlockEventsEngine.cs index 3c34b65..0a205f0 100644 --- a/GamecraftModdingAPI/Blocks/BlockEventsEngine.cs +++ b/GamecraftModdingAPI/Blocks/BlockEventsEngine.cs @@ -1,9 +1,11 @@ using System; -using GamecraftModdingAPI.Engines; -using GamecraftModdingAPI.Utility; + using RobocraftX.Common; using Svelto.ECS; +using GamecraftModdingAPI.Engines; +using GamecraftModdingAPI.Utility; + namespace GamecraftModdingAPI.Blocks { public class BlockEventsEngine : IReactionaryEngine @@ -11,11 +13,18 @@ namespace GamecraftModdingAPI.Blocks public event EventHandler Placed; public event EventHandler Removed; + public BlockEventsEngine() + { + //Console.WriteLine("Creating BlockEventsEngine\n" + Environment.StackTrace); + } + public void Ready() { + //Console.WriteLine("BlockEventsEngine registered"); } public EntitiesDB entitiesDB { get; set; } + public void Dispose() { } @@ -23,17 +32,52 @@ namespace GamecraftModdingAPI.Blocks public string Name { get; } = "GamecraftModdingAPIBlockEventsEngine"; public bool isRemovable { get; } = false; + private bool shouldAddRemove; public void Add(ref DBEntityStruct entityComponent, EGID egid) { - ExceptionUtil.InvokeEvent(Placed, this, new BlockPlacedRemovedEventArgs {ID = egid, Type = (BlockIDs) entityComponent.DBID}); + if (!(shouldAddRemove = !shouldAddRemove)) + return; + ExceptionUtil.InvokeEvent(Placed, this, + new BlockPlacedRemovedEventArgs {ID = egid, Type = (BlockIDs) entityComponent.DBID}); } public void Remove(ref DBEntityStruct entityComponent, EGID egid) { - ExceptionUtil.InvokeEvent(Removed, this, new BlockPlacedRemovedEventArgs {ID = egid, Type = (BlockIDs) entityComponent.DBID}); + if (!(shouldAddRemove = !shouldAddRemove)) + return; + ExceptionUtil.InvokeEvent(Removed, this, + new BlockPlacedRemovedEventArgs {ID = egid, Type = (BlockIDs) entityComponent.DBID}); } } + /*[HarmonyPatch] + public static class TestPatch + { + public static void Postfix(FasterDictionary, FasterList> engines, + ExclusiveGroupStruct? previousGroup, in PlatformProfiler profiler, EGID egid) + { + if (!engines.TryGetValue(new RefWrapper(TypeSafeDictionary._type), out result)) + return; + } + public static MethodBase TargetMethod() + { + return AccessTools.Method("Svelto.ECS.Internal.TypeSafeDictionary:AddEntityComponentToEngines"); + } + }*/ + + /*[HarmonyPatch] + public static class TestPatch + { + public static void Postfix(EGID basePartEGID) + { + Console.WriteLine("Patched Add method: " + basePartEGID); + } + public static MethodBase TargetMethod() + { + return AccessTools.Method("RobocraftX.CR.MachineEditing.BuildBlockAdditionalPartEngine:Add"); + } + }*/ + public struct BlockPlacedRemovedEventArgs { public EGID ID; diff --git a/GamecraftModdingAPI/Blocks/BlockIDs.cs b/GamecraftModdingAPI/Blocks/BlockIDs.cs index b0eca31..596fb38 100644 --- a/GamecraftModdingAPI/Blocks/BlockIDs.cs +++ b/GamecraftModdingAPI/Blocks/BlockIDs.cs @@ -6,7 +6,7 @@ namespace GamecraftModdingAPI.Blocks public enum BlockIDs : ushort { /// - /// A custom value for the API. Doesn't exist for Gamecraft. + /// Called "nothing" in Gamecraft. (DBID.NOTHING) /// Invalid = ushort.MaxValue, AluminiumCube = 0, diff --git a/GamecraftModdingAPI/Blocks/ConsoleBlock.cs b/GamecraftModdingAPI/Blocks/ConsoleBlock.cs index e132029..4425a1e 100644 --- a/GamecraftModdingAPI/Blocks/ConsoleBlock.cs +++ b/GamecraftModdingAPI/Blocks/ConsoleBlock.cs @@ -14,18 +14,10 @@ namespace GamecraftModdingAPI.Blocks { public ConsoleBlock(EGID id): base(id) { - if (!BlockEngine.GetBlockInfoExists(this.Id)) - { - throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); - } } public ConsoleBlock(uint id): base(new EGID(id, CommonExclusiveGroups.BUILD_CONSOLE_BLOCK_GROUP)) { - if (!BlockEngine.GetBlockInfoExists(this.Id)) - { - throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); - } } // custom console block properties @@ -34,43 +26,47 @@ namespace GamecraftModdingAPI.Blocks { get { - return BlockEngine.GetBlockInfo(Id).commandName; + return BlockEngine.GetBlockInfo(this, (ConsoleBlockEntityStruct st) => st.commandName); } set { - BlockEngine.GetBlockInfo(Id).commandName.Set(value); + BlockEngine.SetBlockInfo(this, (ref ConsoleBlockEntityStruct st, string val) => st.commandName.Set(val), + value); } } public string Arg1 { - get => BlockEngine.GetBlockInfo(Id).arg1; + get => BlockEngine.GetBlockInfo(this, (ConsoleBlockEntityStruct st) => st.arg1); set { - BlockEngine.GetBlockInfo(Id).arg1.Set(value); + BlockEngine.SetBlockInfo(this, (ref ConsoleBlockEntityStruct st, string val) => st.arg1.Set(val), + value); } } public string Arg2 { - get => BlockEngine.GetBlockInfo(Id).arg2; + get => BlockEngine.GetBlockInfo(this, (ConsoleBlockEntityStruct st) => st.arg2); - set - { - BlockEngine.GetBlockInfo(Id).arg2.Set(value); - } + set + { + BlockEngine.SetBlockInfo(this, (ref ConsoleBlockEntityStruct st, string val) => st.arg2.Set(val), + value); + } } public string Arg3 { - get => BlockEngine.GetBlockInfo(Id).arg3; + get => BlockEngine.GetBlockInfo(this, (ConsoleBlockEntityStruct st) => st.arg3); - set - { - BlockEngine.GetBlockInfo(Id).arg3.Set(value); - } + set + { + BlockEngine.SetBlockInfo(this, (ref ConsoleBlockEntityStruct st, string val) => st.arg3.Set(val), + value); + } } } } diff --git a/GamecraftModdingAPI/Blocks/Motor.cs b/GamecraftModdingAPI/Blocks/Motor.cs index fde2920..fdadd26 100644 --- a/GamecraftModdingAPI/Blocks/Motor.cs +++ b/GamecraftModdingAPI/Blocks/Motor.cs @@ -13,18 +13,10 @@ namespace GamecraftModdingAPI.Blocks { public Motor(EGID id) : base(id) { - if (!BlockEngine.GetBlockInfoExists(this.Id)) - { - throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); - } } public Motor(uint id): base(new EGID(id, CommonExclusiveGroups.BUILD_MOTOR_BLOCK_GROUP)) { - if (!BlockEngine.GetBlockInfoExists(this.Id)) - { - throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); - } } // custom motor properties @@ -36,13 +28,12 @@ namespace GamecraftModdingAPI.Blocks { get { - return BlockEngine.GetBlockInfo(Id).maxVelocity; + return BlockEngine.GetBlockInfo(this, (MotorReadOnlyStruct st) => st.maxVelocity); } set { - ref MotorReadOnlyStruct motor = ref BlockEngine.GetBlockInfo(Id); - motor.maxVelocity = value; + BlockEngine.SetBlockInfo(this, (ref MotorReadOnlyStruct st, float val) => st.maxVelocity = val, value); } } @@ -53,13 +44,12 @@ namespace GamecraftModdingAPI.Blocks { get { - return BlockEngine.GetBlockInfo(Id).maxForce; + return BlockEngine.GetBlockInfo(this, (MotorReadOnlyStruct st) => st.maxForce); } set { - ref MotorReadOnlyStruct motor = ref BlockEngine.GetBlockInfo(Id); - motor.maxForce = value; + BlockEngine.SetBlockInfo(this, (ref MotorReadOnlyStruct st, float val) => st.maxForce = val, value); } } @@ -70,13 +60,12 @@ namespace GamecraftModdingAPI.Blocks { get { - return BlockEngine.GetBlockInfo(Id).reverse; + return BlockEngine.GetBlockInfo(this, (MotorReadOnlyStruct st) => st.reverse); } set { - ref MotorReadOnlyStruct motor = ref BlockEngine.GetBlockInfo(Id); - motor.reverse = value; + BlockEngine.SetBlockInfo(this, (ref MotorReadOnlyStruct st, bool val) => st.reverse = val, value); } } } diff --git a/GamecraftModdingAPI/Blocks/ObjectIdentifier.cs b/GamecraftModdingAPI/Blocks/ObjectIdentifier.cs index 9af96c2..0dc835a 100644 --- a/GamecraftModdingAPI/Blocks/ObjectIdentifier.cs +++ b/GamecraftModdingAPI/Blocks/ObjectIdentifier.cs @@ -8,27 +8,22 @@ namespace GamecraftModdingAPI.Blocks { public ObjectIdentifier(EGID id) : base(id) { - if (!BlockEngine.GetBlockInfoExists(Id)) - { - throw new BlockTypeException($"Block is not a {GetType().Name} block"); - } } public ObjectIdentifier(uint id) : base(new EGID(id, CommonExclusiveGroups.BUILD_OBJID_BLOCK_GROUP)) { - if (!BlockEngine.GetBlockInfoExists(Id)) - { - throw new BlockTypeException($"Block is not a {GetType().Name} block"); - } } public char Identifier { - get => (char) (BlockEngine.GetBlockInfo(Id).objectId + 'A'); + get => (char) BlockEngine.GetBlockInfo(this, (ObjectIdEntityStruct st) => st.objectId + 'A'); set { - BlockEngine.GetBlockInfo(Id).objectId = (byte) (value - 'A'); - Label = value + ""; //The label isn't updated automatically + BlockEngine.SetBlockInfo(this, (ref ObjectIdEntityStruct st, char val) => + { + st.objectId = (byte) (val - 'A'); + Label = val + ""; //The label isn't updated automatically + }, value); } } @@ -37,7 +32,7 @@ namespace GamecraftModdingAPI.Blocks /// public byte SimID { - get => BlockEngine.GetBlockInfo(Id).simObjectId; + get => BlockEngine.GetBlockInfo(this, (ObjectIdEntityStruct st) => st.simObjectId); } /// diff --git a/GamecraftModdingAPI/Blocks/Piston.cs b/GamecraftModdingAPI/Blocks/Piston.cs index 2586b60..aed8c33 100644 --- a/GamecraftModdingAPI/Blocks/Piston.cs +++ b/GamecraftModdingAPI/Blocks/Piston.cs @@ -13,18 +13,10 @@ namespace GamecraftModdingAPI.Blocks { public Piston(EGID id) : base(id) { - if (!BlockEngine.GetBlockInfoExists(this.Id)) - { - throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); - } } public Piston(uint id) : base(new EGID(id, CommonExclusiveGroups.BUILD_PISTON_BLOCK_GROUP)) { - if (!BlockEngine.GetBlockInfoExists(this.Id)) - { - throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); - } } // custom piston properties @@ -33,13 +25,13 @@ namespace GamecraftModdingAPI.Blocks /// The piston's max extension distance. /// public float MaximumExtension - { - get => BlockEngine.GetBlockInfo(Id).maxDeviation; + { + get => BlockEngine.GetBlockInfo(this, (PistonReadOnlyStruct st) => st.maxDeviation); set { - ref PistonReadOnlyStruct piston = ref BlockEngine.GetBlockInfo(Id); - piston.maxDeviation = value; + BlockEngine.SetBlockInfo(this, (ref PistonReadOnlyStruct st, float val) => st.maxDeviation = val, + value); } } @@ -47,13 +39,12 @@ namespace GamecraftModdingAPI.Blocks /// The piston's max extension force. /// public float MaximumForce - { - get => BlockEngine.GetBlockInfo(Id).maxForce; + { + get => BlockEngine.GetBlockInfo(this, (PistonReadOnlyStruct st) => st.maxForce); set { - ref PistonReadOnlyStruct piston = ref BlockEngine.GetBlockInfo(Id); - piston.maxForce = value; + BlockEngine.SetBlockInfo(this, (ref PistonReadOnlyStruct st, float val) => st.maxForce = val, value); } } } diff --git a/GamecraftModdingAPI/Blocks/PlacementEngine.cs b/GamecraftModdingAPI/Blocks/PlacementEngine.cs index 2297d90..61834b0 100644 --- a/GamecraftModdingAPI/Blocks/PlacementEngine.cs +++ b/GamecraftModdingAPI/Blocks/PlacementEngine.cs @@ -40,15 +40,16 @@ namespace GamecraftModdingAPI.Blocks private static BlockEntityFactory _blockEntityFactory; //Injected from PlaceBlockEngine public EGID PlaceBlock(BlockIDs block, BlockColors color, byte darkness, float3 position, int uscale, - float3 scale, Player player, float3 rotation) + float3 scale, Player player, float3 rotation, out EntityComponentInitializer initializer) { //It appears that only the non-uniform scale has any visible effect, but if that's not given here it will be set to the uniform one if (darkness > 9) throw new Exception("That is too dark. Make sure to use 0-9 as darkness. (0 is default.)"); - return BuildBlock((ushort) block, (byte) (color + darkness * 10), position, uscale, scale, rotation, + initializer = BuildBlock((ushort) block, (byte) (color + darkness * 10), position, uscale, scale, rotation, (player ?? new Player(PlayerType.Local)).Id); + return initializer.EGID; } - private EGID BuildBlock(ushort block, byte color, float3 position, int uscale, float3 scale, float3 rot, uint playerId) + private EntityComponentInitializer BuildBlock(ushort block, byte color, float3 position, int uscale, float3 scale, float3 rot, uint playerId) { if (_blockEntityFactory == null) throw new Exception("The factory is null."); @@ -107,7 +108,7 @@ namespace GamecraftModdingAPI.Blocks pickedBlock.placedBlockEntityID = structInitializer.EGID; pickedBlock.placedBlockWasAPickedBlock = false; Block.BlockEngine.Synced = false; // Block entities will need to be submitted before properties can be used - return structInitializer.EGID; + return structInitializer; } public string Name { get; } = "GamecraftModdingAPIPlacementGameEngine"; diff --git a/GamecraftModdingAPI/Blocks/Servo.cs b/GamecraftModdingAPI/Blocks/Servo.cs index c4b57fb..730749a 100644 --- a/GamecraftModdingAPI/Blocks/Servo.cs +++ b/GamecraftModdingAPI/Blocks/Servo.cs @@ -13,18 +13,10 @@ namespace GamecraftModdingAPI.Blocks { public Servo(EGID id) : base(id) { - if (!BlockEngine.GetBlockInfoExists(this.Id)) - { - throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); - } } public Servo(uint id) : base(new EGID(id, CommonExclusiveGroups.BUILD_SERVO_BLOCK_GROUP)) { - if (!BlockEngine.GetBlockInfoExists(this.Id)) - { - throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); - } } // custom servo properties @@ -33,13 +25,12 @@ namespace GamecraftModdingAPI.Blocks /// The servo's minimum angle. /// public float MinimumAngle - { - get => BlockEngine.GetBlockInfo(Id).minDeviation; + { + get => BlockEngine.GetBlockInfo(this, (ServoReadOnlyStruct st) => st.minDeviation); set { - ref ServoReadOnlyStruct servo = ref BlockEngine.GetBlockInfo(Id); - servo.minDeviation = value; + BlockEngine.SetBlockInfo(this, (ref ServoReadOnlyStruct st, float val) => st.minDeviation = val, value); } } @@ -48,13 +39,12 @@ namespace GamecraftModdingAPI.Blocks /// public float MaximumAngle { - get => BlockEngine.GetBlockInfo(Id).maxDeviation; + get => BlockEngine.GetBlockInfo(this, (ServoReadOnlyStruct st) => st.maxDeviation); - set - { - ref ServoReadOnlyStruct servo = ref BlockEngine.GetBlockInfo(Id); - servo.maxDeviation = value; - } + set + { + BlockEngine.SetBlockInfo(this, (ref ServoReadOnlyStruct st, float val) => st.maxDeviation = val, value); + } } /// @@ -62,13 +52,12 @@ namespace GamecraftModdingAPI.Blocks /// public float MaximumForce { - get => BlockEngine.GetBlockInfo(Id).maxForce; + get => BlockEngine.GetBlockInfo(this, (ServoReadOnlyStruct st) => st.maxForce); - set - { - ref ServoReadOnlyStruct servo = ref BlockEngine.GetBlockInfo(Id); - servo.maxForce = value; - } + set + { + BlockEngine.SetBlockInfo(this, (ref ServoReadOnlyStruct st, float val) => st.maxForce = val, value); + } } /// @@ -76,13 +65,12 @@ namespace GamecraftModdingAPI.Blocks /// public bool Reverse { - get => BlockEngine.GetBlockInfo(Id).reverse; + get => BlockEngine.GetBlockInfo(this, (ServoReadOnlyStruct st) => st.reverse); - set - { - ref ServoReadOnlyStruct servo = ref BlockEngine.GetBlockInfo(Id); - servo.reverse = value; - } + set + { + BlockEngine.SetBlockInfo(this, (ref ServoReadOnlyStruct st, bool val) => st.reverse = val, value); + } } } } diff --git a/GamecraftModdingAPI/Blocks/SignalingBlock.cs b/GamecraftModdingAPI/Blocks/SignalingBlock.cs index 8a62d64..149e450 100644 --- a/GamecraftModdingAPI/Blocks/SignalingBlock.cs +++ b/GamecraftModdingAPI/Blocks/SignalingBlock.cs @@ -16,7 +16,7 @@ namespace GamecraftModdingAPI.Blocks { public SignalingBlock(EGID id) : base(id) { - if (!BlockEngine.GetBlockInfoExists(this.Id)) + if (!BlockEngine.GetBlockInfoExists(this)) { throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); } @@ -24,17 +24,12 @@ namespace GamecraftModdingAPI.Blocks public SignalingBlock(uint id) : base(id) { - if (!BlockEngine.GetBlockInfoExists(this.Id)) + if (!BlockEngine.GetBlockInfoExists(this)) { throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); } } - protected ref BlockPortsStruct GetBlockPortsStruct() - { - return ref BlockEngine.GetBlockInfo(Id); - } - /// /// Generates the input port identifiers. /// @@ -53,16 +48,6 @@ namespace GamecraftModdingAPI.Blocks return SignalEngine.GetSignalOutputs(Id); } - /// - /// Gets the port struct. - /// - /// The port struct. - /// Port identifier. - protected ref PortEntityStruct GetPortStruct(EGID portId) - { - return ref BlockEngine.GetBlockInfo(portId); - } - /// /// Gets the connected wire. /// @@ -89,16 +74,16 @@ namespace GamecraftModdingAPI.Blocks /// The input port count. /// public uint InputCount - { - get => GetBlockPortsStruct().inputCount; - } + { + get => BlockEngine.GetBlockInfo(this, (BlockPortsStruct st) => st.inputCount); + } /// /// The output port count. /// public uint OutputCount { - get => GetBlockPortsStruct().outputCount; + get => BlockEngine.GetBlockInfo(this, (BlockPortsStruct st) => st.outputCount); } } } diff --git a/GamecraftModdingAPI/Blocks/SpawnPoint.cs b/GamecraftModdingAPI/Blocks/SpawnPoint.cs index 4419e38..7616acb 100644 --- a/GamecraftModdingAPI/Blocks/SpawnPoint.cs +++ b/GamecraftModdingAPI/Blocks/SpawnPoint.cs @@ -15,18 +15,10 @@ namespace GamecraftModdingAPI.Blocks { public SpawnPoint(EGID id) : base(id) { - if (!BlockEngine.GetBlockInfoExists(this.Id)) - { - throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); - } } public SpawnPoint(uint id) : base(new EGID(id, CommonExclusiveGroups.BUILD_SPAWNPOINT_BLOCK_GROUP)) { - if (!BlockEngine.GetBlockInfoExists(this.Id)) - { - throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); - } } // custom spawn point properties @@ -36,16 +28,12 @@ namespace GamecraftModdingAPI.Blocks /// public uint Lives { - get - { - return BlockEngine.GetBlockInfo(Id).lives; - } + get => BlockEngine.GetBlockInfo(this, (SpawnPointStatsEntityStruct st) => st.lives); - set - { - ref SpawnPointStatsEntityStruct spses = ref BlockEngine.GetBlockInfo(Id); - spses.lives = value; - } + set + { + BlockEngine.SetBlockInfo(this, (ref SpawnPointStatsEntityStruct st, uint val) => st.lives = val, value); + } } /// @@ -53,16 +41,12 @@ namespace GamecraftModdingAPI.Blocks /// public bool Damageable { - get - { - return BlockEngine.GetBlockInfo(Id).canTakeDamage; - } + get => BlockEngine.GetBlockInfo(this, (SpawnPointStatsEntityStruct st) => st.canTakeDamage); - set - { - ref SpawnPointStatsEntityStruct spses = ref BlockEngine.GetBlockInfo(Id); - spses.canTakeDamage = value; - } + set + { + BlockEngine.SetBlockInfo(this, (ref SpawnPointStatsEntityStruct st, bool val) => st.canTakeDamage = val, value); + } } /// @@ -70,16 +54,12 @@ namespace GamecraftModdingAPI.Blocks /// public bool GameOverEnabled { - get - { - return BlockEngine.GetBlockInfo(Id).gameOverScreen; - } + get => BlockEngine.GetBlockInfo(this, (SpawnPointStatsEntityStruct st) => st.gameOverScreen); - set - { - ref SpawnPointStatsEntityStruct spses = ref BlockEngine.GetBlockInfo(Id); - spses.gameOverScreen = value; - } + set + { + BlockEngine.SetBlockInfo(this, (ref SpawnPointStatsEntityStruct st, bool val) => st.gameOverScreen = val, value); + } } /// @@ -87,16 +67,12 @@ namespace GamecraftModdingAPI.Blocks /// public byte Team { - get - { - return BlockEngine.GetBlockInfo(Id).teamId; - } + get => BlockEngine.GetBlockInfo(this, (SpawnPointIdsEntityStruct st) => st.teamId); - set - { - ref SpawnPointIdsEntityStruct spses = ref BlockEngine.GetBlockInfo(Id); - spses.teamId = value; - } + set + { + BlockEngine.SetBlockInfo(this, (ref SpawnPointIdsEntityStruct st, byte val) => st.teamId = val, value); + } } } } diff --git a/GamecraftModdingAPI/Blocks/TextBlock.cs b/GamecraftModdingAPI/Blocks/TextBlock.cs index 94cf212..6096dd4 100644 --- a/GamecraftModdingAPI/Blocks/TextBlock.cs +++ b/GamecraftModdingAPI/Blocks/TextBlock.cs @@ -14,18 +14,10 @@ namespace GamecraftModdingAPI.Blocks { public TextBlock(EGID id) : base(id) { - if (!BlockEngine.GetBlockInfoExists(this.Id)) - { - throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); - } } public TextBlock(uint id) : base(new EGID(id, CommonExclusiveGroups.BUILD_TEXT_BLOCK_GROUP)) { - if (!BlockEngine.GetBlockInfoExists(this.Id)) - { - throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); - } } // custom text block properties @@ -35,35 +27,34 @@ namespace GamecraftModdingAPI.Blocks /// public string Text { - get - { - return BlockEngine.GetBlockInfo(Id).textCurrent; - } + get => BlockEngine.GetBlockInfo(this, (TextBlockDataStruct st) => st.textCurrent); - set - { - ref TextBlockDataStruct tbds = ref BlockEngine.GetBlockInfo(Id); - tbds.textCurrent.Set(value); - tbds.textStored.Set(value); - BlockEngine.GetBlockInfo(Id).newTextBlockStringContent.Set(value); - } - } + set + { + BlockEngine.SetBlockInfo(this, (ref TextBlockDataStruct tbds, string val) => + { + tbds.textCurrent.Set(val); + tbds.textStored.Set(val); + }, value); + BlockEngine.SetBlockInfo(this, + (ref TextBlockNetworkDataStruct st, string val) => st.newTextBlockStringContent.Set(val), value); + } + } /// - /// The text block's current text block ID (used in ChangeTextBlockCommand). + /// The text block's current text block ID (used in ChangeTextBlockCommand). /// - public string TextBlockId + public string TextBlockId { - get - { - return BlockEngine.GetBlockInfo(Id).textBlockID; - } + get => BlockEngine.GetBlockInfo(this, (TextBlockDataStruct st) => st.textBlockID); - set - { - BlockEngine.GetBlockInfo(Id).textBlockID.Set(value); - BlockEngine.GetBlockInfo(Id).newTextBlockID.Set(value); - } + set + { + BlockEngine.SetBlockInfo(this, (ref TextBlockDataStruct tbds, string val) => + tbds.textBlockID.Set(val), value); + BlockEngine.SetBlockInfo(this, + (ref TextBlockNetworkDataStruct st, string val) => st.newTextBlockID.Set(val), value); + } } } } diff --git a/GamecraftModdingAPI/Blocks/Timer.cs b/GamecraftModdingAPI/Blocks/Timer.cs index 2acab5b..5766a41 100644 --- a/GamecraftModdingAPI/Blocks/Timer.cs +++ b/GamecraftModdingAPI/Blocks/Timer.cs @@ -15,18 +15,10 @@ namespace GamecraftModdingAPI.Blocks { public Timer(EGID id) : base(id) { - if (!BlockEngine.GetBlockInfoExists(this.Id)) - { - throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); - } } public Timer(uint id) : base(new EGID(id, CommonExclusiveGroups.BUILD_TIMER_BLOCK_GROUP)) { - if (!BlockEngine.GetBlockInfoExists(this.Id)) - { - throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); - } } // custom timer properties @@ -36,16 +28,13 @@ namespace GamecraftModdingAPI.Blocks /// public float Start { - get - { - return BlockEngine.GetBlockInfo(Id).startTime; - } + get => BlockEngine.GetBlockInfo(this, (TimerBlockDataStruct st) => st.startTime); - set - { - ref TimerBlockDataStruct tbds = ref BlockEngine.GetBlockInfo(Id); - tbds.startTime = value; - } + set + { + BlockEngine.SetBlockInfo(this, (ref TimerBlockDataStruct tbds, float val) => tbds.startTime = val, + value); + } } /// @@ -53,16 +42,13 @@ namespace GamecraftModdingAPI.Blocks /// public float End { - get - { - return BlockEngine.GetBlockInfo(Id).endTime; - } + get => BlockEngine.GetBlockInfo(this, (TimerBlockDataStruct st) => st.endTime); - set - { - ref TimerBlockDataStruct tbds = ref BlockEngine.GetBlockInfo(Id); - tbds.endTime = value; - } + set + { + BlockEngine.SetBlockInfo(this, (ref TimerBlockDataStruct tbds, float val) => tbds.endTime = val, + value); + } } /// @@ -70,16 +56,13 @@ namespace GamecraftModdingAPI.Blocks /// public bool DisplayMilliseconds { - get - { - return BlockEngine.GetBlockInfo(Id).outputFormatHasMS; - } + get => BlockEngine.GetBlockInfo(this, (TimerBlockDataStruct st) => st.outputFormatHasMS); - set - { - ref TimerBlockDataStruct tbds = ref BlockEngine.GetBlockInfo(Id); - tbds.outputFormatHasMS = value; - } + set + { + BlockEngine.SetBlockInfo(this, (ref TimerBlockDataStruct tbds, bool val) => tbds.outputFormatHasMS = val, + value); + } } /// @@ -87,16 +70,13 @@ namespace GamecraftModdingAPI.Blocks /// public int CurrentTime { - get - { - return BlockEngine.GetBlockInfo(Id).timeLastRenderFrameMS; - } + get => BlockEngine.GetBlockInfo(this, (TimerBlockLabelCacheEntityStruct st) => st.timeLastRenderFrameMS); - set - { - ref TimerBlockLabelCacheEntityStruct tblces = ref BlockEngine.GetBlockInfo(Id); - tblces.timeLastRenderFrameMS = value; - } + set + { + BlockEngine.SetBlockInfo(this, (ref TimerBlockLabelCacheEntityStruct tbds, int val) => tbds.timeLastRenderFrameMS = val, + value); + } } } } From 5e335e78ffa99f8726aefa2e24f54d61e3de7808 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 15 Jul 2020 22:46:48 +0200 Subject: [PATCH 18/34] Implement init for position and rotation --- GamecraftModdingAPI/Block.cs | 8 ++--- GamecraftModdingAPI/Blocks/ConsoleBlock.cs | 3 ++ GamecraftModdingAPI/Blocks/MovementEngine.cs | 19 ++++++++-- GamecraftModdingAPI/Blocks/RotationEngine.cs | 38 ++++++++++++++------ 4 files changed, 52 insertions(+), 16 deletions(-) diff --git a/GamecraftModdingAPI/Block.cs b/GamecraftModdingAPI/Block.cs index c3e0393..f334c30 100644 --- a/GamecraftModdingAPI/Block.cs +++ b/GamecraftModdingAPI/Block.cs @@ -209,10 +209,10 @@ namespace GamecraftModdingAPI /// public float3 Position { - get => Exists ? MovementEngine.GetPosition(Id) : float3.zero; + get => MovementEngine.GetPosition(Id, InitData); set { - if (Exists) MovementEngine.MoveBlock(Id, value); + MovementEngine.MoveBlock(Id, InitData, value); } } @@ -221,10 +221,10 @@ namespace GamecraftModdingAPI /// public float3 Rotation { - get => Exists ? RotationEngine.GetRotation(Id) : float3.zero; + get => RotationEngine.GetRotation(Id, InitData); set { - if (Exists) RotationEngine.RotateBlock(Id, value); + RotationEngine.RotateBlock(Id, InitData, value); } } diff --git a/GamecraftModdingAPI/Blocks/ConsoleBlock.cs b/GamecraftModdingAPI/Blocks/ConsoleBlock.cs index 4425a1e..edf3e76 100644 --- a/GamecraftModdingAPI/Blocks/ConsoleBlock.cs +++ b/GamecraftModdingAPI/Blocks/ConsoleBlock.cs @@ -22,6 +22,9 @@ namespace GamecraftModdingAPI.Blocks // custom console block properties + /// + /// Setting a nonexistent command will crash the game when switching to simulation + /// public string Command { get diff --git a/GamecraftModdingAPI/Blocks/MovementEngine.cs b/GamecraftModdingAPI/Blocks/MovementEngine.cs index 0ff119a..a4ac0fa 100644 --- a/GamecraftModdingAPI/Blocks/MovementEngine.cs +++ b/GamecraftModdingAPI/Blocks/MovementEngine.cs @@ -35,8 +35,17 @@ namespace GamecraftModdingAPI.Blocks // implementations for Movement static class - public float3 MoveBlock(EGID blockID, float3 vector) + internal float3 MoveBlock(EGID blockID, BlockEngine.BlockInitData data, float3 vector) { + if (!entitiesDB.Exists(blockID)) + { + if (data.Group == null) return float3.zero; + var init = new EntityComponentInitializer(blockID, data.Group); + init.Init(new PositionEntityStruct {position = vector}); + init.Init(new GridRotationStruct {position = vector}); + init.Init(new LocalTransformEntityStruct {position = vector}); + return vector; + } ref PositionEntityStruct posStruct = ref this.entitiesDB.QueryEntity(blockID); ref GridRotationStruct gridStruct = ref this.entitiesDB.QueryEntity(blockID); ref LocalTransformEntityStruct transStruct = ref this.entitiesDB.QueryEntity(blockID); @@ -56,8 +65,14 @@ namespace GamecraftModdingAPI.Blocks return posStruct.position; } - public float3 GetPosition(EGID blockID) + internal float3 GetPosition(EGID blockID, BlockEngine.BlockInitData data) { + if (!entitiesDB.Exists(blockID)) + { + if (data.Group == null) return float3.zero; + var init = new EntityComponentInitializer(blockID, data.Group); + return init.Has() ? init.Get().position : float3.zero; + } ref PositionEntityStruct posStruct = ref this.entitiesDB.QueryEntity(blockID); return posStruct.position; } diff --git a/GamecraftModdingAPI/Blocks/RotationEngine.cs b/GamecraftModdingAPI/Blocks/RotationEngine.cs index e9cd1ef..ca97874 100644 --- a/GamecraftModdingAPI/Blocks/RotationEngine.cs +++ b/GamecraftModdingAPI/Blocks/RotationEngine.cs @@ -35,23 +35,32 @@ namespace GamecraftModdingAPI.Blocks // implementations for Rotation static class - public float3 RotateBlock(EGID blockID, Vector3 vector) + internal float3 RotateBlock(EGID blockID, BlockEngine.BlockInitData data, Vector3 vector) { + if (!entitiesDB.Exists(blockID)) + { + if (data.Group == null) return float3.zero; + var init = new EntityComponentInitializer(blockID, data.Group); + init.Init(new RotationEntityStruct {rotation = new Quaternion {eulerAngles = vector}}); + init.Init(new GridRotationStruct {rotation = new Quaternion {eulerAngles = vector}}); + init.Init(new LocalTransformEntityStruct {rotation = new Quaternion {eulerAngles = vector}}); + return vector; + } ref RotationEntityStruct rotStruct = ref this.entitiesDB.QueryEntity(blockID); ref GridRotationStruct gridStruct = ref this.entitiesDB.QueryEntity(blockID); ref LocalTransformEntityStruct transStruct = ref this.entitiesDB.QueryEntity(blockID); ref UECSPhysicsEntityStruct phyStruct = ref this.entitiesDB.QueryEntity(blockID); // main (persistent) position - Quaternion newRotation = (Quaternion)rotStruct.rotation; - newRotation.eulerAngles += vector; - rotStruct.rotation = (quaternion)newRotation; + Quaternion newRotation = rotStruct.rotation; + newRotation.eulerAngles = vector; + rotStruct.rotation = newRotation; // placement grid rotation - Quaternion newGridRotation = (Quaternion)gridStruct.rotation; - newGridRotation.eulerAngles += vector; - gridStruct.rotation = (quaternion)newGridRotation; + Quaternion newGridRotation = gridStruct.rotation; + newGridRotation.eulerAngles = vector; + gridStruct.rotation = newGridRotation; // rendered position - Quaternion newTransRotation = (Quaternion)rotStruct.rotation; - newTransRotation.eulerAngles += vector; + Quaternion newTransRotation = rotStruct.rotation; + newTransRotation.eulerAngles = vector; transStruct.rotation = newTransRotation; // collision position FullGameFields._physicsWorld.EntityManager.SetComponentData(phyStruct.uecsEntity, new Unity.Transforms.Rotation @@ -63,8 +72,17 @@ namespace GamecraftModdingAPI.Blocks } - public float3 GetRotation(EGID blockID) + internal float3 GetRotation(EGID blockID, BlockEngine.BlockInitData data) { + if (!entitiesDB.Exists(blockID)) + { + if (data.Group == null) return float3.zero; + var init = new EntityComponentInitializer(blockID, data.Group); + return init.Has() + ? (float3) ((Quaternion) init.Get().rotation).eulerAngles + : float3.zero; + } + ref RotationEntityStruct rotStruct = ref entitiesDB.QueryEntity(blockID); return ((Quaternion) rotStruct.rotation).eulerAngles; } From 5264d98ce71d8e9be46d3bfe0e676b7014c32d71 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sun, 19 Jul 2020 01:13:39 +0200 Subject: [PATCH 19/34] Test fixes, block event Block property Fixed Assert.Equal() Changed tests to reflect changes Added Block property to the block event args Completely removed sync things --- GamecraftModdingAPI/Block.cs | 4 +- GamecraftModdingAPI/Blocks/BlockEngine.cs | 2 - .../Blocks/BlockEventsEngine.cs | 37 ++----------------- GamecraftModdingAPI/Blocks/BlockTests.cs | 6 +-- GamecraftModdingAPI/Blocks/PlacementEngine.cs | 1 - GamecraftModdingAPI/SimBody.cs | 2 +- GamecraftModdingAPI/Tests/Assert.cs | 24 +----------- .../Tests/GamecraftModdingAPIPluginTest.cs | 2 +- .../DeterministicStepCompositionRootPatch.cs | 25 ------------- 9 files changed, 12 insertions(+), 91 deletions(-) delete mode 100644 GamecraftModdingAPI/Utility/DeterministicStepCompositionRootPatch.cs diff --git a/GamecraftModdingAPI/Block.cs b/GamecraftModdingAPI/Block.cs index f334c30..ade9f9b 100644 --- a/GamecraftModdingAPI/Block.cs +++ b/GamecraftModdingAPI/Block.cs @@ -342,10 +342,10 @@ namespace GamecraftModdingAPI public bool Remove() => RemovalEngine.RemoveBlock(Id); /// - /// Returns the rigid body of the cluster of blocks this one belongs to during simulation. + /// Returns the rigid body of the chunk of blocks this one belongs to during simulation. /// Can be used to apply forces or move the block around while the simulation is running. /// - /// The SimBody of the cluster or null if the block doesn't exist. + /// The SimBody of the chunk or null if the block doesn't exist. public SimBody GetSimBody() { return BlockEngine.GetBlockInfo(this, diff --git a/GamecraftModdingAPI/Blocks/BlockEngine.cs b/GamecraftModdingAPI/Blocks/BlockEngine.cs index d6f4907..375620e 100644 --- a/GamecraftModdingAPI/Blocks/BlockEngine.cs +++ b/GamecraftModdingAPI/Blocks/BlockEngine.cs @@ -25,8 +25,6 @@ namespace GamecraftModdingAPI.Blocks public bool isRemovable => false; - internal bool Synced = true; - public void Dispose() { } diff --git a/GamecraftModdingAPI/Blocks/BlockEventsEngine.cs b/GamecraftModdingAPI/Blocks/BlockEventsEngine.cs index 0a205f0..1e5ce21 100644 --- a/GamecraftModdingAPI/Blocks/BlockEventsEngine.cs +++ b/GamecraftModdingAPI/Blocks/BlockEventsEngine.cs @@ -13,14 +13,8 @@ namespace GamecraftModdingAPI.Blocks public event EventHandler Placed; public event EventHandler Removed; - public BlockEventsEngine() - { - //Console.WriteLine("Creating BlockEventsEngine\n" + Environment.StackTrace); - } - public void Ready() { - //Console.WriteLine("BlockEventsEngine registered"); } public EntitiesDB entitiesDB { get; set; } @@ -50,37 +44,12 @@ namespace GamecraftModdingAPI.Blocks } } - /*[HarmonyPatch] - public static class TestPatch - { - public static void Postfix(FasterDictionary, FasterList> engines, - ExclusiveGroupStruct? previousGroup, in PlatformProfiler profiler, EGID egid) - { - if (!engines.TryGetValue(new RefWrapper(TypeSafeDictionary._type), out result)) - return; - } - public static MethodBase TargetMethod() - { - return AccessTools.Method("Svelto.ECS.Internal.TypeSafeDictionary:AddEntityComponentToEngines"); - } - }*/ - - /*[HarmonyPatch] - public static class TestPatch - { - public static void Postfix(EGID basePartEGID) - { - Console.WriteLine("Patched Add method: " + basePartEGID); - } - public static MethodBase TargetMethod() - { - return AccessTools.Method("RobocraftX.CR.MachineEditing.BuildBlockAdditionalPartEngine:Add"); - } - }*/ - public struct BlockPlacedRemovedEventArgs { public EGID ID; public BlockIDs Type; + private Block block; + + public Block Block => block ?? (block = new Block(ID)); } } \ No newline at end of file diff --git a/GamecraftModdingAPI/Blocks/BlockTests.cs b/GamecraftModdingAPI/Blocks/BlockTests.cs index 3b66f28..85328d2 100644 --- a/GamecraftModdingAPI/Blocks/BlockTests.cs +++ b/GamecraftModdingAPI/Blocks/BlockTests.cs @@ -22,11 +22,11 @@ namespace GamecraftModdingAPI.Blocks } [APITestCase(TestType.EditMode)] - public static void TestSync() + public static void TestInitProperty() { Block newBlock = Block.PlaceNew(BlockIDs.AluminiumCube, Unity.Mathematics.float3.zero + 2); if (!Assert.CloseTo(newBlock.Position, (Unity.Mathematics.float3.zero + 2), $"Newly placed block at {newBlock.Position} is expected at {Unity.Mathematics.float3.zero + 2}.", "Newly placed block position matches.")) return; - Assert.Equal(newBlock.Exists, true, "Newly placed block does not exist, possibly because Sync() skipped/missed/failed.", "Newly placed block exists, Sync() successful."); + //Assert.Equal(newBlock.Exists, true, "Newly placed block does not exist, possibly because Sync() skipped/missed/failed.", "Newly placed block exists, Sync() successful."); } [APITestCase(TestType.EditMode)] @@ -34,7 +34,7 @@ namespace GamecraftModdingAPI.Blocks { TextBlock textBlock = null; // Note: the assignment operation is a lambda, which slightly confuses the compiler Assert.Errorless(() => { textBlock = Block.PlaceNew(BlockIDs.TextBlock, Unity.Mathematics.float3.zero + 1); }, "Block.PlaceNew() raised an exception: ", "Block.PlaceNew() completed without issue."); - if (!Assert.NotNull(textBlock, "Block.Specialize() returned null, possibly because it failed silently.", "Specialized TextBlock is not null.")) return; + if (!Assert.NotNull(textBlock, "Block.PlaceNew() returned null, possibly because it failed silently.", "Specialized TextBlock is not null.")) return; if (!Assert.NotNull(textBlock.Text, "TextBlock.Text is null, possibly because it failed silently.", "TextBlock.Text is not null.")) return; if (!Assert.NotNull(textBlock.TextBlockId, "TextBlock.TextBlockId is null, possibly because it failed silently.", "TextBlock.TextBlockId is not null.")) return; } diff --git a/GamecraftModdingAPI/Blocks/PlacementEngine.cs b/GamecraftModdingAPI/Blocks/PlacementEngine.cs index 61834b0..e111598 100644 --- a/GamecraftModdingAPI/Blocks/PlacementEngine.cs +++ b/GamecraftModdingAPI/Blocks/PlacementEngine.cs @@ -107,7 +107,6 @@ namespace GamecraftModdingAPI.Blocks ref PickedBlockExtraDataStruct pickedBlock = ref entitiesDB.QueryEntity(playerEGID); pickedBlock.placedBlockEntityID = structInitializer.EGID; pickedBlock.placedBlockWasAPickedBlock = false; - Block.BlockEngine.Synced = false; // Block entities will need to be submitted before properties can be used return structInitializer; } diff --git a/GamecraftModdingAPI/SimBody.cs b/GamecraftModdingAPI/SimBody.cs index 420a655..19f4285 100644 --- a/GamecraftModdingAPI/SimBody.cs +++ b/GamecraftModdingAPI/SimBody.cs @@ -9,7 +9,7 @@ using RobocraftX.Physics; namespace GamecraftModdingAPI { /// - /// A rigid body (like a cluster of connected blocks) during simulation. + /// A rigid body (like a chunk of connected blocks) during simulation. /// public class SimBody : IEquatable, IEquatable { diff --git a/GamecraftModdingAPI/Tests/Assert.cs b/GamecraftModdingAPI/Tests/Assert.cs index eec9c5c..78f0597 100644 --- a/GamecraftModdingAPI/Tests/Assert.cs +++ b/GamecraftModdingAPI/Tests/Assert.cs @@ -83,32 +83,12 @@ namespace GamecraftModdingAPI.Tests { if (err == null) err = $"{nameof(T)} '{obj1}' is not equal to '{obj2}'."; if (success == null) success = $"{nameof(T)} '{obj1}' is equal to '{obj2}'."; - if (obj1 == null && obj2 == null) + if ((obj1 == null && obj2 == null) + || (obj1 != null && obj2 != null && obj1.Equals(obj2) && obj2.Equals(obj1))) { // pass Log(PASS + success); TestRoot.TestsPassed = true; - return true; - } - else if (!(obj1 == null && obj2 == null) && obj1.Equals(obj2) && obj2.Equals(obj1)) - { - // pass - Log(PASS + success); - TestRoot.TestsPassed = true; - return true; - } - else if (obj1 != null && (obj1 != null && !obj1.Equals(obj2))) - { - // pass - Log(PASS + success); - TestRoot.TestsPassed = true; - return true; - } - else if (obj2 != null && !obj2.Equals(obj1)) - { - // pass - Log(PASS + success); - TestRoot.TestsPassed = true; return true; } else diff --git a/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs b/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs index d5cf714..d8b50fa 100644 --- a/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs +++ b/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs @@ -234,7 +234,7 @@ namespace GamecraftModdingAPI.Tests CommandBuilder.Builder() .Name("PlaceConsole") - .Description("Place a bunch of console block with a given text") + .Description("Place a bunch of console block with a given text - entering simulation with them crashes the game as the cmd doesn't exist") .Action((float x, float y, float z) => { Stopwatch sw = new Stopwatch(); diff --git a/GamecraftModdingAPI/Utility/DeterministicStepCompositionRootPatch.cs b/GamecraftModdingAPI/Utility/DeterministicStepCompositionRootPatch.cs deleted file mode 100644 index 9cabbe0..0000000 --- a/GamecraftModdingAPI/Utility/DeterministicStepCompositionRootPatch.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; - -using RobocraftX.StateSync; -using Svelto.ECS; - -using HarmonyLib; - -namespace GamecraftModdingAPI.Utility -{ - [HarmonyPatch(typeof(DeterministicStepCompositionRoot), "ResetWorld")] - public static class DeterministicStepCompositionRootPatch - { - private static SimpleEntitiesSubmissionScheduler engineRootScheduler; - public static void Postfix(SimpleEntitiesSubmissionScheduler scheduler) - { - engineRootScheduler = scheduler; - } - - internal static void SubmitEntitiesNow() - { - if (engineRootScheduler != null) - engineRootScheduler.SubmitEntities(); - } - } -} From b53dff5d12b93ca9c0cb93c29a6d008599d1d66e Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sun, 19 Jul 2020 01:42:32 +0200 Subject: [PATCH 20/34] Remove initializer data once the block is placed --- GamecraftModdingAPI/Block.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/GamecraftModdingAPI/Block.cs b/GamecraftModdingAPI/Block.cs index ade9f9b..dc3fe19 100644 --- a/GamecraftModdingAPI/Block.cs +++ b/GamecraftModdingAPI/Block.cs @@ -82,6 +82,7 @@ namespace GamecraftModdingAPI position, uscale, scale, player, rotation, out var initializer); var bl = New(egid.entityID, egid.groupID); bl.InitData.Group = BlockEngine.InitGroup(initializer); + Placed += bl.OnPlacedInit; return bl; } @@ -352,6 +353,13 @@ namespace GamecraftModdingAPI (GridConnectionsEntityStruct st) => new SimBody(st.machineRigidBodyId)); } + private void OnPlacedInit(object sender, BlockPlacedRemovedEventArgs e) + { //Member method instead of lambda to avoid constantly creating delegates + if (e.ID != Id) return; + Placed -= OnPlacedInit; //And we can reference it + InitData = default; //Remove initializer as it's no longer valid - if the block gets removed it shouldn't be used again + } + public override string ToString() { return $"{nameof(Id)}: {Id}, {nameof(Position)}: {Position}, {nameof(Type)}: {Type}, {nameof(Color)}: {Color}, {nameof(Exists)}: {Exists}"; From 15485481a2e4529b9c99d07e116910a39c136521 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Tue, 21 Jul 2020 00:19:30 +0200 Subject: [PATCH 21/34] Add some info and prev. value for setters --- GamecraftModdingAPI/Block.cs | 18 ++++++++++++++++-- GamecraftModdingAPI/Blocks/BlockEngine.cs | 5 +++-- GamecraftModdingAPI/Blocks/BlockEngineInit.cs | 6 ++++++ 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/GamecraftModdingAPI/Block.cs b/GamecraftModdingAPI/Block.cs index dc3fe19..5f30a64 100644 --- a/GamecraftModdingAPI/Block.cs +++ b/GamecraftModdingAPI/Block.cs @@ -137,6 +137,16 @@ namespace GamecraftModdingAPI {typeof(Timer), new[] {CommonExclusiveGroups.BUILD_TIMER_BLOCK_GROUP}} }; + /// + /// Constructs a new instance of T with the given ID and group using dynamically created delegates. + /// It's equivalent to new T(EGID) with a minimal overhead thanks to caching the created delegates. + /// + /// The block ID + /// The block group + /// The block's type or Block itself + /// An instance of the provided type + /// The block group doesn't match or cannot be found + /// The block class doesn't have the needed constructor private static T New(uint id, ExclusiveGroupStruct? group = null) where T : Block { var type = typeof(T); @@ -175,8 +185,8 @@ namespace GamecraftModdingAPI il.DeclareLocal(type); il.Emit(OpCodes.Ldarg_0); //Load EGID and pass to constructor il.Emit(OpCodes.Newobj, ctor); //Call constructor - il.Emit(OpCodes.Stloc_0); - il.Emit(OpCodes.Ldloc_0); + //il.Emit(OpCodes.Stloc_0); - doesn't seem like we need these + //il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ret); func = (Func) dynamic.CreateDelegate(typeof(Func)); @@ -188,6 +198,9 @@ namespace GamecraftModdingAPI public Block(EGID id) { Id = id; + if (typeToGroup.TryGetValue(GetType(), out var groups) && groups.All(gr => gr != id.groupID)) + throw new BlockTypeException("The block has the wrong group! The type is " + GetType() + + " while the group is " + id.groupID); } /// @@ -328,6 +341,7 @@ namespace GamecraftModdingAPI /// /// Whether the block exists. The other properties will return a default value if the block doesn't exist. + /// If the block was just placed, then this will also return false but the properties will work correctly. /// public bool Exists => BlockEngine.BlockExists(Id); diff --git a/GamecraftModdingAPI/Blocks/BlockEngine.cs b/GamecraftModdingAPI/Blocks/BlockEngine.cs index 375620e..f97e405 100644 --- a/GamecraftModdingAPI/Blocks/BlockEngine.cs +++ b/GamecraftModdingAPI/Blocks/BlockEngine.cs @@ -85,10 +85,11 @@ namespace GamecraftModdingAPI.Blocks { if (entitiesDB.Exists(block.Id)) setter(ref entitiesDB.QueryEntity(block.Id), value); - if (block.InitData.Group != null) + else if (block.InitData.Group != null) { var initializer = new EntityComponentInitializer(block.Id, block.InitData.Group); - ref T structRef = ref (new T[1])[0]; //A reference for a default value for struct + T component = initializer.Has() ? initializer.Get() : default; + ref T structRef = ref component; setter(ref structRef, value); initializer.Init(structRef); } diff --git a/GamecraftModdingAPI/Blocks/BlockEngineInit.cs b/GamecraftModdingAPI/Blocks/BlockEngineInit.cs index 4be9a98..70f713a 100644 --- a/GamecraftModdingAPI/Blocks/BlockEngineInit.cs +++ b/GamecraftModdingAPI/Blocks/BlockEngineInit.cs @@ -9,6 +9,9 @@ namespace GamecraftModdingAPI.Blocks { public partial class BlockEngine { + /// + /// Holds information needed to construct a component initializer + /// internal struct BlockInitData { public FasterDictionary, ITypeSafeDictionary> Group; @@ -17,6 +20,9 @@ namespace GamecraftModdingAPI.Blocks internal delegate FasterDictionary, ITypeSafeDictionary> GetInitGroup( EntityComponentInitializer initializer); + /// + /// Accesses the group field of the initializer + /// internal GetInitGroup InitGroup = CreateAccessor("_group"); //https://stackoverflow.com/questions/55878525/unit-testing-ref-structs-with-private-fields-via-reflection From 057a030c2075485a8476c0c6d7306189f1e7cf60 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Tue, 21 Jul 2020 02:36:11 +0200 Subject: [PATCH 22/34] Update music block and attempt to fix test --- GamecraftModdingAPI/Block.cs | 15 ++- GamecraftModdingAPI/Blocks/BlockTests.cs | 17 +++- GamecraftModdingAPI/Blocks/MusicBlock.cs | 123 +++++++++++------------ 3 files changed, 81 insertions(+), 74 deletions(-) diff --git a/GamecraftModdingAPI/Block.cs b/GamecraftModdingAPI/Block.cs index 5f30a64..2f9a901 100644 --- a/GamecraftModdingAPI/Block.cs +++ b/GamecraftModdingAPI/Block.cs @@ -29,7 +29,7 @@ namespace GamecraftModdingAPI protected static readonly SignalEngine SignalEngine = new SignalEngine(); protected static readonly BlockEventsEngine BlockEventsEngine = new BlockEventsEngine(); protected static readonly ScalingEngine ScalingEngine = new ScalingEngine(); - + protected internal static readonly BlockEngine BlockEngine = new BlockEngine(); /// @@ -123,6 +123,7 @@ namespace GamecraftModdingAPI { {typeof(ConsoleBlock), new[] {CommonExclusiveGroups.BUILD_CONSOLE_BLOCK_GROUP}}, {typeof(Motor), new[] {CommonExclusiveGroups.BUILD_MOTOR_BLOCK_GROUP}}, + {typeof(MusicBlock), new[] {CommonExclusiveGroups.BUILD_MUSIC_BLOCK_GROUP}}, {typeof(Piston), new[] {CommonExclusiveGroups.BUILD_PISTON_BLOCK_GROUP}}, {typeof(Servo), new[] {CommonExclusiveGroups.BUILD_SERVO_BLOCK_GROUP}}, { @@ -198,9 +199,15 @@ namespace GamecraftModdingAPI public Block(EGID id) { Id = id; - if (typeToGroup.TryGetValue(GetType(), out var groups) && groups.All(gr => gr != id.groupID)) - throw new BlockTypeException("The block has the wrong group! The type is " + GetType() + - " while the group is " + id.groupID); + var type = GetType(); + if (typeToGroup.TryGetValue(type, out var groups)) + { + if (groups.All(gr => gr != id.groupID)) + throw new BlockTypeException("The block has the wrong group! The type is " + GetType() + + " while the group is " + id.groupID); + } + else if (type != typeof(Block)) + Logging.LogWarning($"Unknown block type! Add {type} to the dictionary."); } /// diff --git a/GamecraftModdingAPI/Blocks/BlockTests.cs b/GamecraftModdingAPI/Blocks/BlockTests.cs index 85328d2..6186a1d 100644 --- a/GamecraftModdingAPI/Blocks/BlockTests.cs +++ b/GamecraftModdingAPI/Blocks/BlockTests.cs @@ -74,8 +74,8 @@ namespace GamecraftModdingAPI.Blocks if (!Assert.CloseTo(b.MaximumForce, 750f, $"Servo.MaximumForce {b.MaximumForce} does not equal default value, possibly because it failed silently.", "Servo.MaximumForce is close enough to default.")) return; } - [APITestCase(TestType.EditMode)] - public static void TestMusicBlock() + [APITestCase(TestType.Game)] + public static void TestMusicBlock1() { Block newBlock = Block.PlaceNew(BlockIDs.MusicBlock, Unity.Mathematics.float3.zero + 2); MusicBlock b = null; // Note: the assignment operation is a lambda, which slightly confuses the compiler @@ -83,8 +83,19 @@ namespace GamecraftModdingAPI.Blocks if (!Assert.NotNull(b, "Block.Specialize() returned null, possibly because it failed silently.", "Specialized MusicBlock is not null.")) return; if (!Assert.CloseTo(b.Volume, 100f, $"MusicBlock.Volume {b.Volume} does not equal default value, possibly because it failed silently.", "MusicBlock.Volume is close enough to default.")) return; if (!Assert.Equal(b.TrackIndex, 0, $"MusicBlock.TrackIndex {b.TrackIndex} does not equal default value, possibly because it failed silently.", "MusicBlock.TrackIndex is equal to default.")) return; + _musicBlock = b; + } + + private static MusicBlock _musicBlock; + + [APITestCase(TestType.EditMode)] + public static void TestMusicBlock2() + { + //Block newBlock = Block.GetLastPlacedBlock(); + var b = _musicBlock; + if (!Assert.NotNull(b, "Block.Specialize() returned null, possibly because it failed silently.", "Specialized MusicBlock is not null.")) return; b.IsPlaying = true; // play sfx - if (!Assert.Equal(b.IsPlaying, true, $"MusicBlock.IsPlaying {b.IsPlaying} does not equal default value, possibly because it failed silently.", "MusicBlock.IsPlaying is set properly.")) return; + if (!Assert.Equal(b.IsPlaying, true, $"MusicBlock.IsPlaying {b.IsPlaying} does not equal true, possibly because it failed silently.", "MusicBlock.IsPlaying is set properly.")) return; if (!Assert.Equal(b.ChannelType, ChannelType.Character, $"MusicBlock.ChannelType {b.ChannelType} does not equal default value, possibly because it failed silently.", "MusicBlock.ChannelType is equal to default.")) return; //Assert.Log(b.Track.ToString()); if (!Assert.Equal(b.Track.ToString(), new Guid("3237ff8f-f5f2-4f84-8144-496ca280f8c0").ToString(), $"MusicBlock.Track {b.Track} does not equal default value, possibly because it failed silently.", "MusicBlock.Track is equal to default.")) return; diff --git a/GamecraftModdingAPI/Blocks/MusicBlock.cs b/GamecraftModdingAPI/Blocks/MusicBlock.cs index a7f862e..2128a45 100644 --- a/GamecraftModdingAPI/Blocks/MusicBlock.cs +++ b/GamecraftModdingAPI/Blocks/MusicBlock.cs @@ -3,58 +3,38 @@ using System; using FMOD.Studio; using FMODUnity; using Gamecraft.Wires; +using RobocraftX.Common; using RobocraftX.Blocks; using Svelto.ECS; using Unity.Mathematics; using GamecraftModdingAPI; +using GamecraftModdingAPI.Tests; using GamecraftModdingAPI.Utility; namespace GamecraftModdingAPI.Blocks { public class MusicBlock : Block { - public static MusicBlock PlaceNew(float3 position, - float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0, - int uscale = 1, float3 scale = default, Player player = null) - { - if (PlacementEngine.IsInGame && GameState.IsBuildMode()) - { - EGID id = PlacementEngine.PlaceBlock(BlockIDs.MusicBlock, color, darkness, - position, uscale, scale, player, rotation); - return new MusicBlock(id); - } - - return null; - } - public MusicBlock(EGID id) : base(id) { - if (!BlockEngine.GetBlockInfoExists(this.Id)) - { - throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); - } } - public MusicBlock(uint id) : base(id) + public MusicBlock(uint id) : base(new EGID(id, CommonExclusiveGroups.BUILD_MUSIC_BLOCK_GROUP)) { - if (!BlockEngine.GetBlockInfoExists(this.Id)) - { - throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); - } } public byte TrackIndex { get { - return BlockEngine.GetBlockInfo(Id).trackIndx; + return BlockEngine.GetBlockInfo(this, (MusicBlockDataEntityStruct st) => st.trackIndx); } set { - ref MusicBlockDataEntityStruct msdes = ref BlockEngine.GetBlockInfo(Id); - msdes.trackIndx = value; + BlockEngine.SetBlockInfo(this, + (ref MusicBlockDataEntityStruct msdes, byte val) => msdes.trackIndx = val, value); } } @@ -62,22 +42,24 @@ namespace GamecraftModdingAPI.Blocks { get { - ref MusicBlockDataEntityStruct msdes = ref BlockEngine.GetBlockInfo(Id); - return msdes.fmod2DEventPaths.Get(msdes.trackIndx); + return BlockEngine.GetBlockInfo(this, + (MusicBlockDataEntityStruct msdes) => msdes.fmod2DEventPaths.Get(msdes.trackIndx)); } set { - ref MusicBlockDataEntityStruct msdes = ref BlockEngine.GetBlockInfo(Id); - for (byte i = 0; i < msdes.fmod2DEventPaths.Count(); i++) + BlockEngine.SetBlockInfo(this, (ref MusicBlockDataEntityStruct msdes, Guid val) => { - Guid track = msdes.fmod2DEventPaths.Get(i); - if (track == value) + for (byte i = 0; i < msdes.fmod2DEventPaths.Count(); i++) { - msdes.trackIndx = i; - break; + Guid track = msdes.fmod2DEventPaths.Get(i); + if (track == val) + { + msdes.trackIndx = i; + break; + } } - } + }, value); } } @@ -85,13 +67,15 @@ namespace GamecraftModdingAPI.Blocks { get { - ref MusicBlockDataEntityStruct msdes = ref BlockEngine.GetBlockInfo(Id); - Guid[] tracks = new Guid[msdes.fmod2DEventPaths.Count()]; - for (byte i = 0; i < tracks.Length; i++) + return BlockEngine.GetBlockInfo(this, (MusicBlockDataEntityStruct msdes) => { - tracks[i] = msdes.fmod2DEventPaths.Get(i); - } - return tracks; + Guid[] tracks = new Guid[msdes.fmod2DEventPaths.Count()]; + for (byte i = 0; i < tracks.Length; i++) + { + tracks[i] = msdes.fmod2DEventPaths.Get(i); + } + return tracks; + }); } } @@ -99,13 +83,13 @@ namespace GamecraftModdingAPI.Blocks { get { - return BlockEngine.GetBlockInfo(Id).tweakableVolume; + return BlockEngine.GetBlockInfo(this, (MusicBlockDataEntityStruct msdes) => msdes.tweakableVolume); } set { - ref MusicBlockDataEntityStruct msdes = ref BlockEngine.GetBlockInfo(Id); - msdes.tweakableVolume = value; + BlockEngine.SetBlockInfo(this, + (ref MusicBlockDataEntityStruct msdes, float val) => msdes.tweakableVolume = val, value); } } @@ -113,13 +97,15 @@ namespace GamecraftModdingAPI.Blocks { get { - return (ChannelType)BlockEngine.GetBlockInfo(Id).channelType; + Assert.Log("Block exists: " + Exists); + return BlockEngine.GetBlockInfo(this, + (MusicBlockDataEntityStruct msdes) => (ChannelType) msdes.channelType); } - + set { - ref MusicBlockDataEntityStruct msdes = ref BlockEngine.GetBlockInfo(Id); - msdes.channelType = (byte)value; + BlockEngine.SetBlockInfo(this, + (ref MusicBlockDataEntityStruct msdes, ChannelType val) => msdes.channelType = (byte) val, value); } } @@ -127,30 +113,33 @@ namespace GamecraftModdingAPI.Blocks { get { - return BlockEngine.GetBlockInfo(Id).isPlaying; + return BlockEngine.GetBlockInfo(this, + (MusicBlockDataEntityStruct msdes) => msdes.isPlaying); } set { - ref MusicBlockDataEntityStruct msdes = ref BlockEngine.GetBlockInfo(Id); - if (msdes.isPlaying == value) return; - if (value) + BlockEngine.SetBlockInfo(this, (ref MusicBlockDataEntityStruct msdes, bool val) => { - // start playing - EventInstance inst = RuntimeManager.CreateInstance(msdes.fmod2DEventPaths.Get(msdes.trackIndx)); - inst.setVolume(msdes.tweakableVolume / 100f); - inst.start(); - msdes.eventHandle = inst.handle; - } - else - { - // stop playing - EventInstance inst = default(EventInstance); - inst.handle = msdes.eventHandle; - inst.stop(FMOD.Studio.STOP_MODE.ALLOWFADEOUT); - inst.release(); - } - msdes.isPlaying = value; + if (msdes.isPlaying == val) return; + if (val) + { + // start playing + EventInstance inst = RuntimeManager.CreateInstance(msdes.fmod2DEventPaths.Get(msdes.trackIndx)); + inst.setVolume(msdes.tweakableVolume / 100f); + inst.start(); + msdes.eventHandle = inst.handle; + } + else + { + // stop playing + EventInstance inst = default(EventInstance); + inst.handle = msdes.eventHandle; + inst.stop(FMOD.Studio.STOP_MODE.ALLOWFADEOUT); + inst.release(); + } + msdes.isPlaying = val; + }, value); } } } From b81562ea58229dc41837b104abdbc00c6cc816b0 Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Sat, 25 Jul 2020 12:12:48 -0400 Subject: [PATCH 23/34] Fix sfx block test default value --- GamecraftModdingAPI/Blocks/BlockTests.cs | 2 +- GamecraftModdingAPI/GamecraftModdingAPI.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/GamecraftModdingAPI/Blocks/BlockTests.cs b/GamecraftModdingAPI/Blocks/BlockTests.cs index 6186a1d..19ad7e6 100644 --- a/GamecraftModdingAPI/Blocks/BlockTests.cs +++ b/GamecraftModdingAPI/Blocks/BlockTests.cs @@ -96,7 +96,7 @@ namespace GamecraftModdingAPI.Blocks if (!Assert.NotNull(b, "Block.Specialize() returned null, possibly because it failed silently.", "Specialized MusicBlock is not null.")) return; b.IsPlaying = true; // play sfx if (!Assert.Equal(b.IsPlaying, true, $"MusicBlock.IsPlaying {b.IsPlaying} does not equal true, possibly because it failed silently.", "MusicBlock.IsPlaying is set properly.")) return; - if (!Assert.Equal(b.ChannelType, ChannelType.Character, $"MusicBlock.ChannelType {b.ChannelType} does not equal default value, possibly because it failed silently.", "MusicBlock.ChannelType is equal to default.")) return; + if (!Assert.Equal(b.ChannelType, ChannelType.None, $"MusicBlock.ChannelType {b.ChannelType} does not equal default value, possibly because it failed silently.", "MusicBlock.ChannelType is equal to default.")) return; //Assert.Log(b.Track.ToString()); if (!Assert.Equal(b.Track.ToString(), new Guid("3237ff8f-f5f2-4f84-8144-496ca280f8c0").ToString(), $"MusicBlock.Track {b.Track} does not equal default value, possibly because it failed silently.", "MusicBlock.Track is equal to default.")) return; } diff --git a/GamecraftModdingAPI/GamecraftModdingAPI.csproj b/GamecraftModdingAPI/GamecraftModdingAPI.csproj index 29cc08f..a7c108a 100644 --- a/GamecraftModdingAPI/GamecraftModdingAPI.csproj +++ b/GamecraftModdingAPI/GamecraftModdingAPI.csproj @@ -2,7 +2,7 @@ net472 true - 1.3.0 + 1.4.0 Exmods GNU General Public Licence 3+ https://git.exmods.org/modtainers/GamecraftModdingAPI From ca0e6e089d489e3bc9a16c04376b3ea9e35a80c3 Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Sun, 2 Aug 2020 22:39:26 -0400 Subject: [PATCH 24/34] Mark old event system as deprecated --- .../Events/DeterministicStepComposeEngineGroupsPatch.cs | 3 ++- GamecraftModdingAPI/Events/EmitterBuilder.cs | 1 + GamecraftModdingAPI/Events/EventEngineFactory.cs | 1 + GamecraftModdingAPI/Events/EventManager.cs | 1 + GamecraftModdingAPI/Events/GameActivatedComposePatch.cs | 1 + GamecraftModdingAPI/Events/GameReloadedPatch.cs | 1 + GamecraftModdingAPI/Events/GameStateBuildEmitterEngine.cs | 1 + .../Events/GameStateSimulationEmitterEngine.cs | 1 + GamecraftModdingAPI/Events/GameSwitchedToPatch.cs | 1 + GamecraftModdingAPI/Events/HandlerBuilder.cs | 1 + GamecraftModdingAPI/Events/IEventEmitterEngine.cs | 1 + GamecraftModdingAPI/Events/IEventHandlerEngine.cs | 1 + GamecraftModdingAPI/Events/MenuActivatedPatch.cs | 1 + GamecraftModdingAPI/Events/MenuSwitchedToPatch.cs | 1 + GamecraftModdingAPI/Events/SimpleEventEmitterEngine.cs | 1 + GamecraftModdingAPI/Events/SimpleEventHandlerEngine.cs | 1 + GamecraftModdingAPI/Utility/VersionTracking.cs | 4 ++++ 17 files changed, 21 insertions(+), 1 deletion(-) diff --git a/GamecraftModdingAPI/Events/DeterministicStepComposeEngineGroupsPatch.cs b/GamecraftModdingAPI/Events/DeterministicStepComposeEngineGroupsPatch.cs index d6e58dc..9f16955 100644 --- a/GamecraftModdingAPI/Events/DeterministicStepComposeEngineGroupsPatch.cs +++ b/GamecraftModdingAPI/Events/DeterministicStepComposeEngineGroupsPatch.cs @@ -18,7 +18,8 @@ namespace GamecraftModdingAPI.Events /// Patch of RobocraftX.StateSync.DeterministicStepCompositionRoot.ComposeEnginesGroups(...) /// //[HarmonyPatch(typeof(DeterministicStepCompositionRoot), "DeterministicCompose")] - [HarmonyPatch] + [Obsolete] + [HarmonyPatch] class GameHostTransitionDeterministicGroupEnginePatch { diff --git a/GamecraftModdingAPI/Events/EmitterBuilder.cs b/GamecraftModdingAPI/Events/EmitterBuilder.cs index 48a6cba..c6a6879 100644 --- a/GamecraftModdingAPI/Events/EmitterBuilder.cs +++ b/GamecraftModdingAPI/Events/EmitterBuilder.cs @@ -4,6 +4,7 @@ using Svelto.ECS; namespace GamecraftModdingAPI.Events { + [Obsolete] public class EmitterBuilder { private string name; diff --git a/GamecraftModdingAPI/Events/EventEngineFactory.cs b/GamecraftModdingAPI/Events/EventEngineFactory.cs index f79dfca..7981303 100644 --- a/GamecraftModdingAPI/Events/EventEngineFactory.cs +++ b/GamecraftModdingAPI/Events/EventEngineFactory.cs @@ -11,6 +11,7 @@ namespace GamecraftModdingAPI.Events /// /// Convenient factories for mod event engines /// + [Obsolete] public static class EventEngineFactory { /// diff --git a/GamecraftModdingAPI/Events/EventManager.cs b/GamecraftModdingAPI/Events/EventManager.cs index efbf377..a1c757e 100644 --- a/GamecraftModdingAPI/Events/EventManager.cs +++ b/GamecraftModdingAPI/Events/EventManager.cs @@ -14,6 +14,7 @@ namespace GamecraftModdingAPI.Events /// Keeps track of event handlers and emitters. /// This is used to add, remove and get API event handlers and emitters. /// + [Obsolete] public static class EventManager { private static Dictionary _eventEmitters = new Dictionary(); diff --git a/GamecraftModdingAPI/Events/GameActivatedComposePatch.cs b/GamecraftModdingAPI/Events/GameActivatedComposePatch.cs index 4481f4b..4142fb3 100644 --- a/GamecraftModdingAPI/Events/GameActivatedComposePatch.cs +++ b/GamecraftModdingAPI/Events/GameActivatedComposePatch.cs @@ -17,6 +17,7 @@ namespace GamecraftModdingAPI.Events /// /// Patch of RobocraftX.FullGameCompositionRoot.ActivateGame() /// + [Obsolete] [HarmonyPatch] class GameActivatedComposePatch { diff --git a/GamecraftModdingAPI/Events/GameReloadedPatch.cs b/GamecraftModdingAPI/Events/GameReloadedPatch.cs index 40f46e1..7228084 100644 --- a/GamecraftModdingAPI/Events/GameReloadedPatch.cs +++ b/GamecraftModdingAPI/Events/GameReloadedPatch.cs @@ -14,6 +14,7 @@ namespace GamecraftModdingAPI.Events /// /// Patch of RobocraftX.FullGameCompositionRoot.ReloadGame() /// + [Obsolete] [HarmonyPatch(typeof(FullGameCompositionRoot), "ReloadGame")] class GameReloadedPatch { diff --git a/GamecraftModdingAPI/Events/GameStateBuildEmitterEngine.cs b/GamecraftModdingAPI/Events/GameStateBuildEmitterEngine.cs index a12433a..725f544 100644 --- a/GamecraftModdingAPI/Events/GameStateBuildEmitterEngine.cs +++ b/GamecraftModdingAPI/Events/GameStateBuildEmitterEngine.cs @@ -12,6 +12,7 @@ namespace GamecraftModdingAPI.Events /// /// Event emitter engine for switching to to build mode. /// + [Obsolete] public class GameStateBuildEmitterEngine : IEventEmitterEngine, IUnorderedInitializeOnTimeStoppedModeEntered { public string Name { get; } = "GamecraftModdingAPIGameStateBuildEventEmitter" ; diff --git a/GamecraftModdingAPI/Events/GameStateSimulationEmitterEngine.cs b/GamecraftModdingAPI/Events/GameStateSimulationEmitterEngine.cs index 5689db9..6e6e2ce 100644 --- a/GamecraftModdingAPI/Events/GameStateSimulationEmitterEngine.cs +++ b/GamecraftModdingAPI/Events/GameStateSimulationEmitterEngine.cs @@ -12,6 +12,7 @@ namespace GamecraftModdingAPI.Events /// /// Event emitter engine for switching to simulation mode. /// + [Obsolete] public class GameStateSimulationEmitterEngine : IEventEmitterEngine, IUnorderedInitializeOnTimeRunningModeEntered { public string Name { get; } = "GamecraftModdingAPIGameStateSimulationEventEmitter" ; diff --git a/GamecraftModdingAPI/Events/GameSwitchedToPatch.cs b/GamecraftModdingAPI/Events/GameSwitchedToPatch.cs index 30bb0d5..dbd63c0 100644 --- a/GamecraftModdingAPI/Events/GameSwitchedToPatch.cs +++ b/GamecraftModdingAPI/Events/GameSwitchedToPatch.cs @@ -18,6 +18,7 @@ namespace GamecraftModdingAPI.Events /// Patch of RobocraftX.FullGameCompositionRoot.ActivateGame() /// (scheduled for execution during RobocraftX.FullGameCompositionRoot.SwitchToGame()) /// + [Obsolete] [HarmonyPatch(typeof(FullGameCompositionRoot), "SwitchToGame")] class GameSwitchedToPatch { diff --git a/GamecraftModdingAPI/Events/HandlerBuilder.cs b/GamecraftModdingAPI/Events/HandlerBuilder.cs index d5d9879..10f3290 100644 --- a/GamecraftModdingAPI/Events/HandlerBuilder.cs +++ b/GamecraftModdingAPI/Events/HandlerBuilder.cs @@ -4,6 +4,7 @@ using Svelto.ECS; namespace GamecraftModdingAPI.Events { + [Obsolete] public class HandlerBuilder { private string name; diff --git a/GamecraftModdingAPI/Events/IEventEmitterEngine.cs b/GamecraftModdingAPI/Events/IEventEmitterEngine.cs index f6fefc5..8917cef 100644 --- a/GamecraftModdingAPI/Events/IEventEmitterEngine.cs +++ b/GamecraftModdingAPI/Events/IEventEmitterEngine.cs @@ -13,6 +13,7 @@ namespace GamecraftModdingAPI.Events /// /// Engine interface to create a ModEventEntityStruct in entitiesDB when a specific event occurs. /// + [Obsolete] public interface IEventEmitterEngine : IFactoryEngine { /// diff --git a/GamecraftModdingAPI/Events/IEventHandlerEngine.cs b/GamecraftModdingAPI/Events/IEventHandlerEngine.cs index 34a14af..228adb8 100644 --- a/GamecraftModdingAPI/Events/IEventHandlerEngine.cs +++ b/GamecraftModdingAPI/Events/IEventHandlerEngine.cs @@ -14,6 +14,7 @@ namespace GamecraftModdingAPI.Events /// /// Engine interface to handle ModEventEntityStruct events emitted by IEventEmitterEngines. /// + [Obsolete] public interface IEventHandlerEngine : IReactionaryEngine { } diff --git a/GamecraftModdingAPI/Events/MenuActivatedPatch.cs b/GamecraftModdingAPI/Events/MenuActivatedPatch.cs index 4237faa..382bac4 100644 --- a/GamecraftModdingAPI/Events/MenuActivatedPatch.cs +++ b/GamecraftModdingAPI/Events/MenuActivatedPatch.cs @@ -15,6 +15,7 @@ namespace GamecraftModdingAPI.Events /// /// Patch of RobocraftX.FullGameCompositionRoot.ActivateMenu() /// + [Obsolete] [HarmonyPatch(typeof(FullGameCompositionRoot), "ActivateMenu")] class MenuActivatedPatch { diff --git a/GamecraftModdingAPI/Events/MenuSwitchedToPatch.cs b/GamecraftModdingAPI/Events/MenuSwitchedToPatch.cs index 52a00b2..30b84da 100644 --- a/GamecraftModdingAPI/Events/MenuSwitchedToPatch.cs +++ b/GamecraftModdingAPI/Events/MenuSwitchedToPatch.cs @@ -15,6 +15,7 @@ namespace GamecraftModdingAPI.Events /// /// Patch of RobocraftX.FullGameCompositionRoot.SwitchToMenu() /// + [Obsolete] [HarmonyPatch(typeof(FullGameCompositionRoot), "SwitchToMenu")] class MenuSwitchedToPatch { diff --git a/GamecraftModdingAPI/Events/SimpleEventEmitterEngine.cs b/GamecraftModdingAPI/Events/SimpleEventEmitterEngine.cs index 0e51823..0ea8170 100644 --- a/GamecraftModdingAPI/Events/SimpleEventEmitterEngine.cs +++ b/GamecraftModdingAPI/Events/SimpleEventEmitterEngine.cs @@ -12,6 +12,7 @@ namespace GamecraftModdingAPI.Events /// /// A simple implementation of IEventEmitterEngine sufficient for most uses /// + [Obsolete] public class SimpleEventEmitterEngine : IEventEmitterEngine { public string Name { get; set; } diff --git a/GamecraftModdingAPI/Events/SimpleEventHandlerEngine.cs b/GamecraftModdingAPI/Events/SimpleEventHandlerEngine.cs index 18314d9..ebce21d 100644 --- a/GamecraftModdingAPI/Events/SimpleEventHandlerEngine.cs +++ b/GamecraftModdingAPI/Events/SimpleEventHandlerEngine.cs @@ -13,6 +13,7 @@ namespace GamecraftModdingAPI.Events /// /// A simple implementation of IEventHandlerEngine sufficient for most uses /// + [Obsolete] public class SimpleEventHandlerEngine : IEventHandlerEngine { public int type { get; set; } diff --git a/GamecraftModdingAPI/Utility/VersionTracking.cs b/GamecraftModdingAPI/Utility/VersionTracking.cs index 780ac38..32b86dc 100644 --- a/GamecraftModdingAPI/Utility/VersionTracking.cs +++ b/GamecraftModdingAPI/Utility/VersionTracking.cs @@ -14,6 +14,7 @@ namespace GamecraftModdingAPI.Utility /// Tracks the API version the current game was built for. /// For compatibility reasons, this must be enabled before it will work. /// + [Obsolete] public static class VersionTracking { private static readonly VersionTrackingEngine versionEngine = new VersionTrackingEngine(); @@ -58,6 +59,7 @@ namespace GamecraftModdingAPI.Utility } + [Obsolete] internal class VersionTrackingEngine : IEventEmitterEngine { public string Name { get; } = "GamecraftModdingAPIVersionTrackingGameEngine"; @@ -94,11 +96,13 @@ namespace GamecraftModdingAPI.Utility public void Emit() { } } + [Obsolete] public struct ModVersionStruct : IEntityComponent { public uint version; } + [Obsolete] public class ModVersionDescriptor: SerializableEntityDescriptor { [HashName("GamecraftModdingAPIVersionV0")] From 708dbdd81d99bb6c9e8986d78fd252e82e0754de Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Mon, 3 Aug 2020 12:45:38 -0400 Subject: [PATCH 25/34] Add wiring API and improve signal support --- GamecraftModdingAPI/Block.cs | 3 + GamecraftModdingAPI/Blocks/BlockExceptions.cs | 22 ++ GamecraftModdingAPI/Blocks/BlockTests.cs | 19 + GamecraftModdingAPI/Blocks/LogicGate.cs | 16 + GamecraftModdingAPI/Blocks/SignalEngine.cs | 203 ++++++++++- GamecraftModdingAPI/Blocks/SignalingBlock.cs | 94 ++++- GamecraftModdingAPI/Blocks/Wire.cs | 338 ++++++++++++++++++ GamecraftModdingAPI/Events/EventManager.cs | 2 +- .../GamecraftModdingAPI.csproj | 2 +- GamecraftModdingAPI/Main.cs | 5 +- .../Tests/GamecraftModdingAPIPluginTest.cs | 16 +- GamecraftModdingAPI/Tests/TestRoot.cs | 2 +- doxygen.conf | 2 +- 13 files changed, 706 insertions(+), 18 deletions(-) create mode 100644 GamecraftModdingAPI/Blocks/LogicGate.cs create mode 100644 GamecraftModdingAPI/Blocks/Wire.cs diff --git a/GamecraftModdingAPI/Block.cs b/GamecraftModdingAPI/Block.cs index 2f9a901..0194bae 100644 --- a/GamecraftModdingAPI/Block.cs +++ b/GamecraftModdingAPI/Block.cs @@ -122,6 +122,7 @@ namespace GamecraftModdingAPI new Dictionary { {typeof(ConsoleBlock), new[] {CommonExclusiveGroups.BUILD_CONSOLE_BLOCK_GROUP}}, + {typeof(LogicGate), new [] {CommonExclusiveGroups.BUILD_LOGIC_BLOCK_GROUP}}, {typeof(Motor), new[] {CommonExclusiveGroups.BUILD_MOTOR_BLOCK_GROUP}}, {typeof(MusicBlock), new[] {CommonExclusiveGroups.BUILD_MUSIC_BLOCK_GROUP}}, {typeof(Piston), new[] {CommonExclusiveGroups.BUILD_PISTON_BLOCK_GROUP}}, @@ -420,6 +421,8 @@ namespace GamecraftModdingAPI GameEngineManager.AddGameEngine(BlockEngine); GameEngineManager.AddGameEngine(BlockEventsEngine); GameEngineManager.AddGameEngine(ScalingEngine); + GameEngineManager.AddGameEngine(SignalEngine); + Wire.signalEngine = SignalEngine; // requires same functionality, no need to duplicate the engine } /// diff --git a/GamecraftModdingAPI/Blocks/BlockExceptions.cs b/GamecraftModdingAPI/Blocks/BlockExceptions.cs index 47af014..9949424 100644 --- a/GamecraftModdingAPI/Blocks/BlockExceptions.cs +++ b/GamecraftModdingAPI/Blocks/BlockExceptions.cs @@ -40,4 +40,26 @@ namespace GamecraftModdingAPI.Blocks { } } + + public class WiringException : BlockException + { + public WiringException() + { + } + + public WiringException(string message) : base(message) + { + } + } + + public class WireInvalidException : WiringException + { + public WireInvalidException() + { + } + + public WireInvalidException(string message) : base(message) + { + } + } } diff --git a/GamecraftModdingAPI/Blocks/BlockTests.cs b/GamecraftModdingAPI/Blocks/BlockTests.cs index 19ad7e6..5447f6c 100644 --- a/GamecraftModdingAPI/Blocks/BlockTests.cs +++ b/GamecraftModdingAPI/Blocks/BlockTests.cs @@ -4,6 +4,7 @@ using Gamecraft.Wires; using GamecraftModdingAPI; using GamecraftModdingAPI.Tests; +using GamecraftModdingAPI.Utility; namespace GamecraftModdingAPI.Blocks { @@ -100,6 +101,24 @@ namespace GamecraftModdingAPI.Blocks //Assert.Log(b.Track.ToString()); if (!Assert.Equal(b.Track.ToString(), new Guid("3237ff8f-f5f2-4f84-8144-496ca280f8c0").ToString(), $"MusicBlock.Track {b.Track} does not equal default value, possibly because it failed silently.", "MusicBlock.Track is equal to default.")) return; } + + [APITestCase(TestType.EditMode)] + public static void TestLogicGate() + { + Block newBlock = Block.PlaceNew(BlockIDs.NOTLogicBlock, Unity.Mathematics.float3.zero + 1); + LogicGate b = null; // Note: the assignment operation is a lambda, which slightly confuses the compiler + Assert.Errorless(() => { b = newBlock.Specialise(); }, "Block.Specialize() raised an exception: ", "Block.Specialize() completed without issue."); + if (!Assert.NotNull(b, "Block.Specialize() returned null, possibly because it failed silently.", "Specialized LogicGate is not null.")) return; + if (!Assert.Equal(b.InputCount, 1u, $"LogicGate.InputCount {b.InputCount} does not equal default value, possibly because it failed silently.", "LogicGate.InputCount is default.")) return; + if (!Assert.Equal(b.OutputCount, 1u, $"LogicGate.OutputCount {b.OutputCount} does not equal default value, possibly because it failed silently.", "LogicGate.OutputCount is default.")) return; + if (!Assert.NotNull(b, "Block.Specialize() returned null, possibly because it failed silently.", "Specialized LogicGate is not null.")) return; + //if (!Assert.Equal(b.PortName(0, true), "Input", $"LogicGate.PortName(0, input:true) {b.PortName(0, true)} does not equal default value, possibly because it failed silently.", "LogicGate.PortName(0, input:true) is close enough to default.")) return; + LogicGate target = null; + if (!Assert.Errorless(() => { target = Block.PlaceNew(BlockIDs.ANDLogicBlock, Unity.Mathematics.float3.zero + 2); })) return; + Wire newWire = null; + if (!Assert.Errorless(() => { newWire = b.Connect(0, target, 0);})) return; + if (!Assert.NotNull(newWire, "SignalingBlock.Connect(...) returned null, possible because it failed silently.", "SignalingBlock.Connect(...) returned a non-null value.")) return; + } } #endif } diff --git a/GamecraftModdingAPI/Blocks/LogicGate.cs b/GamecraftModdingAPI/Blocks/LogicGate.cs new file mode 100644 index 0000000..124bc10 --- /dev/null +++ b/GamecraftModdingAPI/Blocks/LogicGate.cs @@ -0,0 +1,16 @@ +using RobocraftX.Common; +using Svelto.ECS; + +namespace GamecraftModdingAPI.Blocks +{ + public class LogicGate : SignalingBlock + { + public LogicGate(EGID id) : base(id) + { + } + + public LogicGate(uint id) : base(new EGID(id, CommonExclusiveGroups.BUILD_LOGIC_BLOCK_GROUP)) + { + } + } +} \ No newline at end of file diff --git a/GamecraftModdingAPI/Blocks/SignalEngine.cs b/GamecraftModdingAPI/Blocks/SignalEngine.cs index 13a0b3b..e710e24 100644 --- a/GamecraftModdingAPI/Blocks/SignalEngine.cs +++ b/GamecraftModdingAPI/Blocks/SignalEngine.cs @@ -1,4 +1,5 @@ -using Svelto.ECS; +using System; +using Svelto.ECS; using Svelto.DataStructures; using Gamecraft.Wires; @@ -9,7 +10,7 @@ namespace GamecraftModdingAPI.Blocks /// /// Engine which executes signal actions /// - public class SignalEngine : IApiEngine + public class SignalEngine : IApiEngine, IFactoryEngine { public const float POSITIVE_HIGH = 1.0f; public const float NEGATIVE_HIGH = -1.0f; @@ -20,6 +21,8 @@ namespace GamecraftModdingAPI.Blocks public EntitiesDB entitiesDB { set; private get; } + public IEntityFactory Factory { get; set; } + public bool isRemovable => false; public bool IsInGame = false; @@ -34,7 +37,73 @@ namespace GamecraftModdingAPI.Blocks IsInGame = true; } - // implementations for Signal static class + // implementations for block wiring + + public EGID CreateNewWire(EGID startBlock, byte startPort, EGID endBlock, byte endPort) + { + EGID wireEGID = new EGID(WiresExclusiveGroups.NewWireEntityId, NamedExclusiveGroup.Group); + EntityComponentInitializer wireInitializer = Factory.BuildEntity(wireEGID); + wireInitializer.Init(new WireEntityStruct + { + sourceBlockEGID = startBlock, + sourcePortUsage = startPort, + destinationBlockEGID = endBlock, + destinationPortUsage = endPort, + }); + return wireEGID; + } + + public ref WireEntityStruct GetWire(EGID wire) + { + if (!entitiesDB.Exists(wire)) + { + throw new WiringException($"Wire {wire} does not exist"); + } + return ref entitiesDB.QueryEntity(wire); + } + + public ref PortEntityStruct GetPort(EGID port) + { + if (!entitiesDB.Exists(port)) + { + throw new WiringException($"Port {port} does not exist (yet?)"); + } + return ref entitiesDB.QueryEntity(port); + } + + public ref PortEntityStruct GetPortByOffset(BlockPortsStruct bps, byte portNumber, bool input) + { + ExclusiveGroup group = input + ? NamedExclusiveGroup.Group + : NamedExclusiveGroup.Group; + uint id = (input ? bps.firstInputID : bps.firstOutputID) + portNumber; + EGID egid = new EGID(id, group); + if (!entitiesDB.Exists(egid)) + { + throw new WiringException("Port does not exist"); + } + return ref entitiesDB.QueryEntity(egid); + } + + public ref PortEntityStruct GetPortByOffset(Block block, byte portNumber, bool input) + { + BlockPortsStruct bps = GetFromDbOrInitData(block, block.Id, out bool exists); + if (!exists) + { + throw new BlockException("Block does not exist"); + } + return ref GetPortByOffset(bps, portNumber, input); + } + + public ref T GetComponent(EGID egid) where T : struct, IEntityComponent + { + return ref entitiesDB.QueryEntity(egid); + } + + public bool Exists(EGID egid) where T : struct, IEntityComponent + { + return entitiesDB.Exists(egid); + } public bool SetSignal(EGID blockID, float signal, out uint signalID, bool input = true) { @@ -123,7 +192,7 @@ namespace GamecraftModdingAPI.Blocks return inputs; } - public EGID[] GetSignalOutputs(EGID blockID) + public EGID[] GetSignalOutputs(EGID blockID) { BlockPortsStruct ports = entitiesDB.QueryEntity(blockID); EGID[] outputs = new EGID[ports.outputCount]; @@ -134,6 +203,18 @@ namespace GamecraftModdingAPI.Blocks return outputs; } + public EGID MatchBlockInputToPort(Block block, byte portUsage, out bool exists) + { + BlockPortsStruct ports = GetFromDbOrInitData(block, block.Id, out exists); + return new EGID(ports.firstInputID + portUsage, NamedExclusiveGroup.Group); + } + + public EGID MatchBlockOutputToPort(Block block, byte portUsage, out bool exists) + { + BlockPortsStruct ports = GetFromDbOrInitData(block, block.Id, out exists); + return new EGID(ports.firstOutputID + portUsage, NamedExclusiveGroup.Group); + } + public ref WireEntityStruct MatchPortToWire(EGID portID, EGID blockID, out bool exists) { ref PortEntityStruct port = ref entitiesDB.QueryEntity(portID); @@ -152,6 +233,57 @@ namespace GamecraftModdingAPI.Blocks return ref defRef[0]; } + public ref WireEntityStruct MatchBlocksToWire(EGID startBlock, EGID endBlock, out bool exists, byte startPort = byte.MaxValue, + byte endPort = byte.MaxValue) + { + EGID[] startPorts; + if (startPort == byte.MaxValue) + { + // search all output ports on source block + startPorts = GetSignalOutputs(startBlock); + } + else + { + BlockPortsStruct ports = entitiesDB.QueryEntity(startBlock); + startPorts = new EGID[] {new EGID(ports.firstOutputID + startPort, NamedExclusiveGroup.Group) }; + } + + EGID[] endPorts; + if (startPort == byte.MaxValue) + { + // search all input ports on destination block + endPorts = GetSignalInputs(endBlock); + } + else + { + BlockPortsStruct ports = entitiesDB.QueryEntity(endBlock); + endPorts = new EGID[] {new EGID(ports.firstInputID + endPort, NamedExclusiveGroup.Group) }; + } + + EntityCollection wires = entitiesDB.QueryEntities(NamedExclusiveGroup.Group); + for (int endIndex = 0; endIndex < endPorts.Length; endIndex++) + { + PortEntityStruct endPES = entitiesDB.QueryEntity(endPorts[endIndex]); + for (int startIndex = 0; startIndex < startPorts.Length; startIndex++) + { + PortEntityStruct startPES = entitiesDB.QueryEntity(startPorts[startIndex]); + for (int w = 0; w < wires.count; w++) + { + if ((wires[w].destinationPortUsage == endPES.usage && wires[w].destinationBlockEGID == endBlock) + && (wires[w].sourcePortUsage == startPES.usage && wires[w].sourceBlockEGID == startBlock)) + { + exists = true; + return ref wires[w]; + } + } + } + } + + exists = false; + WireEntityStruct[] defRef = new WireEntityStruct[1]; + return ref defRef[0]; + } + public ref ChannelDataStruct GetChannelDataStruct(EGID portID, out bool exists) { ref PortEntityStruct port = ref entitiesDB.QueryEntity(portID); @@ -175,6 +307,69 @@ namespace GamecraftModdingAPI.Blocks return res.ToArray(); } + public EGID[] WiredToInput(EGID block, byte port) + { + WireEntityStruct[] wireEntityStructs = Search(NamedExclusiveGroup.Group, + (WireEntityStruct wes) => wes.destinationPortUsage == port && wes.destinationBlockEGID == block); + EGID[] result = new EGID[wireEntityStructs.Length]; + for (uint i = 0; i < wireEntityStructs.Length; i++) + { + result[i] = wireEntityStructs[i].ID; + } + + return result; + } + + public EGID[] WiredToOutput(EGID block, byte port) + { + WireEntityStruct[] wireEntityStructs = Search(NamedExclusiveGroup.Group, + (WireEntityStruct wes) => wes.sourcePortUsage == port && wes.sourceBlockEGID == block); + EGID[] result = new EGID[wireEntityStructs.Length]; + for (uint i = 0; i < wireEntityStructs.Length; i++) + { + result[i] = wireEntityStructs[i].ID; + } + + return result; + } + + private T[] Search(ExclusiveGroup group, Func isMatch) where T : struct, IEntityComponent + { + FasterList results = new FasterList(); + EntityCollection components = entitiesDB.QueryEntities(group); + for (uint i = 0; i < components.count; i++) + { + if (isMatch(components[i])) + { + results.Add(components[i]); + } + } + return results.ToArray(); + } + + private ref T GetFromDbOrInitData(Block block, EGID id, out bool exists) where T : struct, IEntityComponent + { + T[] defRef = new T[1]; + if (entitiesDB.Exists(id)) + { + exists = true; + return ref entitiesDB.QueryEntity(id); + } + if (block == null || block.InitData.Group == null) + { + exists = false; + return ref defRef[0]; + } + EntityComponentInitializer initializer = new EntityComponentInitializer(block.Id, block.InitData.Group); + if (initializer.Has()) + { + exists = true; + return ref initializer.Get(); + } + exists = false; + return ref defRef[0]; + } + private EntityCollection GetSignalStruct(uint signalID, out uint index, bool input = true) { ExclusiveGroup group = input diff --git a/GamecraftModdingAPI/Blocks/SignalingBlock.cs b/GamecraftModdingAPI/Blocks/SignalingBlock.cs index 149e450..a137b98 100644 --- a/GamecraftModdingAPI/Blocks/SignalingBlock.cs +++ b/GamecraftModdingAPI/Blocks/SignalingBlock.cs @@ -16,18 +16,10 @@ namespace GamecraftModdingAPI.Blocks { public SignalingBlock(EGID id) : base(id) { - if (!BlockEngine.GetBlockInfoExists(this)) - { - throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); - } } public SignalingBlock(uint id) : base(id) { - if (!BlockEngine.GetBlockInfoExists(this)) - { - throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); - } } /// @@ -85,5 +77,91 @@ namespace GamecraftModdingAPI.Blocks { get => BlockEngine.GetBlockInfo(this, (BlockPortsStruct st) => st.outputCount); } + + /// + /// Connect an output on this block to an input on another block. + /// + /// Output port number. + /// Input block. + /// Input port number. + /// The wire connection + /// The wire could not be created. + public Wire Connect(byte sourcePort, SignalingBlock destination, byte destinationPort) + { + if (sourcePort >= OutputCount) + { + throw new WiringException("Source port does not exist"); + } + + if (destinationPort >= destination.InputCount) + { + throw new WiringException("Destination port does not exist"); + } + return Wire.Connect(this, sourcePort, destination, destinationPort); + } + + /// + /// The port's name. + /// This is localized to the user's language, so this is not reliable for port identification. + /// + /// Port number. + /// Whether the port is an input (true) or an output (false). + /// The localized port name. + public string PortName(byte port, bool input) + { + BlockPortsStruct bps = BlockEngine.GetBlockInfo(this, (BlockPortsStruct a) => a); + PortEntityStruct pes = SignalEngine.GetPortByOffset(this, port, input); + return pes.portNameLocalised; + } + + /// + /// The input port's name. + /// + /// Input port number. + /// The port name, localized to the user's language. + public string InputPortName(byte port) => PortName(port, true); + + /// + /// The output port's name. + /// + /// Output port number. + /// The port name, localized to the user's language. + public string OutputPortName(byte port) => PortName(port, false); + + /// + /// All wires connected to the input port. + /// These wires will always be wired output -> input. + /// + /// Port number. + /// Wires connected to the input port. + public Wire[] ConnectedToInput(byte port) + { + if (port >= InputCount) throw new WiringException($"Port input {port} does not exist"); + EGID[] wireEgids = SignalEngine.WiredToInput(Id, port); + Wire[] wires = new Wire[wireEgids.Length]; + for (uint i = 0; i < wireEgids.Length; i++) + { + wires[i] = new Wire(wireEgids[i]); + } + return wires; + } + + /// + /// All wires connected to the output port. + /// These wires will always be wired output -> input. + /// + /// Port number. + /// Wires connected to the output port. + public Wire[] ConnectedToOutput(byte port) + { + if (port >= OutputCount) throw new WiringException($"Port output {port} does not exist"); + EGID[] wireEgids = SignalEngine.WiredToOutput(Id, port); + Wire[] wires = new Wire[wireEgids.Length]; + for (uint i = 0; i < wireEgids.Length; i++) + { + wires[i] = new Wire(wireEgids[i]); + } + return wires; + } } } diff --git a/GamecraftModdingAPI/Blocks/Wire.cs b/GamecraftModdingAPI/Blocks/Wire.cs new file mode 100644 index 0000000..9a73135 --- /dev/null +++ b/GamecraftModdingAPI/Blocks/Wire.cs @@ -0,0 +1,338 @@ +using System; + +using Gamecraft.Wires; +using Svelto.ECS; +using Svelto.ECS.Experimental; + +using GamecraftModdingAPI.Utility; + +namespace GamecraftModdingAPI.Blocks +{ + public class Wire + { + internal static SignalEngine signalEngine; + + protected EGID startPortEGID; + + protected EGID endPortEGID; + + protected EGID startBlockEGID; + + protected EGID endBlockEGID; + + protected EGID wireEGID; + + protected bool inputToOutput; + + public static Wire Connect(SignalingBlock start, byte startPort, SignalingBlock end, byte endPort) + { + EGID wireEgid = signalEngine.CreateNewWire(start.Id, startPort, end.Id, endPort); + return new Wire(start, end, startPort, endPort, wireEgid, false); + } + + /// + /// An existing wire connection ending at the specified input. + /// If multiple exist, this will return the first one found. + /// + /// Destination block. + /// Port number. + /// The wire, where the end of the wire is the block port specified, or null if does not exist. + public static Wire ConnectedToInputPort(SignalingBlock end, byte endPort) + { + EGID port = signalEngine.MatchBlockInputToPort(end, endPort, out bool exists); + if (!exists) return null; + WireEntityStruct wire = signalEngine.MatchPortToWire(port, end.Id, out exists); + if (exists) + { + return new Wire(new Block(wire.sourceBlockEGID), end, wire.sourcePortUsage, endPort); + } + return null; + } + + /// + /// An existing wire connection starting at the specified output. + /// If multiple exist, this will return the first one found. + /// + /// Source block entity ID. + /// Port number. + /// The wire, where the start of the wire is the block port specified, or null if does not exist. + public static Wire ConnectedToOutputPort(SignalingBlock start, byte startPort) + { + EGID port = signalEngine.MatchBlockOutputToPort(start, startPort, out bool exists); + if (!exists) return null; + WireEntityStruct wire = signalEngine.MatchPortToWire(port, start.Id, out exists); + if (exists) + { + return new Wire(start, new Block(wire.destinationBlockEGID), startPort, wire.destinationPortUsage); + } + return null; + } + + /// + /// Construct a wire object from an existing connection. + /// + /// Starting block ID. + /// Ending block ID. + /// Starting port number, or guess if omitted. + /// Ending port number, or guess if omitted. + /// Guessing failed or wire does not exist. + public Wire(Block start, Block end, byte startPort = Byte.MaxValue, byte endPort = Byte.MaxValue) + { + startBlockEGID = start.Id; + endBlockEGID = end.Id; + // find block ports + WireEntityStruct wire = signalEngine.MatchBlocksToWire(start.Id, end.Id, out bool exists, startPort, endPort); + if (exists) + { + wireEGID = wire.ID; + endPortEGID = signalEngine.MatchBlockInputToPort(end, wire.destinationPortUsage, out exists); + if (!exists) throw new WireInvalidException("Wire end port not found"); + startPortEGID = signalEngine.MatchBlockOutputToPort(start, wire.sourcePortUsage, out exists); + if (!exists) throw new WireInvalidException("Wire start port not found"); + inputToOutput = false; + } + else + { + // flip I/O around and try again + wire = signalEngine.MatchBlocksToWire(end.Id, start.Id, out exists, endPort, startPort); + if (exists) + { + wireEGID = wire.ID; + endPortEGID = signalEngine.MatchBlockOutputToPort(end, wire.sourcePortUsage, out exists); + if (!exists) throw new WireInvalidException("Wire end port not found"); + startPortEGID = signalEngine.MatchBlockInputToPort(start, wire.destinationPortUsage, out exists); + if (!exists) throw new WireInvalidException("Wire start port not found"); + inputToOutput = true; // end is actually the source + // NB: start and end are handled exactly as they're received as params. + // This makes wire traversal easier, but makes logic in this class a bit more complex + } + else + { + throw new WireInvalidException("Wire not found"); + } + } + } + + /// + /// Construct a wire object from an existing wire connection. + /// + /// Starting block ID. + /// Ending block ID. + /// Starting port number. + /// Ending port number. + /// The wire ID. + /// Whether the wire direction goes input -> output (true) or output -> input (false, preferred). + public Wire(Block start, Block end, byte startPort, byte endPort, EGID wire, bool inputToOutput) + { + this.startBlockEGID = start.Id; + this.endBlockEGID = end.Id; + this.inputToOutput = inputToOutput; + this.wireEGID = wire; + if (inputToOutput) + { + endPortEGID = signalEngine.MatchBlockOutputToPort(start, startPort, out bool exists); + if (!exists) throw new WireInvalidException("Wire end port not found"); + startPortEGID = signalEngine.MatchBlockInputToPort(end, endPort, out exists); + if (!exists) throw new WireInvalidException("Wire start port not found"); + } + else + { + endPortEGID = signalEngine.MatchBlockInputToPort(end, endPort, out bool exists); + if (!exists) throw new WireInvalidException("Wire end port not found"); + startPortEGID = signalEngine.MatchBlockOutputToPort(start, startPort, out exists); + if (!exists) throw new WireInvalidException("Wire start port not found"); + } + } + + /// + /// Construct a wire object from an existing wire connection. + /// + /// The wire ID. + public Wire(EGID wireEgid) + { + this.wireEGID = wireEgid; + WireEntityStruct wire = signalEngine.GetWire(wireEGID); + this.startBlockEGID = wire.sourceBlockEGID; + this.endBlockEGID = wire.destinationBlockEGID; + this.inputToOutput = false; + } + + /// + /// The wire's in-game id. + /// + public EGID Id + { + get => wireEGID; + } + + /// + /// The wire's signal value, as a float. + /// + public float Float + { + get + { + ref ChannelDataStruct cds = ref signalEngine.GetChannelDataStruct(startPortEGID, out bool exists); + if (!exists) return 0f; + return cds.valueAsFloat; + } + + set + { + ref ChannelDataStruct cds = ref signalEngine.GetChannelDataStruct(startPortEGID, out bool exists); + if (!exists) return; + cds.valueAsFloat = value; + } + } + + /// + /// The wire's string signal. + /// + public string String + { + get + { + ref ChannelDataStruct cds = ref signalEngine.GetChannelDataStruct(startPortEGID, out bool exists); + if (!exists) return ""; + return cds.valueAsEcsString; + } + + set + { + ref ChannelDataStruct cds = ref signalEngine.GetChannelDataStruct(startPortEGID, out bool exists); + if (!exists) return; + cds.valueAsEcsString.Set(value); + } + } + + /// + /// The wire's raw string signal. + /// + public ECSString ECSString + { + get + { + ref ChannelDataStruct cds = ref signalEngine.GetChannelDataStruct(startPortEGID, out bool exists); + if (!exists) return default; + return cds.valueAsEcsString; + } + + set + { + ref ChannelDataStruct cds = ref signalEngine.GetChannelDataStruct(startPortEGID, out bool exists); + if (!exists) return; + cds.valueAsEcsString = value; + } + } + + /// + /// The wire's signal id. + /// I'm 50% sure this is useless. + /// + public uint SignalId + { + get + { + ref ChannelDataStruct cds = ref signalEngine.GetChannelDataStruct(startPortEGID, out bool exists); + if (!exists) return uint.MaxValue; + return cds.valueAsID; + } + + set + { + ref ChannelDataStruct cds = ref signalEngine.GetChannelDataStruct(startPortEGID, out bool exists); + if (!exists) return; + cds.valueAsID = value; + } + } + + /// + /// The block at the beginning of the wire. + /// + public SignalingBlock Start + { + get => new SignalingBlock(startBlockEGID); + } + + /// + /// The port number that the beginning of the wire connects to. + /// + public byte StartPort + { + get + { + WireEntityStruct wire = signalEngine.GetWire(wireEGID); + if (inputToOutput) + { + return wire.destinationPortUsage; + } + return wire.sourcePortUsage; + } + } + + /// + /// The block at the end of the wire. + /// + public SignalingBlock End + { + get => new SignalingBlock(endBlockEGID); + } + + /// + /// The port number that the end of the wire connects to. + /// + public byte EndPort + { + get + { + WireEntityStruct wire = signalEngine.GetWire(wireEGID); + if (inputToOutput) + { + return wire.sourcePortUsage; + } + return wire.destinationPortUsage; + } + } + + /// + /// Create a copy of the wire object where the direction of the wire is guaranteed to be from a block output to a block input. + /// This is simply a different memory configuration and does not affect the in-game wire (which is always output -> input). + /// + /// A copy of the wire object. + public Wire OutputToInputCopy() + { + return new Wire(wireEGID); + } + + /// + /// Convert the wire object to the direction the signal flows. + /// Signals on wires always flows from a block output port to a block input port. + /// This is simply a different memory configuration and does not affect the in-game wire (which is always output -> input). + /// + public void OutputToInputInPlace() + { + if (inputToOutput) + { + inputToOutput = false; + // swap inputs and outputs + EGID temp = endBlockEGID; + endBlockEGID = startBlockEGID; + startBlockEGID = temp; + temp = endPortEGID; + endPortEGID = startPortEGID; + startPortEGID = temp; + } + } + + public override string ToString() + { + if (signalEngine.Exists(wireEGID)) + { + return $"{nameof(Id)}: {Id}, Start{nameof(Start.Id)}: {Start.Id}, End{nameof(Id)}: {End.Id}, ({Start.Type}::{StartPort} aka {Start.PortName(StartPort, inputToOutput)}) -> ({End.Type}::{EndPort} aka {End.PortName(EndPort, !inputToOutput)})"; + } + return $"{nameof(Id)}: {Id}, Start{nameof(Start.Id)}: {Start.Id}, End{nameof(Id)}: {End.Id}, ({Start.Type}::{StartPort}) -> ({End.Type}::{EndPort})"; + } + + internal static void Init() { } + } +} \ No newline at end of file diff --git a/GamecraftModdingAPI/Events/EventManager.cs b/GamecraftModdingAPI/Events/EventManager.cs index a1c757e..f021e9f 100644 --- a/GamecraftModdingAPI/Events/EventManager.cs +++ b/GamecraftModdingAPI/Events/EventManager.cs @@ -14,7 +14,7 @@ namespace GamecraftModdingAPI.Events /// Keeps track of event handlers and emitters. /// This is used to add, remove and get API event handlers and emitters. /// - [Obsolete] + [Obsolete("This will be removed in an upcoming update. Use the new C# event architecture from GamecraftModdingAPI.App")] public static class EventManager { private static Dictionary _eventEmitters = new Dictionary(); diff --git a/GamecraftModdingAPI/GamecraftModdingAPI.csproj b/GamecraftModdingAPI/GamecraftModdingAPI.csproj index a7c108a..32c780b 100644 --- a/GamecraftModdingAPI/GamecraftModdingAPI.csproj +++ b/GamecraftModdingAPI/GamecraftModdingAPI.csproj @@ -2,7 +2,7 @@ net472 true - 1.4.0 + 1.5.0 Exmods GNU General Public Licence 3+ https://git.exmods.org/modtainers/GamecraftModdingAPI diff --git a/GamecraftModdingAPI/Main.cs b/GamecraftModdingAPI/Main.cs index aa80e2a..4a8cf24 100644 --- a/GamecraftModdingAPI/Main.cs +++ b/GamecraftModdingAPI/Main.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using System.Reflection; - +using GamecraftModdingAPI.Blocks; using HarmonyLib; using GamecraftModdingAPI.Utility; @@ -49,6 +49,7 @@ namespace GamecraftModdingAPI harmony.PatchAll(currentAssembly); // init utility Logging.MetaDebugLog($"Initializing Utility"); +#pragma warning disable 0612,0618 Utility.GameState.Init(); Utility.VersionTracking.Init(); // create default event emitters @@ -61,6 +62,7 @@ namespace GamecraftModdingAPI EventManager.AddEventEmitter(new SimpleEventEmitterEngine(EventType.GameSwitchedTo, "GamecraftModdingAPIGameSwitchedToEventEmitter", false)); EventManager.AddEventEmitter(GameHostTransitionDeterministicGroupEnginePatch.buildEngine); EventManager.AddEventEmitter(GameHostTransitionDeterministicGroupEnginePatch.simEngine); +#pragma warning restore 0612,0618 // init block implementors Logging.MetaDebugLog($"Initializing Blocks"); // init inventory @@ -70,6 +72,7 @@ namespace GamecraftModdingAPI // init object-oriented classes Player.Init(); Block.Init(); + Wire.Init(); GameClient.Init(); AsyncUtils.Init(); GamecraftModdingAPI.App.Client.Init(); diff --git a/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs b/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs index d8b50fa..639125c 100644 --- a/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs +++ b/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs @@ -68,6 +68,7 @@ namespace GamecraftModdingAPI.Tests //Utility.VersionTracking.Enable();//(very) unstable // debug/test handlers +#pragma warning disable 0612 HandlerBuilder.Builder() .Name("appinit API debug") .Handle(EventType.ApplicationInitialized) @@ -115,7 +116,7 @@ namespace GamecraftModdingAPI.Tests .Handle(EventType.Menu) .OnActivation(() => { throw new Exception("Event Handler always throws an exception!"); }) .Build(); - +#pragma warning restore 0612 /*HandlerBuilder.Builder("enter game from menu test") .Handle(EventType.Menu) .OnActivation(() => @@ -253,6 +254,19 @@ namespace GamecraftModdingAPI.Tests Logging.CommandLog($"Blocks placed in {sw.ElapsedMilliseconds} ms"); }) .Build(); + + CommandBuilder.Builder() + .Name("WireTest") + .Description("Place two blocks and then wire them together") + .Action(() => + { + LogicGate notBlock = Block.PlaceNew(BlockIDs.NOTLogicBlock, new float3(1, 2, 0)); + LogicGate andBlock = Block.PlaceNew(BlockIDs.ANDLogicBlock, new float3(2, 2, 0)); + // connect NOT Gate output to AND Gate input #2 (ports are zero-indexed, so 1 is 2nd position and 0 is 1st position) + Wire conn = notBlock.Connect(0, andBlock, 1); + Logging.CommandLog(conn.ToString()); + }) + .Build(); GameClient.SetDebugInfo("InstalledMods", InstalledMods); Block.Placed += (sender, args) => diff --git a/GamecraftModdingAPI/Tests/TestRoot.cs b/GamecraftModdingAPI/Tests/TestRoot.cs index f39169e..6acb51c 100644 --- a/GamecraftModdingAPI/Tests/TestRoot.cs +++ b/GamecraftModdingAPI/Tests/TestRoot.cs @@ -209,7 +209,7 @@ namespace GamecraftModdingAPI.Tests { Assert.Fail($"Build test '{m}' raised an exception: {e.ToString()}"); } - yield return Yield.It; + yield return Yield.It; } } } diff --git a/doxygen.conf b/doxygen.conf index d587ecd..bf447b4 100644 --- a/doxygen.conf +++ b/doxygen.conf @@ -38,7 +38,7 @@ PROJECT_NAME = "GamecraftModdingAPI" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = "v1.3.0" +PROJECT_NUMBER = "v1.5.0" # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a From e56871f5efa28420904bd8ec013a4b424186bb67 Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Mon, 3 Aug 2020 13:24:35 -0400 Subject: [PATCH 26/34] Fix wire entity queries when its not submitted yet --- GamecraftModdingAPI/Blocks/SignalEngine.cs | 29 ++++++++++++++++++++-- GamecraftModdingAPI/Blocks/Wire.cs | 24 +++++++++++++++--- 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/GamecraftModdingAPI/Blocks/SignalEngine.cs b/GamecraftModdingAPI/Blocks/SignalEngine.cs index e710e24..e961423 100644 --- a/GamecraftModdingAPI/Blocks/SignalEngine.cs +++ b/GamecraftModdingAPI/Blocks/SignalEngine.cs @@ -39,7 +39,7 @@ namespace GamecraftModdingAPI.Blocks // implementations for block wiring - public EGID CreateNewWire(EGID startBlock, byte startPort, EGID endBlock, byte endPort) + public WireEntityStruct CreateNewWire(EGID startBlock, byte startPort, EGID endBlock, byte endPort) { EGID wireEGID = new EGID(WiresExclusiveGroups.NewWireEntityId, NamedExclusiveGroup.Group); EntityComponentInitializer wireInitializer = Factory.BuildEntity(wireEGID); @@ -49,8 +49,9 @@ namespace GamecraftModdingAPI.Blocks sourcePortUsage = startPort, destinationBlockEGID = endBlock, destinationPortUsage = endPort, + ID = wireEGID }); - return wireEGID; + return wireInitializer.Get(); } public ref WireEntityStruct GetWire(EGID wire) @@ -209,11 +210,35 @@ namespace GamecraftModdingAPI.Blocks return new EGID(ports.firstInputID + portUsage, NamedExclusiveGroup.Group); } + public EGID MatchBlockInputToPort(EGID block, byte portUsage, out bool exists) + { + if (!entitiesDB.Exists(block)) + { + exists = false; + return default; + } + exists = true; + BlockPortsStruct ports = entitiesDB.QueryEntity(block); + return new EGID(ports.firstInputID + portUsage, NamedExclusiveGroup.Group); + } + public EGID MatchBlockOutputToPort(Block block, byte portUsage, out bool exists) { BlockPortsStruct ports = GetFromDbOrInitData(block, block.Id, out exists); return new EGID(ports.firstOutputID + portUsage, NamedExclusiveGroup.Group); } + + public EGID MatchBlockOutputToPort(EGID block, byte portUsage, out bool exists) + { + if (!entitiesDB.Exists(block)) + { + exists = false; + return default; + } + exists = true; + BlockPortsStruct ports = entitiesDB.QueryEntity(block); + return new EGID(ports.firstOutputID + portUsage, NamedExclusiveGroup.Group); + } public ref WireEntityStruct MatchPortToWire(EGID portID, EGID blockID, out bool exists) { diff --git a/GamecraftModdingAPI/Blocks/Wire.cs b/GamecraftModdingAPI/Blocks/Wire.cs index 9a73135..6c427f6 100644 --- a/GamecraftModdingAPI/Blocks/Wire.cs +++ b/GamecraftModdingAPI/Blocks/Wire.cs @@ -26,8 +26,8 @@ namespace GamecraftModdingAPI.Blocks public static Wire Connect(SignalingBlock start, byte startPort, SignalingBlock end, byte endPort) { - EGID wireEgid = signalEngine.CreateNewWire(start.Id, startPort, end.Id, endPort); - return new Wire(start, end, startPort, endPort, wireEgid, false); + WireEntityStruct wire = signalEngine.CreateNewWire(start.Id, startPort, end.Id, endPort); + return new Wire(wire); } /// @@ -155,6 +155,22 @@ namespace GamecraftModdingAPI.Blocks this.startBlockEGID = wire.sourceBlockEGID; this.endBlockEGID = wire.destinationBlockEGID; this.inputToOutput = false; + endPortEGID = signalEngine.MatchBlockInputToPort(wire.destinationBlockEGID, wire.destinationPortUsage, out bool exists); + if (!exists) throw new WireInvalidException("Wire end port not found"); + startPortEGID = signalEngine.MatchBlockOutputToPort(wire.sourceBlockEGID, wire.sourcePortUsage, out exists); + if (!exists) throw new WireInvalidException("Wire start port not found"); + } + + internal Wire(WireEntityStruct wire) + { + this.wireEGID = wire.ID; + this.startBlockEGID = wire.sourceBlockEGID; + this.endBlockEGID = wire.destinationBlockEGID; + inputToOutput = false; + endPortEGID = signalEngine.MatchBlockInputToPort(wire.destinationBlockEGID, wire.destinationPortUsage, out bool exists); + if (!exists) throw new WireInvalidException("Wire end port not found"); + startPortEGID = signalEngine.MatchBlockOutputToPort(wire.sourceBlockEGID, wire.sourcePortUsage, out exists); + if (!exists) throw new WireInvalidException("Wire start port not found"); } /// @@ -328,9 +344,9 @@ namespace GamecraftModdingAPI.Blocks { if (signalEngine.Exists(wireEGID)) { - return $"{nameof(Id)}: {Id}, Start{nameof(Start.Id)}: {Start.Id}, End{nameof(Id)}: {End.Id}, ({Start.Type}::{StartPort} aka {Start.PortName(StartPort, inputToOutput)}) -> ({End.Type}::{EndPort} aka {End.PortName(EndPort, !inputToOutput)})"; + return $"{nameof(Id)}: {Id}, Start{nameof(Start.Id)}: {Start.Id}, End{nameof(End.Id)}: {End.Id}, ({Start.Type}::{StartPort} aka {Start.PortName(StartPort, inputToOutput)}) -> ({End.Type}::{EndPort} aka {End.PortName(EndPort, !inputToOutput)})"; } - return $"{nameof(Id)}: {Id}, Start{nameof(Start.Id)}: {Start.Id}, End{nameof(Id)}: {End.Id}, ({Start.Type}::{StartPort}) -> ({End.Type}::{EndPort})"; + return $"{nameof(Id)}: {Id}, Start{nameof(Start.Id)}: {Start.Id}, End{nameof(End.Id)}: {End.Id}, ({Start.Type} -> {End.Type})"; } internal static void Init() { } From 7f5a36cb621213d07af665f58165ac95bc272f77 Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Tue, 4 Aug 2020 15:10:07 -0400 Subject: [PATCH 27/34] Automate version bumping because I keep forgetting doxygen.conf --- Automation/bump_version.py | 67 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100755 Automation/bump_version.py diff --git a/Automation/bump_version.py b/Automation/bump_version.py new file mode 100755 index 0000000..d3de051 --- /dev/null +++ b/Automation/bump_version.py @@ -0,0 +1,67 @@ +#!/usr/bin/python3 + +import argparse +import re +# this assumes a mostly semver-complient version number + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Increment GamecraftModdingAPI version") + parser.add_argument('version', metavar="VN", type=str, help="The version number to increment, or the index of the number (zero-indexed).") + args = parser.parse_args() + + version_index = -1 + try: + version_index = int(args.version) + except Exception: + if args.version.lower() == "major": + version_index = 0 + elif args.version.lower() == "minor": + version_index = 1 + elif args.version.lower() == "patch": + version_index = 2 + + if version_index < 0: + print("Could not parse version argument.") + exit(version_index) + + print(version_index) + old_version = "" + new_version = "" + + with open("../GamecraftModdingAPI/GamecraftModdingAPI.csproj", "r") as xmlFile: + print("Parsing GamecraftModdingAPI.csproj") + fileStr = xmlFile.read() + versionMatch = re.search(r"(.+)", fileStr) + if versionMatch is None: + print("Unable to find version number in GamecraftModdingAPI.csproj") + exit(1) + old_version = versionMatch.group(1) + versionList = old_version.split(".") + if len(versionList) <= version_index: + print("Invalid version string") + exit(1) + versionList[version_index] = str(int(versionList[version_index]) + 1) + for i in range(version_index + 1, len(versionList)): + try: + int(versionList[i]) + versionList[i] = "0" + except Exception: + tmp = versionList[i].split("-") + tmp[0] = "0" + versionList[i] = "-".join(tmp) + new_version = ".".join(versionList) + print(new_version) + newFileContents = fileStr.replace(""+old_version+"", ""+new_version+"") + + with open("../GamecraftModdingAPI/GamecraftModdingAPI.csproj", "w") as xmlFile: + print("Writing new version to project file") + xmlFile.write(newFileContents) + + with open("../doxygen.conf", "r") as doxFile: + print("Parsing doxygen.conf") + doxStr = doxFile.read() + newFileContents = doxStr.replace("= \"v" + old_version + "\"", "= \"v" + new_version + "\"") + + with open("../doxygen.conf", "w") as doxFile: + print("Writing new version to doxygen config") + doxFile.write(newFileContents) From 83541231695ac99062c495c056cf25d863ed2b6d Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Fri, 7 Aug 2020 12:05:49 -0400 Subject: [PATCH 28/34] Cache additional info to avoid entity queries --- GamecraftModdingAPI/Blocks/Wire.cs | 41 +++++++++++++++--------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/GamecraftModdingAPI/Blocks/Wire.cs b/GamecraftModdingAPI/Blocks/Wire.cs index 6c427f6..c29795f 100644 --- a/GamecraftModdingAPI/Blocks/Wire.cs +++ b/GamecraftModdingAPI/Blocks/Wire.cs @@ -24,6 +24,10 @@ namespace GamecraftModdingAPI.Blocks protected bool inputToOutput; + protected byte startPort; + + protected byte endPort; + public static Wire Connect(SignalingBlock start, byte startPort, SignalingBlock end, byte endPort) { WireEntityStruct wire = signalEngine.CreateNewWire(start.Id, startPort, end.Id, endPort); @@ -90,6 +94,8 @@ namespace GamecraftModdingAPI.Blocks startPortEGID = signalEngine.MatchBlockOutputToPort(start, wire.sourcePortUsage, out exists); if (!exists) throw new WireInvalidException("Wire start port not found"); inputToOutput = false; + endPort = wire.destinationPortUsage; + startPort = wire.sourcePortUsage; } else { @@ -105,6 +111,8 @@ namespace GamecraftModdingAPI.Blocks inputToOutput = true; // end is actually the source // NB: start and end are handled exactly as they're received as params. // This makes wire traversal easier, but makes logic in this class a bit more complex + endPort = wire.sourcePortUsage; + startPort = wire.destinationPortUsage; } else { @@ -142,6 +150,8 @@ namespace GamecraftModdingAPI.Blocks startPortEGID = signalEngine.MatchBlockOutputToPort(start, startPort, out exists); if (!exists) throw new WireInvalidException("Wire start port not found"); } + this.startPort = startPort; + this.endPort = endPort; } /// @@ -159,6 +169,8 @@ namespace GamecraftModdingAPI.Blocks if (!exists) throw new WireInvalidException("Wire end port not found"); startPortEGID = signalEngine.MatchBlockOutputToPort(wire.sourceBlockEGID, wire.sourcePortUsage, out exists); if (!exists) throw new WireInvalidException("Wire start port not found"); + this.endPort = wire.destinationPortUsage; + this.startPort = wire.sourcePortUsage; } internal Wire(WireEntityStruct wire) @@ -171,6 +183,8 @@ namespace GamecraftModdingAPI.Blocks if (!exists) throw new WireInvalidException("Wire end port not found"); startPortEGID = signalEngine.MatchBlockOutputToPort(wire.sourceBlockEGID, wire.sourcePortUsage, out exists); if (!exists) throw new WireInvalidException("Wire start port not found"); + this.endPort = wire.destinationPortUsage; + this.startPort = wire.sourcePortUsage; } /// @@ -275,15 +289,7 @@ namespace GamecraftModdingAPI.Blocks /// public byte StartPort { - get - { - WireEntityStruct wire = signalEngine.GetWire(wireEGID); - if (inputToOutput) - { - return wire.destinationPortUsage; - } - return wire.sourcePortUsage; - } + get => startPort; } /// @@ -299,15 +305,7 @@ namespace GamecraftModdingAPI.Blocks /// public byte EndPort { - get - { - WireEntityStruct wire = signalEngine.GetWire(wireEGID); - if (inputToOutput) - { - return wire.sourcePortUsage; - } - return wire.destinationPortUsage; - } + get => endPort; } /// @@ -322,7 +320,7 @@ namespace GamecraftModdingAPI.Blocks /// /// Convert the wire object to the direction the signal flows. - /// Signals on wires always flows from a block output port to a block input port. + /// Signals on wires always flow from a block output port to a block input port. /// This is simply a different memory configuration and does not affect the in-game wire (which is always output -> input). /// public void OutputToInputInPlace() @@ -337,6 +335,9 @@ namespace GamecraftModdingAPI.Blocks temp = endPortEGID; endPortEGID = startPortEGID; startPortEGID = temp; + byte tempPortNumber = endPort; + endPort = startPort; + startPort = tempPortNumber; } } @@ -346,7 +347,7 @@ namespace GamecraftModdingAPI.Blocks { return $"{nameof(Id)}: {Id}, Start{nameof(Start.Id)}: {Start.Id}, End{nameof(End.Id)}: {End.Id}, ({Start.Type}::{StartPort} aka {Start.PortName(StartPort, inputToOutput)}) -> ({End.Type}::{EndPort} aka {End.PortName(EndPort, !inputToOutput)})"; } - return $"{nameof(Id)}: {Id}, Start{nameof(Start.Id)}: {Start.Id}, End{nameof(End.Id)}: {End.Id}, ({Start.Type} -> {End.Type})"; + return $"{nameof(Id)}: {Id}, Start{nameof(Start.Id)}: {Start.Id}, End{nameof(End.Id)}: {End.Id}, ({Start.Type}::{StartPort} -> {End.Type}::{EndPort})"; } internal static void Init() { } From 89f354b647d1f2fcefa8db82828318d76af3b28c Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Thu, 13 Aug 2020 10:12:36 -0400 Subject: [PATCH 29/34] Fix Game Over detection --- GamecraftModdingAPI/Players/PlayerEngine.cs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/GamecraftModdingAPI/Players/PlayerEngine.cs b/GamecraftModdingAPI/Players/PlayerEngine.cs index 805ae21..f0aa31d 100644 --- a/GamecraftModdingAPI/Players/PlayerEngine.cs +++ b/GamecraftModdingAPI/Players/PlayerEngine.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Reflection; using System.Runtime.CompilerServices; using RobocraftX.Character; @@ -12,12 +14,16 @@ using RobocraftX.Character.Camera; using RobocraftX.Character.Factories; using Gamecraft.CharacterVulnerability; using Gamecraft.CharacterVulnerability.Entities; +using Gamecraft.GUI.HUDFeedbackBlocks; using Svelto.ECS; using Unity.Mathematics; using Unity.Physics; using UnityEngine; using GamecraftModdingAPI.Engines; +using HarmonyLib; +using RobocraftX.Common; +using Svelto.ECS.DataStructures; namespace GamecraftModdingAPI.Players { @@ -365,15 +371,12 @@ namespace GamecraftModdingAPI.Players public bool GetGameOverScreen(uint playerId) { if (entitiesDB == null) return false; - ref var c = ref GetCharacterStruct(playerId, out bool exists); - if (exists) - { - return c.gameOverScreen; - } - return false; + ref HudActivatedBlocksEntityStruct habes = ref entitiesDB.QueryEntity(HUDFeedbackBlocksGUIExclusiveGroups.GameOverHudEgid); + NativeDynamicArrayCast nativeDynamicArrayCast = new NativeDynamicArrayCast(habes.activatedBlocksOrdered); + return nativeDynamicArrayCast.count > 0; } - public bool IsDead(uint playerId) + public bool IsDead(uint playerId) { if (entitiesDB == null) return true; return entitiesDB.Exists(playerId, CharacterExclusiveGroups.DeadCharacters); From fd9719490329670ea33288f754bbc5170f442273 Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Fri, 7 Aug 2020 13:55:00 -0400 Subject: [PATCH 30/34] Fix build issues for latest Gamecraft preview version --- GamecraftModdingAPI/App/GameMenuEngine.cs | 17 ++- GamecraftModdingAPI/Block.cs | 4 +- GamecraftModdingAPI/Blocks/BlockEngine.cs | 70 ++++++++++- GamecraftModdingAPI/Blocks/SignalEngine.cs | 4 +- .../GamecraftModdingAPI.csproj | 109 ++++++++++++++++++ GamecraftModdingAPI/Players/PlayerEngine.cs | 9 +- 6 files changed, 195 insertions(+), 18 deletions(-) diff --git a/GamecraftModdingAPI/App/GameMenuEngine.cs b/GamecraftModdingAPI/App/GameMenuEngine.cs index fc2c35f..74bc42a 100644 --- a/GamecraftModdingAPI/App/GameMenuEngine.cs +++ b/GamecraftModdingAPI/App/GameMenuEngine.cs @@ -10,6 +10,7 @@ using Svelto.ECS.Experimental; using GamecraftModdingAPI.Engines; using GamecraftModdingAPI.Utility; +using Svelto.DataStructures; namespace GamecraftModdingAPI.App { @@ -114,11 +115,21 @@ namespace GamecraftModdingAPI.App } public ref MyGamesSlotEntityViewStruct GetGameViewInfo(EGID id) - { - return ref GetComponent(new EGID(id.entityID, MyGamesScreenExclusiveGroups.GameSlotGuiEntities)); + { + EntityCollection entities = + entitiesDB.QueryEntities(MyGamesScreenExclusiveGroups.GameSlotGuiEntities); + for (int i = 0; i < entities.count; i++) + { + if (entities[i].ID.entityID == id.entityID) + { + return ref entities[i]; + } + } + MyGamesSlotEntityViewStruct[] defRef = new MyGamesSlotEntityViewStruct[1]; + return ref defRef[0]; } - public ref T GetComponent(EGID id) where T: struct, IEntityComponent + public ref T GetComponent(EGID id) where T: unmanaged, IEntityComponent { return ref entitiesDB.QueryEntity(id); } diff --git a/GamecraftModdingAPI/Block.cs b/GamecraftModdingAPI/Block.cs index 0194bae..c7b5d0d 100644 --- a/GamecraftModdingAPI/Block.cs +++ b/GamecraftModdingAPI/Block.cs @@ -337,10 +337,10 @@ namespace GamecraftModdingAPI /// public string Label { - get => BlockEngine.GetBlockInfo(this, (TextLabelEntityViewStruct st) => st.textLabelComponent?.text); + get => BlockEngine.GetBlockInfoViewStruct(this, (TextLabelEntityViewStruct st) => st.textLabelComponent?.text); set { - BlockEngine.SetBlockInfo(this, (ref TextLabelEntityViewStruct text, string val) => + BlockEngine.SetBlockInfoViewStruct(this, (ref TextLabelEntityViewStruct text, string val) => { if (text.textLabelComponent != null) text.textLabelComponent.text = val; }, value); diff --git a/GamecraftModdingAPI/Blocks/BlockEngine.cs b/GamecraftModdingAPI/Blocks/BlockEngine.cs index f97e405..33c4002 100644 --- a/GamecraftModdingAPI/Blocks/BlockEngine.cs +++ b/GamecraftModdingAPI/Blocks/BlockEngine.cs @@ -59,16 +59,34 @@ namespace GamecraftModdingAPI.Blocks color.paletteColour = paletteEntry.Colour; } - public ref T GetBlockInfo(EGID blockID) where T : struct, IEntityComponent + public ref T GetBlockInfo(EGID blockID) where T : unmanaged, IEntityComponent { if (entitiesDB.Exists(blockID)) return ref entitiesDB.QueryEntity(blockID); T[] structHolder = new T[1]; //Create something that can be referenced return ref structHolder[0]; //Gets a default value automatically } + + public ref T GetBlockInfoViewStruct(EGID blockID) where T : struct, INeedEGID, IEntityComponent + { + if (entitiesDB.Exists(blockID)) + { + // TODO: optimize by using EntitiesDB internal calls instead of iterating over everything + EntityCollection entities = entitiesDB.QueryEntities(blockID.groupID); + for (int i = 0; i < entities.count; i++) + { + if (entities[i].ID == blockID) + { + return ref entities[i]; + } + } + } + T[] structHolder = new T[1]; //Create something that can be referenced + return ref structHolder[0]; //Gets a default value automatically + } public U GetBlockInfo(Block block, Func getter, - U def = default) where T : struct, IEntityComponent + U def = default) where T : unmanaged, IEntityComponent { if (entitiesDB.Exists(block.Id)) return getter(entitiesDB.QueryEntity(block.Id)); @@ -78,10 +96,56 @@ namespace GamecraftModdingAPI.Blocks return getter(initializer.Get()); return def; } + + public U GetBlockInfoViewStruct(Block block, Func getter, + U def = default) where T : struct, INeedEGID, IEntityComponent + { + if (entitiesDB.Exists(block.Id)) + { + // TODO: optimize by using EntitiesDB internal calls instead of iterating over everything + EntityCollection entities = entitiesDB.QueryEntities(block.Id.groupID); + for (int i = 0; i < entities.count; i++) + { + if (entities[i].ID == block.Id) + { + return getter(entities[i]); + } + } + } + if (block.InitData.Group == null) return def; + var initializer = new EntityComponentInitializer(block.Id, block.InitData.Group); + if (initializer.Has()) + return getter(initializer.Get()); + return def; + } public delegate void Setter(ref T component, U value) where T : struct, IEntityComponent; - public void SetBlockInfo(Block block, Setter setter, U value) where T : struct, IEntityComponent + public void SetBlockInfoViewStruct(Block block, Setter setter, U value) where T : struct, INeedEGID, IEntityComponent + { + if (entitiesDB.Exists(block.Id)) + { + EntityCollection entities = entitiesDB.QueryEntities(block.Id.groupID); + for (int i = 0; i < entities.count; i++) + { + if (entities[i].ID == block.Id) + { + setter(ref entities[i], value); + return; + } + } + } + else if (block.InitData.Group != null) + { + var initializer = new EntityComponentInitializer(block.Id, block.InitData.Group); + T component = initializer.Has() ? initializer.Get() : default; + ref T structRef = ref component; + setter(ref structRef, value); + initializer.Init(structRef); + } + } + + public void SetBlockInfo(Block block, Setter setter, U value) where T : unmanaged, IEntityComponent { if (entitiesDB.Exists(block.Id)) setter(ref entitiesDB.QueryEntity(block.Id), value); diff --git a/GamecraftModdingAPI/Blocks/SignalEngine.cs b/GamecraftModdingAPI/Blocks/SignalEngine.cs index e961423..763a1a1 100644 --- a/GamecraftModdingAPI/Blocks/SignalEngine.cs +++ b/GamecraftModdingAPI/Blocks/SignalEngine.cs @@ -96,7 +96,7 @@ namespace GamecraftModdingAPI.Blocks return ref GetPortByOffset(bps, portNumber, input); } - public ref T GetComponent(EGID egid) where T : struct, IEntityComponent + public ref T GetComponent(EGID egid) where T : unmanaged, IEntityComponent { return ref entitiesDB.QueryEntity(egid); } @@ -372,7 +372,7 @@ namespace GamecraftModdingAPI.Blocks return results.ToArray(); } - private ref T GetFromDbOrInitData(Block block, EGID id, out bool exists) where T : struct, IEntityComponent + private ref T GetFromDbOrInitData(Block block, EGID id, out bool exists) where T : unmanaged, IEntityComponent { T[] defRef = new T[1]; if (entitiesDB.Exists(id)) diff --git a/GamecraftModdingAPI/GamecraftModdingAPI.csproj b/GamecraftModdingAPI/GamecraftModdingAPI.csproj index 32c780b..49a3a6a 100644 --- a/GamecraftModdingAPI/GamecraftModdingAPI.csproj +++ b/GamecraftModdingAPI/GamecraftModdingAPI.csproj @@ -22,6 +22,7 @@ +<<<<<<< HEAD @@ -55,6 +56,21 @@ ..\ref\Gamecraft_Data\Managed\Accessibility.dll ..\..\ref\Gamecraft_Data\Managed\Accessibility.dll +======= + + + + + + + + ..\ref\GamecraftPreview_Data\Managed\IllusionInjector.dll + ..\..\ref\GamecraftPreview_Data\Managed\IllusionInjector.dll + + + ..\ref\GamecraftPreview_Data\Managed\IllusionPlugin.dll + ..\..\ref\GamecraftPreview_Data\Managed\IllusionPlugin.dll +>>>>>>> 50ebf4f... Fix build issues for latest Gamecraft preview version ..\ref\Gamecraft_Data\Managed\Analytics.dll @@ -72,10 +88,13 @@ ..\ref\Gamecraft_Data\Managed\Authentication.dll ..\..\ref\Gamecraft_Data\Managed\Authentication.dll +<<<<<<< HEAD ..\ref\Gamecraft_Data\Managed\BlockEntityFactory.dll ..\..\ref\Gamecraft_Data\Managed\BlockEntityFactory.dll +======= +>>>>>>> 50ebf4f... Fix build issues for latest Gamecraft preview version ..\ref\Gamecraft_Data\Managed\Blocks.HUDFeedbackBlocks.dll ..\..\ref\Gamecraft_Data\Managed\Blocks.HUDFeedbackBlocks.dll @@ -84,6 +103,18 @@ ..\ref\Gamecraft_Data\Managed\CommandLine.dll ..\..\ref\Gamecraft_Data\Managed\CommandLine.dll + + ..\ref\GamecraftPreview_Data\Managed\CommandLineCompositionRoot.dll + ..\..\ref\GamecraftPreview_Data\Managed\CommandLineCompositionRoot.dll + + + ..\ref\GamecraftPreview_Data\Managed\ConsoleBlockComposotionRoot.dll + ..\..\ref\GamecraftPreview_Data\Managed\ConsoleBlockComposotionRoot.dll + + + ..\ref\GamecraftPreview_Data\Managed\ConsoleCommand.dll + ..\..\ref\GamecraftPreview_Data\Managed\ConsoleCommand.dll + ..\ref\Gamecraft_Data\Managed\DataLoader.dll ..\..\ref\Gamecraft_Data\Managed\DataLoader.dll @@ -108,6 +139,14 @@ ..\ref\Gamecraft_Data\Managed\Gamecraft.AudioBlocks.dll ..\..\ref\Gamecraft_Data\Managed\Gamecraft.AudioBlocks.dll + + ..\ref\GamecraftPreview_Data\Managed\Gamecraft.BlockCompositionRoot.dll + ..\..\ref\GamecraftPreview_Data\Managed\Gamecraft.BlockCompositionRoot.dll + + + ..\ref\GamecraftPreview_Data\Managed\Gamecraft.BlockEntityFactory.dll + ..\..\ref\GamecraftPreview_Data\Managed\Gamecraft.BlockEntityFactory.dll + ..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.ConsoleBlock.dll ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.ConsoleBlock.dll @@ -116,6 +155,10 @@ ..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.DamagingSurfaceBlock.dll ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.DamagingSurfaceBlock.dll + + ..\ref\GamecraftPreview_Data\Managed\Gamecraft.Blocks.DestructionBlocks.dll + ..\..\ref\GamecraftPreview_Data\Managed\Gamecraft.Blocks.DestructionBlocks.dll + ..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.GenericPhysicsBlocks.dll ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.GenericPhysicsBlocks.dll @@ -128,10 +171,18 @@ ..\ref\Gamecraft_Data\Managed\GameCraft.Blocks.ProjectileBlock.dll ..\..\ref\Gamecraft_Data\Managed\GameCraft.Blocks.ProjectileBlock.dll + + ..\ref\GamecraftPreview_Data\Managed\Gamecraft.Blocks.TextBlock.CompositionRoot.dll + ..\..\ref\GamecraftPreview_Data\Managed\Gamecraft.Blocks.TextBlock.CompositionRoot.dll + ..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.TimerBlock.dll ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.TimerBlock.dll + + ..\ref\GamecraftPreview_Data\Managed\Gamecraft.BlocksEntityDescriptors.dll + ..\..\ref\GamecraftPreview_Data\Managed\Gamecraft.BlocksEntityDescriptors.dll + ..\ref\Gamecraft_Data\Managed\Gamecraft.CharacterVulnerability.dll ..\..\ref\Gamecraft_Data\Managed\Gamecraft.CharacterVulnerability.dll @@ -140,10 +191,22 @@ ..\ref\Gamecraft_Data\Managed\Gamecraft.CharacterVulnerabilityGui.dll ..\..\ref\Gamecraft_Data\Managed\Gamecraft.CharacterVulnerabilityGui.dll + + ..\ref\GamecraftPreview_Data\Managed\Gamecraft.Damage.dll + ..\..\ref\GamecraftPreview_Data\Managed\Gamecraft.Damage.dll + ..\ref\Gamecraft_Data\Managed\Gamecraft.Effects.dll ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Effects.dll + + ..\ref\GamecraftPreview_Data\Managed\Gamecraft.ExplosionFragments.dll + ..\..\ref\GamecraftPreview_Data\Managed\Gamecraft.ExplosionFragments.dll + + + ..\ref\GamecraftPreview_Data\Managed\Gamecraft.GraphicsSettings.dll + ..\..\ref\GamecraftPreview_Data\Managed\Gamecraft.GraphicsSettings.dll + ..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.ConsoleBlock.dll ..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.ConsoleBlock.dll @@ -172,6 +235,14 @@ ..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.WorldSpaceGuis.dll ..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.WorldSpaceGuis.dll + + ..\ref\GamecraftPreview_Data\Managed\Gamecraft.InventoryTimeRunning.dll + ..\..\ref\GamecraftPreview_Data\Managed\Gamecraft.InventoryTimeRunning.dll + + + ..\ref\GamecraftPreview_Data\Managed\Gamecraft.JointBlocks.dll + ..\..\ref\GamecraftPreview_Data\Managed\Gamecraft.JointBlocks.dll + ..\ref\Gamecraft_Data\Managed\Gamecraft.Music.dll ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Music.dll @@ -180,6 +251,22 @@ ..\ref\Gamecraft_Data\Managed\Gamecraft.PerformanceWarnings.dll ..\..\ref\Gamecraft_Data\Managed\Gamecraft.PerformanceWarnings.dll + + ..\ref\GamecraftPreview_Data\Managed\Gamecraft.PickupBlck.dll + ..\..\ref\GamecraftPreview_Data\Managed\Gamecraft.PickupBlck.dll + + + ..\ref\GamecraftPreview_Data\Managed\Gamecraft.PickupsCommon.dll + ..\..\ref\GamecraftPreview_Data\Managed\Gamecraft.PickupsCommon.dll + + + ..\ref\GamecraftPreview_Data\Managed\Gamecraft.PopupMessage.dll + ..\..\ref\GamecraftPreview_Data\Managed\Gamecraft.PopupMessage.dll + + + ..\ref\GamecraftPreview_Data\Managed\Gamecraft.Projectiles.dll + ..\..\ref\GamecraftPreview_Data\Managed\Gamecraft.Projectiles.dll + ..\ref\Gamecraft_Data\Managed\Gamecraft.Tweaks.dll ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Tweaks.dll @@ -188,6 +275,10 @@ ..\ref\Gamecraft_Data\Managed\Gamecraft.Tweaks.Mockup.dll ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Tweaks.Mockup.dll + + ..\ref\GamecraftPreview_Data\Managed\Gamecraft.VisualEffects.Decals.dll + ..\..\ref\GamecraftPreview_Data\Managed\Gamecraft.VisualEffects.Decals.dll + ..\ref\Gamecraft_Data\Managed\Gamecraft.VisualEffects.dll ..\..\ref\Gamecraft_Data\Managed\Gamecraft.VisualEffects.dll @@ -196,10 +287,13 @@ ..\ref\Gamecraft_Data\Managed\Gamecraft.Wires.dll ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Wires.dll +<<<<<<< HEAD ..\ref\Gamecraft_Data\Managed\Gamecraft.Wires.Input.dll ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Wires.Input.dll +======= +>>>>>>> 50ebf4f... Fix build issues for latest Gamecraft preview version ..\ref\Gamecraft_Data\Managed\Gamecraft.Wires.Mockup.dll ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Wires.Mockup.dll @@ -424,6 +518,14 @@ ..\ref\Gamecraft_Data\Managed\RobocratX.SimulationCompositionRoot.dll ..\..\ref\Gamecraft_Data\Managed\RobocratX.SimulationCompositionRoot.dll + + ..\ref\GamecraftPreview_Data\Managed\SpawningPointCompositionRoot.dll + ..\..\ref\GamecraftPreview_Data\Managed\SpawningPointCompositionRoot.dll + + + ..\ref\GamecraftPreview_Data\Managed\SpecializedDescriptors.dll + ..\..\ref\GamecraftPreview_Data\Managed\SpecializedDescriptors.dll + ..\ref\Gamecraft_Data\Managed\StringFormatter.dll ..\..\ref\Gamecraft_Data\Managed\StringFormatter.dll @@ -444,6 +546,10 @@ ..\ref\Gamecraft_Data\Managed\Svelto.Tasks.dll ..\..\ref\Gamecraft_Data\Managed\Svelto.Tasks.dll + + ..\ref\GamecraftPreview_Data\Managed\UltimateDecals.dll + ..\..\ref\GamecraftPreview_Data\Managed\UltimateDecals.dll + ..\ref\Gamecraft_Data\Managed\Unity.Addressables.dll ..\..\ref\Gamecraft_Data\Managed\Unity.Addressables.dll @@ -816,6 +922,7 @@ ..\ref\Gamecraft_Data\Managed\UnityEngine.XRModule.dll ..\..\ref\Gamecraft_Data\Managed\UnityEngine.XRModule.dll +<<<<<<< HEAD ..\ref\Gamecraft_Data\Managed\uREPL.dll ..\..\ref\Gamecraft_Data\Managed\uREPL.dll @@ -824,6 +931,8 @@ ..\ref\Gamecraft_Data\Managed\VisualProfiler.dll ..\..\ref\Gamecraft_Data\Managed\VisualProfiler.dll +======= +>>>>>>> 50ebf4f... Fix build issues for latest Gamecraft preview version \ No newline at end of file diff --git a/GamecraftModdingAPI/Players/PlayerEngine.cs b/GamecraftModdingAPI/Players/PlayerEngine.cs index f0aa31d..948c6e9 100644 --- a/GamecraftModdingAPI/Players/PlayerEngine.cs +++ b/GamecraftModdingAPI/Players/PlayerEngine.cs @@ -288,14 +288,7 @@ namespace GamecraftModdingAPI.Players public bool DamagePlayer(uint playerId, float amount) { if (entitiesDB == null) return false; - Factory.BuildEntity( - new EGID(CharacterVulnerabilityExclusiveGroups.NextDamageEntityId, CharacterVulnerabilityExclusiveGroups.CharacterDamageExclusiveGroup) - ).Init(new DamageEntityStruct - { - damage = amount, - targetPlayerEntityId = playerId, - }); - return true; + return SetCurrentHealth(playerId, GetCurrentHealth(playerId) - amount); } public bool GetDamageable(uint playerId) From cfdc5e8c26701bd452a63b8a591cbeba1559151b Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Thu, 13 Aug 2020 16:59:13 +0200 Subject: [PATCH 31/34] Fixes, block IDs, cluster & chunk health support --- GamecraftModdingAPI/Block.cs | 2 +- GamecraftModdingAPI/Blocks/BlockEngine.cs | 91 +++++++++++-------- GamecraftModdingAPI/Blocks/BlockIDs.cs | 5 + GamecraftModdingAPI/Cluster.cs | 41 +++++++++ GamecraftModdingAPI/SimBody.cs | 37 ++++++++ .../Tests/GamecraftModdingAPIPluginTest.cs | 10 ++ .../Utility/DebugInterfaceEngine.cs | 11 ++- 7 files changed, 154 insertions(+), 43 deletions(-) create mode 100644 GamecraftModdingAPI/Cluster.cs diff --git a/GamecraftModdingAPI/Block.cs b/GamecraftModdingAPI/Block.cs index c7b5d0d..b901f81 100644 --- a/GamecraftModdingAPI/Block.cs +++ b/GamecraftModdingAPI/Block.cs @@ -372,7 +372,7 @@ namespace GamecraftModdingAPI public SimBody GetSimBody() { return BlockEngine.GetBlockInfo(this, - (GridConnectionsEntityStruct st) => new SimBody(st.machineRigidBodyId)); + (GridConnectionsEntityStruct st) => new SimBody(st.machineRigidBodyId, st.clusterId)); } private void OnPlacedInit(object sender, BlockPlacedRemovedEventArgs e) diff --git a/GamecraftModdingAPI/Blocks/BlockEngine.cs b/GamecraftModdingAPI/Blocks/BlockEngine.cs index 33c4002..2622d41 100644 --- a/GamecraftModdingAPI/Blocks/BlockEngine.cs +++ b/GamecraftModdingAPI/Blocks/BlockEngine.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using Gamecraft.Wires; using RobocraftX.Blocks; @@ -9,6 +10,7 @@ using RobocraftX.Physics; using RobocraftX.Scene.Simulation; using Svelto.DataStructures; using Svelto.ECS; +using Svelto.ECS.Hybrid; using GamecraftModdingAPI.Engines; @@ -90,28 +92,19 @@ namespace GamecraftModdingAPI.Blocks { if (entitiesDB.Exists(block.Id)) return getter(entitiesDB.QueryEntity(block.Id)); - if (block.InitData.Group == null) return def; - var initializer = new EntityComponentInitializer(block.Id, block.InitData.Group); - if (initializer.Has()) - return getter(initializer.Get()); - return def; + return GetBlockInitInfo(block, getter, def); } public U GetBlockInfoViewStruct(Block block, Func getter, - U def = default) where T : struct, INeedEGID, IEntityComponent + U def = default) where T : struct, IEntityViewComponent { if (entitiesDB.Exists(block.Id)) - { - // TODO: optimize by using EntitiesDB internal calls instead of iterating over everything - EntityCollection entities = entitiesDB.QueryEntities(block.Id.groupID); - for (int i = 0; i < entities.count; i++) - { - if (entities[i].ID == block.Id) - { - return getter(entities[i]); - } - } - } + return getter(entitiesDB.QueryEntity(block.Id)); + return GetBlockInitInfo(block, getter, def); + } + + private U GetBlockInitInfo(Block block, Func getter, U def) where T : struct, IEntityComponent + { if (block.InitData.Group == null) return def; var initializer = new EntityComponentInitializer(block.Id, block.InitData.Group); if (initializer.Has()) @@ -121,35 +114,26 @@ namespace GamecraftModdingAPI.Blocks public delegate void Setter(ref T component, U value) where T : struct, IEntityComponent; - public void SetBlockInfoViewStruct(Block block, Setter setter, U value) where T : struct, INeedEGID, IEntityComponent + public void SetBlockInfoViewStruct(Block block, Setter setter, U value) where T : struct, IEntityViewComponent { if (entitiesDB.Exists(block.Id)) - { - EntityCollection entities = entitiesDB.QueryEntities(block.Id.groupID); - for (int i = 0; i < entities.count; i++) - { - if (entities[i].ID == block.Id) - { - setter(ref entities[i], value); - return; - } - } - } - else if (block.InitData.Group != null) - { - var initializer = new EntityComponentInitializer(block.Id, block.InitData.Group); - T component = initializer.Has() ? initializer.Get() : default; - ref T structRef = ref component; - setter(ref structRef, value); - initializer.Init(structRef); - } + setter(ref entitiesDB.QueryEntity(block.Id), value); + else + SetBlockInitInfo(block, setter, value); } public void SetBlockInfo(Block block, Setter setter, U value) where T : unmanaged, IEntityComponent { if (entitiesDB.Exists(block.Id)) setter(ref entitiesDB.QueryEntity(block.Id), value); - else if (block.InitData.Group != null) + else + SetBlockInitInfo(block, setter, value); + } + + private void SetBlockInitInfo(Block block, Setter setter, U value) + where T : struct, IEntityComponent + { + if (block.InitData.Group != null) { var initializer = new EntityComponentInitializer(block.Id, block.InitData.Group); T component = initializer.Has() ? initializer.Get() : default; @@ -222,6 +206,22 @@ namespace GamecraftModdingAPI.Blocks return list.ToArray(); } + public SimBody[] GetClusterBodies(uint cid) + { + var groups = entitiesDB.QueryEntities(); + var bodies = new HashSet(); + foreach (var (coll, _) in groups) + { + foreach (var conn in coll) + { + if (conn.clusterId == cid) + bodies.Add(conn.machineRigidBodyId); + } + } + + return bodies.Select(id => new SimBody(id)).ToArray(); + } + public EGID? FindBlockEGID(uint id) { var groups = entitiesDB.FindGroups(); @@ -234,6 +234,21 @@ namespace GamecraftModdingAPI.Blocks return null; } + public Cluster GetCluster(uint sbid) + { + var groups = entitiesDB.QueryEntities(); + foreach (var (coll, _) in groups) + { + foreach (var conn in coll) + { + if (conn.machineRigidBodyId == sbid) + return new Cluster(conn.clusterId); + } + } + + return null; + } + #if DEBUG public EntitiesDB GetEntitiesDB() { diff --git a/GamecraftModdingAPI/Blocks/BlockIDs.cs b/GamecraftModdingAPI/Blocks/BlockIDs.cs index 596fb38..33f9522 100644 --- a/GamecraftModdingAPI/Blocks/BlockIDs.cs +++ b/GamecraftModdingAPI/Blocks/BlockIDs.cs @@ -192,6 +192,9 @@ namespace GamecraftModdingAPI.Blocks PlayerFilter, TeamFilter, Number2Text, //193 + DestructionManager = 260, + ChunkHealthModifier, + ClusterHealthModifier, //262 BeachTree1 = 200, BeachTree2, BeachTree3, @@ -243,6 +246,8 @@ namespace GamecraftModdingAPI.Blocks AdvancedRotator, MusicBlock, //256 PlasmaCannonBlock, + QuantumRiflePickup = 300, + QuantumRifleAmmoPickup, MagmaRockCube=777, MagmaRockCubeSliced, MagmaRockSlope, diff --git a/GamecraftModdingAPI/Cluster.cs b/GamecraftModdingAPI/Cluster.cs new file mode 100644 index 0000000..074c26c --- /dev/null +++ b/GamecraftModdingAPI/Cluster.cs @@ -0,0 +1,41 @@ +using Gamecraft.Damage; +using RobocraftX.Common; +using Svelto.ECS; + +namespace GamecraftModdingAPI +{ + /// + /// Represnts a cluster of blocks in time running mode, meaning blocks that are connected either directly or via joints. + /// + public class Cluster + { + public EGID Id { get; } + + public Cluster(EGID id) + { + Id = id; + } + + public Cluster(uint id) : this(new EGID(id, CommonExclusiveGroups.SIMULATION_CLUSTERS_GROUP)) + { + } + + public float InitialHealth + { + get => Block.BlockEngine.GetBlockInfo(Id).initialHealth; + set => Block.BlockEngine.GetBlockInfo(Id).initialHealth = value; + } + + public float CurrentHealth + { + get => Block.BlockEngine.GetBlockInfo(Id).currentHealth; + set => Block.BlockEngine.GetBlockInfo(Id).currentHealth = value; + } + + public float HealthMultiplier + { + get => Block.BlockEngine.GetBlockInfo(Id).healthMultiplier; + set => Block.BlockEngine.GetBlockInfo(Id).healthMultiplier = value; + } + } +} \ No newline at end of file diff --git a/GamecraftModdingAPI/SimBody.cs b/GamecraftModdingAPI/SimBody.cs index 19f4285..a3f6d55 100644 --- a/GamecraftModdingAPI/SimBody.cs +++ b/GamecraftModdingAPI/SimBody.cs @@ -3,6 +3,7 @@ using Svelto.ECS; using Unity.Mathematics; using UnityEngine; +using Gamecraft.Damage; using RobocraftX.Common; using RobocraftX.Physics; @@ -15,6 +16,14 @@ namespace GamecraftModdingAPI { public EGID Id { get; } + /// + /// The cluster this chunk belongs to, or null if the chunk doesn't exist. Get the SimBody from a Block if possible for good performance here. + /// + public Cluster Cluster => cluster ?? (cluster = clusterId == uint.MaxValue ? Block.BlockEngine.GetCluster(Id.entityID) : new Cluster(clusterId)); + + private Cluster cluster; + private uint clusterId; + public SimBody(EGID id) { Id = id; @@ -24,6 +33,11 @@ namespace GamecraftModdingAPI { } + internal SimBody(uint id, uint clusterID) : this(id) + { + clusterId = clusterID; + } + /// /// The position of this body. When setting the position, update the position of the connected bodies as well, /// otherwise unexpected forces may arise. @@ -70,6 +84,29 @@ namespace GamecraftModdingAPI //set => GetStruct().physicsMass.CenterOfMass = value; } + public float Volume + { + get => GetStruct().volume; + } + + public float InitialHealth + { + get => Block.BlockEngine.GetBlockInfo(Id).initialHealth; + set => Block.BlockEngine.GetBlockInfo(Id).initialHealth = value; + } + + public float CurrentHealth + { + get => Block.BlockEngine.GetBlockInfo(Id).currentHealth; + set => Block.BlockEngine.GetBlockInfo(Id).currentHealth = value; + } + + public float HealthMultiplier + { + get => Block.BlockEngine.GetBlockInfo(Id).healthMultiplier; + set => Block.BlockEngine.GetBlockInfo(Id).healthMultiplier = value; + } + /// /// Whether the body can be moved or static. /// diff --git a/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs b/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs index 639125c..7002605 100644 --- a/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs +++ b/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs @@ -268,6 +268,16 @@ namespace GamecraftModdingAPI.Tests }) .Build(); + CommandBuilder.Builder("TestChunkHealth", "Sets the chunk looked at to the given health.") + .Action((float val, float max) => + { + var body = new Player(PlayerType.Local).GetSimBodyLookedAt(); + if (body == null) return; + body.CurrentHealth = val; + body.InitialHealth = max; + Logging.CommandLog("Health set to: " + val); + }).Build(); + GameClient.SetDebugInfo("InstalledMods", InstalledMods); Block.Placed += (sender, args) => Logging.MetaDebugLog("Placed block " + args.Type + " with ID " + args.ID); diff --git a/GamecraftModdingAPI/Utility/DebugInterfaceEngine.cs b/GamecraftModdingAPI/Utility/DebugInterfaceEngine.cs index c604c34..0e4d023 100644 --- a/GamecraftModdingAPI/Utility/DebugInterfaceEngine.cs +++ b/GamecraftModdingAPI/Utility/DebugInterfaceEngine.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Reflection.Emit; +using System.Text; using System.Text.Formatting; using GamecraftModdingAPI.Blocks; using GamecraftModdingAPI.Engines; @@ -46,9 +47,9 @@ namespace GamecraftModdingAPI.Utility var array = new CodeInstruction[] { new CodeInstruction(OpCodes.Ldloc_0), //StringBuffer - new CodeInstruction(OpCodes.Call, ((Action)AddInfo).Method) + new CodeInstruction(OpCodes.Call, ((Action)AddInfo).Method) }; - list.InsertRange(index, array); + list.InsertRange(index - 1, array); //-1: ldloc.1 ("local") before ldfld } catch (Exception e) { @@ -58,13 +59,15 @@ namespace GamecraftModdingAPI.Utility return list; } - public static void AddInfo(StringBuffer sb) + public static void AddInfo(StringBuilder sb) { foreach (var info in _extraInfo) { try { - sb.Append(info.Value() + "\n"); + string text = info.Value().Trim(); + if (text.Length != 0) + sb.Append(text + "\n"); } catch (Exception e) { From 11b94e384ee9a0d21966b1eeefde696c4d24caa2 Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Sat, 22 Aug 2020 09:25:14 -0400 Subject: [PATCH 32/34] Update refs --- .../GamecraftModdingAPI.csproj | 266 +++++++++--------- 1 file changed, 137 insertions(+), 129 deletions(-) diff --git a/GamecraftModdingAPI/GamecraftModdingAPI.csproj b/GamecraftModdingAPI/GamecraftModdingAPI.csproj index 49a3a6a..8be57a7 100644 --- a/GamecraftModdingAPI/GamecraftModdingAPI.csproj +++ b/GamecraftModdingAPI/GamecraftModdingAPI.csproj @@ -22,8 +22,8 @@ -<<<<<<< HEAD - + + ..\ref\Gamecraft_Data\Managed\IllusionInjector.dll @@ -33,45 +33,6 @@ ..\ref\Gamecraft_Data\Managed\IllusionPlugin.dll ..\..\ref\Gamecraft_Data\Managed\IllusionPlugin.dll - - ..\ref\Gamecraft_Data\Managed\JWT.dll - ..\..\ref\Gamecraft_Data\Managed\JWT.dll - - - ..\ref\Gamecraft_Data\Managed\Unity.Burst.Unsafe.dll - ..\..\ref\Gamecraft_Data\Managed\Unity.Burst.Unsafe.dll - - - ..\ref\Gamecraft_Data\Managed\Rewired_Core.dll - ..\..\ref\Gamecraft_Data\Managed\Rewired_Core.dll - - - ..\ref\Gamecraft_Data\Managed\Rewired_Windows.dll - ..\..\ref\Gamecraft_Data\Managed\Rewired_Windows.dll - - - ..\ref\Gamecraft_Data\Managed\mscorlib.dll - ..\..\ref\Gamecraft_Data\Managed\mscorlib.dll - - - ..\ref\Gamecraft_Data\Managed\Accessibility.dll - ..\..\ref\Gamecraft_Data\Managed\Accessibility.dll -======= - - - - - - - - ..\ref\GamecraftPreview_Data\Managed\IllusionInjector.dll - ..\..\ref\GamecraftPreview_Data\Managed\IllusionInjector.dll - - - ..\ref\GamecraftPreview_Data\Managed\IllusionPlugin.dll - ..\..\ref\GamecraftPreview_Data\Managed\IllusionPlugin.dll ->>>>>>> 50ebf4f... Fix build issues for latest Gamecraft preview version - ..\ref\Gamecraft_Data\Managed\Analytics.dll ..\..\ref\Gamecraft_Data\Managed\Analytics.dll @@ -88,13 +49,6 @@ ..\ref\Gamecraft_Data\Managed\Authentication.dll ..\..\ref\Gamecraft_Data\Managed\Authentication.dll -<<<<<<< HEAD - - ..\ref\Gamecraft_Data\Managed\BlockEntityFactory.dll - ..\..\ref\Gamecraft_Data\Managed\BlockEntityFactory.dll - -======= ->>>>>>> 50ebf4f... Fix build issues for latest Gamecraft preview version ..\ref\Gamecraft_Data\Managed\Blocks.HUDFeedbackBlocks.dll ..\..\ref\Gamecraft_Data\Managed\Blocks.HUDFeedbackBlocks.dll @@ -104,16 +58,16 @@ ..\..\ref\Gamecraft_Data\Managed\CommandLine.dll - ..\ref\GamecraftPreview_Data\Managed\CommandLineCompositionRoot.dll - ..\..\ref\GamecraftPreview_Data\Managed\CommandLineCompositionRoot.dll + ..\ref\Gamecraft_Data\Managed\CommandLineCompositionRoot.dll + ..\..\ref\Gamecraft_Data\Managed\CommandLineCompositionRoot.dll - ..\ref\GamecraftPreview_Data\Managed\ConsoleBlockComposotionRoot.dll - ..\..\ref\GamecraftPreview_Data\Managed\ConsoleBlockComposotionRoot.dll + ..\ref\Gamecraft_Data\Managed\ConsoleBlockComposotionRoot.dll + ..\..\ref\Gamecraft_Data\Managed\ConsoleBlockComposotionRoot.dll - ..\ref\GamecraftPreview_Data\Managed\ConsoleCommand.dll - ..\..\ref\GamecraftPreview_Data\Managed\ConsoleCommand.dll + ..\ref\Gamecraft_Data\Managed\ConsoleCommand.dll + ..\..\ref\Gamecraft_Data\Managed\ConsoleCommand.dll ..\ref\Gamecraft_Data\Managed\DataLoader.dll @@ -123,10 +77,6 @@ ..\ref\Gamecraft_Data\Managed\DDNA.dll ..\..\ref\Gamecraft_Data\Managed\DDNA.dll - - ..\ref\Gamecraft_Data\Managed\Facepunch.Steamworks.Win64.dll - ..\..\ref\Gamecraft_Data\Managed\Facepunch.Steamworks.Win64.dll - ..\ref\Gamecraft_Data\Managed\FMOD.dll ..\..\ref\Gamecraft_Data\Managed\FMOD.dll @@ -140,12 +90,12 @@ ..\..\ref\Gamecraft_Data\Managed\Gamecraft.AudioBlocks.dll - ..\ref\GamecraftPreview_Data\Managed\Gamecraft.BlockCompositionRoot.dll - ..\..\ref\GamecraftPreview_Data\Managed\Gamecraft.BlockCompositionRoot.dll + ..\ref\Gamecraft_Data\Managed\Gamecraft.BlockCompositionRoot.dll + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.BlockCompositionRoot.dll - ..\ref\GamecraftPreview_Data\Managed\Gamecraft.BlockEntityFactory.dll - ..\..\ref\GamecraftPreview_Data\Managed\Gamecraft.BlockEntityFactory.dll + ..\ref\Gamecraft_Data\Managed\Gamecraft.BlockEntityFactory.dll + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.BlockEntityFactory.dll ..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.ConsoleBlock.dll @@ -156,8 +106,8 @@ ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.DamagingSurfaceBlock.dll - ..\ref\GamecraftPreview_Data\Managed\Gamecraft.Blocks.DestructionBlocks.dll - ..\..\ref\GamecraftPreview_Data\Managed\Gamecraft.Blocks.DestructionBlocks.dll + ..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.DestructionBlocks.dll + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.DestructionBlocks.dll ..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.GenericPhysicsBlocks.dll @@ -172,16 +122,16 @@ ..\..\ref\Gamecraft_Data\Managed\GameCraft.Blocks.ProjectileBlock.dll - ..\ref\GamecraftPreview_Data\Managed\Gamecraft.Blocks.TextBlock.CompositionRoot.dll - ..\..\ref\GamecraftPreview_Data\Managed\Gamecraft.Blocks.TextBlock.CompositionRoot.dll + ..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.TextBlock.CompositionRoot.dll + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.TextBlock.CompositionRoot.dll ..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.TimerBlock.dll ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Blocks.TimerBlock.dll - ..\ref\GamecraftPreview_Data\Managed\Gamecraft.BlocksEntityDescriptors.dll - ..\..\ref\GamecraftPreview_Data\Managed\Gamecraft.BlocksEntityDescriptors.dll + ..\ref\Gamecraft_Data\Managed\Gamecraft.BlocksEntityDescriptors.dll + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.BlocksEntityDescriptors.dll ..\ref\Gamecraft_Data\Managed\Gamecraft.CharacterVulnerability.dll @@ -192,20 +142,20 @@ ..\..\ref\Gamecraft_Data\Managed\Gamecraft.CharacterVulnerabilityGui.dll - ..\ref\GamecraftPreview_Data\Managed\Gamecraft.Damage.dll - ..\..\ref\GamecraftPreview_Data\Managed\Gamecraft.Damage.dll + ..\ref\Gamecraft_Data\Managed\Gamecraft.Damage.dll + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Damage.dll ..\ref\Gamecraft_Data\Managed\Gamecraft.Effects.dll ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Effects.dll - ..\ref\GamecraftPreview_Data\Managed\Gamecraft.ExplosionFragments.dll - ..\..\ref\GamecraftPreview_Data\Managed\Gamecraft.ExplosionFragments.dll + ..\ref\Gamecraft_Data\Managed\Gamecraft.ExplosionFragments.dll + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.ExplosionFragments.dll - ..\ref\GamecraftPreview_Data\Managed\Gamecraft.GraphicsSettings.dll - ..\..\ref\GamecraftPreview_Data\Managed\Gamecraft.GraphicsSettings.dll + ..\ref\Gamecraft_Data\Managed\Gamecraft.GraphicsSettings.dll + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.GraphicsSettings.dll ..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.ConsoleBlock.dll @@ -236,12 +186,12 @@ ..\..\ref\Gamecraft_Data\Managed\Gamecraft.GUI.WorldSpaceGuis.dll - ..\ref\GamecraftPreview_Data\Managed\Gamecraft.InventoryTimeRunning.dll - ..\..\ref\GamecraftPreview_Data\Managed\Gamecraft.InventoryTimeRunning.dll + ..\ref\Gamecraft_Data\Managed\Gamecraft.InventoryTimeRunning.dll + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.InventoryTimeRunning.dll - ..\ref\GamecraftPreview_Data\Managed\Gamecraft.JointBlocks.dll - ..\..\ref\GamecraftPreview_Data\Managed\Gamecraft.JointBlocks.dll + ..\ref\Gamecraft_Data\Managed\Gamecraft.JointBlocks.dll + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.JointBlocks.dll ..\ref\Gamecraft_Data\Managed\Gamecraft.Music.dll @@ -252,20 +202,20 @@ ..\..\ref\Gamecraft_Data\Managed\Gamecraft.PerformanceWarnings.dll - ..\ref\GamecraftPreview_Data\Managed\Gamecraft.PickupBlck.dll - ..\..\ref\GamecraftPreview_Data\Managed\Gamecraft.PickupBlck.dll + ..\ref\Gamecraft_Data\Managed\Gamecraft.PickupBlck.dll + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.PickupBlck.dll - ..\ref\GamecraftPreview_Data\Managed\Gamecraft.PickupsCommon.dll - ..\..\ref\GamecraftPreview_Data\Managed\Gamecraft.PickupsCommon.dll + ..\ref\Gamecraft_Data\Managed\Gamecraft.PickupsCommon.dll + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.PickupsCommon.dll - ..\ref\GamecraftPreview_Data\Managed\Gamecraft.PopupMessage.dll - ..\..\ref\GamecraftPreview_Data\Managed\Gamecraft.PopupMessage.dll + ..\ref\Gamecraft_Data\Managed\Gamecraft.PopupMessage.dll + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.PopupMessage.dll - ..\ref\GamecraftPreview_Data\Managed\Gamecraft.Projectiles.dll - ..\..\ref\GamecraftPreview_Data\Managed\Gamecraft.Projectiles.dll + ..\ref\Gamecraft_Data\Managed\Gamecraft.Projectiles.dll + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Projectiles.dll ..\ref\Gamecraft_Data\Managed\Gamecraft.Tweaks.dll @@ -276,8 +226,8 @@ ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Tweaks.Mockup.dll - ..\ref\GamecraftPreview_Data\Managed\Gamecraft.VisualEffects.Decals.dll - ..\..\ref\GamecraftPreview_Data\Managed\Gamecraft.VisualEffects.Decals.dll + ..\ref\Gamecraft_Data\Managed\Gamecraft.VisualEffects.Decals.dll + ..\..\ref\Gamecraft_Data\Managed\Gamecraft.VisualEffects.Decals.dll ..\ref\Gamecraft_Data\Managed\Gamecraft.VisualEffects.dll @@ -287,13 +237,6 @@ ..\ref\Gamecraft_Data\Managed\Gamecraft.Wires.dll ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Wires.dll -<<<<<<< HEAD - - ..\ref\Gamecraft_Data\Managed\Gamecraft.Wires.Input.dll - ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Wires.Input.dll - -======= ->>>>>>> 50ebf4f... Fix build issues for latest Gamecraft preview version ..\ref\Gamecraft_Data\Managed\Gamecraft.Wires.Mockup.dll ..\..\ref\Gamecraft_Data\Managed\Gamecraft.Wires.Mockup.dll @@ -326,18 +269,6 @@ ..\ref\Gamecraft_Data\Managed\MultiplayerTest.dll ..\..\ref\Gamecraft_Data\Managed\MultiplayerTest.dll - - ..\ref\Gamecraft_Data\Managed\netstandard.dll - ..\..\ref\Gamecraft_Data\Managed\netstandard.dll - - - ..\ref\Gamecraft_Data\Managed\Newtonsoft.Json.dll - ..\..\ref\Gamecraft_Data\Managed\Newtonsoft.Json.dll - - - ..\ref\Gamecraft_Data\Managed\Novell.Directory.Ldap.dll - ..\..\ref\Gamecraft_Data\Managed\Novell.Directory.Ldap.dll - ..\ref\Gamecraft_Data\Managed\RCX.ScreenshotTaker.dll ..\..\ref\Gamecraft_Data\Managed\RCX.ScreenshotTaker.dll @@ -519,12 +450,12 @@ ..\..\ref\Gamecraft_Data\Managed\RobocratX.SimulationCompositionRoot.dll - ..\ref\GamecraftPreview_Data\Managed\SpawningPointCompositionRoot.dll - ..\..\ref\GamecraftPreview_Data\Managed\SpawningPointCompositionRoot.dll + ..\ref\Gamecraft_Data\Managed\SpawningPointCompositionRoot.dll + ..\..\ref\Gamecraft_Data\Managed\SpawningPointCompositionRoot.dll - ..\ref\GamecraftPreview_Data\Managed\SpecializedDescriptors.dll - ..\..\ref\GamecraftPreview_Data\Managed\SpecializedDescriptors.dll + ..\ref\Gamecraft_Data\Managed\SpecializedDescriptors.dll + ..\..\ref\Gamecraft_Data\Managed\SpecializedDescriptors.dll ..\ref\Gamecraft_Data\Managed\StringFormatter.dll @@ -547,13 +478,41 @@ ..\..\ref\Gamecraft_Data\Managed\Svelto.Tasks.dll - ..\ref\GamecraftPreview_Data\Managed\UltimateDecals.dll - ..\..\ref\GamecraftPreview_Data\Managed\UltimateDecals.dll + ..\ref\Gamecraft_Data\Managed\UltimateDecals.dll + ..\..\ref\Gamecraft_Data\Managed\UltimateDecals.dll ..\ref\Gamecraft_Data\Managed\Unity.Addressables.dll ..\..\ref\Gamecraft_Data\Managed\Unity.Addressables.dll + + ..\ref\Gamecraft_Data\Managed\Unity.Animation.Curves.dll + ..\..\ref\Gamecraft_Data\Managed\Unity.Animation.Curves.dll + + + ..\ref\Gamecraft_Data\Managed\Unity.Animation.Curves.Hybrid.dll + ..\..\ref\Gamecraft_Data\Managed\Unity.Animation.Curves.Hybrid.dll + + + ..\ref\Gamecraft_Data\Managed\Unity.Animation.DefaultGraphPipeline.dll + ..\..\ref\Gamecraft_Data\Managed\Unity.Animation.DefaultGraphPipeline.dll + + + ..\ref\Gamecraft_Data\Managed\Unity.Animation.DefaultGraphPipeline.Hybrid.dll + ..\..\ref\Gamecraft_Data\Managed\Unity.Animation.DefaultGraphPipeline.Hybrid.dll + + + ..\ref\Gamecraft_Data\Managed\Unity.Animation.dll + ..\..\ref\Gamecraft_Data\Managed\Unity.Animation.dll + + + ..\ref\Gamecraft_Data\Managed\Unity.Animation.Graph.dll + ..\..\ref\Gamecraft_Data\Managed\Unity.Animation.Graph.dll + + + ..\ref\Gamecraft_Data\Managed\Unity.Animation.Hybrid.dll + ..\..\ref\Gamecraft_Data\Managed\Unity.Animation.Hybrid.dll + ..\ref\Gamecraft_Data\Managed\Unity.Build.SlimPlayerRuntime.dll ..\..\ref\Gamecraft_Data\Managed\Unity.Build.SlimPlayerRuntime.dll @@ -566,6 +525,10 @@ ..\ref\Gamecraft_Data\Managed\Unity.Collections.dll ..\..\ref\Gamecraft_Data\Managed\Unity.Collections.dll + + ..\ref\Gamecraft_Data\Managed\Unity.DataFlowGraph.dll + ..\..\ref\Gamecraft_Data\Managed\Unity.DataFlowGraph.dll + ..\ref\Gamecraft_Data\Managed\Unity.Deformations.dll ..\..\ref\Gamecraft_Data\Managed\Unity.Deformations.dll @@ -594,6 +557,10 @@ ..\ref\Gamecraft_Data\Managed\Unity.Mathematics.Extensions.Hybrid.dll ..\..\ref\Gamecraft_Data\Managed\Unity.Mathematics.Extensions.Hybrid.dll + + ..\ref\Gamecraft_Data\Managed\Unity.MemoryProfiler.dll + ..\..\ref\Gamecraft_Data\Managed\Unity.MemoryProfiler.dll + ..\ref\Gamecraft_Data\Managed\Unity.Physics.dll ..\..\ref\Gamecraft_Data\Managed\Unity.Physics.dll @@ -678,6 +645,62 @@ ..\ref\Gamecraft_Data\Managed\Unity.Transforms.Hybrid.dll ..\..\ref\Gamecraft_Data\Managed\Unity.Transforms.Hybrid.dll + + ..\ref\Gamecraft_Data\Managed\Unity.VisualEffectGraph.Runtime.dll + ..\..\ref\Gamecraft_Data\Managed\Unity.VisualEffectGraph.Runtime.dll + + + ..\ref\Gamecraft_Data\Managed\UnityEngine.UI.dll + ..\..\ref\Gamecraft_Data\Managed\UnityEngine.UI.dll + + + ..\ref\Gamecraft_Data\Managed\uREPL.dll + ..\..\ref\Gamecraft_Data\Managed\uREPL.dll + + + ..\ref\Gamecraft_Data\Managed\VisualProfiler.dll + ..\..\ref\Gamecraft_Data\Managed\VisualProfiler.dll + + + ..\ref\Gamecraft_Data\Managed\Accessibility.dll + ..\..\ref\Gamecraft_Data\Managed\Accessibility.dll + + + ..\ref\Gamecraft_Data\Managed\Facepunch.Steamworks.Win64.dll + ..\..\ref\Gamecraft_Data\Managed\Facepunch.Steamworks.Win64.dll + + + ..\ref\Gamecraft_Data\Managed\JWT.dll + ..\..\ref\Gamecraft_Data\Managed\JWT.dll + + + ..\ref\Gamecraft_Data\Managed\mscorlib.dll + ..\..\ref\Gamecraft_Data\Managed\mscorlib.dll + + + ..\ref\Gamecraft_Data\Managed\netstandard.dll + ..\..\ref\Gamecraft_Data\Managed\netstandard.dll + + + ..\ref\Gamecraft_Data\Managed\Newtonsoft.Json.dll + ..\..\ref\Gamecraft_Data\Managed\Newtonsoft.Json.dll + + + ..\ref\Gamecraft_Data\Managed\Novell.Directory.Ldap.dll + ..\..\ref\Gamecraft_Data\Managed\Novell.Directory.Ldap.dll + + + ..\ref\Gamecraft_Data\Managed\Rewired_Core.dll + ..\..\ref\Gamecraft_Data\Managed\Rewired_Core.dll + + + ..\ref\Gamecraft_Data\Managed\Rewired_Windows.dll + ..\..\ref\Gamecraft_Data\Managed\Rewired_Windows.dll + + + ..\ref\Gamecraft_Data\Managed\Unity.Burst.Unsafe.dll + ..\..\ref\Gamecraft_Data\Managed\Unity.Burst.Unsafe.dll + ..\ref\Gamecraft_Data\Managed\UnityEngine.AccessibilityModule.dll ..\..\ref\Gamecraft_Data\Managed\UnityEngine.AccessibilityModule.dll @@ -846,10 +869,6 @@ ..\ref\Gamecraft_Data\Managed\UnityEngine.TLSModule.dll ..\..\ref\Gamecraft_Data\Managed\UnityEngine.TLSModule.dll - - ..\ref\Gamecraft_Data\Managed\UnityEngine.UI.dll - ..\..\ref\Gamecraft_Data\Managed\UnityEngine.UI.dll - ..\ref\Gamecraft_Data\Managed\UnityEngine.UIElementsModule.dll ..\..\ref\Gamecraft_Data\Managed\UnityEngine.UIElementsModule.dll @@ -922,17 +941,6 @@ ..\ref\Gamecraft_Data\Managed\UnityEngine.XRModule.dll ..\..\ref\Gamecraft_Data\Managed\UnityEngine.XRModule.dll -<<<<<<< HEAD - - ..\ref\Gamecraft_Data\Managed\uREPL.dll - ..\..\ref\Gamecraft_Data\Managed\uREPL.dll - - - ..\ref\Gamecraft_Data\Managed\VisualProfiler.dll - ..\..\ref\Gamecraft_Data\Managed\VisualProfiler.dll - -======= ->>>>>>> 50ebf4f... Fix build issues for latest Gamecraft preview version - + \ No newline at end of file From daf4a24bc90f333c35cba1d3af576f82a2867ced Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Sat, 22 Aug 2020 09:26:51 -0400 Subject: [PATCH 33/34] Fix namespace build error from unused using statement (I deleted it) --- GamecraftModdingAPI/Players/PlayerEngine.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/GamecraftModdingAPI/Players/PlayerEngine.cs b/GamecraftModdingAPI/Players/PlayerEngine.cs index 948c6e9..6d461f2 100644 --- a/GamecraftModdingAPI/Players/PlayerEngine.cs +++ b/GamecraftModdingAPI/Players/PlayerEngine.cs @@ -12,8 +12,6 @@ using RobocraftX.Physics; using RobocraftX.Blocks.Ghost; using RobocraftX.Character.Camera; using RobocraftX.Character.Factories; -using Gamecraft.CharacterVulnerability; -using Gamecraft.CharacterVulnerability.Entities; using Gamecraft.GUI.HUDFeedbackBlocks; using Svelto.ECS; using Unity.Mathematics; From aae20579723070aaa2fba9f26e1cdd980bd8c4e5 Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Sun, 23 Aug 2020 09:59:13 -0400 Subject: [PATCH 34/34] Convert relevant blocks to wireable blocks and fix wire connect during block init --- GamecraftModdingAPI/Blocks/ConsoleBlock.cs | 2 +- GamecraftModdingAPI/Blocks/Motor.cs | 2 +- GamecraftModdingAPI/Blocks/MusicBlock.cs | 2 +- GamecraftModdingAPI/Blocks/Piston.cs | 2 +- GamecraftModdingAPI/Blocks/Servo.cs | 2 +- GamecraftModdingAPI/Blocks/TextBlock.cs | 2 +- GamecraftModdingAPI/Blocks/Timer.cs | 2 +- GamecraftModdingAPI/Blocks/Wire.cs | 8 +++--- .../Tests/GamecraftModdingAPIPluginTest.cs | 27 +++++-------------- 9 files changed, 18 insertions(+), 31 deletions(-) diff --git a/GamecraftModdingAPI/Blocks/ConsoleBlock.cs b/GamecraftModdingAPI/Blocks/ConsoleBlock.cs index edf3e76..c8982e4 100644 --- a/GamecraftModdingAPI/Blocks/ConsoleBlock.cs +++ b/GamecraftModdingAPI/Blocks/ConsoleBlock.cs @@ -10,7 +10,7 @@ using GamecraftModdingAPI.Utility; namespace GamecraftModdingAPI.Blocks { - public class ConsoleBlock : Block + public class ConsoleBlock : SignalingBlock { public ConsoleBlock(EGID id): base(id) { diff --git a/GamecraftModdingAPI/Blocks/Motor.cs b/GamecraftModdingAPI/Blocks/Motor.cs index fdadd26..3c38a52 100644 --- a/GamecraftModdingAPI/Blocks/Motor.cs +++ b/GamecraftModdingAPI/Blocks/Motor.cs @@ -9,7 +9,7 @@ using GamecraftModdingAPI.Utility; namespace GamecraftModdingAPI.Blocks { - public class Motor : Block + public class Motor : SignalingBlock { public Motor(EGID id) : base(id) { diff --git a/GamecraftModdingAPI/Blocks/MusicBlock.cs b/GamecraftModdingAPI/Blocks/MusicBlock.cs index 2128a45..185913b 100644 --- a/GamecraftModdingAPI/Blocks/MusicBlock.cs +++ b/GamecraftModdingAPI/Blocks/MusicBlock.cs @@ -14,7 +14,7 @@ using GamecraftModdingAPI.Utility; namespace GamecraftModdingAPI.Blocks { - public class MusicBlock : Block + public class MusicBlock : SignalingBlock { public MusicBlock(EGID id) : base(id) { diff --git a/GamecraftModdingAPI/Blocks/Piston.cs b/GamecraftModdingAPI/Blocks/Piston.cs index aed8c33..c3f2497 100644 --- a/GamecraftModdingAPI/Blocks/Piston.cs +++ b/GamecraftModdingAPI/Blocks/Piston.cs @@ -9,7 +9,7 @@ using RobocraftX.Common; namespace GamecraftModdingAPI.Blocks { - public class Piston : Block + public class Piston : SignalingBlock { public Piston(EGID id) : base(id) { diff --git a/GamecraftModdingAPI/Blocks/Servo.cs b/GamecraftModdingAPI/Blocks/Servo.cs index 730749a..1177fb6 100644 --- a/GamecraftModdingAPI/Blocks/Servo.cs +++ b/GamecraftModdingAPI/Blocks/Servo.cs @@ -9,7 +9,7 @@ using GamecraftModdingAPI.Utility; namespace GamecraftModdingAPI.Blocks { - public class Servo : Block + public class Servo : SignalingBlock { public Servo(EGID id) : base(id) { diff --git a/GamecraftModdingAPI/Blocks/TextBlock.cs b/GamecraftModdingAPI/Blocks/TextBlock.cs index 6096dd4..e4b4c73 100644 --- a/GamecraftModdingAPI/Blocks/TextBlock.cs +++ b/GamecraftModdingAPI/Blocks/TextBlock.cs @@ -10,7 +10,7 @@ using GamecraftModdingAPI.Utility; namespace GamecraftModdingAPI.Blocks { - public class TextBlock : Block + public class TextBlock : SignalingBlock { public TextBlock(EGID id) : base(id) { diff --git a/GamecraftModdingAPI/Blocks/Timer.cs b/GamecraftModdingAPI/Blocks/Timer.cs index 5766a41..1aeecd9 100644 --- a/GamecraftModdingAPI/Blocks/Timer.cs +++ b/GamecraftModdingAPI/Blocks/Timer.cs @@ -11,7 +11,7 @@ using GamecraftModdingAPI.Utility; namespace GamecraftModdingAPI.Blocks { - public class Timer : Block + public class Timer : SignalingBlock { public Timer(EGID id) : base(id) { diff --git a/GamecraftModdingAPI/Blocks/Wire.cs b/GamecraftModdingAPI/Blocks/Wire.cs index c29795f..e58a625 100644 --- a/GamecraftModdingAPI/Blocks/Wire.cs +++ b/GamecraftModdingAPI/Blocks/Wire.cs @@ -31,7 +31,7 @@ namespace GamecraftModdingAPI.Blocks public static Wire Connect(SignalingBlock start, byte startPort, SignalingBlock end, byte endPort) { WireEntityStruct wire = signalEngine.CreateNewWire(start.Id, startPort, end.Id, endPort); - return new Wire(wire); + return new Wire(wire, start, end); } /// @@ -173,15 +173,15 @@ namespace GamecraftModdingAPI.Blocks this.startPort = wire.sourcePortUsage; } - internal Wire(WireEntityStruct wire) + internal Wire(WireEntityStruct wire, SignalingBlock src, SignalingBlock dest) { this.wireEGID = wire.ID; this.startBlockEGID = wire.sourceBlockEGID; this.endBlockEGID = wire.destinationBlockEGID; inputToOutput = false; - endPortEGID = signalEngine.MatchBlockInputToPort(wire.destinationBlockEGID, wire.destinationPortUsage, out bool exists); + endPortEGID = signalEngine.MatchBlockInputToPort(dest, wire.destinationPortUsage, out bool exists); if (!exists) throw new WireInvalidException("Wire end port not found"); - startPortEGID = signalEngine.MatchBlockOutputToPort(wire.sourceBlockEGID, wire.sourcePortUsage, out exists); + startPortEGID = signalEngine.MatchBlockOutputToPort(src, wire.sourcePortUsage, out exists); if (!exists) throw new WireInvalidException("Wire start port not found"); this.endPort = wire.destinationPortUsage; this.startPort = wire.sourcePortUsage; diff --git a/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs b/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs index 7002605..4a5547f 100644 --- a/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs +++ b/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs @@ -22,33 +22,29 @@ using GamecraftModdingAPI.Players; namespace GamecraftModdingAPI.Tests { +#if DEBUG // unused by design /// /// Modding API implemented as a standalone IPA Plugin. /// Ideally, GamecraftModdingAPI should be loaded by another mod; not itself /// - public class GamecraftModdingAPIPluginTest -#if DEBUG - : IllusionPlugin.IEnhancedPlugin -#endif + public class GamecraftModdingAPIPluginTest : IllusionPlugin.IEnhancedPlugin { private static Harmony harmony { get; set; } - public string[] Filter { get; } = new string[] { "Gamecraft", "GamecraftPreview" }; + public override string Name { get; } = Assembly.GetExecutingAssembly().GetName().Name; - public string Name { get; } = Assembly.GetExecutingAssembly().GetName().Name; - - public string Version { get; } = Assembly.GetExecutingAssembly().GetName().Version.ToString(); + public override string Version { get; } = Assembly.GetExecutingAssembly().GetName().Version.ToString(); public string HarmonyID { get; } = "org.git.exmods.modtainers.gamecraftmoddingapi"; - public void OnApplicationQuit() + public override void OnApplicationQuit() { GamecraftModdingAPI.Main.Shutdown(); } - public void OnApplicationStart() + public override void OnApplicationStart() { FileLog.Reset(); Harmony.DEBUG = true; @@ -387,16 +383,6 @@ namespace GamecraftModdingAPI.Tests } } - public void OnFixedUpdate() { } - - public void OnLateUpdate() { } - - public void OnLevelWasInitialized(int level) { } - - public void OnLevelWasLoaded(int level) { } - - public void OnUpdate() { } - [HarmonyPatch] public class MinimumSpecsPatch { @@ -411,4 +397,5 @@ namespace GamecraftModdingAPI.Tests } } } +#endif }