This is a creation in Article, where the information may have evolved or changed.
Introduction to the Goworld game server engine
Goworld is an open source, distributed and extensible game Server engine, written in the Go Language (Golang). It employs a structure similar to BigWorld and uses a simplified scene-object framework. As an example of a typical MMORPG, there will be multiple scenes on each server, each of which can contain multiple objects, including players, NPCs, monsters, and so on. The Goworld server can assign scenes to different processes or even different machines, which makes the load on the game server extensible.
Open source Distributed Game Server engine: Https://github.com/xiaonanln/goworld, welcome star, learn together
Chat rooms are a very common feature in the game, such as the world chat room, professional chat room, gang chat room and so on in a MMORPG game. Goworld provides a very simple and efficient support for this, making it easy for developers to implement distributed chat room functionality. Here we are trying to implement a distributed and extensible Chat server using the features provided by Goworld.
Chat room Feature Description
The chat room we want to implement contains some of the following features:
- Registered
- Login
- Speak
- Switch chat Rooms
To target a wider range of game developers, we use Cocos creater 1.5.2 to develop chat room clients, which use JavaScript in the Client programming language. Since this is just a demo, the functionality of the server and the client is relatively simple, but it still uses some of the Goworld's outstanding features.
Developing a distributed Chat server using Goworld
Install Go 1.8.3
Compiling goworld requires installing Golang 1.8.3, make sure your go version is new enough.
Get Goworld Open Source game server
Run the following command to get the Goworld game server engine. Because Goworld relies on other, more external libraries, this process can take a little bit of time.
go get -u github.com/xiaonanln/goworld
Write the Chat service-side code
We develop the chat room service side in the%gopath%/src/github.com/xiaonanln/goworld/examples/chatroom_demo directory. All service-side code can be viewed through the address Https://github.com/xiaonanln/goworld/tree/master/examples/chatroom_demo.
Chat Server main function
Using the Goworld development Service side requires the developer to provide a main function entry. The main function typically registers several custom types and then calls Goworld. Run enters the game server main loop.
// serverDelegate 定义一些游戏服务器的回调函数(必须提供)type serverDelegate struct {game.GameDelegate}func main() {goworld.RegisterSpace(&MySpace{}) // 注册自定义的Space类型(必须提供)// 注册Account类型goworld.RegisterEntity("Account", &Account{}, false, false)// 注册Avatar类型,并定义属性goworld.RegisterEntity("Avatar", &Avatar{}, true, true).DefineAttrs(map[string][]string{"name": {"Client", "Persistent"},"chatroom": {"Client"},})// 运行游戏服务器goworld.Run(&serverDelegate{})}
As shown above, the logic of the main function is very simple. First register a custom scene object type MySpace, this is goworld mandatory, otherwise the operation will be error. Main then registers two object types (account and avatar) that implement the chat server logic. Account is responsible for registration and login process, Avatar is responsible for player chat logic. The specific implementations of these two types continue to be detailed below. Finally, main calls Goworld. Run runs the main loop of the game server.
Custom Scene Type MySpace
The Goworld engine requires that we have to register a custom scene type in Main. Because chat server does not have any scene logic, there is no specific code implementation for this type. Scenes can help with MMORPG, or open room types of games, but it doesn't work for a simple chat server. So we only define and register an empty scene type.
// MySpace 是一个自定义的场景类型//// 由于聊天服务器没有任何场景逻辑,因此这个类型也没有任何具体的代码实现type MySpace struct {entity.Space // 自定义的场景类型必须继承一个引擎所提供的entity.Space类型}
Account Object Type Accounts
The account type is defined as follows. All custom object types must inherit the entity. Entity. When a player client connects to a server, the server automatically creates an account object and takes the new client as the client of the account object. In the Goworld engine, each object can have up to one client object. In this way, the server-side object can invoke some functions of the client object through RPC and update some properties of the client object through the property mechanism.
// Account 是账号对象类型,用于处理注册、登录逻辑。type Account struct {entity.Entity // 自定义对象类型必须继承entity.Entitylogining bool}
Account Registration
When the client clicks Register, it sends a registered RPC request to the server. The account object needs to define a function (Register_client) to accept the RPC request, as shown below. Representing the end of the function name _Client This is an RPC function that can be called by the client. The Register_client function enables the Goworld engine to provide a convenient KVDB module for account-password data storage and reading. When the account password does not exist, insert a new account and password in the KVDB. The registration process creates a Avatar object while creating a new account, and then destroys it immediately. This is to generate the data for the new Avatar object in the database, obtain its unique ID (avatarid) and deposit the Avatar ID into Kvdb, and bind to the account.
func (a *Account) Register_Client(username string, password string) {goworld.GetKVDB("password$"+username, func(val string, err error) {if val != "" {a.CallClient("ShowError", "这个账号已经存在")return}goworld.PutKVDB("password$"+username, password, func(err error) {avatarID := goworld.CreateEntityLocally("Avatar") // 创建一个Avatar对象然后立刻销毁,产生一次存盘avatar := goworld.GetEntity(avatarID)avatar.Attrs.Set("name", username)avatar.Destroy()goworld.PutKVDB("avatarID$"+username, string(avatarID), func(err error) {a.CallClient("ShowInfo", "注册成功,请点击登录")})})})}
Account Login
The account object uses Login_client to process the login request from the client, as shown below. First, get the correct account and password from the KVDB and compare it with the password provided by the player. If the password is correct, we use KVDB again to get the Avatar ID for the account, and use this avatar ID to start loading the Avatar object from the database.
func (a *Account) Login_Client(username string, password string) {goworld.GetKVDB("password$"+username, func(correctPassword string, err error) {if correctPassword == "" {a.CallClient("ShowError", "账号不存在")return}if password != correctPassword {a.CallClient("ShowError", "密码错误")return}goworld.GetKVDB("avatarID$"+username, func(_avatarID string, err error) {avatarID := common.EntityID(_avatarID)goworld.LoadEntityAnywhere("Avatar", avatarID)a.Call(avatarID, "GetSpaceID", a.ID)})})}
Here we use the goworld.LoadEntityAnywhere function to load the Avatar object. In a distributed server, the Avatar object may be created in any of the service-side logical processes. So in this case, the account initiates a request to the Avatar object just loaded GetSpaceID , trying to get the scene where the Avatar object is located. The Avatar object needs to define GetSpaceID a function to process the request and send its own scene ID to the account object, as shown in the code below. _ClientUnlike the End function above, both the RPC caller and the receiver are objects on the server side, so there is no need to provide _Client tags.
func (a *Avatar) GetSpaceID(callerID EntityID) {a.Call(callerID, "OnGetAvatarSpaceID", a.ID, a.Space.ID)}
After the account object receives the OnGetAvatarSpaceID callback, it can EnterSpace request to migrate itself to the process where the Avatar object resides, as shown in the code below. Scene switching is a powerful object manipulation function provided by Goworld, which makes it easy for the server to switch the objects in each scene, which greatly simplifies the development of distributed services for developers.
func (a *Account) OnGetAvatarSpaceID(avatarID common.EntityID, spaceID common.EntityID) {// 如果发现Avatar对象和Account对象在同一个服务器,则不需要进行场景切换avatar := goworld.GetEntity(avatarID)if avatar != nil {a.onAvatarEntityFound(avatar)return}a.Attrs.Set("loginAvatarID", avatarID)a.EnterSpace(spaceID, entity.Position{})}
The account object searches for the specified Avatar object again in the current logical process after switching the scene. The function is then called to onAvatarEntityFound complete the last login logic, which is to hand over the GiveClientTo account's current client connection to the Avatar object through a function, which is then destroyed by losing the client.
func (a *Account) OnMigrateIn() {loginAvatarID := common.EntityID(a.Attrs.GetStr("loginAvatarID"))avatar := goworld.GetEntity(loginAvatarID)if avatar != nil {a.onAvatarEntityFound(avatar)} else {// faileda.CallClient("ShowError", "登录失败,请重试")a.logining = false}}func (a *Account) onAvatarEntityFound(avatar *entity.Entity) {a.GiveClientTo(avatar)}// OnClientDisconnected 会在对象失去客户端的时候被调用func (a *Account) OnClientDisconnected() {a.Destroy()}
The account object's process of loading the Avatar object and completing the login seems somewhat complex, involving Avatar object loading, two RPC calls, and one-time object migration. However, the mechanism provided by Goworld allows us to easily create Avatar objects into various server processes.
Avatar Object Logic
The Avatar object represents an already logged in Chat room player. As with the account object above, we first need to define a avatar type.
Definition and initialization
// Avatar 对象代表一名玩家type Avatar struct {entity.Entity}// OnCreated 函数会在对象创建结束的时候调用func (a *Avatar) OnCreated() {a.Entity.OnCreated()a.setDefaultAttrs()}func (a *Avatar) setDefaultAttrs() {a.Attrs.Set("chatroom", "1")a.SetFilterProp("chatroom", "1")}
When the Avatar object loads successfully, we will set the default chat room for it.
Set the a.Attrs.Set properties of the Avatar object to a by using the chatroom 1 . The property mechanism is a kind of storage object information provided by Goworld, and provides the mechanism of auto-saving object data and automatically synchronizing to the client. As a result, the chatroom client will receive an update of this property as well as synchronize it to the UI interface while setting the properties of the server.
The Avatar object then uses SetFilterProp a function to set its own filter property: chatroom = 1 . The Filter property mechanism is goworld to efficiently implement the client filtering and notification mechanisms provided by the various chat rooms in the game. The server can use the Filter property mechanism to initiate broadcasts to all clients that meet the requirements of the Filter property, which is much more efficient than scanning one object and sending client RPC.
Talking and switching chat rooms
The Avatar object provides SendChat_Client functions to handle speech requests from the client, as shown below.
func (a *Avatar) SendChat_Client(text string) {text = strings.TrimSpace(text)if text[0] == '/' {// this is a commandcmd := spaceSep.Split(text[1:], -1)if cmd[0] == "join" {a.enterRoom(cmd[1])} else {a.CallClient("ShowError", "无法识别的命令:"+cmd[0])}} else {a.CallFitleredClients("chatroom", a.GetStr("chatroom"), "OnRecvChat", a.GetStr("name"), text)}}
SendChat_ClientTake the / beginning as a command and do special processing. Other content is used as normal content, and the CallFitleredClients speaker's name and content are sent to all player clients in the current chat room by invoking the function provided by the engine's Filter property mechanism.
If the player sends a /join ... command, it is considered a request to switch the chat room. The logic for switching chat rooms is very simple, just set the chat room name to the new Filter property value and set it to the Player property to update to the client.
func (a *Avatar) enterRoom(name string) {a.SetFilterProp("chatroom", name)a.Attrs.Set("chatroom", name)}
Chat Room Client
The code for the chat room client is in: Https://github.com/xiaonanln/goworld-chatroom-demo-client, written by JavaScript. In addition to parsing and encapsulating the server-side communication protocol, the client code is very simple, so it is no longer detailed here. In addition, there is also a running client and server implementation on the http://goworldgs.com/chatclient/, which can be viewed with interest.
Compile run service side
A complete Goworld server consists of three parts: a hub Distributor, a gateway server, and a logical server. The code we have just written is all logical server code, central Distributor and gateway server is a fixed program, directly compiled to run.
Compile Center Dispatcher Dispatcher
cd %GOPATH%/src/github.com/xiaonanln/goworld/components/dispatchergo build
Compiling the gateway server
cd %GOPATH%/src/github.com/xiaonanln/goworld/components/gatego build
Compiling Chatroomdemo game Server
cd %GOPATH%/src/github.com/xiaonanln/goworld/examples/chatroom_demogo build
Setting the Goworld configuration file
We use Goworld.ini.sample in the Goworld root directory as the configuration file for the game server.
cd %GOPATH%/src/github.com/xiaonanln/goworldcp goworld.ini.sample goworld.ini
The configuration file sets the type of database used by KVDB (by default, MongoDB), the database type used by the Avatar object Database (MongoDB by default), and the various configurations used by dispatcher, gate, and game. If you use MongoDB as the Kvdb and object database, please install and run MongoDB 3.x separately.
Running the server
cd %GOPATH%/src/github.com/xiaonanln/goworldnohup components/dispatcher/dispatcher &nohup components/gate/gate -gid 1 &nohup examples/chatroom_demo/chatroom_demo -gid 1 &
Running the client
In Cocos Creater, set the address of the Goworld object in all scenes to the localhost HTTP port of the gateway server (GATE1), default 15012 , and then run the client to connect to the local server.
Summarize
As mentioned above, with the distributed scenario-object framework and other features provided by Goworld, we can easily develop a distributed and extensible Chat room server. However, the features offered by Goworld are more suitable for the development of game types that are divided into scenes and rooms. In addition, the thermal update functionality provided by Goworld is also essential for large game service-side projects.
Open source Distributed Game Server engine: Https://github.com/xiaonanln/goworld, welcome star, learn together
Interested friends to go Language Server development Welcome to join QQ Discussion group: 662182346
2,365 Reads