Jump to content

Engine Startup Events


photo

Recommended Posts

I have an architecture with an async system that runs in "user-time" in parallel with the "World". This system is a Control Panel for the world.

It has multiple initialization stages. Some that run before the Engine is started (Engine.Main...), and some after.

Conceptually, I am doing something like this:

static async Task Main(){
    await Control.PreEngine();
    await Engine.Main(...)
    await Control.PostEngine();
    await Engine.ShutDown();
    ... Cleanup
}

Of course (ignoring awaits) this would stop at Engine.Main since it is a blocking void. And, since it needs the main thread I can't do a lot to get around it (e.g., Task.Run(Engine).

I'm able to get something working, but it feels kludgy.

Engine callbacks help. The Engine exposes many update events (e.g., Engine.CALLBACK_INDEX.BEGIN_PHYSICS), but it doesn't expose startup events (e.g., Init).

To get to a Control.PostEngine() I use a callback, but I have to create it.

Ideally (in my mind), Engine would have startup-cycle events like "EngineInitialized" and "WorldReady". But it doesn't, so we fake them.

To get a "WorldReady", I create a one-shot on an update event.

 

{
Control control = //
TaskCompletionSource StartTcs = new();
IntPtr StartCallback = Engine.AddCallback(Engine.CALLBACK_INDEX.BEGIN_PHYSICS, Release);
await StartTcs.Task;
  
  // faux WorldReady
  control.WorldReady()

/* **********   Locals   ********** */
    void Release() {
        StartTcs.SetResult();
        _ = Engine.RemoveCallback(Engine.CALLBACK_INDEX.BEGIN_PHYSICS, StartCallback);
     }
}

** Is there a better event to use with this approach?

To get start-cycle events (like Init) I use wedges:

class WorldWedge : WorldLogic { 
    Control control = //   
    Init(){
        // promote WorldInit
        control.WorldInit();
        Engine.RemoveWorldLogic(...)
    }
}

Engine.AddWorldLogic(...)

I use one for World and one for System.

 

Is there more direct way to integrate with the startup cycle?

Basically, I'm looking to trigger on these conditions:

1) Engine "Started" ( I can access Engine functions)

2) Init Complete - (System and/or World)

3) World "Ready" (i.e., I can access Objects (created in Init) in the World)

4) Update Loop Starting. Something like a global "Game Starting" event.

3 & 4 are similar. 3 is useful for starting things like late-binding. 4 is essentially a gate.

Link to comment

Hi Tessalator,

Of course (ignoring awaits) this would stop at Engine.Main since it is a blocking void. And, since it needs the main thread I can't do a lot to get around it (e.g., Task.Run(Engine).
You can write your own Engine.Main() function:

void MyMain()
{
	Eninge.AddSystemLogic(system_logic);
	Engine.AddWorldLogic(world_logic);

	while (!Engine.IsDone)
	{
		Engine.Update();
		Engine.Render();
		Engine.Swap();
	}
}

Basically, I'm looking to trigger on these conditions:
1) Engine "Started" ( I can access Engine functions)

Unfortunately, you can do it only through the SystemLogic.Init() method.

2) Init Complete - (System and/or World)
System -> SystemLogic.Init() method.
World -> There is a World.AddCallback(World.CALLBACK_INDEX.POST_WORLD_INIT, ...); method for this. PRE_WORLD_INIT - the world has been initialized, but WorldLogic.Init has not been called yet. POST_WORLD_INIT - right after all WorldLogic.Init calls.

3) World "Ready" (i.e., I can access Objects (created in Init) in the World)
Same as in the previous point - through POST_WORLD_INIT callback.

4) Update Loop Starting. Something like a global "Game Starting" event.
Please use Engine.AddCallback(Engine.CALLBACK_INDEX.BEGIN_UPDATE, ...); for this.

Best regards,
Alexander

Link to comment

Hi Alexander,

I had overlooked `World.AddCallback`. But I'm having trouble understanding how to use them for this. I'm not see delegates on them that take a function. 

The tip about my own main is good. Thanks.  What I'm doing is this:

// My Pre
Engine.Update();
// My Post
Engine.Render();
Engine.Swap();

while (!Engine.IsDone) {
    Engine.Update();
	Engine.Render();
	Engine.Swap();
}

I found most of what I wanted to do early can occur after update completes the first time. It's also a good checkpoint.  I'm running render and swap for safety, but do I need to run them here?

 

Do you have a developer program that would give me access to the C# code? I'm writing a low-level framework and I doing a lot of guessing about what Unigine is doing.

Edited by Tessalator
Link to comment

I had overlooked `World.AddCallback`. But I'm having trouble understanding how to use them for this. I'm not see delegates on them that take a function.
Oops. There was a bug in the engine. PRE/POST_WORLD_INIT and PRE/POST_WORLD_SHUTDOWN didn't work. I've fixed it in the next version of the SDK.

I'm running render and swap for safety, but do I need to run them here?
Yes, of course. You can run Update/Render/Swap anywhere, but they must be called sequentially (an Update spawns threads and a Swap stops them).

Best regards,
Alexander

Link to comment
×
×
  • Create New...