Disclaimer
I know this is a bit long, but I want to give people that want to help as much info on what I tried / want to do as possible.
Background / Why
I am trying to make a game that is a bit like Munchkin, For The King or maybe DND, but with controls similar to Jackbox games. Basically, one would start the game on PC where you set up the game with the rules/map you want, and then the players join with their phones on a website.
The players would basically have their character, inventory and abilities on their phone where they control what they want to do, with the battles and map being shown on the PC.
My I Idea would be to use Godots WebSocket Multiplayer with the PC build acting as the server. The build for the clients would be a web build that would have to be hosted by the server build / on the PC.
The problem
And this is my problem. How would I best set up the PC build to launch the web build so that people in the local network can start the game in their browser.
I have tried Caddy to serve the web build. This works when serving on http://localhost
and using non-secure WebSockets ws://
. This is what I would like to achieve, but having it available to everyone on the LAN.
The Caddyfile for working localhost server
http://localhost
file_server browse {
index Multiplayer_Test.html
}
header {
# these headers are required or godot shouts at you
Cross-Origin-Opener-Policy "same-origin"
Cross-Origin-Embedder-Policy "require-corp"
}
What I’ve tried so far
Hosting to LAN (HTTP)
When I use the same configuration as before for localhost
but use http://my.local.ip.address
Godot yells at me with:
With the important part being:
Secure Context ... (use HTTPS)
which would mean that I need to serve the web game over HTTPS instead of HTTP. This in turn means, that I can’t use ws://
but need to use the secure WebSockets wss://
for which I need a certificate.
Possible way forward
Is it possible to turn off the requirement to use HTTPS? Since it’s just for game data on the LAN, it doesn’t need to be encrypted, I would think. This would probably fix my problem if possible.
Creating a certificate to use wss://
As I could not find anything about hosting a Godot web export without HTTPS I tried switching the networking over to use TLS/wss://
.
For this, I followed this tutorial to create self-signed certificates with Godot and converted it to Godot 4, resulting in the following script:
X509 self-signed certificate generator
extends Node
# https://www.youtube.com/watch?v=gcopx40pwvY
var x509_cert_filename = "X509_Certificate.crt"
var x509_key_filename = "x509_Key.key"
@onready var X509_cert_path = "user://Certificate/" + x509_cert_filename
@onready var X509_key_path = "user://Certificate/" + x509_key_filename
var CN = "192.168.178.37" # nameserver
var O = "Gaweringo" # organization
var C = "AT" # country
var not_before = "20240210000000"
var not_after = "20250210000000"
# Called when the node enters the scene tree for the first time.
func _ready():
if DirAccess.dir_exists_absolute("user://Certificate"):
pass
else:
DirAccess.make_dir_absolute("user://Certificate")
CreateX509Cert()
print("Certificate Created")
func CreateX509Cert():
var CNOC = "CN=" + CN + " ,O=" + O + ",C=" + C
var crypto = Crypto.new()
var crypto_key = crypto.generate_rsa(4096)
var X509_cert = crypto.generate_self_signed_certificate(crypto_key, CNOC, not_before, not_after)
X509_cert.save(X509_cert_path)
crypto_key.save(X509_key_path)
I then used the generated certificate in the multiplayer implementation:
The basic multiplayer code
func _on_host_pressed():
var server = WebSocketMultiplayerPeer.new()
var error = server.create_server(6942, "*", TLSOptions.server(key, cert))
if error != OK:
print("Problem creating server:" + str(error))
return
multiplayer.set_multiplayer_peer(server)
print("server done")
func _on_join_pressed():
var peer = WebSocketMultiplayerPeer.new()
var error = peer.create_client("wss://192.168.178.37:6942", TLSOptions.client(cert))
if error != OK:
print("failed to join: " + str(error))
return
multiplayer.set_multiplayer_peer(peer)
But when I try to use this implementation, the connection from the client to the server fails, with the following error showing up in the debugger: _do_handshake: TLS handshake error: -9984
when I run two Windows builds and WebSocket connection to 'wss://192.168.178.37:6942/' failed
on the web build in Chrome.
From this discussion, it seems like there might be a problem with my certificates, but I can’t really think of what I could do differently. Or more specifically, the solutions in this discussion seems to be to not use an IP address, but I can’t have a domain name on LAN.
The strange thing is, that if I use Postman to try the WebSocket connection it actually connects, even from a different PC on the LAN, and it shows up as a new client having connected to the server.
Well, at least it did, until I just checked it again while writing this part. Now I am getting this error in Postman:
Postman wss connection error
Error: write EPROTO 124881672:error:0400006b:RSA routines:OPENSSL_internal:BLOCK_TYPE_IS_NOT_01:../../../../src/third_party/boringssl/src/crypto/fipsmodule/rsa/padding.c:108:
124881672:error:04000088:RSA routines:OPENSSL_internal:PADDING_CHECK_FAILED:../../../../src/third_party/boringssl/src/crypto/fipsmodule/rsa/rsa_impl.c:676:
124881672:error:10000072:SSL routines:OPENSSL_internal:BAD_SIGNATURE:../../../../src/third_party/boringssl/src/ssl/handshake_client.cc:1191:
With this one, there seem to be so many things that could be a problem, that I don’t really know how to check and don’t really know where to start fixing things.
Wrapping up
Is what I’m trying to do here even the right approach?
If not, what would be some of your ideas that I could try?
If it is, how can I make this work?
Thanks a lot for reading this long cry for help ; )