青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

天行健 君子當自強而不息

Getting Online with Multiplayer Gaming(14)

 

Updating Players

In order to synchronize itself with clients, the server needs to maintain a simplified
version of the game running internally. This version of the game doesn’t include
graphics, sound, or any other fancy features; it only needs to track player’s actions.

The server tracks those actions by updating the player’s actions every 33ms (just as
the client application will do). Those actions include walking and waiting for other
specific states to clear (such as sword swinging and being hurt).

The cApp::update_players function is responsible for updating all players:

void cApp::update_players()
{
    sStateChangeMsg change_msg;

    
// loop through all players
    for(int i = 0; i < MAX_PLAYERS; i++)
    {
        
// only update connected players
        if(! m_players[i].connected)
            
continue;

        
long elapsed = timeGetTime() - m_players[i].last_update_time;

        
if(m_players[i].last_state == STATE_MOVE)
        {
            
// calculate amount of movement by time passed
            float speed  = elapsed / 1000.0f * m_players[i].speed;
            
float x_move = sin(m_players[i].direction) * speed;
            
float z_move = cos(m_players[i].direction) * speed;

            
// check for movement collision - can not walk past anything blocking path
            if(check_intersect(&m_level_mesh,
                m_players[i].x_pos,          m_players[i].y_pos + 16.0f, m_players[i].z_pos,
                m_players[i].x_pos + x_move, m_players[i].y_pos + 16.0f, m_players[i].z_pos + z_move))
            {
                x_move = z_move = 0.0f;
            }

            
// update player coordinates
            m_players[i].x_pos += x_move;
            m_players[i].y_pos  = 0.0f;     
// stay on ground
            m_players[i].z_pos += z_move;

            m_players[i].last_update_time = timeGetTime();
        }
        
else if(m_players[i].last_state == STATE_SWING && elapsed > 1000)   // clear swing status after 1 second
        {
            m_players[i].last_state = STATE_IDLE;

            
// send network message to player to clear
            change_msg.header.type      = MSG_STATE_CHANGE;
            change_msg.header.size      = 
sizeof(sStateChangeMsg);
            change_msg.header.player_id = m_players[i].player_id;
            change_msg.x_pos            = m_players[i].x_pos;
            change_msg.y_pos            = m_players[i].y_pos;
            change_msg.z_pos            = m_players[i].z_pos;
            change_msg.direction        = m_players[i].direction;
            change_msg.speed            = m_players[i].speed;
            change_msg.state            = m_players[i].last_state;

            send_network_msg(&change_msg, DPNSEND_NOLOOPBACK, ALL_CLIENT_PLAYERS);
        }
        
else if(m_players[i].last_state == STATE_HURT && elapsed > 1000)    // clear hurt status after 1 second
        {
            m_players[i].last_state = STATE_IDLE;

            
// send network message to player to clear
            change_msg.header.type      = MSG_STATE_CHANGE;
            change_msg.header.size      = 
sizeof(sStateChangeMsg);
            change_msg.header.player_id = m_players[i].player_id;
            change_msg.x_pos            = m_players[i].x_pos;
            change_msg.y_pos            = m_players[i].y_pos;
            change_msg.z_pos            = m_players[i].z_pos;
            change_msg.direction        = m_players[i].direction;
            change_msg.speed            = m_players[i].speed;
            change_msg.state            = m_players[i].last_state;

            send_network_msg(&change_msg, DPNSEND_NOLOOPBACK, ALL_CLIENT_PLAYERS);
        }
    }
}

As the server scans the list of players, it determines which players are connected
and calculates the time since the last server update for all connected players. Next,
if a player’s state is set to STATE_MOVE, the elapsed time is used to move the player.

Next, the server deals with the STATE_SWING and STATE_HURT states. Those states are
cleared only after one second has passed (as determined by the elapsed time).

Surprisingly, that’s it for cApp::update_players! Remember that the update_players function
is called every 33ms, so keeping the function quick and to the point is crucial.
Once all players are updated, you need to notify other players.

 

Updating the Network Clients

