forked from mirror/openmw-tes3mp
Compare commits
54 commits
experiment
...
0.7.0
Author | SHA1 | Date | |
---|---|---|---|
|
8aad93b904 | ||
|
3effd5f1ff | ||
|
4692f29b9d | ||
|
03d377ec54 | ||
|
8ff2d1b829 | ||
|
cb82318c36 | ||
|
3b2098382b | ||
|
cb5e24e6c5 | ||
|
91f82d845c | ||
|
d35026bbf5 | ||
|
bd677726bf | ||
|
9fc4c83858 | ||
|
ece39748de | ||
|
5c4d3df551 | ||
|
2cdabddc0e | ||
|
b46767de6e | ||
|
911079e0bc | ||
|
331fa86844 | ||
|
a0ec9dfd2e | ||
|
986528c67d | ||
|
552a94a0ca | ||
|
a508a0faf8 | ||
|
dcbc9d1831 | ||
|
828c52138f | ||
|
69e7d3f2a7 | ||
|
f3b8a5b909 | ||
|
a0ad0b29bc | ||
|
222837976c | ||
|
77386525f2 | ||
|
c058dce346 | ||
|
1df1515c7e | ||
|
999ce857c7 | ||
|
db7e09f441 | ||
|
0fa116b47d | ||
|
0df32accca | ||
|
fd40e8c971 | ||
|
6e47b65205 | ||
|
f481c85e07 | ||
|
8a99f215f6 | ||
|
db9c1b9882 | ||
|
799241e8c6 | ||
|
43f195f0c7 | ||
|
2e1d4a9449 | ||
|
81e2e48561 | ||
|
d83160523f | ||
|
433a69a588 | ||
|
e70fd2cf3a | ||
|
eb52babf29 | ||
|
e96091fd6b | ||
|
906d2a837d | ||
|
71679934a1 | ||
|
5d9893ee92 | ||
|
6e1504f0a1 | ||
|
42b5a8054f |
67 changed files with 887 additions and 574 deletions
26
.travis.yml
26
.travis.yml
|
@ -4,7 +4,7 @@ os:
|
|||
osx_image: xcode9.4
|
||||
language: cpp
|
||||
sudo: required
|
||||
dist: trusty
|
||||
dist: xenial
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
@ -15,18 +15,18 @@ env:
|
|||
global:
|
||||
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
|
||||
# via the "travis encrypt" command using the project repo's public key
|
||||
- secure: NZmvVuA0O9NJXVQ12tXQZHDJC2mbFgYNFcsicw0DgW1It2Nk5hxIkF0pfu4/Z59mhQuOPgRVjl5b0FKy2Axh0gkWc1DJEXGwNaiW5lpTMNWR1LJG5rxa8LrDUpFkycpbzfAFuTUZu5z3iYVv64XzELvBuqNGhPMu1LeBnrlech0jFNjkR9p5qtJGWb8zYcPMCC57rig8a9g1ABoVYS6UXjrKpx0946ZLRsE5ukc9pXsypGwPmOMyfzZkxxzIqFaxoE5JIEdaJTWba/6Za315ozYYIi/N35ROI1YAv5GHRe/Iw9XAa4vQpbDzjM7ZSsZdTvvQsSU598gD2xC6jFUKSrpW6GZKwM2x236fZLGnOk5Uw7DUbG+AwpcEmxBwoy9PjBl9ZF3tJykI0gROewCy8MODhdsVMKr1HGIMVBIJySm/RnNqtoDbYV8mYnSl5b8rwJiCajoiR8Zuv4CIfGneeH1a3DOQDPH/qkDsU6ilzF4ANsBlMUUpgY653KBMBmTlNuVZSH527tnD7Fg6JgHVuSQkTbRa1vSkR7Zcre604RZcAoaEdbX3bhVDasPPghU/I742L0RH3oQNlR09pPBDZ8kG7ydl4aPHwpCWnvXNM1vgxtGvnYLztwrse7IoaRXRYiMFmrso78WhMWUDKgvY4wV9aeUu0DtnMezZVIQwCKg=
|
||||
- secure: 1QK0yVyoOB+gf2I7XzvhXu9w/5lq4stBXIwJbVCTjz4Q4XVHCosURaW1MAgKzMrPnbFEwjyn5uQ8BwsvvfkuN1AZD0YXITgc7gyI+J1wQ/p/ljxRxglakU6WEgsTs2J5z9UmGac4YTXg+quK7YP3rv+zuGim2I2rhzImejyzp0Ym3kRCnNcy+SGBsiRaevRJMe00Ch8zGAbEhduQGeSoS6W0rcu02DNlQKiq5NktWsXR+TWWWVfIeIlQR/lbPsCd0pdxMaMv2QCY0rVbwrYxWJwr/Qe45dAdWp+8/C3PbXpeMSGxlLa33nJNX4Lf/djxbjm8KWk6edaXPajrjR/0iwcpwq0jg2Jt6XfEdnJt35F1gpXlc04sxStjG45uloOKCFYT0wdhIO1Lq+hDP54wypQl+JInd5qC001O7pwhVxO36EgKWqo8HD+BqGDBwsNj2engy9Qcp3wO6G0rLBPB3CrZsk9wrHVv5cSiQSLMhId3Xviu3ZI2qEDA+kgTvxrKrsnMj4bILVCyG5Ka2Mj22wIDW9e8oIab9oTdujax3DTN1GkD6QuOAGzwDsNwGASsgfoeZ+FUhgM75RlBWGMilgkmnF7EJ0oAXLEpjtABnEr2d4qHv+y08kOuTDBLB9ExzCIj024dYYYNLZrqPKx0ncHuCMG2QNj2aJAJEZtj1rQ=
|
||||
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: 'ppa:openmw/openmw'
|
||||
- sourceline: 'ppa:rakhimov/boost'
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-precise-3.8
|
||||
packages: [
|
||||
# Dev
|
||||
cmake, clang-3.8, libunshield-dev, libtinyxml-dev,
|
||||
g++-6,
|
||||
cmake, clang-6.0, libunshield-dev, libtinyxml-dev,
|
||||
g++-8,
|
||||
# Tests
|
||||
libgtest-dev, google-mock,
|
||||
# Boost
|
||||
|
@ -45,7 +45,7 @@ addons:
|
|||
project:
|
||||
name: "TES3MP/openmw-tes3mp"
|
||||
description: "<Your project description here>"
|
||||
notification_email: stas5978@gmail.com
|
||||
notification_email: koncord@tes3mp.com
|
||||
build_command_prepend: "cmake . -DBUILD_UNITTESTS=FALSE -DBUILD_OPENCS=FALSE -DBUILD_BSATOOL=FALSE -DBUILD_ESMTOOL=FALSE -DBUILD_MWINIIMPORTER=FALSE -DBUILD_LAUNCHER=FALSE"
|
||||
build_command: "make -j3"
|
||||
branch_pattern: coverity_scan
|
||||
|
@ -53,21 +53,21 @@ matrix:
|
|||
include:
|
||||
- os: linux
|
||||
env:
|
||||
- ANALYZE="scan-build-3.8 --use-cc clang-3.8 --use-c++ clang++-3.8 "
|
||||
- MATRIX_CC="CC=clang-3.8 && CXX=clang++-3.8"
|
||||
- ANALYZE="scan-build-6.0 --use-cc clang-6.0 --use-c++ clang++-6.0 "
|
||||
- MATRIX_CC="CC=clang-6.0 && CXX=clang++-6.0"
|
||||
compiler: clang
|
||||
- os: linux
|
||||
env:
|
||||
- MATRIX_CC="CC=gcc-6 && CXX=g++-6"
|
||||
- MATRIX_CC="CC=gcc-8 && CXX=g++-8"
|
||||
- os: linux
|
||||
env:
|
||||
- MATRIX_CC="CC=clang-3.8 && CXX=clang++-3.8"
|
||||
- MATRIX_CC="CC=clang-6.0 && CXX=clang++-6.0"
|
||||
allow_failures:
|
||||
- env:
|
||||
- MATRIX_CC="CC=clang-3.8 && CXX=clang++-3.8"
|
||||
- MATRIX_CC="CC=clang-6.0 && CXX=clang++-6.0"
|
||||
- env:
|
||||
- ANALYZE="scan-build-3.8 --use-cc clang-3.8 --use-c++ clang++-3.8 "
|
||||
- MATRIX_CC="CC=clang-3.8 && CXX=clang++-3.8"
|
||||
- ANALYZE="scan-build-6.0 --use-cc clang-6.0 --use-c++ clang++-6.0 "
|
||||
- MATRIX_CC="CC=clang-6.0 && CXX=clang++-6.0"
|
||||
|
||||
before_install:
|
||||
- ./CI/before_install.${TRAVIS_OS_NAME}.sh
|
||||
|
|
|
@ -15,19 +15,8 @@ sudo ln -s /usr/src/gtest/build/libgtest.so /usr/lib/libgtest.so
|
|||
sudo ln -s /usr/src/gtest/build/libgtest_main.so /usr/lib/libgtest_main.so
|
||||
|
||||
cd ~/
|
||||
git clone https://github.com/TES3MP/RakNet
|
||||
cd RakNet
|
||||
cmake . -DRAKNET_ENABLE_DLL=OFF -DRAKNET_ENABLE_SAMPLES=OFF -DCMAKE_BUILD_TYPE=Release
|
||||
git clone https://github.com/TES3MP/CrabNet
|
||||
cd CrabNet
|
||||
cmake . -DCRABNET_ENABLE_DLL=OFF -DCRABNET_ENABLE_SAMPLES=OFF -DCMAKE_BUILD_TYPE=Release
|
||||
make -j3
|
||||
|
||||
cd ~/
|
||||
git clone https://github.com/Koncord/CallFF
|
||||
cd CallFF
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ../
|
||||
make -j3
|
||||
|
||||
cd ~/
|
||||
wget https://github.com/zdevito/terra/releases/download/release-2016-03-25/terra-Linux-x86_64-332a506.zip
|
||||
unzip terra-Linux-x86_64-332a506.zip
|
||||
|
|
|
@ -9,8 +9,7 @@ if [ ! -z "${MATRIX_CC}" ]; then
|
|||
eval "${MATRIX_CC}"
|
||||
fi
|
||||
|
||||
export RAKNET_ROOT=~/RakNet
|
||||
export Terra_ROOT=~/terra-Linux-x86_64-332a506
|
||||
export RAKNET_ROOT=~/CrabNet
|
||||
|
||||
export CODE_COVERAGE=0
|
||||
if [ ! -z "${ANALYZE}" ]; then
|
||||
|
@ -36,7 +35,5 @@ ${ANALYZE}cmake .. \
|
|||
-DBINDIR=/usr/games \
|
||||
-DCMAKE_BUILD_TYPE="None" \
|
||||
-DUSE_SYSTEM_TINYXML=TRUE \
|
||||
-DRakNet_LIBRARY_RELEASE=~/RakNet/lib/libRakNetLibStatic.a \
|
||||
-DRakNet_LIBRARY_DEBUG=~/RakNet/lib/libRakNetLibStatic.a \
|
||||
-DCallFF_INCLUDES=~/CallFF/include \
|
||||
-DCallFF_LIBRARY=~/CallFF/build/src/libcallff.a
|
||||
-DRakNet_LIBRARY_RELEASE=~/CrabNet/lib/libRakNetLibStatic.a \
|
||||
-DRakNet_LIBRARY_DEBUG=~/CrabNet/lib/libRakNetLibStatic.a
|
||||
|
|
23
README.md
23
README.md
|
@ -2,7 +2,7 @@ TES3MP
|
|||
======
|
||||
|
||||
Copyright (c) 2008-2015, OpenMW Team
|
||||
Copyright (c) 2016-2018, TES3MP Team
|
||||
Copyright (c) 2016-2019, Stanislav Zhukov & David Cernat
|
||||
|
||||
[](https://travis-ci.org/TES3MP/openmw-tes3mp)
|
||||
|
||||
|
@ -15,7 +15,7 @@ TES3MP is a project adding multiplayer functionality to [OpenMW](https://github.
|
|||
Font Licenses:
|
||||
* DejaVuLGCSansMono.ttf: custom (see [files/mygui/DejaVu Font License.txt](https://github.com/TES3MP/openmw-tes3mp/blob/master/files/mygui/DejaVu%20Font%20License.txt) for more information)
|
||||
|
||||
Project Status
|
||||
Project status
|
||||
--------------
|
||||
|
||||
[Version changelog](https://github.com/TES3MP/openmw-tes3mp/blob/master/tes3mp-changelog.md)
|
||||
|
@ -24,25 +24,26 @@ As of version 0.7.0, TES3MP is fully playable, providing very extensive player,
|
|||
|
||||
Remaining gameplay problems mostly relate to AI and the synchronization of clientside script variables.
|
||||
|
||||
Donations
|
||||
---------------
|
||||
|
||||
You can benefit the project by donating on Patreon to our two developers, [David Cernat](https://www.patreon.com/davidcernat) and [Koncord](https://www.patreon.com/Koncord), as well as by supporting [OpenMW](https://openmw.org).
|
||||
|
||||
Contributing
|
||||
--------------
|
||||
---------------
|
||||
|
||||
Development has been relatively fast, but any contribution regarding [code](https://github.com/TES3MP/openmw-tes3mp/blob/master/CONTRIBUTING.md), documentation, bug hunting or video showcases is greatly appreciated.
|
||||
Helping us with documentation, bug hunting and video showcases is always greatly appreciated.
|
||||
|
||||
Test sessions are often advertised on [our Discord server](https://discord.gg/ECJk293) or in [our Steam group](https://steamcommunity.com/groups/mwmulti).
|
||||
For code contributions, it's best to start out with modestly sized fixes and features and work your way up. There are so many different possible implementations of more major features – many of which would cause undesirable code or vision conflicts with OpenMW – that those should be talked over in advance with the existing developers before effort is spent on them.
|
||||
|
||||
Feel free to contact the [team members](https://github.com/TES3MP/openmw-tes3mp/blob/master/tes3mp-credits.md) for any questions you might have.
|
||||
|
||||
Getting Started
|
||||
Getting started
|
||||
---------------
|
||||
|
||||
* [Quickstart guide](https://github.com/TES3MP/openmw-tes3mp/wiki/Quickstart-guide)
|
||||
* [Steam group](https://steamcommunity.com/groups/mwmulti) and its [detailed FAQ](https://steamcommunity.com/groups/mwmulti/discussions/1/353916184342480541/)
|
||||
* [TES3MP section on OpenMW forums](https://forum.openmw.org/viewforum.php?f=45)
|
||||
* [Discord server](https://discord.gg/ECJk293)
|
||||
* [Subreddit](https://www.reddit.com/r/tes3mp)
|
||||
* [Known issues and bug reports](https://github.com/TES3MP/openmw-tes3mp/issues)
|
||||
|
||||
Donations
|
||||
---------------
|
||||
|
||||
You can benefit the project by contributing to the Patreon pages of our two developers, [David Cernat](https://www.patreon.com/davidcernat) and [Koncord](https://www.patreon.com/Koncord), as well as by supporting [OpenMW](https://openmw.org).
|
||||
|
|
|
@ -75,9 +75,9 @@ Networking::~Networking()
|
|||
delete worldstatePacketController;
|
||||
}
|
||||
|
||||
void Networking::setServerPassword(std::string passw) noexcept
|
||||
void Networking::setServerPassword(std::string password) noexcept
|
||||
{
|
||||
serverPassword = passw.empty() ? TES3MP_DEFAULT_PASSW : passw;
|
||||
serverPassword = password.empty() ? TES3MP_DEFAULT_PASSW : password;
|
||||
}
|
||||
|
||||
bool Networking::isPassworded() const
|
||||
|
@ -98,25 +98,32 @@ void Networking::processPlayerPacket(RakNet::Packet *packet)
|
|||
|
||||
if (!myPacket->isPacketValid())
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Invalid handshake packet from %d", player->getId());
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Invalid handshake packet from client at %s", packet->systemAddress.ToString());
|
||||
kickPlayer(player->guid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (player->isHandshaked())
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Wrong handshake with player %d, name: %s", player->getId(),
|
||||
player->npc.mName.c_str());
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Wrong handshake with client at %s", packet->systemAddress.ToString());
|
||||
kickPlayer(player->guid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (player->passw != serverPassword)
|
||||
if (player->serverPassword != serverPassword)
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Wrong server password for player %d, name: %s (pass: %s)",
|
||||
player->getId(), player->npc.mName.c_str(), player->passw.c_str());
|
||||
kickPlayer(player->guid);
|
||||
return;
|
||||
if (isPassworded())
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Wrong server password %s used by client at %s",
|
||||
player->serverPassword.c_str(), packet->systemAddress.ToString());
|
||||
kickPlayer(player->guid);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Client at %s tried to join using password, despite the server not being passworded",
|
||||
packet->systemAddress.ToString());
|
||||
}
|
||||
}
|
||||
player->setHandshake();
|
||||
return;
|
||||
|
@ -125,9 +132,8 @@ void Networking::processPlayerPacket(RakNet::Packet *packet)
|
|||
if (!player->isHandshaked())
|
||||
{
|
||||
player->incrementHandshakeAttempts();
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Have not completed handshake with player %d", player->getId());
|
||||
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Attempts so far: %i", player->getHandshakeAttempts());
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Have not completed handshake with client at %s", packet->systemAddress.ToString());
|
||||
LOG_APPEND(Log::LOG_WARN, "- Attempts so far: %i", player->getHandshakeAttempts());
|
||||
|
||||
if (player->getHandshakeAttempts() > 20)
|
||||
kickPlayer(player->guid, false);
|
||||
|
@ -579,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()
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include "Cell.hpp"
|
||||
#include "CellController.hpp"
|
||||
|
||||
struct Player;
|
||||
typedef std::map<RakNet::RakNetGUID, Player*> TPlayers;
|
||||
typedef std::map<unsigned short, Player*> TSlots;
|
||||
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
//
|
||||
// Created by koncord on 15.03.16.
|
||||
//
|
||||
|
||||
#include "TimerAPI.hpp"
|
||||
|
||||
#include <chrono>
|
||||
|
@ -14,7 +10,7 @@ Timer::Timer(ScriptFunc callback, long msec, const std::string& def, std::vector
|
|||
{
|
||||
targetMsec = msec;
|
||||
this->args = args;
|
||||
end = true;
|
||||
isEnded = true;
|
||||
}
|
||||
|
||||
#if defined(ENABLE_LUA)
|
||||
|
@ -22,13 +18,13 @@ Timer::Timer(lua_State *lua, ScriptFuncLua callback, long msec, const std::strin
|
|||
{
|
||||
targetMsec = msec;
|
||||
this->args = args;
|
||||
end = true;
|
||||
isEnded = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void Timer::Tick()
|
||||
{
|
||||
if (end)
|
||||
if (isEnded)
|
||||
return;
|
||||
|
||||
const auto duration = chrono::system_clock::now().time_since_epoch();
|
||||
|
@ -36,19 +32,19 @@ void Timer::Tick()
|
|||
|
||||
if (time - startTime >= targetMsec)
|
||||
{
|
||||
end = true;
|
||||
isEnded = true;
|
||||
Call(args);
|
||||
}
|
||||
}
|
||||
|
||||
bool Timer::IsEnd()
|
||||
bool Timer::IsEnded()
|
||||
{
|
||||
return end;
|
||||
return isEnded;
|
||||
}
|
||||
|
||||
void Timer::Stop()
|
||||
{
|
||||
end = true;
|
||||
isEnded = true;
|
||||
}
|
||||
|
||||
void Timer::Restart(int msec)
|
||||
|
@ -59,7 +55,7 @@ void Timer::Restart(int msec)
|
|||
|
||||
void Timer::Start()
|
||||
{
|
||||
end = false;
|
||||
isEnded = false;
|
||||
|
||||
const auto duration = chrono::system_clock::now().time_since_epoch();
|
||||
const auto msec = chrono::duration_cast<chrono::milliseconds>(duration).count();
|
||||
|
@ -172,12 +168,12 @@ void TimerAPI::StopTimer(int timerid)
|
|||
}
|
||||
}
|
||||
|
||||
bool TimerAPI::IsEndTimer(int timerid)
|
||||
bool TimerAPI::IsTimerElapsed(int timerid)
|
||||
{
|
||||
bool ret = false;
|
||||
try
|
||||
{
|
||||
ret = timers.at(timerid)->IsEnd();
|
||||
ret = timers.at(timerid)->IsEnded();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
//
|
||||
// Created by koncord on 15.03.16.
|
||||
//
|
||||
|
||||
#ifndef OPENMW_TIMERAPI_HPP
|
||||
#define OPENMW_TIMERAPI_HPP
|
||||
|
||||
|
@ -27,7 +23,7 @@ namespace mwmp
|
|||
#endif
|
||||
void Tick();
|
||||
|
||||
bool IsEnd();
|
||||
bool IsEnded();
|
||||
void Stop();
|
||||
void Start();
|
||||
void Restart(int msec);
|
||||
|
@ -36,7 +32,7 @@ namespace mwmp
|
|||
std::string publ, arg_types;
|
||||
std::vector<boost::any> args;
|
||||
Script *scr;
|
||||
bool end;
|
||||
bool isEnded;
|
||||
};
|
||||
|
||||
class TimerAPI
|
||||
|
@ -50,7 +46,7 @@ namespace mwmp
|
|||
static void ResetTimer(int timerid, long msec);
|
||||
static void StartTimer(int timerid);
|
||||
static void StopTimer(int timerid);
|
||||
static bool IsEndTimer(int timerid);
|
||||
static bool IsTimerElapsed(int timerid);
|
||||
|
||||
static void Terminate();
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -7,20 +7,6 @@
|
|||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
void PositionFunctions::GetPos(unsigned short pid, float *x, float *y, float *z) noexcept
|
||||
{
|
||||
*x = 0.00;
|
||||
*y = 0.00;
|
||||
*z = 0.00;
|
||||
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player,);
|
||||
|
||||
*x = player->position.pos[0];
|
||||
*y = player->position.pos[1];
|
||||
*z = player->position.pos[2];
|
||||
}
|
||||
|
||||
double PositionFunctions::GetPosX(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
|
@ -69,20 +55,6 @@ double PositionFunctions::GetPreviousCellPosZ(unsigned short pid) noexcept
|
|||
return player->previousCellPosition.pos[2];
|
||||
}
|
||||
|
||||
void PositionFunctions::GetRot(unsigned short pid, float *x, float *y, float *z) noexcept
|
||||
{
|
||||
*x = 0.00;
|
||||
*y = 0.00;
|
||||
*z = 0.00;
|
||||
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, );
|
||||
|
||||
*x = player->position.rot[0];
|
||||
*y = player->position.rot[1];
|
||||
*z = player->position.rot[2];
|
||||
}
|
||||
|
||||
double PositionFunctions::GetRotX(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
#include "../Types.hpp"
|
||||
|
||||
#define POSITIONAPI \
|
||||
{"GetPos", PositionFunctions::GetPos},\
|
||||
{"GetPosX", PositionFunctions::GetPosX},\
|
||||
{"GetPosY", PositionFunctions::GetPosY},\
|
||||
{"GetPosZ", PositionFunctions::GetPosZ},\
|
||||
|
@ -13,7 +12,6 @@
|
|||
{"GetPreviousCellPosY", PositionFunctions::GetPreviousCellPosY},\
|
||||
{"GetPreviousCellPosZ", PositionFunctions::GetPreviousCellPosZ},\
|
||||
\
|
||||
{"GetRot", PositionFunctions::GetRot},\
|
||||
{"GetRotX", PositionFunctions::GetRotX},\
|
||||
{"GetRotZ", PositionFunctions::GetRotZ},\
|
||||
\
|
||||
|
@ -29,18 +27,6 @@ class PositionFunctions
|
|||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* \brief Assign the player's positional coordinate values to the variables passed as
|
||||
* parameters.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \param x The variable for the X position.
|
||||
* \param y The variable for the Y position.
|
||||
* \param z The variable for the Z position.
|
||||
* \return void
|
||||
*/
|
||||
static void GetPos(unsigned short pid, float *x, float *y, float *z) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the X position of a player.
|
||||
*
|
||||
|
@ -89,18 +75,6 @@ public:
|
|||
*/
|
||||
static double GetPreviousCellPosZ(unsigned short pid) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Assign the player's rotational coordinate values to the variables passed as
|
||||
* parameters.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \param x The variable for the X rotation.
|
||||
* \param y The variable for the Y rotation.
|
||||
* \param z The variable for the Z rotation.
|
||||
* \return void
|
||||
*/
|
||||
static void GetRot(unsigned short pid, float *x, float *y, float *z) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the X rotation of a player.
|
||||
*
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
@ -54,5 +54,5 @@ void ScriptFunctions::FreeTimer(int timerId) noexcept
|
|||
|
||||
bool ScriptFunctions::IsTimerElapsed(int timerId) noexcept
|
||||
{
|
||||
return TimerAPI::IsEndTimer(timerId);
|
||||
return TimerAPI::IsTimerElapsed(timerId);
|
||||
}
|
||||
|
|
|
@ -107,6 +107,32 @@ template<> struct F_<1> { static constexpr LuaFuctionData F{"CreateTimerEx", Lan
|
|||
template<> struct F_<2> { static constexpr LuaFuctionData F{"MakePublic", LangLua::MakePublic}; };
|
||||
template<> struct F_<3> { static constexpr LuaFuctionData F{"CallPublic", LangLua::CallPublic}; };
|
||||
|
||||
#ifdef __arm__
|
||||
template<std::size_t... Is>
|
||||
struct indices {};
|
||||
template<std::size_t N, std::size_t... Is>
|
||||
struct build_indices : build_indices<N-1, N-1, Is...> {};
|
||||
template<std::size_t... Is>
|
||||
struct build_indices<0, Is...> : indices<Is...> {};
|
||||
template<std::size_t N>
|
||||
using IndicesFor = build_indices<N>;
|
||||
|
||||
template<size_t... Indices>
|
||||
LuaFuctionData *functions(indices<Indices...>)
|
||||
{
|
||||
|
||||
static LuaFuctionData functions_[sizeof...(Indices)]{
|
||||
F_<Indices>::F...
|
||||
};
|
||||
|
||||
static_assert(
|
||||
sizeof(functions_) / sizeof(functions_[0]) ==
|
||||
sizeof(ScriptFunctions::functions) / sizeof(ScriptFunctions::functions[0]),
|
||||
"Not all functions have been mapped to Lua");
|
||||
|
||||
return functions_;
|
||||
}
|
||||
#else
|
||||
template<unsigned int I>
|
||||
struct C
|
||||
{
|
||||
|
@ -117,7 +143,6 @@ struct C
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
struct C<0>
|
||||
{
|
||||
|
@ -141,6 +166,7 @@ LuaFuctionData *functions()
|
|||
|
||||
return functions_;
|
||||
}
|
||||
#endif
|
||||
|
||||
void LangLua::LoadProgram(const char *filename)
|
||||
{
|
||||
|
@ -152,8 +178,11 @@ void LangLua::LoadProgram(const char *filename)
|
|||
|
||||
constexpr auto functions_n = sizeof(ScriptFunctions::functions) / sizeof(ScriptFunctions::functions[0]);
|
||||
|
||||
#if __arm__
|
||||
LuaFuctionData *functions_ = functions(IndicesFor<functions_n>{});
|
||||
#else
|
||||
LuaFuctionData *functions_ = functions<sizeof(ScriptFunctions::functions) / sizeof(ScriptFunctions::functions[0])>();
|
||||
|
||||
#endif
|
||||
luabridge::Namespace tes3mp = luabridge::getGlobalNamespace(lua).beginNamespace("tes3mp");
|
||||
|
||||
for (unsigned i = 0; i < functions_n; i++)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -13,62 +13,6 @@ constexpr ScriptCallbackData ScriptFunctions::callbacks[];
|
|||
|
||||
using namespace std;
|
||||
|
||||
void ScriptFunctions::GetArguments(std::vector<boost::any> ¶ms, 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);
|
||||
}
|
||||
|
|
|
@ -47,7 +47,6 @@ class ScriptFunctions
|
|||
{
|
||||
public:
|
||||
|
||||
static void GetArguments(std::vector<boost::any> ¶ms, 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<>()}
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -105,7 +105,7 @@ struct ScriptFunctionPointer : public ScriptIdentity
|
|||
void *addr;
|
||||
#if (!defined(__clang__) && defined(__GNUC__))
|
||||
template<typename R, typename... Types>
|
||||
constexpr ScriptFunctionPointer(Function<R, Types...> addr) : ScriptIdentity(addr), addr(reinterpret_cast<void*>(addr)) {}
|
||||
constexpr ScriptFunctionPointer(Function<R, Types...> addr) : ScriptIdentity(addr), addr((void*)(addr)) {}
|
||||
#else
|
||||
template<typename R, typename... Types>
|
||||
constexpr ScriptFunctionPointer(Function<R, Types...> addr) : ScriptIdentity(addr), addr(addr) {}
|
||||
|
|
|
@ -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> ¶ms, 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);
|
||||
}
|
||||
|
|
|
@ -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> ¶ms, va_list args, const std::string &def);
|
||||
|
||||
template<size_t N>
|
||||
constexpr unsigned int hash(const char(&str)[N], size_t I = N)
|
||||
{
|
||||
|
|
|
@ -190,47 +190,27 @@ int main(int argc, char *argv[])
|
|||
LOG_INIT(logLevel);
|
||||
|
||||
int players = mgr.getInt("maximumPlayers", "General");
|
||||
string addr = mgr.getString("localAddress", "General");
|
||||
string address = mgr.getString("localAddress", "General");
|
||||
int port = mgr.getInt("port", "General");
|
||||
|
||||
string passw = mgr.getString("password", "General");
|
||||
string password = mgr.getString("password", "General");
|
||||
|
||||
string plugin_home = mgr.getString("home", "Plugins");
|
||||
string moddir = Utils::convertPath(plugin_home + "/data");
|
||||
string pluginHome = mgr.getString("home", "Plugins");
|
||||
string dataDirectory = Utils::convertPath(pluginHome + "/data");
|
||||
|
||||
vector<string> plugins (Utils::split(mgr.getString("plugins", "Plugins"), ','));
|
||||
vector<string> plugins(Utils::split(mgr.getString("plugins", "Plugins"), ','));
|
||||
|
||||
Utils::printVersion("TES3MP dedicated server", TES3MP_VERSION, version.mCommitHash, TES3MP_PROTO_VERSION);
|
||||
|
||||
// Check for unmodified tes3mp-credits file; this makes it so people can't repackage official releases with
|
||||
// their own made-up credits, though it obviously has no bearing on unofficial releases that change
|
||||
// the checksum below
|
||||
boost::filesystem::path folderPath(boost::filesystem::initial_path<boost::filesystem::path>());
|
||||
folderPath = boost::filesystem::system_complete(boost::filesystem::path(argv[0])).remove_filename();
|
||||
std::string creditsPath = folderPath.string() + "/tes3mp-credits";
|
||||
|
||||
unsigned int expectedChecksumInt = Utils::hexStrToInt(TES3MP_CREDITS_CHECKSUM);
|
||||
bool hasValidCredits = Utils::doesFileHaveChecksum(creditsPath + ".md", expectedChecksumInt);
|
||||
|
||||
if (!hasValidCredits)
|
||||
hasValidCredits = Utils::doesFileHaveChecksum(creditsPath + ".txt", expectedChecksumInt);
|
||||
|
||||
if (!hasValidCredits)
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_FATAL, "The server is shutting down");
|
||||
LOG_APPEND(Log::LOG_FATAL, "- %s", TES3MP_CREDITS_ERROR);
|
||||
return 1;
|
||||
}
|
||||
|
||||
Script::SetModDir(moddir);
|
||||
Script::SetModDir(dataDirectory);
|
||||
|
||||
#ifdef ENABLE_LUA
|
||||
LangLua::AddPackagePath(Utils::convertPath(plugin_home + "/scripts/?.lua" + ";"
|
||||
+ plugin_home + "/lib/lua/?.lua" + ";"));
|
||||
LangLua::AddPackagePath(Utils::convertPath(pluginHome + "/scripts/?.lua" + ";"
|
||||
+ pluginHome + "/lib/lua/?.lua" + ";"));
|
||||
#ifdef _WIN32
|
||||
LangLua::AddPackageCPath(Utils::convertPath(plugin_home + "/lib/?.dll"));
|
||||
LangLua::AddPackageCPath(Utils::convertPath(pluginHome + "/lib/?.dll"));
|
||||
#else
|
||||
LangLua::AddPackageCPath(Utils::convertPath(plugin_home + "/lib/?.so"));
|
||||
LangLua::AddPackageCPath(Utils::convertPath(pluginHome + "/lib/?.so"));
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -246,18 +226,18 @@ int main(int argc, char *argv[])
|
|||
|
||||
peer->SetIncomingPassword(sstr.str().c_str(), (int) sstr.str().size());
|
||||
|
||||
if (RakNet::NonNumericHostString(addr.c_str()))
|
||||
if (RakNet::NonNumericHostString(address.c_str()))
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "You cannot use non-numeric addresses for the server.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
RakNet::SocketDescriptor sd((unsigned short) port, addr.c_str());
|
||||
RakNet::SocketDescriptor sd((unsigned short) port, address.c_str());
|
||||
|
||||
try
|
||||
{
|
||||
for (auto plugin : plugins)
|
||||
Script::LoadScript(plugin.c_str(), plugin_home.c_str());
|
||||
Script::LoadScript(plugin.c_str(), pluginHome.c_str());
|
||||
|
||||
switch (peer->Startup((unsigned) players, &sd, 1))
|
||||
{
|
||||
|
@ -284,7 +264,7 @@ int main(int argc, char *argv[])
|
|||
peer->SetMaximumIncomingConnections((unsigned short) (players));
|
||||
|
||||
Networking networking(peer);
|
||||
networking.setServerPassword(passw);
|
||||
networking.setServerPassword(password);
|
||||
|
||||
if (mgr.getBool("enabled", "MasterServer"))
|
||||
{
|
||||
|
@ -327,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
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -221,10 +221,11 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
|||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Check for unmodified tes3mp-credits file; this makes it so people can't repackage official releases with
|
||||
their own made-up credits, though it obviously has no bearing on unofficial releases that change
|
||||
the checksum below
|
||||
Check for unmodified tes3mp-credits file on Windows; this makes it so people can't repackage official
|
||||
releases with their own made-up credits, though it obviously has no bearing on unofficial releases that
|
||||
change the checksum below
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
boost::filesystem::path folderPath(boost::filesystem::initial_path<boost::filesystem::path>());
|
||||
folderPath = boost::filesystem::system_complete(boost::filesystem::path(argv[0])).remove_filename();
|
||||
std::string creditsPath = folderPath.string() + "/tes3mp-credits";
|
||||
|
@ -242,6 +243,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
|||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "tes3mp", TES3MP_CREDITS_ERROR, 0);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
|
|
|
@ -553,9 +553,10 @@ namespace MWClass
|
|||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
If the attacker was the LocalPlayer or LocalActor, record their target and send a packet with it
|
||||
If the attacker was the LocalPlayer or LocalActor, record their target and send a
|
||||
packet with it
|
||||
|
||||
If the victim was a LocalActor who died, record their attacker as the deathReason
|
||||
If the victim was a LocalActor who died, record their attacker as the killer
|
||||
*/
|
||||
mwmp::Attack *localAttack = MechanicsHelper::getLocalAttack(attacker);
|
||||
|
||||
|
|
|
@ -966,12 +966,13 @@ namespace MWClass
|
|||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
If the attacker was the LocalPlayer or LocalActor, record their target and send a packet with it
|
||||
If the attacker was the LocalPlayer or LocalActor, record their target and send a
|
||||
packet with it
|
||||
|
||||
If the victim was the LocalPlayer, check whether packets should be sent about
|
||||
their new dynamic stats and position
|
||||
|
||||
If the victim was a LocalActor who died, record their attacker as the deathReason
|
||||
If the victim was a LocalActor who died, record their attacker as the killer
|
||||
*/
|
||||
mwmp::Attack *localAttack = MechanicsHelper::getLocalAttack(attacker);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -9,6 +9,19 @@
|
|||
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Include additional headers for multiplayer purposes
|
||||
*/
|
||||
#include "../mwmp/Main.hpp"
|
||||
#include "../mwmp/Networking.hpp"
|
||||
#include "../mwmp/LocalPlayer.hpp"
|
||||
#include "../mwmp/MechanicsHelper.hpp"
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
|
@ -163,9 +176,26 @@ void Recharge::onItemClicked(MyGUI::Widget *sender, const MWWorld::Ptr& item)
|
|||
|
||||
const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().find(
|
||||
item.getClass().getEnchantment(item));
|
||||
|
||||
/*
|
||||
Start of tes3mp change (minor)
|
||||
|
||||
Send PlayerInventory packets that replace the original item with the new one
|
||||
*/
|
||||
mwmp::LocalPlayer *localPlayer = mwmp::Main::get().getLocalPlayer();
|
||||
mwmp::Item removedItem = MechanicsHelper::getItem(item, 1);
|
||||
|
||||
item.getCellRef().setEnchantmentCharge(
|
||||
std::min(item.getCellRef().getEnchantmentCharge() + restored, static_cast<float>(enchantment->mData.mCharge)));
|
||||
|
||||
mwmp::Item addedItem = MechanicsHelper::getItem(item, 1);
|
||||
|
||||
localPlayer->sendItemChange(addedItem, mwmp::InventoryChanges::ADD);
|
||||
localPlayer->sendItemChange(removedItem, mwmp::InventoryChanges::REMOVE);
|
||||
/*
|
||||
End of tes3mp change (minor)
|
||||
*/
|
||||
|
||||
MWBase::Environment::get().getWindowManager()->playSound("Enchant Success");
|
||||
|
||||
player.getClass().getContainerStore(player).restack(item);
|
||||
|
|
|
@ -842,6 +842,22 @@ namespace MWMechanics
|
|||
|
||||
if (isDamageEffect)
|
||||
{
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
If the victim was a LocalActor who died, record the caster as the killer
|
||||
*/
|
||||
if (mwmp::Main::get().getCellController()->isLocalActor(ptr))
|
||||
{
|
||||
bool isSuicide = ptr == caster || caster.isEmpty();
|
||||
|
||||
mwmp::Main::get().getCellController()->getLocalActor(ptr)->killer = isSuicide ?
|
||||
MechanicsHelper::getTarget(ptr) : MechanicsHelper::getTarget(caster);
|
||||
}
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
|
||||
if (caster == player || playerFollowers.find(caster) != playerFollowers.end())
|
||||
{
|
||||
if (caster.getClass().getNpcStats(caster).isWerewolf())
|
||||
|
|
|
@ -4,6 +4,19 @@
|
|||
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Include additional headers for multiplayer purposes
|
||||
*/
|
||||
#include "../mwmp/Main.hpp"
|
||||
#include "../mwmp/Networking.hpp"
|
||||
#include "../mwmp/LocalPlayer.hpp"
|
||||
#include "../mwmp/MechanicsHelper.hpp"
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
|
@ -57,8 +70,25 @@ void Repair::repair(const MWWorld::Ptr &itemToRepair)
|
|||
// repair by 'y' points
|
||||
int charge = itemToRepair.getClass().getItemHealth(itemToRepair);
|
||||
charge = std::min(charge + y, itemToRepair.getClass().getItemMaxHealth(itemToRepair));
|
||||
|
||||
/*
|
||||
Start of tes3mp change (minor)
|
||||
|
||||
Send PlayerInventory packets that replace the original item with the new one
|
||||
*/
|
||||
mwmp::LocalPlayer *localPlayer = mwmp::Main::get().getLocalPlayer();
|
||||
mwmp::Item removedItem = MechanicsHelper::getItem(itemToRepair, 1);
|
||||
|
||||
itemToRepair.getCellRef().setCharge(charge);
|
||||
|
||||
mwmp::Item addedItem = MechanicsHelper::getItem(itemToRepair, 1);
|
||||
|
||||
localPlayer->sendItemChange(addedItem, mwmp::InventoryChanges::ADD);
|
||||
localPlayer->sendItemChange(removedItem, mwmp::InventoryChanges::REMOVE);
|
||||
/*
|
||||
End of tes3mp change (minor)
|
||||
*/
|
||||
|
||||
// attempt to re-stack item, in case it was fully repaired
|
||||
MWWorld::ContainerStoreIterator stacked = player.getClass().getContainerStore(player).restack(itemToRepair);
|
||||
|
||||
|
|
|
@ -537,7 +537,7 @@ namespace MWMechanics
|
|||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
If the victim was a LocalPlayer or LocalActor who died, record their attacker as the deathReason
|
||||
If the victim was a LocalPlayer or LocalActor who died, record the caster as the killer
|
||||
*/
|
||||
if (!wasDead && isDead)
|
||||
{
|
||||
|
|
|
@ -82,8 +82,10 @@ void Cell::updateLocal(bool forceUpdate)
|
|||
}
|
||||
else
|
||||
{
|
||||
// Forcibly update this local actor if its data has never been sent before;
|
||||
// otherwise, use the current forceUpdate value
|
||||
if (actor->getPtr().getRefData().isEnabled())
|
||||
actor->update(forceUpdate);
|
||||
actor->update(actor->hasSentData ? forceUpdate : true);
|
||||
|
||||
++it;
|
||||
}
|
||||
|
@ -397,6 +399,9 @@ void Cell::readCellChange(ActorList& actorList)
|
|||
|
||||
void Cell::initializeLocalActor(const MWWorld::Ptr& ptr)
|
||||
{
|
||||
std::string mapIndex = Main::get().getCellController()->generateMapIndex(ptr);
|
||||
LOG_APPEND(Log::LOG_VERBOSE, "- Initializing LocalActor %s in %s", mapIndex.c_str(), getDescription().c_str());
|
||||
|
||||
LocalActor *actor = new LocalActor();
|
||||
actor->cell = *store->getCell();
|
||||
actor->setPtr(ptr);
|
||||
|
@ -406,16 +411,17 @@ void Cell::initializeLocalActor(const MWWorld::Ptr& ptr)
|
|||
if (ptr.getClass().getCreatureStats(ptr).isDead())
|
||||
actor->wasDead = true;
|
||||
|
||||
std::string mapIndex = Main::get().getCellController()->generateMapIndex(ptr);
|
||||
localActors[mapIndex] = actor;
|
||||
|
||||
Main::get().getCellController()->setLocalActorRecord(mapIndex, getDescription());
|
||||
|
||||
LOG_APPEND(Log::LOG_VERBOSE, "- Initialized LocalActor %s in %s", mapIndex.c_str(), getDescription().c_str());
|
||||
LOG_APPEND(Log::LOG_VERBOSE, "- Successfully initialized LocalActor %s in %s", mapIndex.c_str(), getDescription().c_str());
|
||||
}
|
||||
|
||||
void Cell::initializeLocalActors()
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Initializing LocalActors in %s", getDescription().c_str());
|
||||
|
||||
for (const auto &mergedRef : store->getMergedRefs())
|
||||
{
|
||||
if (mergedRef->mClass->isActor())
|
||||
|
@ -432,20 +438,24 @@ void Cell::initializeLocalActors()
|
|||
initializeLocalActor(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
LOG_APPEND(Log::LOG_VERBOSE, "- Successfully initialized LocalActors in %s", getDescription().c_str());
|
||||
}
|
||||
|
||||
void Cell::initializeDedicatedActor(const MWWorld::Ptr& ptr)
|
||||
{
|
||||
std::string mapIndex = Main::get().getCellController()->generateMapIndex(ptr);
|
||||
LOG_APPEND(Log::LOG_VERBOSE, "- Initializing DedicatedActor %s in %s", mapIndex.c_str(), getDescription().c_str());
|
||||
|
||||
DedicatedActor *actor = new DedicatedActor();
|
||||
actor->cell = *store->getCell();
|
||||
actor->setPtr(ptr);
|
||||
|
||||
std::string mapIndex = Main::get().getCellController()->generateMapIndex(ptr);
|
||||
dedicatedActors[mapIndex] = actor;
|
||||
|
||||
Main::get().getCellController()->setDedicatedActorRecord(mapIndex, getDescription());
|
||||
|
||||
LOG_APPEND(Log::LOG_VERBOSE, "- Initialized DedicatedActor %s in %s", mapIndex.c_str(), getDescription().c_str());
|
||||
LOG_APPEND(Log::LOG_VERBOSE, "- Successfully initialized DedicatedActor %s in %s", mapIndex.c_str(), getDescription().c_str());
|
||||
}
|
||||
|
||||
void Cell::initializeDedicatedActors(ActorList& actorList)
|
||||
|
|
|
@ -77,6 +77,8 @@ void CellController::initializeCell(const ESM::Cell& cell)
|
|||
// If this key doesn't exist, create it
|
||||
if (cellsInitialized.count(mapIndex) == 0)
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Initializing mwmp::Cell %s", cell.getDescription().c_str());
|
||||
|
||||
MWWorld::CellStore *cellStore = getCellStore(cell);
|
||||
|
||||
if (!cellStore) return;
|
||||
|
@ -84,7 +86,7 @@ void CellController::initializeCell(const ESM::Cell& cell)
|
|||
mwmp::Cell *mpCell = new mwmp::Cell(cellStore);
|
||||
cellsInitialized[mapIndex] = mpCell;
|
||||
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "- Initialized mwmp::Cell %s", mpCell->getDescription().c_str());
|
||||
LOG_APPEND(Log::LOG_VERBOSE, "- Successfully initialized mwmp::Cell %s", cell.getDescription().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -22,6 +22,7 @@ using namespace std;
|
|||
|
||||
LocalActor::LocalActor()
|
||||
{
|
||||
hasSentData = false;
|
||||
posWasChanged = false;
|
||||
equipmentChanged = false;
|
||||
|
||||
|
@ -61,14 +62,16 @@ void LocalActor::update(bool forceUpdate)
|
|||
updateSpeech();
|
||||
updateAttack();
|
||||
}
|
||||
|
||||
hasSentData = true;
|
||||
}
|
||||
|
||||
void LocalActor::updateCell()
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Sending ID_ACTOR_CELL_CHANGE about %s %i-%i to server",
|
||||
refId.c_str(), refNum, mpNum);
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Sending ID_ACTOR_CELL_CHANGE about %s %i-%i in cell %s to server",
|
||||
refId.c_str(), refNum, mpNum, cell.getDescription().c_str());
|
||||
|
||||
LOG_APPEND(Log::LOG_VERBOSE, "- Moved from %s to %s", cell.getDescription().c_str(), ptr.getCell()->getCell()->getDescription().c_str());
|
||||
LOG_APPEND(Log::LOG_VERBOSE, "- Moved to cell %s", ptr.getCell()->getCell()->getDescription().c_str());
|
||||
|
||||
cell = *ptr.getCell()->getCell();
|
||||
position = ptr.getRefData().getPosition();
|
||||
|
@ -191,8 +194,8 @@ void LocalActor::updateStatsDynamic(bool forceUpdate)
|
|||
if (MechanicsHelper::isEmptyTarget(killer))
|
||||
killer = MechanicsHelper::getTarget(ptr);
|
||||
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Sending ID_ACTOR_DEATH about %s %i-%i to server",
|
||||
refId.c_str(), refNum, mpNum);
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Sending ID_ACTOR_DEATH about %s %i-%i in cell %s to server",
|
||||
refId.c_str(), refNum, mpNum, cell.getDescription().c_str());
|
||||
|
||||
mwmp::Main::get().getNetworking()->getActorList()->addDeathActor(*this);
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ namespace mwmp
|
|||
MWWorld::Ptr getPtr();
|
||||
void setPtr(const MWWorld::Ptr& newPtr);
|
||||
|
||||
bool hasSentData;
|
||||
bool wasDead;
|
||||
|
||||
private:
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
@ -920,7 +922,7 @@ void LocalPlayer::setAttributes()
|
|||
{
|
||||
MWWorld::Ptr ptrPlayer = getPlayerPtr();
|
||||
|
||||
MWMechanics::CreatureStats *ptrCreatureStats = &ptrPlayer.getClass().getCreatureStats(ptrPlayer);
|
||||
MWMechanics::NpcStats *ptrNpcStats = &ptrPlayer.getClass().getNpcStats(ptrPlayer);
|
||||
MWMechanics::AttributeValue attributeValue;
|
||||
|
||||
for (int attributeIndex = 0; attributeIndex < 8; ++attributeIndex)
|
||||
|
@ -928,14 +930,14 @@ void LocalPlayer::setAttributes()
|
|||
// If the server wants to clear our attribute's non-zero modifier, we need to remove
|
||||
// the spell effect causing it, to avoid an infinite loop where the effect keeps resetting
|
||||
// the modifier
|
||||
if (creatureStats.mAttributes[attributeIndex].mMod == 0 && ptrCreatureStats->getAttribute(attributeIndex).getModifier() > 0)
|
||||
if (creatureStats.mAttributes[attributeIndex].mMod == 0 && ptrNpcStats->getAttribute(attributeIndex).getModifier() > 0)
|
||||
{
|
||||
ptrCreatureStats->getActiveSpells().purgeEffectByArg(ESM::MagicEffect::FortifyAttribute, attributeIndex);
|
||||
ptrNpcStats->getActiveSpells().purgeEffectByArg(ESM::MagicEffect::FortifyAttribute, attributeIndex);
|
||||
MWBase::Environment::get().getMechanicsManager()->updateMagicEffects(ptrPlayer);
|
||||
|
||||
// Is the modifier for this attribute still higher than 0? If so, unequip items that
|
||||
// fortify the attribute
|
||||
if (ptrCreatureStats->getAttribute(attributeIndex).getModifier() > 0)
|
||||
if (ptrNpcStats->getAttribute(attributeIndex).getModifier() > 0)
|
||||
{
|
||||
MechanicsHelper::unequipItemsByEffect(ptrPlayer, ESM::Enchantment::ConstantEffect, ESM::MagicEffect::FortifyAttribute, attributeIndex, -1);
|
||||
mwmp::Main::get().getGUIController()->refreshGuiMode(MWGui::GM_Inventory);
|
||||
|
@ -943,7 +945,9 @@ void LocalPlayer::setAttributes()
|
|||
}
|
||||
|
||||
attributeValue.readState(creatureStats.mAttributes[attributeIndex]);
|
||||
ptrCreatureStats->setAttribute(attributeIndex, attributeValue);
|
||||
ptrNpcStats->setAttribute(attributeIndex, attributeValue);
|
||||
|
||||
ptrNpcStats->setSkillIncrease(attributeIndex, npcStats.mSkillIncrease[attributeIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -976,11 +980,6 @@ void LocalPlayer::setSkills()
|
|||
skillValue.readState(npcStats.mSkills[skillIndex]);
|
||||
ptrNpcStats->setSkill(skillIndex, skillValue);
|
||||
}
|
||||
|
||||
for (int attributeIndex = 0; attributeIndex < 8; ++attributeIndex)
|
||||
ptrNpcStats->setSkillIncrease(attributeIndex, npcStats.mSkillIncrease[attributeIndex]);
|
||||
|
||||
ptrNpcStats->setLevelProgress(npcStats.mLevelProgress);
|
||||
}
|
||||
|
||||
void LocalPlayer::setLevel()
|
||||
|
@ -988,8 +987,9 @@ void LocalPlayer::setLevel()
|
|||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
MWWorld::Ptr ptrPlayer = world->getPlayerPtr();
|
||||
|
||||
MWMechanics::CreatureStats *ptrCreatureStats = &ptrPlayer.getClass().getCreatureStats(ptrPlayer);
|
||||
ptrCreatureStats->setLevel(creatureStats.mLevel);
|
||||
MWMechanics::NpcStats *ptrNpcStats = &ptrPlayer.getClass().getNpcStats(ptrPlayer);
|
||||
ptrNpcStats->setLevel(creatureStats.mLevel);
|
||||
ptrNpcStats->setLevelProgress(npcStats.mLevelProgress);
|
||||
}
|
||||
|
||||
void LocalPlayer::setBounty()
|
||||
|
@ -1403,31 +1403,23 @@ void LocalPlayer::sendInventory()
|
|||
getNetworking()->getPlayerPacket(ID_PLAYER_INVENTORY)->Send();
|
||||
}
|
||||
|
||||
void LocalPlayer::sendItemChange(const mwmp::Item& item, unsigned int action)
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Sending item change for %s with action %i, count %i",
|
||||
item.refId.c_str(), action, item.count);
|
||||
|
||||
inventoryChanges.items.clear();
|
||||
inventoryChanges.items.push_back(item);
|
||||
inventoryChanges.action = action;
|
||||
|
||||
getNetworking()->getPlayerPacket(ID_PLAYER_INVENTORY)->setPlayer(this);
|
||||
getNetworking()->getPlayerPacket(ID_PLAYER_INVENTORY)->Send();
|
||||
}
|
||||
|
||||
void LocalPlayer::sendItemChange(const MWWorld::Ptr& itemPtr, int count, unsigned int action)
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Sending item change for %s with action %i, count %i",
|
||||
itemPtr.getCellRef().getRefId().c_str(), action, count);
|
||||
|
||||
inventoryChanges.items.clear();
|
||||
|
||||
mwmp::Item item;
|
||||
|
||||
if (itemPtr.getClass().isGold(itemPtr))
|
||||
item.refId = MWWorld::ContainerStore::sGoldId;
|
||||
else
|
||||
item.refId = itemPtr.getCellRef().getRefId();
|
||||
|
||||
item.count = count;
|
||||
item.charge = itemPtr.getCellRef().getCharge();
|
||||
item.enchantmentCharge = itemPtr.getCellRef().getEnchantmentCharge();
|
||||
item.soul = itemPtr.getCellRef().getSoul();
|
||||
|
||||
inventoryChanges.items.push_back(item);
|
||||
|
||||
inventoryChanges.action = action;
|
||||
getNetworking()->getPlayerPacket(ID_PLAYER_INVENTORY)->setPlayer(this);
|
||||
getNetworking()->getPlayerPacket(ID_PLAYER_INVENTORY)->Send();
|
||||
mwmp::Item item = MechanicsHelper::getItem(itemPtr, count);
|
||||
sendItemChange(item, action);
|
||||
}
|
||||
|
||||
void LocalPlayer::sendItemChange(const std::string& refId, int count, unsigned int action)
|
||||
|
|
|
@ -77,6 +77,7 @@ namespace mwmp
|
|||
|
||||
void sendClass();
|
||||
void sendInventory();
|
||||
void sendItemChange(const mwmp::Item& item, unsigned int action);
|
||||
void sendItemChange(const MWWorld::Ptr& itemPtr, int count, unsigned int action);
|
||||
void sendItemChange(const std::string& refId, int count, unsigned int action);
|
||||
void sendSpellbook();
|
||||
|
|
|
@ -51,8 +51,8 @@ using namespace mwmp;
|
|||
using namespace std;
|
||||
|
||||
Main *Main::pMain = 0;
|
||||
std::string Main::addr = "";
|
||||
std::string Main::passw = TES3MP_DEFAULT_PASSW;
|
||||
std::string Main::address = "";
|
||||
std::string Main::serverPassword = TES3MP_DEFAULT_PASSW;
|
||||
std::string Main::resourceDir = "";
|
||||
|
||||
std::string Main::getResDir()
|
||||
|
@ -118,8 +118,8 @@ void Main::optionsDesc(boost::program_options::options_description *desc)
|
|||
|
||||
void Main::configure(const boost::program_options::variables_map &variables)
|
||||
{
|
||||
Main::addr = variables["connect"].as<string>();
|
||||
Main::passw = variables["password"].as<string>();
|
||||
Main::address = variables["connect"].as<string>();
|
||||
Main::serverPassword = variables["password"].as<string>();
|
||||
resourceDir = variables["resources"].as<Files::EscapeHashString>().toStdString();
|
||||
}
|
||||
|
||||
|
@ -155,22 +155,22 @@ bool Main::init(std::vector<std::string> &content, Files::Collections &collectio
|
|||
|
||||
int logLevel = mgr.getInt("logLevel", "General");
|
||||
Log::SetLevel(logLevel);
|
||||
if (addr.empty())
|
||||
if (address.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;
|
||||
serverPassword = mgr.getString("password", "General");
|
||||
if (serverPassword.empty())
|
||||
serverPassword = 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());
|
||||
size_t delimPos = address.find(':');
|
||||
pMain->server = address.substr(0, delimPos);
|
||||
pMain->port = atoi(address.substr(delimPos + 1).c_str());
|
||||
}
|
||||
get().mLocalPlayer->passw = passw;
|
||||
get().mLocalPlayer->serverPassword = serverPassword;
|
||||
|
||||
pMain->mNetworking->connect(pMain->server, pMain->port, content, collections);
|
||||
RestoreMgr(mgr);
|
||||
|
|
|
@ -39,8 +39,8 @@ namespace mwmp
|
|||
|
||||
private:
|
||||
static std::string resourceDir;
|
||||
static std::string addr;
|
||||
static std::string passw;
|
||||
static std::string address;
|
||||
static std::string serverPassword;
|
||||
Main (const Main&);
|
||||
///< not implemented
|
||||
Main& operator= (const Main&);
|
||||
|
|
|
@ -125,6 +125,23 @@ MWWorld::Ptr MechanicsHelper::getPlayerPtr(const Target& target)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
mwmp::Item MechanicsHelper::getItem(const MWWorld::Ptr& itemPtr, int count)
|
||||
{
|
||||
mwmp::Item item;
|
||||
|
||||
if (itemPtr.getClass().isGold(itemPtr))
|
||||
item.refId = MWWorld::ContainerStore::sGoldId;
|
||||
else
|
||||
item.refId = itemPtr.getCellRef().getRefId();
|
||||
|
||||
item.count = count;
|
||||
item.charge = itemPtr.getCellRef().getCharge();
|
||||
item.enchantmentCharge = itemPtr.getCellRef().getEnchantmentCharge();
|
||||
item.soul = itemPtr.getCellRef().getSoul();
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
mwmp::Target MechanicsHelper::getTarget(const MWWorld::Ptr& ptr)
|
||||
{
|
||||
mwmp::Target target;
|
||||
|
@ -393,18 +410,14 @@ void MechanicsHelper::processAttack(Attack attack, const MWWorld::Ptr& attacker)
|
|||
break;
|
||||
}
|
||||
|
||||
if (it != inventoryStore.end())
|
||||
{
|
||||
inventoryStore.setSelectedEnchantItem(it);
|
||||
LOG_APPEND(Log::LOG_VERBOSE, "- itemId: %s", attack.itemId.c_str());
|
||||
MWBase::Environment::get().getWorld()->castSpell(attacker);
|
||||
inventoryStore.setSelectedEnchantItem(inventoryStore.end());
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Could not find item %s used by %s to cast item spell!",
|
||||
attack.itemId.c_str(), attacker.getCellRef().getRefId().c_str());
|
||||
}
|
||||
// Add the item if it's missing
|
||||
if (it == inventoryStore.end())
|
||||
it = attacker.getClass().getContainerStore(attacker).add(attack.itemId, 1, attacker);
|
||||
|
||||
inventoryStore.setSelectedEnchantItem(it);
|
||||
LOG_APPEND(Log::LOG_VERBOSE, "- itemId: %s", attack.itemId.c_str());
|
||||
MWBase::Environment::get().getWorld()->castSpell(attacker);
|
||||
inventoryStore.setSelectedEnchantItem(inventoryStore.end());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ namespace MechanicsHelper
|
|||
|
||||
MWWorld::Ptr getPlayerPtr(const mwmp::Target& target);
|
||||
|
||||
mwmp::Item getItem(const MWWorld::Ptr& itemPtr, int count);
|
||||
mwmp::Target getTarget(const MWWorld::Ptr& ptr);
|
||||
void clearTarget(mwmp::Target& target);
|
||||
bool isEmptyTarget(const mwmp::Target& target);
|
||||
|
|
|
@ -110,7 +110,7 @@ void RecordHelper::overrideCreatureRecord(const mwmp::CreatureRecord& record)
|
|||
|
||||
if (recordData.mId.empty())
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Ignoring record override with no id provided");
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with no id provided");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -164,6 +164,11 @@ void RecordHelper::overrideCreatureRecord(const mwmp::CreatureRecord& record)
|
|||
|
||||
world->getModifiableStore().overrideRecord(finalData);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with invalid baseId %s", record.baseId.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (isExistingId)
|
||||
world->updatePtrsWithRefId(recordData.mId);
|
||||
|
@ -175,7 +180,7 @@ void RecordHelper::overrideNpcRecord(const mwmp::NpcRecord& record)
|
|||
|
||||
if (recordData.mId.empty())
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Ignoring record override with no id provided");
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with no id provided");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -186,12 +191,12 @@ void RecordHelper::overrideNpcRecord(const mwmp::NpcRecord& record)
|
|||
{
|
||||
if (!doesRaceRecordExist(recordData.mRace))
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Ignoring new NPC record with invalid race provided");
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring new NPC record with invalid race provided");
|
||||
return;
|
||||
}
|
||||
else if (!doesClassRecordExist(recordData.mClass))
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Ignoring new NPC record with invalid class provided");
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring new NPC record with invalid class provided");
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
@ -272,6 +277,11 @@ void RecordHelper::overrideNpcRecord(const mwmp::NpcRecord& record)
|
|||
|
||||
world->getModifiableStore().overrideRecord(finalData);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with invalid baseId %s", record.baseId.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (isExistingId)
|
||||
world->updatePtrsWithRefId(recordData.mId);
|
||||
|
@ -283,18 +293,17 @@ void RecordHelper::overrideEnchantmentRecord(const mwmp::EnchantmentRecord& reco
|
|||
|
||||
if (recordData.mId.empty())
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Ignoring record override with no id provided");
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with no id provided");
|
||||
return;
|
||||
}
|
||||
|
||||
bool isExistingId = doesEnchantmentRecordExist(recordData.mId);
|
||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
|
||||
if (record.baseId.empty())
|
||||
{
|
||||
if (recordData.mEffects.mList.empty())
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Ignoring new enchantment record with no effects");
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring new enchantment record with no effects");
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
@ -323,6 +332,11 @@ void RecordHelper::overrideEnchantmentRecord(const mwmp::EnchantmentRecord& reco
|
|||
|
||||
world->getModifiableStore().overrideRecord(finalData);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with invalid baseId %s", record.baseId.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void RecordHelper::overridePotionRecord(const mwmp::PotionRecord& record)
|
||||
|
@ -331,7 +345,7 @@ void RecordHelper::overridePotionRecord(const mwmp::PotionRecord& record)
|
|||
|
||||
if (recordData.mId.empty())
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Ignoring record override with no id provided");
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with no id provided");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -374,6 +388,11 @@ void RecordHelper::overridePotionRecord(const mwmp::PotionRecord& record)
|
|||
|
||||
world->getModifiableStore().overrideRecord(finalData);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with invalid baseId %s", record.baseId.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (isExistingId)
|
||||
world->updatePtrsWithRefId(recordData.mId);
|
||||
|
@ -385,7 +404,7 @@ void RecordHelper::overrideSpellRecord(const mwmp::SpellRecord& record)
|
|||
|
||||
if (recordData.mId.empty())
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Ignoring record override with no id provided");
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with no id provided");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -419,9 +438,11 @@ void RecordHelper::overrideSpellRecord(const mwmp::SpellRecord& record)
|
|||
|
||||
world->getModifiableStore().overrideRecord(finalData);
|
||||
}
|
||||
|
||||
if (isExistingId)
|
||||
world->updatePtrsWithRefId(recordData.mId);
|
||||
else
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with invalid baseId %s", record.baseId.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void RecordHelper::overrideArmorRecord(const mwmp::ArmorRecord& record)
|
||||
|
@ -430,7 +451,7 @@ void RecordHelper::overrideArmorRecord(const mwmp::ArmorRecord& record)
|
|||
|
||||
if (recordData.mId.empty())
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Ignoring record override with no id provided");
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with no id provided");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -441,7 +462,7 @@ void RecordHelper::overrideArmorRecord(const mwmp::ArmorRecord& record)
|
|||
{
|
||||
if (!recordData.mEnchant.empty() && !doesEnchantmentRecordExist(recordData.mEnchant))
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Ignoring new armor record with invalid enchantment provided");
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring new armor record with invalid enchantmentId %s", recordData.mEnchant.c_str());
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
@ -479,8 +500,13 @@ void RecordHelper::overrideArmorRecord(const mwmp::ArmorRecord& record)
|
|||
if (record.baseOverrides.hasArmorRating)
|
||||
finalData.mData.mArmor = recordData.mData.mArmor;
|
||||
|
||||
if (record.baseOverrides.hasEnchantmentId && doesEnchantmentRecordExist(recordData.mEnchant))
|
||||
finalData.mEnchant = recordData.mEnchant;
|
||||
if (record.baseOverrides.hasEnchantmentId)
|
||||
{
|
||||
if (doesEnchantmentRecordExist(recordData.mEnchant))
|
||||
finalData.mEnchant = recordData.mEnchant;
|
||||
else
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring invalid enchantmentId %s", recordData.mEnchant.c_str());
|
||||
}
|
||||
|
||||
if (record.baseOverrides.hasEnchantmentCharge)
|
||||
finalData.mData.mEnchant = recordData.mData.mEnchant;
|
||||
|
@ -493,6 +519,11 @@ void RecordHelper::overrideArmorRecord(const mwmp::ArmorRecord& record)
|
|||
|
||||
world->getModifiableStore().overrideRecord(finalData);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with invalid baseId %s", record.baseId.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (isExistingId)
|
||||
world->updatePtrsWithRefId(recordData.mId);
|
||||
|
@ -504,7 +535,7 @@ void RecordHelper::overrideBookRecord(const mwmp::BookRecord& record)
|
|||
|
||||
if (recordData.mId.empty())
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Ignoring record override with no id provided");
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with no id provided");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -515,7 +546,7 @@ void RecordHelper::overrideBookRecord(const mwmp::BookRecord& record)
|
|||
{
|
||||
if (!recordData.mEnchant.empty() && !doesEnchantmentRecordExist(recordData.mEnchant))
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Ignoring new book record with invalid enchantment provided");
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring new book record with invalid enchantmentId %s", recordData.mEnchant.c_str());
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
@ -551,8 +582,13 @@ void RecordHelper::overrideBookRecord(const mwmp::BookRecord& record)
|
|||
if (record.baseOverrides.hasSkillId)
|
||||
finalData.mData.mSkillId = recordData.mData.mSkillId;
|
||||
|
||||
if (record.baseOverrides.hasEnchantmentId && doesEnchantmentRecordExist(recordData.mEnchant))
|
||||
finalData.mEnchant = recordData.mEnchant;
|
||||
if (record.baseOverrides.hasEnchantmentId)
|
||||
{
|
||||
if (doesEnchantmentRecordExist(recordData.mEnchant))
|
||||
finalData.mEnchant = recordData.mEnchant;
|
||||
else
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring invalid enchantmentId %s", recordData.mEnchant.c_str());
|
||||
}
|
||||
|
||||
if (record.baseOverrides.hasEnchantmentCharge)
|
||||
finalData.mData.mEnchant = recordData.mData.mEnchant;
|
||||
|
@ -562,6 +598,11 @@ void RecordHelper::overrideBookRecord(const mwmp::BookRecord& record)
|
|||
|
||||
world->getModifiableStore().overrideRecord(finalData);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with invalid baseId %s", record.baseId.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (isExistingId)
|
||||
world->updatePtrsWithRefId(recordData.mId);
|
||||
|
@ -573,7 +614,7 @@ void RecordHelper::overrideClothingRecord(const mwmp::ClothingRecord& record)
|
|||
|
||||
if (recordData.mId.empty())
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Ignoring record override with no id provided");
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with no id provided");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -584,7 +625,7 @@ void RecordHelper::overrideClothingRecord(const mwmp::ClothingRecord& record)
|
|||
{
|
||||
if (!recordData.mEnchant.empty() && !doesEnchantmentRecordExist(recordData.mEnchant))
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Ignoring new clothing record with invalid enchantment provided");
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring new clothing record with invalid enchantmentId %s", recordData.mEnchant.c_str());
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
@ -614,8 +655,13 @@ void RecordHelper::overrideClothingRecord(const mwmp::ClothingRecord& record)
|
|||
if (record.baseOverrides.hasValue)
|
||||
finalData.mData.mValue = recordData.mData.mValue;
|
||||
|
||||
if (record.baseOverrides.hasEnchantmentId && doesEnchantmentRecordExist(recordData.mEnchant))
|
||||
finalData.mEnchant = recordData.mEnchant;
|
||||
if (record.baseOverrides.hasEnchantmentId)
|
||||
{
|
||||
if (doesEnchantmentRecordExist(recordData.mEnchant))
|
||||
finalData.mEnchant = recordData.mEnchant;
|
||||
else
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring invalid enchantmentId %s", recordData.mEnchant.c_str());
|
||||
}
|
||||
|
||||
if (record.baseOverrides.hasEnchantmentCharge)
|
||||
finalData.mData.mEnchant = recordData.mData.mEnchant;
|
||||
|
@ -628,6 +674,11 @@ void RecordHelper::overrideClothingRecord(const mwmp::ClothingRecord& record)
|
|||
|
||||
world->getModifiableStore().overrideRecord(finalData);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with invalid baseId %s", record.baseId.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (isExistingId)
|
||||
world->updatePtrsWithRefId(recordData.mId);
|
||||
|
@ -639,7 +690,7 @@ void RecordHelper::overrideMiscellaneousRecord(const mwmp::MiscellaneousRecord&
|
|||
|
||||
if (recordData.mId.empty())
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Ignoring record override with no id provided");
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with no id provided");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -679,6 +730,11 @@ void RecordHelper::overrideMiscellaneousRecord(const mwmp::MiscellaneousRecord&
|
|||
|
||||
world->getModifiableStore().overrideRecord(finalData);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with invalid baseId %s", record.baseId.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (isExistingId)
|
||||
world->updatePtrsWithRefId(recordData.mId);
|
||||
|
@ -690,7 +746,7 @@ void RecordHelper::overrideWeaponRecord(const mwmp::WeaponRecord& record)
|
|||
|
||||
if (recordData.mId.empty())
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Ignoring record override with no id provided");
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with no id provided");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -701,7 +757,7 @@ void RecordHelper::overrideWeaponRecord(const mwmp::WeaponRecord& record)
|
|||
{
|
||||
if (!recordData.mEnchant.empty() && !doesEnchantmentRecordExist(recordData.mEnchant))
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Ignoring new weapon record with invalid enchantment provided");
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring new weapon record with invalid enchantmentId %s", recordData.mEnchant.c_str());
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
@ -761,8 +817,13 @@ void RecordHelper::overrideWeaponRecord(const mwmp::WeaponRecord& record)
|
|||
if (record.baseOverrides.hasFlags)
|
||||
finalData.mData.mFlags = recordData.mData.mFlags;
|
||||
|
||||
if (record.baseOverrides.hasEnchantmentId && doesEnchantmentRecordExist(recordData.mEnchant))
|
||||
finalData.mEnchant = recordData.mEnchant;
|
||||
if (record.baseOverrides.hasEnchantmentId)
|
||||
{
|
||||
if (doesEnchantmentRecordExist(recordData.mEnchant))
|
||||
finalData.mEnchant = recordData.mEnchant;
|
||||
else
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring invalid enchantmentId %s", recordData.mEnchant.c_str());
|
||||
}
|
||||
|
||||
if (record.baseOverrides.hasEnchantmentCharge)
|
||||
finalData.mData.mEnchant = recordData.mData.mEnchant;
|
||||
|
@ -772,6 +833,11 @@ void RecordHelper::overrideWeaponRecord(const mwmp::WeaponRecord& record)
|
|||
|
||||
world->getModifiableStore().overrideRecord(finalData);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with invalid baseId %s", record.baseId.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (isExistingId)
|
||||
world->updatePtrsWithRefId(recordData.mId);
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -613,13 +613,17 @@ namespace MWScript
|
|||
Start of tes3mp addition
|
||||
|
||||
Send an ID_OBJECT_STATE packet whenever an object is enabled, as long as
|
||||
the player is logged in on the server and the object wasn't already
|
||||
enabled previously
|
||||
the player is logged in on the server, the object is still disabled, and our last
|
||||
packet regarding its state did not already attempt to enable it (to prevent
|
||||
packet spam)
|
||||
*/
|
||||
if (mwmp::Main::get().getLocalPlayer()->isLoggedIn())
|
||||
{
|
||||
if (ref.isInCell() && !ref.getRefData().isEnabled())
|
||||
if (ref.isInCell() && !ref.getRefData().isEnabled() &&
|
||||
ref.getRefData().getLastCommunicatedState() != MWWorld::RefData::StateCommunication::Enabled)
|
||||
{
|
||||
ref.getRefData().setLastCommunicatedState(MWWorld::RefData::StateCommunication::Enabled);
|
||||
|
||||
mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList();
|
||||
objectList->reset();
|
||||
objectList->packetOrigin = ScriptController::getPacketOriginFromContextType(getContextType());
|
||||
|
@ -650,14 +654,18 @@ namespace MWScript
|
|||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Send an ID_OBJECT_STATE packet whenever an object is disabled, as long as
|
||||
the player is logged in on the server and the object wasn't already
|
||||
disabled previously
|
||||
Send an ID_OBJECT_STATE packet whenever an object should be disabled, as long as
|
||||
the player is logged in on the server, the object is still enabled, and our last
|
||||
packet regarding its state did not already attempt to disable it (to prevent
|
||||
packet spam)
|
||||
*/
|
||||
if (mwmp::Main::get().getLocalPlayer()->isLoggedIn())
|
||||
{
|
||||
if (ref.isInCell() && ref.getRefData().isEnabled())
|
||||
if (ref.isInCell() && ref.getRefData().isEnabled() &&
|
||||
ref.getRefData().getLastCommunicatedState() != MWWorld::RefData::StateCommunication::Disabled)
|
||||
{
|
||||
ref.getRefData().setLastCommunicatedState(MWWorld::RefData::StateCommunication::Disabled);
|
||||
|
||||
mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList();
|
||||
objectList->reset();
|
||||
objectList->packetOrigin = ScriptController::getPacketOriginFromContextType(getContextType());
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
Include additional headers for multiplayer purposes
|
||||
*/
|
||||
#include <components/openmw-mp/Log.hpp>
|
||||
#include "../mwmp/Main.hpp"
|
||||
#include "../mwmp/CellController.hpp"
|
||||
#include "../mwmp/PlayerList.hpp"
|
||||
|
@ -251,7 +252,19 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::findSlot (int slot) con
|
|||
{
|
||||
// Object has been deleted
|
||||
// This should no longer happen, since the new remove function will unequip first
|
||||
throw std::runtime_error("Invalid slot, make sure you are not calling RefData::setCount for a container object");
|
||||
|
||||
/*
|
||||
Start of tes3mp change (major)
|
||||
|
||||
Instead of throwing an error, display an error log message with information about
|
||||
the item
|
||||
*/
|
||||
//throw std::runtime_error("Invalid slot, make sure you are not calling RefData::setCount for a container object");
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Invalid slot, make sure you are not calling RefData::setCount for a container object\n- item was %s",
|
||||
mSlots[slot]->getCellRef().getRefId().c_str());
|
||||
/*
|
||||
End of tes3mp change (major)
|
||||
*/
|
||||
}
|
||||
|
||||
return mSlots[slot];
|
||||
|
|
|
@ -138,6 +138,34 @@ namespace MWWorld
|
|||
|
||||
const ESM::AnimationState& getAnimationState() const;
|
||||
ESM::AnimationState& getAnimationState();
|
||||
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Track the last state communicated to the server for this reference,
|
||||
to avoid packet spam when the server denies our state change request or
|
||||
is slow to reply
|
||||
*/
|
||||
enum StateCommunication
|
||||
{
|
||||
None = 0,
|
||||
Enabled = 1,
|
||||
Disabled = 2
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
short mLastCommunicatedState = StateCommunication::None;
|
||||
|
||||
public:
|
||||
|
||||
short getLastCommunicatedState() { return mLastCommunicatedState; };
|
||||
|
||||
void setLastCommunicatedState(short communicationState) { mLastCommunicatedState = communicationState; };
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -3258,10 +3258,11 @@ namespace MWWorld
|
|||
|
||||
If this actor is a LocalPlayer or LocalActor, get their Attack and prepare
|
||||
it for sending
|
||||
|
||||
Set the attack details before going through with the casting, in case it's
|
||||
a one use item that would get removed through the casting (like a scroll)
|
||||
*/
|
||||
{
|
||||
cast.cast(*inv.getSelectedEnchantItem());
|
||||
|
||||
mwmp::Attack *localAttack = MechanicsHelper::getLocalAttack(actor);
|
||||
|
||||
if (localAttack)
|
||||
|
@ -3271,6 +3272,8 @@ namespace MWWorld
|
|||
localAttack->itemId = inv.getSelectedEnchantItem()->getCellRef().getRefId();
|
||||
localAttack->shouldSend = true;
|
||||
}
|
||||
|
||||
cast.cast(*inv.getSelectedEnchantItem());
|
||||
}
|
||||
/*
|
||||
End of tes3mp addition
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
||||
|
|
|
@ -232,6 +232,8 @@ namespace mwmp
|
|||
}
|
||||
|
||||
RakNet::RakNetGUID guid;
|
||||
std::string serverPassword;
|
||||
|
||||
GUIMessageBox guiMessageBox;
|
||||
|
||||
// Track only the indexes of the attributes that have been changed,
|
||||
|
@ -295,7 +297,6 @@ namespace mwmp
|
|||
std::string birthsign;
|
||||
std::string chatMessage;
|
||||
CharGenState charGenState;
|
||||
std::string passw;
|
||||
|
||||
std::string sound;
|
||||
Animation animation;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
//
|
||||
// Created by koncord on 28.04.16.
|
||||
//
|
||||
|
||||
#include <components/openmw-mp/NetworkMessages.hpp>
|
||||
#include "PacketHandshake.hpp"
|
||||
|
||||
|
@ -17,8 +13,8 @@ void PacketHandshake::Packet(RakNet::BitStream *bs, bool send)
|
|||
{
|
||||
PlayerPacket::Packet(bs, send);
|
||||
|
||||
if (!RW(player->npc.mName, send, true, maxNameLen) ||
|
||||
!RW(player->passw, send, true, maxPasswLen))
|
||||
if (!RW(player->npc.mName, send, true, maxNameLength) ||
|
||||
!RW(player->serverPassword, send, true, maxPasswordLength))
|
||||
{
|
||||
packetValid = false;
|
||||
return;
|
||||
|
|
|
@ -16,8 +16,8 @@ namespace mwmp
|
|||
|
||||
virtual void Packet(RakNet::BitStream *bs, bool send);
|
||||
|
||||
const static uint32_t maxNameLen = 256;
|
||||
const static uint32_t maxPasswLen = 256;
|
||||
const static uint32_t maxNameLength = 256;
|
||||
const static uint32_t maxPasswordLength = 256;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
17
components/openmw-mp/Packets/Worldstate/PacketCellReset.cpp
Normal file
17
components/openmw-mp/Packets/Worldstate/PacketCellReset.cpp
Normal 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
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
|
@ -211,7 +212,7 @@ void Utils::printVersion(std::string appName, std::string version, std::string c
|
|||
cout << appName << " " << version;
|
||||
cout << " (" << getOperatingSystemType() << " " << getArchitectureType() << ")" << endl;
|
||||
cout << "Protocol version: " << protocol << endl;
|
||||
cout << "Commit hash: " << commitHash.substr(0, 10) << endl;
|
||||
cout << "Oldest compatible commit hash: " << commitHash.substr(0, 10) << endl;
|
||||
|
||||
cout << "------------------------------------------------------------" << endl;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#define TES3MP_DEFAULT_PASSW "SuperPassword"
|
||||
#define TES3MP_MASTERSERVER_PASSW "12345"
|
||||
|
||||
#define TES3MP_CREDITS_CHECKSUM "BC39D2E9"
|
||||
#define TES3MP_CREDITS_CHECKSUM "BAEFF920"
|
||||
|
||||
|
||||
#endif //OPENMW_VERSION_HPP
|
||||
|
|
|
@ -4,14 +4,14 @@ tes3mp Credits
|
|||
Programmers
|
||||
----------------
|
||||
|
||||
Stanislav Zhukov (Koncord) - Overall architecture, networking & scripting systems, player sync, server browser & master server
|
||||
Stanislav Zhukov (Koncord) - Architecture, networking & scripting systems, player sync, server browser & master server
|
||||
David Cernat - World, NPC & quest sync, player sync improvements, state saving & loading, extensive bug fixes
|
||||
|
||||
|
||||
Additional programming
|
||||
----------------------
|
||||
|
||||
Grim Kriegor - Lua teleportation commands, early script fixes
|
||||
Grim Kriegor - Linux deployment scripts, Lua teleportation commands, early script fixes
|
||||
Battlerax - Various small fixes
|
||||
|
||||
|
||||
|
@ -26,6 +26,7 @@ Community administrators
|
|||
Community moderators
|
||||
--------------------
|
||||
|
||||
Lysol
|
||||
Michael Fitzmayer (mupf)
|
||||
Nac
|
||||
NicholasAH
|
||||
|
@ -53,6 +54,7 @@ Translation
|
|||
Super special thanks
|
||||
--------------------
|
||||
|
||||
Alexander Ovsyannikov
|
||||
Bret Curtis (psi29a)
|
||||
Gabriel Pascu (iGrebla)
|
||||
greetasdf
|
||||
|
@ -73,8 +75,9 @@ Special thanks
|
|||
Gluka
|
||||
Goodevil
|
||||
Ignatious
|
||||
James Wards of Gore Corps LAN Club (www.gorecorps.co.nz)
|
||||
James Wards of Gore Corps LAN Club (gorecorps.co.nz)
|
||||
Jeremiah
|
||||
Kyle Willey of Loreshaper Games (steempeak.com/@loreshapergames)
|
||||
Lewis Sadlier
|
||||
Luc Keating
|
||||
Michael Zagar (Zoops)
|
||||
|
@ -84,6 +87,7 @@ Special thanks
|
|||
Scorcio
|
||||
Simon Nemes
|
||||
Texafornian
|
||||
Thrud
|
||||
Zaphida
|
||||
All the developers of OpenMW for creating an amazing open source project
|
||||
|
||||
|
|
Loading…
Reference in a new issue