From 508a60df19217be8d3cccbc872c208b0e637ae6b Mon Sep 17 00:00:00 2001 From: Kelwan Date: Sat, 8 Feb 2025 08:47:15 -0800 Subject: [PATCH 1/4] chore: rebase main --- .gitmodules | 11 ++ unreal-cpp-benchmark/.gitignore | 78 +++++++++++ unreal-cpp-benchmark/BuildSystemImpls.ps1 | 84 ++++++++++++ unreal-cpp-benchmark/Config/DefaultEcsact.ini | 11 ++ unreal-cpp-benchmark/Config/DefaultEditor.ini | 0 unreal-cpp-benchmark/Config/DefaultEngine.ini | 92 +++++++++++++ unreal-cpp-benchmark/Config/DefaultGame.ini | 3 + unreal-cpp-benchmark/Config/DefaultInput.ini | 84 ++++++++++++ .../BP_EcsactBenchmarkMassSpawner.uasset | Bin 0 -> 22659 bytes .../Content/Maps/Benchmark.umap | Bin 0 -> 8926 bytes .../Content/Mass/BenchmarkConfig.uasset | Bin 0 -> 1615 bytes unreal-cpp-benchmark/EcsactBenchmark.uproject | 26 ++++ unreal-cpp-benchmark/Plugins/Ecsact | 1 + .../Source/EcsactBenchmark.Target.cs | 15 ++ .../EcsactBenchmark/EcsactBenchmark.Build.cs | 23 ++++ .../EcsactBenchmark/EcsactBenchmark.cpp | 8 ++ .../EcsactBenchmark/EcsactBenchmark.ecsact | 12 ++ .../EcsactBenchmark/EcsactBenchmark.ecsact.hh | 29 ++++ .../Source/EcsactBenchmark/EcsactBenchmark.h | 6 + .../EcsactBenchmarkMassSpawner.cpp | 89 ++++++++++++ .../EcsactBenchmarkMassSpawner.h | 25 ++++ .../EcsactBenchmark__ecsact__mass__ue.cpp | 128 ++++++++++++++++++ .../EcsactBenchmark__ecsact__mass__ue.h | 66 +++++++++ .../EcsactBenchmark__ecsact__ue.cpp | 77 +++++++++++ .../EcsactBenchmark__ecsact__ue.h | 83 ++++++++++++ .../Fragments/NoEcsactFragment.h | 0 .../Processors/MassBenchmarkProcessor.cpp | 43 ++++++ .../Processors/MassBenchmarkProcessor.h | 22 +++ .../Source/EcsactBenchmarkEditor.Target.cs | 15 ++ .../SystemImpls/EcsactSystemImpls.cpp | 10 ++ .../generated/EcsactBenchmark.ecsact.hh | 23 ++++ .../EcsactBenchmark.ecsact.systems.cc | 6 + .../EcsactBenchmark.ecsact.systems.h | 12 ++ .../EcsactBenchmark.ecsact.systems.hh | 53 ++++++++ 34 files changed, 1135 insertions(+) create mode 100644 .gitmodules create mode 100644 unreal-cpp-benchmark/.gitignore create mode 100644 unreal-cpp-benchmark/BuildSystemImpls.ps1 create mode 100644 unreal-cpp-benchmark/Config/DefaultEcsact.ini create mode 100644 unreal-cpp-benchmark/Config/DefaultEditor.ini create mode 100644 unreal-cpp-benchmark/Config/DefaultEngine.ini create mode 100644 unreal-cpp-benchmark/Config/DefaultGame.ini create mode 100644 unreal-cpp-benchmark/Config/DefaultInput.ini create mode 100644 unreal-cpp-benchmark/Content/Blueprints/BP_EcsactBenchmarkMassSpawner.uasset create mode 100644 unreal-cpp-benchmark/Content/Maps/Benchmark.umap create mode 100644 unreal-cpp-benchmark/Content/Mass/BenchmarkConfig.uasset create mode 100644 unreal-cpp-benchmark/EcsactBenchmark.uproject create mode 160000 unreal-cpp-benchmark/Plugins/Ecsact create mode 100644 unreal-cpp-benchmark/Source/EcsactBenchmark.Target.cs create mode 100644 unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmark.Build.cs create mode 100644 unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmark.cpp create mode 100644 unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmark.ecsact create mode 100644 unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmark.ecsact.hh create mode 100644 unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmark.h create mode 100644 unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmarkMassSpawner.cpp create mode 100644 unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmarkMassSpawner.h create mode 100644 unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmark__ecsact__mass__ue.cpp create mode 100644 unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmark__ecsact__mass__ue.h create mode 100644 unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmark__ecsact__ue.cpp create mode 100644 unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmark__ecsact__ue.h create mode 100644 unreal-cpp-benchmark/Source/EcsactBenchmark/Fragments/NoEcsactFragment.h create mode 100644 unreal-cpp-benchmark/Source/EcsactBenchmark/Processors/MassBenchmarkProcessor.cpp create mode 100644 unreal-cpp-benchmark/Source/EcsactBenchmark/Processors/MassBenchmarkProcessor.h create mode 100644 unreal-cpp-benchmark/Source/EcsactBenchmarkEditor.Target.cs create mode 100644 unreal-cpp-benchmark/SystemImpls/EcsactSystemImpls.cpp create mode 100644 unreal-cpp-benchmark/SystemImpls/generated/EcsactBenchmark.ecsact.hh create mode 100644 unreal-cpp-benchmark/SystemImpls/generated/EcsactBenchmark.ecsact.systems.cc create mode 100644 unreal-cpp-benchmark/SystemImpls/generated/EcsactBenchmark.ecsact.systems.h create mode 100644 unreal-cpp-benchmark/SystemImpls/generated/EcsactBenchmark.ecsact.systems.hh diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..5b782ea --- /dev/null +++ b/.gitmodules @@ -0,0 +1,11 @@ +[submodule "unreal-cpp-net-fps/Plugins/Ecsact"] + path = unreal-cpp-net-fps/Plugins/Ecsact + url = https://github.com/ecsact-dev/ecsact_unreal + branch = main +[submodule "unreal-cpp-net-fps/Plugins/EcsactNet"] + path = unreal-cpp-net-fps/Plugins/EcsactNet + url = https://github.com/seaube/ecsact-net-unreal + branch = main +[submodule "unreal-cpp-benchmark/Plugins/Ecsact"] + path = unreal-cpp-benchmark/Plugins/Ecsact + url = git@github.com:ecsact-dev/ecsact_unreal.git diff --git a/unreal-cpp-benchmark/.gitignore b/unreal-cpp-benchmark/.gitignore new file mode 100644 index 0000000..8320393 --- /dev/null +++ b/unreal-cpp-benchmark/.gitignore @@ -0,0 +1,78 @@ +# Visual Studio 2015 user specific files +.vs/ + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app +*.ipa + +# These project files can be generated by the engine +*.xcodeproj +*.xcworkspace +*.sln +*.suo +*.opensdf +*.sdf +*.VC.db +*.VC.opendb + +# Precompiled Assets +SourceArt/**/*.png +SourceArt/**/*.tga + +# Binary Files +Binaries/* +Plugins/**/Binaries/* + +# Builds +Build/* + +# Whitelist PakBlacklist-.txt files +!Build/*/ +Build/*/** +!Build/*/PakBlacklist*.txt + +# Don't ignore icon files in Build +!Build/**/*.ico + +# Built data for maps +*_BuiltData.uasset + +# Configuration files generated by the Editor +Saved/* + +# Compiled source files for the engine to use +Intermediate/* +Plugins/**/Intermediate/* + +# Cache files for the editor to use +DerivedDataCache/* + +# Clangd +.cache +compile_commands.json diff --git a/unreal-cpp-benchmark/BuildSystemImpls.ps1 b/unreal-cpp-benchmark/BuildSystemImpls.ps1 new file mode 100644 index 0000000..d39c192 --- /dev/null +++ b/unreal-cpp-benchmark/BuildSystemImpls.ps1 @@ -0,0 +1,84 @@ +#!/usr/bin/env pwsh + +# This is an example batch file for building your Ecsact system implementations +# with Emscripten. In a more sophisticated setup you will likely use a build +# system such as bazel, cmake, zig, etc. + +param ( + [Parameter(Mandatory)] $ProjectDir +) + +if (${env:UE-ZenSubprocessDataPath}) +{ + Write-Host "Detected live coding enabled" + Write-Host "Skipping system impl re-build" + exit 0 +} + +$ErrorActionPreference = 'Stop' + +if (-not $env:EMSDK) +{ + if (Test-Path -Path "C:\emsdk\emsdk_env.ps1" -PathType Leaf) + { + (. C:\emsdk\emsdk_env.ps1) 2> $null + } + + if (-not $env:EMSDK) + { + throw "Unable to find the Emscripten SDK installed on your system" + } +} + +$EcsactFiles = @( + "$ProjectDir/Source/EcsactBenchmark/EcsactBenchmark.ecsact" +) + +$Sources = @( + "$ProjectDir/SystemImpls/EcsactSystemImpls.cpp" +) + +$GeneratedOutDir = "$ProjectDir/SystemImpls/generated" + +# TODO: don't hard set generated sources +$GeneratedSources = @( + "$ProjectDir/SystemImpls/generated/EcsactBenchmark.ecsact.systems.cc" +) + +$EcsactInc = (ecsact config include_dir) + +ecsact codegen $EcsactFiles ` + --plugin=cpp_header ` + --plugin=systems_header ` + --plugin=cpp_systems_header ` + --plugin=cpp_systems_source ` + --outdir=$GeneratedOutDir + +emcc -v + +mkdir -Force "$ProjectDir/Binaries" | Out-Null + +$WasmOutputFilePath = "$ProjectDir/Binaries/SystemImpls.wasm" + +Write-Host "Building $WasmOutputFilePath ..." + +# NOTE: PURE_WASI=1 removes emscripten_* functions that are not compatible with the Ecsact SI Wasm host +emcc -std=c++20 --no-entry -I"$EcsactInc" -I"SystemImpls/generated" ` + -s ERROR_ON_UNDEFINED_SYMBOLS=0 ` + -s WASM=1 ` + -s STANDALONE_WASM=1 ` + -s PURE_WASI=1 ` + -O3 ` + -Wno-js-compiler ` + -o $WasmOutputFilePath ` + $Sources ` + $GeneratedSources + +if (-not $?) +{ + throw "emcc exited with code ${LastExitCode}" +} + + +Write-Host "Uploading $WasmOutputFilePath to Ecsact Net ..." + diff --git a/unreal-cpp-benchmark/Config/DefaultEcsact.ini b/unreal-cpp-benchmark/Config/DefaultEcsact.ini new file mode 100644 index 0000000..795cf93 --- /dev/null +++ b/unreal-cpp-benchmark/Config/DefaultEcsact.ini @@ -0,0 +1,11 @@ +[/Script/Ecsact.EcsactSettings] +bEnableBuild=True +CustomEcsactRuntimeLibraryPath= +BuildReportFilter=None ++Recipes=rt_entt ++Recipes=si_wasmer +Runner=Automatic +CustomRunnerClass=None +bAutoCollectBlueprintRunnerSubsystems=True ++RunnerSubsystems=/Game/Blueprints/BP_EcsactBenchmarkMassSpawner.BP_EcsactBenchmarkMassSpawner_C + diff --git a/unreal-cpp-benchmark/Config/DefaultEditor.ini b/unreal-cpp-benchmark/Config/DefaultEditor.ini new file mode 100644 index 0000000..e69de29 diff --git a/unreal-cpp-benchmark/Config/DefaultEngine.ini b/unreal-cpp-benchmark/Config/DefaultEngine.ini new file mode 100644 index 0000000..4884f74 --- /dev/null +++ b/unreal-cpp-benchmark/Config/DefaultEngine.ini @@ -0,0 +1,92 @@ + + +[/Script/EngineSettings.GameMapsSettings] +GameDefaultMap=/Engine/Maps/Templates/OpenWorld + +[/Script/Engine.RendererSettings] +r.AllowStaticLighting=False + +r.GenerateMeshDistanceFields=True + +r.DynamicGlobalIlluminationMethod=1 + +r.ReflectionMethod=1 + +r.SkinCache.CompileShaders=True + +r.RayTracing=True + +r.Shadow.Virtual.Enable=1 + +r.DefaultFeature.AutoExposure.ExtendDefaultLuminanceRange=True + +r.DefaultFeature.LocalExposure.HighlightContrastScale=0.8 + +r.DefaultFeature.LocalExposure.ShadowContrastScale=0.8 + +[/Script/WindowsTargetPlatform.WindowsTargetSettings] +DefaultGraphicsRHI=DefaultGraphicsRHI_DX12 +DefaultGraphicsRHI=DefaultGraphicsRHI_DX12 +-D3D12TargetedShaderFormats=PCD3D_SM5 ++D3D12TargetedShaderFormats=PCD3D_SM6 +-D3D11TargetedShaderFormats=PCD3D_SM5 ++D3D11TargetedShaderFormats=PCD3D_SM5 +Compiler=Default +AudioSampleRate=48000 +AudioCallbackBufferFrameSize=1024 +AudioNumBuffersToEnqueue=1 +AudioMaxChannels=0 +AudioNumSourceWorkers=4 +SpatializationPlugin= +SourceDataOverridePlugin= +ReverbPlugin= +OcclusionPlugin= +CompressionOverrides=(bOverrideCompressionTimes=False,DurationThreshold=5.000000,MaxNumRandomBranches=0,SoundCueQualityIndex=0) +CacheSizeKB=65536 +MaxChunkSizeOverrideKB=0 +bResampleForDevice=False +MaxSampleRate=48000.000000 +HighSampleRate=32000.000000 +MedSampleRate=24000.000000 +LowSampleRate=12000.000000 +MinSampleRate=8000.000000 +CompressionQualityModifier=1.000000 +AutoStreamingThreshold=0.000000 +SoundCueCookQualityIndex=-1 + +[/Script/LinuxTargetPlatform.LinuxTargetSettings] +-TargetedRHIs=SF_VULKAN_SM5 ++TargetedRHIs=SF_VULKAN_SM6 + +[/Script/HardwareTargeting.HardwareTargetingSettings] +TargetedHardwareClass=Desktop +AppliedTargetedHardwareClass=Desktop +DefaultGraphicsPerformance=Maximum +AppliedDefaultGraphicsPerformance=Maximum + +[/Script/WorldPartitionEditor.WorldPartitionEditorSettings] +CommandletClass=Class'/Script/UnrealEd.WorldPartitionConvertCommandlet' + +[/Script/Engine.UserInterfaceSettings] +bAuthorizeAutomaticWidgetVariableCreation=False +FontDPIPreset=Standard +FontDPI=72 + +[/Script/Engine.Engine] ++ActiveGameNameRedirects=(OldGameName="TP_Blank",NewGameName="/Script/EcsactBenchmark") ++ActiveGameNameRedirects=(OldGameName="/Script/TP_Blank",NewGameName="/Script/EcsactBenchmark") + +[/Script/AndroidFileServerEditor.AndroidFileServerRuntimeSettings] +bEnablePlugin=True +bAllowNetworkConnection=True +SecurityToken=636BE87843D087D62604C5917E6F5CA0 +bIncludeInShipping=False +bAllowExternalStartInShipping=False +bCompileAFSProject=False +bUseCompression=False +bLogFiles=False +bReportStats=False +ConnectionType=USBOnly +bUseManualIPAddress=False +ManualIPAddress= + diff --git a/unreal-cpp-benchmark/Config/DefaultGame.ini b/unreal-cpp-benchmark/Config/DefaultGame.ini new file mode 100644 index 0000000..9ad2e90 --- /dev/null +++ b/unreal-cpp-benchmark/Config/DefaultGame.ini @@ -0,0 +1,3 @@ + +[/Script/EngineSettings.GeneralProjectSettings] +ProjectID=96F09A7E4BCF19A5F9C692A8E6975C7C diff --git a/unreal-cpp-benchmark/Config/DefaultInput.ini b/unreal-cpp-benchmark/Config/DefaultInput.ini new file mode 100644 index 0000000..a919105 --- /dev/null +++ b/unreal-cpp-benchmark/Config/DefaultInput.ini @@ -0,0 +1,84 @@ +[/Script/Engine.InputSettings] +-AxisConfig=(AxisKeyName="Gamepad_LeftX",AxisProperties=(DeadZone=0.25,Exponent=1.f,Sensitivity=1.f)) +-AxisConfig=(AxisKeyName="Gamepad_LeftY",AxisProperties=(DeadZone=0.25,Exponent=1.f,Sensitivity=1.f)) +-AxisConfig=(AxisKeyName="Gamepad_RightX",AxisProperties=(DeadZone=0.25,Exponent=1.f,Sensitivity=1.f)) +-AxisConfig=(AxisKeyName="Gamepad_RightY",AxisProperties=(DeadZone=0.25,Exponent=1.f,Sensitivity=1.f)) +-AxisConfig=(AxisKeyName="MouseX",AxisProperties=(DeadZone=0.f,Exponent=1.f,Sensitivity=0.07f)) +-AxisConfig=(AxisKeyName="MouseY",AxisProperties=(DeadZone=0.f,Exponent=1.f,Sensitivity=0.07f)) +-AxisConfig=(AxisKeyName="Mouse2D",AxisProperties=(DeadZone=0.f,Exponent=1.f,Sensitivity=0.07f)) ++AxisConfig=(AxisKeyName="Gamepad_LeftX",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="Gamepad_LeftY",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="Gamepad_RightX",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="Gamepad_RightY",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MouseX",AxisProperties=(DeadZone=0.000000,Sensitivity=0.070000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MouseY",AxisProperties=(DeadZone=0.000000,Sensitivity=0.070000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="Mouse2D",AxisProperties=(DeadZone=0.000000,Sensitivity=0.070000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MouseWheelAxis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="Gamepad_LeftTriggerAxis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="Gamepad_RightTriggerAxis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="Gamepad_Special_Left_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="Gamepad_Special_Left_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="Vive_Left_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="Vive_Left_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="Vive_Left_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="Vive_Right_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="Vive_Right_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="Vive_Right_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MixedReality_Left_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MixedReality_Left_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MixedReality_Left_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MixedReality_Left_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MixedReality_Left_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MixedReality_Right_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MixedReality_Right_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MixedReality_Right_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MixedReality_Right_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MixedReality_Right_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="OculusTouch_Left_Grip_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="OculusTouch_Left_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="OculusTouch_Left_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="OculusTouch_Left_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="OculusTouch_Right_Grip_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="OculusTouch_Right_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="OculusTouch_Right_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="OculusTouch_Right_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="ValveIndex_Left_Grip_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="ValveIndex_Left_Grip_Force",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="ValveIndex_Left_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="ValveIndex_Left_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="ValveIndex_Left_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="ValveIndex_Left_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="ValveIndex_Left_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="ValveIndex_Left_Trackpad_Force",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="ValveIndex_Right_Grip_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="ValveIndex_Right_Grip_Force",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="ValveIndex_Right_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="ValveIndex_Right_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="ValveIndex_Right_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="ValveIndex_Right_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="ValveIndex_Right_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="ValveIndex_Right_Trackpad_Force",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) +bAltEnterTogglesFullscreen=True +bF11TogglesFullscreen=True +bUseMouseForTouch=False +bEnableMouseSmoothing=True +bEnableFOVScaling=True +bCaptureMouseOnLaunch=True +bEnableLegacyInputScales=True +bEnableMotionControls=True +bFilterInputByPlatformUser=False +bShouldFlushPressedKeysOnViewportFocusLost=True +bAlwaysShowTouchInterface=False +bShowConsoleOnFourFingerTap=True +bEnableGestureRecognizer=False +bUseAutocorrect=False +DefaultViewportMouseCaptureMode=CapturePermanently_IncludingInitialMouseDown +DefaultViewportMouseLockMode=LockOnCapture +FOVScale=0.011110 +DoubleClickTime=0.200000 +DefaultPlayerInputClass=/Script/EnhancedInput.EnhancedPlayerInput +DefaultInputComponentClass=/Script/EnhancedInput.EnhancedInputComponent +DefaultTouchInterface=/Engine/MobileResources/HUD/DefaultVirtualJoysticks.DefaultVirtualJoysticks +-ConsoleKeys=Tilde ++ConsoleKeys=Tilde + diff --git a/unreal-cpp-benchmark/Content/Blueprints/BP_EcsactBenchmarkMassSpawner.uasset b/unreal-cpp-benchmark/Content/Blueprints/BP_EcsactBenchmarkMassSpawner.uasset new file mode 100644 index 0000000000000000000000000000000000000000..c94e5e530583f1b7adbdf6d825f76cf7d4b8f8e4 GIT binary patch literal 22659 zcmd^Hdwf*Iy`P0B5FR4(5D{G>kART(gNR5Tn?N3rKoUeKB%AEnWMQ+r?ry*!B5lD^ zd=v$1i`rHy*NXOn^rqDg7sGy>9Zb@EIQAv4GMNU~^UU8KpH!m-@#F0~yn_q}3G7-LL7%jwwbbpUB z_Hl~PcDnDR--GlUF>~4vOD~zR=&9#|5AD9;;E0)9dv3Vh^;G4Jw>>fO1ju)bS zg@W;wnz$GCY9K(PrECE98#Qmx6Jv=?c4K?c69{Kl_=84secM{2JuLoSJ?DyZEM=9x z4v)_eHd2O6fWe!US4dR#_Tx367F zI{L$%t1be1Qh&2=xN|v(wlx}FcZJ^STeO;52^b3pQ=O5lP zOoGEkhdpmcod7VV=g`Uo;SQrHS#SKGOG$FW2J*8{z{lYKSLn)c5X!xiTu@r{+ zuQ88|gJG(DCck|z7S*7G)#fenyNniTpO$6aJ_N7)mikPOjJRmfuVME( zl0-Mz@BPavV81$#Z=JKl5Fh;b7+hL`8l2Q}VX^t>b(h0c70@)&=Et5~0FPSi zcXfLW3T)(P>ka8Rfs7lSpaY^2bARFep*3(xC@<~x!h>lKFrdL7S|OfYwSABUaFqyF zy=$NqQ6(gv{P<2UjJ?E9q377(XGg*}{VG5iwRiNQ#kBWwC@OpP;kPBYI~?c^BNWNr zF{10X#ghrUfqE#Jug>4@^m;bRjslTG0Vg@^m~hW_G@&ws@__UIZ{Mo(0fYA&!6rXE zRk}k}kSdC%y_fHSh}2)bV)@VR&w_}$i8mb#rh}f!Hin(Su-N(dphnoX(YfAmE%z83 z>fLU%&8DBe>V7?^8E!0J{)HAknh-<{IeQ=y!)L zo%s5DUcCoZLg8RHMe^NKzPdtU$!w%?a>QLHK`Gp6P(*#`H(P)cqufQF+vlRcm|zZ= zCB1+6BUh09wt=h~5*J*uHy{0_Ib^7DTO4kEX#v*ugz*RS9HKeL zI}9Fmr9bF(>4>T{5sxf;*oMJF%?aSp*^x$-f&CuXi3%I8FF;hRBMGK)2VBJ zZLCEfi4d>#gu0Bd8hh(JZ9yjuV~=Hy$U(Ctq4U*}sT&Xr6pHQ(ZV3A=a4HV!BKZE3 zU$#Wu3L2OrWykNh_m_~(8j(e4+sa9@LL7Y`cUA9(Bq|h_$?1X|L)WAqm7!~~5q3J9 zVW&8<<&jgQs8$1NV7D@8mb1-zrgw>?F?&J^)HDd4?DeAlFi*OCI>n?!GQ z3V3f2-trXju1pcHHAOsk9K1#iW7(m{syKM;2i#UzE0(5!cbxDr1|Y@rE2am$*$OQw z-Uoz-kdI`gM{78lSV!3Ta~fvFYtpbe`u-=vYmS4*`mWVwxHY7Rw=_jO=3$kOVOGA& zQl!Ui*&jW&RXjYe<^}t8B;jktn;!@7L#nUA@@5S~f7eQ49m)wH*4+xjGm(m-#pSpk z)0O^4IPf7Z4$!9$@rmtkihS+nkV>` z0!Rt`_Q)q83d;3EKetr)eXMzb6xLuE)4&V%yb9wmrRUB7zY~g-h{q3lg5M_0a4F5G zQTP6?$@Dv}E63wEn99KK6+BS-cD=gycTI)gsTg}=>}PxK*Zi*I0M!q}Wc*b=T{#X%XvQ2s6v=XM4hrT{+b zBabpXTWL@>Y2rGO#ewXdNtXg*H|<3xTTs}EV^RvV8u%8`sMIkVGW5UYHIc9)3njTJ zlw}Hyc`>F25eV;X5ljfosLc|8SAZ7rw5KZ#mLo_Kv(#aPYc**Sw z6k_rap=&PQQ53Z)DEB4$*D$J%+(?v=hNi0;DqEKLgI%<)$JARcz^c5?j*xVlf`Y=i z1tmrDxyn;6R{$se+}oQ*PKv*LF;d=3bzVVjz=L*XKOmkX`ob6^@R*R!@TOr z20r3u6U@tmu+2@qMrrPKWSOw6*Dac8i0}{vA5pT2$r@u3*{_Z4=n<6?_iAc^HnCAK z^;S_OHc%};S=q!j+aZ4GS(>^j(ZE_;`H+odL;Jc&*0m%n+B-lJ*|d)(E@xYratzm! z_4PEH7_H0diMpw4Gvxwg6>z43H&wKi#6VJrpr zra_jT#btHW3%O3b7Hf^PvQ3QF@|*2BMQjoasW8K-MoZhMFH@i2K5>tmx3rz{z-EM1o+*MjX}wYs(U zm^@Bb50;19b`jZaEqRNL24bZ}-x7|S$#uxk^>anJ$fIbSD=rg-^jt`uP$WvopGv4N z;;D+B%V_~Sm#|9cUQUo)s~VUnOZsI2mpJU zaWsDESS>?xO|muCOwlN=pjOGIzGME)AwP@}5||5^ zQ8^aQBMDnT*m#U$Pi2ZWn$WAVfz1IC2QV^WeqzQ1jy%@VDVB2P$?_%lwM1jm#4}`F zmV!sm2J*4BG~30T*c^+@9@`(@1zIkq8(+KW8Y@T63VBwQL$Sg|qhgyJ@ew)9T(lk5 z)66$a{X9(e$Bfb@CY>RB@QiJ#v;gMxeIXZWUOdMZHjWXjbpwrv-4t1Iog!zCh)A8% zU))riXTPWGi9Et!e%e9Q*UNe0mGq?6F*aI~DGyJKagoM2U0K-gmE{~-*G@SKY$P82 zm0zsoU>nBw9G+odZW?V<`x(-M?NCGBRZhJD>l4VI2tMTu@n!pfZ=-Ba%tNvAanaSZ zU!roJJ0-Utd$XIyVK-5>iA%KneZ86I@z%a)6H_&Qaz0!)Ks|Mx-Zj3{oo>wxt^6}3J_82r=@LuN`edF+i| z3!qPS(I3ZfURBw|%#^6Ihvm^+p@e4UCDcDIqhBG(nNP4HQ9!h-Bs`C16(}zuxPwab zsWhJ=A!hA1xnf0JO7274qpiCL*;F4on5_-FWcSgjhJ0JC(JxI&x9AyBE>X-Q-JlaB zS2H3&vGypSAGDuCYma#Iq(n2K*;ezKB2cH>{M4Ns7zp=a4v6a;;oWeWiq+98_9Cb!_qn zj(zQD?n+?pjlDUnsoZj{U#z9`6%jWWj#ZzAkS{1@e(UIcqeA; z3sR!Q{ilFDv4HwQA@v446;kggqNhUYImPsZ5v+j9is_EN1pH$9tB`#PZG5fBpa_;h zrK`khF`J%pbq*zY@;QTgWQHs&(D_20FOvCHk_zJ%>$15Tw?yZ2H6L&Q552hSQVmpqo7KP9C01xt+usNOU{8?;gfR6m)b&#yok-LTumL=-k3MA zUaWurTvzweEno5jXVwg{o!egdT?R>qCtzVDP<-S0LqViXllwz~q@wg?9#(yshbdj6 zwl{r<<+su??KaSsu~PeVI22fXJ~@ZJZI5`N+NJ-tkM?OqqS#(jAbm=;3R@1bYoHvU zjiSbSVQ$MX=1>^%t^RfB>%WB&k7FM3{I@XTZ~t8XHKqHk{1>w|wm4hJ>eJi`n9~ik zow=qNy9y(IiFF#sDfT!sc40O-Fs_9bUuC@tBfe^KEsVrBjJ!&cqSNxYqLe(Y=ri&- zQ@YQ}pENyJ37Q8O-c{sqW&^uh>^9>l!#zkxuB-lmC0 zo$<+zLT2^z=FbfJ|27>>>I!%b90D_3bV|txy6MnMh~Vm-8Y-nDX@)EEN=-<<>y$ZD zzW!1j!YeNIK5q|gNYl&qPH)Jd?Gv2%!6BfE*!O$zUXUuXo~BtsP&R<&v|*Nfxn>5J z#GEb2ipg6JWXzDSL@nv=T4n^io^~AE(g$2{Vh*o3<SxiBn|?%VNN8V9vJlQ!t0DUJNm{B!Q^EU%5{Mc&9D-y;&Ql7HSyq(B+Zv3~4xh6Au7R&=6~-N)1Cfew-ko6t_%6td-EEkYX!A zrJ>gZYw9`=tS(*AOljPT(sGHaPHO8%`2sIJZ&^^RA(!ZTADcrF{kE-q?NZ~Z8zK{u zRkmpg6koPQo>e#1Tl@8il&L}h?SrKvh+)hKBr zZyWN=c~1K}$G4ihC%$<2OGl!FkIHDuu*nSlJW=1-$hbqa-5PFbKUOO{>eDTAO$)>h6@AW6yUw^e{=>p~VC zS?NPKaFnGBt?^Xy!nlXThA2?kNb@5rso3dSn5eLoq{-KXR)ME!7;M2N1W3lkd&iC5 z(SCD=dacrAWyYscjTQ|OPYC$~MWK_~g#t_oE z7evx=P+ooD0>xGy8eQEI7DQo1XCxz5YZ#T~*;bWLzUr;&TVDU@>ib*fNn^*V9!)}N zcXDoYA-OXil9!EmFLUofw?Jtk-~7vb4ch05r{I64Z}WCLMtRJQ1#+oqs#+m8}{@$xo@7D zQu9dKOOH+UPLzjYQZY}-U1g15|DT(x@9R42zLW2Lw+!Zqg*mhc(y4)<4!BAO(qE(i zR6oKy&?QthU7ho_tAoCFebU#i&av9f)@U7s}9DyH|ZDTZ67C+}>6 zC?I86&{#O~Q4~_qH0y&M_Z5G*wR+dJ$ImPN%l4a~X)Fv!B{)SiEh7kj2P9p70>hpe zqK}PujX8m!(eA-lRA#29dktSlxYO=;+vzJJ&K`TF$7c^2?S7vtG?U!p3QgC}^keUd zj9|r+aUm;5CK*X{vdkcyl0}#rw147`_m_2kc-P|FUOqhi)?LHq#DifF;uNt6rabBh zw;iXq)Ah4D&n-cAb@aMBXr!k%bsBd1xCJd4?ey&-G8S1w4l+cAmBt9nY~-B_qJS|O zm^4#=!ejoN+}Zdl0`7f2XEHw{V|GQ<7iH$-BN%Eeu7sDT(3yUeC`oqJsTH=Ct8c z92c2!Dw=F{3_o=IXCE%U=|1C~bDrI|37W*hKKb~Ed8!`&)c%q^@=*^vc9`t?D`P2) zgVtlqQZcL7v8MgqQ|iG?1SUBDr(gWdZF~0C?%5W2%y#$kL-AnPpyL#2;86srz{h3M zu?yIN52;~jL`o=l!U9!KUa`c>&5Uvu?TI;@?N@p>nr}eBb-} z%g??PIJo5Y_8snzj(y`qJlJJY8+D0v3S@0#bqQ;(v+8F3mQ7SaKbh1cHxY^#5aPk& zc5DdpDNd)jOUDbPk~P@lAwhy3CqD2V`t!WMEZTO#Tfjvb8$TVSalX`kr?RA2c@ z*E1=V>pOF@#qJ@TJ0a_;0G-`@NdwQ~Gq5|d_NLVG%N4N~R2ZwHp z4I?B>o1*li|MIJZ!MLHjjs5|dtq_`h_#B|l=&%3rx6ZOUWu;G#a$IEqoTsFv*O62B oMD8K_obVkV?%R?z@5e7dR^B4hG{pMDbC;(5{D(6+$N~TV0UPXW8~^|S literal 0 HcmV?d00001 diff --git a/unreal-cpp-benchmark/Content/Maps/Benchmark.umap b/unreal-cpp-benchmark/Content/Maps/Benchmark.umap new file mode 100644 index 0000000000000000000000000000000000000000..59f3b19ddcfa57d651be2cd8d4e983a01a7ef459 GIT binary patch literal 8926 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 literal 0 HcmV?d00001 diff --git a/unreal-cpp-benchmark/EcsactBenchmark.uproject b/unreal-cpp-benchmark/EcsactBenchmark.uproject new file mode 100644 index 0000000..9832c72 --- /dev/null +++ b/unreal-cpp-benchmark/EcsactBenchmark.uproject @@ -0,0 +1,26 @@ +{ + "FileVersion": 3, + "EngineAssociation": "5.5", + "Category": "", + "Description": "", + "Modules": [ + { + "Name": "EcsactBenchmark", + "Type": "Runtime", + "LoadingPhase": "Default" + } + ], + "Plugins": [ + { + "Name": "ModelingToolsEditorMode", + "Enabled": true, + "TargetAllowList": [ + "Editor" + ] + }, + { + "Name": "MassGameplay", + "Enabled": true + } + ] +} \ No newline at end of file diff --git a/unreal-cpp-benchmark/Plugins/Ecsact b/unreal-cpp-benchmark/Plugins/Ecsact new file mode 160000 index 0000000..e0e9f2c --- /dev/null +++ b/unreal-cpp-benchmark/Plugins/Ecsact @@ -0,0 +1 @@ +Subproject commit e0e9f2ca6622fe31d5a20bcf2d5de652c0ac91ad diff --git a/unreal-cpp-benchmark/Source/EcsactBenchmark.Target.cs b/unreal-cpp-benchmark/Source/EcsactBenchmark.Target.cs new file mode 100644 index 0000000..43abcdc --- /dev/null +++ b/unreal-cpp-benchmark/Source/EcsactBenchmark.Target.cs @@ -0,0 +1,15 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +using UnrealBuildTool; +using System.Collections.Generic; + +public class EcsactBenchmarkTarget : TargetRules +{ + public EcsactBenchmarkTarget(TargetInfo Target) : base(Target) + { + Type = TargetType.Game; + DefaultBuildSettings = BuildSettingsVersion.V5; + IncludeOrderVersion = EngineIncludeOrderVersion.Unreal5_5; + ExtraModuleNames.Add("EcsactBenchmark"); + } +} diff --git a/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmark.Build.cs b/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmark.Build.cs new file mode 100644 index 0000000..5657b46 --- /dev/null +++ b/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmark.Build.cs @@ -0,0 +1,23 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +using UnrealBuildTool; + +public class EcsactBenchmark : ModuleRules +{ + public EcsactBenchmark(ReadOnlyTargetRules Target) : base(Target) + { + PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; + + PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "EnhancedInput", "MassEntity", "Ecsact", "MassSpawner" }); + + PrivateDependencyModuleNames.AddRange(new string[] { }); + + // Uncomment if you are using Slate UI + // PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" }); + + // Uncomment if you are using online features + // PrivateDependencyModuleNames.Add("OnlineSubsystem"); + + // To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true + } +} diff --git a/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmark.cpp b/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmark.cpp new file mode 100644 index 0000000..75d4321 --- /dev/null +++ b/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmark.cpp @@ -0,0 +1,8 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "EcsactBenchmark.h" +#include "EcsactUnreal/EcsactGameModuleImpl.h" +#include "Modules/ModuleManager.h" + +IMPLEMENT_PRIMARY_GAME_MODULE(FEcsactGameModuleImpl, EcsactBenchmark, + "EcsactBenchmark"); diff --git a/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmark.ecsact b/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmark.ecsact new file mode 100644 index 0000000..9f17bc0 --- /dev/null +++ b/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmark.ecsact @@ -0,0 +1,12 @@ +main package benchmark; + +component Counter { + i32 value; +} +component MassOnly; + +system IterateCounter { + exclude MassOnly; + readwrite Counter; +} + diff --git a/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmark.ecsact.hh b/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmark.ecsact.hh new file mode 100644 index 0000000..b89e28d --- /dev/null +++ b/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmark.ecsact.hh @@ -0,0 +1,29 @@ +// GENERATED FILE - DO NOT EDIT +#pragma once + +#include +#include +#include "ecsact/runtime/common.h" + +namespace benchmark { + +struct Counter { + static constexpr bool transient = false; + static constexpr bool has_assoc_fields = false; + static constexpr auto id = static_cast(1); + int32_t value; + auto operator<=>(const benchmark::Counter&) const = default; +}; +struct MassOnly { + static constexpr bool transient = false; + static constexpr bool has_assoc_fields = false; + static constexpr auto id = static_cast(2); + auto operator<=>(const benchmark::MassOnly&) const = default; +}; +struct IterateCounter { + static constexpr auto id = static_cast(3); + struct context; + static void impl(context&); +}; + +}// namespace benchmark diff --git a/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmark.h b/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmark.h new file mode 100644 index 0000000..677c8e2 --- /dev/null +++ b/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmark.h @@ -0,0 +1,6 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" + diff --git a/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmarkMassSpawner.cpp b/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmarkMassSpawner.cpp new file mode 100644 index 0000000..4f59b98 --- /dev/null +++ b/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmarkMassSpawner.cpp @@ -0,0 +1,89 @@ + +#include "EcsactBenchmarkMassSpawner.h" +#include "EcsactBenchmark/EcsactBenchmark.ecsact.hh" +#include "EcsactBenchmark/EcsactBenchmark__ecsact__ue.h" +#include "EcsactUnreal/EcsactRunner.h" +#include "ecsact/si/wasm.h" +#include + +auto UEcsactBenchmarkMassSpawner::CreateMassEntities(int count, bool UseEcsact) + -> void { + auto runner = GetRunner(); + + for (int i = 0; i < count; ++i) { + if (UseEcsact) { + runner->CreateEntity() + .AddComponent(benchmark::Counter{.value = 0}) + .OnCreate(TDelegate::CreateLambda( // + [](auto entity) { + UE_LOG(LogTemp, Warning, TEXT("Ecsact entity %i created"), + static_cast(entity)); + })); + } else { + runner->CreateEntity() + .AddComponent(benchmark::Counter{.value = 0}) + .AddComponent(benchmark::MassOnly{}) + .OnCreate(TDelegate::CreateLambda( // + [](auto entity) { + UE_LOG(LogTemp, Warning, TEXT("Mass entity %i created"), + static_cast(entity)); + })); + } + } +} +auto UEcsactBenchmarkMassSpawner::LoadWASMFiles() -> void { + auto cwd = FString{std::filesystem::current_path().string().c_str()}; + + UE_LOG(LogTemp, Log, TEXT("CWD %s"), *cwd); + auto file_path = + FString{"C:/Users/Austin/Documents/programming/ecsact/ecsact-examples/" + "unreal-cpp-benchmark/Binaries/SystemImpls.wasm"}; + + auto err = ecsact_si_wasm_load_file( + const_cast(TCHAR_TO_UTF8(*file_path)), + EcsactUnreal::CodegenMeta::BenchmarkSystemLikeIds.size(), + const_cast( + EcsactUnreal::CodegenMeta::BenchmarkSystemLikeIds.data()), + const_cast( + EcsactUnreal::CodegenMeta::BenchmarkExportNames.data())); + + if (err != ECSACT_SI_WASM_OK) { +#define HANDLE_ECSACT_SI_ERROR_CASE(err) \ + case err: \ + UE_LOG(LogTemp, Error, TEXT("ecsact_si_wasm_load_file error: " #err)); \ + break + switch (err) { + HANDLE_ECSACT_SI_ERROR_CASE(ECSACT_SI_WASM_ERR_FILE_OPEN_FAIL); + HANDLE_ECSACT_SI_ERROR_CASE(ECSACT_SI_WASM_ERR_FILE_READ_FAIL); + HANDLE_ECSACT_SI_ERROR_CASE(ECSACT_SI_WASM_ERR_COMPILE_FAIL); + HANDLE_ECSACT_SI_ERROR_CASE(ECSACT_SI_WASM_ERR_INSTANTIATE_FAIL); + HANDLE_ECSACT_SI_ERROR_CASE(ECSACT_SI_WASM_ERR_EXPORT_NOT_FOUND); + HANDLE_ECSACT_SI_ERROR_CASE(ECSACT_SI_WASM_ERR_EXPORT_INVALID); + HANDLE_ECSACT_SI_ERROR_CASE(ECSACT_SI_WASM_ERR_GUEST_IMPORT_UNKNOWN); + HANDLE_ECSACT_SI_ERROR_CASE(ECSACT_SI_WASM_ERR_GUEST_IMPORT_INVALID); + HANDLE_ECSACT_SI_ERROR_CASE(ECSACT_SI_WASM_ERR_INITIALIZE_FAIL); + HANDLE_ECSACT_SI_ERROR_CASE(ECSACT_SI_WASM_ERR_NO_SET_SYSTEM_EXECUTION); + case ECSACT_SI_WASM_OK: + break; + } +#undef HANDLE_ECSACT_SI_ERROR_CASE + } else { + + UE_LOG(LogTemp, Log, TEXT("yay")); + } +} + +auto UEcsactBenchmarkMassSpawner::InitCounter_Implementation( + int32 Entity, FBenchmarkCounter Counter) -> void { + Super::InitCounter_Implementation(Entity, Counter); + + UE_LOG(LogTemp, Log, TEXT("Counter started on entity %i"), Entity); +} + +auto UEcsactBenchmarkMassSpawner::UpdateCounter_Implementation( + int32 Entity, FBenchmarkCounter Counter) -> void { + Super::UpdateCounter_Implementation(Entity, Counter); + + UE_LOG(LogTemp, Log, TEXT("Counter updated on entity %i to %i"), Entity, + Counter.Value); +} diff --git a/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmarkMassSpawner.h b/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmarkMassSpawner.h new file mode 100644 index 0000000..b9b701c --- /dev/null +++ b/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmarkMassSpawner.h @@ -0,0 +1,25 @@ +#pragma once + +#include "CoreMinimal.h" + +#include "EcsactBenchmark__ecsact__mass__ue.h" +#include "EcsactBenchmark__ecsact__ue.h" + +#include "EcsactBenchmarkMassSpawner.generated.h" + +UCLASS(Abstract) +class UEcsactBenchmarkMassSpawner : public UOneToOneBenchmarkMassSpawner { + GENERATED_BODY() + +public: + UFUNCTION(BlueprintCallable) + void CreateMassEntities(int count, bool UseEcsact); + + UFUNCTION(BlueprintCallable) + void LoadWASMFiles(); + + void InitCounter_Implementation(int32 Entity, + FBenchmarkCounter counter) override; + void UpdateCounter_Implementation(int32 Entity, + FBenchmarkCounter counter) override; +}; diff --git a/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmark__ecsact__mass__ue.cpp b/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmark__ecsact__mass__ue.cpp new file mode 100644 index 0000000..6d99a25 --- /dev/null +++ b/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmark__ecsact__mass__ue.cpp @@ -0,0 +1,128 @@ +#include "EcsactBenchmark__ecsact__mass__ue.h" +#include "Engine/World.h" +#include "MassEntitySubsystem.h" +#include "MassSpawnerSubsystem.h" +#include "MassCommandBuffer.h" + +void UBenchmarkMassSpawner::InitCounter_Implementation(int32 Entity, FBenchmarkCounter Counter) + { + auto* world = GetWorld(); + check(world); + + auto& entity_manager = world->GetSubsystem()->GetMutableEntityManager(); + auto entity_handles = GetEcsactMassEntityHandles(Entity); + for(auto entity_handle : entity_handles) { + entity_manager.Defer().AddFragment(entity_handle); + entity_manager.Defer().PushCommand(entity_handle, FBenchmarkCounterFragment{Counter}); + + } +} +void UBenchmarkMassSpawner::UpdateCounter_Implementation(int32 Entity, FBenchmarkCounter Counter) + { + auto* world = GetWorld(); + check(world); + + auto& entity_manager = world->GetSubsystem()->GetMutableEntityManager(); + auto entity_handles = GetEcsactMassEntityHandles(Entity); + for(auto entity_handle : entity_handles) { + entity_manager.Defer().PushCommand([this, Entity, entity_handle, Counter](FMassEntityManager& entity_manager) + { + auto fragment = entity_manager.GetFragmentDataPtr(entity_handle); + if(!fragment) { + UE_LOG(Ecsact, Warning, TEXT("%s fragment FBenchmarkCounterFragment does not exist for entity %i"), *GetClass()->GetName(), Entity); + return; + } + fragment->component = Counter; + + }); + + } +} +void UBenchmarkMassSpawner::RemoveCounter_Implementation(int32 Entity, FBenchmarkCounter Counter) + { + auto* world = GetWorld(); + check(world); + + auto& entity_manager = world->GetSubsystem()->GetMutableEntityManager(); + auto entity_handles = GetEcsactMassEntityHandles(Entity); + for(auto entity_handle : entity_handles) { + entity_manager.Defer().RemoveFragment(entity_handle); + + } +} +void UBenchmarkMassSpawner::InitMassonly_Implementation(int32 Entity, FBenchmarkMassonly Massonly) + { + auto* world = GetWorld(); + check(world); + + auto& entity_manager = world->GetSubsystem()->GetMutableEntityManager(); + auto entity_handles = GetEcsactMassEntityHandles(Entity); + for(auto entity_handle : entity_handles) { + entity_manager.Defer().AddTag(entity_handle); + + } +} +void UBenchmarkMassSpawner::RemoveMassonly_Implementation(int32 Entity, FBenchmarkMassonly Massonly) + { + auto* world = GetWorld(); + check(world); + + auto& entity_manager = world->GetSubsystem()->GetMutableEntityManager(); + auto entity_handles = GetEcsactMassEntityHandles(Entity); + for(auto entity_handle : entity_handles) { + entity_manager.Defer().RemoveTag(entity_handle); + + } +} +auto UBenchmarkMassSpawner::GetEcsactMassEntityHandles(int32 Entity) -> TArray { + UE_LOG(LogTemp, Error, TEXT("GetEcsactMassEntityHandless must be implemented for EcsactMassEntitySpawner")); + return TArray{}; + +} +auto UOneToOneBenchmarkMassSpawner::EntityCreated_Implementation(int32 Entity) -> void { + auto* world = GetWorld(); + check(world); + + auto* config = GetEntityMassConfig(); + if(!config) { + UE_LOG(Ecsact, Warning, TEXT("%s GetEntityMassConfig() returned null"), *GetClass()->GetName()); + return; + } + const auto& entity_template = config->GetOrCreateEntityTemplate(*world); + auto new_entity_handles = TArray{}; + + auto mass_spawner = world->GetSubsystem(); + auto& entity_manager = world->GetSubsystem()->GetMutableEntityManager(); + + mass_spawner->SpawnEntities(entity_template, 1, new_entity_handles); + MassEntities.Add(static_cast(Entity), new_entity_handles); + for(auto entity_handle : new_entity_handles) { + entity_manager.Defer().AddFragment(entity_handle); + entity_manager.Defer().PushCommand(entity_handle, FEcsactEntityFragment{static_cast(Entity)}); + ; + + } +}auto UOneToOneBenchmarkMassSpawner::EntityDestroyed_Implementation(int32 Entity) -> void { + auto* world = GetWorld(); + check(world); + + auto& entity_manager = world->GetSubsystem()->GetMutableEntityManager(); + + auto old_entity_handles = TArray{}; + MassEntities.RemoveAndCopyValue(static_cast(Entity),old_entity_handles); + for(auto entity_handle : old_entity_handles) { + entity_manager.Defer().DestroyEntity(entity_handle); + + } +} +auto UOneToOneBenchmarkMassSpawner::GetEcsactMassEntityHandles(int32 Entity) -> TArray { + auto handles = MassEntities.Find(static_cast(Entity)); + if(!handles) return {}; + return *handles; + +} +auto UOneToOneBenchmarkMassSpawner::GetEntityMassConfig() const -> UMassEntityConfigAsset* + { + return MassEntityConfigAsset; + +} \ No newline at end of file diff --git a/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmark__ecsact__mass__ue.h b/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmark__ecsact__mass__ue.h new file mode 100644 index 0000000..ba40f9e --- /dev/null +++ b/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmark__ecsact__mass__ue.h @@ -0,0 +1,66 @@ +#pragma once + +#include "CoreMinimal.h" +#include "MassEntityTypes.h" +#include "MassEntityConfigAsset.h" +#include "ecsact/runtime/common.h" +#include "EcsactBenchmark__ecsact__ue.h" +#include "EcsactBenchmark.ecsact.hh" +#include "EcsactBenchmark__ecsact__mass__ue.generated.h" + +USTRUCT() +struct FEcsactEntityFragment : public FMassFragment { + GENERATED_BODY() + FEcsactEntityFragment() = default; + FEcsactEntityFragment(const ecsact_entity_id EntityId) : id(EntityId) {} + + ecsact_entity_id GetId() const { + return id; + + } + private: + ecsact_entity_id id; +}; +USTRUCT() +struct FBenchmarkCounterFragment : public FMassFragment { + GENERATED_BODY() + + FBenchmarkCounterFragment() = default; + FBenchmarkCounterFragment(FBenchmarkCounter in_component) : component(in_component){} + + FBenchmarkCounter component; +}; +USTRUCT() +struct FBenchmarkMassonlyFragment : public FMassTag { + GENERATED_BODY() + +}; + +UCLASS(Abstract) +class UBenchmarkMassSpawner : public UBenchmarkEcsactRunnerSubsystem { + GENERATED_BODY() + + public: + virtual auto GetEcsactMassEntityHandles(int32 Entity) -> TArray; + void InitCounter_Implementation(int32 Entity, FBenchmarkCounter Counter) override; + void UpdateCounter_Implementation(int32 Entity, FBenchmarkCounter Counter) override; + void RemoveCounter_Implementation(int32 Entity, FBenchmarkCounter Counter) override; + void InitMassonly_Implementation(int32 Entity, FBenchmarkMassonly Massonly) override; + void RemoveMassonly_Implementation(int32 Entity, FBenchmarkMassonly Massonly) override; + +}; + +UCLASS(Abstract) +class UOneToOneBenchmarkMassSpawner : public UBenchmarkMassSpawner { + GENERATED_BODY() + + TMap> MassEntities; + protected: + UPROPERTY(EditAnywhere) + UMassEntityConfigAsset* MassEntityConfigAsset; + auto EntityCreated_Implementation(int32 Entity) -> void override; + auto EntityDestroyed_Implementation(int32 Entity) -> void override; + auto GetEcsactMassEntityHandles(int32 Entity) -> TArray override; + virtual auto GetEntityMassConfig() const -> UMassEntityConfigAsset*; + +}; diff --git a/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmark__ecsact__ue.cpp b/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmark__ecsact__ue.cpp new file mode 100644 index 0000000..de874ef --- /dev/null +++ b/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmark__ecsact__ue.cpp @@ -0,0 +1,77 @@ +#include "EcsactBenchmark__ecsact__ue.h" +FBenchmarkCounter FBenchmarkCounter::FromEcsactComponentData(const void* component_data) { + auto result = FBenchmarkCounter{}; + result.Value = static_cast(component_data)->value; + return result; +} +FBenchmarkMassonly FBenchmarkMassonly::FromEcsactComponentData(const void* component_data) { + auto result = FBenchmarkMassonly{}; + return result; +} +UBenchmarkEcsactRunnerSubsystem::UBenchmarkEcsactRunnerSubsystem() { + InitComponentFns.Init(nullptr, 3); + UpdateComponentFns.Init(nullptr, 3); + RemoveComponentFns.Init(nullptr, 3); + InitComponentFns[1] = &ThisClass::RawInitCounter; + UpdateComponentFns[1] = &ThisClass::RawUpdateCounter; + RemoveComponentFns[1] = &ThisClass::RawRemoveCounter; + InitComponentFns[2] = &ThisClass::RawInitMassonly; + UpdateComponentFns[2] = &ThisClass::RawUpdateMassonly; + RemoveComponentFns[2] = &ThisClass::RawRemoveMassonly; + +} + +void UBenchmarkEcsactRunnerSubsystem::InitComponentRaw( ecsact_entity_id entity, ecsact_component_id component_id, const void* component_data) { + (this->*InitComponentFns[static_cast(component_id)])(static_cast(entity), component_data); +} + +void UBenchmarkEcsactRunnerSubsystem::UpdateComponentRaw( ecsact_entity_id entity, ecsact_component_id component_id, const void* component_data) { + (this->*UpdateComponentFns[static_cast(component_id)])(static_cast(entity), component_data); +} + +void UBenchmarkEcsactRunnerSubsystem::RemoveComponentRaw( ecsact_entity_id entity, ecsact_component_id component_id, const void* component_data) { + (this->*RemoveComponentFns[static_cast(component_id)])(static_cast(entity), component_data); +} + +void UBenchmarkEcsactRunnerSubsystem::RawInitCounter(int32 entity, const void* component) { + InitCounter(entity, FBenchmarkCounter::FromEcsactComponentData(component)); +} +void UBenchmarkEcsactRunnerSubsystem::RawUpdateCounter(int32 entity, const void* component) { + UpdateCounter(entity, FBenchmarkCounter::FromEcsactComponentData(component)); +} +void UBenchmarkEcsactRunnerSubsystem::RawRemoveCounter(int32 entity, const void* component) { + RemoveCounter(entity, FBenchmarkCounter::FromEcsactComponentData(component)); +} +void UBenchmarkEcsactRunnerSubsystem::RawInitMassonly(int32 entity, const void* component) { + InitMassonly(entity, FBenchmarkMassonly::FromEcsactComponentData(component)); +} +void UBenchmarkEcsactRunnerSubsystem::RawUpdateMassonly(int32 entity, const void* component) { + UpdateMassonly(entity, FBenchmarkMassonly::FromEcsactComponentData(component)); +} +void UBenchmarkEcsactRunnerSubsystem::RawRemoveMassonly(int32 entity, const void* component) { + RemoveMassonly(entity, FBenchmarkMassonly::FromEcsactComponentData(component)); +} +void UBenchmarkEcsactRunnerSubsystem::InitCounter_Implementation(int32 Entity, FBenchmarkCounter Counter) { + +} + +void UBenchmarkEcsactRunnerSubsystem::UpdateCounter_Implementation(int32 Entity, FBenchmarkCounter Counter) { + +} + +void UBenchmarkEcsactRunnerSubsystem::RemoveCounter_Implementation(int32 Entity, FBenchmarkCounter Counter) { + +} + +void UBenchmarkEcsactRunnerSubsystem::InitMassonly_Implementation(int32 Entity, FBenchmarkMassonly Massonly) { + +} + +void UBenchmarkEcsactRunnerSubsystem::UpdateMassonly_Implementation(int32 Entity, FBenchmarkMassonly Massonly) { + +} + +void UBenchmarkEcsactRunnerSubsystem::RemoveMassonly_Implementation(int32 Entity, FBenchmarkMassonly Massonly) { + +} + diff --git a/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmark__ecsact__ue.h b/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmark__ecsact__ue.h new file mode 100644 index 0000000..1f9563f --- /dev/null +++ b/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmark__ecsact__ue.h @@ -0,0 +1,83 @@ +#pragma once + +#include "CoreMinimal.h" +#include "UObject/Interface.h" +#include +#include "ecsact/runtime/common.h" +#include "EcsactUnreal/Ecsact.h" +#include "EcsactUnreal/EcsactRunnerSubsystem.h" +#include "EcsactBenchmark.ecsact.hh" +#include "EcsactBenchmark__ecsact__ue.generated.h" + + +namespace EcsactUnreal::CodegenMeta { + constexpr auto BenchmarkSystemLikeIds = std::array{ + static_cast(3 /* benchmark.IterateCounter */), + }; + + constexpr auto BenchmarkExportNames = std::array{ + "benchmark__IterateCounter", + }; + +} + +USTRUCT(BlueprintType) +struct FBenchmarkCounter { + GENERATED_BODY() + + static FBenchmarkCounter FromEcsactComponentData(const void*); + UPROPERTY(EditAnywhere, BlueprintReadWrite) + int32 Value; + +}; + +USTRUCT(BlueprintType) +struct FBenchmarkMassonly { + GENERATED_BODY() + + static FBenchmarkMassonly FromEcsactComponentData(const void*); + +}; + +UCLASS(Abstract, Blueprintable, meta = (DisplayName = "Ecsact Runner Package Subsystem (benchmark)")) +class UBenchmarkEcsactRunnerSubsystem : public UEcsactRunnerSubsystem { + GENERATED_BODY() // NOLINT + + TArray InitComponentFns; + TArray UpdateComponentFns; + TArray RemoveComponentFns; + void RawInitCounter(int32 Entity, const void* Component); + void RawUpdateCounter(int32 Entity, const void* Component); + void RawRemoveCounter(int32 Entity, const void* Component); + void RawInitMassonly(int32 Entity, const void* Component); + void RawUpdateMassonly(int32 Entity, const void* Component); + void RawRemoveMassonly(int32 Entity, const void* Component); + +protected: + void InitComponentRaw(ecsact_entity_id, ecsact_component_id, const void*) override; + void UpdateComponentRaw(ecsact_entity_id, ecsact_component_id, const void*) override; + void RemoveComponentRaw(ecsact_entity_id, ecsact_component_id, const void*) override; + + +public: + UBenchmarkEcsactRunnerSubsystem(); + UFUNCTION(BlueprintNativeEvent, Category = "Ecsact Runner", meta = (DisplayName = "Init benchmark.Counter")) + void InitCounter(int32 Entity, FBenchmarkCounter Counter); + virtual void InitCounter_Implementation(int32 Entity, FBenchmarkCounter Counter); + UFUNCTION(BlueprintNativeEvent, Category = "Ecsact Runner", meta = (DisplayName = "Update benchmark.Counter")) + void UpdateCounter(int32 Entity, FBenchmarkCounter Counter); + virtual void UpdateCounter_Implementation(int32 Entity, FBenchmarkCounter Counter); + UFUNCTION(BlueprintNativeEvent, Category = "Ecsact Runner", meta = (DisplayName = "Remove benchmark.Counter")) + void RemoveCounter(int32 Entity, FBenchmarkCounter Counter); + virtual void RemoveCounter_Implementation(int32 Entity, FBenchmarkCounter Counter); + UFUNCTION(BlueprintNativeEvent, Category = "Ecsact Runner", meta = (DisplayName = "Init benchmark.MassOnly")) + void InitMassonly(int32 Entity, FBenchmarkMassonly Massonly); + virtual void InitMassonly_Implementation(int32 Entity, FBenchmarkMassonly Massonly); + UFUNCTION(BlueprintNativeEvent, Category = "Ecsact Runner", meta = (DisplayName = "Update benchmark.MassOnly")) + void UpdateMassonly(int32 Entity, FBenchmarkMassonly Massonly); + virtual void UpdateMassonly_Implementation(int32 Entity, FBenchmarkMassonly Massonly); + UFUNCTION(BlueprintNativeEvent, Category = "Ecsact Runner", meta = (DisplayName = "Remove benchmark.MassOnly")) + void RemoveMassonly(int32 Entity, FBenchmarkMassonly Massonly); + virtual void RemoveMassonly_Implementation(int32 Entity, FBenchmarkMassonly Massonly); + +}; diff --git a/unreal-cpp-benchmark/Source/EcsactBenchmark/Fragments/NoEcsactFragment.h b/unreal-cpp-benchmark/Source/EcsactBenchmark/Fragments/NoEcsactFragment.h new file mode 100644 index 0000000..e69de29 diff --git a/unreal-cpp-benchmark/Source/EcsactBenchmark/Processors/MassBenchmarkProcessor.cpp b/unreal-cpp-benchmark/Source/EcsactBenchmark/Processors/MassBenchmarkProcessor.cpp new file mode 100644 index 0000000..fb3f126 --- /dev/null +++ b/unreal-cpp-benchmark/Source/EcsactBenchmark/Processors/MassBenchmarkProcessor.cpp @@ -0,0 +1,43 @@ +#include "MassBenchmarkProcessor.h" +#include "../EcsactBenchmark__ecsact__mass__ue.h" +#include "EcsactBenchmark/EcsactBenchmark__ecsact__ue.h" +#include "MassArchetypeTypes.h" +#include "MassEntityView.h" +#include "MassExecutionContext.h" +#include "MassRequirements.h" + +UMassBenchmarkProcessor::UMassBenchmarkProcessor() : EntityQuery(*this) {} + +void UMassBenchmarkProcessor::ConfigureQueries() { + + EntityQuery.AddRequirement( + EMassFragmentAccess::ReadWrite); + EntityQuery.AddRequirement( + EMassFragmentAccess::ReadOnly); +} + +void UMassBenchmarkProcessor::Execute(FMassEntityManager &EntityManager, + FMassExecutionContext &Context) { + + EntityQuery.ForEachEntityChunk( // + EntityManager, Context, [](FMassExecutionContext &context) { + const auto entity_num = context.GetNumEntities(); + auto counter_fragments = + context.GetMutableFragmentView(); + + const auto entity_fragments = + context.GetFragmentView(); + + for (int i = 0; i < entity_num; ++i) { + + auto &counter_fragment = counter_fragments[i]; + auto entity_id = static_cast(entity_fragments[i].GetId()); + + counter_fragment.component.Value += 1; + + UE_LOG(LogTemp, Warning, + TEXT("MASS: Updated entity %i counter to %i"), entity_id, + counter_fragment.component.Value); + } + }); +} diff --git a/unreal-cpp-benchmark/Source/EcsactBenchmark/Processors/MassBenchmarkProcessor.h b/unreal-cpp-benchmark/Source/EcsactBenchmark/Processors/MassBenchmarkProcessor.h new file mode 100644 index 0000000..575699a --- /dev/null +++ b/unreal-cpp-benchmark/Source/EcsactBenchmark/Processors/MassBenchmarkProcessor.h @@ -0,0 +1,22 @@ + +#pragma once +#include "MassEntityQuery.h" +#include "MassProcessor.h" + +#include "MassBenchmarkProcessor.generated.h" + +UCLASS() +class ECSACTBENCHMARK_API UMassBenchmarkProcessor : public UMassProcessor { + GENERATED_BODY() + +public: + UMassBenchmarkProcessor(); + +protected: + virtual void ConfigureQueries() override; + virtual void Execute(FMassEntityManager &EntityManager, + FMassExecutionContext &Context) override; + +private: + FMassEntityQuery EntityQuery; +}; diff --git a/unreal-cpp-benchmark/Source/EcsactBenchmarkEditor.Target.cs b/unreal-cpp-benchmark/Source/EcsactBenchmarkEditor.Target.cs new file mode 100644 index 0000000..a5793e9 --- /dev/null +++ b/unreal-cpp-benchmark/Source/EcsactBenchmarkEditor.Target.cs @@ -0,0 +1,15 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +using UnrealBuildTool; +using System.Collections.Generic; + +public class EcsactBenchmarkEditorTarget : TargetRules +{ + public EcsactBenchmarkEditorTarget( TargetInfo Target) : base(Target) + { + Type = TargetType.Editor; + DefaultBuildSettings = BuildSettingsVersion.V5; + IncludeOrderVersion = EngineIncludeOrderVersion.Unreal5_5; + ExtraModuleNames.Add("EcsactBenchmark"); + } +} diff --git a/unreal-cpp-benchmark/SystemImpls/EcsactSystemImpls.cpp b/unreal-cpp-benchmark/SystemImpls/EcsactSystemImpls.cpp new file mode 100644 index 0000000..139094d --- /dev/null +++ b/unreal-cpp-benchmark/SystemImpls/EcsactSystemImpls.cpp @@ -0,0 +1,10 @@ + +#include "generated/EcsactBenchmark.ecsact.hh" +#include "generated/EcsactBenchmark.ecsact.systems.hh" + +auto benchmark::IterateCounter::impl(context &ctx) -> void { + auto counter = ctx.get(); + + counter.value += 1; + ctx.update(counter); +} diff --git a/unreal-cpp-benchmark/SystemImpls/generated/EcsactBenchmark.ecsact.hh b/unreal-cpp-benchmark/SystemImpls/generated/EcsactBenchmark.ecsact.hh new file mode 100644 index 0000000..05e9804 --- /dev/null +++ b/unreal-cpp-benchmark/SystemImpls/generated/EcsactBenchmark.ecsact.hh @@ -0,0 +1,23 @@ +// GENERATED FILE - DO NOT EDIT +#pragma once + +#include +#include +#include "ecsact/runtime/common.h" + +namespace benchmark { + +struct Counter { + static constexpr bool transient = false; + static constexpr bool has_assoc_fields = false; + static constexpr auto id = static_cast(1); + int32_t value; + auto operator<=>(const benchmark::Counter&) const = default; +}; +struct IterateCounter { + static constexpr auto id = static_cast(2); + struct context; + static void impl(context&); +}; + +}// namespace benchmark diff --git a/unreal-cpp-benchmark/SystemImpls/generated/EcsactBenchmark.ecsact.systems.cc b/unreal-cpp-benchmark/SystemImpls/generated/EcsactBenchmark.ecsact.systems.cc new file mode 100644 index 0000000..07b5ac2 --- /dev/null +++ b/unreal-cpp-benchmark/SystemImpls/generated/EcsactBenchmark.ecsact.systems.cc @@ -0,0 +1,6 @@ +// GENERATED FILE - DO NOT EDIT +#include "EcsactBenchmark.ecsact.systems.hh" +void benchmark__IterateCounter (struct ecsact_system_execution_context* cctx) { + benchmark::IterateCounter::context ctx{cctx}; + benchmark::IterateCounter::impl(ctx); +} diff --git a/unreal-cpp-benchmark/SystemImpls/generated/EcsactBenchmark.ecsact.systems.h b/unreal-cpp-benchmark/SystemImpls/generated/EcsactBenchmark.ecsact.systems.h new file mode 100644 index 0000000..bffafbb --- /dev/null +++ b/unreal-cpp-benchmark/SystemImpls/generated/EcsactBenchmark.ecsact.systems.h @@ -0,0 +1,12 @@ +// GENERATED FILE - DO NOT EDIT +#ifndef BENCHMARK_H +#define BENCHMARK_H + +#include "ecsact/runtime/common.h" + + +ECSACT_EXTERN +ECSACT_EXPORT("benchmark__IterateCounter") +void benchmark__IterateCounter(struct ecsact_system_execution_context*); + +#endif // BENCHMARK_H diff --git a/unreal-cpp-benchmark/SystemImpls/generated/EcsactBenchmark.ecsact.systems.hh b/unreal-cpp-benchmark/SystemImpls/generated/EcsactBenchmark.ecsact.systems.hh new file mode 100644 index 0000000..ad64458 --- /dev/null +++ b/unreal-cpp-benchmark/SystemImpls/generated/EcsactBenchmark.ecsact.systems.hh @@ -0,0 +1,53 @@ +// GENERATED FILE - DO NOT EDIT +#pragma once + +#include +#include "ecsact/cpp/execution_context.hh" +#include "EcsactBenchmark.ecsact.hh" +#include "EcsactBenchmark.ecsact.systems.h" + + +struct ecsact_system_execution_context; + +struct benchmark::IterateCounter::context { + [[no_unique_address]] ::ecsact::execution_context _ctx; + + template + auto get(AssocFields&&... assoc_fields) -> T { + // local type to make static assert always fail + struct codegen_error {}; + static_assert(std::is_same_v, + "| [Ecsact C++ Error]: System Execution Context Misuse\n" + "| benchmark.IterateCounter context.get may only be called with a component\n" + "| readable by the system. Did you forget to add readonly or readwrite\n" + "| capabilities? The following components are allowed:\n" + "| - benchmark.Counter\n" + "| \n"); + } + + template + auto update(const T& updated_component, AssocFields&&... assoc_fields) -> void { + // local type to make static assert always fail + struct codegen_error {}; + static_assert(std::is_same_v, + "| [Ecsact C++ Error]: System Execution Context Misuse\n" + "| benchmark.IterateCounter context.update may only be called with a\n" + "| component writable by the system. Did you forget to add readwrite capabilities? The\n" + "| following components are allowed:\n" + "| - benchmark.Counter\n" + "| \n"); + } + + template<> auto get() -> benchmark::Counter { + return _ctx.get(); + } + template<> auto update(const benchmark::Counter& updated_component) -> void { + _ctx.update(updated_component); + } + auto entity() const -> ecsact_entity_id { + return _ctx.entity(); + } + + + +}; From fae3ae3bc445231f13bba3b5f7316b1349ba86e7 Mon Sep 17 00:00:00 2001 From: Kelwan Date: Sat, 8 Feb 2025 08:40:34 -0800 Subject: [PATCH 2/4] feat: Benchmarks for mass end ecsact ready for measuring --- unreal-cpp-benchmark/Config/DefaultEcsact.ini | 2 +- unreal-cpp-benchmark/Config/DefaultEngine.ini | 3 +- .../BP_EcsactBenchmarkMassSpawner.uasset | Bin 22659 -> 32984 bytes .../Content/Blueprints/BP_StartButton.uasset | Bin 0 -> 57375 bytes .../Content/Blueprints/StartButton.uasset | Bin 0 -> 2545 bytes .../Content/Maps/Benchmark.umap | Bin 8926 -> 27887 bytes .../Content/Mass/BenchmarkConfig.uasset | Bin 1615 -> 2233 bytes .../EcsactBenchmarkMassSpawner.cpp | 127 +++++++++++++----- .../EcsactBenchmarkMassSpawner.h | 45 ++++++- .../EcsactBenchmark/EcsactBenchmarkRunner.cpp | 0 .../EcsactBenchmark/EcsactBenchmarkRunner.h | 12 ++ .../Processors/MassBenchmarkProcessor.cpp | 9 +- .../Content/Blueprints/ConnectMenu.uasset | Bin 59260 -> 58396 bytes 13 files changed, 150 insertions(+), 48 deletions(-) create mode 100644 unreal-cpp-benchmark/Content/Blueprints/BP_StartButton.uasset create mode 100644 unreal-cpp-benchmark/Content/Blueprints/StartButton.uasset create mode 100644 unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmarkRunner.cpp create mode 100644 unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmarkRunner.h diff --git a/unreal-cpp-benchmark/Config/DefaultEcsact.ini b/unreal-cpp-benchmark/Config/DefaultEcsact.ini index 795cf93..98ad987 100644 --- a/unreal-cpp-benchmark/Config/DefaultEcsact.ini +++ b/unreal-cpp-benchmark/Config/DefaultEcsact.ini @@ -4,7 +4,7 @@ CustomEcsactRuntimeLibraryPath= BuildReportFilter=None +Recipes=rt_entt +Recipes=si_wasmer -Runner=Automatic +Runner=Custom CustomRunnerClass=None bAutoCollectBlueprintRunnerSubsystems=True +RunnerSubsystems=/Game/Blueprints/BP_EcsactBenchmarkMassSpawner.BP_EcsactBenchmarkMassSpawner_C diff --git a/unreal-cpp-benchmark/Config/DefaultEngine.ini b/unreal-cpp-benchmark/Config/DefaultEngine.ini index 4884f74..ffd1b77 100644 --- a/unreal-cpp-benchmark/Config/DefaultEngine.ini +++ b/unreal-cpp-benchmark/Config/DefaultEngine.ini @@ -1,7 +1,8 @@ [/Script/EngineSettings.GameMapsSettings] -GameDefaultMap=/Engine/Maps/Templates/OpenWorld +GameDefaultMap=/Game/Maps/Benchmark.Benchmark +EditorStartupMap=/Game/Maps/Benchmark.Benchmark [/Script/Engine.RendererSettings] r.AllowStaticLighting=False diff --git a/unreal-cpp-benchmark/Content/Blueprints/BP_EcsactBenchmarkMassSpawner.uasset b/unreal-cpp-benchmark/Content/Blueprints/BP_EcsactBenchmarkMassSpawner.uasset index c94e5e530583f1b7adbdf6d825f76cf7d4b8f8e4..a6ecd220c167d232084cb10c33c6b9617090f254 100644 GIT binary patch literal 32984 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 diff --git a/unreal-cpp-benchmark/Content/Blueprints/BP_StartButton.uasset b/unreal-cpp-benchmark/Content/Blueprints/BP_StartButton.uasset new file mode 100644 index 0000000000000000000000000000000000000000..ab7d4e04717eeb6307051bf4aacfcca7abf4a879 GIT binary patch literal 57375 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 CW3dwe literal 0 HcmV?d00001 diff --git a/unreal-cpp-benchmark/Content/Blueprints/StartButton.uasset b/unreal-cpp-benchmark/Content/Blueprints/StartButton.uasset new file mode 100644 index 0000000000000000000000000000000000000000..0ceeb1e2bb1a38f24e1e5e3edb192b917efe2770 GIT binary patch literal 2545 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 literal 8926 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 delta 554 zcmdlfc%Em11S8`_U2&!$)`@Pad;$y%3<-=t0tikrO^)MGpSXY}@FWuh0}wG}GBYr+ zfMpmMJV6W~2n5m~oCw6>lclF!dM@j_f48f_?k;Vu+;|Bkg*`L8=KChd9gR|M2N?`9 zM_}UDV5R9m4bp5NBM{&}5CpL@FmM8e*7LF@C5dD5RXA?3=8UZ?Pr;6&kUH z0>jOTb#evUN;M!0ZY)?KNDByXKq#=gSSR0Q6_@e^i2$Py43MQ+CNp#Bh`}5VqruA9 PCL6K|GqO*P -auto UEcsactBenchmarkMassSpawner::CreateMassEntities(int count, bool UseEcsact) - -> void { - auto runner = GetRunner(); +UEcsactBenchmarkMassSpawner::UEcsactBenchmarkMassSpawner() {} + +auto UEcsactBenchmarkMassSpawner::CreateEcsactEntities(int count) -> void { + + registry.emplace("Benchmark"); + evc.emplace(); + + evc->set_init_callback( + [this](auto entity_id, const auto comp) { + this->InitCounter(entity_id, comp); + }); + + evc->set_update_callback( + [this](auto entity_id, const auto comp) { + this->UpdateCounter(entity_id, comp); + }); + + auto exec_options = ecsact::core::execution_options{}; for (int i = 0; i < count; ++i) { - if (UseEcsact) { - runner->CreateEntity() - .AddComponent(benchmark::Counter{.value = 0}) - .OnCreate(TDelegate::CreateLambda( // - [](auto entity) { - UE_LOG(LogTemp, Warning, TEXT("Ecsact entity %i created"), - static_cast(entity)); - })); - } else { - runner->CreateEntity() - .AddComponent(benchmark::Counter{.value = 0}) - .AddComponent(benchmark::MassOnly{}) - .OnCreate(TDelegate::CreateLambda( // - [](auto entity) { - UE_LOG(LogTemp, Warning, TEXT("Mass entity %i created"), - static_cast(entity)); - })); - } + auto entity = registry->create_entity(); + + auto benchmark_counter = benchmark::Counter{.value = 0}; + + exec_options.add_component(entity, &benchmark_counter); + } + auto exec_err = registry->execute_systems(std::array{exec_options}, *evc); + if (exec_err != ECSACT_EXEC_SYS_OK) { + UE_LOG(LogTemp, Error, TEXT("Ecsact system execution failed")); + } else { + UE_LOG(LogTemp, Log, TEXT("ECSACT: Created %i entities"), count); } } + +auto UEcsactBenchmarkMassSpawner::CreateMassEntities(int count) -> void { + auto *world = GetWorld(); + check(world); + + const auto &entity_template = config->GetOrCreateEntityTemplate(*world); + auto new_entity_handles = TArray{}; + + auto mass_spawner = world->GetSubsystem(); + + for (int i = 0; i < count; ++i) { + mass_spawner->SpawnEntities(entity_template, 1, new_entity_handles); + mass_entities.Add(new_entity_handles[0]); + } + UE_LOG(LogTemp, Log, TEXT("MASS: Created %i entities"), count); +} + auto UEcsactBenchmarkMassSpawner::LoadWASMFiles() -> void { auto cwd = FString{std::filesystem::current_path().string().c_str()}; @@ -67,23 +99,54 @@ auto UEcsactBenchmarkMassSpawner::LoadWASMFiles() -> void { break; } #undef HANDLE_ECSACT_SI_ERROR_CASE - } else { - - UE_LOG(LogTemp, Log, TEXT("yay")); } } -auto UEcsactBenchmarkMassSpawner::InitCounter_Implementation( - int32 Entity, FBenchmarkCounter Counter) -> void { - Super::InitCounter_Implementation(Entity, Counter); +auto UEcsactBenchmarkMassSpawner::InitCounter( // + ecsact_entity_id Entity, const benchmark::Counter &) -> void { UE_LOG(LogTemp, Log, TEXT("Counter started on entity %i"), Entity); } -auto UEcsactBenchmarkMassSpawner::UpdateCounter_Implementation( - int32 Entity, FBenchmarkCounter Counter) -> void { - Super::UpdateCounter_Implementation(Entity, Counter); +auto UEcsactBenchmarkMassSpawner::UpdateCounter( // + ecsact_entity_id Entity, const benchmark::Counter &counter) -> void { + + UE_LOG(LogTemp, Log, TEXT("Counter update on entity %i to %i"), Entity, + counter.value); +} + +auto UEcsactBenchmarkMassSpawner::ExecuteSystems(int count) -> void { + for (int i = 0; i < count; ++i) { + registry->execute_systems(1, *evc); + } +} + +void UEcsactBenchmarkMassSpawner::StartMassSpawner( // + UObject *WorldContext, EcsactBenchmarkType BenchmarkType) { + UE_LOG(LogTemp, Warning, TEXT("BENCHMARKTYPE: %s"), + *UEnum::GetValueAsString(BenchmarkType)); - UE_LOG(LogTemp, Log, TEXT("Counter updated on entity %i to %i"), Entity, - Counter.Value); + auto *world = WorldContext->GetWorld(); + check(world); + + auto ecsact_game_subsystem = + world->GetGameInstance()->GetSubsystem(); + check(ecsact_game_subsystem); + + ecsact_game_subsystem->StartCustomRunner(); + auto runner = EcsactUnrealExecution::Runner(world); + + if (!runner.IsValid()) { + UE_LOG(LogTemp, Error, TEXT("Provided runner is invalid")); + return; + } + + auto mass_spawner_subsystem = + runner->GetSubsystem(); + + if (mass_spawner_subsystem) { + mass_spawner_subsystem->OnStartButtonPressed(BenchmarkType); + } else { + UE_LOG(LogTemp, Error, TEXT("BenchmarkMassSpawner can't be found")); + } } diff --git a/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmarkMassSpawner.h b/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmarkMassSpawner.h index b9b701c..dbc1adc 100644 --- a/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmarkMassSpawner.h +++ b/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmarkMassSpawner.h @@ -1,25 +1,58 @@ #pragma once +#include +#include + #include "CoreMinimal.h" +#include "MassEntityConfigAsset.h" +#include "ecsact/runtime/core.hh" #include "EcsactBenchmark__ecsact__mass__ue.h" #include "EcsactBenchmark__ecsact__ue.h" #include "EcsactBenchmarkMassSpawner.generated.h" +UENUM(BlueprintType) +enum class EcsactBenchmarkType : uint8 { + EcsactCounter UMETA(DisplayName = "Ecsact Counter"), + MassCounter UMETA(DisplayName = "Mass Counter") +}; + UCLASS(Abstract) -class UEcsactBenchmarkMassSpawner : public UOneToOneBenchmarkMassSpawner { +class UEcsactBenchmarkMassSpawner : public UBenchmarkMassSpawner { GENERATED_BODY() + UEcsactBenchmarkMassSpawner(); + + std::optional registry; + std::optional> evc; + + TArray entities; + TArray mass_entities; + + UPROPERTY(EditAnywhere) + UMassEntityConfigAsset *config; public: + UFUNCTION(BlueprintCallable, Meta = (WorldContext = "WorldContext")) + static void StartMassSpawner(UObject *WorldContext, + EcsactBenchmarkType BenchmarkType); + + UFUNCTION(BlueprintCallable) + void CreateMassEntities(int count); + UFUNCTION(BlueprintCallable) - void CreateMassEntities(int count, bool UseEcsact); + void CreateEcsactEntities(int count); UFUNCTION(BlueprintCallable) void LoadWASMFiles(); - void InitCounter_Implementation(int32 Entity, - FBenchmarkCounter counter) override; - void UpdateCounter_Implementation(int32 Entity, - FBenchmarkCounter counter) override; + UFUNCTION(BlueprintCallable) + void ExecuteSystems(int count); + + void InitCounter(ecsact_entity_id Entity, const benchmark::Counter &Counter); + void UpdateCounter(ecsact_entity_id Entity, + const benchmark::Counter &Counter); + + UFUNCTION(BlueprintImplementableEvent) + void OnStartButtonPressed(EcsactBenchmarkType BenchmarkType); }; diff --git a/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmarkRunner.cpp b/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmarkRunner.cpp new file mode 100644 index 0000000..e69de29 diff --git a/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmarkRunner.h b/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmarkRunner.h new file mode 100644 index 0000000..d608517 --- /dev/null +++ b/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmarkRunner.h @@ -0,0 +1,12 @@ +#pragma once + +#include "CoreMinimal.h" +#include "EcsactUnreal/EcsactRunner.h" + +#include "EcsactBenchmarkRunner.generated.h" + +UCLASS() + +class ECSACTBENCHMARK_API UEcsactBenchmarkRunner : public UEcsactRunner { + GENERATED_BODY() +}; diff --git a/unreal-cpp-benchmark/Source/EcsactBenchmark/Processors/MassBenchmarkProcessor.cpp b/unreal-cpp-benchmark/Source/EcsactBenchmark/Processors/MassBenchmarkProcessor.cpp index fb3f126..544af2d 100644 --- a/unreal-cpp-benchmark/Source/EcsactBenchmark/Processors/MassBenchmarkProcessor.cpp +++ b/unreal-cpp-benchmark/Source/EcsactBenchmark/Processors/MassBenchmarkProcessor.cpp @@ -12,8 +12,6 @@ void UMassBenchmarkProcessor::ConfigureQueries() { EntityQuery.AddRequirement( EMassFragmentAccess::ReadWrite); - EntityQuery.AddRequirement( - EMassFragmentAccess::ReadOnly); } void UMassBenchmarkProcessor::Execute(FMassEntityManager &EntityManager, @@ -25,18 +23,13 @@ void UMassBenchmarkProcessor::Execute(FMassEntityManager &EntityManager, auto counter_fragments = context.GetMutableFragmentView(); - const auto entity_fragments = - context.GetFragmentView(); - for (int i = 0; i < entity_num; ++i) { auto &counter_fragment = counter_fragments[i]; - auto entity_id = static_cast(entity_fragments[i].GetId()); counter_fragment.component.Value += 1; - UE_LOG(LogTemp, Warning, - TEXT("MASS: Updated entity %i counter to %i"), entity_id, + UE_LOG(LogTemp, Warning, TEXT("MASS: Updated entity counter to %i"), counter_fragment.component.Value); } }); diff --git a/unreal-cpp-floppybots/Content/Blueprints/ConnectMenu.uasset b/unreal-cpp-floppybots/Content/Blueprints/ConnectMenu.uasset index 3e669a56cff3b171d303bac7e841421768032343..98ce114ec36adff12ed4b94c6b13d49614054e74 100644 GIT binary patch delta 4892 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 From 975ef8b8cbfbac493a2352c1907e41e9423e08d6 Mon Sep 17 00:00:00 2001 From: Kelwan Date: Sat, 8 Feb 2025 09:04:18 -0800 Subject: [PATCH 3/4] chore: Change to Ecsact engine plugin --- unreal-cpp-benchmark/EcsactBenchmark.uproject | 11 ++++++++++- unreal-cpp-benchmark/Plugins/Ecsact | 1 - 2 files changed, 10 insertions(+), 2 deletions(-) delete mode 160000 unreal-cpp-benchmark/Plugins/Ecsact diff --git a/unreal-cpp-benchmark/EcsactBenchmark.uproject b/unreal-cpp-benchmark/EcsactBenchmark.uproject index 9832c72..106e5be 100644 --- a/unreal-cpp-benchmark/EcsactBenchmark.uproject +++ b/unreal-cpp-benchmark/EcsactBenchmark.uproject @@ -3,6 +3,11 @@ "EngineAssociation": "5.5", "Category": "", "Description": "", + "PreBuildSteps": { + "Win64": [ + "EcsactUnrealCodegen $(ProjectDir) --engine-dir $(EngineDir) || exit /b 1" + ] + }, "Modules": [ { "Name": "EcsactBenchmark", @@ -21,6 +26,10 @@ { "Name": "MassGameplay", "Enabled": true + }, + { + "Name": "Ecsact", + "Enabled": true } ] -} \ No newline at end of file +} diff --git a/unreal-cpp-benchmark/Plugins/Ecsact b/unreal-cpp-benchmark/Plugins/Ecsact deleted file mode 160000 index e0e9f2c..0000000 --- a/unreal-cpp-benchmark/Plugins/Ecsact +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e0e9f2ca6622fe31d5a20bcf2d5de652c0ac91ad From 09654ddcf6a6eeadd9702a85e17478fff206b1b8 Mon Sep 17 00:00:00 2001 From: Kelwan Date: Sat, 8 Feb 2025 16:51:43 -0800 Subject: [PATCH 4/4] feat: Testing mass vs Ecsact --- unreal-cpp-benchmark/.clang-format | 99 +++++++ .../BP_EcsactBenchmarkMassSpawner.uasset | Bin 32984 -> 30500 bytes .../Content/Maps/Benchmark.umap | Bin 27887 -> 27887 bytes .../Content/Mass/BenchmarkConfig.uasset | Bin 2233 -> 2390 bytes .../EcsactBenchmarkMassSpawner.cpp | 258 ++++++++++-------- .../EcsactBenchmarkMassSpawner.h | 53 ++-- .../EcsactBenchmark/EcsactBenchmarkRunner.cpp | 33 +++ .../EcsactBenchmark/EcsactBenchmarkRunner.h | 11 +- .../Fragments/MassCounterFragments.h | 11 + .../Fragments/NoEcsactFragment.h | 0 .../Processors/MassBenchmarkProcessor.cpp | 57 ++-- 11 files changed, 350 insertions(+), 172 deletions(-) create mode 100644 unreal-cpp-benchmark/.clang-format create mode 100644 unreal-cpp-benchmark/Source/EcsactBenchmark/Fragments/MassCounterFragments.h delete mode 100644 unreal-cpp-benchmark/Source/EcsactBenchmark/Fragments/NoEcsactFragment.h diff --git a/unreal-cpp-benchmark/.clang-format b/unreal-cpp-benchmark/.clang-format new file mode 100644 index 0000000..b090ef9 --- /dev/null +++ b/unreal-cpp-benchmark/.clang-format @@ -0,0 +1,99 @@ +AccessModifierOffset: -2 +AlignAfterOpenBracket: BlockIndent +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: true +AlignEscapedNewlines: Left +AlignOperands: DontAlign +AlignTrailingComments: false +AllowAllArgumentsOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: WithoutElse +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: false +BinPackParameters: false +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: false +BreakAfterJavaFieldAnnotations: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeInheritanceComma: false +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeComma +BreakConstructorInitializersBeforeComma: false +BreakStringLiterals: true +ColumnLimit: 80 +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 2 +ContinuationIndentWidth: 2 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +IncludeBlocks: Preserve +IncludeIsMainRegex: "(Test)?$" +IndentCaseLabels: true +IndentPPDirectives: AfterHash +IndentWidth: 2 +IndentWrappedFunctionNames: false +InsertBraces: true +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: "" +MacroBlockEnd: "" +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +PackConstructorInitializers: NextLine +PenaltyBreakAssignment: 10 +PenaltyBreakBeforeFirstCallParameter: 30 +PenaltyBreakComment: 10 +PenaltyBreakFirstLessLess: 0 +PenaltyBreakString: 10 +PenaltyExcessCharacter: 400 +PenaltyReturnTypeOnItsOwnLine: 350 +PointerAlignment: Left +ReflowComments: true +RequiresClausePosition: OwnLine +SortIncludes: false +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: Never +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: Never +SpacesInContainerLiterals: false +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +SeparateDefinitionBlocks: Always +Standard: Latest +TabWidth: 2 +UseTab: ForContinuationAndIndentation diff --git a/unreal-cpp-benchmark/Content/Blueprints/BP_EcsactBenchmarkMassSpawner.uasset b/unreal-cpp-benchmark/Content/Blueprints/BP_EcsactBenchmarkMassSpawner.uasset index a6ecd220c167d232084cb10c33c6b9617090f254..67269be1c477f3fd559ad98c341bd00082109e97 100644 GIT binary patch delta 5649 zcmcIodr*|u75_d3VR=86UEXixDeUrwM0a_YH%Jg!VPSa)3WykAD6n7>+w_rYPMc_x zsdlDyCYdyiLuxWwQ`$*tGU;@poiV8yQ<BG#YH3n$(W;ocrBx`G8&EkMzKP_ug}U z_uPA4_kOz{O|1I)9r4I-R*98I-^%maFCeWF1QDD29xyr{4=JK+wHFTW_zFSarw3PLmT?(LoYw^+M+vc>r?E>;T%{T%_@c;BFyNUDjHxPFNx zEQcFd9%mJ3;T_8Zh0hSzw?f?GE5z*TUVg)8sf|=#I?ydzCIf+bTujL zm4Upa#vX2Pg}9vyaBTf8oGDvL7I!WH(okMFoXZH;vjk2K*H?&B+s8@vD}e#_fsCuf zWv&ocv?PxE{~qqpxFk>#{tIy$J2)(BMsgS^bX`l}@%9GdTJ7NE zknG_yYN*DE3{u0M_HZVYF#DGS%9EGF$$7LKPWBe!YHWLy7um--}Nb1UHqDbvK89OO3LnGfxWb&R<)V4p&USEAsCA9uJJ7}ESXI!!i}B!nhqgrq)gkkBM^#}DC2 zPJQB2pEQ%4wnr_EZ^DkC9@jtMU5oz$q*iL-UQpbcOE|h+F&PouECx)WE+-5F{W%NX ztgV>*LCA+%e-&q^3wrr)avyQNx76^&XgA2En#6^L zP*ayRZ`~A93a`}pB+FO^ZICDMmKvs&!eoFObrC9gYa7A4K5DIP_NNZ&jwTktruz6f zC~}xnHe!cJ)<_;K17oY!%6uWK_G2J)E^nz}d-?}1DTA1-k|P!&5jeYn3zhLu0wYN- z<$j11jYY|i04Er0)oO%f0wXE6&RiP)l*@U4OJra1$;LfFfBxj#*XM1}02Y6LXWBt3 ze7G^u&nAo{Wk_i--Vmj+vG3x(y(NjzNFpzrh`4Ux){tnmv9Km)MKK25n1-LKNPN_= zBn#szC>G|>FHvcjvCv!4n5xYtbLh;x@fupsZ0fy*TrIw1j2qJahTTZyZi&K2*!%vi zeo=AQBhu@ji`2VZxF{x4=0;baeN!R8nc!NifDj?jiF*19BYhC zK8zDICR8W5u3~A-6ee=D%6!SCRENR6&Z-iIm@kb4D+e@S*> zc0qAgX=ZUjZb4RQc4z!wb;?CkH}-Q6W%+-GU37(-8_xm8Yz z)nMJN_hRe<_9XFOv$Tn1s2yF0?+-e0Gl)&mO{^zl;KV*>)j}^1bri$-wif%I z{$ac1>0Fp@k8^CBA|VYHy&Y2~EGss}cP1$L7gv&FtKJ+w|JX|hUB5EGJxix8^@ci5 zGGoF)*Qv5`Et}a6;oZ(;W=OwkE?ef=0DtXjP_5$;m`k)6H;RN_M+7^D@*SG`|E|WV zC9Cn+R*LdVTj$(?m534U>1oTdUyB7frMbnK8HJe{CFzCw?2M8UeXcIMFsHaAuOvg4 z2M>C53MU%jsor)e6F|EyL*c}QCFcr%+?If4=W8-3P>w3j70zsbLS?_$c4492?b{Un zP1Kko56cG}t(gH z3f?@7=taqG>a@?D!~VvjzUSUZy|U+wJzg=zSE9RYvNV??hHL=GK#1cfVg=;Z@GiAsmk z3mOr9A-ZjPZRAg{zgRx`@$`XDpYyop3El^@l;tdXz=?x7iG)4Qlk+Rk0tBoh5%BlY-`uF7QbCe)2) z2GAy^A59y0&#W&#^PM-#x=zJi@Py-|hm=OZp0QkJ!m0f7m;ZYqwd%RxzOw9f!Lu}b xAukJlIT{Q987rNq;U`vd%Lmp3`ufS<1M@%}FHljXiTI&Wf;06>VE=gg{{W<^wh{mU delta 6425 zcmcgw3sjWH6`o&F0Red|%fkghk%!1*U$6@zKd)6}0bxZ20T&TO5k+}4+BA!)CAB>o zJ-5-OdfIBzq)|_zB~8-!sGdGFO-nRQYO5y|O-)RE#Gdw~CfeA0|9}23-f_s-0{GxN{#{B7aSTgL4?KJHxEu9N0~O$^I8#sq`_e|W1q0cH!{rBkq(63kc( zp+93M!ez=gA{hG?KKt=`C+4>Y`}{N|Pu<*o_>Qj4lC*VG?=vfp6@7Qdi5I@wUon+j zlAlemMX*heie&8h9&Eal2UyOPF;;`JpZ4^9E|iZCBa5QPni{)0n{1mpI-A-$*wtUG zd!nys!e1siR&e8MXt;*gMUDj2B^6g*n=E1?M*>g0bzCoUByi(77qU+P?!15EMDn;^WC;(M?!w!}pl(r^C^3afu1gR(~ zAYL<E@6Ll8K?!&gL;8|v5EpwxR3!%X# zQw}1fk&Cs6N_~3;QsN;p#Gr2FYH!3p@cJD^tx0{0i|*mbc~#1HJa14W3i#AdR7zgI z3`v}Rlha9~tV*Ju=Vq)*qOMUHpkM9hTRlmZpO?iKRR%R3#pCgzab2VemRWU@)q+r2 zJpo0eKI%nE#=IH^sVAa{)Qa<;H%V&6Idw_uXSsDi+aPOF(X*GUU)&(6f1ozN+%P}i zclnU=yCt!2m_bcvJHvLzexMSAi_Hk2KzqdZ<37ZJ&b6f_7T z(@Y4d{RtcjU*)w8Kj^T`R|C3;xQWkT<9JzLZA7&YnuSiiFb4Ejhu?ETYv1o8FN94| z#5$%$VGis}nb~()_xtg%CnY)|P+|(q!ZxvHwvu(TF2qG_GwYOU>ktLD0F6=#3YeZ1 zu>xjd8O)3pMy%@)GtqGoVivA9J-+q$XGWQc%|i*jGm&dVKPAwg6yYs!(9)8?g9$MaN()&fUwsN9lH!dAwEt zlS?$S(wuTR_EJo%xR5U%90Kkhs3@5&WWy6BnoykweFeNyV(_ov8nP&d)7G$PN+>NF zwt!w(Tq#SDqM2J(w$10(PkO`^;k^yvy^UgtOk_zM3Hb8v$rZUUnPUMstj0n8rl8Z= z$qG-REmFuF2_%oSYD5Sxo#vwq%LZa;Y`jPeDg(nDC}da&Pn9M-q@qL$n2qePC>|*m z^C74uh-nhiAP<>-qkgw^)>aHJJcqZ z>Y9mk+a}p(BqJ+{)AA`c!=f4M$xXY0)fiMPi^W&e+aYz1;8^8D5tgnlt=HT_2D&Om zJ-Sj!BhX@l3XP!U1`;G`x+IgOaoE+QUJ~H2aZk&I_@j7`uM9+t6VSz7GIV!A6ZJR= zGm@h|c=wB@L38k$Y!iCO4=^sPL7pkkV6f;A zOnQsaoMFi`nGITfp}Eim11r*oxI4VaE|h_Pl@{(b>V5Jhk94|NtE5hC$-;HmRaGlg zL##~&w^k;*aAKQ?BZP$Em8lmlG+BI#xqYHCXxj`3T(VKnOV*z>=TBd#^uUppHLuEm zGex8JRo@I9E?b&NXD(bUr7Roam8CI3A{RT80|QG{x?!_%2O~IaHiG_Gl9AI?TsI%= z**y_&Hs^?7tM-@~App*Igg|tSRj8Dv8&&U~JwLc#83;nU-N^=dGeEPC{j>X<6Il!h>nS)%h9UKLGoy zG!Pi#jqAV*UapTDaq35WQhDy2%icCaI(g4dfvW8MxDWEPB$2e^aaL@bd$cwtTh=-7E`{-Txit81Thn zN0;*bJ>$c_OxJj&6NQlyVqA#aKBU~Npi z^CPBk5T&#%L?6zS(-$su*pC=|r!6o?ba6meU@CO0_C0kp@OE#AxGU(`>!}yJUh^a? z!Vg+FeAecJCs1CnY66YF5U(WmBx3hXn>K0Njikaok+sWb#eMaQL3+EqSdjGMV_+MGoJFR2T*9lFwK+CJ-$$h{HJ z3ZO#2-*43%dA$GCeZ_s31~y;W?e}2-EZbllbXv!>`@!uEh9qJiy%dvvt>TyYThC^- z>dx$`^&~6Bct!Y-hKl?2{o(zMnHYrFju8INBmQ*f{Y^Gw^bbj1m4R+o$*{931rA&3 zbA&e*`3-kF)(;vm-8Gx5Rq%dioHXbcvWgGhKa*bz6 diff --git a/unreal-cpp-benchmark/Content/Maps/Benchmark.umap b/unreal-cpp-benchmark/Content/Maps/Benchmark.umap index e07989bb411bfdf24b8aecf8c3d6b60c964bfe0e..3304a809a915140820731e0ce0f378e947d30e9c 100644 GIT binary patch delta 103 zcmaEVlkxpc#tqvT1rB@VS2aFq1_p)_Mj!zM511#%ai~vRz+&-$nSlX_7!+6;7&yQ(3=9Qq zAT@$m2+L-unGySuCwTN=c#5)p<(i6W1D;)w#Dse(Iz{vkVP|ME1 zzz-BqJ3jO zFK3qJ6^5Gi2WXVoTB62E3!#Vc3@+fEWxV6xO%cJ ztGJjTRFWG=Z-KIPIN%C9SZzclpu$W*+6l^jF!?6yOx6Zqpyf_3XIsSz3iEH1)!1Vv hA7mGq?8dIk`2*-WkSHh6g(8zDup2V+O+Li_9RSLkXe$5! delta 376 zcmca6v{P_`3yUE;1H}KpKP{fLKgfIa9&&qI>VNuZP+Xsqsy`Bf%&+@oTVB8Bns71EK*& z{s#h(-F!fSPL9o4j9QGF7cvPmPCm^n%L#T2P~y*IM;3Wr81ENQi}2(`Hfcto$$~8E zjAD}$S=4#OU?u`-ez2_AW3)2!0Ny#K3R}Wn9+H%D%(s}6QK7LCm&{8B?Jnc bGGu+MlP|D4Oy18fFj;}aj*)kAJjZtcxfe=f diff --git a/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmarkMassSpawner.cpp b/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmarkMassSpawner.cpp index 80f3d89..60a55c1 100644 --- a/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmarkMassSpawner.cpp +++ b/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmarkMassSpawner.cpp @@ -10,143 +10,161 @@ #include "Logging/LogVerbosity.h" #include "MassEntitySubsystem.h" #include "MassSpawnerSubsystem.h" +#include "Fragments/MassCounterFragments.h" #include "ecsact/si/wasm.h" #include -UEcsactBenchmarkMassSpawner::UEcsactBenchmarkMassSpawner() {} +UEcsactBenchmarkMassSpawner::UEcsactBenchmarkMassSpawner() { +} auto UEcsactBenchmarkMassSpawner::CreateEcsactEntities(int count) -> void { - - registry.emplace("Benchmark"); - evc.emplace(); - - evc->set_init_callback( - [this](auto entity_id, const auto comp) { - this->InitCounter(entity_id, comp); - }); - - evc->set_update_callback( - [this](auto entity_id, const auto comp) { - this->UpdateCounter(entity_id, comp); - }); - - auto exec_options = ecsact::core::execution_options{}; - - for (int i = 0; i < count; ++i) { - auto entity = registry->create_entity(); - - auto benchmark_counter = benchmark::Counter{.value = 0}; - - exec_options.add_component(entity, &benchmark_counter); - } - auto exec_err = registry->execute_systems(std::array{exec_options}, *evc); - if (exec_err != ECSACT_EXEC_SYS_OK) { - UE_LOG(LogTemp, Error, TEXT("Ecsact system execution failed")); - } else { - UE_LOG(LogTemp, Log, TEXT("ECSACT: Created %i entities"), count); - } + auto runner = GetRunner(); + check(runner); + + GetWorld()->GetTimerManager().SetTimer( + RunTimer, + [this]() { + UE_LOG(LogTemp, Log, TEXT("Stop dat runner")); + auto runner = GetRunner(); + runner->Stop(); + }, + 5.0f, + false + ); + + for(int i = 0; i < count; ++i) { + runner->CreateEntity().AddComponent({.value = 0}); + } + UE_LOG(LogTemp, Log, TEXT("ECSACT: Created %i entities"), count); } auto UEcsactBenchmarkMassSpawner::CreateMassEntities(int count) -> void { - auto *world = GetWorld(); - check(world); - - const auto &entity_template = config->GetOrCreateEntityTemplate(*world); - auto new_entity_handles = TArray{}; - - auto mass_spawner = world->GetSubsystem(); - - for (int i = 0; i < count; ++i) { - mass_spawner->SpawnEntities(entity_template, 1, new_entity_handles); - mass_entities.Add(new_entity_handles[0]); - } - UE_LOG(LogTemp, Log, TEXT("MASS: Created %i entities"), count); + auto* world = GetWorld(); + check(world); + + const auto& entity_template = config->GetOrCreateEntityTemplate(*world); + + auto mass_spawner = world->GetSubsystem(); + + // GetWorld()->GetTimerManager().SetTimer( + // RunTimer, + // [this]() { + // UE_LOG(LogTemp, Log, TEXT("Remove mass tag")); + // auto& entity_manager = // + // GetWorld() + // ->GetSubsystem() + // ->GetMutableEntityManager(); + // for(auto entity_handle : mass_entities) { + // entity_manager.Defer().RemoveTag(entity_handle); + // } + // }, + // 5.0f, + // false + // ); + + for(int i = 0; i < count; ++i) { + auto new_entity_handles = TArray{}; + mass_spawner->SpawnEntities(entity_template, 1, new_entity_handles); + mass_entities.Add(new_entity_handles[0]); + } + UE_LOG(LogTemp, Log, TEXT("MASS: Created %i entities"), count); } auto UEcsactBenchmarkMassSpawner::LoadWASMFiles() -> void { - auto cwd = FString{std::filesystem::current_path().string().c_str()}; - - UE_LOG(LogTemp, Log, TEXT("CWD %s"), *cwd); - auto file_path = - FString{"C:/Users/Austin/Documents/programming/ecsact/ecsact-examples/" - "unreal-cpp-benchmark/Binaries/SystemImpls.wasm"}; - - auto err = ecsact_si_wasm_load_file( - const_cast(TCHAR_TO_UTF8(*file_path)), - EcsactUnreal::CodegenMeta::BenchmarkSystemLikeIds.size(), - const_cast( - EcsactUnreal::CodegenMeta::BenchmarkSystemLikeIds.data()), - const_cast( - EcsactUnreal::CodegenMeta::BenchmarkExportNames.data())); - - if (err != ECSACT_SI_WASM_OK) { -#define HANDLE_ECSACT_SI_ERROR_CASE(err) \ - case err: \ - UE_LOG(LogTemp, Error, TEXT("ecsact_si_wasm_load_file error: " #err)); \ - break - switch (err) { - HANDLE_ECSACT_SI_ERROR_CASE(ECSACT_SI_WASM_ERR_FILE_OPEN_FAIL); - HANDLE_ECSACT_SI_ERROR_CASE(ECSACT_SI_WASM_ERR_FILE_READ_FAIL); - HANDLE_ECSACT_SI_ERROR_CASE(ECSACT_SI_WASM_ERR_COMPILE_FAIL); - HANDLE_ECSACT_SI_ERROR_CASE(ECSACT_SI_WASM_ERR_INSTANTIATE_FAIL); - HANDLE_ECSACT_SI_ERROR_CASE(ECSACT_SI_WASM_ERR_EXPORT_NOT_FOUND); - HANDLE_ECSACT_SI_ERROR_CASE(ECSACT_SI_WASM_ERR_EXPORT_INVALID); - HANDLE_ECSACT_SI_ERROR_CASE(ECSACT_SI_WASM_ERR_GUEST_IMPORT_UNKNOWN); - HANDLE_ECSACT_SI_ERROR_CASE(ECSACT_SI_WASM_ERR_GUEST_IMPORT_INVALID); - HANDLE_ECSACT_SI_ERROR_CASE(ECSACT_SI_WASM_ERR_INITIALIZE_FAIL); - HANDLE_ECSACT_SI_ERROR_CASE(ECSACT_SI_WASM_ERR_NO_SET_SYSTEM_EXECUTION); - case ECSACT_SI_WASM_OK: - break; - } + auto cwd = FString{std::filesystem::current_path().string().c_str()}; + + UE_LOG(LogTemp, Log, TEXT("CWD %s"), *cwd); + auto file_path = FString{ + "C:/Users/Austin/Documents/programming/ecsact/ecsact-examples/" + "unreal-cpp-benchmark/Binaries/SystemImpls.wasm" + }; + + auto err = ecsact_si_wasm_load_file( + const_cast(TCHAR_TO_UTF8(*file_path)), + EcsactUnreal::CodegenMeta::BenchmarkSystemLikeIds.size(), + const_cast( + EcsactUnreal::CodegenMeta::BenchmarkSystemLikeIds.data() + ), + const_cast( + EcsactUnreal::CodegenMeta::BenchmarkExportNames.data() + ) + ); + + if(err != ECSACT_SI_WASM_OK) { +#define HANDLE_ECSACT_SI_ERROR_CASE(err) \ + case err: \ + UE_LOG(LogTemp, Error, TEXT("ecsact_si_wasm_load_file error: " #err)); \ + break + switch(err) { + HANDLE_ECSACT_SI_ERROR_CASE(ECSACT_SI_WASM_ERR_FILE_OPEN_FAIL); + HANDLE_ECSACT_SI_ERROR_CASE(ECSACT_SI_WASM_ERR_FILE_READ_FAIL); + HANDLE_ECSACT_SI_ERROR_CASE(ECSACT_SI_WASM_ERR_COMPILE_FAIL); + HANDLE_ECSACT_SI_ERROR_CASE(ECSACT_SI_WASM_ERR_INSTANTIATE_FAIL); + HANDLE_ECSACT_SI_ERROR_CASE(ECSACT_SI_WASM_ERR_EXPORT_NOT_FOUND); + HANDLE_ECSACT_SI_ERROR_CASE(ECSACT_SI_WASM_ERR_EXPORT_INVALID); + HANDLE_ECSACT_SI_ERROR_CASE(ECSACT_SI_WASM_ERR_GUEST_IMPORT_UNKNOWN); + HANDLE_ECSACT_SI_ERROR_CASE(ECSACT_SI_WASM_ERR_GUEST_IMPORT_INVALID); + HANDLE_ECSACT_SI_ERROR_CASE(ECSACT_SI_WASM_ERR_INITIALIZE_FAIL); + HANDLE_ECSACT_SI_ERROR_CASE(ECSACT_SI_WASM_ERR_NO_SET_SYSTEM_EXECUTION); + case ECSACT_SI_WASM_OK: + break; + } #undef HANDLE_ECSACT_SI_ERROR_CASE - } + } } -auto UEcsactBenchmarkMassSpawner::InitCounter( // - ecsact_entity_id Entity, const benchmark::Counter &) -> void { - - UE_LOG(LogTemp, Log, TEXT("Counter started on entity %i"), Entity); +void UEcsactBenchmarkMassSpawner::InitCounter_Implementation( + int32 Entity, + FBenchmarkCounter +) { + // UE_LOG(LogTemp, Log, TEXT("Counter init on entity %i"), Entity); } -auto UEcsactBenchmarkMassSpawner::UpdateCounter( // - ecsact_entity_id Entity, const benchmark::Counter &counter) -> void { - - UE_LOG(LogTemp, Log, TEXT("Counter update on entity %i to %i"), Entity, - counter.value); -} - -auto UEcsactBenchmarkMassSpawner::ExecuteSystems(int count) -> void { - for (int i = 0; i < count; ++i) { - registry->execute_systems(1, *evc); - } +void UEcsactBenchmarkMassSpawner::UpdateCounter_Implementation( + int32 Entity, + FBenchmarkCounter Counter +) { + // UE_LOG( + // LogTemp, + // Log, + // TEXT("Counter updated on entity %i to %i"), + // Entity, + // Counter.Value + // ); } void UEcsactBenchmarkMassSpawner::StartMassSpawner( // - UObject *WorldContext, EcsactBenchmarkType BenchmarkType) { - UE_LOG(LogTemp, Warning, TEXT("BENCHMARKTYPE: %s"), - *UEnum::GetValueAsString(BenchmarkType)); - - auto *world = WorldContext->GetWorld(); - check(world); - - auto ecsact_game_subsystem = - world->GetGameInstance()->GetSubsystem(); - check(ecsact_game_subsystem); - - ecsact_game_subsystem->StartCustomRunner(); - auto runner = EcsactUnrealExecution::Runner(world); - - if (!runner.IsValid()) { - UE_LOG(LogTemp, Error, TEXT("Provided runner is invalid")); - return; - } - - auto mass_spawner_subsystem = - runner->GetSubsystem(); - - if (mass_spawner_subsystem) { - mass_spawner_subsystem->OnStartButtonPressed(BenchmarkType); - } else { - UE_LOG(LogTemp, Error, TEXT("BenchmarkMassSpawner can't be found")); - } + UObject* WorldContext, + EcsactBenchmarkType BenchmarkType +) { + UE_LOG( + LogTemp, + Warning, + TEXT("BENCHMARKTYPE: %s"), + *UEnum::GetValueAsString(BenchmarkType) + ); + + auto* world = WorldContext->GetWorld(); + check(world); + + auto ecsact_game_subsystem = + world->GetGameInstance()->GetSubsystem(); + check(ecsact_game_subsystem); + + ecsact_game_subsystem->StartCustomRunner(); + auto runner = EcsactUnrealExecution::Runner(world); + + if(!runner.IsValid()) { + UE_LOG(LogTemp, Error, TEXT("Provided runner is invalid")); + return; + } + + auto mass_spawner_subsystem = + runner->GetSubsystem(); + + if(mass_spawner_subsystem) { + mass_spawner_subsystem->OnStartButtonPressed(BenchmarkType); + } else { + UE_LOG(LogTemp, Error, TEXT("BenchmarkMassSpawner can't be found")); + } } diff --git a/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmarkMassSpawner.h b/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmarkMassSpawner.h index dbc1adc..6312d2c 100644 --- a/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmarkMassSpawner.h +++ b/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmarkMassSpawner.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include "CoreMinimal.h" #include "MassEntityConfigAsset.h" @@ -14,45 +13,43 @@ UENUM(BlueprintType) enum class EcsactBenchmarkType : uint8 { - EcsactCounter UMETA(DisplayName = "Ecsact Counter"), - MassCounter UMETA(DisplayName = "Mass Counter") + EcsactCounter UMETA(DisplayName = "Ecsact Counter"), + MassCounter UMETA(DisplayName = "Mass Counter") }; UCLASS(Abstract) + class UEcsactBenchmarkMassSpawner : public UBenchmarkMassSpawner { - GENERATED_BODY() - UEcsactBenchmarkMassSpawner(); + GENERATED_BODY() + UEcsactBenchmarkMassSpawner(); - std::optional registry; - std::optional> evc; + TArray entities; + TArray mass_entities; - TArray entities; - TArray mass_entities; + FTimerHandle RunTimer; - UPROPERTY(EditAnywhere) - UMassEntityConfigAsset *config; + UPROPERTY(EditAnywhere) + UMassEntityConfigAsset* config; public: - UFUNCTION(BlueprintCallable, Meta = (WorldContext = "WorldContext")) - static void StartMassSpawner(UObject *WorldContext, - EcsactBenchmarkType BenchmarkType); - - UFUNCTION(BlueprintCallable) - void CreateMassEntities(int count); + UFUNCTION(BlueprintCallable, Meta = (WorldContext = "WorldContext")) + static void StartMassSpawner( + UObject* WorldContext, + EcsactBenchmarkType BenchmarkType + ); - UFUNCTION(BlueprintCallable) - void CreateEcsactEntities(int count); + UFUNCTION(BlueprintCallable) + void CreateMassEntities(int count); - UFUNCTION(BlueprintCallable) - void LoadWASMFiles(); + UFUNCTION(BlueprintCallable) + void CreateEcsactEntities(int count); - UFUNCTION(BlueprintCallable) - void ExecuteSystems(int count); + UFUNCTION(BlueprintCallable) + void LoadWASMFiles(); - void InitCounter(ecsact_entity_id Entity, const benchmark::Counter &Counter); - void UpdateCounter(ecsact_entity_id Entity, - const benchmark::Counter &Counter); + UFUNCTION(BlueprintImplementableEvent) + void OnStartButtonPressed(EcsactBenchmarkType BenchmarkType); - UFUNCTION(BlueprintImplementableEvent) - void OnStartButtonPressed(EcsactBenchmarkType BenchmarkType); + void InitCounter_Implementation(int32 Entity, FBenchmarkCounter) override; + void UpdateCounter_Implementation(int32 Entity, FBenchmarkCounter) override; }; diff --git a/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmarkRunner.cpp b/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmarkRunner.cpp index e69de29..bdd851e 100644 --- a/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmarkRunner.cpp +++ b/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmarkRunner.cpp @@ -0,0 +1,33 @@ +#include "EcsactBenchmarkRunner.h" +#include "ecsact/runtime/core.h" +#include "ecsact/runtime/core.hh" + +auto UEcsactBenchmarkRunner::Start() -> void { + Super::Start(); + should_run = true; + registry.emplace("Benchmark"); +} + +auto UEcsactBenchmarkRunner::Stop() -> void { + Super::Stop(); + should_run = false; +} + +auto UEcsactBenchmarkRunner::Tick(float deltaTime) -> void { + Super::Tick(deltaTime); + if(ecsact_execute_systems && should_run) { + ecsact_execution_options* exec_opts = nullptr; + if(ExecutionOptions != nullptr && ExecutionOptions->IsNotEmpty()) { + exec_opts = ExecutionOptions->GetCPtr(); + } + auto err = ecsact_execute_systems( // + registry->id(), + 1, + exec_opts, + GetEventsCollector() + ); + if(ExecutionOptions != nullptr) { + ExecutionOptions->Clear(); + } + } +} diff --git a/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmarkRunner.h b/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmarkRunner.h index d608517..f394f39 100644 --- a/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmarkRunner.h +++ b/unreal-cpp-benchmark/Source/EcsactBenchmark/EcsactBenchmarkRunner.h @@ -2,11 +2,20 @@ #include "CoreMinimal.h" #include "EcsactUnreal/EcsactRunner.h" +#include "ecsact/runtime/core.hh" #include "EcsactBenchmarkRunner.generated.h" UCLASS() class ECSACTBENCHMARK_API UEcsactBenchmarkRunner : public UEcsactRunner { - GENERATED_BODY() + GENERATED_BODY() + + std::optional registry; + + auto Start() -> void override; + auto Stop() -> void override; + auto Tick(float deltaTime) -> void override; + + bool should_run; }; diff --git a/unreal-cpp-benchmark/Source/EcsactBenchmark/Fragments/MassCounterFragments.h b/unreal-cpp-benchmark/Source/EcsactBenchmark/Fragments/MassCounterFragments.h new file mode 100644 index 0000000..1b37433 --- /dev/null +++ b/unreal-cpp-benchmark/Source/EcsactBenchmark/Fragments/MassCounterFragments.h @@ -0,0 +1,11 @@ +#pragma once + +#include "MassEntityTypes.h" + +#include "MassCounterFragments.generated.h" + +USTRUCT() + +struct ECSACTBENCHMARK_API FRunMassCounter : public FMassTag { + GENERATED_BODY() +}; diff --git a/unreal-cpp-benchmark/Source/EcsactBenchmark/Fragments/NoEcsactFragment.h b/unreal-cpp-benchmark/Source/EcsactBenchmark/Fragments/NoEcsactFragment.h deleted file mode 100644 index e69de29..0000000 diff --git a/unreal-cpp-benchmark/Source/EcsactBenchmark/Processors/MassBenchmarkProcessor.cpp b/unreal-cpp-benchmark/Source/EcsactBenchmark/Processors/MassBenchmarkProcessor.cpp index 544af2d..2cc968c 100644 --- a/unreal-cpp-benchmark/Source/EcsactBenchmark/Processors/MassBenchmarkProcessor.cpp +++ b/unreal-cpp-benchmark/Source/EcsactBenchmark/Processors/MassBenchmarkProcessor.cpp @@ -2,35 +2,46 @@ #include "../EcsactBenchmark__ecsact__mass__ue.h" #include "EcsactBenchmark/EcsactBenchmark__ecsact__ue.h" #include "MassArchetypeTypes.h" + +#include "../Fragments/MassCounterFragments.h" #include "MassEntityView.h" #include "MassExecutionContext.h" #include "MassRequirements.h" -UMassBenchmarkProcessor::UMassBenchmarkProcessor() : EntityQuery(*this) {} +UMassBenchmarkProcessor::UMassBenchmarkProcessor() : EntityQuery(*this) { +} void UMassBenchmarkProcessor::ConfigureQueries() { - - EntityQuery.AddRequirement( - EMassFragmentAccess::ReadWrite); + EntityQuery.AddRequirement( + EMassFragmentAccess::ReadWrite + ); + EntityQuery.AddTagRequirement(EMassFragmentPresence::All); } -void UMassBenchmarkProcessor::Execute(FMassEntityManager &EntityManager, - FMassExecutionContext &Context) { - - EntityQuery.ForEachEntityChunk( // - EntityManager, Context, [](FMassExecutionContext &context) { - const auto entity_num = context.GetNumEntities(); - auto counter_fragments = - context.GetMutableFragmentView(); - - for (int i = 0; i < entity_num; ++i) { - - auto &counter_fragment = counter_fragments[i]; - - counter_fragment.component.Value += 1; - - UE_LOG(LogTemp, Warning, TEXT("MASS: Updated entity counter to %i"), - counter_fragment.component.Value); - } - }); +void UMassBenchmarkProcessor::Execute( + FMassEntityManager& EntityManager, + FMassExecutionContext& Context +) { + EntityQuery.ForEachEntityChunk( // + EntityManager, + Context, + [](FMassExecutionContext& context) { + const auto entity_num = context.GetNumEntities(); + auto counter_fragments = + context.GetMutableFragmentView(); + + for(int i = 0; i < entity_num; ++i) { + auto& counter_fragment = counter_fragments[i]; + + counter_fragment.component.Value += 1; + + // UE_LOG( + // LogTemp, + // Warning, + // TEXT("MASS: Updated entity counter to %i"), + // counter_fragment.component.Value + // ); + } + } + ); }