From e211798077de88fe39d1e1c0add7a0f460d1da5a Mon Sep 17 00:00:00 2001 From: physcik Date: Mon, 6 Apr 2026 18:29:34 +0500 Subject: Experimental async update function --- engine/Components/World.go | 11 +++++- engine/Config.json | 3 +- engine/CoreObjects/Balancer.go | 75 ++++++++++++++++++++++++++++++++++++++ engine/CoreObjects/OverlayScene.go | 6 +++ engine/CoreObjects/Scene.go | 44 +--------------------- engine/CoreObjects/SceneManager.go | 54 +++++++++++++++++++++++++++ engine/Dynamic/DynamicMenu.go | 4 ++ engine/Loop/initWindow.go | 38 +++++++++++++++++++ engine/Render/initWindow.go | 38 ------------------- engine/Settings/Settings.go | 2 + engine/UI/Label.go | 2 +- engine/main.go | 10 +++-- 12 files changed, 199 insertions(+), 88 deletions(-) create mode 100644 engine/CoreObjects/Balancer.go create mode 100644 engine/CoreObjects/SceneManager.go create mode 100644 engine/Loop/initWindow.go delete mode 100644 engine/Render/initWindow.go (limited to 'engine') diff --git a/engine/Components/World.go b/engine/Components/World.go index c7a96df..ccbe99f 100644 --- a/engine/Components/World.go +++ b/engine/Components/World.go @@ -13,27 +13,34 @@ type World struct { StaticObjects []coreobjects.GameObject Player *Player - Camera *rl.Camera2D - layersStatic layering // ========== Cache ========== // the collection of the colliders that belong to static objects - world, buildings, etc staticColliders []*coreobjects.Collider + + updateQueue []coreobjects.UpdateFunction } func (base *World) Create(manager *coreobjects.SceneManager) { base.Manager = manager base.Player.Init(manager) + // The max length will be higher but this length is guaranteed + base.updateQueue = make([]coreobjects.UpdateFunction, 0, len(base.StaticObjects)) for _, v := range base.StaticObjects { v.Init(manager) + base.updateQueue = append(base.updateQueue, v.Update) } base.layersStatic = layering{} base.generateStaticLayers() } +func (base *World) GetUpdateFunctions() []coreobjects.UpdateFunction { + return base.updateQueue +} + func (base *World) Destroy() { base.Player.Destroy() } diff --git a/engine/Config.json b/engine/Config.json index 2f173d7..e67fb1a 100644 --- a/engine/Config.json +++ b/engine/Config.json @@ -5,5 +5,6 @@ "Patch": 1, "IsBeta": true }, - "PackagesLocation": "../packages" + "PackagesLocation": "../packages", + "MaxUpdateRoutines": 10 } diff --git a/engine/CoreObjects/Balancer.go b/engine/CoreObjects/Balancer.go new file mode 100644 index 0000000..0e80b10 --- /dev/null +++ b/engine/CoreObjects/Balancer.go @@ -0,0 +1,75 @@ +package coreobjects + +import ( + "sync" + + settings "github.com/DegustatorPonos/RuinesOfRafdolon/Settings" +) + +type runner struct { + ExecChan chan UpdateFunction + CompleteChan chan any +} + +func makeRunner(execChan chan UpdateFunction, completeChan chan any) *runner { + var outp = &runner { + ExecChan: execChan, + CompleteChan: completeChan, + } + outp.Init() + return outp +} + +func (base *runner) Init() { + go func() { + for { + var task = <- base.ExecChan + task() + base.CompleteChan <- nil + } + }() +} + +// Balances the updates so that the execution of WASM doesn't clog the system +type balancer struct { + MaxRoutines int + // So that we don't use invloke balancer twice + mut *sync.Mutex + Runners []*runner + // balancer -> + ExecChan chan UpdateFunction + CompleteChan chan any +} + +func makeBalancer() *balancer { + var maxRoutines = settings.Current.MaxUpdateRoutines + var outp = &balancer{ + MaxRoutines: maxRoutines, + mut: &sync.Mutex{}, + Runners: make([]*runner, maxRoutines), + ExecChan: make(chan UpdateFunction, maxRoutines), + CompleteChan: make(chan any, maxRoutines), + } + for i := range maxRoutines { + outp.Runners[i] = makeRunner(outp.ExecChan, outp.CompleteChan) + } + return outp +} + +func (base *balancer) Execute(tasks []UpdateFunction) { + base.mut.Lock() + defer base.mut.Unlock() + for _, v := range tasks { + base.ExecChan <- v + } + + // Sync + var results = 0 + for { + <- base.CompleteChan + results++ + if results == len(tasks) { + break + } + } +} diff --git a/engine/CoreObjects/OverlayScene.go b/engine/CoreObjects/OverlayScene.go index 73aa987..3689262 100644 --- a/engine/CoreObjects/OverlayScene.go +++ b/engine/CoreObjects/OverlayScene.go @@ -9,9 +9,15 @@ import ( type OveralyScene struct { FPS FpsMeter + updateFunctions []UpdateFunction } func (base *OveralyScene) Create(_ *SceneManager) { + base.updateFunctions = []UpdateFunction { base.Update } +} + +func (base *OveralyScene) GetUpdateFunctions() []UpdateFunction { + return base.updateFunctions } func (base *OveralyScene) Destroy() { diff --git a/engine/CoreObjects/Scene.go b/engine/CoreObjects/Scene.go index b6b886c..8a11e29 100644 --- a/engine/CoreObjects/Scene.go +++ b/engine/CoreObjects/Scene.go @@ -2,54 +2,14 @@ package coreobjects import rl "github.com/gen2brain/raylib-go/raylib" -type SceneManager struct { - OverlayScene Scene - SelectedScene Scene -} +type UpdateFunction func() type Scene interface { Create(*SceneManager) Destroy() Update() + GetUpdateFunctions() []UpdateFunction Draw() GetMousePosition() rl.Vector2 } -func InitSceneManager() SceneManager { - return SceneManager{ - OverlayScene: &OveralyScene{}, - SelectedScene: nil, - } -} - -func (base *SceneManager) ChangeScene(newScene Scene) { - if base.SelectedScene != nil { - base.SelectedScene.Destroy() - } - base.SelectedScene = newScene - base.SelectedScene.Create(base) -} - -func (base *SceneManager) Update() { - if (base.SelectedScene != nil) { - base.SelectedScene.Update() - } - - if (base.OverlayScene != nil) { - base.OverlayScene.Update() - } - - if rl.IsKeyDown(rl.KeyF11) { - rl.ToggleFullscreen() - } -} - -func (base *SceneManager) Draw() { - if (base.SelectedScene != nil) { - base.SelectedScene.Draw() - } - - if (base.OverlayScene != nil) { - base.OverlayScene.Draw() - } -} diff --git a/engine/CoreObjects/SceneManager.go b/engine/CoreObjects/SceneManager.go new file mode 100644 index 0000000..dc44dd9 --- /dev/null +++ b/engine/CoreObjects/SceneManager.go @@ -0,0 +1,54 @@ +package coreobjects + +import ( + rl "github.com/gen2brain/raylib-go/raylib" +) + +type SceneManager struct { + OverlayScene Scene + SelectedScene Scene + + balancer *balancer +} + +func InitSceneManager() SceneManager { + return SceneManager{ + OverlayScene: &OveralyScene{}, + SelectedScene: nil, + balancer: makeBalancer(), + } +} + +func (base *SceneManager) ChangeScene(newScene Scene) { + if base.SelectedScene != nil { + base.SelectedScene.Destroy() + } + base.SelectedScene = newScene + base.SelectedScene.Create(base) +} + +func (base *SceneManager) Update() { + if (base.SelectedScene != nil) { + base.SelectedScene.Update() + } + + if (base.OverlayScene != nil) { + base.OverlayScene.Update() + } + + base.balancer.Execute(base.SelectedScene.GetUpdateFunctions()) + + if rl.IsKeyDown(rl.KeyF11) { + rl.ToggleFullscreen() + } +} + +func (base *SceneManager) Draw() { + if (base.SelectedScene != nil) { + base.SelectedScene.Draw() + } + + if (base.OverlayScene != nil) { + base.OverlayScene.Draw() + } +} diff --git a/engine/Dynamic/DynamicMenu.go b/engine/Dynamic/DynamicMenu.go index c7226dd..25ec513 100644 --- a/engine/Dynamic/DynamicMenu.go +++ b/engine/Dynamic/DynamicMenu.go @@ -35,6 +35,10 @@ func (base *DynamicMenu) Create(manager *coreobjects.SceneManager) { base.baseMenu.Create(manager) } +func (base *DynamicMenu) GetUpdateFunctions() []coreobjects.UpdateFunction { + return []coreobjects.UpdateFunction{} +} + func (base *DynamicMenu) Destroy() { base.baseMenu.Destroy() } diff --git a/engine/Loop/initWindow.go b/engine/Loop/initWindow.go new file mode 100644 index 0000000..c1fe1b6 --- /dev/null +++ b/engine/Loop/initWindow.go @@ -0,0 +1,38 @@ +package loop + +import ( + "fmt" + + coreobjects "github.com/DegustatorPonos/RuinesOfRafdolon/CoreObjects" + settings "github.com/DegustatorPonos/RuinesOfRafdolon/Settings" + rl "github.com/gen2brain/raylib-go/raylib" +) + +func InitWindow() { + rl.SetConfigFlags(rl.FlagWindowResizable) + + var titleString = fmt.Sprintf("Ruines of Rafdolon v.%d.%d.%d", + settings.Current.Version.MajorVersion, + settings.Current.Version.MinorVersion, + settings.Current.Version.Patch) + + rl.InitWindow(800, 450, titleString) +} + +func StartLoop(manager coreobjects.SceneManager, startScene coreobjects.Scene) { + manager.ChangeScene(startScene) + + // rl.SetTargetFPS(60) + + for !rl.WindowShouldClose() { + manager.Update() + rl.BeginDrawing() + rl.ClearBackground(rl.SkyBlue) + manager.Draw() + rl.EndDrawing() + } +} + +func DeinitWindow() { + rl.CloseWindow() +} diff --git a/engine/Render/initWindow.go b/engine/Render/initWindow.go deleted file mode 100644 index e131b99..0000000 --- a/engine/Render/initWindow.go +++ /dev/null @@ -1,38 +0,0 @@ -package render - -import ( - "fmt" - - coreobjects "github.com/DegustatorPonos/RuinesOfRafdolon/CoreObjects" - settings "github.com/DegustatorPonos/RuinesOfRafdolon/Settings" - rl "github.com/gen2brain/raylib-go/raylib" -) - -func InitWindow() { - rl.SetConfigFlags(rl.FlagWindowResizable) - - var titleString = fmt.Sprintf("Ruines of Rafdolon v.%d.%d.%d", - settings.Current.Version.MajorVersion, - settings.Current.Version.MinorVersion, - settings.Current.Version.Patch) - - rl.InitWindow(800, 450, titleString) -} - -func StartLoop(manager coreobjects.SceneManager, startScene coreobjects.Scene) { - manager.ChangeScene(startScene) - - // rl.SetTargetFPS(60) - - for !rl.WindowShouldClose() { - manager.Update() - rl.BeginDrawing() - rl.ClearBackground(rl.SkyBlue) - manager.Draw() - rl.EndDrawing() - } -} - -func DeinitWindow() { - rl.CloseWindow() -} diff --git a/engine/Settings/Settings.go b/engine/Settings/Settings.go index f943203..fc1058e 100644 --- a/engine/Settings/Settings.go +++ b/engine/Settings/Settings.go @@ -9,6 +9,7 @@ import ( type Settings struct { Version AppVersion PackagesLocation string + MaxUpdateRoutines int } var defaultSettings = Settings { @@ -19,6 +20,7 @@ var defaultSettings = Settings { IsBeta: true, }, PackagesLocation: "Packages", + MaxUpdateRoutines: 10, } func (base Settings) String() string { diff --git a/engine/UI/Label.go b/engine/UI/Label.go index eef85e2..27f85c0 100644 --- a/engine/UI/Label.go +++ b/engine/UI/Label.go @@ -14,7 +14,7 @@ var defaultLabelRoundness float32 = 0.2 // If the text formation formula is applied without it the text is // overlowing on the right due to rounding errors -const overflowMultiplyer float32 = 1.1 +const overflowMultiplyer float32 = 1.15 var defaultLabelStyle = &Style{ BacgroundColor: &rl.LightGray, diff --git a/engine/main.go b/engine/main.go index 1ec01ec..265695c 100644 --- a/engine/main.go +++ b/engine/main.go @@ -7,7 +7,7 @@ import ( components "github.com/DegustatorPonos/RuinesOfRafdolon/Components" coreobjects "github.com/DegustatorPonos/RuinesOfRafdolon/CoreObjects" dynamic "github.com/DegustatorPonos/RuinesOfRafdolon/Dynamic" - render "github.com/DegustatorPonos/RuinesOfRafdolon/Render" + loop "github.com/DegustatorPonos/RuinesOfRafdolon/Loop" settings "github.com/DegustatorPonos/RuinesOfRafdolon/Settings" ) @@ -24,8 +24,8 @@ func main() { panic("The core package was not loaded") } - render.InitWindow() - defer render.DeinitWindow() + loop.InitWindow() + defer loop.DeinitWindow() // TEMPORARY SECTION // for _, v := range dynamic.Manager.AvaliablePackages { @@ -38,8 +38,10 @@ func main() { panic(fmt.Sprintf("Failed to load core package: %s", coreLoadErr.Error())) } + dynamic.Manager.LoadPackage("testPackage") log.Printf("Resource manager: %s", &components.Resources) var manager = coreobjects.InitSceneManager() - render.StartLoop(manager, components.Resources.Scenes[MainMenuName]) + loop.StartLoop(manager, components.Resources.Scenes["MainWorld"]) + // loop.StartLoop(manager, components.Resources.Scenes[MainMenuName]) } -- cgit v1.3