diff options
Diffstat (limited to 'Stars45/NetLobbyServer.cpp')
-rw-r--r-- | Stars45/NetLobbyServer.cpp | 2746 |
1 files changed, 1385 insertions, 1361 deletions
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<Campaign> c_iter = Campaign::GetAllCampaigns();
- while (++c_iter && !mission_id) {
- Campaign* campaign = c_iter.value();
-
- if (campaign->GetCampaignId() == Campaign::MULTIPLAYER_MISSIONS) {
- ListIter<MissionInfo> 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<Campaign> 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<MissionInfo> m_iter = campaign->GetMissionList();
- while (++m_iter) {
- MissionInfo* m = m_iter.value();
- c->missions.append(m);
- }
- }
- }
- }
-
- ModConfig* config = ModConfig::GetInstance();
- List<ModInfo>& mods = config->GetModInfoList();
-
- server_mods.clear();
- server_mods.append(mods);
-
- net_lobby_server = this;
-}
-
-NetLobbyServer::~NetLobbyServer()
-{
- ListIter<NetUser> 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<ModInfo>& 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<Campaign> c_iter = Campaign::GetAllCampaigns();
- while (++c_iter && !mission_id) {
- Campaign* campaign = c_iter.value();
-
- if (campaign->GetCampaignId() == Campaign::MULTIPLAYER_MISSIONS) {
- ListIter<MissionInfo> 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<NetUser> 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<NetUser> 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<NetUser> 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<NetUser> iter = users;
- while (++iter) {
- NetUser* u = iter.value();
- SendData(u, NET_LOBBY_MISSION_SELECT, buffer);
- }
-}
-
-// +-------------------------------------------------------------------+
-
-List<NetUnitEntry>&
-NetLobbyServer::GetUnitMap()
-{
- if (!mission) {
- unit_map.destroy();
- return unit_map;
- }
-
- List<NetUnitEntry> units;
- ListIter<MissionElement> 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<NetUnitEntry> map_iter = GetUnitMap();
- while (++map_iter) {
- NetUnitEntry* unit = map_iter.value();
- reply += unit->GetDescription();
- }
-
- ListIter<NetUser> 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<NetUnitEntry> map_iter = GetUnitMap();
- while (++map_iter) {
- NetUnitEntry* unit = map_iter.value();
- reply += unit->GetDescription();
- }
-
- ListIter<NetUser> u_iter = users;
- while (++u_iter) {
- NetUser* u = u_iter.value();
- SendData(u, NET_LOBBY_UNIT_LIST, reply);
- }
-}
-
-void
-NetLobbyServer::SendUnits()
-{
- Text content;
-
- ListIter<NetUnitEntry> map_iter = GetUnitMap();
- while (++map_iter) {
- NetUnitEntry* unit = map_iter.value();
- content += unit->GetDescription();
- }
-
- ListIter<NetUser> 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<NetUnitEntry> 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<ModInfo>& mods = config->GetModInfoList();
- ListIter<ModInfo> 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<NetLobbyParam> 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<NetLobbyParam> 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<NetChatEntry> 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<NetUser> 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<NetLobbyParam> 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<Campaign> 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<MissionInfo> 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<NetLobbyParam> 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<NetUnitEntry> 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<NetLobbyParam> 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<Campaign> c_iter = Campaign::GetAllCampaigns(); + while (++c_iter && !mission_id) { + Campaign* campaign = c_iter.value(); + + if (campaign->GetCampaignId() == Campaign::MULTIPLAYER_MISSIONS) { + ListIter<MissionInfo> 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<Campaign> 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<MissionInfo> m_iter = campaign->GetMissionList(); + while (++m_iter) { + MissionInfo* m = m_iter.value(); + c->missions.append(m); + } + } + } + } + + ModConfig* config = ModConfig::GetInstance(); + List<ModInfo>& mods = config->GetModInfoList(); + + server_mods.clear(); + server_mods.append(mods); + + net_lobby_server = this; +} + +NetLobbyServer::~NetLobbyServer() +{ + ListIter<NetUser> 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<ModInfo>& 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<Campaign> c_iter = Campaign::GetAllCampaigns(); + while (++c_iter && !mission_id) { + Campaign* campaign = c_iter.value(); + + if (campaign->GetCampaignId() == Campaign::MULTIPLAYER_MISSIONS) { + ListIter<MissionInfo> 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<NetUser> 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<NetUser> 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<NetUser> 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<NetUser> iter = users; + while (++iter) { + NetUser* u = iter.value(); + SendData(u, NET_LOBBY_MISSION_SELECT, buffer); + } +} + +// +-------------------------------------------------------------------+ + +List<NetUnitEntry>& +NetLobbyServer::GetUnitMap() +{ + if (!mission) { + unit_map.destroy(); + return unit_map; + } + + List<NetUnitEntry> units; + ListIter<MissionElement> 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<NetUnitEntry> map_iter = GetUnitMap(); + while (++map_iter) { + NetUnitEntry* unit = map_iter.value(); + reply += unit->GetDescription(); + } + + ListIter<NetUser> 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<NetUnitEntry> map_iter = GetUnitMap(); + while (++map_iter) { + NetUnitEntry* unit = map_iter.value(); + reply += unit->GetDescription(); + } + + ListIter<NetUser> u_iter = users; + while (++u_iter) { + NetUser* u = u_iter.value(); + SendData(u, NET_LOBBY_UNIT_LIST, reply); + } +} + +void +NetLobbyServer::SendUnits() +{ + Text content; + + ListIter<NetUnitEntry> map_iter = GetUnitMap(); + while (++map_iter) { + NetUnitEntry* unit = map_iter.value(); + content += unit->GetDescription(); + } + + ListIter<NetUser> 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<NetUnitEntry> 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<ModInfo>& mods = config->GetModInfoList(); + ListIter<ModInfo> 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<NetLobbyParam> 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<NetLobbyParam> 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<NetChatEntry> 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<NetUser> 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<NetLobbyParam> 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<Campaign> 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<MissionInfo> 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<NetLobbyParam> 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<NetUnitEntry> 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<NetLobbyParam> 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(); +} |