From d17521c8b9085a91d08fecfd0b51bbbf7b1dccac Mon Sep 17 00:00:00 2001 From: "milo24x7@gmail.com" Date: Sun, 7 Jul 2013 22:08:49 +0000 Subject: Updated open source license declaration and fixed some formatting issues. --- Stars45/NetLobbyServer.cpp | 2746 ++++++++++++++++++++++---------------------- 1 file changed, 1385 insertions(+), 1361 deletions(-) (limited to 'Stars45/NetLobbyServer.cpp') diff --git a/Stars45/NetLobbyServer.cpp b/Stars45/NetLobbyServer.cpp index 13ba07b..c439560 100644 --- a/Stars45/NetLobbyServer.cpp +++ b/Stars45/NetLobbyServer.cpp @@ -1,1361 +1,1385 @@ -/* Project Starshatter 4.5 - Destroyer Studios LLC - Copyright © 1997-2004. All Rights Reserved. - - SUBSYSTEM: Stars.exe - FILE: NetLobbyServer.cpp - AUTHOR: John DiCamillo - - - OVERVIEW - ======== - NetLink Engine for Multiplayer Lobby -*/ - -#include "MemDebug.h" -#include "NetLobbyServer.h" -#include "NetServerConfig.h" -#include "NetClientConfig.h" -#include "NetBrokerClient.h" -#include "NetAuth.h" -#include "NetChat.h" -#include "NetUser.h" -#include "Campaign.h" -#include "Mission.h" -#include "StarServer.h" -#include "Starshatter.h" -#include "StarServer.h" -#include "ShipDesign.h" -#include "Sim.h" - -#include "ModConfig.h" -#include "ModInfo.h" - -#include "NetGame.h" -#include "NetPlayer.h" -#include "NetUtil.h" - -#include "NetPeer.h" -#include "NetLayer.h" -#include "NetHost.h" -#include "NetMsg.h" - -#include "MachineInfo.h" -#include "Game.h" -#include "FormatUtil.h" - -extern const char* versionInfo; - -// +-------------------------------------------------------------------+ - -static NetLobbyServer* net_lobby_server = 0; - -NetLobbyServer::NetLobbyServer() -: announce_time(0), server_config(0), motd_index(1) -{ - status = NetServerInfo::LOBBY; - server_name = Text("Starshatter NetLobbyServer ") + versionInfo; - start_time = NetLayer::GetUTC(); - - selected_mission = 0; - - WORD server_port = 11100; - - server_config = NetServerConfig::GetInstance(); - if (server_config) { - server_name = server_config->Name(); - server_port = server_config->GetLobbyPort(); - server_mission = server_config->GetMission(); - - NetAuth::SetAuthLevel(server_config->GetAuthLevel()); - - server_addr = NetAddr(NetHost().Address().IPAddr(), server_port); - link = new(__FILE__,__LINE__) NetLink(server_addr); - } - - LoadMOTD(); - - StarServer* star_server = StarServer::GetInstance(); - DWORD mission_id = 0; - - // only one mission: - if (star_server && server_mission.length() > 0) { - NetCampaignInfo* c = new(__FILE__,__LINE__) NetCampaignInfo; - c->id = Campaign::MULTIPLAYER_MISSIONS; - c->name = "Persistent Multiplayer"; - campaigns.append(c); - - ListIter c_iter = Campaign::GetAllCampaigns(); - while (++c_iter && !mission_id) { - Campaign* campaign = c_iter.value(); - - if (campaign->GetCampaignId() == Campaign::MULTIPLAYER_MISSIONS) { - ListIter m_iter = campaign->GetMissionList(); - while (++m_iter && !mission_id) { - MissionInfo* m = m_iter.value(); - - if (m->script == server_mission) { - c->missions.append(m); - mission_id = (Campaign::MULTIPLAYER_MISSIONS << NET_CAMPAIGN_SHIFT) + m->id; - - SelectMission(mission_id); - star_server->SetGameMode(StarServer::LOAD_MODE); - - // lock in mission: - SetStatus(NetServerInfo::PERSISTENT); - } - } - } - } - } - - // player host may select mission: - if (!mission_id) { - campaigns.destroy(); - - ListIter c_iter = Campaign::GetAllCampaigns(); - while (++c_iter) { - Campaign* campaign = c_iter.value(); - - if (campaign->GetCampaignId() >= Campaign::MULTIPLAYER_MISSIONS) { - NetCampaignInfo* c = new(__FILE__,__LINE__) NetCampaignInfo; - c->id = campaign->GetCampaignId(); - c->name = campaign->Name(); - campaigns.append(c); - - ListIter m_iter = campaign->GetMissionList(); - while (++m_iter) { - MissionInfo* m = m_iter.value(); - c->missions.append(m); - } - } - } - } - - ModConfig* config = ModConfig::GetInstance(); - List& mods = config->GetModInfoList(); - - server_mods.clear(); - server_mods.append(mods); - - net_lobby_server = this; -} - -NetLobbyServer::~NetLobbyServer() -{ - ListIter iter = users; - while (++iter) { - NetUser* u = iter.value(); - SendData(u, NET_LOBBY_EXIT, Text()); - ExecFrame(); - } - - Sleep(500); - - unit_map.destroy(); - chat_log.destroy(); - users.destroy(); - motd.destroy(); - - if (net_lobby_server == this) - net_lobby_server = 0; -} - -NetLobbyServer* -NetLobbyServer::GetInstance() -{ - return net_lobby_server; -} - -// +--------------------------------------------------------------------+ - -void -NetLobbyServer::LoadMOTD() -{ - motd.destroy(); - - FILE* f; - fopen_s(&f, "motd.txt", "r"); - - if (f) { - char line[256]; - - while (fgets(line, 256, f)) { - int n = strlen(line) - 1; - - while (n >= 0 && isspace(line[n])) - line[n--] = 0; - - motd.append(new(__FILE__,__LINE__) Text(line)); - } - } -} - -void -NetLobbyServer::SendMOTD(NetUser* user) -{ - if (motd.size() < 1) return; - - char buffer[512]; - - for (int i = 0; i < motd.size(); i++) { - Text* line = motd[i]; - - sprintf_s(buffer, "id %d user \" \" msg \"%s\"", - motd_index++, line->data()); - - SendData(user, NET_LOBBY_CHAT, buffer); - } - - sprintf_s(buffer, "id %d user \" \" msg \" \"", motd_index++); - SendData(user, NET_LOBBY_CHAT, buffer); -} - -void -NetLobbyServer::SendMods(NetUser* user) -{ - char buffer[300]; - - ModConfig* config = ModConfig::GetInstance(); - List& mods = config->GetModInfoList(); - - if (mods.size() < 1) return; - - for (int i = 0; i < mods.size(); i++) { - ModInfo* info = mods[i]; - - sprintf_s(buffer, "id %d user \"Enabled Mods:\" msg \"%d. '%s' ", - motd_index++, i+1, info->Name().data()); - - Text msg = buffer; - - if (info->Version().length() > 0) { - msg += "version "; - msg += info->Version().data(); - } - - if (info->URL().length() > 0) { - msg += " - "; - msg += info->URL().data(); - } - - msg += "\""; - - SendData(user, NET_LOBBY_CHAT, msg); - } - - sprintf_s(buffer, "id %d user \" \" msg \" \"", motd_index++); - SendData(user, NET_LOBBY_CHAT, buffer); -} - -// +--------------------------------------------------------------------+ - -void -NetLobbyServer::ExecFrame() -{ - NetLobby::ExecFrame(); - - if (announce_time == 0 || Game::RealTime() - announce_time > 200000) { - GameOn(); - announce_time = Game::RealTime(); - } - - if (GetStatus() == NetServerInfo::BRIEFING) { - NetGame* net_game = NetGame::GetInstance(); - - if (net_game && net_game->NumPlayers() > 0) { - SetStatus(NetServerInfo::ACTIVE); - } - } - - StarServer* star_server = StarServer::GetInstance(); - DWORD mission_id = 0; - - // restart persistent mission? - if (star_server && - star_server->GetGameMode() == StarServer::MENU_MODE && - server_mission.length() > 0) { - - NetCampaignInfo* c = campaigns.last(); - - if (!c || c->name != "Persistent Multiplayer") { - c = new(__FILE__,__LINE__) NetCampaignInfo; - c->id = Campaign::MULTIPLAYER_MISSIONS; - c->name = "Persistent Multiplayer"; - campaigns.append(c); - } - else { - c->missions.clear(); - } - - ListIter c_iter = Campaign::GetAllCampaigns(); - while (++c_iter && !mission_id) { - Campaign* campaign = c_iter.value(); - - if (campaign->GetCampaignId() == Campaign::MULTIPLAYER_MISSIONS) { - ListIter m_iter = campaign->GetMissionList(); - while (++m_iter && !mission_id) { - MissionInfo* m = m_iter.value(); - - if (m->script == server_mission) { - c->missions.append(m); - mission_id = (Campaign::MULTIPLAYER_MISSIONS << NET_CAMPAIGN_SHIFT) + m->id; - - // unlock old mission: - SetStatus(NetServerInfo::LOBBY); - - SelectMission(mission_id); - - if (star_server->GetGameMode() == StarServer::MENU_MODE) { - star_server->SetGameMode(StarServer::LOAD_MODE); - } - - // lock in new mission: - SetStatus(NetServerInfo::PERSISTENT); - } - } - } - } - } - - CheckSessions(); -} - -// +-------------------------------------------------------------------+ - -void -NetLobbyServer::SendData(NetUser* dst, int type, Text msg) -{ - if (link && dst && type > 0 && type < 255) { - if (msg.length()) - link->SendMessage(dst->GetNetID(), (BYTE) type, msg.data(), msg.length(), NetMsg::RELIABLE); - else - link->SendMessage(dst->GetNetID(), (BYTE) type, 0, 0, NetMsg::RELIABLE); - } -} - -// +-------------------------------------------------------------------+ - -void -NetLobbyServer::CheckSessions() -{ - if (!link) - return; - - bool dropped = false; - - ListIter u_iter = users; - while (++u_iter) { - NetUser* u = u_iter.value(); - NetPeer* p = link->FindPeer(u->GetNetID()); - - if (p && (NetLayer::GetUTC() - p->LastReceiveTime()) > NET_DISCONNECT_TIME) { - // check game peer for activity: - NetGame* game = NetGame::GetInstance(); - NetPlayer* player = 0; - NetPeer* p2 = 0; - - if (game) { - player = game->FindPlayerByName(u->Name()); - - if (player) { - p2 = game->GetPeer(player); - - if (p2 && (NetLayer::GetUTC() - p2->LastReceiveTime()) < NET_DISCONNECT_TIME) { - p->SetLastReceiveTime(p2->LastReceiveTime()); - continue; - } - } - else { - ::Print("NetLobbyServer::CheckSessions() Could not find player for '%s'\n", u->Name().data()); - } - } - else { - ::Print("NetLobbyServer::CheckSessions() Could not find net game for '%s'\n", u->Name().data()); - } - - // announce drop: - char timestr[64]; - FormatTime(timestr, Game::RealTime()/1000); - Print("NetLobbyServer: Dropped inactive connection '%s' %s\n", - u->Name().data(), timestr); - - if (u->IsHost()) { - Print(" User was host - ending net game.\n"); - GameStop(); - } - - u_iter.removeItem(); // first remove user from list - NetLobby::UnmapUnit(u->Name()); // then unmap unit - delete u; // now it is safe to discard the inactive user - - dropped = true; - } - } - - if (dropped) { - SendUsers(); - SendUnits(); - } -} - -// +-------------------------------------------------------------------+ - -void -NetLobbyServer::GameStart() -{ - if (status < NetServerInfo::ACTIVE) { - SetStatus(NetServerInfo::BRIEFING); - - if (Starshatter::GetInstance()) { - Starshatter::GetInstance()->SetGameMode(Starshatter::PREP_MODE); - } - else { - StarServer* s = StarServer::GetInstance(); - if (s && s->GetGameMode() == StarServer::MENU_MODE) { - s->SetGameMode(StarServer::LOAD_MODE); - } - } - } -} - -void -NetLobbyServer::GameStop() -{ - if (GetStatus() != NetServerInfo::PERSISTENT) { - SetStatus(NetServerInfo::LOBBY); - - StarServer* s = StarServer::GetInstance(); - if (s && s->GetGameMode() != StarServer::MENU_MODE) { - s->SetGameMode(StarServer::MENU_MODE); - } - } -} - -// +-------------------------------------------------------------------+ - -void -NetLobbyServer::BanUser(NetUser* user) -{ - if (user && !user->IsHost()) { - ::Print("NetLobbyServer::BanUser name '%s' addr %d.%d.%d.%d\n", - user->Name().data(), - user->GetAddress().B1(), - user->GetAddress().B2(), - user->GetAddress().B3(), - user->GetAddress().B4()); - - SendData(user, NET_LOBBY_EXIT, Text()); - - if (server_config) - server_config->BanUser(user); - - DelUser(user); - } -} - -void -NetLobbyServer::AddUser(NetUser* user) -{ - if (server_config && server_config->IsUserBanned(user)) { - delete user; - return; - } - - NetLobby::AddUser(user); - SendUsers(); -} - -void -NetLobbyServer::DelUser(NetUser* user) -{ - NetLobby::DelUser(user); - SendUsers(); -} - -void -NetLobbyServer::SendUsers() -{ - Text content; - - ListIter u_iter = users; - while (++u_iter) { - NetUser* u = u_iter.value(); - content += u->GetDescription(); - } - - u_iter.reset(); - - while (++u_iter) { - NetUser* u = u_iter.value(); - SendData(u, NET_LOBBY_USER_LIST, content); - } -} - -// +-------------------------------------------------------------------+ - -void -NetLobbyServer::RequestAuth(NetUser* user) -{ - if (user) { - Text request = NetAuth::CreateAuthRequest(user); - - if (request.length() > 0) - SendData(user, NET_LOBBY_AUTH_USER, request); - } -} - -// +-------------------------------------------------------------------+ - -void -NetLobbyServer::AddChat(NetUser* user, const char* msg, bool route) -{ - NetChatEntry* entry = 0; - - if (user && msg && *msg) { - bool msg_ok = false; - const char* p = msg; - - while (*p && !msg_ok) { - if (!isspace(*p++)) - msg_ok = true; - } - - if (msg_ok) { - entry = new(__FILE__,__LINE__) NetChatEntry(user, msg); - - chat_log.append(entry); - - // forward to all clients: - if (users.size()) { - char buffer[768]; - char msg_buf[256]; - char usr_buf[256]; - - // safe quotes uses a static buffer, - // so make sure to save copies of the - // results when using more than one in - // a function call... - - strcpy_s(msg_buf, SafeQuotes(msg)); - strcpy_s(usr_buf, SafeQuotes(user->Name())); - - sprintf_s(buffer, "id %d user \"%s\" msg \"%s\"", - entry->GetID(), usr_buf, msg_buf); - - ListIter iter = users; - while (++iter) { - NetUser* u = iter.value(); - SendData(u, NET_LOBBY_CHAT, buffer); - } - - if (route) { - // send to active game: - NetUtil::SendChat(0xffff, usr_buf, msg_buf); - } - } - } - } -} - -void -NetLobbyServer::ClearChat() -{ - NetLobby::ClearChat(); -} - -void -NetLobbyServer::SaveChat() -{ - FILE* f; - fopen_s(&f, "chat.txt", "w"); - if (f) { - for (int i = 0; i < chat_log.size(); i++) { - NetChatEntry* c = chat_log[i]; - fprintf(f, "%08x [%s] %s\n", - c->GetTime(), - c->GetUser().data(), - c->GetMessage().data()); - } - - fclose(f); - } -} - -// +-------------------------------------------------------------------+ - -void -NetLobbyServer::SelectMission(DWORD id) -{ - if (GetStatus() == NetServerInfo::PERSISTENT) - return; - - NetLobby::SelectMission(id); - - // inform all users of the selection: - char buffer[32]; - sprintf_s(buffer, "m_id 0x%08x", selected_mission); - - ListIter iter = users; - while (++iter) { - NetUser* u = iter.value(); - SendData(u, NET_LOBBY_MISSION_SELECT, buffer); - } -} - -// +-------------------------------------------------------------------+ - -List& -NetLobbyServer::GetUnitMap() -{ - if (!mission) { - unit_map.destroy(); - return unit_map; - } - - List units; - ListIter iter = mission->GetElements(); - int i = 0; - - Sim* sim = Sim::GetSim(); - if (sim && sim->GetElements().size() > 0) - iter = sim->GetMissionElements(); - - // create new entries for the playable elements in the mission or simulation: - while (++iter) { - MissionElement* elem = iter.value(); - - if (elem->IsPlayable()) { - NetUnitEntry* u = 0; - if (elem->Count() == 1) { - u = new(__FILE__,__LINE__) NetUnitEntry(elem, 0); - u->SetLives(elem->RespawnCount() + 1); - u->SetMissionRole(elem->MissionRole()); - u->SetIFF(elem->GetIFF()); - - if (elem->GetDesign()) - u->SetDesign(elem->GetDesign()->name); - - if (elem->Ships().size() > 0) { - MissionShip* s = elem->Ships()[0]; - u->SetIntegrity((int) s->Integrity()); - } - units.append(u); - } - else { - for (int i = 0; i < elem->Count(); i++) { - u = new(__FILE__,__LINE__) NetUnitEntry(elem, i+1); - u->SetMissionRole(elem->MissionRole()); - u->SetIFF(elem->GetIFF()); - - if (elem->GetDesign()) - u->SetDesign(elem->GetDesign()->name); - - if (elem->Ships().size() > i) { - MissionShip* s = elem->Ships()[i]; - u->SetLives(s->Respawns() + 1); - u->SetIntegrity((int) s->Integrity()); - } - units.append(u); - } - } - } - } - - // match new entries with any existing map entries: - if (unit_map.size()) { - for (i = 0; i < units.size(); i++) { - NetUnitEntry* e_new = units[i]; - NetUnitEntry* e_old = unit_map.find(e_new); - - if (e_old) { - e_new->SetUserName(e_old->GetUserName()); - e_new->SetLock(e_old->GetLocked()); - } - } - } - - // rewrite the unit map with the new entries: - ClearUnitMap(); - for (i = 0; i < units.size(); i++) { - unit_map.append(units[i]); - } - - return unit_map; -} - -void -NetLobbyServer::MapUnit(int n, const char* user, bool lock) -{ - NetLobby::MapUnit(n, user, lock); - - Text reply; - - ListIter map_iter = GetUnitMap(); - while (++map_iter) { - NetUnitEntry* unit = map_iter.value(); - reply += unit->GetDescription(); - } - - ListIter u_iter = users; - while (++u_iter) { - NetUser* u = u_iter.value(); - SendData(u, NET_LOBBY_UNIT_LIST, reply); - } -} - -void -NetLobbyServer::UnmapUnit(const char* user) -{ - NetLobby::UnmapUnit(user); - - Text reply; - - ListIter map_iter = GetUnitMap(); - while (++map_iter) { - NetUnitEntry* unit = map_iter.value(); - reply += unit->GetDescription(); - } - - ListIter u_iter = users; - while (++u_iter) { - NetUser* u = u_iter.value(); - SendData(u, NET_LOBBY_UNIT_LIST, reply); - } -} - -void -NetLobbyServer::SendUnits() -{ - Text content; - - ListIter map_iter = GetUnitMap(); - while (++map_iter) { - NetUnitEntry* unit = map_iter.value(); - content += unit->GetDescription(); - } - - ListIter u_iter = users; - while (++u_iter) { - NetUser* u = u_iter.value(); - SendData(u, NET_LOBBY_UNIT_LIST, content); - } -} - -// +-------------------------------------------------------------------+ - -Text -NetLobbyServer::Serialize(Mission* m, NetUser* user) -{ - Text s; - - if (!m || !user) - return s; - - NetUnitEntry* unit = 0; - - ListIter u_iter = GetUnitMap(); - while (++u_iter && !unit) { - NetUnitEntry* u = u_iter.value(); - if (u->GetUserName() == user->Name()) - unit = u; - } - - if (unit) - s = m->Serialize(unit->GetElemName(), unit->GetIndex()); - - return s; -} - -Mission* -NetLobbyServer::GetSelectedMission() -{ - if (mission) { - Text content = Serialize(mission, GetLocalUser()); - Campaign* c = Campaign::SelectCampaign("Multiplayer Missions"); - - if (c) { - c->LoadNetMission(99999, content.data()); - return c->GetMission(99999); - } - } - - return mission; -} - -// +-------------------------------------------------------------------+ - -void -NetLobbyServer::GameOn() -{ - NetHost host; - const char* type = "Starshatter"; - const char* password = "No"; - char address[32]; - - strcpy_s(address, "0"); - - if (server_config) { - if (server_config->GetGameType() == NetServerConfig::NET_GAME_PRIVATE) - return; - - if (server_config->GetGameType() == NetServerConfig::NET_GAME_LAN) { - type = "Starshatter-LAN"; - sprintf_s(address, "%d.%d.%d.%d", - host.Address().B1(), - host.Address().B2(), - host.Address().B3(), - host.Address().B4()); - } - else { - type = "Starshatter"; - sprintf_s(address, "0.0.0.0"); - } - - if (server_config->GetGamePass().length() > 0) - password = "Yes"; - } - - NetBrokerClient::GameOn(server_name, - type, - address, - server_addr.Port(), - password); -} - -void -NetLobbyServer::GameOff() -{ -} - -// +-------------------------------------------------------------------+ - -void -NetLobbyServer::DoPing(NetPeer* peer, Text s) -{ } - -void -NetLobbyServer::DoServerInfo(NetPeer* peer, Text s) -{ - if (peer && peer->NetID()) { - char buffer[1024]; - WORD gameport = 11101; - - if (server_config) - gameport = server_config->GetGamePort(); - - sprintf_s(buffer, "info \"%s\" version \"%s\" mode %d users %d host %s port %d", - MachineInfo::GetShortDescription(), - versionInfo, - GetStatus(), - NumUsers(), - HasHost() ? "true" : "false", - gameport); - - link->SendMessage(peer->NetID(), (BYTE) NET_LOBBY_SERVER_INFO, buffer, strlen(buffer), NetMsg::RELIABLE); - } -} - -void -NetLobbyServer::DoServerMods(NetPeer* peer, Text s) -{ - if (peer && peer->NetID()) { - Text response; - ModConfig* config = ModConfig::GetInstance(); - List& mods = config->GetModInfoList(); - ListIter mod_iter = mods; - - char buffer[32]; - sprintf_s(buffer, "num %d ", mods.size()); - response += buffer; - - while (++mod_iter) { - ModInfo* info = mod_iter.value(); - - response += "mod \""; - response += info->Name(); - response += "\" url \""; - response += info->URL(); - response += "\" ver \""; - response += info->Version(); - response += "\" "; - } - - link->SendMessage(peer->NetID(), (BYTE) NET_LOBBY_SERVER_MODS, response, response.length(), NetMsg::RELIABLE); - } -} - -// +-------------------------------------------------------------------+ - -void -NetLobbyServer::DoLogin(NetPeer* peer, Text msg) -{ - List params; - ParseMsg(msg, params); - - Text name; - Text pass; - Text host; - Text gamepass; - Text signature; - Text squadron; - Text version; - int rank = 0; - int flight_time = 0; - int missions = 0; - int kills = 0; - int losses = 0; - - for (int i = 0; i < params.size(); i++) { - NetLobbyParam* p = params[i]; - - int num = 0; - sscanf_s(p->value, "%d", &num); - - if (p->name == "name") - name = p->value; - - else if (p->name == "pass") - pass = p->value; - - else if (p->name == "gamepass") - gamepass = p->value; - - else if (p->name == "host") - host = p->value; - - else if (p->name == "sig") - signature = p->value; - - else if (p->name == "squad") - squadron = p->value; - - else if (p->name == "version") - version = p->value; - - else if (p->name == "rank") - rank = num; - - else if (p->name == "time") - flight_time = num; - - else if (p->name == "miss") - missions = num; - - else if (p->name == "kill") - kills = num; - - else if (p->name == "loss") - losses = num; - } - - params.destroy(); - - // first check the game version: - if (version != versionInfo) { - Print("NetLobbyServer - user '%s' tried to login with invalid game version '%s'\n", - name.data(), version.data()); - - return; - } - - // next check the game password: - if (server_config && server_config->GetGamePass().length() > 0) { - if (gamepass != server_config->GetGamePass()) { - Print("NetLobbyServer - user '%s' tried to login with invalid game password '%s'\n", - name.data(), gamepass.data()); - - return; - } - } - - // now try to log the user in: - NetUser* pre_existing = FindUserByName(name); - - // is user already logged in? - if (pre_existing) { - if (pre_existing->Pass() == pass && - pre_existing->GetAddress().IPAddr() == peer->Address().IPAddr()) { - } - } - - // otherwise, create a new user: - else { - NetUser* user = new(__FILE__,__LINE__) NetUser(name); - user->SetAddress(peer->Address()); - user->SetNetID(peer->NetID()); - user->SetPass(pass); - user->SetSignature(signature); - user->SetSquadron(squadron); - user->SetRank(rank); - user->SetFlightTime(flight_time); - user->SetMissions(missions); - user->SetKills(kills); - user->SetLosses(losses); - - if (host == "true" && !HasHost()) - user->SetHost(true); - - AddUser(user); - RequestAuth(user); - SendMOTD(user); - SendMods(user); - } -} - -void -NetLobbyServer::DoLogout(NetPeer* peer, Text msg) -{ - NetUser* user = FindUserByNetID(peer->NetID()); - - if (user) { - if (user->IsHost()) - GameStop(); - - DelUser(user); - } -} - -void -NetLobbyServer::DoUserAuth(NetPeer* peer, Text msg) -{ - NetUser* user = FindUserByNetID(peer->NetID()); - - if (user) { - NetAuth::AuthUser(user, msg); - - if (!user->IsAuthOK()) { - char buffer[256]; - - sprintf_s(buffer, "id %d user \"SERVER\" msg \"**********\"", motd_index++); - SendData(user, NET_LOBBY_CHAT, buffer); - - sprintf_s(buffer, "id %d user \"SERVER\" msg \"*** Your game configuration does not match the server.\"", motd_index++); - SendData(user, NET_LOBBY_CHAT, buffer); - - if (server_mods.size() > 0) { - sprintf_s(buffer, "id %d user \"SERVER\" msg \"*** Please check that you have the proper mods deployed in\"", motd_index++); - SendData(user, NET_LOBBY_CHAT, buffer); - sprintf_s(buffer, "id %d user \"SERVER\" msg \"*** the order shown above.\"", motd_index++); - SendData(user, NET_LOBBY_CHAT, buffer); - } - - else { - sprintf_s(buffer, "id %d user \"SERVER\" msg \"*** Please verify that you have no mods deployed.\"", motd_index++); - SendData(user, NET_LOBBY_CHAT, buffer); - } - - sprintf_s(buffer, "id %d user \"SERVER\" msg \"*** You will not be permitted to join the game with an invalid\"", motd_index++); - SendData(user, NET_LOBBY_CHAT, buffer); - - sprintf_s(buffer, "id %d user \"SERVER\" msg \"*** configuration. You may reconnect to this server after you\"", motd_index++); - SendData(user, NET_LOBBY_CHAT, buffer); - - sprintf_s(buffer, "id %d user \"SERVER\" msg \"*** have corrected your mod configuration.\"", motd_index++); - SendData(user, NET_LOBBY_CHAT, buffer); - - sprintf_s(buffer, "id %d user \"SERVER\" msg \"**********\"", motd_index++); - SendData(user, NET_LOBBY_CHAT, buffer); - - sprintf_s(buffer, "id %d user \" \" msg \" \"", motd_index++); - SendData(user, NET_LOBBY_CHAT, buffer); - } - } -} - -void -NetLobbyServer::DoChat(NetPeer* peer, Text msg) -{ - List params; - ParseMsg(msg, params); - - Text chat_msg; - - for (int i = 0; i < params.size(); i++) { - NetLobbyParam* p = params[i]; - - int num = 0; - sscanf_s(p->value, "%d", &num); - - if (p->name == "msg") { - chat_msg = p->value; - } - } - - params.destroy(); - - NetUser* user = FindUserByNetID(peer->NetID()); - - if (user) { - // receive chat from client: - if (chat_msg.length()) { - AddChat(user, chat_msg); - } - - // request for chat log: - else { - ListIter iter = chat_log; - while (++iter) { - NetChatEntry* entry = iter.value(); - - char buffer[512]; - char msg_buf[256]; - char usr_buf[256]; - - // safe quotes uses a static buffer, - // so make sure to save copies of the - // results when using more than one in - // a function call... - - strcpy_s(msg_buf, SafeQuotes(entry->GetMessage())); - strcpy_s(usr_buf, SafeQuotes(entry->GetUser())); - - sprintf_s(buffer, "id %d user \"%s\" msg \"%s\"", - entry->GetID(), usr_buf, msg_buf); - - SendData(user, NET_LOBBY_CHAT, buffer); - } - } - } -} - -void -NetLobbyServer::DoUserList(NetPeer* peer, Text msg) -{ - NetUser* user = FindUserByNetID(peer->NetID()); - - if (user) { - Text content; - - if (local_user) - content += local_user->GetDescription(); - - ListIter iter = users; - while (++iter) { - NetUser* u = iter.value(); - content += u->GetDescription(); - } - - SendData(user, NET_LOBBY_USER_LIST, content); - } -} - -void -NetLobbyServer::DoBanUser(NetPeer* peer, Text msg) -{ - NetUser* user = FindUserByNetID(peer->NetID()); - - if (user && user->IsHost() && user->IsAuthOK()) { - List params; - ParseMsg(msg, params); - - if (params.size() > 0) { - NetLobbyParam* p = params[0]; - - if (p->name == "user") { - Text user_name = p->value; - - NetUser* u = FindUserByName(user_name); - if (u && !u->IsHost()) - BanUser(u); - } - } - - params.destroy(); - } -} - -void -NetLobbyServer::DoMissionList(NetPeer* peer, Text msg) -{ - NetUser* user = FindUserByNetID(peer->NetID()); - - if (user) { - Text reply; - char buffer[4096]; - - ListIter c_iter = Campaign::GetAllCampaigns(); - while (++c_iter) { - Campaign* c = c_iter.value(); - - if (c->GetCampaignId() >= Campaign::MULTIPLAYER_MISSIONS) { - sprintf_s(buffer, "c_id 0x%08x c_name \"%s\" ", - c->GetCampaignId(), - SafeQuotes(c->Name())); - - reply += buffer; - } - } - - c_iter.reset(); - - while (++c_iter) { - Campaign* c = c_iter.value(); - - if (c->GetCampaignId() >= Campaign::MULTIPLAYER_MISSIONS) { - - ListIter m_iter = c->GetMissionList(); - while (++m_iter) { - MissionInfo* m = m_iter.value(); - - int mission_id = (c->GetCampaignId() << NET_CAMPAIGN_SHIFT) + m->id; - - sprintf_s(buffer, "m_id 0x%08x ", mission_id); - reply += buffer; - - reply += "m_name \""; - reply += SafeQuotes(m->name); - - // long version of safe quotes: - int n = 0; - const char* s = m->description.data(); - - while (*s && n < 4090) { - if (*s == '"') { - buffer[n++] = '\''; - s++; - } - else if (*s == '\n') { - buffer[n++] = '\\'; - buffer[n++] = 'n'; - s++; - } - else if (*s == '\t') { - buffer[n++] = '\\'; - buffer[n++] = 't'; - s++; - } - else { - buffer[n++] = *s++; - } - } - - // don't forget the null terminator! - buffer[n] = 0; - - reply += "\" m_desc \""; - reply += buffer; - - reply += "\" "; - } - } - } - - SendData(user, NET_LOBBY_MISSION_LIST, reply); - - sprintf_s(buffer, "m_id 0x%08x", selected_mission); - SendData(user, NET_LOBBY_MISSION_SELECT, buffer); - } -} - -void -NetLobbyServer::DoMissionSelect(NetPeer* peer, Text msg) -{ - if (GetStatus() == NetServerInfo::PERSISTENT) - return; - - NetUser* user = FindUserByNetID(peer->NetID()); - - if (user && user->IsHost() && user->IsAuthOK()) { - List params; - ParseMsg(msg, params); - - for (int i = 0; i < params.size(); i++) { - NetLobbyParam* p = params[i]; - - int num = 0; - sscanf_s(p->value, "0x%x", &num); - - if (p->name == "m_id") { - SelectMission(num); - } - } - - params.destroy(); - } -} - -void -NetLobbyServer::DoMissionData(NetPeer* peer, Text msg) -{ - NetUser* user = FindUserByNetID(peer->NetID()); - - if (user && mission && user->IsAuthOK()) { - Text reply = Serialize(mission, user); - SendData(user, NET_LOBBY_MISSION_DATA, reply); - - FILE* f = ::fopen("multi_mission_send.def", "w"); - if (f) { - ::fwrite(reply.data(), reply.length(), 1, f); - ::fclose(f); - } - } -} - -void -NetLobbyServer::DoUnitList(NetPeer* peer, Text msg) -{ - NetUser* user = FindUserByNetID(peer->NetID()); - - if (user && unit_map.size() && user->IsAuthOK()) { - Text reply; - - ListIter iter = GetUnitMap(); - while (++iter) { - NetUnitEntry* unit = iter.value(); - reply += unit->GetDescription(); - } - - SendData(user, NET_LOBBY_UNIT_LIST, reply); - } -} - -void -NetLobbyServer::DoMapUnit(NetPeer* peer, Text msg) -{ - NetUser* user = FindUserByNetID(peer->NetID()); - - if (user && unit_map.size() && user->IsAuthOK()) { - List params; - ParseMsg(msg, params); - - int id = 0; - bool lock = false; - Text user_name; - - for (int i = 0; i < params.size(); i++) { - NetLobbyParam* p = params[i]; - - if (p->name == "id") { - sscanf_s(p->value, "%d", &id); - } - - else if (p->name == "user") { - user_name = p->value; - } - - else if (p->name == "lock") { - lock = (p->value == "true") ? true : false; - } - } - - params.destroy(); - - MapUnit(id, user_name, lock); - } -} - -void -NetLobbyServer::DoGameStart(NetPeer* peer, Text msg) -{ - GameStart(); -} - -void -NetLobbyServer::DoGameStop(NetPeer* peer, Text msg) -{ - NetUser* user = FindUserByNetID(peer->NetID()); - - if (user && user->IsHost() && user->IsAuthOK()) - GameStop(); -} +/* Starshatter OpenSource Distribution + Copyright (c) 1997-2004, Destroyer Studios LLC. + All Rights Reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name "Destroyer Studios" nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + SUBSYSTEM: Stars.exe + FILE: NetLobbyServer.cpp + AUTHOR: John DiCamillo + + + OVERVIEW + ======== + NetLink Engine for Multiplayer Lobby +*/ + +#include "MemDebug.h" +#include "NetLobbyServer.h" +#include "NetServerConfig.h" +#include "NetClientConfig.h" +#include "NetBrokerClient.h" +#include "NetAuth.h" +#include "NetChat.h" +#include "NetUser.h" +#include "Campaign.h" +#include "Mission.h" +#include "StarServer.h" +#include "Starshatter.h" +#include "StarServer.h" +#include "ShipDesign.h" +#include "Sim.h" + +#include "ModConfig.h" +#include "ModInfo.h" + +#include "NetGame.h" +#include "NetPlayer.h" +#include "NetUtil.h" + +#include "NetPeer.h" +#include "NetLayer.h" +#include "NetHost.h" +#include "NetMsg.h" + +#include "MachineInfo.h" +#include "Game.h" +#include "FormatUtil.h" + +extern const char* versionInfo; + +// +-------------------------------------------------------------------+ + +static NetLobbyServer* net_lobby_server = 0; + +NetLobbyServer::NetLobbyServer() +: announce_time(0), server_config(0), motd_index(1) +{ + status = NetServerInfo::LOBBY; + server_name = Text("Starshatter NetLobbyServer ") + versionInfo; + start_time = NetLayer::GetUTC(); + + selected_mission = 0; + + WORD server_port = 11100; + + server_config = NetServerConfig::GetInstance(); + if (server_config) { + server_name = server_config->Name(); + server_port = server_config->GetLobbyPort(); + server_mission = server_config->GetMission(); + + NetAuth::SetAuthLevel(server_config->GetAuthLevel()); + + server_addr = NetAddr(NetHost().Address().IPAddr(), server_port); + link = new(__FILE__,__LINE__) NetLink(server_addr); + } + + LoadMOTD(); + + StarServer* star_server = StarServer::GetInstance(); + DWORD mission_id = 0; + + // only one mission: + if (star_server && server_mission.length() > 0) { + NetCampaignInfo* c = new(__FILE__,__LINE__) NetCampaignInfo; + c->id = Campaign::MULTIPLAYER_MISSIONS; + c->name = "Persistent Multiplayer"; + campaigns.append(c); + + ListIter c_iter = Campaign::GetAllCampaigns(); + while (++c_iter && !mission_id) { + Campaign* campaign = c_iter.value(); + + if (campaign->GetCampaignId() == Campaign::MULTIPLAYER_MISSIONS) { + ListIter m_iter = campaign->GetMissionList(); + while (++m_iter && !mission_id) { + MissionInfo* m = m_iter.value(); + + if (m->script == server_mission) { + c->missions.append(m); + mission_id = (Campaign::MULTIPLAYER_MISSIONS << NET_CAMPAIGN_SHIFT) + m->id; + + SelectMission(mission_id); + star_server->SetGameMode(StarServer::LOAD_MODE); + + // lock in mission: + SetStatus(NetServerInfo::PERSISTENT); + } + } + } + } + } + + // player host may select mission: + if (!mission_id) { + campaigns.destroy(); + + ListIter c_iter = Campaign::GetAllCampaigns(); + while (++c_iter) { + Campaign* campaign = c_iter.value(); + + if (campaign->GetCampaignId() >= Campaign::MULTIPLAYER_MISSIONS) { + NetCampaignInfo* c = new(__FILE__,__LINE__) NetCampaignInfo; + c->id = campaign->GetCampaignId(); + c->name = campaign->Name(); + campaigns.append(c); + + ListIter m_iter = campaign->GetMissionList(); + while (++m_iter) { + MissionInfo* m = m_iter.value(); + c->missions.append(m); + } + } + } + } + + ModConfig* config = ModConfig::GetInstance(); + List& mods = config->GetModInfoList(); + + server_mods.clear(); + server_mods.append(mods); + + net_lobby_server = this; +} + +NetLobbyServer::~NetLobbyServer() +{ + ListIter iter = users; + while (++iter) { + NetUser* u = iter.value(); + SendData(u, NET_LOBBY_EXIT, Text()); + ExecFrame(); + } + + Sleep(500); + + unit_map.destroy(); + chat_log.destroy(); + users.destroy(); + motd.destroy(); + + if (net_lobby_server == this) + net_lobby_server = 0; +} + +NetLobbyServer* +NetLobbyServer::GetInstance() +{ + return net_lobby_server; +} + +// +--------------------------------------------------------------------+ + +void +NetLobbyServer::LoadMOTD() +{ + motd.destroy(); + + FILE* f; + fopen_s(&f, "motd.txt", "r"); + + if (f) { + char line[256]; + + while (fgets(line, 256, f)) { + int n = strlen(line) - 1; + + while (n >= 0 && isspace(line[n])) + line[n--] = 0; + + motd.append(new(__FILE__,__LINE__) Text(line)); + } + } +} + +void +NetLobbyServer::SendMOTD(NetUser* user) +{ + if (motd.size() < 1) return; + + char buffer[512]; + + for (int i = 0; i < motd.size(); i++) { + Text* line = motd[i]; + + sprintf_s(buffer, "id %d user \" \" msg \"%s\"", + motd_index++, line->data()); + + SendData(user, NET_LOBBY_CHAT, buffer); + } + + sprintf_s(buffer, "id %d user \" \" msg \" \"", motd_index++); + SendData(user, NET_LOBBY_CHAT, buffer); +} + +void +NetLobbyServer::SendMods(NetUser* user) +{ + char buffer[300]; + + ModConfig* config = ModConfig::GetInstance(); + List& mods = config->GetModInfoList(); + + if (mods.size() < 1) return; + + for (int i = 0; i < mods.size(); i++) { + ModInfo* info = mods[i]; + + sprintf_s(buffer, "id %d user \"Enabled Mods:\" msg \"%d. '%s' ", + motd_index++, i+1, info->Name().data()); + + Text msg = buffer; + + if (info->Version().length() > 0) { + msg += "version "; + msg += info->Version().data(); + } + + if (info->URL().length() > 0) { + msg += " - "; + msg += info->URL().data(); + } + + msg += "\""; + + SendData(user, NET_LOBBY_CHAT, msg); + } + + sprintf_s(buffer, "id %d user \" \" msg \" \"", motd_index++); + SendData(user, NET_LOBBY_CHAT, buffer); +} + +// +--------------------------------------------------------------------+ + +void +NetLobbyServer::ExecFrame() +{ + NetLobby::ExecFrame(); + + if (announce_time == 0 || Game::RealTime() - announce_time > 200000) { + GameOn(); + announce_time = Game::RealTime(); + } + + if (GetStatus() == NetServerInfo::BRIEFING) { + NetGame* net_game = NetGame::GetInstance(); + + if (net_game && net_game->NumPlayers() > 0) { + SetStatus(NetServerInfo::ACTIVE); + } + } + + StarServer* star_server = StarServer::GetInstance(); + DWORD mission_id = 0; + + // restart persistent mission? + if (star_server && + star_server->GetGameMode() == StarServer::MENU_MODE && + server_mission.length() > 0) { + + NetCampaignInfo* c = campaigns.last(); + + if (!c || c->name != "Persistent Multiplayer") { + c = new(__FILE__,__LINE__) NetCampaignInfo; + c->id = Campaign::MULTIPLAYER_MISSIONS; + c->name = "Persistent Multiplayer"; + campaigns.append(c); + } + else { + c->missions.clear(); + } + + ListIter c_iter = Campaign::GetAllCampaigns(); + while (++c_iter && !mission_id) { + Campaign* campaign = c_iter.value(); + + if (campaign->GetCampaignId() == Campaign::MULTIPLAYER_MISSIONS) { + ListIter m_iter = campaign->GetMissionList(); + while (++m_iter && !mission_id) { + MissionInfo* m = m_iter.value(); + + if (m->script == server_mission) { + c->missions.append(m); + mission_id = (Campaign::MULTIPLAYER_MISSIONS << NET_CAMPAIGN_SHIFT) + m->id; + + // unlock old mission: + SetStatus(NetServerInfo::LOBBY); + + SelectMission(mission_id); + + if (star_server->GetGameMode() == StarServer::MENU_MODE) { + star_server->SetGameMode(StarServer::LOAD_MODE); + } + + // lock in new mission: + SetStatus(NetServerInfo::PERSISTENT); + } + } + } + } + } + + CheckSessions(); +} + +// +-------------------------------------------------------------------+ + +void +NetLobbyServer::SendData(NetUser* dst, int type, Text msg) +{ + if (link && dst && type > 0 && type < 255) { + if (msg.length()) + link->SendMessage(dst->GetNetID(), (BYTE) type, msg.data(), msg.length(), NetMsg::RELIABLE); + else + link->SendMessage(dst->GetNetID(), (BYTE) type, 0, 0, NetMsg::RELIABLE); + } +} + +// +-------------------------------------------------------------------+ + +void +NetLobbyServer::CheckSessions() +{ + if (!link) + return; + + bool dropped = false; + + ListIter u_iter = users; + while (++u_iter) { + NetUser* u = u_iter.value(); + NetPeer* p = link->FindPeer(u->GetNetID()); + + if (p && (NetLayer::GetUTC() - p->LastReceiveTime()) > NET_DISCONNECT_TIME) { + // check game peer for activity: + NetGame* game = NetGame::GetInstance(); + NetPlayer* player = 0; + NetPeer* p2 = 0; + + if (game) { + player = game->FindPlayerByName(u->Name()); + + if (player) { + p2 = game->GetPeer(player); + + if (p2 && (NetLayer::GetUTC() - p2->LastReceiveTime()) < NET_DISCONNECT_TIME) { + p->SetLastReceiveTime(p2->LastReceiveTime()); + continue; + } + } + else { + ::Print("NetLobbyServer::CheckSessions() Could not find player for '%s'\n", u->Name().data()); + } + } + else { + ::Print("NetLobbyServer::CheckSessions() Could not find net game for '%s'\n", u->Name().data()); + } + + // announce drop: + char timestr[64]; + FormatTime(timestr, Game::RealTime()/1000); + Print("NetLobbyServer: Dropped inactive connection '%s' %s\n", + u->Name().data(), timestr); + + if (u->IsHost()) { + Print(" User was host - ending net game.\n"); + GameStop(); + } + + u_iter.removeItem(); // first remove user from list + NetLobby::UnmapUnit(u->Name()); // then unmap unit + delete u; // now it is safe to discard the inactive user + + dropped = true; + } + } + + if (dropped) { + SendUsers(); + SendUnits(); + } +} + +// +-------------------------------------------------------------------+ + +void +NetLobbyServer::GameStart() +{ + if (status < NetServerInfo::ACTIVE) { + SetStatus(NetServerInfo::BRIEFING); + + if (Starshatter::GetInstance()) { + Starshatter::GetInstance()->SetGameMode(Starshatter::PREP_MODE); + } + else { + StarServer* s = StarServer::GetInstance(); + if (s && s->GetGameMode() == StarServer::MENU_MODE) { + s->SetGameMode(StarServer::LOAD_MODE); + } + } + } +} + +void +NetLobbyServer::GameStop() +{ + if (GetStatus() != NetServerInfo::PERSISTENT) { + SetStatus(NetServerInfo::LOBBY); + + StarServer* s = StarServer::GetInstance(); + if (s && s->GetGameMode() != StarServer::MENU_MODE) { + s->SetGameMode(StarServer::MENU_MODE); + } + } +} + +// +-------------------------------------------------------------------+ + +void +NetLobbyServer::BanUser(NetUser* user) +{ + if (user && !user->IsHost()) { + ::Print("NetLobbyServer::BanUser name '%s' addr %d.%d.%d.%d\n", + user->Name().data(), + user->GetAddress().B1(), + user->GetAddress().B2(), + user->GetAddress().B3(), + user->GetAddress().B4()); + + SendData(user, NET_LOBBY_EXIT, Text()); + + if (server_config) + server_config->BanUser(user); + + DelUser(user); + } +} + +void +NetLobbyServer::AddUser(NetUser* user) +{ + if (server_config && server_config->IsUserBanned(user)) { + delete user; + return; + } + + NetLobby::AddUser(user); + SendUsers(); +} + +void +NetLobbyServer::DelUser(NetUser* user) +{ + NetLobby::DelUser(user); + SendUsers(); +} + +void +NetLobbyServer::SendUsers() +{ + Text content; + + ListIter u_iter = users; + while (++u_iter) { + NetUser* u = u_iter.value(); + content += u->GetDescription(); + } + + u_iter.reset(); + + while (++u_iter) { + NetUser* u = u_iter.value(); + SendData(u, NET_LOBBY_USER_LIST, content); + } +} + +// +-------------------------------------------------------------------+ + +void +NetLobbyServer::RequestAuth(NetUser* user) +{ + if (user) { + Text request = NetAuth::CreateAuthRequest(user); + + if (request.length() > 0) + SendData(user, NET_LOBBY_AUTH_USER, request); + } +} + +// +-------------------------------------------------------------------+ + +void +NetLobbyServer::AddChat(NetUser* user, const char* msg, bool route) +{ + NetChatEntry* entry = 0; + + if (user && msg && *msg) { + bool msg_ok = false; + const char* p = msg; + + while (*p && !msg_ok) { + if (!isspace(*p++)) + msg_ok = true; + } + + if (msg_ok) { + entry = new(__FILE__,__LINE__) NetChatEntry(user, msg); + + chat_log.append(entry); + + // forward to all clients: + if (users.size()) { + char buffer[768]; + char msg_buf[256]; + char usr_buf[256]; + + // safe quotes uses a static buffer, + // so make sure to save copies of the + // results when using more than one in + // a function call... + + strcpy_s(msg_buf, SafeQuotes(msg)); + strcpy_s(usr_buf, SafeQuotes(user->Name())); + + sprintf_s(buffer, "id %d user \"%s\" msg \"%s\"", + entry->GetID(), usr_buf, msg_buf); + + ListIter iter = users; + while (++iter) { + NetUser* u = iter.value(); + SendData(u, NET_LOBBY_CHAT, buffer); + } + + if (route) { + // send to active game: + NetUtil::SendChat(0xffff, usr_buf, msg_buf); + } + } + } + } +} + +void +NetLobbyServer::ClearChat() +{ + NetLobby::ClearChat(); +} + +void +NetLobbyServer::SaveChat() +{ + FILE* f; + fopen_s(&f, "chat.txt", "w"); + if (f) { + for (int i = 0; i < chat_log.size(); i++) { + NetChatEntry* c = chat_log[i]; + fprintf(f, "%08x [%s] %s\n", + c->GetTime(), + c->GetUser().data(), + c->GetMessage().data()); + } + + fclose(f); + } +} + +// +-------------------------------------------------------------------+ + +void +NetLobbyServer::SelectMission(DWORD id) +{ + if (GetStatus() == NetServerInfo::PERSISTENT) + return; + + NetLobby::SelectMission(id); + + // inform all users of the selection: + char buffer[32]; + sprintf_s(buffer, "m_id 0x%08x", selected_mission); + + ListIter iter = users; + while (++iter) { + NetUser* u = iter.value(); + SendData(u, NET_LOBBY_MISSION_SELECT, buffer); + } +} + +// +-------------------------------------------------------------------+ + +List& +NetLobbyServer::GetUnitMap() +{ + if (!mission) { + unit_map.destroy(); + return unit_map; + } + + List units; + ListIter iter = mission->GetElements(); + int i = 0; + + Sim* sim = Sim::GetSim(); + if (sim && sim->GetElements().size() > 0) + iter = sim->GetMissionElements(); + + // create new entries for the playable elements in the mission or simulation: + while (++iter) { + MissionElement* elem = iter.value(); + + if (elem->IsPlayable()) { + NetUnitEntry* u = 0; + if (elem->Count() == 1) { + u = new(__FILE__,__LINE__) NetUnitEntry(elem, 0); + u->SetLives(elem->RespawnCount() + 1); + u->SetMissionRole(elem->MissionRole()); + u->SetIFF(elem->GetIFF()); + + if (elem->GetDesign()) + u->SetDesign(elem->GetDesign()->name); + + if (elem->Ships().size() > 0) { + MissionShip* s = elem->Ships()[0]; + u->SetIntegrity((int) s->Integrity()); + } + units.append(u); + } + else { + for (int i = 0; i < elem->Count(); i++) { + u = new(__FILE__,__LINE__) NetUnitEntry(elem, i+1); + u->SetMissionRole(elem->MissionRole()); + u->SetIFF(elem->GetIFF()); + + if (elem->GetDesign()) + u->SetDesign(elem->GetDesign()->name); + + if (elem->Ships().size() > i) { + MissionShip* s = elem->Ships()[i]; + u->SetLives(s->Respawns() + 1); + u->SetIntegrity((int) s->Integrity()); + } + units.append(u); + } + } + } + } + + // match new entries with any existing map entries: + if (unit_map.size()) { + for (i = 0; i < units.size(); i++) { + NetUnitEntry* e_new = units[i]; + NetUnitEntry* e_old = unit_map.find(e_new); + + if (e_old) { + e_new->SetUserName(e_old->GetUserName()); + e_new->SetLock(e_old->GetLocked()); + } + } + } + + // rewrite the unit map with the new entries: + ClearUnitMap(); + for (i = 0; i < units.size(); i++) { + unit_map.append(units[i]); + } + + return unit_map; +} + +void +NetLobbyServer::MapUnit(int n, const char* user, bool lock) +{ + NetLobby::MapUnit(n, user, lock); + + Text reply; + + ListIter map_iter = GetUnitMap(); + while (++map_iter) { + NetUnitEntry* unit = map_iter.value(); + reply += unit->GetDescription(); + } + + ListIter u_iter = users; + while (++u_iter) { + NetUser* u = u_iter.value(); + SendData(u, NET_LOBBY_UNIT_LIST, reply); + } +} + +void +NetLobbyServer::UnmapUnit(const char* user) +{ + NetLobby::UnmapUnit(user); + + Text reply; + + ListIter map_iter = GetUnitMap(); + while (++map_iter) { + NetUnitEntry* unit = map_iter.value(); + reply += unit->GetDescription(); + } + + ListIter u_iter = users; + while (++u_iter) { + NetUser* u = u_iter.value(); + SendData(u, NET_LOBBY_UNIT_LIST, reply); + } +} + +void +NetLobbyServer::SendUnits() +{ + Text content; + + ListIter map_iter = GetUnitMap(); + while (++map_iter) { + NetUnitEntry* unit = map_iter.value(); + content += unit->GetDescription(); + } + + ListIter u_iter = users; + while (++u_iter) { + NetUser* u = u_iter.value(); + SendData(u, NET_LOBBY_UNIT_LIST, content); + } +} + +// +-------------------------------------------------------------------+ + +Text +NetLobbyServer::Serialize(Mission* m, NetUser* user) +{ + Text s; + + if (!m || !user) + return s; + + NetUnitEntry* unit = 0; + + ListIter u_iter = GetUnitMap(); + while (++u_iter && !unit) { + NetUnitEntry* u = u_iter.value(); + if (u->GetUserName() == user->Name()) + unit = u; + } + + if (unit) + s = m->Serialize(unit->GetElemName(), unit->GetIndex()); + + return s; +} + +Mission* +NetLobbyServer::GetSelectedMission() +{ + if (mission) { + Text content = Serialize(mission, GetLocalUser()); + Campaign* c = Campaign::SelectCampaign("Multiplayer Missions"); + + if (c) { + c->LoadNetMission(99999, content.data()); + return c->GetMission(99999); + } + } + + return mission; +} + +// +-------------------------------------------------------------------+ + +void +NetLobbyServer::GameOn() +{ + NetHost host; + const char* type = "Starshatter"; + const char* password = "No"; + char address[32]; + + strcpy_s(address, "0"); + + if (server_config) { + if (server_config->GetGameType() == NetServerConfig::NET_GAME_PRIVATE) + return; + + if (server_config->GetGameType() == NetServerConfig::NET_GAME_LAN) { + type = "Starshatter-LAN"; + sprintf_s(address, "%d.%d.%d.%d", + host.Address().B1(), + host.Address().B2(), + host.Address().B3(), + host.Address().B4()); + } + else { + type = "Starshatter"; + sprintf_s(address, "0.0.0.0"); + } + + if (server_config->GetGamePass().length() > 0) + password = "Yes"; + } + + NetBrokerClient::GameOn(server_name, + type, + address, + server_addr.Port(), + password); +} + +void +NetLobbyServer::GameOff() +{ +} + +// +-------------------------------------------------------------------+ + +void +NetLobbyServer::DoPing(NetPeer* peer, Text s) +{ } + +void +NetLobbyServer::DoServerInfo(NetPeer* peer, Text s) +{ + if (peer && peer->NetID()) { + char buffer[1024]; + WORD gameport = 11101; + + if (server_config) + gameport = server_config->GetGamePort(); + + sprintf_s(buffer, "info \"%s\" version \"%s\" mode %d users %d host %s port %d", + MachineInfo::GetShortDescription(), + versionInfo, + GetStatus(), + NumUsers(), + HasHost() ? "true" : "false", + gameport); + + link->SendMessage(peer->NetID(), (BYTE) NET_LOBBY_SERVER_INFO, buffer, strlen(buffer), NetMsg::RELIABLE); + } +} + +void +NetLobbyServer::DoServerMods(NetPeer* peer, Text s) +{ + if (peer && peer->NetID()) { + Text response; + ModConfig* config = ModConfig::GetInstance(); + List& mods = config->GetModInfoList(); + ListIter mod_iter = mods; + + char buffer[32]; + sprintf_s(buffer, "num %d ", mods.size()); + response += buffer; + + while (++mod_iter) { + ModInfo* info = mod_iter.value(); + + response += "mod \""; + response += info->Name(); + response += "\" url \""; + response += info->URL(); + response += "\" ver \""; + response += info->Version(); + response += "\" "; + } + + link->SendMessage(peer->NetID(), (BYTE) NET_LOBBY_SERVER_MODS, response, response.length(), NetMsg::RELIABLE); + } +} + +// +-------------------------------------------------------------------+ + +void +NetLobbyServer::DoLogin(NetPeer* peer, Text msg) +{ + List params; + ParseMsg(msg, params); + + Text name; + Text pass; + Text host; + Text gamepass; + Text signature; + Text squadron; + Text version; + int rank = 0; + int flight_time = 0; + int missions = 0; + int kills = 0; + int losses = 0; + + for (int i = 0; i < params.size(); i++) { + NetLobbyParam* p = params[i]; + + int num = 0; + sscanf_s(p->value, "%d", &num); + + if (p->name == "name") + name = p->value; + + else if (p->name == "pass") + pass = p->value; + + else if (p->name == "gamepass") + gamepass = p->value; + + else if (p->name == "host") + host = p->value; + + else if (p->name == "sig") + signature = p->value; + + else if (p->name == "squad") + squadron = p->value; + + else if (p->name == "version") + version = p->value; + + else if (p->name == "rank") + rank = num; + + else if (p->name == "time") + flight_time = num; + + else if (p->name == "miss") + missions = num; + + else if (p->name == "kill") + kills = num; + + else if (p->name == "loss") + losses = num; + } + + params.destroy(); + + // first check the game version: + if (version != versionInfo) { + Print("NetLobbyServer - user '%s' tried to login with invalid game version '%s'\n", + name.data(), version.data()); + + return; + } + + // next check the game password: + if (server_config && server_config->GetGamePass().length() > 0) { + if (gamepass != server_config->GetGamePass()) { + Print("NetLobbyServer - user '%s' tried to login with invalid game password '%s'\n", + name.data(), gamepass.data()); + + return; + } + } + + // now try to log the user in: + NetUser* pre_existing = FindUserByName(name); + + // is user already logged in? + if (pre_existing) { + if (pre_existing->Pass() == pass && + pre_existing->GetAddress().IPAddr() == peer->Address().IPAddr()) { + } + } + + // otherwise, create a new user: + else { + NetUser* user = new(__FILE__,__LINE__) NetUser(name); + user->SetAddress(peer->Address()); + user->SetNetID(peer->NetID()); + user->SetPass(pass); + user->SetSignature(signature); + user->SetSquadron(squadron); + user->SetRank(rank); + user->SetFlightTime(flight_time); + user->SetMissions(missions); + user->SetKills(kills); + user->SetLosses(losses); + + if (host == "true" && !HasHost()) + user->SetHost(true); + + AddUser(user); + RequestAuth(user); + SendMOTD(user); + SendMods(user); + } +} + +void +NetLobbyServer::DoLogout(NetPeer* peer, Text msg) +{ + NetUser* user = FindUserByNetID(peer->NetID()); + + if (user) { + if (user->IsHost()) + GameStop(); + + DelUser(user); + } +} + +void +NetLobbyServer::DoUserAuth(NetPeer* peer, Text msg) +{ + NetUser* user = FindUserByNetID(peer->NetID()); + + if (user) { + NetAuth::AuthUser(user, msg); + + if (!user->IsAuthOK()) { + char buffer[256]; + + sprintf_s(buffer, "id %d user \"SERVER\" msg \"**********\"", motd_index++); + SendData(user, NET_LOBBY_CHAT, buffer); + + sprintf_s(buffer, "id %d user \"SERVER\" msg \"*** Your game configuration does not match the server.\"", motd_index++); + SendData(user, NET_LOBBY_CHAT, buffer); + + if (server_mods.size() > 0) { + sprintf_s(buffer, "id %d user \"SERVER\" msg \"*** Please check that you have the proper mods deployed in\"", motd_index++); + SendData(user, NET_LOBBY_CHAT, buffer); + sprintf_s(buffer, "id %d user \"SERVER\" msg \"*** the order shown above.\"", motd_index++); + SendData(user, NET_LOBBY_CHAT, buffer); + } + + else { + sprintf_s(buffer, "id %d user \"SERVER\" msg \"*** Please verify that you have no mods deployed.\"", motd_index++); + SendData(user, NET_LOBBY_CHAT, buffer); + } + + sprintf_s(buffer, "id %d user \"SERVER\" msg \"*** You will not be permitted to join the game with an invalid\"", motd_index++); + SendData(user, NET_LOBBY_CHAT, buffer); + + sprintf_s(buffer, "id %d user \"SERVER\" msg \"*** configuration. You may reconnect to this server after you\"", motd_index++); + SendData(user, NET_LOBBY_CHAT, buffer); + + sprintf_s(buffer, "id %d user \"SERVER\" msg \"*** have corrected your mod configuration.\"", motd_index++); + SendData(user, NET_LOBBY_CHAT, buffer); + + sprintf_s(buffer, "id %d user \"SERVER\" msg \"**********\"", motd_index++); + SendData(user, NET_LOBBY_CHAT, buffer); + + sprintf_s(buffer, "id %d user \" \" msg \" \"", motd_index++); + SendData(user, NET_LOBBY_CHAT, buffer); + } + } +} + +void +NetLobbyServer::DoChat(NetPeer* peer, Text msg) +{ + List params; + ParseMsg(msg, params); + + Text chat_msg; + + for (int i = 0; i < params.size(); i++) { + NetLobbyParam* p = params[i]; + + int num = 0; + sscanf_s(p->value, "%d", &num); + + if (p->name == "msg") { + chat_msg = p->value; + } + } + + params.destroy(); + + NetUser* user = FindUserByNetID(peer->NetID()); + + if (user) { + // receive chat from client: + if (chat_msg.length()) { + AddChat(user, chat_msg); + } + + // request for chat log: + else { + ListIter iter = chat_log; + while (++iter) { + NetChatEntry* entry = iter.value(); + + char buffer[512]; + char msg_buf[256]; + char usr_buf[256]; + + // safe quotes uses a static buffer, + // so make sure to save copies of the + // results when using more than one in + // a function call... + + strcpy_s(msg_buf, SafeQuotes(entry->GetMessage())); + strcpy_s(usr_buf, SafeQuotes(entry->GetUser())); + + sprintf_s(buffer, "id %d user \"%s\" msg \"%s\"", + entry->GetID(), usr_buf, msg_buf); + + SendData(user, NET_LOBBY_CHAT, buffer); + } + } + } +} + +void +NetLobbyServer::DoUserList(NetPeer* peer, Text msg) +{ + NetUser* user = FindUserByNetID(peer->NetID()); + + if (user) { + Text content; + + if (local_user) + content += local_user->GetDescription(); + + ListIter iter = users; + while (++iter) { + NetUser* u = iter.value(); + content += u->GetDescription(); + } + + SendData(user, NET_LOBBY_USER_LIST, content); + } +} + +void +NetLobbyServer::DoBanUser(NetPeer* peer, Text msg) +{ + NetUser* user = FindUserByNetID(peer->NetID()); + + if (user && user->IsHost() && user->IsAuthOK()) { + List params; + ParseMsg(msg, params); + + if (params.size() > 0) { + NetLobbyParam* p = params[0]; + + if (p->name == "user") { + Text user_name = p->value; + + NetUser* u = FindUserByName(user_name); + if (u && !u->IsHost()) + BanUser(u); + } + } + + params.destroy(); + } +} + +void +NetLobbyServer::DoMissionList(NetPeer* peer, Text msg) +{ + NetUser* user = FindUserByNetID(peer->NetID()); + + if (user) { + Text reply; + char buffer[4096]; + + ListIter c_iter = Campaign::GetAllCampaigns(); + while (++c_iter) { + Campaign* c = c_iter.value(); + + if (c->GetCampaignId() >= Campaign::MULTIPLAYER_MISSIONS) { + sprintf_s(buffer, "c_id 0x%08x c_name \"%s\" ", + c->GetCampaignId(), + SafeQuotes(c->Name())); + + reply += buffer; + } + } + + c_iter.reset(); + + while (++c_iter) { + Campaign* c = c_iter.value(); + + if (c->GetCampaignId() >= Campaign::MULTIPLAYER_MISSIONS) { + + ListIter m_iter = c->GetMissionList(); + while (++m_iter) { + MissionInfo* m = m_iter.value(); + + int mission_id = (c->GetCampaignId() << NET_CAMPAIGN_SHIFT) + m->id; + + sprintf_s(buffer, "m_id 0x%08x ", mission_id); + reply += buffer; + + reply += "m_name \""; + reply += SafeQuotes(m->name); + + // long version of safe quotes: + int n = 0; + const char* s = m->description.data(); + + while (*s && n < 4090) { + if (*s == '"') { + buffer[n++] = '\''; + s++; + } + else if (*s == '\n') { + buffer[n++] = '\\'; + buffer[n++] = 'n'; + s++; + } + else if (*s == '\t') { + buffer[n++] = '\\'; + buffer[n++] = 't'; + s++; + } + else { + buffer[n++] = *s++; + } + } + + // don't forget the null terminator! + buffer[n] = 0; + + reply += "\" m_desc \""; + reply += buffer; + + reply += "\" "; + } + } + } + + SendData(user, NET_LOBBY_MISSION_LIST, reply); + + sprintf_s(buffer, "m_id 0x%08x", selected_mission); + SendData(user, NET_LOBBY_MISSION_SELECT, buffer); + } +} + +void +NetLobbyServer::DoMissionSelect(NetPeer* peer, Text msg) +{ + if (GetStatus() == NetServerInfo::PERSISTENT) + return; + + NetUser* user = FindUserByNetID(peer->NetID()); + + if (user && user->IsHost() && user->IsAuthOK()) { + List params; + ParseMsg(msg, params); + + for (int i = 0; i < params.size(); i++) { + NetLobbyParam* p = params[i]; + + int num = 0; + sscanf_s(p->value, "0x%x", &num); + + if (p->name == "m_id") { + SelectMission(num); + } + } + + params.destroy(); + } +} + +void +NetLobbyServer::DoMissionData(NetPeer* peer, Text msg) +{ + NetUser* user = FindUserByNetID(peer->NetID()); + + if (user && mission && user->IsAuthOK()) { + Text reply = Serialize(mission, user); + SendData(user, NET_LOBBY_MISSION_DATA, reply); + + FILE* f = ::fopen("multi_mission_send.def", "w"); + if (f) { + ::fwrite(reply.data(), reply.length(), 1, f); + ::fclose(f); + } + } +} + +void +NetLobbyServer::DoUnitList(NetPeer* peer, Text msg) +{ + NetUser* user = FindUserByNetID(peer->NetID()); + + if (user && unit_map.size() && user->IsAuthOK()) { + Text reply; + + ListIter iter = GetUnitMap(); + while (++iter) { + NetUnitEntry* unit = iter.value(); + reply += unit->GetDescription(); + } + + SendData(user, NET_LOBBY_UNIT_LIST, reply); + } +} + +void +NetLobbyServer::DoMapUnit(NetPeer* peer, Text msg) +{ + NetUser* user = FindUserByNetID(peer->NetID()); + + if (user && unit_map.size() && user->IsAuthOK()) { + List params; + ParseMsg(msg, params); + + int id = 0; + bool lock = false; + Text user_name; + + for (int i = 0; i < params.size(); i++) { + NetLobbyParam* p = params[i]; + + if (p->name == "id") { + sscanf_s(p->value, "%d", &id); + } + + else if (p->name == "user") { + user_name = p->value; + } + + else if (p->name == "lock") { + lock = (p->value == "true") ? true : false; + } + } + + params.destroy(); + + MapUnit(id, user_name, lock); + } +} + +void +NetLobbyServer::DoGameStart(NetPeer* peer, Text msg) +{ + GameStart(); +} + +void +NetLobbyServer::DoGameStop(NetPeer* peer, Text msg) +{ + NetUser* user = FindUserByNetID(peer->NetID()); + + if (user && user->IsHost() && user->IsAuthOK()) + GameStop(); +} -- cgit v1.1