hostile-takeover/server/main.cpp
Nathan Fulton abb1823956 Add /t server command for team chat
New command /t that can be used in game to send chats that only appear
to players on the same team. Observing players cannot use team chat.
2016-08-31 22:43:34 -04:00

234 lines
7.8 KiB
C++

#include "inc/basictypes.h"
#include "base/thread.h"
#include "base/socketaddress.h"
#include "base/tick.h"
#include "base/log.h"
#include "server/server.h"
#include "server/levelinfocache.h"
#include "server/ncpackfile.h"
#include "server/statsposter.h"
#include "server/serverinfoupdater.h"
#include "mpshared/constants.h"
#include "mpshared/packmanager.h"
#include "mpshared/xmsglog.h"
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <vector>
// Main server thread
base::Thread main_thread;
// These are defaults that can be overridden
const dword kcRoomsMax = 200;
const dword kcGamesPerRoomMax = 100;
const dword kcPlayersPerRoomMax = 200;
const dword kcConnectedPlayersMax = 1500;
std::vector<std::string> ParseArgs(int argc, char **argv, const char *fmt) {
std::vector<std::string> args;
for (int i = 0; i < argc; i++) {
if (strcmp(argv[i], fmt) == 0 && i <= argc - 2) {
args.push_back(argv[i + 1]);
i++;
}
}
return args;
}
std::string ParseString(int argc, char **argv, const char *fmt) {
std::vector<std::string> args = ParseArgs(argc, argv, fmt);
if (!args.empty()) {
return args[0];
}
return "";
}
int ParseInteger(int argc, char **argv, const char *fmt, int def = 0) {
std::string s = ParseString(argc, argv, fmt);
if (s.length() == 0) {
return def;
}
int n = def;
base::Format::ToInteger(s.c_str(), 10, &n);
return n;
}
int ParseDword(int argc, char **argv, const char *fmt, dword def = 0) {
std::string s = ParseString(argc, argv, fmt);
if (s.length() == 0) {
return def;
}
dword n = def;
base::Format::ToDword(s.c_str(), 10, &n);
return n;
}
bool FindArg(int argc, char **argv, const char *fmt) {
for (int i = 0; i < argc; i++) {
if (strcmp(argv[i], fmt) == 0) {
return true;
}
}
return false;
}
base::SocketAddress GetListenAddress(int argc, char **argv) {
// Accept address arg or default address, port arg or default port
// For default address, choose interface adapter.
base::SocketAddress listen_address;
std::string listen_address_arg = ParseString(argc, argv, "--listen_address");
if (listen_address_arg.size() != 0) {
listen_address = base::SocketAddress(listen_address_arg.c_str());
} else {
// Choose a network, rather than using ANY, since it will be sent in server info
int n = 0;
char sz[32];
dword ip;
while (base::SocketAddress::GetNetworkInfo(n, sz, sizeof(sz), &ip)) {
if (strncmp(sz, "eth", 3) == 0) {
listen_address.SetIP(ip);
break;
}
if (strncmp(sz, "en", 2) == 0) {
listen_address.SetIP(ip);
break;
}
n++;
}
}
int listen_port = ParseInteger(argc, argv, "--listen_port");
if (listen_port != 0) {
listen_address.SetPort(listen_port);
}
return listen_address;
}
int main(int argc, char **argv)
{
// Log arguments
std::string args;
if (argc != 0) {
for (int i = 0; i < argc; i++) {
if (i != 0) {
args += " ";
}
args += argv[i];
}
} else {
args = "<none>";
}
RLOG() << "Arguments: " << args.c_str();
// Seed random number generator
srand((int)base::GetTickCount());
// Root of the pack cache
std::string rootdir = ParseString(argc, argv, "--missionpack_dir");
std::string packdir = rootdir + "/pack";
std::string indexfile = rootdir + "/index";
std::string modfile = rootdir + "/modlist";
std::string badwordsfile = rootdir + "/badwords";
// Initialize the level info cache from the index so the server knows
// the latest and greatest mission packs.
wi::PackManager packm(packdir.c_str());
packm.WatchIndex(indexfile.c_str());
wi::LevelInfoCache cache(packm);
// Submit main pack and packs from the index
wi::NoCachePackFileReader pakr;
if (pakr.Push(NULL, ParseString(argc, argv, "--htdata").c_str())) {
wi::PackId packid;
memset(&packid, 0, sizeof(packid));
packid.id = PACKID_MAIN;
cache.Submit(pakr, packid);
pakr.Pop();
}
cache.SubmitIndex(indexfile);
if (cache.empty()) {
RLOG() << "cache is empty!";
exit(1);
}
// Set up StatsPoster
base::SocketAddress stats_address(ParseString(argc, argv,
"--stats_address").c_str());
std::string stats_path(ParseString(argc, argv, "--stats_path"));
wi::StatsPoster stats(stats_address, stats_path);
// Set up the server
dword server_id = ParseDword(argc, argv, "--server_id");
bool checksync = FindArg(argc, argv, "--checksync");
RLOG() << "Sync checking turned " << (checksync ? "ON." : "OFF.");
bool accountsharing = FindArg(argc, argv, "--accountsharing");
RLOG() << "Account sharing turned " << (accountsharing ? "ON." : "OFF.");
std::string log_file = ParseString(argc, argv, "--log_file");
wi::XMsgLog *xmsglog = NULL;
if (log_file.size() != 0) {
xmsglog = new wi::XMsgLog(log_file);
}
int max_players = ParseInteger(argc, argv, "--max_players",
kcConnectedPlayersMax);
int max_rooms = ParseInteger(argc, argv, "--max_rooms", kcRoomsMax);
int max_games_per_room = ParseInteger(argc, argv, "--max_games_per_room",
kcGamesPerRoomMax);
int max_players_per_room = ParseInteger(argc, argv,
"--max_players_per_room", kcPlayersPerRoomMax);
wi::Server server(stats, xmsglog, cache, server_id, checksync,
max_rooms, max_games_per_room, max_players_per_room,
max_players, modfile, badwordsfile, accountsharing);
base::SocketAddress listen_address = GetListenAddress(argc, argv);
if (!server.Listen(listen_address)) {
printf("Server failed to start.\n");
return 1;
}
listen_address = server.listen_address();
// Create default rooms
dword result;
server.lobby().NewRoom(NULL, "Main", "", wi::kroomidMain,
wi::kfRmPermanent | wi::kfRmLocked, &result);
server.lobby().NewRoom(NULL, "Main / Registered", "", wi::kroomidRegistered,
wi::kfRmPermanent | wi::kfRmRegisteredOnly | wi::kfRmLocked,
&result);
server.lobby().NewRoom(NULL, "Main / Unmoderated", "",
wi::kroomidUnmoderated,
wi::kfRmPermanent | wi::kfRmLocked | wi::kfRmUnmoderated,
&result);
// Get the public_address. This is the address that gets sent in
// ServerInfo. For example in AWS, the internal "private" ip
// is not the same as the public one. If this is not present,
// use the listen_address.
base::SocketAddress public_address;
std::string public_address_str = ParseString(argc, argv, "--public_address");
if (public_address_str.size() != 0) {
public_address = base::SocketAddress(public_address_str.c_str());
} else {
public_address = listen_address;
}
// Start up ServerInfoUpdater
std::string server_info_path(ParseString(argc, argv, "--server_info_path"));
std::string server_name(ParseString(argc, argv, "--server_name"));
std::string server_location(ParseString(argc, argv, "--server_location"));
std::string server_type(ParseString(argc, argv, "--server_type"));
std::string server_info_extra(ParseString(argc, argv, "--server_info_extra"));
dword expires = ParseDword(argc, argv, "--server_info_expires", 60 * 5);
wi::ServerInfoUpdater updater(server, stats_address, server_info_path,
server_id, server_name, server_location, server_type,
public_address, server_info_extra, expires);
server.SetUpdater(&updater);
// Pump messages and wait for network i/o
base::Thread::RunLoop();
return 0;
}