Game Development Note: game logic module organization and Data Synchronization

Source: Internet
Author: User

This week's work is mainly divided into two parts: one is the establishment of the Basic module on the server side, the other is the protocol and verification of the communication mode between the server and the client, as well as data synchronization and other solutions. Overall progress is good.

The server is built in the actor mode. Currently, the actor running on the server is called a service, each Service maintains a request queue, A goroutine continuously retrieves and Processes requests, and a group of logic modules responsible for message processing. Each player in the game server is a service, and the function modules that are not affiliated with the players are also running as services (such as rankings, chats, and guilds ), other global modules also run as independent services (such as the player ID generator, registration module, and GM module ). Different services use messages for interaction (synchronous or asynchronous). messages are packaged using Google protocol buffer by default.

This week, the basic functions of the server provide a simple log package, an actor package that is currently available but unreliable, and a rest package to receive responses to HTTP requests sent from the client. Game-related mechanisms include player registration, logon, Database loading and storage, and data loading and synchronization with clients. In addition, a module is designed for table reading and code generation.

At present, the basic module can run smoothly, but it is still not perfect. Some problems have not yet been figured out. After that, we will sort out the ideas for optimization and testing, and finally share and open-source :)

 

The topic is as follows.

This week, the game logic module and Server Client Data Synchronization have been discussed clearly and a good implementation has been made. Here we will share with you.

A game can be divided into multiple modules based on its functions, such as money, backpacks, equipment, skills, tasks, and achievements. According to the idea of software engineering, we hope to implement different modules separately, and then combine these modules into a complete game. However, the reality is cruel. Different modules are often closely related. For example, when purchasing a backpack, you need to deduct a gold coin, make a copy, and complete the task. After the task is completed, you will be rewarded with gold coins and items, the increase in gold coins leads to an achievement. Therefore, although we implement various modules in different classes or files, we are inevitably unable to cross-reference and call each other between modules. In the end, these modules are too messy. Any slight modification can lead to a big bang.

 

For the convenience of subsequent instructions, we considered a small game system with three modules in total: Money, backpacks, and tasks. Gold coins are required to purchase a backpack. Gold Coins can be obtained when you sell a backpack. after a certain amount of gold coins is added, the status of a task changes to complete, and items and gold coins can be obtained after the task is completed. The call relationship between the three modules.

 

First, we separate the data and logic of the module, and draw on the classic MVC model. The data part is called model, and the logic part is called controller. As a result, the game function is divided into two different layers. The controller is at a higher level and can reference one or more models. The model layer focuses on data processing and is not aware of the upper layer. Each model is a completely independent module that does not reference any controller or model and does not depend on any other object. You can take it out for unit testing.

For our example, the interfaces provided by each module are listed as follows:

Bagmodel: Get the number of items, add items, and deduct items

Moneymodel: obtains the number of gold coins, adds gold coins, and deducts gold coins.

Taskmodel: Adds or deletes a task and marks the task as completed.

Bagcontroller: purchase and sell items

Taskcontroller: complete the task

When purchasing or selling an item, bagcontroller performs or performs operation verification. Then, bagmodel and moneymodel are called to complete data modification. When the task is completed, taskcontroller calls each module.

 

The only problem now is that since moneymodel does not reference other modules, how can we tell the task module to complete the task when the gold coins increase? Here we need to introduce a powerful tool for managing dependencies: the observer mode.

The specific method is to implement the model as a subject. The controller that is interested in the data changes of a model is implemented as the corresponding observer. In our example, moneymodel is subject, which notifies all registered observers when the number of gold coins changes. taskcontroller is an observer of moneymodel and registers it with moneymodel during initialization.

Note that in the figure, the moneymodel points to the dotted arrow of taskcontroller, indicating that taskcontroller will be notified when the data of moneymodel changes. The dotted line is used because moneymodel does not depend on taskcontroller (only on the observer interface ). Similarly, bagmodel can provide a subject for the change of a backpack item. If a new task requires that the number of items reach a certain value, taskcontroller can register with bagmodel, in this way, the item will be notified when it changes, and this dotted line is also shown in the figure.

