Navigation

  • Recent
  • Tags
  • Users
  • Search
  • Login
Colyseus
  • Login
  • Search
  • Recent
  • Tags
  • Users

Documentation GitHub

We're migrating to GitHub Discussions. This forum does not accept new registrations since April 6, 2023.
  1. Home
  2. TeeTeeHaa
  3. Posts
  • Profile
  • More
    • Continue chat with TeeTeeHaa
    • Flag Profile
    • Following
    • Followers
    • Topics
    • Posts
    • Best
    • Groups

Posts made by TeeTeeHaa

C# equivalent of Schema library?

I currently use Colyseus for a TypeScript/browser project and really like it. I especially like its Schema library, because after getting the basic things running (server, client, rooms, state) it is sooooo easy to add (and change and remove) variables which are automatically synchronized from the server to the client.

Can anybody recommend a pure C# library which provides exactly that feature (making adding and changing synchronized variables as easy as possible)?

On its GitHub page Schema lists some libraries under "inspiration" (protocol buffers, flatbuffers, schemapack, avro) but those don't seem to completely provide what I am looking for (only serialization, not the whole incremental delta synchronization).

I am aware that Colyseus has a C#/Unity client but in a project with a C#/Unity client I would prefer a C# server because having the same programming language everywhere makes things easier in my opinion.

posted in General Discussion • 2 Jan 2022, 14:54
preventing client from creating rooms on the server

If your server is fully responsible for the creation and deletion of rooms and the matchmaking of players into them and...
if your server will give the client a room reservation in some way and...
if your client will only connect to the server with a room reservation using client.consumeSeatReservation and...
if you want to prevent any client from ever creating a room on the server and...
if you do not mind to use a dirty workaround...

