Architecture for mixing synchronous and asynchronous program flow to maximize faux real-time yet logical gameplay?

What I am attempting to make is a faux real-time game engine in node.js (taking advantage of the non-blocking I/O). When I say 'faux real-time' what I mean is I want players to interact with the world as much as possible without players blocking each other or having to 'wait in line to use the world'.

That is, unless the gameplay requires it. For example, in real life you have to wait in line to do certain things, some as simple as taking up space on a certain section of the highway. However if each person is in their own space, they can do jumping jacks or spin donuts in their car at a unique pace completely unrelated and 'in parallel' to every other person who is also taking these unrelated actions.

Related/synchronized actions would be things like trading, or even moving. If two players move into the same space and attempt to pick up the same object then suddenly it matters if they get there at the same time...

I hope this is making sense, but I'll add some code to try and give an example:

setInterval(function() {
for(var i = 0; i < someArray.length; i++){
someArray[i].QueuedAction();
}
someArray = new Array();
}, 1000);


If every 1 second we went through this array and then emptied it, we would effectively have a synchronized list. There may be many events coming in to add to this array while this loop is running, but this loop is blocking those events from modifying the array until it is done and has cleared the array. This would be list of things happening in order.

However if this takes too long, then it will also block players from requesting their current location or the client from requesting objects around the player, etc. So this needs to happen quickly to keep the illusion of real-time but in order to keep the illusion of a logical world.

Is there any patterns I should evaluate that could improve this balance of in-order yet non-blocking world game engine?

• PHD student? The title of your question looks like the title of a thesis. :)
– House
Jan 25, 2013 at 18:20
• @Byte56 nope, just a side hobby Jan 25, 2013 at 18:21
• Might be helpful to learn about the Node.js event loop and maybe multiplayer networking. What problems do you foresee with implementing that? It sounds like any other online multiplayer game.
– Anko
Dec 11, 2014 at 2:30

To allow the actions to be queued to the list while the list is processed, you could have a second list that receives the actions while the first list is being processed. With that, instead of getting through all of the elements of the list every second, you could process as many items as possible in a shorter time span, then combine the two lists.

I'm not a JavaScript programmer, but with an object oriented language, I'd go with that kind of pseudocode:

Class EventQueue
queueItem( item )
queueBuffer.apped( item )

processItems()
beginTime = performance.now()
processBuffer.apped( queueBuffer )
queueBuffer.clear()

while( beginTime + (1/60) < performance.now() )
{
item = processBuffer.popFront()
item.QueuedAction()
}


The object of type EventQueue will be your entry point, with the method queueItem. You'll have to find a way to call the method processItems on a regular interval. In this example, it will run for a bit more than 1/60th of a second but you could change that and tailor it to your needs.

Maybe I'm oversimplifying your question, but this is what async/await are good for.

For sequences of actions that you need to happen one after another, you call them sequentially with await:

await doOneThing();
await doNextThing();
await doFinalThing();


And this entire sequence itself can be an async function that can either be awaited on or launched asynchronously.

Larger Example Code:

// example actions that are slow
async function doA() { await delay(100); }
async function doB() { await delay(1000); }

// awaiting this function returns in approximately 0 milliseconds
async function do_A_and_B_and_return_immediately() {
doA();
doB();
}

// awaiting this function returns in approximately 1100 milliseconds
async function do_A_afterwards_do_B_afterwards_return() {
await doA();
await doB();
}

async function main() {
// this is quick
await do_A_and_B_and_return_immediately();
// this is slow
await do_A_afterwards_do_B_afterwards_return();
// this seems like what you're asking for -
// do a sequential task but don't wait up for it.
do_A_afterwards_do_B_afterwards_return()
}