Purple Martians
Technical Code Descriptions
Netgame - Server Setup
Program states for server
PM_PROGRAM_STATE_SERVER_NEW_GAME
Server initializes network
Server adds new clients
PM_PROGRAM_STATE_SERVER_EXIT
Program states for server
The program states used by the server are:
PM_PROGRAM_STATE_SERVER_NEW_GAME
PM_PROGRAM_STATE_MAIN_GAME_LOOP
PM_PROGRAM_STATE_SERVER_EXIT
PM_PROGRAM_STATE_SERVER_NEW_GAME
if (state[1] == PM_PROGRAM_STATE_SERVER_NEW_GAME)
{
mLog.add(LOG_OTH_program_state, 0, "[PM_PROGRAM_STATE_SERVER_NEW_GAME]\n");
if (!mNetgame.ServerInitNetwork())
{
state[0] = PM_PROGRAM_STATE_SERVER_EXIT;
return;
}
mEventQueue.reset_fps_timer();
if (!load_and_setup_level(mLevel.play_level, 3)) state[0] = PM_PROGRAM_STATE_SERVER_EXIT;
}
Server initializes network
When a server game is started, the first thing that happens is the network initialization.
int mwNetgame::ServerInitNetwork(void)
{
mLog.log_versions();
mLog.add_fw (LOG_NET, 0, 76, 10, "+", "-", "");
mLog.add_fw (LOG_NET, 0, 76, 10, "|", " ", "Server mode started");
mLog.add_fwf(LOG_NET, 0, 76, 10, "|", " ", "Server hostname: [%s]", mLoop.local_hostname);
mLog.add_fwf(LOG_NET, 0, 76, 10, "|", " ", "Level: [%d]", mLevel.play_level);
char msg[256];
if (NetworkInit())
{
sprintf(msg, "Error: failed to initialize network");
mLog.add_fw(LOG_error, 0, 76, 10, "|", " ", msg);
mInput.m_err(msg);
return 0;
}
// open the server channel
char port[256];
sprintf(port, ":%d", server_port);
if (!(Channel = net_openchannel(NetworkDriver, port)))
{
sprintf(msg, "Error opening server channel");
mLog.add_fw(LOG_error, 0, 76, 10, "|", " ", msg);
mInput.m_err(msg);
return 0;
}
mLog.add_fw(LOG_NET, 0, 76, 10, "|", " ", "Server network initialized");
mLog.add_fw(LOG_NET, 0, 76, 10, "+", "-", "");
ima_server = 1;
return 1;
}
Server adds new clients
When the server receives a cjon packet from an unknown address, it sets up a channel and replies.
void mwPacketBuffer::add_to_rx_buffer(void)
{
char data[1024] = {0};
char address[256];
if (mNetgame.ima_server)
while (int len = net_receive(mNetgame.Channel, data, 1024, address))
{
int p = mNetgame.server_check_address(address);
if (p == -1) // unknown address
{
if (PacketRead(data, "cjon")) mNetgame.server_proc_cjon_packet(data, address); // setup channel and reply with sjon
}
....
void mwNetgame::server_proc_cjon_packet(char *data, char * address)
{
int pos = 4;
int color = mPacketBuffer.PacketGetByte(data, pos);
char hostname[16];
mPacketBuffer.PacketReadString(data, pos, hostname);
mLog.add_fwf(LOG_NET, 0, 76, 10, "+", "-", "");
mLog.add_fwf(LOG_NET, 0, 76, 10, "|", " ", "Server received join request from %s requesting color:%d", hostname, color);
int p = mPlayer.find_inactive_player();
if (p == 99) // no inactive player found
{
mLog.add_fwf(LOG_NET, 0, 76, 10, "|", " ", "Reply sent: 'SERVER FULL'");
mLog.add_fwf(LOG_NET, 0, 76, 10, "+", "-", "");
server_send_sjon_packet(address, 0, 0, 99, 0);
if (mLog.log_types[LOG_NET_session].action) session_add_entry(address, hostname, 99, 0, 1);
}
else // inactive player found, proceed with join
{
// set up channel, use the player number as the index to the channel
mwChannels[p].active = 1;
strcpy(mwChannels[p].address, address);
// try to use requested color, unless already used by another player
while (mPlayer.is_player_color_used(color)) if (++color > 15) color = 1;
mPlayer.init_player(p, 1); // full player reset
mStateHistory[p].initialize();
mItem.set_player_start_pos(p);
mPlayer.syn[p].active = 1;
mPlayer.syn[p].control_method = PM_PLAYER_CONTROL_METHOD_NETGAME_REMOTE;
mPlayer.loc[p].server_last_stak_rx_frame_num = mLoop.frame_num + 200;
sprintf(mPlayer.loc[p].hostname, "%s", hostname);
mGameMoves.add_game_move(mLoop.frame_num, PM_GAMEMOVE_TYPE_PLAYER_ACTIVE, p, color); // add game move to make client active
server_send_sjon_packet(address, mLevel.play_level, mLoop.frame_num, p, color);
if (mLog.log_types[LOG_NET_session].action) session_add_entry(address, hostname, p, 1, 0);
mLog.add_fwf(LOG_NET, 0, 76, 10, "|", " ", "Server replied with join invitation:");
mLog.add_fwf(LOG_NET_join_details, 0, 76, 10, "|", " ", "Level:[%d]", mLevel.play_level);
mLog.add_fwf(LOG_NET_join_details, 0, 76, 10, "|", " ", "Player Number:[%d]", p);
mLog.add_fwf(LOG_NET_join_details, 0, 76, 10, "|", " ", "Player Color:[%d]", color);
mLog.add_fwf(LOG_NET_join_details, 0, 76, 10, "|", " ", "Server Frame:[%d]", mLoop.frame_num);
mLog.add_fwf(LOG_NET_join_details, 0, 76, 10, "|", " ", "Server Level Sequence Num:[%d]", mPlayer.syn[0].server_lev_seq_num);
mLog.add_fwf(LOG_NET, 0, 76, 10, "+", "-", "");
}
}
PM_PROGRAM_STATE_SERVER_EXIT
if (state[1] == PM_PROGRAM_STATE_SERVER_EXIT)
{
mLog.add(LOG_OTH_program_state, 0, "[PM_PROGRAM_STATE_SERVER_EXIT]\n");
if (mGameMoves.autosave_game_on_level_quit) mGameMoves.save_gm_make_fn("autosave on level quit", 0);
mNetgame.ServerExitNetwork();
state[0] = PM_PROGRAM_STATE_MENU;
}
void mwNetgame::ServerExitNetwork(void)
{
mLog.add_header(LOG_NET, 0, 0, "Shutting down the server network");
if (Channel) net_closechannel(Channel);
Channel = NULL;
ima_server = 0;
// reset player data
for (int p=0; p < NUM_PLAYERS; p++) mPlayer.init_player(p, 1);
mPlayer.syn[0].active = 1;
if (mLog.log_types[LOG_NET_session].action) session_flush_active_at_server_exit();
}