We don’t believe in a one-size-fits-all approach when building our online services. We know that there will be some customization needed to make them work with your games.
There are two kinds of customization: configuration-based and code-based.
When the logic required varies significantly, it is increasingly difficult to encapsulate complex logic in a config-based solution.
There are a lot of scenarios in which games want to extend, override, or customize:
In all these cases, oftentimes game studios want to put alternative logic on the server side, programmatically.
We admit this is not the way to go!
Augment was an attempt to support serverless function architecture. We wanted to give game developers a simple way to run logic on the server side. However, the solution lacked a few critical attributes such as debuggability, observability, and predictability. The problem is not the serverless architecture itself but partially due to the use of some immature techs as implementation. The use cases that can be applied are also somewhat limited. In general, game developers want more fully functional development and production environments based on more mature technology.
Cloud Script allows games to define event callbacks that will cause requests to be sent from the client and executed on the server side.
However, those events can only be defined from a very fine-grained level. If not carefully designed, the events could easily result in excessive calls to the server, resulting in scalability issues and downtime or, at best, inflated infrastructure cost. For those who are not aware of these potential issues, these problems will not be detected until after the game is launched. On top of that, early versions of Cloud Script also suffer from troubleshooting difficulties, lack of observability, and language dependency; among other limitations.
When there’s a heavier need to extend or customize our platform, some of our developers' clients would fork and modify the source code on one or more repos of our platform. The forked repo would need to be merged regularly (we release new code every two weeks) to get new features, bug fixes, performance improvement, etc. While this model works well for clients that need deep customization, it is time-consuming and may present other sets of challenges:
The solution to this software engineering problem has long existed. What we need here is a stable contract between the core code and the customized logic. In addition, to allow more than one implementation to coexist, Strategy Pattern can be used, which in turn, also relies on the use of a language specific interface.
However, some issues remain. Core and customized code need to use the same language. This is not flexible enough in the game industry. Colocated code cannot be scaled independently. In some languages such as Golang, code from both sides need to be compiled together or at least, with the help of the Golang plugin feature, compiled independently with identical compiler and dependent module versions. We were also dealing with unclear responsibility for colocated logic – troubleshooting requires experts from both development teams.
To improve the strategy pattern with colocated code, gRPC can help.
Server SDK such as Golang or Java is used to talk to other AccelByte services securely using JWT token; so this will work in tandem with the gRPC call.
This is still good for getting current Accelbyte Cloud behavior for further processing. And, still plays a significant role in a few places: async event processing (e.g. analytics) and synchronous call from the customized gRPC server code.
We will go through a couple of real examples, looking at how the new architecture enables easy development of customized game specific server logic.
Example one: Matchmaking V2 is one of the most commonly wanted customization targets. First, we identify the interface for abstraction (strategy pattern). Then, we convert the local interface into gRPC protobuf, build an implementation of the interface as an adapter to call gRPC and finally build a gRPC server implementation. The service definition of the protobuf is shown below:
service MatchFunction { rpc GetStatCodes(GetStatCodesRequest) returns (StatCodesResponse); rpc ValidateTicket(ValidateTicketRequest) returns (ValidateTicketResponse); rpc MakeMatches(stream MakeMatchesRequest) returns (stream MatchResponse); }
First, note that the protobuf service definition is very straightforward and simple. By carefully designing the gRPC interface, the amount of logic you need to implement is minimal. Once the gRPC protobuf is defined and agreed, the gRPC server logic can be iterated separately. With a stable interface using protobuf, you are guaranteed compatibility. Even when the protobuf definition is evolving, you can easily support backward and forward compatibility by following protobuf best practices. This removes any potential problem about project schedules.
Integration testing is also straightforward. When your server implementation is ready, simply register your endpoint to the corresponding AccelByte service (Matchmaking in this example) with our Admin API. This binds your implementation with the core service dynamically.
Also note that you are not limited to the language that is used to implement the core service. You can implement the logic in any gRPC supported languages and, if needed by your logic, use the Accelbyte server SDK to access your data in the Accelbyte Cloud.
Example two: Customized in-game items. By default, in-game items in the online shop are configured statically and appear to be the identical for every player in the game. To attract more players to visit the online shop more regularly, the logic to show the available in-game items in the online shop can be customized in different ways (e.g. exclusive, personalized, daily surprise, random, promotion, newly featured, etc). The selection may be based on information from different sources such as player analytics or other Accelbyte Cloud services such as current item ownership, skill levels, friend-owned items, etc, all accessible from the Accelbyte Cloud server SDK.
Example three: Chat V2. A different gRPC extension point will be provided to allow your own pre-processing of chat messages; for toxicity detection or third party integration.
We learned that what we needed here was a stable contract between the core code and the customized logic. We also learned that in order to allow more than one implementation to coexist, a Strategy Pattern can be used.
To help our customers and to improve the strategy pattern with colocated code, gRPC can help our customers through Support Streaming – both unidirectional and bidirectional streaming. gRPC works in tandem with server SDK – such as Golang or Java – to help deploy the strategy as microservices, utilizing multiple language support, reducing runtime surprises, and efficiently serializing for cost.
Ultimately these updates serve to further extend and customize the backend platform for our customers. AccelByte works with studios to ensure visions come to fruition for each game, no matter the unique aspects that may need to be included.
Interested in learning more about our solutions and how they can help you? Request a demo here.