I'm making a mod for shapez.io, multiplayer, but I have some issues with webRTC.
When I'm running the two clients local they can connect via an external signalling server. So they can talk via a datachannel.
Whem I'm using clients from different networks they don't connect. There is no error, but the offers and answers are send via the signalling server.
I do not understand webRTC very well so I hope some one can help me.
The current github code is online on https://thomasbrants.nl/shapez.io-multiplayer/.
Goto to multiplayer -> new game or resume game -> enter wss://thomasbrants.nl:8888
-> you get a uuid
Open a new client -> multiplayer -> join -> enter wss://thomasbrants.nl:8888
-> enter uuid
Github: https://github.com/DJ1TJOO/shapez.io/tree/multiplayer
This code generates a uuid and the user can share this. It connects to the signalling server and creates a room with the uuid. Then when createPeer is called it tries to connect to a peer.
this.connectionId = uuidv4();
// @ts-ignore
var socket = io(this.host, { transport: ["websocket"] });
var socketId = undefined;
var connections = [];
socket.on("connect", () => {
socket.on("id", id => {
socketId = id;
});
socket.emit("createRoom", this.connectionId);
//Create peer
socket.on("createPeer", async data => {
const config = {
iceServers: [{
urls: "stun:stun.1.google.com:19302",
}, ],
};
const pc = new RTCPeerConnection(config);
const dc = pc.createDataChannel("game", {
negotiated: true,
id: 0,
});
//Create offer
await pc.setLocalDescription(await pc.createOffer());
pc.onicecandidate = ({ candidate }) => {
if (candidate || pc.signalingState === "stable") return;
console.log("Offer send");
console.log(pc.signalingState);
console.log(pc.getStats);
socket.emit("offer", {
offer: pc.localDescription.sdp,
socketIdReceiver: socketId,
socketIdSender: data.socketIdSender,
room: data.room,
});
};
//Answer
socket.on("answer", data => {
if (data.socketIdReceiver !== socketId || pc.signalingState === "stable") return;
pc.setRemoteDescription({
type: "answer",
sdp: data.answer,
});
console.log("Answer received");
console.log(pc.signalingState);
console.log(pc.getStats());
var onOpen = event => {
//not empty but not related
};
var onMessage = ev => {
//not empty but not related
};
dc.onopen = onOpen;
dc.onmessage = onMessage;
onOpen();
pc.ondatachannel = event => {
let receiveChannel = event.channel;
receiveChannel.onmessage = onMessage;
receiveChannel.onopen = onOpen;
};
connections.push({ pc: pc, dc: dc });
});
});
});
Here the uuid is put in and then it connects to the signalling server. And tries to make a connection.
// @ts-ignore
var socket = io(host, { transport: ["websocket"] });
var socketId = undefined;
socket.on("connect", () => {
console.log("Connected to the signalling server");
socket.on("id", id => {
socketId = id;
console.log("Got id: " + id);
socket.emit("joinRoom", connectionId, socketId);
});
socket.on("error", () => {
this.dialogs.showWarning(
T.dialogs.multiplayerGameError.title,
T.dialogs.multiplayerGameError.desc + "<br><br>"
);
});
socket.on("offer", async data => {
if (data.socketIdSender !== socketId) return;
console.log("offer received");
const config = {
iceServers: [
{
urls: "stun:stun.1.google.com:19302",
},
],
};
const pc = new RTCPeerConnection(config);
const dc = pc.createDataChannel("game", {
negotiated: true,
id: 0,
});
await pc.setRemoteDescription({
type: "offer",
sdp: data.offer,
});
await pc.setLocalDescription(await pc.createAnswer());
pc.onicecandidate = ({ candidate }) => {
if (candidate) return;
socket.emit("answer", {
socketIdReceiver: data.socketIdReceiver,
socketIdSender: data.socketIdSender,
answer: pc.localDescription.sdp,
room: data.room,
});
console.log("answer send");
};
var gameDataState = -1;
var gameData = "";
var onMessage = ev => {
//not empty but not related
};
dc.onmessage = onMessage;
pc.ondatachannel = event => {
let receiveChannel = event.channel;
receiveChannel.onmessage = onMessage;
};
});
});