Compare commits

...

22 commits

Author SHA1 Message Date
David Cernat
8aad93b904
Merge pull request #519 from TES3MP/0.7.0-alpha
[General] Update positions for dead players on other clients
2019-03-24 03:54:43 +02:00
David Cernat
3effd5f1ff [General] Update positions for dead players on other clients
Dead players will now show up at the correct cell and position for living players, making server scripts that allow players to revive each other much more functional.
2019-03-24 03:52:05 +02:00
David Cernat
4692f29b9d
Merge pull request #517 from uramer/0.7.0markers
update player map markers when client changes cell
2019-03-22 21:39:06 +02:00
David Cernat
03d377ec54
Merge pull request #518 from TES3MP/0.7.0-alpha
[General] Rename CellReplace packet into CellReset
2019-03-22 21:36:07 +02:00
David Cernat
8ff2d1b829 [General] Rename CellReplace packet into CellReset 2019-03-22 21:33:34 +02:00
David Cernat
cb82318c36 [General] Fix problems with Utils::getArchitectureType() 2019-03-22 03:09:11 +02:00
uramer
3b2098382b update player map markers when client changes cell 2019-03-21 16:27:15 +01:00
David Cernat
cb5e24e6c5
Merge pull request #516 from TES3MP/0.7.0-alpha
[Server] Add GetMillisecondsSinceServerStart() server function
2019-03-20 20:05:30 +02:00
David Cernat
91f82d845c [Server] Add GetMillisecondsSinceServerStart() server function 2019-03-20 20:02:31 +02:00
David Cernat
d35026bbf5
Merge pull request #515 from TES3MP/0.7.0-alpha
0.7.0 alpha
2019-03-20 18:58:31 +02:00
David Cernat
bd677726bf [Server] Add StatsFunctions that get/set damage to attributes/skills 2019-03-20 18:54:35 +02:00
David Cernat
9fc4c83858 [Client] Send skill/attribute packets when skills/attributes are damaged 2019-03-20 18:40:46 +02:00
David Cernat
ece39748de [Server] Fix typo causing recursion in deprecated actor list function 2019-03-20 17:01:21 +02:00
David Cernat
5c4d3df551 [Server] Deprecate DoesFileExist(), add DoesFilePathExist() 2019-03-19 04:52:58 +02:00
David Cernat
2cdabddc0e [Server] Move most MiscellaneousFunctions to ServerFunctions 2019-03-19 04:25:33 +02:00
David Cernat
b46767de6e [Server] Clean up recent additions to ServerFunctions 2019-03-19 03:57:16 +02:00
David Cernat
911079e0bc
Merge pull request #512 from TES3MP/0.7.0-alpha
0.7.0 alpha
2019-03-12 05:38:36 +02:00
David Cernat
331fa86844 [Server] Call OnServerPostInit after OnRequestDataFileList
This allows different actions to be taken in OnServerPostInit based on what the data files being used are.
2019-03-12 05:36:33 +02:00
David Cernat
a0ec9dfd2e [Server] Rename OnRequestPluginList into OnRequestDataFileList 2019-03-12 03:18:57 +02:00
David Cernat
986528c67d [Server] Add error message as argument to OnServerScriptCrash 2019-03-12 02:15:20 +02:00
David Cernat
552a94a0ca [Server] Add OnServerScriptCrash script event 2019-03-10 00:46:40 +02:00
David Cernat
a508a0faf8 [Server] Turn GetArguments() from ScriptFunctions into Utils function 2019-02-24 01:43:04 +02:00
30 changed files with 424 additions and 271 deletions

View file

@ -585,8 +585,8 @@ void Networking::InitQuery(std::string queryAddr, unsigned short queryPort)
void Networking::postInit()
{
Script::Call<Script::CallbackIdentity("OnRequestDataFileList")>();
Script::Call<Script::CallbackIdentity("OnServerPostInit")>();
Script::Call<Script::CallbackIdentity("OnRequestPluginList")>();
}
PacketPreInit::PluginContainer &Networking::getSamples()

View file

@ -537,7 +537,7 @@ void ActorFunctions::InitializeActorList(unsigned short pid) noexcept
void ActorFunctions::CopyLastActorListToStore() noexcept
{
CopyLastActorListToStore();
CopyReceivedActorListToStore();
}
unsigned int ActorFunctions::GetActorRefNumIndex(unsigned int index) noexcept

View file

