[ZT] online-game server design (4)

Source: Internet
Author: User
In this section, I want to talk about the design of scripts on the server. In the previous chapter, some script-related things have been introduced when talking about NPC intelligence. Let's talk about the role of the script first.
In a compiled server-side program, you cannot build something during the program running process. Therefore, you need the support of the script language. Because the script language involves logical judgment, therefore, it is useless to provide some function interfaces. You also need to provide some simple syntax and Syntax Parsing functions. In fact, in the end, any event can be regarded as two parts: the first is to change the value of itself or other objects, and the other is to broadcast the event in the form of text or graphics. A very important topic is addressing an object. Well, when talking about this, I want to divide this chapter into three parts: first, how the server manages dynamically created objects (Server Memory Management ), the second is how to address an object, and the third is how to organize and explain the script language. In fact, the reason for talking about Server Memory Management in Chapter 4 is that we don't have a perceptual knowledge of the server memory management in the previous chapters, and we may not know what the server memory management actually uses.

4.1 Server Memory Management
For server memory management, we will adopt the memory pool method, also known as static memory management. The concept is to apply for a very large memory pool called a memory pool during server initialization, and also apply for a small memory space, it is called the garbage recollecting station ). The general idea is as follows: when the program needs to apply for memory, first check whether the recycle bin is empty. If not, find an available memory address from the recycle bin, find the corresponding space in the memory pool based on the address and allocate it to the program. If the spam recycle bin is empty, apply for a memory directly from the current pointer position of the memory pool; when the program releases space, it marks the memory that has been released, and then places the memory address in the garbage bin.
The following describes the detailed design of this method. First, we will use a segment-based system similar to the operating system to manage the memory. The advantage is that the memory pool can be fully utilized, the disadvantage is that it is difficult to manage. Well, let's take a look at how we can define the structure of pages and segments:

Typedef struct m_segment_s
{
Struct m_segment_s * Next;/* double-line linked list + static memory can achieve random access and sequential access,
If you really want to access it, you can access it. */
Struct m_segment_s * pre; int flags; // some marks of the segment.
Int start; // relative to the first address of the page.
Int size; // length.
Struct m_page_s * my_owner; // The page on which I belong.
Char * data; // content pointer.
} M_segment_t;

Typedef struct m_page_s
{
Unsigned int flags;/* Indicates whether to use the flag completely or not */
Int size;/* the size of the page, which is generally unified, except for the last page */
Int end;/* Where is it used */
Int my_index;/* provides random access indexes */
M_segment_t * segments; // the header pointer of the segment in the page.
} M_page_t;

How can we build a memory pool and a garbage collection bin? The following are some pseudo code related to building:

Static m_page_t * all_pages;
// Total_size indicates the total number of memories to be applied for, and num_pages indicates the total number of pages to be created.
Void initialize_memory_pool (INT total_size, int num_pages)
{
Int I, page_size, last_size; // calculate the size of each page.
Page_size = total_size/num_pages; // allocate enough pages.
All_pages = (m_page_t *) calloc (num_pages, sizeof (m_page_t *));
For (I = 0; I <num_pages; I ++)
{
// Initialize the segment pointer of each page.
All_pages [I]. m_segment_t = (m_segment_t *) malloc (page_size );
// Initialize the tag of the page.
All_pages [I]. Flags | = never_used;
// Except the last page, all the other pages are page_size.
All_pages [I]. size = page_size;
// Initialize the random access index.
All_pages [I]. my_index = I;
// Since it has not been used, the size is 0.
All_pages [I]. End = 0;
}

// Set the size of the last page.
If (last_size = total_size % num_pages )! = 0)
All_pages [I]. size = last_size;
}

The following describes how to design the recycle bin:

Int ** garbage_station;
Void init_garbage_station (INT num_pages, int page_size)
{
Int I;
Garbage_station = (INT **) calloc (num_pages, sizeof (int *));
For (I = 0; I <num_pages; I ++)
{
// Here, the unsigned short's 8-bit high is used to store the Prime Minister's address, and the 8-bit low is used to store the length.
Garbage_station [I] = (int *) calloc (page_size, sizeof (unsigned short ));
Memset (garbage_station [I], 0, sizeof (garbage_station [I]);
}
}

Maybe this post-code will make you feel quite confused. Well, my code level is really not very good, so let's talk about the general concept in text. For segment-page memory management, it is first divided into N pages, which is fixed, while the segments in each page are dynamic. The major and minor sections are unknown, we need to reclaim not only the page memory, but also the segment memory, so we need a two-dimensional array to save the address of the segment of which the page is released. Then, when applying for memory, first check the size of the memory to be applied. If there is not enough page size, find available segment space allocation in the recycle bin. If not, apply for a new page space.
In this way, using a memory pool to manage the memory of the entire game world can effectively reduce memory fragments and improve the stability and efficiency of game operation to a certain extent.

4.2 addressing of objects in the game
The first question is, why are we addressing? After the concept of scripting language is added, some logical objects in the game, such as the NPC and an item, are dynamically generated by the scripting language during the game's operation, so how can we index these objects? To put it simply, how can we find them? There is a very simple method to traverse all at once. Of course, this is a simple and effective method, but the cost of efficiency is too high for any server, especially after the game scale is relatively large.
So how can we quickly find these objects in the game world? Before talking about this, let me talk about the hash table data structure. It is also called a hash table or a hash table. The working principle of hash table is sequential access or random access, instead, a hash function is used to calculate the key, calculate the address of the value corresponding to the key in the memory, and access it. The advantage is that no matter how big the data is, you only need to calculate it once to find its address, which is very fast. What is the drawback? When the addresses calculated by the two keys through the hash function are the same address, the problem arises and a collision occurs. The solution is very troublesome, I will not discuss the solution in detail here. Otherwise, I would like to write another four or five chapters. However, if you are interested in the solution, you are welcome to discuss it.
Well, we will use a hash to index the objects in the game. What should we do? First, why is it twice as large as applying for a piece of memory in the memory pool that is more than the total number of objects in the game? Prevents hash collision. Then we select the object name as the index key of the hash table, and then we can start designing the hash function. Here is an example:

Static int T [] =
{
1, 87, 49, 12,176,178,102,166,121,193, 6, 84,249,230, 44,163,
14,197,213,181,161, 85,218, 80, 64,239, 24,226,236,142, 38,200,
110,177,104,103,141,253,255, 50, 77,101, 81, 18, 45, 96, 31,222,
25,107,190, 70, 86,237,240, 34, 72,242, 20,214,244,227,149,235,
97,234, 57, 22, 60,250, 82,175,208, 5,127,199,111, 62,135,248,
174,169,211, 58, 66,154,106,195,245,171, 17,187,182,179, 0,243,
132, 56,148, 75,128,133,158,100,130,126, 91, 13,153,246,216,219,
119, 68,223, 78, 83, 88,201, 99,122, 11, 92, 32,136,114, 52, 10,
138, 30, 48,183,156, 35, 61, 26,143, 74,251, 94,129,162, 63,152,
170, 7,115,167,241,206, 3,150, 55, 59,151,220, 90, 53, 23,131,
125,173, 15,238, 79, 95, 89, 16,105,137,225,224,217,160, 37,123,
118, 73, 2,157, 46,116, 9,145,134,228,207,212,202,215, 69,229,
27,188, 67,124,168,252, 42, 4, 29,108, 21,247, 19,205, 39,203,
233, 40,186,147,198,192,155, 33,164,191, 98,204,165,180,117, 76,
140, 36,210,172, 41, 54,159, 8,185,232,113,196,231, 47,146,120,
51, 65, 28,144,254,221, 93,189,194,139,112, 43, 71,109,184,209,
};

// S is the string pointer to be indexed, maxn is the maximum possible length of a string, and the return value is the relative address.
Inline int whashstr (char * s, int maxn)
{
Register unsigned char Oh, h;
Register unsigned char * P;
Register int I;

If (! * S)
Return 0;
P = (unsigned char *) S;
Oh = T [* p]; H = (* (p ++) + 1) & 0xff;
For (I = maxn-1; * P & -- I> = 0 ;)
{
Oh = T [OH ^ * p]; H = T [H ^ * (p ++)];
}
Return (Oh <8) + h;
}

The specific algorithm is not mentioned. Don't ask me why in the above section. The source of this algorithm is Peter K in CACM 33-6. the algorithms introduced in Pearson's ghost paper are said to be very fast. With this hash function, we can use it to quickly address any object in the world.

4.3 script language explanation
Before designing a script language, we must first understand what features should we implement in our script language? Otherwise, you may want to write a C interpreter or something like that. The functions we need to implement are simple logical judgment and loops. All other functions can be completed by providing functions in advance. Well, we can list a workload form: design the storage structure of objects at the underlying layer, provide the access interface between scripts and the underlying layer, and design the interpreter supporting logical judgment and loop.
Next we will talk about the storage structure of objects at the underlying layer. Objects with different properties must have different structures. Of course, if you want to, you can use the same structure for all objects, then, design a hash in the structure to save different attributes. However, this is not a good method. relying too much on the scattered list will complicate the logic of your game. Therefore, try to distinguish between different objects and adopt different structures for design. But it is worth noting that no matter what structure, there are some things that are unified, that is, what we call object headers. How can we design such an object header?

Typedef struct object_head_s
{
Char * Name;
Char * prog;
} Object_head_t;

Here, name is the index number of the object in the hash list, and prog is the program content to be explained by the script interpreter. The following uses the NPC as an example to design a structure:

Typedef struct npc_s
{
Object_head_t header; // Object Header
Int HP; // The hpvalue of the NPC.
Int level; // The level of the NPC.
Struct position_s position; // The current position information.
Unsigned int personality; // NPC personality. An unsigned int can save 24 types of personality.
} Npc_t;

OK. The structure design is complete. How can we design the script interpreter? There are two methods: one is to use the virtual machine mode to parse the script language, and the other is to use a structure similar to the assembly language for design, you can set conditional jumps and loops to implement logical judgment and loops, for example:

Set Name, "Lu Ren jia ";
Choose: random_choose_personality; // randomly select the NPC personality
Compare HP, 100; // compare qi and blood. The value can be placed in a fixed variable.
Ifless less; // if HP is less than 100, return.
Jump choose; // otherwise, continue to select only one HP <100.
Less: Return success;

This script structure is similar to the CPU instruction structure. A single instruction can be executed in sequence, and script programmers can also develop their assembly capabilities.
So how can we imitate this structure? Let's take the CPU command as a reference. First, we need to set some registers. The size and quantity of the CPU registers are affected by hardware, but we use memory to simulate the registers, that's how big it can be. Then some commands are provided, including four operations, addressing, judgment, and loop. Next we will use different parsing methods for different scripts. For example, we will use a fixed script for the NPC and a fixed script for the item, after parsing, the result is used to generate the structure of the underlying object.
If you use a virtual machine to implement the scripting language, the project will become very huge and is strongly not recommended. However, if you want to build a general underlying network game, you can consider designing a virtual machine. The general interpretation process of the virtual machine is to compile the keywords twice. The first compilation is to generate the assembly language for the second generation. Then, the virtual machine will explain the compilation language line by line, if you are interested in this, you can download a mudos source code from www.mudos.org for research. The general idea is that it is almost the same here. Next we will use unreal (unreal) as an example to talk about the design of online game servers.
 

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.