|
|
//
|
|
|
// Created by koncord on 01.01.16.
|
|
|
//
|
|
|
|
|
|
#include <cstdlib>
|
|
|
|
|
|
#include <components/openmw-mp/Log.hpp>
|
|
|
#include <components/openmw-mp/Version.hpp>
|
|
|
|
|
|
#include <components/esm/esmwriter.hpp>
|
|
|
#include <components/files/escape.hpp>
|
|
|
|
|
|
#include "../mwbase/environment.hpp"
|
|
|
|
|
|
#include "../mwclass/creature.hpp"
|
|
|
#include "../mwclass/npc.hpp"
|
|
|
|
|
|
#include "../mwdialogue/dialoguemanagerimp.hpp"
|
|
|
|
|
|
#include "../mwgui/windowmanagerimp.hpp"
|
|
|
|
|
|
#include "../mwinput/inputmanagerimp.hpp"
|
|
|
|
|
|
#include "../mwmechanics/aitravel.hpp"
|
|
|
#include "../mwmechanics/creaturestats.hpp"
|
|
|
#include "../mwmechanics/mechanicsmanagerimp.hpp"
|
|
|
#include "../mwmechanics/spellcasting.hpp"
|
|
|
|
|
|
#include "../mwscript/scriptmanagerimp.hpp"
|
|
|
|
|
|
#include "../mwstate/statemanagerimp.hpp"
|
|
|
|
|
|
#include "../mwworld/cellstore.hpp"
|
|
|
#include "../mwworld/customdata.hpp"
|
|
|
#include "../mwworld/inventorystore.hpp"
|
|
|
#include "../mwworld/manualref.hpp"
|
|
|
#include "../mwworld/player.hpp"
|
|
|
#include "../mwworld/ptr.hpp"
|
|
|
#include "../mwworld/worldimp.hpp"
|
|
|
|
|
|
#include "Main.hpp"
|
|
|
#include "Networking.hpp"
|
|
|
#include "LocalPlayer.hpp"
|
|
|
#include "DedicatedPlayer.hpp"
|
|
|
#include "PlayerList.hpp"
|
|
|
#include "GUIController.hpp"
|
|
|
#include "CellController.hpp"
|
|
|
#include "MechanicsHelper.hpp"
|
|
|
|
|
|
using namespace mwmp;
|
|
|
using namespace std;
|
|
|
|
|
|
Main *Main::pMain = 0;
|
|
|
std::string Main::address = "";
|
|
|
std::string Main::serverPassword = TES3MP_DEFAULT_PASSW;
|
|
|
std::string Main::resourceDir = "";
|
|
|
|
|
|
std::string Main::getResDir()
|
|
|
{
|
|
|
return resourceDir;
|
|
|
}
|
|
|
|
|
|
std::string loadSettings(Settings::Manager& settings)
|
|
|
{
|
|
|
Files::ConfigurationManager mCfgMgr;
|
|
|
// Create the settings manager and load default settings file
|
|
|
const std::string localdefault = (mCfgMgr.getLocalPath() / "tes3mp-client-default.cfg").string();
|
|
|
const std::string globaldefault = (mCfgMgr.getGlobalPath() / "tes3mp-client-default.cfg").string();
|
|
|
|
|
|
// prefer local
|
|
|
if (boost::filesystem::exists(localdefault))
|
|
|
settings.loadDefault(localdefault);
|
|
|
else if (boost::filesystem::exists(globaldefault))
|
|
|
settings.loadDefault(globaldefault);
|
|
|
else
|
|
|
throw std::runtime_error ("No default settings file found! Make sure the file \"tes3mp-client-default.cfg\" was properly installed.");
|
|
|
|
|
|
// load user settings if they exist
|
|
|
const std::string settingspath = (mCfgMgr.getUserConfigPath() / "tes3mp-client.cfg").string();
|
|
|
if (boost::filesystem::exists(settingspath))
|
|
|
settings.loadUser(settingspath);
|
|
|
|
|
|
return settingspath;
|
|
|
}
|
|
|
|
|
|
Main::Main()
|
|
|
{
|
|
|
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "tes3mp started");
|
|
|
mNetworking = new Networking();
|
|
|
mLocalPlayer = new LocalPlayer();
|
|
|
mGUIController = new GUIController();
|
|
|
mCellController = new CellController();
|
|
|
|
|
|
server = "mp.tes3mp.com";
|
|
|
port = 25565;
|
|
|
}
|
|
|
|
|
|
Main::~Main()
|
|
|
{
|
|
|
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "tes3mp stopped");
|
|
|
delete mNetworking;
|
|
|
delete mLocalPlayer;
|
|
|
delete mCellController;
|
|
|
delete mGUIController;
|
|
|
PlayerList::cleanUp();
|
|
|
}
|
|
|
|
|
|
void Main::optionsDesc(boost::program_options::options_description *desc)
|
|
|
{
|
|
|
namespace bpo = boost::program_options;
|
|
|
desc->add_options()
|
|
|
("connect", bpo::value<std::string>()->default_value(""),
|
|
|
"connect to server (e.g. --connect=127.0.0.1:25565)")
|
|
|
("password", bpo::value<std::string>()->default_value(TES3MP_DEFAULT_PASSW),
|
|
|
"сonnect to a secured server. (e.g. --password=AnyPassword");
|
|
|
}
|
|
|
|
|
|
void Main::configure(const boost::program_options::variables_map &variables)
|
|
|
{
|
|
|
Main::address = variables["connect"].as<string>();
|
|
|
Main::serverPassword = variables["password"].as<string>();
|
|
|
resourceDir = variables["resources"].as<Files::EscapeHashString>().toStdString();
|
|
|
}
|
|
|
|
|
|
static Settings::CategorySettingValueMap saveUserSettings;
|
|
|
static Settings::CategorySettingValueMap saveDefaultSettings;
|
|
|
static Settings::CategorySettingVector saveChangedSettings;
|
|
|
|
|
|
void initializeManager(Settings::Manager &manager)
|
|
|
{
|
|
|
saveUserSettings = manager.mUserSettings;
|
|
|
saveDefaultSettings = manager.mDefaultSettings;
|
|
|
saveChangedSettings = manager.mChangedSettings;
|
|
|
manager.mUserSettings.clear();
|
|
|
manager.mDefaultSettings.clear();
|
|
|
manager.mChangedSettings.clear();
|
|
|
loadSettings(manager);
|
|
|
}
|
|
|
|
|
|
void restoreManager(Settings::Manager &manager)
|
|
|
{
|
|
|
manager.mUserSettings = saveUserSettings;
|
|
|
manager.mDefaultSettings = saveDefaultSettings;
|
|
|
manager.mChangedSettings = saveChangedSettings;
|
|
|
}
|
|
|
|
|
|
bool Main::init(std::vector<std::string> &content, Files::Collections &collections)
|
|
|
{
|
|
|
assert(!pMain);
|
|
|
pMain = new Main();
|
|
|
|
|
|
Settings::Manager manager;
|
|
|
initializeManager(manager);
|
|
|
|
|
|
int logLevel = manager.getInt("logLevel", "General");
|
|
|
Log::SetLevel(logLevel);
|
|
|
if (address.empty())
|
|
|
{
|
|
|
pMain->server = manager.getString("destinationAddress", "General");
|
|
|
pMain->port = (unsigned short) manager.getInt("port", "General");
|
|
|
|
|
|
serverPassword = manager.getString("password", "General");
|
|
|
if (serverPassword.empty())
|
|
|
serverPassword = TES3MP_DEFAULT_PASSW;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
size_t delimPos = address.find(':');
|
|
|
pMain->server = address.substr(0, delimPos);
|
|
|
pMain->port = atoi(address.substr(delimPos + 1).c_str());
|
|
|
}
|
|
|
get().mLocalPlayer->serverPassword = serverPassword;
|
|
|
|
|
|
pMain->mNetworking->connect(pMain->server, pMain->port, content, collections);
|
|
|
restoreManager(manager);
|
|
|
return pMain->mNetworking->isConnected();
|
|
|
}
|
|
|
|
|
|
void Main::postInit()
|
|
|
{
|
|
|
Settings::Manager manager;
|
|
|
initializeManager(manager);
|
|
|
|
|
|
pMain->mGUIController->setupChat(manager);
|
|
|
restoreManager(manager);
|
|
|
|
|
|
const MWBase::Environment &environment = MWBase::Environment::get();
|
|
|
environment.getStateManager()->newGame(true);
|
|
|
MWBase::Environment::get().getMechanicsManager()->toggleAI();
|
|
|
}
|
|
|
|
|
|
void Main::destroy()
|
|
|
{
|
|
|
assert(pMain);
|
|
|
|
|
|
delete pMain;
|
|
|
pMain = 0;
|
|
|
}
|
|
|
|
|
|
void Main::frame(float dt)
|
|
|
{
|
|
|
get().getNetworking()->update();
|
|
|
|
|
|
PlayerList::update(dt);
|
|
|
get().getCellController()->updateDedicated(dt);
|
|
|
get().updateWorld(dt);
|
|
|
|
|
|
get().getGUIController()->update(dt);
|
|
|
|
|
|
}
|
|
|
|
|
|
void Main::updateWorld(float dt) const
|
|
|
{
|
|
|
|
|
|
if (!mLocalPlayer->processCharGen())
|
|
|
return;
|
|
|
|
|
|
static bool init = true;
|
|
|
if (init)
|
|
|
{
|
|
|
init = false;
|
|
|
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Sending ID_PLAYER_BASEINFO to server");
|
|
|
|
|
|
mNetworking->getPlayerPacket(ID_PLAYER_BASEINFO)->setPlayer(getLocalPlayer());
|
|
|
mNetworking->getPlayerPacket(ID_LOADED)->setPlayer(getLocalPlayer());
|
|
|
mNetworking->getPlayerPacket(ID_PLAYER_BASEINFO)->Send();
|
|
|
mNetworking->getPlayerPacket(ID_LOADED)->Send();
|
|
|
mLocalPlayer->updateStatsDynamic(true);
|
|
|
get().getGUIController()->setChatVisible(true);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
mLocalPlayer->update();
|
|
|
mCellController->updateLocal(false);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
const Main &Main::get()
|
|
|
{
|
|
|
return *pMain;
|
|
|
}
|
|
|
|
|
|
Networking *Main::getNetworking() const
|
|
|
{
|
|
|
return mNetworking;
|
|
|
}
|
|
|
|
|
|
LocalPlayer *Main::getLocalPlayer() const
|
|
|
{
|
|
|
return mLocalPlayer;
|
|
|
}
|
|
|
|
|
|
|
|
|
GUIController *Main::getGUIController() const
|
|
|
{
|
|
|
return mGUIController;
|
|
|
}
|
|
|
|
|
|
CellController *Main::getCellController() const
|
|
|
{
|
|
|
return mCellController;
|
|
|
}
|
|
|
|
|
|
void Main::pressedKey(int key)
|
|
|
{
|
|
|
if (pMain == nullptr) return;
|
|
|
if (get().getGUIController()->pressedKey(key))
|
|
|
return; // if any gui bind pressed
|
|
|
}
|
|
|
|
|
|
// When sending packets with ingame script values, certain packets
|
|
|
// should be ignored because of their potential for spam
|
|
|
bool Main::isValidPacketScript(std::string script)
|
|
|
{
|
|
|
static const int validPacketScriptsCount = 21;
|
|
|
static const std::string validPacketScripts[validPacketScriptsCount] = {
|
|
|
// Ghostgate buttons
|
|
|
"GG_OpenGate1", // coc Ghostgate
|
|
|
"GG_OpenGate2",
|
|
|
// Dwemer ruin cranks
|
|
|
"Arkn_doors", // coe 0, -2
|
|
|
"nchuleftingthWrong1", // coc "Nchuleftingth, Test of Pattern"
|
|
|
"nchuleftingthWrong2",
|
|
|
"nchulfetingthRight",
|
|
|
"Akula_innerdoors", // coc "Akulakhan's Chamber"
|
|
|
"Dagoth_doors", // coe 2, 8
|
|
|
// Sotha Sil levers
|
|
|
"SothaLever1", // coc "Sotha Sil, Outer Flooded Halls"
|
|
|
"SothaLever2",
|
|
|
"SothaLever3",
|
|
|
"SothaLever4",
|
|
|
"SothaLever5",
|
|
|
"SothaLever6",
|
|
|
"SothaLever7",
|
|
|
"SothaLever8",
|
|
|
"SothaLever9",
|
|
|
"SothaLever10",
|
|
|
"SothaLever11",
|
|
|
"SothaOilLever", // coc "Sotha Sil, Dome of Udok"
|
|
|
// Generic state script
|
|
|
"LocalState"
|
|
|
};
|
|
|
|
|
|
static const int invalidPacketScriptsCount = 17;
|
|
|
static const std::string invalidPacketScripts[invalidPacketScriptsCount] = {
|
|
|
// Spammy shorts
|
|
|
"OutsideBanner",
|
|
|
"sleeperScript",
|
|
|
"dreamer_talkerEnable",
|
|
|
"drenSlaveOwners",
|
|
|
"ahnassiScript",
|
|
|
"hlormarScript",
|
|
|
// Spammy floats
|
|
|
"Float",
|
|
|
"SignRotate",
|
|
|
"FaluraScript",
|
|
|
"jsaddhaScript",
|
|
|
// Spammy globals
|
|
|
"wraithguardScript",
|
|
|
// Spammy globals leading to crashes
|
|
|
"LegionUniform",
|
|
|
"OrdinatorUniform",
|
|
|
"LorkhanHeart",
|
|
|
"ouch_keening",
|
|
|
"ouch_sunder",
|
|
|
"ouch_wraithguard"
|
|
|
};
|
|
|
|
|
|
for (const auto &validPacketScript : validPacketScripts)
|
|
|
{
|
|
|
if (Misc::StringUtils::ciEqual(script, validPacketScript))
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
|
|
|
/* Switch over to this when using a blacklist system
|
|
|
for (int i = 0; i < invalidPacketScriptsCount; i++)
|
|
|
{
|
|
|
if (Misc::StringUtils::ciEqual(script, invalidPacketScripts[i]))
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
*/
|
|
|
}
|