...you can override the private (D'OH) property exposedMethods of the Server class:

const gameServer = new Server();
const tempServer = gameServer as any; // force access to private property by casting to any
tempServer.exposedMethods = []; // override property with empty array to not expose those methods anymore
gameServer.listen(port);

Yes, it is dirty, it might break in the future, it might not work for you, but it works perfectly for me and it made me giggle maniacally.

posted in Questions & Help • 2 Jun 2021, 21:37
RE: Dynamic Rooms (sovled)

From what I know about Colyseus and Mazmorra they seem to be the perfect fit: Each dungeon floor in Mazmorra is exactly one room in Colyseus, created and deleted by demand. But as far as I know players in different dungeon floors / rooms do not see each other and do not interact with each other - except within the chat, which is a totally different system.

But what about cross-room-interaction?

Let's assume I want to make a MMORPG with a (logically) twodimensional, persistent game world and hundreds of players. Players have a "sight range", both for gameplay and technical reasons. Players only see each other and can interact with each other inside that sight range. Based on that sight range players could technically be "clustered" in some way - maybe rooms, maybe not, maybe something else. In case they are clustered in rooms, maybe even according to predefined areas of the game world, in the simplest case in quadratic areas, there needs to be some interaction/connection between the rooms, because the player being near the border of such an area need to see the players on the other side of the border, at least up to their sight range.

Are there any "best practices" regarding such a scenario?

Currently I use one single room (of Colyseus) for the whole game world, created at server start and deleted at server shutdown, and never ever a second room. Regarding the state synchronization (of Colyseus) including all player data like position for example I currently think about using the filter functions (of Colyseus). But so far I really doubt that this is a great idea, mostly for performance reasons and because those functions might not be intended for that.

I'd really appreciate some suggestions and pros and cons for this scenario.

posted in Questions & Help • 2 Jun 2021, 12:24
RE: Async authoritative turn-based multiplayer in scope for Colyseus? (sovled)

I really like Colyseus and use it for my games with synchronous gameplay. For the game you described, with asynchronous gameplay, I personally would not use Colyseus.

Small definition of terms to avoid misunderstandings:
"synchronous gameplay" means players who are online and playing see each other and can interact with each other instantly.
"asynchronous gameplay" means players go online and play independently from each other, comparable with physical board games with a turn order for players.

If I would make a game which has asychronous gameplay and which has a game client (frontend) and game server (backend) being implemented in JavaScript or TypeScript and the game server is running on node.js...

...I would make the game server a simple HTTP server receiving requests over HTTP POST including "stringified" JSON objects and again sending back "stringified" JSON objects as HTTP responses. As hillarious as it might sound I would start with the "hello world" example on the website of node.js (see here) and start building the game server from there (actually I already did exactly that myself). The game client would simply do HTTP POST requests to the server, with all data required for the game, for example authentication or gameplay inputs, in the POST-part of the request, nicely wrapped as JSON object. The game server would process those requests and send the game state back, again as JSON object. Especially at the beginning of a JavaScript/TypeScript project using JSON is great because it is so simple. Later, if the game gets bigger, either because of growing amount of data or growing amount of players, the JSON could be swapped against something else, for example BSON or MsgPack.

In this scenario any "event" is initiated by the game client and the game server only reacts to those. If this scenario must be extended because the game server wants to initiate an event, for example because one player wants to send a chat message to the another player who might currently be registered as "online", the simplest way would be to use long polling. A friend of mine currently makes an asynchronous game just like that and it is working really good, probably because of the simplicity of the used network technology.

Maybe an asynchronous game can even be made with Colyseus, but from what I know about Colyseus it is not a good fit.

posted in Questions & Help • 2 Jun 2021, 12:06
How to reset callbacks for state changes?

Hello everybody. I have two questions about resetting callbacks for state changes for data based on schema:

#1

Set onChange callback for collection of primitive types based on schema:
https://docs.colyseus.io/state/schema/#onchange-instance-key

room.state.players.onChange = (player, key) => {
    console.log(player, "have changes at", key);
};

Question: How to reset that callback? Is the following correct?

room.state.players.onChange = undefined;

#2

Set listen callback on single property based on schema:
https://docs.colyseus.io/state/schema/#listenprop-callback

state.listen("currentTurn", (currentValue, previousValue) => {
    console.log(`currentTurn is now ${currentValue}`);
    console.log(`previous value was: ${previousValue}`);
});

Question: How to reset that callback? The following does not work (at least not in TypeScript)!

state.listen("currentTurn", undefined); // compiler error, at least in TypeScript

P.S.:
Plenty other features of Colyseus work really fine for me. 👍

posted in Questions & Help • 18 Apr 2021, 17:21
RE: Documentation improvement suggestions

Thank you for your fast and positive response, @endel. I suggest the following additional changes to make the documentation fully consistent within in itself:

send(type, message)
I think this should be:
send(identifier, message)

Send message a type of message to the client.
I think this should be:
Send message with identifier and payload message to the client.

The type can be either a string or a number.
I think this should be:
The identifier can be either a string or a number.

// sending message with string type
I think this should be:
// sending message with string identifier
Because it should be consistent with:
// sending message with number identifier

The green "Tip - See how to handle these messages on client-side." was removed. I'm not sure whether this was intentional. I think it should come back.

posted in General Discussion • 16 Feb 2021, 20:13
Documentation improvement suggestions

https://docs.colyseus.io/server/client/#sendtype-message

send(type, message)

I suggest not to call this "type" because "type" has a meaning in JavaScript/TypeScript (pun intended, proving my point). Maybe call it "messageId", similar to "roomId" or "clientId".

//
// sending message with string type
//
client.send("powerup", { type: "ammo" });

//
// sending message with number type
//
client.send(1, { type: "ammo"});

Regarding { type: "ammo" } I suggest not to call this "type" because of the very same reason and because it currently can be mistaked for the "type" mentioned above. Maybe call it "poweruptype" or "category" or any other synonym for "type".

class MyMessage extends Schema {
  @type("string") message: string;
}

const data = new MyMessage();
data.message = "Hello world!";

client.send(data);

Why does client.send have no "type" (in the sense of "messageId") as the first parameter?

https://docs.colyseus.io/client/room/#onmessage
C# example

class PowerUpMessage {
  string type;
}

room.OnMessage<PowerUpMessage>("powerup", (message) => {
  Debug.Log ("message received from server");
  Debug.Log(message);
});

/**
 * Handling schema-encoded messages:
 */
room.OnMessage("powerup", (message) => {
  if (message is MyMessage)
  {
    Debug.Log ("MyMessage type has been received");
    Debug.Log(message);
  }
  else if (message is AnotherMessage) {
    // ...
  }
});

In both room.OnMessage functions there actually is a "type" (in the sense of "messageId") as first parameter.

In general I am missing TypeScript examples in the client documentation. In the server documentation there are plenty of those.

This being said the whole documentation is quite good in my opinion. Nevertheless there are some details which could be clearer, for example those mentioned here.

posted in General Discussion • 13 Feb 2021, 22:44
RE: Can I extend the Client and the Room class?

I want the code of my own classes for rooms look and work similar both on the client and on the server.

In a Colyseus server the function creating rooms, Server.define, takes a custom room class as argument. That custom class has to extend the server's room class, for example export class MyServerRoom extends Room<MyState>, and is instantiated by Server.define on demand.

export class MyServerRoom extends Room<MyState> { /* ... */ }

Server.define("myserverroom", MyServerRoom, options)

In a Colyseus client the functions creating rooms, Client.joinOrCreate or Client.consumeSeatReservation or the others, do not take a custom class as argument. Instead they instantiate and return (a promise to) the client's room class, Room<MyState>. As far as I know one cannot simply cast this to a custom room class which extends the client's room class.

Client.consumeSeatReservation<MyState>(roomReservation, MyState)
.then((room: Room<MyState>) => { /* ... */ }

The code in my first post tries to overload the client's internal method createRoom to instantiate a custom room class (extending the client's room class), which is then cast "down" to the client's room class and which is then cast "back up" to the custom room class after it is returned by Client.joinOrCreate or Client.consumeSeatReservation.

I assume what I want is Client.joinOrCreate or Client.consumeSeatReservation taking a custom room class (extending the client's room class) as argument and returning an instance of that class (instead of the plain client's room class).

Another thing about similarity: The server's room class has its "room lifecycle" methods, for example onCreate or onLeave, which can be overloaded in a custom class. The client's room class does not have those, but instead has member variables which can be set to callback functions, for example onStateChange or onLeave. That simply is not similar in my opinion - but probably it is like that for good reasons - reasons I do not understand yet.

posted in Questions & Help • 11 Jan 2021, 20:53
Can I extend the Client and the Room class?

Is the following (client-side) code possible?

import * as Colyseus from 'colyseus.js'

export class MyOwnClassExtendingColyseusRoom<T> extends Colyseus.Room<T> {
}

class MyOwnClassExtendingColyseusClient extends Colyseus.Client {

  protected createRoom<T> (roomName: string, rootSchema?: Colyseus.SchemaConstructor<T>) {
    return new MyOwnClassExtendingColyseusRoom(roomName, rootSchema) as Colyseus.Room<T>
  }
}

I am using colyseus.js 0.14.1 and the compiler error message is:

Namespace '"c:/mygame/node_modules/colyseus.js/lib/index"' has no exported member 'SchemaConstructor'.

Bonus question: In case it is possible, is there any good reason against extending those classes?

posted in Questions & Help • 10 Jan 2021, 22:00
RE: Can server-side matchmaking be done in the server's verifyClient?

Hello @endel . I will have a look at that example. Your recommendation regarding an HTTP route for authentication and seat reservation sounds like a better idea than the one I explained above. Thank you for your input. 👍

posted in Questions & Help • 8 Dec 2020, 19:55
RE: Can server-side matchmaking be done in the server's verifyClient?

I am thinking of the following situation:

  • The server is JS/TS/node-based.
  • The server has several connected clients already, distributed over several rooms.
  • The client is JS/TS/browser-based.
  • The client reads credentials from browser cookie ("session key") or asks user for credentials.
  • The client opens http connection to server (which will later become a ws connection), sending the credentials as attributes in the http header.
  • In the server verifyClient is called.
  • In there the server then gets the credentials from the http header and verifies them against a database. This should be done asynchronous.
  • If successful the server decides whether there already is an existing room for the new client or whether it should create a new room for the client (the client shall have no say in choosing the room). Creating a room seems to be asynchronous according to the documentation.
  • If successful the server allows the upgrade of the http connection to a ws connection and establishes this connection straight to the room chosen or created right before.
  • The client finally connects to this room.

I hope to stick around, too, because that would mean I will continue using Colyseus :)