Throughout earlier sections in this chapter, I mentioned periodic server updates
that are sent to the client in order to synchronize game-play. That’s the purpose of
the cApp::update_network function. The update_network function is quick and to the
point, sending out the current state of all connected clients every 100ms.

void cApp::update_network()
{
    
// send all player updates
    for(long i = 0; i < MAX_PLAYERS; i++)
    {
        
if(m_players[i].connected)  // only send data about connected players
        {
            sStateChangeMsg change_msg;

            change_msg.header.type      = MSG_STATE_CHANGE;
            change_msg.header.size      = 
sizeof(sStateChangeMsg);
            change_msg.header.player_id = m_players[i].player_id;
            change_msg.x_pos            = m_players[i].x_pos;
            change_msg.y_pos            = m_players[i].y_pos;
            change_msg.z_pos            = m_players[i].z_pos;
            change_msg.direction        = m_players[i].direction;
            change_msg.speed            = m_players[i].speed;
            change_msg.state            = m_players[i].last_state;
            change_msg.latency          = m_players[i].latency;

            send_network_msg(&change_msg, DPNSEND_NOLOOPBACK, ALL_CLIENT_PLAYERS);
        }
    }
}

 

Calculating Latency

The server periodically calculates the time it takes a message to be received from a
client and uses the latency in the timed calculations to update clients, all of which
is crucial to maintaining the synchronization of the game. The function that calculates
the latency is update_latency, and it is called every 10 seconds from the main
application loop (cApp::frame).

void cApp::update_latency()
{
    
// go through all players
    for(long i = 0; i < MAX_PLAYERS; i++)
    {
        
if(m_players[i].connected)  // only process connected players
        {
            DPN_CONNECTION_INFO connect_info;

            
// request player connection settings
            if(SUCCEEDED(m_server.get_server()->GetConnectionInfo(m_players[i].player_id, &connect_info, 0)))
            {
                m_players[i].latency = connect_info.dwRoundTripLatencyMS / 2;

                
// bounds latency to 1 second
                if(m_players[i].latency > 1000)
                    m_players[i].latency = 1000;
            }
            
else
                m_players[i].latency = 0;
        }
    }
}

To calculate the latency, the server queries DirectPlay for the connection statistics
via the IDirectPlay8Server::GetConnectInfo function. That function call takes a structure
(DPN_CONNECTION_INFO) as an argument, and inside the structure is a variable that
represents the roundtrip latency time in milliseconds. The server divides that
latency value in half and stores it in each player’s data structure.

 

Other function:

int WINAPI WinMain(HINSTANCE inst, HINSTANCE, LPSTR cmd_line, int cmd_show)
{
    
const char* class_name = "ServerClass";

    WNDCLASSEX win_class;

    
// create window class and register it

    win_class.cbSize        = 
sizeof(win_class);
    win_class.style         = CS_CLASSDC;
    win_class.lpfnWndProc   = window_proc;
    win_class.cbClsExtra    = 0;
    win_class.cbWndExtra    = 0;
    win_class.hInstance     = inst;
    win_class.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    win_class.hCursor       = LoadCursor(NULL, IDC_ARROW);
    win_class.hbrBackground = (HBRUSH) GetStockObject(LTGRAY_BRUSH);;
    win_class.lpszMenuName  = NULL;
    win_class.lpszClassName = class_name;
    win_class.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

    
if(! RegisterClassEx(&win_class))
        
return false;

    DWORD style = WS_BORDER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU;

    DWORD pos_x = (get_screen_width()  - CLIENT_WIDTH) / 2;
    DWORD pos_y = (get_screen_height() - CLIENT_HEIGHT) / 4;
    
    g_hwnd = CreateWindow(class_name, "Network Server Demo", style, pos_x, pos_y, 
                          CLIENT_WIDTH, CLIENT_HEIGHT, NULL, NULL, inst, NULL);

    
if(g_hwnd == NULL)
        
return -1;

    ShowWindow(g_hwnd, SW_NORMAL);
    UpdateWindow(g_hwnd);

    resize_window(g_hwnd, CLIENT_WIDTH, CLIENT_HEIGHT);

    cApp app;
    app.run();

    
return 0;
}