@ -1,38 +1,12 @@
#include "Miscellaneous.hpp"
#include <components/misc/stringops.hpp>
#include <components/openmw-mp/Log.hpp>
#include <apps/openmw-mp/Script/ScriptFunctions.hpp>
#include <apps/openmw-mp/Networking.hpp>
#include <iostream>
using namespace std;
static std::string tempFilename;
bool MiscellaneousFunctions::DoesFileExist(const char *filePath) noexcept
{
return boost::filesystem::exists(filePath);
}
const char *MiscellaneousFunctions::GetCaseInsensitiveFilename(const char *folderPath, const char *filename) noexcept
{
if (!boost::filesystem::exists(folderPath)) return "invalid";
boost::filesystem::directory_iterator end_itr; // default construction yields past-the-end
for (boost::filesystem::directory_iterator itr(folderPath); itr != end_itr; ++itr)
{
if (Misc::StringUtils::ciEqual(itr->path().filename().string(), filename))
{
tempFilename = itr->path().filename().string();
return tempFilename.c_str();
}
}
return "invalid";
}
unsigned int MiscellaneousFunctions::GetLastPlayerId() noexcept
{
return Players::getLastPlayerId();
@ -47,13 +21,3 @@ void MiscellaneousFunctions::SetCurrentMpNum(int mpNum) noexcept
{
mwmp::Networking::getPtr()->setCurrentMpNum(mpNum);
}
void MiscellaneousFunctions::LogMessage(unsigned short level, const char *message) noexcept
{
LOG_MESSAGE_SIMPLE(level, "[Script]: %s", message);
}
void MiscellaneousFunctions::LogAppend(unsigned short level, const char *message) noexcept
{
LOG_APPEND(level, "[Script]: %s", message);
}

View file

@ -4,42 +4,15 @@
#include "../Types.hpp"
#define MISCELLANEOUSAPI \
{"DoesFileExist", MiscellaneousFunctions::DoesFileExist},\
{"GetCaseInsensitiveFilename", MiscellaneousFunctions::GetCaseInsensitiveFilename},\
\
{"GetLastPlayerId", MiscellaneousFunctions::GetLastPlayerId},\
\
{"GetCurrentMpNum", MiscellaneousFunctions::GetCurrentMpNum},\
{"SetCurrentMpNum", MiscellaneousFunctions::SetCurrentMpNum},\
\
{"LogMessage", MiscellaneousFunctions::LogMessage},\
{"LogAppend", MiscellaneousFunctions::LogAppend}
{"SetCurrentMpNum", MiscellaneousFunctions::SetCurrentMpNum}
class MiscellaneousFunctions
{
public:
/**
* \brief Check whether a certain file exists.
*
* This will be a case sensitive check on case sensitive filesystems.
*
* Whenever you want to enforce case insensitivity, use GetCaseInsensitiveFilename() instead.
*
* \return Whether the file exists or not.
*/
static bool DoesFileExist(const char *filePath) noexcept;
/**
* \brief Get the first filename in a folder that has a case insensitive match with the filename
* argument.
*
* This is used to retain case insensitivity when opening data files on Linux.
*
* \return The filename that matches.
*/
static const char *GetCaseInsensitiveFilename(const char *folderPath, const char *filename) noexcept;
/**
* \brief Get the last player ID currently connected to the server.
*
@ -75,30 +48,6 @@ public:
* \return void
*/
static void SetCurrentMpNum(int mpNum) noexcept;
/**
* \brief Write a log message with its own timestamp.
*
* It will have "[Script]:" prepended to it so as to mark it as a script-generated log message.
*
* \param level The logging level used (0 for LOG_VERBOSE, 1 for LOG_INFO, 2 for LOG_WARN,
* 3 for LOG_ERROR, 4 for LOG_FATAL).
* \param message The message logged.
* \return void
*/
static void LogMessage(unsigned short level, const char *message) noexcept;
/**
* \brief Write a log message without its own timestamp.
*
* It will have "[Script]:" prepended to it so as to mark it as a script-generated log message.
*
* \param level The logging level used (0 for LOG_VERBOSE, 1 for LOG_INFO, 2 for LOG_WARN,
* 3 for LOG_ERROR, 4 for LOG_FATAL).
* \param message The message logged.
* \return void
*/
static void LogAppend(unsigned short level, const char *message) noexcept;
};
#endif //OPENMW_MISCELLANEOUSAPI_HPP

View file

@ -1,5 +1,6 @@
#include "Server.hpp"
#include <components/misc/stringops.hpp>
#include <components/openmw-mp/NetworkMessages.hpp>
#include <components/openmw-mp/Log.hpp>
#include <components/openmw-mp/Version.hpp>
@ -9,6 +10,18 @@
#include <apps/openmw-mp/MasterClient.hpp>
#include <Script/Script.hpp>
static std::string tempFilename;
static std::chrono::high_resolution_clock::time_point startupTime = std::chrono::high_resolution_clock::now();
void ServerFunctions::LogMessage(unsigned short level, const char *message) noexcept
{
LOG_MESSAGE_SIMPLE(level, "[Script]: %s", message);
}
void ServerFunctions::LogAppend(unsigned short level, const char *message) noexcept
{
LOG_APPEND(level, "[Script]: %s", message);
}
void ServerFunctions::StopServer(int code) noexcept
{
@ -35,6 +48,40 @@ void ServerFunctions::UnbanAddress(const char *ipAddress) noexcept
mwmp::Networking::getPtr()->unbanAddress(ipAddress);
}
bool ServerFunctions::DoesFilePathExist(const char *filePath) noexcept
{
return boost::filesystem::exists(filePath);
}
const char *ServerFunctions::GetCaseInsensitiveFilename(const char *folderPath, const char *filename) noexcept
{
if (!boost::filesystem::exists(folderPath)) return "invalid";
boost::filesystem::directory_iterator end_itr; // default construction yields past-the-end
for (boost::filesystem::directory_iterator itr(folderPath); itr != end_itr; ++itr)
{
if (Misc::StringUtils::ciEqual(itr->path().filename().string(), filename))
{
tempFilename = itr->path().filename().string();
return tempFilename.c_str();
}
}
return "invalid";
}
const char* ServerFunctions::GetDataPath() noexcept
{
return Script::GetModDir();
}
unsigned int ServerFunctions::GetMillisecondsSinceServerStart() noexcept
{
std::chrono::high_resolution_clock::time_point currentTime = std::chrono::high_resolution_clock::now();
std::chrono::milliseconds milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(currentTime - startupTime);
return milliseconds.count();
}
const char *ServerFunctions::GetOperatingSystemType() noexcept
{
return Utils::getOperatingSystemType().c_str();
@ -137,34 +184,46 @@ void ServerFunctions::SetRuleValue(const char *key, double value) noexcept
mc->SetRuleValue(key, value);
}
void ServerFunctions::AddPluginHash(const char *pluginName, const char *hashStr) noexcept
void ServerFunctions::AddDataFileRequirement(const char *dataFilename, const char *checksumString) noexcept
{
auto &samples = mwmp::Networking::getPtr()->getSamples();
auto it = std::find_if(samples.begin(), samples.end(), [&pluginName](mwmp::PacketPreInit::PluginPair &item) {
return item.first == pluginName;
auto it = std::find_if(samples.begin(), samples.end(), [&dataFilename](mwmp::PacketPreInit::PluginPair &item) {
return item.first == dataFilename;
});
if (it != samples.end())
it->second.push_back((unsigned) std::stoul(hashStr));
it->second.push_back((unsigned) std::stoul(checksumString));
else
{
mwmp::PacketPreInit::HashList hashList;
mwmp::PacketPreInit::HashList checksumList;
unsigned hash = 0;
unsigned checksum = 0;
if (strlen(hashStr) != 0)
if (strlen(checksumString) != 0)
{
hash = (unsigned) std::stoul(hashStr);
hashList.push_back(hash);
checksum = (unsigned) std::stoul(checksumString);
checksumList.push_back(checksum);
}
samples.emplace_back(pluginName, hashList);
samples.emplace_back(dataFilename, checksumList);
auto mclient = mwmp::Networking::getPtr()->getMasterClient();
if (mclient)
mclient->PushPlugin({pluginName, hash});
mclient->PushPlugin({dataFilename, checksum});
}
}
// All methods below are deprecated versions of methods from above
bool ServerFunctions::DoesFileExist(const char *filePath) noexcept
{
return DoesFilePathExist(filePath);
}
const char* ServerFunctions::GetModDir() noexcept
{
return Script::GetModDir();
return GetDataPath();
}
void ServerFunctions::AddPluginHash(const char *pluginName, const char *checksumString) noexcept
{
AddDataFileRequirement(pluginName, checksumString);
}

View file

@ -4,38 +4,73 @@
#include "../Types.hpp"
#define SERVERAPI \
{"StopServer", ServerFunctions::StopServer},\
{"LogMessage", ServerFunctions::LogMessage},\
{"LogAppend", ServerFunctions::LogAppend},\
\
{"Kick", ServerFunctions::Kick},\
{"BanAddress", ServerFunctions::BanAddress},\
{"UnbanAddress", ServerFunctions::UnbanAddress},\
{"StopServer", ServerFunctions::StopServer},\
\
{"GetOperatingSystemType", ServerFunctions::GetOperatingSystemType},\
{"GetArchitectureType", ServerFunctions::GetArchitectureType},\
{"GetServerVersion", ServerFunctions::GetServerVersion},\
{"GetProtocolVersion", ServerFunctions::GetProtocolVersion},\
{"GetAvgPing", ServerFunctions::GetAvgPing},\
{"GetIP", ServerFunctions::GetIP},\
{"GetMaxPlayers", ServerFunctions::GetMaxPlayers},\
{"GetPort", ServerFunctions::GetPort},\
{"HasPassword", ServerFunctions::HasPassword},\
{"GetPluginEnforcementState", ServerFunctions::GetPluginEnforcementState},\
{"GetScriptErrorIgnoringState", ServerFunctions::GetScriptErrorIgnoringState},\
{"Kick", ServerFunctions::Kick},\
{"BanAddress", ServerFunctions::BanAddress},\
{"UnbanAddress", ServerFunctions::UnbanAddress},\
\
{"SetGameMode", ServerFunctions::SetGameMode},\
{"SetHostname", ServerFunctions::SetHostname},\
{"SetServerPassword", ServerFunctions::SetServerPassword},\
{"SetPluginEnforcementState", ServerFunctions::SetPluginEnforcementState},\
{"SetScriptErrorIgnoringState", ServerFunctions::SetScriptErrorIgnoringState},\
{"SetRuleString", ServerFunctions::SetRuleString},\
{"SetRuleValue", ServerFunctions::SetRuleValue},\
{"AddPluginHash", ServerFunctions::AddPluginHash},\
{"GetModDir", ServerFunctions::GetModDir}
{"DoesFilePathExist", ServerFunctions::DoesFilePathExist},\
{"GetCaseInsensitiveFilename", ServerFunctions::GetCaseInsensitiveFilename},\
{"GetDataPath", ServerFunctions::GetDataPath},\
{"GetMillisecondsSinceServerStart", ServerFunctions::GetMillisecondsSinceServerStart},\
{"GetOperatingSystemType", ServerFunctions::GetOperatingSystemType},\
{"GetArchitectureType", ServerFunctions::GetArchitectureType},\
{"GetServerVersion", ServerFunctions::GetServerVersion},\
{"GetProtocolVersion", ServerFunctions::GetProtocolVersion},\
{"GetAvgPing", ServerFunctions::GetAvgPing},\
{"GetIP", ServerFunctions::GetIP},\
{"GetMaxPlayers", ServerFunctions::GetMaxPlayers},\
{"GetPort", ServerFunctions::GetPort},\
{"HasPassword", ServerFunctions::HasPassword},\
{"GetPluginEnforcementState", ServerFunctions::GetPluginEnforcementState},\
{"GetScriptErrorIgnoringState", ServerFunctions::GetScriptErrorIgnoringState},\
\
{"SetGameMode", ServerFunctions::SetGameMode},\
{"SetHostname", ServerFunctions::SetHostname},\
{"SetServerPassword", ServerFunctions::SetServerPassword},\
{"SetPluginEnforcementState", ServerFunctions::SetPluginEnforcementState},\
{"SetScriptErrorIgnoringState", ServerFunctions::SetScriptErrorIgnoringState},\
{"SetRuleString", ServerFunctions::SetRuleString},\
{"SetRuleValue", ServerFunctions::SetRuleValue},\
\
{"AddDataFileRequirement", ServerFunctions::AddDataFileRequirement},\
\
{"DoesFileExist", ServerFunctions::DoesFileExist},\
{"GetModDir", ServerFunctions::GetModDir},\
{"AddPluginHash", ServerFunctions::AddPluginHash}
class ServerFunctions
{
public:
/**
* \brief Write a log message with its own timestamp.
*
* It will have "[Script]:" prepended to it so as to mark it as a script-generated log message.
*
* \param level The logging level used (0 for LOG_VERBOSE, 1 for LOG_INFO, 2 for LOG_WARN,
* 3 for LOG_ERROR, 4 for LOG_FATAL).
* \param message The message logged.
* \return void
*/
static void LogMessage(unsigned short level, const char *message) noexcept;
/**
* \brief Write a log message without its own timestamp.
*
* It will have "[Script]:" prepended to it so as to mark it as a script-generated log message.
*
* \param level The logging level used (0 for LOG_VERBOSE, 1 for LOG_INFO, 2 for LOG_WARN,
* 3 for LOG_ERROR, 4 for LOG_FATAL).
* \param message The message logged.
* \return void
*/
static void LogAppend(unsigned short level, const char *message) noexcept;
/**
* \brief Shut down the server.
*
@ -68,6 +103,41 @@ public:
*/
static void UnbanAddress(const char *ipAddress) noexcept;
/**
* \brief Check whether a certain file path exists.
*
* This will be a case sensitive check on case sensitive filesystems.
*
* Whenever you want to enforce case insensitivity, use GetCaseInsensitiveFilename() instead.
*
* \return Whether the file exists or not.
*/
static bool DoesFilePathExist(const char *filePath) noexcept;
/**
* \brief Get the first filename in a folder that has a case insensitive match with the filename
* argument.
*
* This is used to retain case insensitivity when opening data files on Linux.
*
* \return The filename that matches.
*/
static const char *GetCaseInsensitiveFilename(const char *folderPath, const char *filename) noexcept;
/**
* \brief Get the path of the server's data folder.
*
* \return The data path.
*/
static const char *GetDataPath() noexcept;
/**
* \brief Get the milliseconds elapsed since the server was started.
*
* \return The time since the server's startup in milliseconds.
*/
static unsigned int GetMillisecondsSinceServerStart() noexcept;
/**
* \brief Get the type of the operating system used by the server.
*
@ -119,7 +189,7 @@ public:
/**
* \brief Get the port used by the server.
*
* \return Port
* \return The port.
*/
static unsigned short GetPort() noexcept;
@ -220,13 +290,24 @@ public:
static void SetRuleValue(const char *key, double value) noexcept;
/**
* \brief Adds plugins to the internal server structure to validate players.
* @param pluginName Name with extension of the plugin or master file.
* @param hash Hash string
* \brief Add a data file and a corresponding CRC32 checksum to the data file loadout
* that connecting clients need to match.
*
* It can be used multiple times to set multiple checksums for the same data file.
*
* Note: If an empty string is provided for the checksum, a checksum will not be
* required for that data file.
*
* @param dataFilename The filename of the data file.
* @param checksumString A string with the CRC32 checksum required.
*/
static void AddPluginHash(const char *pluginName, const char *hash) noexcept;
static void AddDataFileRequirement(const char *dataFilename, const char *checksumString) noexcept;
// All methods below are deprecated versions of methods from above
static bool DoesFileExist(const char *filePath) noexcept;
static const char *GetModDir() noexcept;
static void AddPluginHash(const char *pluginName, const char *checksumString) noexcept;
};
#endif //OPENMW_SERVERAPI_HPP

View file

@ -201,6 +201,17 @@ int StatsFunctions::GetAttributeModifier(unsigned short pid, unsigned short attr
return player->creatureStats.mAttributes[attributeId].mMod;
}
double StatsFunctions::GetAttributeDamage(unsigned short pid, unsigned short attributeId) noexcept
{
Player *player;
GET_PLAYER(pid, player, 0);
if (attributeId >= Attribute::Length)
return 0;
return player->creatureStats.mAttributes[attributeId].mDamage;
}
int StatsFunctions::GetSkillBase(unsigned short pid, unsigned short skillId) noexcept
{
Player *player;
@ -223,6 +234,17 @@ int StatsFunctions::GetSkillModifier(unsigned short pid, unsigned short skillId)
return player->npcStats.mSkills[skillId].mMod;
}
double StatsFunctions::GetSkillDamage(unsigned short pid, unsigned short skillId) noexcept
{
Player *player;
GET_PLAYER(pid, player, 0);
if (skillId >= Skill::Length)
return 0;
return player->npcStats.mSkills[skillId].mDamage;
}
double StatsFunctions::GetSkillProgress(unsigned short pid, unsigned short skillId) noexcept
{
Player *player;
@ -437,6 +459,20 @@ void StatsFunctions::ClearAttributeModifier(unsigned short pid, unsigned short a
player->attributeIndexChanges.push_back(attributeId);
}
void StatsFunctions::SetAttributeDamage(unsigned short pid, unsigned short attributeId, double value) noexcept
{
Player *player;
GET_PLAYER(pid, player, );
if (attributeId >= Attribute::Length)
return;
player->creatureStats.mAttributes[attributeId].mDamage = value;
if (!Utils::vectorContains(player->attributeIndexChanges, attributeId))
player->attributeIndexChanges.push_back(attributeId);
}
void StatsFunctions::SetSkillBase(unsigned short pid, unsigned short skillId, int value) noexcept
{
Player *player;
@ -465,6 +501,20 @@ void StatsFunctions::ClearSkillModifier(unsigned short pid, unsigned short skill
player->skillIndexChanges.push_back(skillId);
}
void StatsFunctions::SetSkillDamage(unsigned short pid, unsigned short skillId, double value) noexcept
{
Player *player;
GET_PLAYER(pid, player, );
if (skillId >= Skill::Length)
return;
player->npcStats.mSkills[skillId].mDamage = value;
if (!Utils::vectorContains(player->skillIndexChanges, skillId))
player->skillIndexChanges.push_back(skillId);
}
void StatsFunctions::SetSkillProgress(unsigned short pid, unsigned short skillId, double value) noexcept
{
Player *player;

View file

@ -30,9 +30,11 @@
\
{"GetAttributeBase", StatsFunctions::GetAttributeBase},\
{"GetAttributeModifier", StatsFunctions::GetAttributeModifier},\
{"GetAttributeDamage", StatsFunctions::GetAttributeDamage},\
\
{"GetSkillBase", StatsFunctions::GetSkillBase},\
{"GetSkillModifier", StatsFunctions::GetSkillModifier},\
{"GetSkillDamage", StatsFunctions::GetSkillDamage},\
{"GetSkillProgress", StatsFunctions::GetSkillProgress},\
{"GetSkillIncrease", StatsFunctions::GetSkillIncrease},\
\
@ -58,9 +60,11 @@
\
{"SetAttributeBase", StatsFunctions::SetAttributeBase},\
{"ClearAttributeModifier", StatsFunctions::ClearAttributeModifier},\
{"SetAttributeDamage", StatsFunctions::SetAttributeDamage},\
\
{"SetSkillBase", StatsFunctions::SetSkillBase},\
{"ClearSkillModifier", StatsFunctions::ClearSkillModifier},\
{"SetSkillDamage", StatsFunctions::SetSkillDamage},\
{"SetSkillProgress", StatsFunctions::SetSkillProgress},\
{"SetSkillIncrease", StatsFunctions::SetSkillIncrease},\
\
@ -267,6 +271,16 @@ public:
*/
static int GetAttributeModifier(unsigned short pid, unsigned short attributeId) noexcept;
/**
* \brief Get the amount of damage (as caused through the Damage Attribute effect)
* to a player's attribute.
*
* \param pid The player ID.
* \param attributeId The attribute ID.
* \return The amount of damage to the attribute.
*/
static double GetAttributeDamage(unsigned short pid, unsigned short attributeId) noexcept;
/**
* \brief Get the base value of a player's skill.
*
@ -285,6 +299,16 @@ public:
*/
static int GetSkillModifier(unsigned short pid, unsigned short skillId) noexcept;
/**
* \brief Get the amount of damage (as caused through the Damage Skill effect)
* to a player's skill.
*
* \param pid The player ID.
* \param skillId The skill ID.
* \return The amount of damage to the skill.
*/
static double GetSkillDamage(unsigned short pid, unsigned short skillId) noexcept;
/**
* \brief Get the progress the player has made towards increasing a certain skill by 1.
*
@ -477,6 +501,17 @@ public:
*/
static void ClearAttributeModifier(unsigned short pid, unsigned short attributeId) noexcept;
/**
* \brief Set the amount of damage (as caused through the Damage Attribute effect) to
* a player's attribute.
*
* \param pid The player ID.
* \param attributeId The attribute ID.
* \param value The amount of damage to the player's attribute.
* \return void
*/
static void SetAttributeDamage(unsigned short pid, unsigned short attributeId, double value) noexcept;
/**
* \brief Set the base value of a player's skill.
*
@ -501,6 +536,17 @@ public:
*/
static void ClearSkillModifier(unsigned short pid, unsigned short skillId) noexcept;
/**
* \brief Set the amount of damage (as caused through the Damage Skill effect) to
* a player's skill.
*
* \param pid The player ID.
* \param skillId The skill ID.
* \param value The amount of damage to the player's skill.
* \return void
*/
static void SetSkillDamage(unsigned short pid, unsigned short skillId, double value) noexcept;
/**
* \brief Set the progress the player has made towards increasing a certain skill by 1.
*

View file

@ -21,7 +21,7 @@ int ScriptFunctions::CreateTimerEx(ScriptFunc callback, int msec, const char *ty
try
{
vector<boost::any> params;
GetArguments(params, args, types);
Utils::getArguments(params, args, types);
return mwmp::TimerAPI::CreateTimer(callback, msec, types, params);
}

View file

@ -105,6 +105,7 @@ public:
catch (std::exception &e)
{
LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, e.what());
Script::Call<Script::CallbackIdentity("OnServerScriptCrash")>(e.what());
if (!mwmp::Networking::getPtr()->getScriptErrorIgnoringState())
throw;

View file

@ -13,62 +13,6 @@ constexpr ScriptCallbackData ScriptFunctions::callbacks[];
using namespace std;
void ScriptFunctions::GetArguments(std::vector<boost::any> &params, va_list args, const std::string &def)
{
params.reserve(def.length());
try
{
for (char c : def)
{
switch (c)
{
case 'i':
params.emplace_back(va_arg(args, unsigned int));
break;
case 'q':
params.emplace_back(va_arg(args, signed int));
break;
case 'l':
params.emplace_back(va_arg(args, unsigned long long));
break;
case 'w':
params.emplace_back(va_arg(args, signed long long));
break;
case 'f':
params.emplace_back(va_arg(args, double));
break;
case 'p':
params.emplace_back(va_arg(args, void*));
break;
case 's':
params.emplace_back(va_arg(args, const char*));
break;
case 'b':
params.emplace_back(va_arg(args, int));
break;
default:
throw runtime_error("C++ call: Unknown argument identifier " + c);
}
}
}
catch (...)
{
va_end(args);
throw;
}
va_end(args);
}
void ScriptFunctions::MakePublic(ScriptFunc _public, const char *name, char ret_type, const char *def) noexcept
{
Public::MakePublic(_public, name, ret_type, def);
@ -81,7 +25,7 @@ boost::any ScriptFunctions::CallPublic(const char *name, va_list args) noexcept
try
{
string def = Public::GetDefinition(name);
GetArguments(params, args, def);
Utils::getArguments(params, args, def);
return Public::Call(name, params);
}

View file

@ -47,7 +47,6 @@ class ScriptFunctions
{
public:
static void GetArguments(std::vector<boost::any> &params, va_list args, const std::string &def);
static void MakePublic(ScriptFunc _public, const char *name, char ret_type, const char *def) noexcept;
static boost::any CallPublic(const char *name, va_list args) noexcept;
@ -157,6 +156,7 @@ public:
{"OnServerInit", Callback<>()},
{"OnServerPostInit", Callback<>()},
{"OnServerExit", Callback<bool>()},
{"OnServerScriptCrash", Callback<const char*>()},
{"OnPlayerConnect", Callback<unsigned short>()},
{"OnPlayerDisconnect", Callback<unsigned short>()},
{"OnPlayerDeath", Callback<unsigned short>()},
@ -209,7 +209,7 @@ public:
{"OnWorldMap", Callback<unsigned short>()},
{"OnWorldWeather", Callback<unsigned short>() },
{"OnMpNumIncrement", Callback<int>()},
{"OnRequestPluginList", Callback<>()}
{"OnRequestDataFileList", Callback<>()}
};
};

View file

@ -1,9 +1,7 @@
//
// Created by koncord on 04.03.17.
//
#include "Utils.hpp"
#include <cstdarg>
using namespace std;
const vector<string> Utils::split(const string &str, int delimiter)
@ -52,3 +50,59 @@ ESM::Cell Utils::getCellFromDescription(std::string cellDescription)
return cell;
}
void Utils::getArguments(std::vector<boost::any> &params, va_list args, const std::string &def)
{
params.reserve(def.length());
try
{
for (char c : def)
{
switch (c)
{
case 'i':
params.emplace_back(va_arg(args, unsigned int));
break;
case 'q':
params.emplace_back(va_arg(args, signed int));
break;
case 'l':
params.emplace_back(va_arg(args, unsigned long long));
break;
case 'w':
params.emplace_back(va_arg(args, signed long long));
break;
case 'f':
params.emplace_back(va_arg(args, double));
break;
case 'p':
params.emplace_back(va_arg(args, void*));
break;
case 's':
params.emplace_back(va_arg(args, const char*));
break;
case 'b':
params.emplace_back(va_arg(args, int));
break;
default:
throw runtime_error("C++ call: Unknown argument identifier " + c);
}
}
}
catch (...)
{
va_end(args);
throw;
}
va_end(args);
}

View file

@ -1,7 +1,3 @@
//
// Created by koncord on 04.03.17.
//
#ifndef OPENMW_UTILS_HPP
#define OPENMW_UTILS_HPP
@ -9,6 +5,8 @@
#include <regex>
#include <vector>
#include <boost/any.hpp>
#include <components/esm/loadcell.hpp>
#include <components/openmw-mp/Utils.hpp>
@ -27,6 +25,8 @@ namespace Utils
ESM::Cell getCellFromDescription(std::string cellDescription);
void getArguments(std::vector<boost::any> &params, va_list args, const std::string &def);
template<size_t N>
constexpr unsigned int hash(const char(&str)[N], size_t I = N)
{

View file

@ -307,6 +307,7 @@ int main(int argc, char *argv[])
catch (std::exception &e)
{
LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, e.what());
Script::Call<Script::CallbackIdentity("OnServerScriptCrash")>(e.what());
throw; //fall through
}

View file

@ -1,7 +1,3 @@
//
// Created by koncord on 31.03.17.
//
#ifndef OPENMW_PROCESSORPLAYERPOSITION_HPP
#define OPENMW_PROCESSORPLAYERPOSITION_HPP
@ -19,11 +15,7 @@ namespace mwmp
void Do(PlayerPacket &packet, Player &player) override
{
//DEBUG_PRINTF(strPacketID);
if (!player.creatureStats.mDead)
{
player.sendToLoaded(&packet);
}
player.sendToLoaded(&packet);
}
};
}

View file

@ -134,7 +134,7 @@ add_openmw_dir (mwmp/processors/object BaseObjectProcessor
ProcessorScriptGlobalFloat
)
add_openmw_dir (mwmp/processors/worldstate ProcessorCellCreate ProcessorCellReplace ProcessorRecordDynamic
add_openmw_dir (mwmp/processors/worldstate ProcessorCellCreate ProcessorCellReset ProcessorRecordDynamic
ProcessorWorldCollisionOverride ProcessorWorldMap ProcessorWorldRegionAuthority ProcessorWorldTime
ProcessorWorldWeather
)

View file

@ -458,6 +458,15 @@ namespace MWGui
updateMagicMarkers();
updateCustomMarkers();
/*
Start of tes3mp addition
Update player markers when cell changes to fix their locations
*/
updatePlayerMarkers();
/*
End of tes3mp addition
*/
}
void LocalMapBase::requestMapRender(const MWWorld::CellStore *cell)

View file

@ -71,6 +71,13 @@ DedicatedPlayer::~DedicatedPlayer()
void DedicatedPlayer::update(float dt)
{
// Only move and set anim flags if the framerate isn't too low
if (dt < 0.1)
{
move(dt);
setAnimFlags();
}
MWMechanics::CreatureStats *ptrCreatureStats = &ptr.getClass().getCreatureStats(ptr);
MWMechanics::DynamicStat<float> value;
@ -100,13 +107,6 @@ void DedicatedPlayer::update(float dt)
ptrCreatureStats->setAiSetting(MWMechanics::CreatureStats::AI_Fight, 0);
ptrCreatureStats->setAiSetting(MWMechanics::CreatureStats::AI_Flee, 0);
ptrCreatureStats->setAiSetting(MWMechanics::CreatureStats::AI_Hello, 0);
// Only move and set anim flags if the framerate isn't too low
if (dt < 0.1)
{
move(dt);
setAnimFlags();
}
}
void DedicatedPlayer::move(float dt)

View file

@ -284,6 +284,7 @@ void LocalPlayer::updateAttributes(bool forceUpdate)
{
if (ptrNpcStats.getAttribute(i).getBase() != creatureStats.mAttributes[i].mBase ||
ptrNpcStats.getAttribute(i).getModifier() != creatureStats.mAttributes[i].mMod ||
ptrNpcStats.getAttribute(i).getDamage() != creatureStats.mAttributes[i].mDamage ||
ptrNpcStats.getSkillIncrease(i) != npcStats.mSkillIncrease[i] ||
forceUpdate)
{
@ -318,6 +319,7 @@ void LocalPlayer::updateSkills(bool forceUpdate)
// Update a skill if its base value has changed at all or its progress has changed enough
if (ptrNpcStats.getSkill(i).getBase() != npcStats.mSkills[i].mBase ||
ptrNpcStats.getSkill(i).getModifier() != npcStats.mSkills[i].mMod ||
ptrNpcStats.getSkill(i).getDamage() != npcStats.mSkills[i].mDamage ||
abs(ptrNpcStats.getSkill(i).getProgress() - npcStats.mSkills[i].mProgress) > 0.75 ||
forceUpdate)
{

View file

@ -89,7 +89,7 @@
#include "WorldstateProcessor.hpp"
#include "worldstate/ProcessorCellCreate.hpp"
#include "worldstate/ProcessorCellReplace.hpp"
#include "worldstate/ProcessorCellReset.hpp"
#include "worldstate/ProcessorRecordDynamic.hpp"
#include "worldstate/ProcessorWorldCollisionOverride.hpp"
#include "worldstate/ProcessorWorldMap.hpp"
@ -186,7 +186,7 @@ void ProcessorInitializer()
ActorProcessor::AddProcessor(new ProcessorActorTest());
WorldstateProcessor::AddProcessor(new ProcessorCellCreate());
WorldstateProcessor::AddProcessor(new ProcessorCellReplace());
WorldstateProcessor::AddProcessor(new ProcessorCellReset());
WorldstateProcessor::AddProcessor(new ProcessorRecordDynamic());
WorldstateProcessor::AddProcessor(new ProcessorWorldCollisionOverride());
WorldstateProcessor::AddProcessor(new ProcessorWorldMap());

View file

@ -1,23 +0,0 @@
#ifndef OPENMW_PROCESSORCELLREPLACE_HPP
#define OPENMW_PROCESSORCELLREPLACE_HPP
#include "../WorldstateProcessor.hpp"
namespace mwmp
{
class ProcessorCellReplace : public WorldstateProcessor
{
public:
ProcessorCellReplace()
{
BPP_INIT(ID_CELL_REPLACE)
}
virtual void Do(WorldstatePacket &packet, Worldstate &worldstate)
{
// Placeholder
}
};
}
#endif //OPENMW_PROCESSORCELLREPLACE_HPP

View file

@ -0,0 +1,23 @@
#ifndef OPENMW_PROCESSORCELLRESET_HPP
#define OPENMW_PROCESSORCELLRESET_HPP
#include "../WorldstateProcessor.hpp"
namespace mwmp
{
class ProcessorCellReset : public WorldstateProcessor
{
public:
ProcessorCellReset()
{
BPP_INIT(ID_CELL_RESET)
}
virtual void Do(WorldstatePacket &packet, Worldstate &worldstate)
{
// Placeholder
}
};
}
#endif //OPENMW_PROCESSORCELLRESET_HPP

View file

@ -202,7 +202,7 @@ add_component_dir (openmw-mp/Packets/Object
add_component_dir (openmw-mp/Packets/Worldstate
WorldstatePacket
PacketCellCreate PacketCellReplace PacketRecordDynamic PacketWorldCollisionOverride PacketWorldMap
PacketCellCreate PacketCellReset PacketRecordDynamic PacketWorldCollisionOverride PacketWorldMap
PacketWorldRegionAuthority PacketWorldTime PacketWorldWeather
)

View file

@ -1,5 +1,5 @@
#include "../Packets/Worldstate/PacketCellCreate.hpp"
#include "../Packets/Worldstate/PacketCellReplace.hpp"
#include "../Packets/Worldstate/PacketCellReset.hpp"
#include "../Packets/Worldstate/PacketRecordDynamic.hpp"
#include "../Packets/Worldstate/PacketWorldCollisionOverride.hpp"
#include "../Packets/Worldstate/PacketWorldMap.hpp"
@ -20,7 +20,7 @@ inline void AddPacket(mwmp::WorldstatePacketController::packets_t *packets, RakN
mwmp::WorldstatePacketController::WorldstatePacketController(RakNet::RakPeerInterface *peer)
{
AddPacket<PacketCellCreate>(&packets, peer);
AddPacket<PacketCellReplace>(&packets, peer);
AddPacket<PacketCellReset>(&packets, peer);
AddPacket<PacketRecordDynamic>(&packets, peer);
AddPacket<PacketWorldCollisionOverride>(&packets, peer);
AddPacket<PacketWorldMap>(&packets, peer);

View file

@ -104,7 +104,7 @@ enum GameMessages
ID_GAME_PREINIT,
ID_CELL_CREATE,
ID_CELL_REPLACE,
ID_CELL_RESET,
ID_RECORD_DYNAMIC,
ID_WORLD_COLLISION_OVERRIDE,
ID_WORLD_MAP,

View file

@ -1,17 +0,0 @@
#include "PacketCellReplace.hpp"
#include <components/openmw-mp/NetworkMessages.hpp>
using namespace mwmp;
PacketCellReplace::PacketCellReplace(RakNet::RakPeerInterface *peer) : WorldstatePacket(peer)
{
packetID = ID_CELL_REPLACE;
orderChannel = CHANNEL_SYSTEM;
}
void PacketCellReplace::Packet(RakNet::BitStream *bs, bool send)
{
WorldstatePacket::Packet(bs, send);
// Placeholder
}

View file

@ -0,0 +1,17 @@
#include "PacketCellReset.hpp"
#include <components/openmw-mp/NetworkMessages.hpp>
using namespace mwmp;
PacketCellReset::PacketCellReset(RakNet::RakPeerInterface *peer) : WorldstatePacket(peer)
{
packetID = ID_CELL_RESET;
orderChannel = CHANNEL_SYSTEM;
}
void PacketCellReset::Packet(RakNet::BitStream *bs, bool send)
{
WorldstatePacket::Packet(bs, send);
// Placeholder
}

View file

@ -1,18 +1,18 @@
#ifndef OPENMW_PACKETCELLREPLACE_HPP
#define OPENMW_PACKETCELLREPLACE_HPP
#ifndef OPENMW_PACKETCELLRESET_HPP
#define OPENMW_PACKETCELLRESET_HPP
#include <components/openmw-mp/Packets/Worldstate/WorldstatePacket.hpp>
#include <components/openmw-mp/NetworkMessages.hpp>
namespace mwmp
{
class PacketCellReplace: public WorldstatePacket
class PacketCellReset: public WorldstatePacket
{
public:
PacketCellReplace(RakNet::RakPeerInterface *peer);
PacketCellReset(RakNet::RakPeerInterface *peer);
virtual void Packet(RakNet::BitStream *bs, bool send);
};
}
#endif //OPENMW_PACKETCELLREPLACE_HPP
#endif //OPENMW_PACKETCELLRESET_HPP

View file

@ -192,15 +192,16 @@ std::string Utils::getArchitectureType()
{
#if defined(__x86_64__) || defined(_M_X64)
return "64-bit";
#elif defined(__i386__) || defined(_M_I86)
#elif defined(__i386__) || defined(_M_I86) || defined(_M_IX86)
return "32-bit";
#elif defined(__ARM_ARCH)
return "ARMv" + __ARM_ARCH;
std::string architectureType = "ARMv" + __ARM_ARCH;
#ifdef __aarch64__
return "64-bit";
architectureType = architectureType + " 64-bit";
#else
return "32-bit";
architectureType = architectureType + " 32-bit";
#endif
return architectureType;
#else
return "Unknown architecture";
#endif