posted in Questions & Help • 7 Dec 2020, 20:23
RE: fixing warnings when bundling Colyseus server with webpack

Hello @endel , thank you for your time.
I do not expect you to fix this because I assume this cannot be fixed by Colyseus itself.
Nevertheless here is a minimal code example which causes those warnings (without my fixes suggested above):
https://gist.github.com/TeeTeeHaa/5e38ccf475a9efc54c958650020d61cc

posted in Questions & Help • 7 Dec 2020, 20:08
fixing warnings when bundling Colyseus server with webpack

The game server I am currently creating is written in TypeScript and includes the Colyseus server as a node module. Everything is compiled and bundled with webpack because I think that deployment of a game server gets a lot easier by simply copying one bundled file.

When using webpack to compile and bundle the Colyseus server (yes, the Colyseus server, not the Colyseus client) there are several warnings, at least in my combination of versions of node, webpack, TypeScript and Colyseus. I took the following steps to fix those warnings. In the future somebody might search for those warnings, might find this post and might consider it helpful.

node 12.19.0
webpack 4.44.2
TypeScript 4.0.5
Colyseus 0.14.0

I added the following to my webpack.config.js file:

plugins: [
  // problem: bundling Colyseus with webpack causes warnings regarding hiredis
  // solution: force webpack to ignore hiredis
  // source: https://github.com/NodeRedis/node-redis/issues/790#issuecomment-501869990
  new webpack.IgnorePlugin(/^hiredis$/),
  // problem: bundling Colyseus with webpack causes warnings regarding unexpected characters in default-gateway module
  // reason: default-gateway/index.js contains a dynamic require command and webpack tries to read readme and license files
  // solution: force webpack to ignore readme and license files
  new webpack.IgnorePlugin(/README.md$/),
  new webpack.IgnorePlugin(/LICENSE$/)
]
// problem: bundling Colyseus with webpack causes warnings regarding optional dependencies bufferutil and utf-8-validate
// solution: npm install --save-optional bufferutil utf-8-validate
// source: https://github.com/websockets/ws/issues/1220#issuecomment-717785572

