-
Notifications
You must be signed in to change notification settings - Fork 41
Structure of the codebase
This figure indicates the most important files and methods to be aware of in order to start navigating the code. More details below.
index.html is the entry point for the players. This page loads the client code bundled in dist/client.js
, and creates the space where the game canvas will be located.
client/main.js is where the Phaser game
object is configured and created. As part of that configuration, 3 Phaser scenes
are created: Boot
, UI
and Engine
(see below).
client/Boot.js defines the Boot scene. This scene displays the title screen while receiving some boot parameters from the server. When everything is ready, the "play" and "tutorial" buttons are displayed and the UI
scene is launched.
client/UI.js defines the UI scene. As the name implies, this scene is in charge of the UI elements and menus (although this responsibility is still a bit shared with the Engine
scene, which is not ideal). When a new players has selected a starting region, or when a returning player is recognized, the Engine
scene is launched.
client/Engine.js is the main scene of the game, containing a big part of the game logic. The key methods of that scene are the following, in order of execution:
-
Engine.preload()
loads all the assets of the game that haven't been preloaded by theUI
scene. -
Engine.create()
sets up a lot of necessary data structures, sets up the camera, the animations (by callingEngine.createAnimations()
and sets up the input callbacks. In other words, it lays the basic groundwork for the game being able to run. When it is finished, it callsClient.requestData()
which fetches from the server all the information about the player and the world around it. When that data is received,Engine.initWorld()
is called. -
Engine.initWorld()
sets up the player character (viaEngine.addHero()
) and the game world. It also creates all the game menus (viaEngine.makeUI()
), and start the tutorial if the game is in tutorial mode.
At that point, the player can play the game. The communication with the server is handled in client/Client.js. In addition to establishing the socket.io
connection with the server, it contains several methods to send the actions of the player to the server. In exchange, the server sends regular updates, which trigger the Client.socket.on('update')
callback. This callback, in turn, calls:
-
Engine.updateSelf()
to update properties of the player that are relevant and visible to him/her only (e.g. amount of gold, inventory...) -
Engine.updateWorld()
to update the environment around the player (buildings, animals, etc.)
The entry point for the server side code is server/server.js. This file is mainly responsible for:
- Establishing the connection to the database
- Setting up callbacks to handle the messages coming from the client (see the
callbacksMap
in theio.on('connection')
callback) - Launching the game server proper by calling
GameServer.readMap()
(see below). TheGameServer
module handles most of the server side game logic.
All communication from Client
is sent to the GameServer
via server.js
. Conversely, all data that needs to be sent to the players comes from the GameServer
and is sent to Client
by helper methods defined in server.js
such as server.sendUpdate()
.
The most important methods in GameServer
are:
-
GameServer.readMap()
which creates the entire game world and initializes everything. It starts by reading several static files about the game entities (such as lists of items, animals, etc.) and the world itself (to know its size and how many AOIs to create) and then goes through a series of sequential steps called the initialization sequence, defined byGameServer.initializationMethods
. At the end of this, the game server is ready and playable. -
GameServer.updateClients()
is called multiple times per second (the rate is set in the config files) to update the players about their state and the state of the world. This is done in a smart way so as to send only new and relevant information to each player. The details are out of scope of this article, but in a nutshell, each player maintains an individual update package about his own state, while the AOIs around the player maintain their own update packages about their own states. For each player, theupdateClients()
method merges these different update packages in the proper way and then send them to be consumed by theClient.socket.on('update')
callback inClient
.