///////////////////////////////////////////////////////////////////////////////////////

BOOL CALLBACK config_dlg_proc(HWND dlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
    
static HWND adapter_wnd;

    
switch(msg)
    {
    
case WM_INITDIALOG:
        adapter_wnd = GetDlgItem(dlg, IDC_ADAPTERS);

        
// add adapter names to list
        for(long i = 0; i < g_adapter->get_num_adapters(); i++)
        {
            
char text[256];
            g_adapter->get_name(i, text);

            insert_string_to_combo(adapter_wnd, i, text);
        }

        
// select first adapter in list
        set_combo_cur_sel(adapter_wnd, 0);

        
return TRUE;

    
case WM_COMMAND:
        
switch(LOWORD(wParam))
        {
        
case IDC_OK:
            {
            
int sel = (int) get_combo_cur_sel(adapter_wnd);  

            
// make sure an adapter was selected
            if(sel == LB_ERR)
                
break;

            g_app->set_adapter_guid(g_adapter->get_guid(sel));

            EndDialog(dlg, TRUE);
            
return TRUE;
            }

        
case IDC_CANCEL:
            EndDialog(dlg, FALSE);
            
return TRUE;
        }
    }

    
return FALSE;
}

///////////////////////////////////////////////////////////////////////////////////////

bool cApp::init()
{
    
// select a network adapter to use (or quit if selected)
    if(! select_adapter())
        
return false;

    setup_app_window();

    
// intialize the game, set display mode, load level mesh.
    if(! init_game())
    {
        show_error_msg(
false, "Unable to initialize game.");
        
return false;
    }

    
// begin hosting the game session
    if(! host_game())
    {
        show_error_msg(
false, "Unable to host network server.");
        
return false;
    }

    
return true;
}

///////////////////////////////////////////////////////////////////////////////////////

bool cApp::frame()
{
    
static DWORD player_counter  = timeGetTime();
    
static DWORD network_counter = timeGetTime();
    
static DWORD latency_counter = timeGetTime();

    process_queue_msg();

    
// update players every 33ms (30 times a second)
    if(timeGetTime() > player_counter + 33)
    {
        update_players();
        player_counter = timeGetTime();
    }
    
    
// send out network update every 100ms (10 times a second)
    if(timeGetTime() > network_counter + 100)
    {
        update_network();
        network_counter = timeGetTime();
    }

    
// update player latency values every 10 seconds
    if(timeGetTime() > latency_counter + 10000)
    {
        update_latency();
        latency_counter = timeGetTime();
    }

    
return true;
}

///////////////////////////////////////////////////////////////////////////////////////

void cApp::shutdown()
{
    delete[] m_msgs;
    m_msgs = NULL;

    delete[] m_players;
    m_players = NULL;

    DeleteCriticalSection(&m_msg_cs);
}
    
///////////////////////////////////////////////////////////////////////////////////////

bool cApp::select_adapter()
{
    ShowWindow(g_hwnd, SW_HIDE);    
// hide main window
    m_adapter.init();

    
return (bool) DialogBox(get_window_inst(), MAKEINTRESOURCE(IDD_CONFIG), g_hwnd, config_dlg_proc);
}

///////////////////////////////////////////////////////////////////////////////////////

void cApp::setup_app_window()
{
    
// window to hold host IP address
    m_controls[CONTROL_SERVER_IP] = CreateWindow("STATIC", "", WS_CHILD | WS_VISIBLE, 4, 4, 312, 18,
                                                 g_hwnd, NULL, get_window_inst(), NULL);

    
// window to hold number of connected players
    m_controls[CONTROL_PLAYER_NUM] = CreateWindow("STATIC", "No Connected Players",  WS_CHILD | WS_VISIBLE,
                                                  4, 26, 312, 18, g_hwnd, NULL, get_window_inst(), NULL);

    
// list box to display connect player's names
    m_controls[CONTROL_PLAYER_LIST] = CreateWindow("LISTBOX", "", WS_CHILD | WS_BORDER | WS_VSCROLL | WS_VISIBLE,
                                                   4, 48, 312, 154, g_hwnd, NULL, get_window_inst(), NULL);

    
// show main window
    ShowWindow(g_hwnd, SW_SHOW);
}