The module mentioned in the last hint must be installed manually.

Here are the original warnings, hopefully to be found with search engines:

WARNING in ./node_modules/colyseus/node_modules/ws/lib/buffer-util.js
Module not found: Error: Can't resolve 'bufferutil' in 'C:\CUSTOMFOLDER\node_modules\colyseus\node_modules\ws\lib'
 @ ./node_modules/colyseus/node_modules/ws/lib/buffer-util.js
 @ ./node_modules/colyseus/node_modules/ws/lib/websocket.js
 @ ./node_modules/colyseus/node_modules/ws/index.js
 @ ./node_modules/colyseus/lib/Server.js
 @ ./node_modules/colyseus/lib/index.js
 @ ./CUSTOMFILE.ts

WARNING in ./node_modules/colyseus/node_modules/ws/lib/validation.js
Module not found: Error: Can't resolve 'utf-8-validate' in 'C:\CUSTOMFOLDER\node_modules\colyseus\node_modules\ws\lib'
 @ ./node_modules/colyseus/node_modules/ws/lib/validation.js
 @ ./node_modules/colyseus/node_modules/ws/lib/receiver.js
 @ ./node_modules/colyseus/node_modules/ws/index.js
 @ ./node_modules/colyseus/lib/Server.js
 @ ./node_modules/colyseus/lib/index.js
 @ ./CUSTOMFILE.ts

