代码拉取完成,页面将自动刷新
同步操作将从 pqo/peer-stream 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
"4.27.2";
// node signal.js player=88 engine=8888 token=hello limit=4
const WebSocket = require("ws");
const http = require("http");
// process.argv[0] == 'path/to/node.exe'
// process.argv[1] === __filename
const args = process.argv.slice(2).reduce((pairs, pair) => {
let [key, ...value] = pair.split("=");
value = value.join("") || "true";
try {
value = JSON.parse(value);
} catch {}
pairs[key] = value;
return pairs;
}, {});
Object.assign(
global,
{
player: 88,
engine: 8888,
token: "hello",
limit: 4,
nextPlayerId: 100,
},
args
);
const ENGINE = new WebSocket.Server({ noServer: true });
ENGINE.ws = {}; // Unreal Engine's WebSocket
// browser client
const PLAYER = new WebSocket.Server({
noServer: true,
clientTracking: true,
});
http
.createServer()
.on("upgrade", (request, socket, head) => {
try {
// 认证
// if (request.url.slice(1) !== token) throw "";
if (PLAYER.clients.size >= limit) throw "";
} catch (err) {
socket.destroy();
return;
}
PLAYER.handleUpgrade(request, socket, head, (ws) => PLAYER.emit("connection", ws, request));
})
.listen(player, () => console.log("֍ signaling for player:", player));
http
.createServer()
.on("upgrade", (request, socket, head) => {
try {
// 1个信令服务器只能连1个UE
if (ENGINE.ws.readyState === WebSocket.OPEN) throw "";
} catch (err) {
socket.destroy();
return;
}
ENGINE.handleUpgrade(request, socket, head, (ws) => ENGINE.emit("connection", ws, request));
})
.listen(engine, () => console.log("✡ signaling for engine:", engine));
ENGINE.on("connection", (ws, req) => {
ws.req = req;
ENGINE.ws = ws;
console.log("✅ Engine connected:", req.socket.remoteAddress, req.socket.remotePort);
ws.on("message", (msg) => {
try {
msg = JSON.parse(msg);
} catch (err) {
console.error("❌【JSON error】 Engine:", msg);
return;
}
// Convert incoming playerId to a string if it is an integer, if needed. (We support receiving it as an int or string).
const playerId = String(msg.playerId || "");
delete msg.playerId; // no need to send it to the player
console.log("Engine:", msg.type, playerId);
if (msg.type === "ping") {
ws.send(JSON.stringify({ type: "pong", time: msg.time }));
return;
}
const p = [...PLAYER.clients].find((x) => x.playerId === playerId);
if (!p) {
console.error("❌ player not found:", playerId);
return;
}
if (["answer", "iceCandidate"].includes(msg.type)) {
p.send(JSON.stringify(msg));
} else if (msg.type == "disconnectPlayer") {
p.send(msg.reason);
p.close(1011, "Infinity");
} else {
console.error("❌ invalid Engine message type:", msg.type);
}
});
ws.on("close", (code, reason) => {
// reason是buffer??
console.log("❌ Engine closed:", String(reason));
for (const client of PLAYER.clients) {
client.send(`❌ Engine:${engine} stopped`);
}
});
ws.on("error", (error) => {
console.error("❌ Engine connection error:", error);
// A control frame must have a payload length of 125 bytes or less
// ws.close(1011, error.message.slice(0, 100));
});
// sent to Unreal Engine as initial signal
ws.send(
JSON.stringify({
type: "config",
peerConnectionOptions: {
// iceServers: [{
// urls: [
// "stun:stun.l.google.com:19302",
// "stun:stun1.l.google.com:19302",
// "stun:stun2.l.google.com:19302",
// "stun:stun3.l.google.com:19302",
// "stun:stun4.l.google.com:19302",
// ],},],
},
})
);
for (const client of PLAYER.clients) {
// reconnect immediately
client.send(`✅ Engine:${engine} started`);
client.close(1011, "1");
}
});
// every player
PLAYER.on("connection", async (ws, req) => {
const playerId = String(++nextPlayerId);
console.log("✅ player", playerId, "connected:", req.socket.remoteAddress, req.socket.remotePort);
ws.req = req;
ws.playerId = playerId;
ws.on("message", (msg) => {
if (ENGINE.ws.readyState !== WebSocket.OPEN) {
ws.send(`❌ Engine:${engine} not ready`);
return;
}
try {
msg = JSON.parse(msg);
} catch (err) {
console.info("player", playerId, String(msg));
ws.send("hello " + msg.slice(0, 100));
return;
}
console.log("player", playerId, msg.type);
msg.playerId = playerId;
if (["offer", "iceCandidate"].includes(msg.type)) {
ENGINE.ws.send(JSON.stringify(msg));
} else if (msg.type === "debug") {
let debug;
try {
debug = String(eval(msg.debug));
} catch (err) {
debug = err.message;
}
ws.send("【debug】" + debug);
} else {
ws.send("hello " + msg.type);
}
});
ws.on("close", (code, reason) => {
console.log("❌ player", playerId, "closed:", String(reason));
if (ENGINE.ws.readyState === WebSocket.OPEN)
ENGINE.ws.send(JSON.stringify({ type: "playerDisconnected", playerId }));
});
ws.on("error", (error) => {
console.error("❌ player", playerId, "connection error:", error);
});
});
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。