Proposed multiplayer architecture: is it sane?

Hey Defold,

Running a publish-subscribe type server (depicted below) appears scaleable. Is it even vaguely close to best practices for multiplayer game design? Is this something achievable w/ Defold? Which tools might I use to e.g. consume from an Apache Kafka or AWS SNS stream?

Cheers

1 Like

Not sure, but there should be tons of articles and presentations that answer this question.

Do you plan to use Defold for the backend as well or only in the client?

On the server or client? I’ve written a Defold/Lua generator for the AWS services, mainly for use with GameLift but SNS should work as well or be fairly easy to get working.

2 Likes

I do plan to use Defold for the “backend” i.e. the server-side world-state management including determining whether user propositions are valid, disseminating the authoritative world-state, etc. I know headless Defold is doable, but can Defold be used as a server node?

Cheers

Yes, sure. This is what @andreas.strangequest is doing with the backend for Blastlands.

1 Like

I’d read his post - didn’t give entry points on his implementation but said to reach out for help - I guess I’ll do that! I’ll post here with details if I get it figured out.

Cheers

1 Like

Hi Teriyaki.

Not sure if I fully understand the architecture you are describing above and I guess it all depends on the type of game. A shooter would probably have a much different arch than an MMO or a MOBA, but let me just briefly describe what we are doing with Defold atm.
We are creating a casual shooter (releasing a very new and different version in a few weeks) and have built the whole multiplayer part (server/client) on Defold meanwhile having all the metadata backend (player profle, inventory, settings, leaderboards, matchmaking, clans, rewards, items etc etc) on Gamesparks.

We also are utilising Gamelift which helps out with starting enough instances of gameservers whenever needed and is the middle tech between the matchmaking on gamesparks and the actual defold process running on a Amazon server.

The network code is created from scratch using lua sockets and we are very happy to have created it in a way that it is using the benefits of Defolds message-posting when propagating out the events to client/server.

The gameserver is authoritative and decides all physics, collision-detection, health-deduction, well mostly all game logic and the client is just a stupid renderer of whats happening serverside.
Server right now runs on a tickrate of 30 ticks/sec having no problem keeping track of 12-18 players in the same room with very little memory and processing print.

I will soon be able to stream a lot more where I actually can show and talk a lot more about what we did and how we did it. But before that we need to get this baby out to appstore.

12 Likes

Hi Andreas!

It’s looks like you be able create and run defold game as authoritative server.

Can you describe how you build and run it? Can you provide headless.settings file? Thank you in advance!

Below is my headless.settings file content and build with run commands but I’ve got my CPU use on 100%(

Now I’am doing like that:

-- build headless game
java -jar bob.jar --variant=headless clean build --variant headless --settings game_server.settings

-- run it like
./dmengine_headless

headless.settings file content below:

[project]
title = Escape from here
custom_resources = 
dependencies#0 = https://github.com/defold/extension-websocket/archive/refs/tags/3.1.0.zip
dependencies#1 = https://github.com/heroiclabs/nakama-defold/archive/refs/tags/3.1.0.zip
dependencies#2 = https://github.com/britzl/defold-input/archive/master.zip
dependencies#3 = https://github.com/britzl/broadsock/archive/1.1.1.zip
dependencies#4 = https://github.com/AGulev/jstodef/archive/refs/tags/2.0.0.zip

[bootstrap]
main_collection = /server/server.collectionc
render = /builtins/render/default.renderc

[input]
game_binding = /input/game.input_bindingc
gamepads = /builtins/input/default.gamepadsc

[display]
width = 1136
height = 640
variable_dt = 0
vsync = 0
swap_interval = 0
frame_cap = 0
update_frequency = 20

[physics]
scale = 0.02
debug = 0
max_collisions = 256
max_contacts = 256
gravity_y = -100
max_collision_object_count = 256

[script]
shared_state = 1

[android]
iap_provider = GooglePlay
package = com.britzl.publicexamples.rotate_and_move

[sprite]
max_count = 1000

[resource]
max_resources = 1000

[osx]
bundle_identifier = com.britzl.publicexamples.rotate_and_move

[ios]
bundle_identifier = com.britzl.publicexamples.rotate_and_move

[tilemap]
max_tile_count = 10000

[particle_fx]
max_count = 128
max_particle_count = 2048

[sound]
max_sound_buffers = 64
max_sound_sources = 32
max_component_count = 64

[html5]
htmlfile = /client/engine_template.html

My guess is that the engine is mostly busy waiting for the next frame, not doing actual work. You can check with the web profiler what the engine is actually doing.

Hi!

I found workaround to reduce CPU usage:

local _20_MILISECONDS = 0.02
function update(self, dt)
	if sleepTime > 0 then
            os.execute("sleep " .. tonumber(_20_MILISECONDS))
        end
	broadsock_update(dt)
end

But I have other problem with debug logs! I’m trying switch off logs but still smth logging but I cannon find what and why?

My build of headless game server:
java -jar bob.jar clean build --platform x86_64-linux --variant headless --settings game_server.settings

Server start with:
./dmengine_headless

When client game starts communicating with game server smth. logging DEBUG:SCRIPT: a lot( All my logs is disabled but what actually logging? May be smth in dmengine_headless? How to disable log which doesn’t show anything?

Starting dmengine_headless
INFO:DLIB: Log server started on port 40069
INFO:ENGINE: Target listening with name: vmi1180579.contaboserver.net - 127.0.1.1 - Linux
INFO:ENGINE: Engine service started on port 8001
INFO:GRAPHICS: Initialised graphics device 'null'
INFO:ENGINE: Defold Engine 1.5.0 (57b34ef)
INFO:DLIB: Initialized Remotery (ws://127.0.0.1:17815/rmt)
INFO:ENGINE: Loading data from: build/default
INFO:LIVEUPDATE: Could not find base .arci/.arcd. Liveupdate disabled
INFO:ENGINE: Initialised sound device 'default'
DEBUG:SCRIPT: Logger OFF
INFO:DLIB: SSDP: Started on address 172.17.0.1
INFO:DLIB: SSDP: Started on address 172.18.0.1
INFO:DLIB: SSDP: Started on address 172.19.0.1
INFO:DLIB: SSDP: Started on address 172.21.0.1
DEBUG:SCRIPT: 
DEBUG:SCRIPT: 
DEBUG:SCRIPT: 
DEBUG:SCRIPT: 
DEBUG:SCRIPT: 
DEBUG:SCRIPT: 
DEBUG:SCRIPT: 
DEBUG:SCRIPT: 
DEBUG:SCRIPT: 
DEBUG:SCRIPT: 
DEBUG:SCRIPT: 
DEBUG:SCRIPT: 
1 Like

We currently have no easy way of disabling the logging for headless variant.

But as you say, easiest is to avoid printing from the script.
If you search your code, do you have any prints ?
Perhaps add your moidule name in front of them so it’s easier to find when you use them, e.g.:
print("server.lua", log_message)

You can monkey patch the print function, and add an assert if the string is empty, or all whitespace?

1 Like

Thank you!

I found brilliant function:

old_print = print
print = function(...) 
    local calling_script = debug.getinfo(2).short_src
    old_print('Print called by: '..calling_script)
    old_print(...)
end

It shows from which script print() was invoked!

Then you write a lot of code it is difficult to maintain with scripting languages and easy to create bugs(
I have Java background and think if you creating really big game with a lot of code then it easier to handle complexity with specifically designed languages for that as Java / C#. I didn’t found game engine + editor in Java but used to write some Lua scripts, so I try Defold;)

2 Likes