///////////////////////////////////////////////////////////////////////////////////////

bool cApp::init_game()
{
    create_display(g_hwnd, CLIENT_WIDTH, CLIENT_HEIGHT, 16, 
truetrue);

    
// load the level mesh for collision checking
    if(! m_level_mesh.load("..\\Data\\ArenaCM.x", "..\\Data\\"))
        
return false;

    m_msgs = 
new sMsg[MAX_MESSAGES];
    m_msg_head = m_msg_tail = 0;

    m_players = 
new sPlayer[MAX_PLAYERS];
    m_connected_player_num = 0;

    
return true;
}

///////////////////////////////////////////////////////////////////////////////////////

bool cApp::host_game()
{
    
// configure server and begin hosting

    m_server.init();

    
if(! m_server.host(m_adapter_guid, 9123, "RPGGAME", NULL, MAX_PLAYERS))
        
return false;

    
char text[33], ip[16];

    
// get server ip address and display in application window
    m_server.get_ip(ip, 0);
    sprintf(text, "Host IP Address: %s", ip);
    SetWindowText(m_controls[CONTROL_SERVER_IP], text);

    
return true;
}

download source and solution

posted on 2007-12-18 23:20 lovedday 閱讀(220) 評論(0)  編輯 收藏 引用


只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


公告

導航

統計

常用鏈接

隨筆分類(178)

3D游戲編程相關鏈接

搜索

