first commit! 🎉
This commit is contained in:
commit
c35c18bbbc
19 changed files with 1046 additions and 0 deletions
231
server/ws.js
Normal file
231
server/ws.js
Normal file
|
@ -0,0 +1,231 @@
|
|||
import { WebSocketServer } from "ws";
|
||||
import Log from "../common/log.js";
|
||||
import { WORLD_SIZE } from "../common/world.js";
|
||||
import Player from "../common/player.js";
|
||||
import Prop from "../common/prop.js";
|
||||
|
||||
const TICK_RATE = 30;
|
||||
|
||||
var clients = [];
|
||||
var props = {
|
||||
1: new Prop("the silly",
|
||||
WORLD_SIZE / 2, WORLD_SIZE / 2,
|
||||
"#ff00ff", "/img/ball.png")
|
||||
};
|
||||
var last_update = 0.0;
|
||||
var ticks = 0;
|
||||
var wss;
|
||||
|
||||
export function init(http_server) {
|
||||
wss = new WebSocketServer({ server: http_server });
|
||||
|
||||
wss.on("connection", (socket) => {
|
||||
clients.push(socket);
|
||||
|
||||
socket.on("error", error => {
|
||||
Log.warn("Websocket connection closed due to error: " + error);
|
||||
if (socket.player) {
|
||||
broadcast({
|
||||
type: "leave",
|
||||
id: socket.id,
|
||||
});
|
||||
}
|
||||
clients = clients.filter(s => s != socket);
|
||||
});
|
||||
|
||||
socket.on("close", () => {
|
||||
if (socket.player) {
|
||||
Log.info(socket.player.name + " left the game.");
|
||||
broadcast({
|
||||
type: "leave",
|
||||
id: socket.id,
|
||||
});
|
||||
}
|
||||
clients = clients.filter(s => s != socket);
|
||||
});
|
||||
|
||||
socket.on("message", msg => {
|
||||
try {
|
||||
const data = JSON.parse(msg);
|
||||
if (!data.type)
|
||||
throw new Error("Type not specified");
|
||||
|
||||
switch (data.type) {
|
||||
case "join":
|
||||
if (!data.name)
|
||||
throw new Error("Name cannot be null");
|
||||
|
||||
var player_name = data.name.slice(0, 32);
|
||||
player_name = player_name.replaceAll('<', '<');
|
||||
player_name = player_name.replaceAll('>', '>');
|
||||
player_name = player_name.trim();
|
||||
|
||||
socket.id = generateID();
|
||||
socket.player = new Player(
|
||||
data.name.slice(0, 32),
|
||||
WORLD_SIZE / 2,
|
||||
WORLD_SIZE / 2,
|
||||
randomColour()
|
||||
);
|
||||
|
||||
Log.info(socket.player.name + " joined the game.");
|
||||
|
||||
var lobby_players = {};
|
||||
clients.forEach(client => {
|
||||
if (!client.player) return;
|
||||
lobby_players[client.id] = {
|
||||
name: client.player.name,
|
||||
x: client.player.x,
|
||||
y: client.player.y,
|
||||
col: client.player.colour,
|
||||
};
|
||||
});
|
||||
|
||||
var lobby_props = {};
|
||||
Object.keys(props).forEach(id => {
|
||||
const prop = props[id];
|
||||
lobby_props[id] = {
|
||||
name: prop.name,
|
||||
x: prop.x,
|
||||
y: prop.y,
|
||||
col: prop.colour,
|
||||
sprite: prop.sprite,
|
||||
}
|
||||
});
|
||||
|
||||
socket.send(JSON.stringify({
|
||||
type: "welcome",
|
||||
id: socket.id,
|
||||
tick: ticks,
|
||||
players: lobby_players,
|
||||
props: lobby_props,
|
||||
}));
|
||||
|
||||
clients.forEach(s => {
|
||||
if (s.id == socket.id) return;
|
||||
// send player joined event
|
||||
s.send(JSON.stringify({
|
||||
type: "join",
|
||||
id: socket.id,
|
||||
name: socket.player.name,
|
||||
x: socket.player.x,
|
||||
y: socket.player.y,
|
||||
col: socket.player.colour,
|
||||
}));
|
||||
});
|
||||
break;
|
||||
case "update":
|
||||
if (!socket.player)
|
||||
throw new Error("Player does not exist");
|
||||
if (data.x === undefined || data.y === undefined)
|
||||
throw new Error("Movement vector not provided");
|
||||
if (data.tick === undefined)
|
||||
throw new Error("User tick not provided");
|
||||
|
||||
socket.player.tick = data.tick;
|
||||
socket.player.in_x = Math.min(1.0, data.x);
|
||||
socket.player.in_y = Math.min(1.0, data.y);
|
||||
break;
|
||||
case "chat":
|
||||
if (data.msg === undefined)
|
||||
throw new Error("Attempted chat with no message");
|
||||
Log.info('<' + socket.player.name + '> ' + data.msg)
|
||||
data.msg = data.msg.replaceAll("<", "<")
|
||||
data.msg = data.msg.replaceAll(">", ">")
|
||||
data.msg = data.msg.replaceAll("\n", "");
|
||||
data.msg = data.msg.trim();
|
||||
if (data.msg == "") return;
|
||||
clients.forEach(client => {
|
||||
client.send(JSON.stringify({
|
||||
type: "chat",
|
||||
player: socket.id,
|
||||
msg: data.msg,
|
||||
}));
|
||||
});
|
||||
break;
|
||||
default:
|
||||
throw new Error("Invalid message type");
|
||||
}
|
||||
} catch (error) {
|
||||
if (socket.player) {
|
||||
Log.warn("Received invalid packet from " + socket.player.id + ": " + error);
|
||||
socket.send(JSON.stringify({
|
||||
type: "kick",
|
||||
reason: "Received invalid packet",
|
||||
}));
|
||||
} else {
|
||||
Log.warn("Received invalid packet: " + error);
|
||||
}
|
||||
socket.close();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
function update() {
|
||||
var delta = (performance.now() - last_update) / 1000;
|
||||
|
||||
// update players
|
||||
var frame_players = {};
|
||||
clients.forEach(client => {
|
||||
if (!client.player) return;
|
||||
client.player.update(delta);
|
||||
client.player.x = Math.max(Math.min(client.player.x, WORLD_SIZE), 0);
|
||||
client.player.y = Math.max(Math.min(client.player.y, WORLD_SIZE), 0);
|
||||
frame_players[client.id] = {
|
||||
x: client.player.x,
|
||||
y: client.player.y,
|
||||
};
|
||||
});
|
||||
|
||||
// god help me this code is awful
|
||||
// really leaning on this just being a tech demo here
|
||||
var prop_players = [];
|
||||
clients.forEach(client => {
|
||||
if (client.player) prop_players.push(client.player);
|
||||
});
|
||||
var frame_props = {};
|
||||
Object.keys(props).forEach(id => {
|
||||
const prop = props[id];
|
||||
prop.update(delta, prop_players);
|
||||
frame_props[id] = {
|
||||
x: prop.x,
|
||||
y: prop.y,
|
||||
}
|
||||
});
|
||||
|
||||
// send update to players
|
||||
clients.forEach(client => {
|
||||
if (!client.player) return;
|
||||
client.send(JSON.stringify({
|
||||
type: "update",
|
||||
tick: client.player.tick,
|
||||
players: frame_players,
|
||||
props: frame_props,
|
||||
}));
|
||||
})
|
||||
|
||||
last_update = performance.now();
|
||||
ticks++;
|
||||
setTimeout(update, 1000 / TICK_RATE);
|
||||
}
|
||||
|
||||
function broadcast(data) {
|
||||
clients.forEach(socket => {
|
||||
socket.send(JSON.stringify(data));
|
||||
});
|
||||
}
|
||||
|
||||
function generateID() {
|
||||
// five random digits followed by five digits from the end of unix timestamp
|
||||
return (10000 + Math.floor(Math.random() * 90000)).toString() + (new Date() % 100000).toString();
|
||||
}
|
||||
|
||||
function randomColour() {
|
||||
var res = "#";
|
||||
for (var i = 0; i < 6; i++)
|
||||
res += "0123456789abcdef"[Math.floor(Math.random() * 16)];
|
||||
return res;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue