// create a _permanent_ observer player int multi_obs_create_player(int player_num, char* name, net_addr* addr, player* pl) { // blast the player struct memset(&Net_players[player_num], 0, sizeof(net_player)); // Net_players[player_num].flags |= (NETINFO_FLAG_CONNECTED | NETINFO_FLAG_OBSERVER); // DOH!!! The lack of this caused many bugs. Net_players[player_num].flags = (NETINFO_FLAG_DO_NETWORKING | NETINFO_FLAG_OBSERVER); // memcpy(&Net_players[player_num].p_info.addr, addr, sizeof(net_addr)); Net_players[player_num].m_player = pl; // 6/3/98 -- don't set observer to update high...let it be whatever player set it at. //Net_players[player_num].p_info.options.obj_update_level = OBJ_UPDATE_HIGH; // set up the net_player structure memset(pl, 0, sizeof(player)); stuff_netplayer_info(&Net_players[player_num], addr, 0, pl); Net_players[player_num].last_heard_time = timer_get_fixed_seconds(); Net_players[player_num].reliable_socket = INVALID_SOCKET; Net_players[player_num].s_info.kick_timestamp = -1; Net_players[player_num].s_info.voice_token_timestamp = -1; Net_players[player_num].s_info.tracker_security_last = -1; Net_players[player_num].s_info.target_objnum = -1; Net_players[player_num].s_info.accum_buttons = 0; // reset the ping for this player multi_ping_reset(&Net_players[player_num].s_info.ping); // timestamp his last_full_update_time Net_players[player_num].s_info.last_full_update_time = timestamp(0); Net_players[player_num].m_player->objnum = -1; // nil his file xfer handle Net_players[player_num].s_info.xfer_handle = -1; // zero out his object update and control info sequencing data Net_players[player_num].client_cinfo_seq = 0; Net_players[player_num].client_server_seq = 0; // his kick timestamp Net_players[player_num].s_info.kick_timestamp = -1; // nil his data rate timestamp stuff Net_players[player_num].s_info.rate_stamp = -1; Net_players[player_num].s_info.rate_bytes = 0; // nil packet buffer stuff Net_players[player_num].s_info.unreliable_buffer_size = 0; Net_players[player_num].s_info.reliable_buffer_size = 0; // callsign and short callsign strcpy_s(pl->callsign, name); pilot_set_short_callsign(pl, SHORT_CALLSIGN_PIXEL_W); pl->flags |= PLAYER_FLAGS_STRUCTURE_IN_USE; Net_players[player_num].sv_bytes_sent = 0; Net_players[player_num].sv_last_pl = -1; Net_players[player_num].cl_bytes_recvd = 0; Net_players[player_num].cl_last_pl = -1; return 1; }
bool pilotfile::load_player(const char *callsign, player *_p) { // if we're a standalone server in multiplayer, just fill in some bogus values // since we don't have a pilot file if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_STANDALONE_SERVER) ) { Player->insignia_texture = -1; strcpy_s(Player->callsign, NOX("Standalone")); strcpy_s(Player->short_callsign, NOX("Standalone")); return true; } // set player ptr first thing p = _p; if ( !p ) { Assert( (Player_num >= 0) && (Player_num < MAX_PLAYERS) ); p = &Players[Player_num]; } filename = callsign; filename += ".plr"; if ( filename.size() == 4 ) { mprintf(("PLR => Invalid filename '%s'!\n", filename.c_str())); return false; } cfp = cfopen((char*)filename.c_str(), "rb", CFILE_NORMAL, CF_TYPE_PLAYERS); if ( !cfp ) { mprintf(("PLR => Unable to open '%s' for reading!\n", filename.c_str())); return false; } unsigned int plr_id = cfread_uint(cfp); if (plr_id != PLR_FILE_ID) { mprintf(("PLR => Invalid header id for '%s'!\n", filename.c_str())); plr_close(); return false; } // version, should be able to just ignore it version = cfread_ubyte(cfp); mprintf(("PLR => Loading '%s' with version %d...\n", filename.c_str(), version)); plr_reset_data(); // the point of all this: read in the PLR contents while ( !cfeof(cfp) ) { ushort section_id = cfread_ushort(cfp); uint section_size = cfread_uint(cfp); size_t start_pos = cftell(cfp); // safety, to help protect against long reads cf_set_max_read_len(cfp, section_size); try { switch (section_id) { case Section::Flags: mprintf(("PLR => Parsing: Flags...\n")); m_have_flags = true; plr_read_flags(); break; case Section::Info: mprintf(("PLR => Parsing: Info...\n")); m_have_info = true; plr_read_info(); break; case Section::Variables: mprintf(("PLR => Parsing: Variables...\n")); plr_read_variables(); break; case Section::HUD: mprintf(("PLR => Parsing: HUD...\n")); plr_read_hud(); break; case Section::Scoring: mprintf(("PLR => Parsing: Scoring...\n")); plr_read_stats(); break; case Section::ScoringMulti: mprintf(("PLR => Parsing: ScoringMulti...\n")); plr_read_stats_multi(); break; case Section::Multiplayer: mprintf(("PLR => Parsing: Multiplayer...\n")); plr_read_multiplayer(); break; case Section::Controls: mprintf(("PLR => Parsing: Controls...\n")); plr_read_controls(); break; case Section::Settings: mprintf(("PLR => Parsing: Settings...\n")); plr_read_settings(); break; default: mprintf(("PLR => Skipping unknown section 0x%04x!\n", section_id)); break; } } catch (cfile::max_read_length &msg) { // read to max section size, move to next section, discarding // extra/unknown data mprintf(("PLR => (0x%04x) %s\n", section_id, msg.what())); } catch (const char *err) { mprintf(("PLR => ERROR: %s\n", err)); plr_close(); return false; } // reset safety catch cf_set_max_read_len(cfp, 0); // skip to next section (if not already there) size_t offset_pos = (start_pos + section_size) - cftell(cfp); if (offset_pos) { cfseek(cfp, offset_pos, CF_SEEK_CUR); } } // restore the callsign into the Player structure strcpy_s(p->callsign, callsign); // restore the truncated callsign into Player structure pilot_set_short_callsign(p, SHORT_CALLSIGN_PIXEL_W); player_set_squad_bitmap(p, p->m_squad_filename, true); hud_squadmsg_save_keys(); // set last pilot os_config_write_string(NULL, "LastPlayer", (char*)callsign); mprintf(("PLR => Loading complete!\n")); // cleanup and return plr_close(); return true; }