最新評論

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美专区在线| 久久久久国产成人精品亚洲午夜| 麻豆成人精品| 久久精品国产成人| 在线高清一区| 欧美夫妇交换俱乐部在线观看| 久久99伊人| 在线成人av网站| 欧美成人一区二区三区在线观看 | 欧美性猛交xxxx乱大交蜜桃| 亚洲美女视频网| 亚洲免费久久| 国产精品人成在线观看免费| 香蕉亚洲视频| 久久不射中文字幕| 亚洲人被黑人高潮完整版| 欧美激情视频网站| 欧美区在线播放| 欧美一级黄色网| 欧美中文在线免费| 亚洲区免费影片| 99精品久久久| 国内外成人在线| 欧美国产在线观看| 欧美视频网址| 久久久久久久久一区二区| 久久一区精品| 亚洲欧美欧美一区二区三区| 欧美一区二区高清| 91久久在线视频| 亚洲天天影视| 91久久精品国产91性色tv| 亚洲深夜福利网站| 激情久久五月天| 亚洲精品一区二区在线观看| 国产欧美日韩亚州综合| 欧美激情欧美狂野欧美精品| 国产精品v日韩精品v欧美精品网站| 久久精品一本| 欧美日韩一区二区在线| 毛片av中文字幕一区二区| 欧美日韩国产免费观看| 久久综合狠狠综合久久综合88| 欧美日韩的一区二区| 久久永久免费| 国产精品免费区二区三区观看| 欧美黄网免费在线观看| 国产欧美日韩三级| 亚洲精品综合久久中文字幕| 尤物yw午夜国产精品视频| 亚洲视频中文| 日韩亚洲综合在线| 久久婷婷亚洲| 久久久久国内| 欧美大片18| 国产精品一区视频| 日韩一级在线| 亚洲精品影院| 老司机一区二区三区| 久久久91精品| 国产欧美亚洲日本| 一本一本久久a久久精品综合麻豆 一本一本久久a久久精品牛牛影视 | 日韩一区二区精品视频| 久久精品国产69国产精品亚洲| 亚洲女人小视频在线观看| 欧美二区在线观看| 亚洲二区在线视频| 在线观看欧美视频| 久久精彩免费视频| 久久久免费精品| 国产一区二区精品久久99| 亚洲男人第一网站| 欧美在线观看视频在线| 国产精品亚洲美女av网站| 国产精品99久久久久久人| 亚洲欧美日韩精品| 国产精品美女久久久久久免费| 一区二区三区不卡视频在线观看 | 午夜宅男久久久| 国产精品草莓在线免费观看| 夜夜嗨av一区二区三区四区| 中文一区字幕| 国产精品久久国产精品99gif| 亚洲狼人精品一区二区三区| 一本久久a久久精品亚洲| 欧美精品久久久久久久免费观看 | 亚洲免费视频在线观看| 欧美一区二区三区在线| 国产在线不卡| 久久综合九色综合久99| 亚洲国产精品视频一区| 一区二区三区欧美成人| 国产精品久久久久久久久久免费| 亚洲欧洲一二三| 欧美精品日韩综合在线| 在线综合亚洲欧美在线视频| 欧美一区二区三区四区夜夜大片| 极品尤物久久久av免费看| 欧美xart系列高清| 亚洲午夜精品一区二区三区他趣| 久久精品二区亚洲w码| 1769国产精品| 欧美视频精品在线| 久久久福利视频| 亚洲日本中文字幕区 | 国产日韩精品一区二区| 久久只有精品| 在线综合亚洲欧美在线视频| 久久三级福利| 一区二区三区四区精品| 国产欧美一区二区三区沐欲| 噜噜噜躁狠狠躁狠狠精品视频| 亚洲免费av网站| 老妇喷水一区二区三区| 一个人看的www久久| 国产在线不卡| 欧美日韩大片| 美女被久久久| 欧美一二三视频| 亚洲三级电影全部在线观看高清| 久久精品夜夜夜夜久久| 一区二区免费看| 在线国产精品播放| 国产精品久久久久7777婷婷| 老鸭窝91久久精品色噜噜导演| 亚洲深夜福利网站| 亚洲精品一区在线| 欧美激情1区2区3区| 久久精品视频播放| 亚洲视频免费在线观看| 精品动漫3d一区二区三区免费| 国产精品高潮久久| 欧美日韩国产一区二区| 久久久噜噜噜久久| 欧美亚洲自偷自偷| 亚洲一区二区三区四区在线观看| 91久久久久久久久| 欧美成va人片在线观看| 久久精品亚洲热| 欧美亚洲日本国产| 亚洲一区二区在线| 中日韩在线视频| 亚洲午夜视频在线观看| 夜夜嗨av色综合久久久综合网| 亚洲成色999久久网站| 国产在线麻豆精品观看| 国产精品一区久久| 国产女人水真多18毛片18精品视频| 欧美三级视频在线| 国产精品超碰97尤物18| 国产精品乱码久久久久久| 国产精品扒开腿做爽爽爽视频| 欧美特黄a级高清免费大片a级| 欧美手机在线| 国产精品久久久久7777婷婷| 国产精品成人观看视频国产奇米| 欧美日韩免费观看一区| 国产精品福利av| 国产精品无人区| 国产亚洲欧美在线| 在线观看中文字幕不卡| 亚洲精品视频在线| 亚洲一区中文字幕在线观看| 香蕉久久一区二区不卡无毒影院 | 亚洲一区二区3| 性久久久久久久久久久久| 午夜精品免费在线| 久久国产精品久久精品国产 | 亚洲精品一区二区三| 99精品欧美一区| 午夜亚洲精品| 六月婷婷久久| 亚洲激情视频网| 宅男噜噜噜66国产日韩在线观看| 亚洲一级在线观看| 久久久久免费视频| 欧美韩日一区二区| 国产精品久久久久久影视| 国产日韩欧美黄色| 亚洲黄色在线视频| 亚洲欧美在线看| 美女视频黄免费的久久| 亚洲精品日韩久久| 欧美在线视频全部完| 蜜臀久久99精品久久久画质超高清| 欧美日韩精品免费看| 国产婷婷精品| 99热免费精品| 久久久久久噜噜噜久久久精品| 亚洲国产精品久久久久| 亚洲视频一区在线观看| 老司机精品导航| 国产精品婷婷午夜在线观看| 亚洲青涩在线| 久久久久久久性| 一本色道久久综合| 久久在线免费观看| 国产午夜精品全部视频播放| 一二三四社区欧美黄| 欧美va亚洲va日韩∨a综合色|