mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-15 22:19:54 +00:00
1b1e5e86d1
Although b4e8560698
made players instantly able to see each other on minimalist servers that did not change their cells from the default, it created problems with the default CoreScripts where players need to be logged in before receipt of a CellStates packet from them is taken into account, with the result being that a player was recorded as having loaded their initial cells on the server's C++ side but not on the Lua side.
It may simply be best to expect servers to set player cells.
347 lines
9.2 KiB
C++
347 lines
9.2 KiB
C++
//
|
||
// 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::addr = "";
|
||
std::string Main::passw = 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();
|
||
//mLocalPlayer->CharGen(0, 4);
|
||
|
||
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::addr = variables["connect"].as<string>();
|
||
Main::passw = variables["password"].as<string>();
|
||
resourceDir = variables["resources"].as<Files::EscapeHashString>().toStdString();
|
||
}
|
||
|
||
static Settings::CategorySettingValueMap saveUserSettings;
|
||
static Settings::CategorySettingValueMap saveDefaultSettings;
|
||
static Settings::CategorySettingVector saveChangedSettings;
|
||
|
||
void InitMgr(Settings::Manager &mgr)
|
||
{
|
||
saveUserSettings = mgr.mUserSettings;
|
||
saveDefaultSettings = mgr.mDefaultSettings;
|
||
saveChangedSettings = mgr.mChangedSettings;
|
||
mgr.mUserSettings.clear();
|
||
mgr.mDefaultSettings.clear();
|
||
mgr.mChangedSettings.clear();
|
||
loadSettings(mgr);
|
||
}
|
||
|
||
void RestoreMgr(Settings::Manager &mgr)
|
||
{
|
||
mgr.mUserSettings = saveUserSettings;
|
||
mgr.mDefaultSettings = saveDefaultSettings;
|
||
mgr.mChangedSettings = saveChangedSettings;
|
||
}
|
||
|
||
bool Main::init(std::vector<std::string> &content, Files::Collections &collections)
|
||
{
|
||
assert(!pMain);
|
||
pMain = new Main();
|
||
|
||
Settings::Manager mgr;
|
||
InitMgr(mgr);
|
||
|
||
int logLevel = mgr.getInt("logLevel", "General");
|
||
Log::SetLevel(logLevel);
|
||
if (addr.empty())
|
||
{
|
||
pMain->server = mgr.getString("destinationAddress", "General");
|
||
pMain->port = (unsigned short) mgr.getInt("port", "General");
|
||
|
||
passw = mgr.getString("password", "General");
|
||
if (passw.empty())
|
||
passw = TES3MP_DEFAULT_PASSW;
|
||
}
|
||
else
|
||
{
|
||
size_t delim_pos = addr.find(':');
|
||
pMain->server = addr.substr(0, delim_pos);
|
||
pMain->port = atoi(addr.substr(delim_pos + 1).c_str());
|
||
}
|
||
get().mLocalPlayer->passw = passw;
|
||
|
||
pMain->mNetworking->connect(pMain->server, pMain->port, content, collections);
|
||
RestoreMgr(mgr);
|
||
return pMain->mNetworking->isConnected();
|
||
}
|
||
|
||
void Main::postInit()
|
||
{
|
||
Settings::Manager mgr;
|
||
InitMgr(mgr);
|
||
|
||
pMain->mGUIController->setupChat(mgr);
|
||
RestoreMgr(mgr);
|
||
|
||
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;
|
||
*/
|
||
}
|