DefNet Capability

Hi, and sorry for so many questions in a single day here :sweat:

It’s really simple to make a p2p network and make a LAN multiplayer with DefNet, but is it possible to make online multiplayer that everyone in the world can come and join? If it’s possible, so how could I do so? (But I still want it to be p2p network)

1 Like

That is more complicated. I would recommend that you have a central server for the matchmaking and then hand over to the game clients for the gameplay with client authoritative play where one client acts as a server.

It might work if the client that acts as a host is able to share a public IP with the other players somehow. Perhaps as a QR code or link in a message or something.

2 Likes

If you like the idea of global servers without creating them at runtime, then here is an example of a Cold Path game server implementation using the defnet module
Sources: https://github.com/jalhund/cold-path-server
How to use: Global servers - Cold Path

6 Likes

Like Quake?

Yes, exactly!

2 Likes

Hi @britzl, there is a question that I want to ask with DefNet:

  • How to send a data from the server to a specific client?

I’ve seen a function with the server is: server.send(server, data, client)
I think this is a function that is used for that purpose, but I didn’t know how to use this function. I think I know what to put in the data parameter, but what to put to the server and client?

Correct, that is the right function to use. You have two ways to use the tcp_server and tcp_client modules:

local tcp_server = require "defnet.tcp_server"

local my_server = tcp_server.create(...)

-- option 1
my_server.start()

-- option 2
tcp_server.start(my_server)

The same goes for all of the other functions, such as send:

my_server.send("some data", client)
tcp_server.send(my_server, "some data", client)

So it is just a matter of preference. I prefer the second way where a reference to the server instance is used as the first argument.

Now, the client argument is the open socket connection for the client you wish to send to. You can get a reference to the client from for instance the on_connected or on_data callbacks.

2 Likes

Hi, it’s me again. So to organize clients, I was trying to put them in a table so that can call back to the client whenever I want, but when I do so, I got this error

ERROR:SCRIPT: defnet/tcp_server.lua:181: main/network/server.script:13: unsupported value type in table: userdata
stack traceback:
  [C]:-1: ?
  defnet/tcp_server.lua:181: in function update
  main/network/server.script:52: in function <main/network/server.script:49>

Do you have a solution for this? I know that I can put them in a variable, but it’s not really flexible to reference and organize the data. I don’t really know about the userdata type in lua, so I cannot really think of a solution for this.

Hmm, what are you doing with the table? Are you using msg.post()? You can’t post userdata (the socket connection in this case).

Actually I’m not post userdata using msg.post, but I want to add the client with other data such as name, ip and port, state, etc. to the table in the server script, so that I can organize the data of the client and talk to them easier.
Right now I think it’s not possible, so is there a way to talk to the specific client right inside the on_data function (after the server receive the message, it send a certain data back to that client)?

Could you please share the code you are using?

https://drive.google.com/drive/folders/1oKf6T-ejInkLHIyRPhSlbnnh6I-7pJmF?usp=sharing

Hi, for the server.script, I put that in \main\network\server.script, could you have a look please?

local players = {}

local function on_data(data, ip, port, client)
	print("[DATA RECEIVED] TCP server received data '" .. data .. "' from " .. ip .. ":" .. port)
	local data = cjson.decode(data)
	if data.id == "connect" then
		table.insert(players, {ip = ip, port = port, name = data.name, client = client})
		msg.post("server:/server#server", "update_players", {ip = players})
	end
end

Here’s what it looks like in the on_data function, and the error is also from here.

But you are posting userdata above! The client is a socket connection object of type “userdata”. You can’t post it since our msg.post code in the engine doesn’t know how to serialize it.

I think what we need is a way to easily look up a client in the tcp server or associate additional data with the clients in the server.

1 Like

OMG I’m so sorry for that! I didn’t know why I forgot that when I send the players data that it’s already contain the the userdata :sweat::sweat::sweat:I, all the time, thought that the problem is that I put the userdata in the table :sweat:

So sorry for taking your time for this, and thank you so much for your help! Have a nice day!

Not a problem!

1 Like

Hi @britzl , it’s me again :sweat:
Anw, do you still have the code for this example? I’ve clicked the link but seem like the page has been removed/deleted. But the platformer example is exactly what I try to make. I now (kinda) know how to send message, receive message with client and server, looking for ip address using p2p_discovery. Still, there are so much more to do with multiplayer game like how you can only move your character without moving another? What kind of data to send between players (I don’t think that sending position every frame and their animation is the right way, but instead to send their input? And about the enemy, how to make them in sync and if other players kill it, it should be killed in sync - which means every players see that it got killed?). Is there any standard way of doing it (or like the method that people usually use)?

Thank you for your help!

You can browse old versions by going through the commit history on GitHub to find when the multiplayer example was added. Here it is:

It is old and it was removed for a reason (I can’t remember why exactly but I was probably not happy with the results).

There are many ways in which to achieve this:

  • Client authoritative multiplayer - Here you trust the players and let each of them handle their own simulation and only send state changes to the other clients (“I shot a bullet at position P”, “I am at position P” or “I killed enemy X”).
  • Server authoritative multiplayer - In this scenario you do not trust the players at all. You run the game on the server and the clients send any actions they do to the server and get a world state back. It is unlikely that you will be able to send client updates each frame so instead you let the clients simulate and predict what the clients do and only correct their simulations if they deviate enough from the server (“Player X moved in direction D last frame. I predict that Player X will move in direction D this frame too”).

You should read up on the different solutions. I’m sure there are many great articles out there!

Here’s one on the networking in the Source Engine (TF, HalfLife etc):

https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking

2 Likes