Let's get your dream game done! Tell us about your creative vision and we’ll help you make it come to life.
Tom Kopera
Head of Growth
Multiplayer SDK
Competitive game development with no overhead
Smart Matchmaking
Fairness starts at matchmaking
Verifiable Replays
The best moments, captured
Bot Deployment
Engage with players at all levels
Simulation Analyzer
Pinpoint issues in your game
API Integration
React to your players in real-time
Technology that drives the revolution in competitive gaming
Explore the innovation and cutting edge technologies that power Elympics on the way to independent, decentralized competition
Documentation
Learn how Elymipcs works
Open-Source projects
Bootstrap your project in seconds
Blog
Explore the world of gaming
Development Hub
Earn with Elympics as Certified Developer
Single Player with leaderboards
Compete offline with accumulated prize pools
Game Token Duel
Dueling for Real Rewards in Multiplayer Games
Battle Royale with Prize Pools
Esports-Level Competition Made On-Chain
Players’ Skill Profiles
Creating Digital Profiles Based on Players’ Skillset
Securing On-Chain Esports
Esports-level security in on-chain competitive gaming
Security & fairness
Seamless experience guaranteed
Serverless gameplay hosting
Scale without a slip
In-game Oracle
External source of truth
Proof-of-Game
Gameplay secured by mathematics
Paid Competitive Gaming
Zero-sum games with blockchain tokens
Onboarding Players
Helping the next wave of players move on-chain
Let's dive into another learning trip with Elympics
Competitive games rely on one key element: the accurate determination of match outcomes. Whether it’s a player securing a hard-fought victory in a head-to-head match or earning a spot at the top of a leaderboard in a solo tournament, the result defines the experience. For asynchronous multiplayer games, where players compete indirectly through leaderboards, tournaments offer not just excitement but also monetization potential. Players enter by purchasing tickets, and the top performers share the prize pool, adding stakes to every playthrough.
In such scenarios, ensuring the reliability, fairness, and security of match results becomes the backbone of competitive integrity. This article delves into Elympics’ approach to refining competitive match outcomes for asynchronous multiplayer with leaderboards, focusing on robust systems and best practices that guarantee a level playing field for all.
- Elympics uses and requires server authoritative approach, which ensures that the players follow rules of the game - they are unable to do some hacking black magic and send a score of 1000000 without doing anything in the game. Everyone must follow the rules!
- That said, the developer is still responsible to apply these principles properly, without leaving out any security gaps like for example sending a match result as a player’s input.
- The game has to be competitive & skill-based - with scoring system based on player’s performance, by design optimised around high result variance (it should be hard to score the same twice) and with minimal or no luck contribution to the score.
- Each player should have equal chances - starting a tournament with the same randomization seed, with deterministic and fair flow of events.
- The game should gracefully handle all the possible cases with the player's connection to the match and finish it with a proper score.
If you have followed the guide on randomization and have the random seed synchronized between your server & client, then we can go one step further and synchronize the random seed based on the tournament id. This ensures that all players have the same seed if they participate in the same tournament.
But how do you get access to the tournament id in the first place?
For that, `IServerHandlerGuid` implementation will be needed. In the Elympics system prefab there is a default one called `DefaultServerHandler`. You should disable or remove it and provide your own implementation instead. As a base, you could copy the default contents (replacing `ElympicsLogger`s with `Debug`).
Now, provide the code for deriving the seed and initializing randomization, for example:
private readonly ElympicsInt RandomizationSeed = new ElympicsInt(int.MinValue);
private readonly ElympicsInt RandomizationSeed = new ElympicsInt(int.MinValue);
private void Awake()
{
RandomizationSeed.ValueChanged += SetRandomization(_, seed);
}
private void SetRandomization(int _, int seed)
{
UnityEngine.Random.InitState(seed);
}
public void OnServerInit(InitialMatchPlayerDatasGuid initialMatchPlayerDatas)
{
if (initialMatchPlayerDatas.CustomMatchmakingData != null && initialMatchPlayerDatas.CustomMatchmakingData.TryGetValue(TournamentConst.TournamentIdKey, out var tournamentId))
{
// existing tournament, online play
RandomizationSeed.Value = tournamentId.GetHashCode();
}
else
{
// no tournament, editor testing
RandomizationSeed.Value = UnityEngine.Random.Range(int.MinValue + 1, int.MaxValue);
}
// put the default contents of this method below
}
Please note that when the player connects, they could receive the whole state at the same time or the seed value up to 1s later. So there might be a case when some `GameStarted` event is called before `RandomizationSeed.ValueChanged` is resolved, causing problems. To make it work reliably check both if `RandomizationSeed` and `GameStarted` occurred.
To implement the `GameStarted` event, you can change the `_gameStarted` variable into a `ElympicsBool` and manage when the gameplay starts for both the Client and the Server. You can use its `ValueChanged` event or check the variable directly.
1. Happy path - the match starts and ends properly, with the score reached by the player sent to the database. It should be done whenever the player reaches any game end condition, like losing all lives or running out of time (there can be many conditions).
public void EndGameWithScore()
{
if (!Elympics.IsServer)
return;
Elympics.EndGame(
new ResultMatchPlayerDatas(
new List<ResultMatchPlayerData>
{
new ResultMatchPlayerData { MatchmakerData = new float[1] { score.Value } }
}
)
);
}
In the example above, `score` is some `ElympicsInt` variable containing its value and being controlled by the server.
To handle ending a match on the Client and display results screen, use `IClientHandlerGuid.OnMatchEnded` (note that this interface has default, empty interfaces implementations).
2. The player starts loading a match, our infrastructure is ready (the server), but for some reason (like loss of Internet connection) the player never connects with the server.
In such a case, the desired outcome is that the game ends without any result (null), so we could detect it and return an entry ticket to the player.
By default, it is managed by the `DefaultServerHandler`, but if you override it (like you should when determining the seed), your own implementation should handle this case. The simplest solution would be to copy the default implementation for timeout from the `DefaultServerHandler` class. This already includes waiting for players to connect & sending null to the server if they do not.
3. The player starts a match correctly, but disconnects mid-game. The reason could simply be Internet connection issues, but it may also be an attempt to regain the entry ticket when facing an unsuccessful playthrough. In such a case, the correct way to handle it would be ending the match with the score at the moment of disconnection. This way, players won’t be able to abuse leaving the match to regain a ticket, and accidental connection loss won’t be punished.
The default implementation unfortunately doesn’t handle such a case this way, since it cannot determine which variables you will use as a score. For that you will need to slightly adjust your own implementation. Find `OnPlayerDisconnected` method and change it so it ends the match with score like in the happy path case:
public void OnPlayerDisconnected(ElympicsPlayer player)
{
if (!IsEnabledAndActive)
return;
Debug.Log($"Player {player} disconnected.");
Debug.LogWarning("Forcing game server to quit because one of the players disconnected.");
EndGameWithScore();
}
A bit better alternative to this would be allowing the player to rejoin the game instead of ending the match and sending their score half-way.
Please note that the rejoining feature doesn't necessarily work for every game, as there could exist a perfectly working game which is incompatible with rejoining because of local state accumulated through the game, for example game object references or sprites.
With this approach, remember to remove the immediate ending of the game from `OnPlayerDisconnected` and provide a timeout similar to the default implementation in `OnServerInit` so the server doesn’t run excessively.
private void RejoinIfHasOngoingMatch()
{
var joinedRooms = ElympicsLobbyClient.Instance.RoomsManager.ListJoinedRooms();
if (joinedRooms.Count > 0 && joinedRooms[0].State.MatchmakingData.MatchData.State == Elympics.Rooms.Models.MatchState.Running)
{
var matchmakingData = joinedRooms[0].State.MatchmakingData;
ElympicsLobbyClient.Instance.PlayMatch(new Elympics.Models.Matchmaking.MatchmakingFinishedData(matchmakingData.MatchData.MatchId, matchmakingData.MatchData.MatchDetails, matchmakingData.QueueName, ElympicsLobbyClient.Instance.CurrentRegion));
}
}
private async UniTask OnLobbySceneLoaded(SessionManager sessionManager)
{
sessionManager.FinishSessionInfoUpdate += RejoinIfHasOngoingMatch;
// the rest of the lobby scene initialization (like in the sample)
}
private void Start()
{
var sessionManager = FindObjectOfType<SessionManager>();
OnLobbySceneLoaded(sessionManager).Forget();
}
private void OnDestroy()
{
var sessionManager = FindObjectOfType<SessionManager>();
if (sessionManager == null)
return;
sessionManager.FinishSessionInfoUpdate -= RejoinIfHasOngoingMatch;
// remaining cleanup
}
Elympics' emphasis on reliable, secure, and fair match outcomes highlights its commitment to competitive integrity. By leveraging a server-authoritative approach, synchronized randomization seeds, and complete solutions for handling player connections, Elympics ensures that every match - whether won, lost, or interrupted, is managed with precision and fairness.
These systems not only build and maintain trust but also support diverse gameplay scenarios, from high-stakes tournaments to casual competitions. By addressing the complexities of disconnections, rejoining, and score validation, Elympics empowers developers to create experiences that players can rely on. In a landscape where fairness and quality competition are key to long-term success, Elympics continues to set the standard for what Web3 gaming can achieve.