Readers who are not familiar with the observer mode can view the information on their own. The focus of this article is not to introduce the design mode. Here, we will briefly remind you of the essence of the observer mode: When a module calls other modules, it will produce dependencies. In this case, instead of directly calling, we can implement a mechanism instead, this mechanism allows other modules to tell themselves that they need to be called. The final call process remains unchanged, and the dependency is changed.

 

The client needs to be more complex. In fact, after adding the UI, our module design becomes a classic MVC, this is why we call the data module and logic module model and controller respectively.

Only the backpack module is shown here. The system API here refers to some interfaces related to the game running platform, such as the operating system API, engine API, and graphics library API. The View module and the model module are in the same position. They only process the display, regardless of the game function. The data to be displayed is provided by the Controller. For views that can be entered, the observer mode is also used. When an event occurs, click it to notify other modules (instead of calling it directly). Note that in the figure, bagview points to the dotted arrow of bagcontroller.

 

The following describes the design of data synchronization.

First, for online games, the data displayed on the client is transmitted by the server. When player operations cause data changes, it is recommended that the server update the data to the client. Once I took over a project, many operations were first calculated by the client, so various logics were implemented by the server and client, and it was easy to see data inconsistency between the two sides, it is a headache.

So our synchronization idea is that when the client initiates a request to the server, the server synchronizes all the changed data to the client, and the client updates the data after receiving the response from the server, never modify data without authorization. In this guiding ideology, the message package structure is as follows (for example, selling an item ):

message BagItemSellCG {    optional int32 Id = 1;    opitnoal int32 count = 2;}message BagItemSellGC {    optional int32 result = 1;    optional Sync  sync    = 2;    opitonal BagItemSellCG postback = 3;}

The messages returned by the server to the client almost always contain three fields. Result indicates that the operation result may be 0 or an error code. Sync contains all the data updates. PostBack unblocks the client request messages and returns them. This allows the client to perform interface updates or prompt.

Sync is a complicated message that contains all the data of the model to be updated. Thanks to the optional option of protocol buffer, in most cases, the data we send is only a small part.

Let's take a look at the design of server-side message processing and synchronization.

We added a new handler interface layer on the model and controller. Handler is responsible for parsing the message package, calling the Controller to process the message package, calling the synccontroller to construct the synchronization data when necessary, and finally packaging the data into a message and returning it to the client.

Each model maintains a set of changed data on the basis of data management. For simple models such as moneymodel, It is a dirty bool mark, while bagmodel maintains a set of changed item IDs. The changed data list is cleared after synchronization.

 

The client structure is similar.

The difference with the server is that synccontroller is responsible for calling the model to update data, and each model implements the data update interface. Note that except for synccontroller, other controllers can only read the model but cannot change its data. This ensures that all data must be synchronized from the server.

Finally, I want to take the example of selling items as a complete process. Start from the operation on the client, send the request to the server, and then return the client to update the data and interface. The complete figure is complex and cannot be viewed after being mixed together. I had to delete the task-related modules ......

1. A click is generated on the bagview interface. Because bagcontroller is the observer of bagview, bagcontroller is notified of click events.

2. bagcontroller identified that this click was intended to sell items, so it constructed a good news package and sent it to the server.

3. The server identifies that the message type is callback, so the message is distributed to sellhandler.

4. sellhandler calls bagcontroller to execute the logic.

5. bagcontroller extracts the data of bagmodel and moneymodel for condition check. If the operation cannot be performed, an error code is generated and returned to sellhandler. Otherwise, the model is called to modify the data. At this time, bagmodel records the ID of the changed item, moneymodel makes a dirty mark.

6. After sellhandler calls bagcontroller, if an error occurs, the message package is directly returned to the client. Otherwise, synccontroller is called to collect synchronization data.

7. synccontroller calls each module to collect the synchronized data. After each module submits the synchronized data, it is clear that it maintains the mark.

8. sellhandler packages the operation results and synchronized data and sends them to the client.

9. The client identifies that the message type is callback and the message is distributed to baghandler.

10. baghandler sends the message processing result to bagcontroller.

11. bagcontroller notifies bagview of necessary prompts Based on the message processing result.

12. sellhandler sends the data synchronization part of the message package to synccontroller.

13. synccontroller synchronizes data to each module.

14. The data of bagmodel and moneymodel has changed, notifying the observer, that is, the corresponding controller.

15. The controller calls view to update the interface.

Game Development Note: game logic module organization and Data Synchronization

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.