Working multiplayer test

@blurredPixels

@pumpkinhead Can you upload the repl it code?

Or anybody else

do you mean put the code on the forums?
//Very useful website: https://www.gabrielgambetta.com/client-server-game-architecture.html

const HTTP = require("http");
const WebSocket = require("ws");

const UPDATE_TIME = 5; // in frames per second

class Player {
  constructor(ws, id) {
    this.x = 0;
    this.y = 0;
    this.ws = ws; // WebSocket connection
    this.id = id;
    ws.player = this;
  }
}

var players = {}; //A list of all the players
//This is a dictionary. The key will be the players' unique IDs,
//and the values will be the players themselves

var requestQueue = [];
//Instead of processing each request as they're made,
//only actually process them a few times per second
//Put them in a queue for processing when it is time

//This is a utility function that sends data to all the clients
function sendToAllPlayers(dat) {
  if (typeof dat === "object") dat = JSON.stringify(dat);

  for (let pid in players) {
    players[pid].ws.send(dat);
  }
}

//This function handles information sent from a client
function handleRequest(player, req) {
  if (req === "disconnect") {
    delete players[player.id];
    
    sendToAllPlayers({ type: "player_disconnected", id: player.id });
    return;
  }

  if (req === "connection") {
    sendToAllPlayers({ type: "player_connected", id: player.id });
    return;
  }

  if (req.type === "position") {
    player.x = +req.x; //unary plus operator converts things into numbers
    player.y = +req.y;
    return;
  }
}

var lastUpdate = 0;
//This function handles all the requests in the request queue
function handleRequests() {
  //get the time since the last update
  var now = Date.now();
  var dt = (now - lastUpdate) / 1000;
  lastUpdate = now;

  //console.log("Update");

  for (let req of requestQueue) {
    //console.log(req);
    handleRequest(req[0], req[1]);
  }

  //clear request queue
  requestQueue = [];

  //send the positions of all the players to every player, if there are any
  //to check if there are any players, check if the player list has keys
  //using .length on the player list won't work because length only works on numbered arrays
  //it is not an array, so it will not work.
  if (Object.keys(players).length > 0) {
    var posData = [];
    for (let i in players) {
      let player = players[i];
      let id = player.id;
      posData.push({
        id: id,
        x: player.x,
        y: player.y,
      });
    }

    sendToAllPlayers({ type: "positions", positions: posData, dt: dt });

    //i need to give the client the server update timestep for entity interpolation
    //entity interpolation is used to make movement look smooth, despite
    //the positions only updating a few times per second. this works by
    //simulating what happened for the player between server updates
    //in the client by interpolating the player's position, which is why
    //i must send the dt to the client
  }

  setTimeout(handleRequests, 1000 / UPDATE_TIME);
  //Not using setInterval, since if it takes longer than usual to run the function,
  //the function might execute while setInterval already ran the function again
  //overlapping the two's execution :O
}

///////////////////
// Create Server //
///////////////////

/*
//I will create an HTTP server which the WebSocket server will use for connecting...
//I think only HTTP server
const https = HTTP.createServer((req, res) => {
  res.statusCode = 400;
  res.end("This is the HTTP server for the websocket. There is nothing here in terms of HTTP content.");
});

https.listen(8080, () => {
  console.log("HTTP server running at port 8080");
})*/

const wss = new WebSocket.Server({ port: 8080 });

wss.on("connection", function(ws) { //When someone connections
  //Player limit, up to 4 people 
  if (Object.keys(players).length >= 4) {
    console.log("Server full!");
    ws.close(1013, "Server is full -- max of 4 players"); //code 1013 means "Try Again Later"
    return;
  }

  console.log("New socket opened");

  //Generate random identifier ID for the player
  var id = Math.floor(Math.random() * 99999);
  var player = new Player(ws, id);
  players[id] = player;

  ws.on("message", function(msg) { //When the server receives a message from client
    var json;

    try {
      json = JSON.parse(msg);
    } catch(err) {
      console.log("Invalid json data from " + id);
      return;
    }

    requestQueue.push([player, json]);
  })

  ws.on("close", function() { //When the player disconnects
    console.log("Socket closed");
    requestQueue.push([player, "disconnect"]);
  })

  //Tell all other clients a new player joined
  requestQueue.push([player, "connection"]);

  //Send client's ID and other players' ids and position to the client
  var posData = [];

  for (let i in players) {
    let p = players[i];
    if (p.id === id) continue; //ignore own client

    posData.push({
      id: p.id,
      x: p.x,
      y: p.y
    });
  }

  var initData = {
    type: "init",
    id: id,
    players: posData
  }

  //console.log(initData);
  ws.send(JSON.stringify(initData));
});

wss.on("listening", function() {
  console.log("Websocket server listening on port 8080");

  lastUpdate = Date.now();
  handleRequests();
})

(it uses Node.js)

1 Like

I don’t have access to repl.it, so could you upload it?

Then why would you give the code

Look:networking.html (2.1 MB)

It’s super!! Great job! I liked it =D

You can share the .wick file, just modify it so no data that can be used to hack you is there. You could probably just replace it with something like “put_private_key_here”.
Thank you so much for making this because I now know how to make a multiplayer game using the wick editor.

hey could i please get a wick file (im not going to hack it) i just really want to make a multiplayer game txh

Here’s how to fork this:

  1. Download this wick file: networking.wick (8.6 KB)
  2. Fork this on repl.it: https://replit.com/@phazrlazr/wicknet
  3. Once you’ve forked it, hit “Run” on the top and copy the link here
    (It shouldn’t say “wicknet.phazrlazr.repl.co” exactly, it should say something else)
  4. Open the wick file and go to the default script of the yellow square
  5. Put the link to your server on line 10

    (Replace the https in the beginning of the link with wss)
6 Likes

thanks if you want then i will let you know when i make a multiplayer game!

hey pumpkinhead! may is use this code?

yes you can. also discourse isn’t letting me edit the og post to put the steps on how to fork this, because i made it too long ago.

3 Likes

for testing you can duplicate tabs for 2 players and it does work

nice work can you provide a wick file

the file’s over here

oh ok… well thanks

hey @pumpkinhead there is a bug with the networking file I think it’s because the websocket in the repl needs to be updated but I don’t know how to do this, if you could help (if you know what’s going on with the repl) I would appreciate it thanks.

if he doesn’t fix i will

1 Like

What Type of code is this?