You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openmw-tes3mp/apps/openmw/mwmp/Main.cpp

347 lines
9.4 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

//
// 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;
*/
}