Most of the network game servers will choose the non-blocking Select this structure, why? Because the network game server needs to deal with a lot of connections, and most will choose to run under Linux/unix, it is actually very uneconomical to open a thread for each user, on the one hand, because the thread under Linux/unix is simulated with the concept of a process, Compared to the consumption of system resources, in addition to I/O, each thread basically does not have any unnecessary parallel tasks, and the network game is very interactive, so synchronization between threads will become a very troublesome problem. As a result, blocking is obviously impractical for this single-threaded server with a large network connection. For a network connection, you need a structure to store, which needs to contain a buffer to write messages to the client, but also a buffer from the client to read the message, the size of the specific message structure is determined. In addition, for synchronization, it takes some time to proofread the values, but also requires a number of different values to record the current state, the following gives a preliminary structure of the connection:
typedef connection_s {
user_t *ob; /* Point to the structure that handles server-side logic */
int FD; /* Socket Connection */
struct sockaddr_in addr; /* Address information for the connection */
Char Text[max_text]; /* Message buffer received by */
int text_end; /* Receive a message-buffered tail pointer */
int Text_start; /* Receive the message buffer's head pointer */
int last_time; /* When was the last message received? */
struct Timeval latency; /* Difference between client local time and server local time */
struct Timeval last_confirm_time; /* Last verified time */
Short is_confirmed; /* Whether the connection has been verified by */
int ping_num; /* The client-to-server ping value */
int ping_ticker; /* How many IO cycle processing updates a ping value */
int message_length; /* Send buffered message length */
Char Message_buf[max_text]; /* Send buffer */
int iflags; /* The status of the connection */
} connection_t;
The server loops through all the connections, is a dead loop process, each cycle uses Select to check if a new connection arrives, and then loops through all the connections to see which connection can be written or readable, and to handle the read and write of the connection. Because all of the processing is non-blocking, all socket IO can be done with a single thread.
Because of the network transmission relationship, each time recv () to the data may contain more than one message, or less than a message, then how to deal with it? So for the receive message buffer with two pointers, each receive starts reading from Text_start, because it is likely that there is an extra half message that was last received, and then text_end points to the end of the message buffer. This can be easily handled with two pointers, another point worth noting is that the process of parsing the message is a cyclic process, may receive more than two messages in the message buffer, this time should be executed into the message buffer only one of the messages, the general process is as follows:
while (Text_end–text_start > a full message length)
{
Start processing from the Text_start place;
Text_start + = the message length;
}
memcpy (text, text + Text_start, text_end–text_start);
For the processing of messages, here you first need to know what the total amount of information in your game, and what all the messages are, in order to design a more reasonable message header. Generally speaking, the message can be divided into main character message, scene message, synchronization message and interface message four parts. The protagonist message includes all the actions of the role that the client controls, including walking, running, fighting, and so on. Scenario messages include weather changes, a certain amount of time to appear in the scene, and so on, which is characterized by all messages being the initiator of the server, the broadcast object being all the players in the scene. While the synchronization message is for the originating object is a player, through the server broadcast to all visible players, the message is also included all the action, and the protagonist message is different from the message is the server broadcast to the client, and the protagonist message is generally the client actively to the server. Finally, the interface message includes the chat message and various attributes and status information that the server sends to the client.
Let's talk about the composition of the message. In general, a message consists of two parts: the message header and the message body, where the length of the message header is constant, and the length of the message body is variable, and the length of the message body needs to be preserved in the body of the message. Because a distinct distinction is to be given to each message, you need to define a flag that is unique to the message header, and then you need the type of message and the message ID. The message header is roughly structured as follows:
Type struct MESSAGE_S {
unsigned short message_sign;
unsigned char message_type;
unsigned short message_id
unsigned char Message_len
}message_t;
2 broadcast of the server
The focus of the server's broadcast is how to calculate the broadcast object. Obviously, in a large map, a player in the most east of an action, a player in the West should not see, then how to calculate the broadcast object? The simplest way to do this is to divide the map into small chunks of the right size, and then broadcast each time just like a few small players around. So how much is it appropriate to cut it? In general, the cut is large, the memory consumption will increase, cut the block smaller, CPU consumption will increase (reason will be mentioned later). Personally think cut into a screen about the small pieces more appropriate, each broadcast broadcast around nine small pieces of players, because of the radio operation is very frequent, then the operation of the nine blocks around the profit will become quite frequent, so if the block is smaller, then the scope of the benefit will be expanded, the CPU resources will be eaten quickly.
After cutting the block, how to let the player in the various blocks to walk around? Let's think about what to do when switching blocks at a time. First of all, to figure out the next block of nine players around the current block of what is not, to broadcast their information to those players, but also to figure out the next block around nine pieces inside what is not now, the information of those objects broadcast to themselves, and then the next block around nine fast without, And now the block around nine pieces of information about the disappearance of the message broadcast to themselves, but also the disappearance of the message broadcast to those objects. This operation is not only cumbersome and will eat a lot of CPU resources, then there is any way to quickly calculate these objects? How do you compare each other? Obviously not a good way, here can refer to the two-dimensional matrix collision detection of some ideas, with their own around nine blocks for a matrix, nine blocks around the target block for another matrix, to detect whether the two matrices collide, if the two matrices intersect, then do not intersect those blocks how to calculate. Here you can convert the coordinates of the intersecting blocks into internal coordinates and then perform the operations.
There is another solution for broadcasting, which is not as simple as slicing, which requires the client to assist in the operation. First in the server-side connection structure needs to add a Broadcast object queue, the queue when the client log on to the server by the server to the client, and then the client itself to maintain the queue, when someone out of the client's field of view, the client actively asked the server to send the message disappeared. And for some people always into the field of view, it is more troublesome.
The client is required to first send an update position message to the server, the server calculates a field of view for the connection, and then loops the player on the entire map when it needs to be broadcast, and finds the player whose coordinates are within its field of view. The advantage of using this method is that there is no conversion block to broadcast a large number of messages at a time, the disadvantage is that when calculating the broadcast objects need to traverse the entire map of the player, if a map of the players more than the more outrageous, the operation will be relatively slow.
3 synchronization of servers
Synchronization is very important in online games, which ensures that every player sees something on the screen that is roughly the same. In fact, the simplest way to solve the synchronization problem is to broadcast each player's actions to the other players, there are actually two questions: 1, which players to broadcast, broadcast which messages. 2, what to do if the network is delayed. In fact, the first question is a very simple question, but the reason I ask this question is to remind you that you need to take this factor into consideration when designing your own message structure. And for the second problem, it is a very troublesome problem, you can see this example:
For example, a player A to the server issued a command, said I am now in P1 point, to go to P2 point. The time that the instruction is issued is T0, the server receives the instruction time is T1, then broadcasts this message to the surrounding player, the message content is "Player A from P1 to P2" has a player in the vicinity of a B, the time to receive this broadcast message of the server is T2, and then start drawing on the client, a from P1 to P2 point. At this time there is an out of sync problem, player A and Player B on the screen shows a difference of t2-t1 time. What about this time?
There is a solution, I call it the prediction pull, although some strange point, but basically people can literally understand its meaning. To solve this problem, first define a value called: Prediction error. Then need to be in the server side of each player connected to the class to add an attribute, called latency, and then when the player landed, the client time and the server time to compare, the difference is saved in the latency inside. Or the above example, when the server broadcasts the message, it calculates a client's currenttime based on the latency of the object to be broadcast, and then includes the currenttime in the message header before broadcasting. And at the same time in player A's client local set up a queue, save the message, only to obtain the server authentication has never been authenticated message queue to delete the message, if the verification fails, it will be pulled back to the P1 point. Then when player B receives a message from the server "Player A from P1 to P2" This time to check the message inside the server issued time and local time to do the comparison, if the forecast error is greater than the definition, even if the T2 at this time, player A's screen to go to the place P3, Then the Player B screen player A directly pull to P3, and then continue to go on, so that the synchronization can be guaranteed. Further, in order to ensure that the client run more smooth, I do not recommend directly to pull the player past, but to calculate the P3 after a bit of P4, and then use (P4-P1)/T (P4-P3) to calculate a fast speed s, and then let player a with speed s fast move to P4, This approach is reasonable, the prototype of this solution is internationally known as the (full plesiochronous), of course, the prototype was I tampered with a lot to adapt to the synchronization of online games, so instead of the so-called: predictive pull.
Another solution, I called it to verify the synchronization, listen to the name also know, the general meaning is that each instruction after the server verification passed after the execution of the action. The specific idea is as follows: First of all, you need to define a latency in each player connection type, and then when the client responds to the player's Mouse walk, the client does not move forward, but sends a walking instruction to the server and waits for the server to authenticate. After the server accepts this message, it verifies the logic layer, and then calculates the range that needs to be broadcast, including player A, to generate different message headers according to different latency of each client, to start broadcasting, this time the player's walking information is fully synchronized. The advantage of this method is to ensure the absolute synchronization between the client, the disadvantage is that when the network latency is relatively large, the player's client behavior will become more fluid, to the player to bring a very uncomfortable feeling. The prototype of this solution is internationally known (Hierarchical Master-slave synchronization) and is widely used in various fields of the network since the 80 's.
The final solution is an idealized solution, known internationally as mutual synchronization, as a well-predicted solution to future network prospects. The reason for this proposal is not that we have fully implemented this approach, but that some of the ideas in this scenario are applied to certain aspects of the online game domain. I named this scenario: half-server synchronization. The general design ideas are as follows:
First, the client needs to be in the world to build a number of broadcast list, these lists in the client background and the server to be not in time to synchronize, the reason to create multiple lists, because there is more than one type of broadcast, for example, there is a local message, a remote message, There is also a global message and so on, these lists need to be established when the client logs in according to the message sent by the server. In the establishment of the list, but also need to get the latency of the broadcast object in each list, and to maintain a complete list of user status in the background, but also not timely and the server synchronization, according to the local User state table, can make a part of the decision by the client to decide, When the client sends this part of the decision, the final decision is sent directly to the client in each broadcast list, and the time is proofread to ensure that each client receives the message at the time and is proofread according to the local time. Then using the predicted pull mentioned in the calculation of the amount of advance, to improve the speed of walking past, will make synchronization become very smooth. The advantage of this scheme is not through the server, the client synchronization between themselves, greatly reducing the network delay caused by the error, and because most of the decisions can be done by the client, but also greatly reduce the server resources. The disadvantage is that the message and decision-making power are placed on the client-side, so the plug-in provides a great opportunity.
4 NPC Questions
Next I would like to talk about the design of the NPC on the server and the NPC intelligence and other aspects of the problems involved. First, we need to know what NPC,NPC needs to do. NPC Full name is (Non-player Character), it is clear that he is a Character, but not the player, then from this point can be known that some of the NPC behavior is similar to the player, he can walk, can fight, Can breathe (this is mentioned in the following NPC intelligence), and the other point is different from the player's object, the NPC can be resurrected (that is, the NPC is killed in a certain period of time can be re-out). In fact, the most important point is that all the decisions of the player's objects are made by the player, and the NPC's decision is made by the computer, so when it comes to making decisions about NPC, it needs the so-called NPC intelligence to make decisions.
Here I will be divided into two parts to talk about NPC, first, NPC intelligence, followed by how the server to organize NPC. The reason we have to talk about NPC intelligence is because only when we understand clearly what we need NPC to do, we start designing the server to organize the NPC.
NPC Intelligence
NPC intelligence is divided into two types, one is the passive triggering event, and the other is the active trigger event. For passively triggered events, the processing is relatively simple, can be called by the event itself function, such as NPC death, in fact, when the NPC's HP is less than a certain value, to actively call the NPC Body Ondie () function, The NPC intelligence, which is triggered by events to trigger NPC behavior, is called passive triggering. This type of trigger is often divided into two types:
One is a change in the attributes of an NPC caused by another object, and then the attributes change, causing the NPC to behave. As a result, the NPC object contains at least the following functions:
Class NPC {
Public
Who was there that caused me which property changed how much.
Onchangeattribute (object_t *who, int which, int how, int where);
Private:
Ondie ();
Onescape ();
Onfollow ();
Onsleep ();
A series of events.
}
This is the structure of a basic NPC, this passive trigger NPC event, I call it a reflection of NPC. However, such a structure can only let the NPC passively receive some information to make the decision, such NPC is foolish. So, how can an NPC take the initiative to make some decisions? Here's one way: breathe. So how do you get the NPC to breathe?
A very simple method, with a timer, to trigger the breath of all NPCs at timed intervals, so that an NPC can breathe. There will be a problem, when the NPC is too many, the last NPC breath has not been exhausted, the next breath again, then how to solve the problem. Here is a way for the NPC to breathe asynchronously, that is, each NPC's breathing cycle is based on the time the NPC was born, and this time the timer needs to do is to check the time interval, which NPCs to breathe, to trigger these NPC's breathing.
The above mentioned is how the system to trigger the NPC's breathing, then the NPC's own breathing frequency how to set it? It's like a real person, and it's not the same as when you're sleeping and exercising intensely. In the same way, when the NPC is fighting, the frequency of breathing is not the same as usual. Then you need a breath_ticker to set the current respiration rate of the NPC.
So how do we set the NPC's intelligence in the event of an NPC's breathing? It can be broadly summarized as two parts to examine the environment and make decisions. First, the current environment needs to be digitally counted, such as whether there are several enemies in combat, how much of their HP is left, and where there are no enemies, and so on. The statistics come into their own decision-making module, the decision-making module based on the NPC's own disposition to make some decisions, such as Savage NPC will be less than the HP still pounce, such as the wisdom of the NPC will be less hp when the choice to escape. Wait, something like that.
At this point, the structure of an NPC that can breathe and reflect has been basically formed, so let's talk about how the system organizes an NPC into the present world.
Organization of NPC
Here are two options to choose from: The location information of the NPC is stored in the scene and loaded into the NPC when the scene is loaded. Second, the NPC location information is stored in NPC, there is a special event for all NPC landing scene. What is the difference between these two methods? What are the good and bad?
The advantage of the previous method is that when the scene is loaded into the NPC at the same time, the scene can manage the NPC, no unnecessary processing, and the disadvantage is that when the refresh is synchronized refresh, that is, a scene of NPC may be in the same time grow out. And for the second method, the design will be a little more trouble, need a unified mechanism for NPC landing to the scene, but also need some more cumbersome design, but this scheme can realize the NPC asynchronous refresh, is the current network game widely used method, the following we will focus on the implementation of this method:
First we will introduce a concept of "soul", that is, a NPC after death, the disappearance of his body, his soul still exists in the world, not breathing, floating near the death, waiting for the time to reincarnate, reincarnation of all the attributes of the previous to zero, re-build their body in the scene. So, how do we design such a structure? First, the NPC that appears in a scene is made into a chart, giving each NPC a unique identifier, which, after loading the scene, loads the NPC into the scene according to the graph. In the NPC Ondie () event, instead of destroy the object directly, it closes the NPC's breath, then opens a reborn timer and finally sets the object to Invisable. This design, can realize the NPC asynchronous refresh, save the server resources, but also let the players feel more real.
The application of heuristic search (heuristic searching) in NPC intelligence is supplemented.
The main idea is to filter all nodes in the next layer through a heuristic function, and narrow the search scope within a certain range, while the breadth first searches. The well-known pathfinding * algorithm is a typical heuristic search application, and the principle is to design a judge (point_t* point) function to obtain the price of point, and then each time the search takes place all the points that can be reached are judge () function evaluation, get two to three cost relatively small point, continue to search, those not selected points will not continue to search, so the result is probably not the optimal path, this is why a * algorithm in the search for the road will go to the front of the obstacles and then around the past, Instead of a pre-slash to get around the obstacle. If we want to find the optimal path, it is not possible to use a * algorithm, but to use a dynamic programming method, its consumption is much larger than a *.
So, what else can be applied to heuristic search besides the pathfinding? In fact, to speak a little bigger, any decision of NPC can be used heuristic search to do, such as escape, if it is a 2D network game, there are eight directions, NPC choose which direction to escape? You can set a judge (int direction) to the cost of each point, calculate the strength of the enemy in the judge, or how agile the enemy is, and finally choose the least expensive place to escape. Next, let's talk about the design of a heuristic search method for the common intelligence of several NPCs:
Target Select (select target):
First get a list of enemies near the NPC on the map. Design judge () function, according to the strength of the enemy, the enemy's distance, calculate the price. Then select the least expensive enemy to attack aggressively.
Escape (Escape):
Check your HP in a breathing event, if HP is below a certain value, or if you are a remote class, and the enemy is close, trigger the escape function, and in the escape function also organize a list of all surrounding enemies, and then design the judge () function to select the enemy that poses the greatest threat to you. The judge () function needs to judge the enemy's speed, combat effectiveness, and finally draw a major enemy, and then the main enemy of the path of the judge () function of the design, the scope of the search can only be the main enemy in the opposite direction, and then based on the strength of the enemy in the several directions to calculate the cost, Make the final choice.
Random walk (walk randomly):
This I do not recommend A * algorithm, because the NPC once more up, then this CPU consumption is very scary, and NPC most do not need long-distance search, just to walk around in the vicinity, then, in the vicinity randomly to several points, and then let the NPC walk over, if encountered obstacles to stop, There is hardly any burden in this way.
Follow target (following target):
There are two ways, one method NPC looks stupid, one method looks more intelligent, the first method is to let the NPC follow the target of the road point, almost no resource consumption. The latter is to let the NPC in the following time, in the breath event to determine the other party's current position, and then go straight, encountered obstacles in a * around the past, the design will consume a certain amount of system resources, so do not recommend the NPC large number of follow-up targets, if a large number of NPCs to follow the target, There is also a relatively simple way: let the NPC and the target synchronous movement, that is, to let their speed unified, moving the same road points, of course, this design is only suitable for NPC following the goal is not to kill the relationship, just follow the players go.
Original URL: http://www.cnblogs.com/GameDeveloper/archive/2011/05/24/2055880.html
[Turn] online game server Development Primer Knowledge