Create Your Own Module
Most of the time, when you want to extend the functionality of MST, you'll be writing custom modules to do that.
What are the modules?
In essence, a module is just a game object, which is initialized by the Master Server. When client interacts with master server, he sends messages. So modules are all about handling those messages. Here's how modules are picked up and initialized:
- Master Server begins "starting"
- Master Server looks for all of the modules
- All of the modules are "registered" to master server
- Master starts initializing modules.
- If the module has dependencies, it won't be initialized, until it's dependency is initialized
- Master server is started
Creating a basic module
To create a module, you'll need to create a new script which extends BaseServerModule. You should also override the Initialize method.
This script should then be added to a new game object, which is a child of Master Server game object.
Here's an example of the most basic module you can have:
public class LeaderboardModule : BaseServerModule
{
public override void Initialize(IServer server)
{
Debug.Log("Leaderboard Module initialized");
}
}
Dependencies
Modules can register dependencies on other modules, which must be done before the master server starts. Dependencies can be required or optional.
It's recommended to set dependencies on Awake method. This will make sure that dependencies are registered before master server actually starts.
Here's an example, which demonstrates dependencies:
public class LeaderboardModule : BaseServerModule
{
protected override void Awake()
{
base.Awake();
// Add dependency to auth module
AddDependency<AuthModule>();
// Add optional dependency to profiles
AddOptionalDependency<ProfilesModule>();
}
public override void Initialize(IServer server)
{
// If initialize method is called, we are sure that our dependencies
// were already initialized
var auth = server.GetModule<AuthModule>();
if (!auth)
throw new Exception("Auth module is required to be located on the scene");
var profiles = server.GetModule<ProfilesModule>();
// Since this is an optional dependency, it might not exist on the master server
if (!profiles)
logger.Warn("Profiles module is not on the scene");
Debug.Log("Leaderboard Module initialized");
}
}
Handling messages
Here's an example of a custom module, which handles a message from client, and responds with a list of leaders:
public override void Initialize(IServer server)
{
// ...
server.RegisterMessageHandler((ushort)DemoMsgKeys.GetLearderboard, GetLearderboardMessageHandler);
Debug.Log("Leaderboard Module initialized");
}
private void GetLearderboardMessageHandler(IIncomingMessage message)
{
var packet = new LeadersPacket()
{
Leaders = leaders
};
message.Respond(packet, ResponseStatus.Success);
}
On the client, you can send the message like this, and it will be handled by our custom module:
public class LeaderboardClienModule : BaseClientBehaviour
{
public void GetLeaderbord()
{
logger.Debug("Getting list of leaders");
Connection.SendMessage((ushort)DemoMsgKeys.GetLearderboard, (status, message) =>
{
if (status != MasterServerToolkit.Networking.ResponseStatus.Success)
{
logger.Error(message.AsString());
return;
}
var leaders = message.Deserialize(new LeadersPacket());
logger.Debug($"Received the list of leaders. Count: {leaders.Leaders.Count}");
});
}
}
For more to know about message serialization look into this page.
Getting access to the user's account
Let's say you want to list user scores to the leaderboard. To do this, you need to access the player's account to take a username from it. In the code below, you can see how we get a user account from a peer extension. We get the username and add it to the leaderboard.
private void AddLeaderMessageHandler(IIncomingMessage message)
{
// Gets user extension that holds user account info
var user = message.Peer.GetExtension<IUserPeerExtension>();
// Checks if user is null
if (user == null)
{
message.Respond("Unauthorized request", ResponseStatus.Unauthorized);
return;
}
// Find user if exists
var leaderIndex = leaders.FindIndex(i => i.Name == user.Username);
// Add scores
if (leaderIndex >= 0)
{
var leaderInfo = leaders[leaderIndex];
leaderInfo.Score += message.AsInt();
}
// Create new record
else
{
leaders[leaderIndex] = new LeaderInfo()
{
Name = user.Username,
Score = message.AsInt()
};
}
message.Respond(ResponseStatus.Success);
}