WARNING in ./node_modules/default-gateway/README.md 1:0
Module parse failed: Unexpected character '#' (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
> # default-gateway
| [![](https://img.shields.io/npm/v/default-gateway.svg?style=flat)](https://www.npmjs.org/package/default-gateway) [![](https://img.shields.io/npm/dm/default-gateway.svg)](https://www.npmjs.org/package/default-gateway) [![](https://api.travis-ci.org/silverwind/default-gateway.svg?style=flat)](https://travis-ci.org/silverwind/default-gateway)
| 
 @ ./node_modules/default-gateway sync ^\.\/.*$ ./README.md
 @ ./node_modules/default-gateway/index.js
 @ ./node_modules/internal-ip/index.js
 @ ./node_modules/colyseus/lib/discovery/index.js
 @ ./node_modules/colyseus/lib/Server.js
 @ ./node_modules/colyseus/lib/index.js
 @ ./CUSTOMFILE.ts

WARNING in ./node_modules/default-gateway/LICENSE 1:14
Module parse failed: Unexpected token (1:14)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
> Copyright (c) silverwind
| All rights reserved.
| 
 @ ./node_modules/default-gateway sync ^\.\/.*$ ./LICENSE
 @ ./node_modules/default-gateway/index.js
 @ ./node_modules/internal-ip/index.js
 @ ./node_modules/colyseus/lib/discovery/index.js
 @ ./node_modules/colyseus/lib/Server.js
 @ ./node_modules/colyseus/lib/index.js
 @ ./CUSTOMFILE.ts

ERROR in ./node_modules/redis-parser/lib/hiredis.js
Module not found: Error: Can't resolve 'hiredis' in 'C:\CUSTOMFOLDER\node_modules\redis-parser\lib'
 @ ./node_modules/redis-parser/lib/hiredis.js 3:14-32
 @ ./node_modules/redis-parser/lib/parser.js
 @ ./node_modules/redis-parser/index.js
 @ ./node_modules/redis/index.js
 @ ./node_modules/colyseus/lib/presence/RedisPresence.js
 @ ./node_modules/colyseus/lib/index.js
 @ ./CUSTOMFILE.ts
posted in Questions & Help • 5 Dec 2020, 21:36
Can server-side matchmaking be done in the server's verifyClient?

Hello everyone. I stumbled upon Colyseus two weeks ago and so far I am excited about it. It might exactly be what I need and now I am evaluating it for my projects. Currently I have a question about server-side matchmaking.

I've seen endel's example for ranked matchmaking at https://github.com/endel/colyseus-ranked-matchmaking. It does use a special room for matchmaking to which players have to connect to initially. When they are finally matched to a game room, players will be disconnected from the matchmaking room and connect to the game room.

In my project I even want server-side matchmaking, but I would prefer to avoid a such a special room for matchmaking. Ideally the authentication and the matchmaking is done before completely establishing a websocket connection and ideally there is only one websocket connection ever made.

All this being said, here is my question: There is a callback function named "verifyClient" (https://docs.colyseus.io/server/api/#optionsverifyclient) which can be used to decide whether the http connection is rejected or upgraded to a websocket connection. Can I cram all my authentication and my matchmaking and my asychronous code (async, await, promises, etc) into that function? Or is that a bad idea? If it is a bad idea, why?

posted in Questions & Help • 5 Dec 2020, 21:30

© 2023 Endel Dreyer