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
|
osx_image: xcode9.4
|
||||||
language: cpp
|
language: cpp
|
||||||
sudo: required
|
sudo: required
|
||||||
dist: trusty
|
dist: xenial
|
||||||
branches:
|
branches:
|
||||||
only:
|
only:
|
||||||
- master
|
- master
|
||||||
|
@ -15,18 +15,18 @@ env:
|
||||||
global:
|
global:
|
||||||
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
|
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
|
||||||
# via the "travis encrypt" command using the project repo's public key
|
# 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:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
- sourceline: 'ppa:openmw/openmw'
|
- sourceline: 'ppa:openmw/openmw'
|
||||||
- sourceline: 'ppa:rakhimov/boost'
|
- sourceline: 'ppa:rakhimov/boost'
|
||||||
- ubuntu-toolchain-r-test
|
- ubuntu-toolchain-r-test
|
||||||
- llvm-toolchain-precise-3.8
|
|
||||||
packages: [
|
packages: [
|
||||||
# Dev
|
# Dev
|
||||||
cmake, clang-3.8, libunshield-dev, libtinyxml-dev,
|
cmake, clang-6.0, libunshield-dev, libtinyxml-dev,
|
||||||
g++-6,
|
g++-8,
|
||||||
# Tests
|
# Tests
|
||||||
libgtest-dev, google-mock,
|
libgtest-dev, google-mock,
|
||||||
# Boost
|
# Boost
|
||||||
|
@ -45,7 +45,7 @@ addons:
|
||||||
project:
|
project:
|
||||||
name: "TES3MP/openmw-tes3mp"
|
name: "TES3MP/openmw-tes3mp"
|
||||||
description: "<Your project description here>"
|
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_prepend: "cmake . -DBUILD_UNITTESTS=FALSE -DBUILD_OPENCS=FALSE -DBUILD_BSATOOL=FALSE -DBUILD_ESMTOOL=FALSE -DBUILD_MWINIIMPORTER=FALSE -DBUILD_LAUNCHER=FALSE"
|
||||||
build_command: "make -j3"
|
build_command: "make -j3"
|
||||||
branch_pattern: coverity_scan
|
branch_pattern: coverity_scan
|
||||||
|
@ -53,21 +53,21 @@ matrix:
|
||||||
include:
|
include:
|
||||||
- os: linux
|
- os: linux
|
||||||
env:
|
env:
|
||||||
- ANALYZE="scan-build-3.8 --use-cc clang-3.8 --use-c++ clang++-3.8 "
|
- ANALYZE="scan-build-6.0 --use-cc clang-6.0 --use-c++ clang++-6.0 "
|
||||||
- MATRIX_CC="CC=clang-3.8 && CXX=clang++-3.8"
|
- MATRIX_CC="CC=clang-6.0 && CXX=clang++-6.0"
|
||||||
compiler: clang
|
compiler: clang
|
||||||
- os: linux
|
- os: linux
|
||||||
env:
|
env:
|
||||||
- MATRIX_CC="CC=gcc-6 && CXX=g++-6"
|
- MATRIX_CC="CC=gcc-8 && CXX=g++-8"
|
||||||
- os: linux
|
- os: linux
|
||||||
env:
|
env:
|
||||||
- MATRIX_CC="CC=clang-3.8 && CXX=clang++-3.8"
|
- MATRIX_CC="CC=clang-6.0 && CXX=clang++-6.0"
|
||||||
allow_failures:
|
allow_failures:
|
||||||
- env:
|
- env:
|
||||||
- MATRIX_CC="CC=clang-3.8 && CXX=clang++-3.8"
|
- MATRIX_CC="CC=clang-6.0 && CXX=clang++-6.0"
|
||||||
- env:
|
- env:
|
||||||
- ANALYZE="scan-build-3.8 --use-cc clang-3.8 --use-c++ clang++-3.8 "
|
- ANALYZE="scan-build-6.0 --use-cc clang-6.0 --use-c++ clang++-6.0 "
|
||||||
- MATRIX_CC="CC=clang-3.8 && CXX=clang++-3.8"
|
- MATRIX_CC="CC=clang-6.0 && CXX=clang++-6.0"
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- ./CI/before_install.${TRAVIS_OS_NAME}.sh
|
- ./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
|
sudo ln -s /usr/src/gtest/build/libgtest_main.so /usr/lib/libgtest_main.so
|
||||||
|
|
||||||
cd ~/
|
cd ~/
|
||||||
git clone https://github.com/TES3MP/RakNet
|
git clone https://github.com/TES3MP/CrabNet
|
||||||
cd RakNet
|
cd CrabNet
|
||||||
cmake . -DRAKNET_ENABLE_DLL=OFF -DRAKNET_ENABLE_SAMPLES=OFF -DCMAKE_BUILD_TYPE=Release
|
cmake . -DCRABNET_ENABLE_DLL=OFF -DCRABNET_ENABLE_SAMPLES=OFF -DCMAKE_BUILD_TYPE=Release
|
||||||
make -j3
|
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}"
|
eval "${MATRIX_CC}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
export RAKNET_ROOT=~/RakNet
|
export RAKNET_ROOT=~/CrabNet
|
||||||
export Terra_ROOT=~/terra-Linux-x86_64-332a506
|
|
||||||
|
|
||||||
export CODE_COVERAGE=0
|
export CODE_COVERAGE=0
|
||||||
if [ ! -z "${ANALYZE}" ]; then
|
if [ ! -z "${ANALYZE}" ]; then
|
||||||
|
@ -36,7 +35,5 @@ ${ANALYZE}cmake .. \
|
||||||
-DBINDIR=/usr/games \
|
-DBINDIR=/usr/games \
|
||||||
-DCMAKE_BUILD_TYPE="None" \
|
-DCMAKE_BUILD_TYPE="None" \
|
||||||
-DUSE_SYSTEM_TINYXML=TRUE \
|
-DUSE_SYSTEM_TINYXML=TRUE \
|
||||||
-DRakNet_LIBRARY_RELEASE=~/RakNet/lib/libRakNetLibStatic.a \
|
-DRakNet_LIBRARY_RELEASE=~/CrabNet/lib/libRakNetLibStatic.a \
|
||||||
-DRakNet_LIBRARY_DEBUG=~/RakNet/lib/libRakNetLibStatic.a \
|
-DRakNet_LIBRARY_DEBUG=~/CrabNet/lib/libRakNetLibStatic.a
|
||||||
-DCallFF_INCLUDES=~/CallFF/include \
|
|
||||||
-DCallFF_LIBRARY=~/CallFF/build/src/libcallff.a
|
|
||||||
|
|
23
README.md
23
README.md
|
@ -2,7 +2,7 @@ TES3MP
|
||||||
======
|
======
|
||||||
|
|
||||||
Copyright (c) 2008-2015, OpenMW Team
|
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)
|
[](https://travis-ci.org/TES3MP/openmw-tes3mp)
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ TES3MP is a project adding multiplayer functionality to [OpenMW](https://github.
|
||||||
Font Licenses:
|
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)
|
* 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)
|
[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.
|
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
|
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.
|
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)
|
* [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/)
|
* [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)
|
* [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)
|
* [Subreddit](https://www.reddit.com/r/tes3mp)
|
||||||
* [Known issues and bug reports](https://github.com/TES3MP/openmw-tes3mp/issues)
|
* [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;
|
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
|
bool Networking::isPassworded() const
|
||||||
|
@ -98,25 +98,32 @@ void Networking::processPlayerPacket(RakNet::Packet *packet)
|
||||||
|
|
||||||
if (!myPacket->isPacketValid())
|
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);
|
kickPlayer(player->guid);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (player->isHandshaked())
|
if (player->isHandshaked())
|
||||||
{
|
{
|
||||||
LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Wrong handshake with player %d, name: %s", player->getId(),
|
LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Wrong handshake with client at %s", packet->systemAddress.ToString());
|
||||||
player->npc.mName.c_str());
|
|
||||||
kickPlayer(player->guid);
|
kickPlayer(player->guid);
|
||||||
return;
|
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)",
|
if (isPassworded())
|
||||||
player->getId(), player->npc.mName.c_str(), player->passw.c_str());
|
{
|
||||||
kickPlayer(player->guid);
|
LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Wrong server password %s used by client at %s",
|
||||||
return;
|
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();
|
player->setHandshake();
|
||||||
return;
|
return;
|
||||||
|
@ -125,9 +132,8 @@ void Networking::processPlayerPacket(RakNet::Packet *packet)
|
||||||
if (!player->isHandshaked())
|
if (!player->isHandshaked())
|
||||||
{
|
{
|
||||||
player->incrementHandshakeAttempts();
|
player->incrementHandshakeAttempts();
|
||||||
LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Have not completed handshake with player %d", player->getId());
|
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());
|
||||||
LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Attempts so far: %i", player->getHandshakeAttempts());
|
|
||||||
|
|
||||||
if (player->getHandshakeAttempts() > 20)
|
if (player->getHandshakeAttempts() > 20)
|
||||||
kickPlayer(player->guid, false);
|
kickPlayer(player->guid, false);
|
||||||
|
@ -579,8 +585,8 @@ void Networking::InitQuery(std::string queryAddr, unsigned short queryPort)
|
||||||
|
|
||||||
void Networking::postInit()
|
void Networking::postInit()
|
||||||
{
|
{
|
||||||
|
Script::Call<Script::CallbackIdentity("OnRequestDataFileList")>();
|
||||||
Script::Call<Script::CallbackIdentity("OnServerPostInit")>();
|
Script::Call<Script::CallbackIdentity("OnServerPostInit")>();
|
||||||
Script::Call<Script::CallbackIdentity("OnRequestPluginList")>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PacketPreInit::PluginContainer &Networking::getSamples()
|
PacketPreInit::PluginContainer &Networking::getSamples()
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
#include "Cell.hpp"
|
#include "Cell.hpp"
|
||||||
#include "CellController.hpp"
|
#include "CellController.hpp"
|
||||||
|
|
||||||
struct Player;
|
|
||||||
typedef std::map<RakNet::RakNetGUID, Player*> TPlayers;
|
typedef std::map<RakNet::RakNetGUID, Player*> TPlayers;
|
||||||
typedef std::map<unsigned short, Player*> TSlots;
|
typedef std::map<unsigned short, Player*> TSlots;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,3 @@
|
||||||
//
|
|
||||||
// Created by koncord on 15.03.16.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "TimerAPI.hpp"
|
#include "TimerAPI.hpp"
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
@ -14,7 +10,7 @@ Timer::Timer(ScriptFunc callback, long msec, const std::string& def, std::vector
|
||||||
{
|
{
|
||||||
targetMsec = msec;
|
targetMsec = msec;
|
||||||
this->args = args;
|
this->args = args;
|
||||||
end = true;
|
isEnded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(ENABLE_LUA)
|
#if defined(ENABLE_LUA)
|
||||||
|
@ -22,13 +18,13 @@ Timer::Timer(lua_State *lua, ScriptFuncLua callback, long msec, const std::strin
|
||||||
{
|
{
|
||||||
targetMsec = msec;
|
targetMsec = msec;
|
||||||
this->args = args;
|
this->args = args;
|
||||||
end = true;
|
isEnded = true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void Timer::Tick()
|
void Timer::Tick()
|
||||||
{
|
{
|
||||||
if (end)
|
if (isEnded)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const auto duration = chrono::system_clock::now().time_since_epoch();
|
const auto duration = chrono::system_clock::now().time_since_epoch();
|
||||||
|
@ -36,19 +32,19 @@ void Timer::Tick()
|
||||||
|
|
||||||
if (time - startTime >= targetMsec)
|
if (time - startTime >= targetMsec)
|
||||||
{
|
{
|
||||||
end = true;
|
isEnded = true;
|
||||||
Call(args);
|
Call(args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Timer::IsEnd()
|
bool Timer::IsEnded()
|
||||||
{
|
{
|
||||||
return end;
|
return isEnded;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Timer::Stop()
|
void Timer::Stop()
|
||||||
{
|
{
|
||||||
end = true;
|
isEnded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Timer::Restart(int msec)
|
void Timer::Restart(int msec)
|
||||||
|
@ -59,7 +55,7 @@ void Timer::Restart(int msec)
|
||||||
|
|
||||||
void Timer::Start()
|
void Timer::Start()
|
||||||
{
|
{
|
||||||
end = false;
|
isEnded = false;
|
||||||
|
|
||||||
const auto duration = chrono::system_clock::now().time_since_epoch();
|
const auto duration = chrono::system_clock::now().time_since_epoch();
|
||||||
const auto msec = chrono::duration_cast<chrono::milliseconds>(duration).count();
|
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;
|
bool ret = false;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ret = timers.at(timerid)->IsEnd();
|
ret = timers.at(timerid)->IsEnded();
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,7 +1,3 @@
|
||||||
//
|
|
||||||
// Created by koncord on 15.03.16.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef OPENMW_TIMERAPI_HPP
|
#ifndef OPENMW_TIMERAPI_HPP
|
||||||
#define OPENMW_TIMERAPI_HPP
|
#define OPENMW_TIMERAPI_HPP
|
||||||
|
|
||||||
|
@ -27,7 +23,7 @@ namespace mwmp
|
||||||
#endif
|
#endif
|
||||||
void Tick();
|
void Tick();
|
||||||
|
|
||||||
bool IsEnd();
|
bool IsEnded();
|
||||||
void Stop();
|
void Stop();
|
||||||
void Start();
|
void Start();
|
||||||
void Restart(int msec);
|
void Restart(int msec);
|
||||||
|
@ -36,7 +32,7 @@ namespace mwmp
|
||||||
std::string publ, arg_types;
|
std::string publ, arg_types;
|
||||||
std::vector<boost::any> args;
|
std::vector<boost::any> args;
|
||||||
Script *scr;
|
Script *scr;
|
||||||
bool end;
|
bool isEnded;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TimerAPI
|
class TimerAPI
|
||||||
|
@ -50,7 +46,7 @@ namespace mwmp
|
||||||
static void ResetTimer(int timerid, long msec);
|
static void ResetTimer(int timerid, long msec);
|
||||||
static void StartTimer(int timerid);
|
static void StartTimer(int timerid);
|
||||||
static void StopTimer(int timerid);
|
static void StopTimer(int timerid);
|
||||||
static bool IsEndTimer(int timerid);
|
static bool IsTimerElapsed(int timerid);
|
||||||
|
|
||||||
static void Terminate();
|
static void Terminate();
|
||||||
|
|
||||||
|
|
|
@ -537,7 +537,7 @@ void ActorFunctions::InitializeActorList(unsigned short pid) noexcept
|
||||||
|
|
||||||
void ActorFunctions::CopyLastActorListToStore() noexcept
|
void ActorFunctions::CopyLastActorListToStore() noexcept
|
||||||
{
|
{
|
||||||
CopyLastActorListToStore();
|
CopyReceivedActorListToStore();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int ActorFunctions::GetActorRefNumIndex(unsigned int index) noexcept
|
unsigned int ActorFunctions::GetActorRefNumIndex(unsigned int index) noexcept
|
||||||
|
|
|
@ -1,38 +1,12 @@
|
||||||
#include "Miscellaneous.hpp"
|
#include "Miscellaneous.hpp"
|
||||||
|
|
||||||
#include <components/misc/stringops.hpp>
|
|
||||||
#include <components/openmw-mp/Log.hpp>
|
#include <components/openmw-mp/Log.hpp>
|
||||||
|
|
||||||
#include <apps/openmw-mp/Script/ScriptFunctions.hpp>
|
|
||||||
#include <apps/openmw-mp/Networking.hpp>
|
#include <apps/openmw-mp/Networking.hpp>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
using namespace std;
|
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
|
unsigned int MiscellaneousFunctions::GetLastPlayerId() noexcept
|
||||||
{
|
{
|
||||||
return Players::getLastPlayerId();
|
return Players::getLastPlayerId();
|
||||||
|
@ -47,13 +21,3 @@ void MiscellaneousFunctions::SetCurrentMpNum(int mpNum) noexcept
|
||||||
{
|
{
|
||||||
mwmp::Networking::getPtr()->setCurrentMpNum(mpNum);
|
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"
|
#include "../Types.hpp"
|
||||||
|
|
||||||
#define MISCELLANEOUSAPI \
|
#define MISCELLANEOUSAPI \
|
||||||
{"DoesFileExist", MiscellaneousFunctions::DoesFileExist},\
|
|
||||||
{"GetCaseInsensitiveFilename", MiscellaneousFunctions::GetCaseInsensitiveFilename},\
|
|
||||||
\
|
|
||||||
{"GetLastPlayerId", MiscellaneousFunctions::GetLastPlayerId},\
|
{"GetLastPlayerId", MiscellaneousFunctions::GetLastPlayerId},\
|
||||||
\
|
\
|
||||||
{"GetCurrentMpNum", MiscellaneousFunctions::GetCurrentMpNum},\
|
{"GetCurrentMpNum", MiscellaneousFunctions::GetCurrentMpNum},\
|
||||||
{"SetCurrentMpNum", MiscellaneousFunctions::SetCurrentMpNum},\
|
{"SetCurrentMpNum", MiscellaneousFunctions::SetCurrentMpNum}
|
||||||
\
|
|
||||||
{"LogMessage", MiscellaneousFunctions::LogMessage},\
|
|
||||||
{"LogAppend", MiscellaneousFunctions::LogAppend}
|
|
||||||
|
|
||||||
class MiscellaneousFunctions
|
class MiscellaneousFunctions
|
||||||
{
|
{
|
||||||
public:
|
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.
|
* \brief Get the last player ID currently connected to the server.
|
||||||
*
|
*
|
||||||
|
@ -75,30 +48,6 @@ public:
|
||||||
* \return void
|
* \return void
|
||||||
*/
|
*/
|
||||||
static void SetCurrentMpNum(int mpNum) noexcept;
|
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
|
#endif //OPENMW_MISCELLANEOUSAPI_HPP
|
||||||
|
|
|
@ -7,20 +7,6 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
using namespace std;
|
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
|
double PositionFunctions::GetPosX(unsigned short pid) noexcept
|
||||||
{
|
{
|
||||||
Player *player;
|
Player *player;
|
||||||
|
@ -69,20 +55,6 @@ double PositionFunctions::GetPreviousCellPosZ(unsigned short pid) noexcept
|
||||||
return player->previousCellPosition.pos[2];
|
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
|
double PositionFunctions::GetRotX(unsigned short pid) noexcept
|
||||||
{
|
{
|
||||||
Player *player;
|
Player *player;
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
#include "../Types.hpp"
|
#include "../Types.hpp"
|
||||||
|
|
||||||
#define POSITIONAPI \
|
#define POSITIONAPI \
|
||||||
{"GetPos", PositionFunctions::GetPos},\
|
|
||||||
{"GetPosX", PositionFunctions::GetPosX},\
|
{"GetPosX", PositionFunctions::GetPosX},\
|
||||||
{"GetPosY", PositionFunctions::GetPosY},\
|
{"GetPosY", PositionFunctions::GetPosY},\
|
||||||
{"GetPosZ", PositionFunctions::GetPosZ},\
|
{"GetPosZ", PositionFunctions::GetPosZ},\
|
||||||
|
@ -13,7 +12,6 @@
|
||||||
{"GetPreviousCellPosY", PositionFunctions::GetPreviousCellPosY},\
|
{"GetPreviousCellPosY", PositionFunctions::GetPreviousCellPosY},\
|
||||||
{"GetPreviousCellPosZ", PositionFunctions::GetPreviousCellPosZ},\
|
{"GetPreviousCellPosZ", PositionFunctions::GetPreviousCellPosZ},\
|
||||||
\
|
\
|
||||||
{"GetRot", PositionFunctions::GetRot},\
|
|
||||||
{"GetRotX", PositionFunctions::GetRotX},\
|
{"GetRotX", PositionFunctions::GetRotX},\
|
||||||
{"GetRotZ", PositionFunctions::GetRotZ},\
|
{"GetRotZ", PositionFunctions::GetRotZ},\
|
||||||
\
|
\
|
||||||
|
@ -29,18 +27,6 @@ class PositionFunctions
|
||||||
{
|
{
|
||||||
public:
|
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.
|
* \brief Get the X position of a player.
|
||||||
*
|
*
|
||||||
|
@ -89,18 +75,6 @@ public:
|
||||||
*/
|
*/
|
||||||
static double GetPreviousCellPosZ(unsigned short pid) noexcept;
|
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.
|
* \brief Get the X rotation of a player.
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "Server.hpp"
|
#include "Server.hpp"
|
||||||
|
|
||||||
|
#include <components/misc/stringops.hpp>
|
||||||
#include <components/openmw-mp/NetworkMessages.hpp>
|
#include <components/openmw-mp/NetworkMessages.hpp>
|
||||||
#include <components/openmw-mp/Log.hpp>
|
#include <components/openmw-mp/Log.hpp>
|
||||||
#include <components/openmw-mp/Version.hpp>
|
#include <components/openmw-mp/Version.hpp>
|
||||||
|
@ -9,6 +10,18 @@
|
||||||
#include <apps/openmw-mp/MasterClient.hpp>
|
#include <apps/openmw-mp/MasterClient.hpp>
|
||||||
#include <Script/Script.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
|
void ServerFunctions::StopServer(int code) noexcept
|
||||||
{
|
{
|
||||||
|
@ -35,6 +48,40 @@ void ServerFunctions::UnbanAddress(const char *ipAddress) noexcept
|
||||||
mwmp::Networking::getPtr()->unbanAddress(ipAddress);
|
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
|
const char *ServerFunctions::GetOperatingSystemType() noexcept
|
||||||
{
|
{
|
||||||
return Utils::getOperatingSystemType().c_str();
|
return Utils::getOperatingSystemType().c_str();
|
||||||
|
@ -137,34 +184,46 @@ void ServerFunctions::SetRuleValue(const char *key, double value) noexcept
|
||||||
mc->SetRuleValue(key, value);
|
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 &samples = mwmp::Networking::getPtr()->getSamples();
|
||||||
auto it = std::find_if(samples.begin(), samples.end(), [&pluginName](mwmp::PacketPreInit::PluginPair &item) {
|
auto it = std::find_if(samples.begin(), samples.end(), [&dataFilename](mwmp::PacketPreInit::PluginPair &item) {
|
||||||
return item.first == pluginName;
|
return item.first == dataFilename;
|
||||||
});
|
});
|
||||||
if (it != samples.end())
|
if (it != samples.end())
|
||||||
it->second.push_back((unsigned) std::stoul(hashStr));
|
it->second.push_back((unsigned) std::stoul(checksumString));
|
||||||
else
|
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);
|
checksum = (unsigned) std::stoul(checksumString);
|
||||||
hashList.push_back(hash);
|
checksumList.push_back(checksum);
|
||||||
}
|
}
|
||||||
samples.emplace_back(pluginName, hashList);
|
samples.emplace_back(dataFilename, checksumList);
|
||||||
|
|
||||||
auto mclient = mwmp::Networking::getPtr()->getMasterClient();
|
auto mclient = mwmp::Networking::getPtr()->getMasterClient();
|
||||||
if (mclient)
|
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
|
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"
|
#include "../Types.hpp"
|
||||||
|
|
||||||
#define SERVERAPI \
|
#define SERVERAPI \
|
||||||
{"StopServer", ServerFunctions::StopServer},\
|
{"LogMessage", ServerFunctions::LogMessage},\
|
||||||
|
{"LogAppend", ServerFunctions::LogAppend},\
|
||||||
\
|
\
|
||||||
{"Kick", ServerFunctions::Kick},\
|
{"StopServer", ServerFunctions::StopServer},\
|
||||||
{"BanAddress", ServerFunctions::BanAddress},\
|
|
||||||
{"UnbanAddress", ServerFunctions::UnbanAddress},\
|
|
||||||
\
|
\
|
||||||
{"GetOperatingSystemType", ServerFunctions::GetOperatingSystemType},\
|
{"Kick", ServerFunctions::Kick},\
|
||||||
{"GetArchitectureType", ServerFunctions::GetArchitectureType},\
|
{"BanAddress", ServerFunctions::BanAddress},\
|
||||||
{"GetServerVersion", ServerFunctions::GetServerVersion},\
|
{"UnbanAddress", ServerFunctions::UnbanAddress},\
|
||||||
{"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},\
|
{"DoesFilePathExist", ServerFunctions::DoesFilePathExist},\
|
||||||
{"SetHostname", ServerFunctions::SetHostname},\
|
{"GetCaseInsensitiveFilename", ServerFunctions::GetCaseInsensitiveFilename},\
|
||||||
{"SetServerPassword", ServerFunctions::SetServerPassword},\
|
{"GetDataPath", ServerFunctions::GetDataPath},\
|
||||||
{"SetPluginEnforcementState", ServerFunctions::SetPluginEnforcementState},\
|
{"GetMillisecondsSinceServerStart", ServerFunctions::GetMillisecondsSinceServerStart},\
|
||||||
{"SetScriptErrorIgnoringState", ServerFunctions::SetScriptErrorIgnoringState},\
|
{"GetOperatingSystemType", ServerFunctions::GetOperatingSystemType},\
|
||||||
{"SetRuleString", ServerFunctions::SetRuleString},\
|
{"GetArchitectureType", ServerFunctions::GetArchitectureType},\
|
||||||
{"SetRuleValue", ServerFunctions::SetRuleValue},\
|
{"GetServerVersion", ServerFunctions::GetServerVersion},\
|
||||||
{"AddPluginHash", ServerFunctions::AddPluginHash},\
|
{"GetProtocolVersion", ServerFunctions::GetProtocolVersion},\
|
||||||
{"GetModDir", ServerFunctions::GetModDir}
|
{"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
|
class ServerFunctions
|
||||||
{
|
{
|
||||||
public:
|
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.
|
* \brief Shut down the server.
|
||||||
*
|
*
|
||||||
|
@ -68,6 +103,41 @@ public:
|
||||||
*/
|
*/
|
||||||
static void UnbanAddress(const char *ipAddress) noexcept;
|
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.
|
* \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.
|
* \brief Get the port used by the server.
|
||||||
*
|
*
|
||||||
* \return Port
|
* \return The port.
|
||||||
*/
|
*/
|
||||||
static unsigned short GetPort() noexcept;
|
static unsigned short GetPort() noexcept;
|
||||||
|
|
||||||
|
@ -220,13 +290,24 @@ public:
|
||||||
static void SetRuleValue(const char *key, double value) noexcept;
|
static void SetRuleValue(const char *key, double value) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Adds plugins to the internal server structure to validate players.
|
* \brief Add a data file and a corresponding CRC32 checksum to the data file loadout
|
||||||
* @param pluginName Name with extension of the plugin or master file.
|
* that connecting clients need to match.
|
||||||
* @param hash Hash string
|
*
|
||||||
|
* 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 const char *GetModDir() noexcept;
|
||||||
|
static void AddPluginHash(const char *pluginName, const char *checksumString) noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //OPENMW_SERVERAPI_HPP
|
#endif //OPENMW_SERVERAPI_HPP
|
||||||
|
|
|
@ -201,6 +201,17 @@ int StatsFunctions::GetAttributeModifier(unsigned short pid, unsigned short attr
|
||||||
return player->creatureStats.mAttributes[attributeId].mMod;
|
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
|
int StatsFunctions::GetSkillBase(unsigned short pid, unsigned short skillId) noexcept
|
||||||
{
|
{
|
||||||
Player *player;
|
Player *player;
|
||||||
|
@ -223,6 +234,17 @@ int StatsFunctions::GetSkillModifier(unsigned short pid, unsigned short skillId)
|
||||||
return player->npcStats.mSkills[skillId].mMod;
|
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
|
double StatsFunctions::GetSkillProgress(unsigned short pid, unsigned short skillId) noexcept
|
||||||
{
|
{
|
||||||
Player *player;
|
Player *player;
|
||||||
|
@ -437,6 +459,20 @@ void StatsFunctions::ClearAttributeModifier(unsigned short pid, unsigned short a
|
||||||
player->attributeIndexChanges.push_back(attributeId);
|
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
|
void StatsFunctions::SetSkillBase(unsigned short pid, unsigned short skillId, int value) noexcept
|
||||||
{
|
{
|
||||||
Player *player;
|
Player *player;
|
||||||
|
@ -465,6 +501,20 @@ void StatsFunctions::ClearSkillModifier(unsigned short pid, unsigned short skill
|
||||||
player->skillIndexChanges.push_back(skillId);
|
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
|
void StatsFunctions::SetSkillProgress(unsigned short pid, unsigned short skillId, double value) noexcept
|
||||||
{
|
{
|
||||||
Player *player;
|
Player *player;
|
||||||
|
|
|
@ -30,9 +30,11 @@
|
||||||
\
|
\
|
||||||
{"GetAttributeBase", StatsFunctions::GetAttributeBase},\
|
{"GetAttributeBase", StatsFunctions::GetAttributeBase},\
|
||||||
{"GetAttributeModifier", StatsFunctions::GetAttributeModifier},\
|
{"GetAttributeModifier", StatsFunctions::GetAttributeModifier},\
|
||||||
|
{"GetAttributeDamage", StatsFunctions::GetAttributeDamage},\
|
||||||
\
|
\
|
||||||
{"GetSkillBase", StatsFunctions::GetSkillBase},\
|
{"GetSkillBase", StatsFunctions::GetSkillBase},\
|
||||||
{"GetSkillModifier", StatsFunctions::GetSkillModifier},\
|
{"GetSkillModifier", StatsFunctions::GetSkillModifier},\
|
||||||
|
{"GetSkillDamage", StatsFunctions::GetSkillDamage},\
|
||||||
{"GetSkillProgress", StatsFunctions::GetSkillProgress},\
|
{"GetSkillProgress", StatsFunctions::GetSkillProgress},\
|
||||||
{"GetSkillIncrease", StatsFunctions::GetSkillIncrease},\
|
{"GetSkillIncrease", StatsFunctions::GetSkillIncrease},\
|
||||||
\
|
\
|
||||||
|
@ -58,9 +60,11 @@
|
||||||
\
|
\
|
||||||
{"SetAttributeBase", StatsFunctions::SetAttributeBase},\
|
{"SetAttributeBase", StatsFunctions::SetAttributeBase},\
|
||||||
{"ClearAttributeModifier", StatsFunctions::ClearAttributeModifier},\
|
{"ClearAttributeModifier", StatsFunctions::ClearAttributeModifier},\
|
||||||
|
{"SetAttributeDamage", StatsFunctions::SetAttributeDamage},\
|
||||||
\
|
\
|
||||||
{"SetSkillBase", StatsFunctions::SetSkillBase},\
|
{"SetSkillBase", StatsFunctions::SetSkillBase},\
|
||||||
{"ClearSkillModifier", StatsFunctions::ClearSkillModifier},\
|
{"ClearSkillModifier", StatsFunctions::ClearSkillModifier},\
|
||||||
|
{"SetSkillDamage", StatsFunctions::SetSkillDamage},\
|
||||||
{"SetSkillProgress", StatsFunctions::SetSkillProgress},\
|
{"SetSkillProgress", StatsFunctions::SetSkillProgress},\
|
||||||
{"SetSkillIncrease", StatsFunctions::SetSkillIncrease},\
|
{"SetSkillIncrease", StatsFunctions::SetSkillIncrease},\
|
||||||
\
|
\
|
||||||
|
@ -267,6 +271,16 @@ public:
|
||||||
*/
|
*/
|
||||||
static int GetAttributeModifier(unsigned short pid, unsigned short attributeId) noexcept;
|
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.
|
* \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;
|
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.
|
* \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;
|
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.
|
* \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;
|
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.
|
* \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
|
try
|
||||||
{
|
{
|
||||||
vector<boost::any> params;
|
vector<boost::any> params;
|
||||||
GetArguments(params, args, types);
|
Utils::getArguments(params, args, types);
|
||||||
|
|
||||||
return mwmp::TimerAPI::CreateTimer(callback, msec, types, params);
|
return mwmp::TimerAPI::CreateTimer(callback, msec, types, params);
|
||||||
}
|
}
|
||||||
|
@ -54,5 +54,5 @@ void ScriptFunctions::FreeTimer(int timerId) noexcept
|
||||||
|
|
||||||
bool ScriptFunctions::IsTimerElapsed(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_<2> { static constexpr LuaFuctionData F{"MakePublic", LangLua::MakePublic}; };
|
||||||
template<> struct F_<3> { static constexpr LuaFuctionData F{"CallPublic", LangLua::CallPublic}; };
|
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>
|
template<unsigned int I>
|
||||||
struct C
|
struct C
|
||||||
{
|
{
|
||||||
|
@ -117,7 +143,6 @@ struct C
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct C<0>
|
struct C<0>
|
||||||
{
|
{
|
||||||
|
@ -141,6 +166,7 @@ LuaFuctionData *functions()
|
||||||
|
|
||||||
return functions_;
|
return functions_;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void LangLua::LoadProgram(const char *filename)
|
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]);
|
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])>();
|
LuaFuctionData *functions_ = functions<sizeof(ScriptFunctions::functions) / sizeof(ScriptFunctions::functions[0])>();
|
||||||
|
#endif
|
||||||
luabridge::Namespace tes3mp = luabridge::getGlobalNamespace(lua).beginNamespace("tes3mp");
|
luabridge::Namespace tes3mp = luabridge::getGlobalNamespace(lua).beginNamespace("tes3mp");
|
||||||
|
|
||||||
for (unsigned i = 0; i < functions_n; i++)
|
for (unsigned i = 0; i < functions_n; i++)
|
||||||
|
|
|
@ -105,6 +105,7 @@ public:
|
||||||
catch (std::exception &e)
|
catch (std::exception &e)
|
||||||
{
|
{
|
||||||
LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, e.what());
|
LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, e.what());
|
||||||
|
Script::Call<Script::CallbackIdentity("OnServerScriptCrash")>(e.what());
|
||||||
|
|
||||||
if (!mwmp::Networking::getPtr()->getScriptErrorIgnoringState())
|
if (!mwmp::Networking::getPtr()->getScriptErrorIgnoringState())
|
||||||
throw;
|
throw;
|
||||||
|
|
|
@ -13,62 +13,6 @@ constexpr ScriptCallbackData ScriptFunctions::callbacks[];
|
||||||
|
|
||||||
using namespace std;
|
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
|
void ScriptFunctions::MakePublic(ScriptFunc _public, const char *name, char ret_type, const char *def) noexcept
|
||||||
{
|
{
|
||||||
Public::MakePublic(_public, name, ret_type, def);
|
Public::MakePublic(_public, name, ret_type, def);
|
||||||
|
@ -81,7 +25,7 @@ boost::any ScriptFunctions::CallPublic(const char *name, va_list args) noexcept
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string def = Public::GetDefinition(name);
|
string def = Public::GetDefinition(name);
|
||||||
GetArguments(params, args, def);
|
Utils::getArguments(params, args, def);
|
||||||
|
|
||||||
return Public::Call(name, params);
|
return Public::Call(name, params);
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,6 @@ class ScriptFunctions
|
||||||
{
|
{
|
||||||
public:
|
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 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;
|
static boost::any CallPublic(const char *name, va_list args) noexcept;
|
||||||
|
|
||||||
|
@ -157,6 +156,7 @@ public:
|
||||||
{"OnServerInit", Callback<>()},
|
{"OnServerInit", Callback<>()},
|
||||||
{"OnServerPostInit", Callback<>()},
|
{"OnServerPostInit", Callback<>()},
|
||||||
{"OnServerExit", Callback<bool>()},
|
{"OnServerExit", Callback<bool>()},
|
||||||
|
{"OnServerScriptCrash", Callback<const char*>()},
|
||||||
{"OnPlayerConnect", Callback<unsigned short>()},
|
{"OnPlayerConnect", Callback<unsigned short>()},
|
||||||
{"OnPlayerDisconnect", Callback<unsigned short>()},
|
{"OnPlayerDisconnect", Callback<unsigned short>()},
|
||||||
{"OnPlayerDeath", Callback<unsigned short>()},
|
{"OnPlayerDeath", Callback<unsigned short>()},
|
||||||
|
@ -209,7 +209,7 @@ public:
|
||||||
{"OnWorldMap", Callback<unsigned short>()},
|
{"OnWorldMap", Callback<unsigned short>()},
|
||||||
{"OnWorldWeather", Callback<unsigned short>() },
|
{"OnWorldWeather", Callback<unsigned short>() },
|
||||||
{"OnMpNumIncrement", Callback<int>()},
|
{"OnMpNumIncrement", Callback<int>()},
|
||||||
{"OnRequestPluginList", Callback<>()}
|
{"OnRequestDataFileList", Callback<>()}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -105,7 +105,7 @@ struct ScriptFunctionPointer : public ScriptIdentity
|
||||||
void *addr;
|
void *addr;
|
||||||
#if (!defined(__clang__) && defined(__GNUC__))
|
#if (!defined(__clang__) && defined(__GNUC__))
|
||||||
template<typename R, typename... Types>
|
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
|
#else
|
||||||
template<typename R, typename... Types>
|
template<typename R, typename... Types>
|
||||||
constexpr ScriptFunctionPointer(Function<R, Types...> addr) : ScriptIdentity(addr), addr(addr) {}
|
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 "Utils.hpp"
|
||||||
|
|
||||||
|
#include <cstdarg>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
const vector<string> Utils::split(const string &str, int delimiter)
|
const vector<string> Utils::split(const string &str, int delimiter)
|
||||||
|
@ -52,3 +50,59 @@ ESM::Cell Utils::getCellFromDescription(std::string cellDescription)
|
||||||
|
|
||||||
return cell;
|
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
|
#ifndef OPENMW_UTILS_HPP
|
||||||
#define OPENMW_UTILS_HPP
|
#define OPENMW_UTILS_HPP
|
||||||
|
|
||||||
|
@ -9,6 +5,8 @@
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <boost/any.hpp>
|
||||||
|
|
||||||
#include <components/esm/loadcell.hpp>
|
#include <components/esm/loadcell.hpp>
|
||||||
|
|
||||||
#include <components/openmw-mp/Utils.hpp>
|
#include <components/openmw-mp/Utils.hpp>
|
||||||
|
@ -27,6 +25,8 @@ namespace Utils
|
||||||
|
|
||||||
ESM::Cell getCellFromDescription(std::string cellDescription);
|
ESM::Cell getCellFromDescription(std::string cellDescription);
|
||||||
|
|
||||||
|
void getArguments(std::vector<boost::any> ¶ms, va_list args, const std::string &def);
|
||||||
|
|
||||||
template<size_t N>
|
template<size_t N>
|
||||||
constexpr unsigned int hash(const char(&str)[N], size_t I = 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);
|
LOG_INIT(logLevel);
|
||||||
|
|
||||||
int players = mgr.getInt("maximumPlayers", "General");
|
int players = mgr.getInt("maximumPlayers", "General");
|
||||||
string addr = mgr.getString("localAddress", "General");
|
string address = mgr.getString("localAddress", "General");
|
||||||
int port = mgr.getInt("port", "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 pluginHome = mgr.getString("home", "Plugins");
|
||||||
string moddir = Utils::convertPath(plugin_home + "/data");
|
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);
|
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
|
#ifdef ENABLE_LUA
|
||||||
LangLua::AddPackagePath(Utils::convertPath(plugin_home + "/scripts/?.lua" + ";"
|
LangLua::AddPackagePath(Utils::convertPath(pluginHome + "/scripts/?.lua" + ";"
|
||||||
+ plugin_home + "/lib/lua/?.lua" + ";"));
|
+ pluginHome + "/lib/lua/?.lua" + ";"));
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
LangLua::AddPackageCPath(Utils::convertPath(plugin_home + "/lib/?.dll"));
|
LangLua::AddPackageCPath(Utils::convertPath(pluginHome + "/lib/?.dll"));
|
||||||
#else
|
#else
|
||||||
LangLua::AddPackageCPath(Utils::convertPath(plugin_home + "/lib/?.so"));
|
LangLua::AddPackageCPath(Utils::convertPath(pluginHome + "/lib/?.so"));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -246,18 +226,18 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
peer->SetIncomingPassword(sstr.str().c_str(), (int) sstr.str().size());
|
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.");
|
LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "You cannot use non-numeric addresses for the server.");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
RakNet::SocketDescriptor sd((unsigned short) port, addr.c_str());
|
RakNet::SocketDescriptor sd((unsigned short) port, address.c_str());
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
for (auto plugin : plugins)
|
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))
|
switch (peer->Startup((unsigned) players, &sd, 1))
|
||||||
{
|
{
|
||||||
|
@ -284,7 +264,7 @@ int main(int argc, char *argv[])
|
||||||
peer->SetMaximumIncomingConnections((unsigned short) (players));
|
peer->SetMaximumIncomingConnections((unsigned short) (players));
|
||||||
|
|
||||||
Networking networking(peer);
|
Networking networking(peer);
|
||||||
networking.setServerPassword(passw);
|
networking.setServerPassword(password);
|
||||||
|
|
||||||
if (mgr.getBool("enabled", "MasterServer"))
|
if (mgr.getBool("enabled", "MasterServer"))
|
||||||
{
|
{
|
||||||
|
@ -327,6 +307,7 @@ int main(int argc, char *argv[])
|
||||||
catch (std::exception &e)
|
catch (std::exception &e)
|
||||||
{
|
{
|
||||||
LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, e.what());
|
LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, e.what());
|
||||||
|
Script::Call<Script::CallbackIdentity("OnServerScriptCrash")>(e.what());
|
||||||
throw; //fall through
|
throw; //fall through
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,3 @@
|
||||||
//
|
|
||||||
// Created by koncord on 31.03.17.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef OPENMW_PROCESSORPLAYERPOSITION_HPP
|
#ifndef OPENMW_PROCESSORPLAYERPOSITION_HPP
|
||||||
#define OPENMW_PROCESSORPLAYERPOSITION_HPP
|
#define OPENMW_PROCESSORPLAYERPOSITION_HPP
|
||||||
|
|
||||||
|
@ -19,11 +15,7 @@ namespace mwmp
|
||||||
|
|
||||||
void Do(PlayerPacket &packet, Player &player) override
|
void Do(PlayerPacket &packet, Player &player) override
|
||||||
{
|
{
|
||||||
//DEBUG_PRINTF(strPacketID);
|
player.sendToLoaded(&packet);
|
||||||
if (!player.creatureStats.mDead)
|
|
||||||
{
|
|
||||||
player.sendToLoaded(&packet);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,7 +134,7 @@ add_openmw_dir (mwmp/processors/object BaseObjectProcessor
|
||||||
ProcessorScriptGlobalFloat
|
ProcessorScriptGlobalFloat
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwmp/processors/worldstate ProcessorCellCreate ProcessorCellReplace ProcessorRecordDynamic
|
add_openmw_dir (mwmp/processors/worldstate ProcessorCellCreate ProcessorCellReset ProcessorRecordDynamic
|
||||||
ProcessorWorldCollisionOverride ProcessorWorldMap ProcessorWorldRegionAuthority ProcessorWorldTime
|
ProcessorWorldCollisionOverride ProcessorWorldMap ProcessorWorldRegionAuthority ProcessorWorldTime
|
||||||
ProcessorWorldWeather
|
ProcessorWorldWeather
|
||||||
)
|
)
|
||||||
|
|
|
@ -221,10 +221,11 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
||||||
/*
|
/*
|
||||||
Start of tes3mp addition
|
Start of tes3mp addition
|
||||||
|
|
||||||
Check for unmodified tes3mp-credits file; this makes it so people can't repackage official releases with
|
Check for unmodified tes3mp-credits file on Windows; this makes it so people can't repackage official
|
||||||
their own made-up credits, though it obviously has no bearing on unofficial releases that change
|
releases with their own made-up credits, though it obviously has no bearing on unofficial releases that
|
||||||
the checksum below
|
change the checksum below
|
||||||
*/
|
*/
|
||||||
|
#ifdef _WIN32
|
||||||
boost::filesystem::path folderPath(boost::filesystem::initial_path<boost::filesystem::path>());
|
boost::filesystem::path folderPath(boost::filesystem::initial_path<boost::filesystem::path>());
|
||||||
folderPath = boost::filesystem::system_complete(boost::filesystem::path(argv[0])).remove_filename();
|
folderPath = boost::filesystem::system_complete(boost::filesystem::path(argv[0])).remove_filename();
|
||||||
std::string creditsPath = folderPath.string() + "/tes3mp-credits";
|
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);
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "tes3mp", TES3MP_CREDITS_ERROR, 0);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
/*
|
/*
|
||||||
End of tes3mp addition
|
End of tes3mp addition
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -553,9 +553,10 @@ namespace MWClass
|
||||||
/*
|
/*
|
||||||
Start of tes3mp addition
|
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);
|
mwmp::Attack *localAttack = MechanicsHelper::getLocalAttack(attacker);
|
||||||
|
|
||||||
|
|
|
@ -966,12 +966,13 @@ namespace MWClass
|
||||||
/*
|
/*
|
||||||
Start of tes3mp addition
|
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
|
If the victim was the LocalPlayer, check whether packets should be sent about
|
||||||
their new dynamic stats and position
|
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);
|
mwmp::Attack *localAttack = MechanicsHelper::getLocalAttack(attacker);
|
||||||
|
|
||||||
|
|
|
@ -458,6 +458,15 @@ namespace MWGui
|
||||||
|
|
||||||
updateMagicMarkers();
|
updateMagicMarkers();
|
||||||
updateCustomMarkers();
|
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)
|
void LocalMapBase::requestMapRender(const MWWorld::CellStore *cell)
|
||||||
|
|
|
@ -9,6 +9,19 @@
|
||||||
|
|
||||||
#include <components/misc/rng.hpp>
|
#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/world.hpp"
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/windowmanager.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(
|
const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().find(
|
||||||
item.getClass().getEnchantment(item));
|
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(
|
item.getCellRef().setEnchantmentCharge(
|
||||||
std::min(item.getCellRef().getEnchantmentCharge() + restored, static_cast<float>(enchantment->mData.mCharge)));
|
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");
|
MWBase::Environment::get().getWindowManager()->playSound("Enchant Success");
|
||||||
|
|
||||||
player.getClass().getContainerStore(player).restack(item);
|
player.getClass().getContainerStore(player).restack(item);
|
||||||
|
|
|
@ -842,6 +842,22 @@ namespace MWMechanics
|
||||||
|
|
||||||
if (isDamageEffect)
|
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 == player || playerFollowers.find(caster) != playerFollowers.end())
|
||||||
{
|
{
|
||||||
if (caster.getClass().getNpcStats(caster).isWerewolf())
|
if (caster.getClass().getNpcStats(caster).isWerewolf())
|
||||||
|
|
|
@ -4,6 +4,19 @@
|
||||||
|
|
||||||
#include <components/misc/rng.hpp>
|
#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/world.hpp"
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/mechanicsmanager.hpp"
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
|
@ -57,8 +70,25 @@ void Repair::repair(const MWWorld::Ptr &itemToRepair)
|
||||||
// repair by 'y' points
|
// repair by 'y' points
|
||||||
int charge = itemToRepair.getClass().getItemHealth(itemToRepair);
|
int charge = itemToRepair.getClass().getItemHealth(itemToRepair);
|
||||||
charge = std::min(charge + y, itemToRepair.getClass().getItemMaxHealth(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);
|
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
|
// attempt to re-stack item, in case it was fully repaired
|
||||||
MWWorld::ContainerStoreIterator stacked = player.getClass().getContainerStore(player).restack(itemToRepair);
|
MWWorld::ContainerStoreIterator stacked = player.getClass().getContainerStore(player).restack(itemToRepair);
|
||||||
|
|
||||||
|
|
|
@ -537,7 +537,7 @@ namespace MWMechanics
|
||||||
/*
|
/*
|
||||||
Start of tes3mp addition
|
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)
|
if (!wasDead && isDead)
|
||||||
{
|
{
|
||||||
|
|
|
@ -82,8 +82,10 @@ void Cell::updateLocal(bool forceUpdate)
|
||||||
}
|
}
|
||||||
else
|
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())
|
if (actor->getPtr().getRefData().isEnabled())
|
||||||
actor->update(forceUpdate);
|
actor->update(actor->hasSentData ? forceUpdate : true);
|
||||||
|
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
|
@ -397,6 +399,9 @@ void Cell::readCellChange(ActorList& actorList)
|
||||||
|
|
||||||
void Cell::initializeLocalActor(const MWWorld::Ptr& ptr)
|
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();
|
LocalActor *actor = new LocalActor();
|
||||||
actor->cell = *store->getCell();
|
actor->cell = *store->getCell();
|
||||||
actor->setPtr(ptr);
|
actor->setPtr(ptr);
|
||||||
|
@ -406,16 +411,17 @@ void Cell::initializeLocalActor(const MWWorld::Ptr& ptr)
|
||||||
if (ptr.getClass().getCreatureStats(ptr).isDead())
|
if (ptr.getClass().getCreatureStats(ptr).isDead())
|
||||||
actor->wasDead = true;
|
actor->wasDead = true;
|
||||||
|
|
||||||
std::string mapIndex = Main::get().getCellController()->generateMapIndex(ptr);
|
|
||||||
localActors[mapIndex] = actor;
|
localActors[mapIndex] = actor;
|
||||||
|
|
||||||
Main::get().getCellController()->setLocalActorRecord(mapIndex, getDescription());
|
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()
|
void Cell::initializeLocalActors()
|
||||||
{
|
{
|
||||||
|
LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Initializing LocalActors in %s", getDescription().c_str());
|
||||||
|
|
||||||
for (const auto &mergedRef : store->getMergedRefs())
|
for (const auto &mergedRef : store->getMergedRefs())
|
||||||
{
|
{
|
||||||
if (mergedRef->mClass->isActor())
|
if (mergedRef->mClass->isActor())
|
||||||
|
@ -432,20 +438,24 @@ void Cell::initializeLocalActors()
|
||||||
initializeLocalActor(ptr);
|
initializeLocalActor(ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOG_APPEND(Log::LOG_VERBOSE, "- Successfully initialized LocalActors in %s", getDescription().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cell::initializeDedicatedActor(const MWWorld::Ptr& ptr)
|
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();
|
DedicatedActor *actor = new DedicatedActor();
|
||||||
actor->cell = *store->getCell();
|
actor->cell = *store->getCell();
|
||||||
actor->setPtr(ptr);
|
actor->setPtr(ptr);
|
||||||
|
|
||||||
std::string mapIndex = Main::get().getCellController()->generateMapIndex(ptr);
|
|
||||||
dedicatedActors[mapIndex] = actor;
|
dedicatedActors[mapIndex] = actor;
|
||||||
|
|
||||||
Main::get().getCellController()->setDedicatedActorRecord(mapIndex, getDescription());
|
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)
|
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 this key doesn't exist, create it
|
||||||
if (cellsInitialized.count(mapIndex) == 0)
|
if (cellsInitialized.count(mapIndex) == 0)
|
||||||
{
|
{
|
||||||
|
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Initializing mwmp::Cell %s", cell.getDescription().c_str());
|
||||||
|
|
||||||
MWWorld::CellStore *cellStore = getCellStore(cell);
|
MWWorld::CellStore *cellStore = getCellStore(cell);
|
||||||
|
|
||||||
if (!cellStore) return;
|
if (!cellStore) return;
|
||||||
|
@ -84,7 +86,7 @@ void CellController::initializeCell(const ESM::Cell& cell)
|
||||||
mwmp::Cell *mpCell = new mwmp::Cell(cellStore);
|
mwmp::Cell *mpCell = new mwmp::Cell(cellStore);
|
||||||
cellsInitialized[mapIndex] = mpCell;
|
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)
|
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::CreatureStats *ptrCreatureStats = &ptr.getClass().getCreatureStats(ptr);
|
||||||
|
|
||||||
MWMechanics::DynamicStat<float> value;
|
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_Fight, 0);
|
||||||
ptrCreatureStats->setAiSetting(MWMechanics::CreatureStats::AI_Flee, 0);
|
ptrCreatureStats->setAiSetting(MWMechanics::CreatureStats::AI_Flee, 0);
|
||||||
ptrCreatureStats->setAiSetting(MWMechanics::CreatureStats::AI_Hello, 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)
|
void DedicatedPlayer::move(float dt)
|
||||||
|
|
|
@ -22,6 +22,7 @@ using namespace std;
|
||||||
|
|
||||||
LocalActor::LocalActor()
|
LocalActor::LocalActor()
|
||||||
{
|
{
|
||||||
|
hasSentData = false;
|
||||||
posWasChanged = false;
|
posWasChanged = false;
|
||||||
equipmentChanged = false;
|
equipmentChanged = false;
|
||||||
|
|
||||||
|
@ -61,14 +62,16 @@ void LocalActor::update(bool forceUpdate)
|
||||||
updateSpeech();
|
updateSpeech();
|
||||||
updateAttack();
|
updateAttack();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hasSentData = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalActor::updateCell()
|
void LocalActor::updateCell()
|
||||||
{
|
{
|
||||||
LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Sending ID_ACTOR_CELL_CHANGE about %s %i-%i to server",
|
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);
|
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();
|
cell = *ptr.getCell()->getCell();
|
||||||
position = ptr.getRefData().getPosition();
|
position = ptr.getRefData().getPosition();
|
||||||
|
@ -191,8 +194,8 @@ void LocalActor::updateStatsDynamic(bool forceUpdate)
|
||||||
if (MechanicsHelper::isEmptyTarget(killer))
|
if (MechanicsHelper::isEmptyTarget(killer))
|
||||||
killer = MechanicsHelper::getTarget(ptr);
|
killer = MechanicsHelper::getTarget(ptr);
|
||||||
|
|
||||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Sending ID_ACTOR_DEATH about %s %i-%i to server",
|
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Sending ID_ACTOR_DEATH about %s %i-%i in cell %s to server",
|
||||||
refId.c_str(), refNum, mpNum);
|
refId.c_str(), refNum, mpNum, cell.getDescription().c_str());
|
||||||
|
|
||||||
mwmp::Main::get().getNetworking()->getActorList()->addDeathActor(*this);
|
mwmp::Main::get().getNetworking()->getActorList()->addDeathActor(*this);
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ namespace mwmp
|
||||||
MWWorld::Ptr getPtr();
|
MWWorld::Ptr getPtr();
|
||||||
void setPtr(const MWWorld::Ptr& newPtr);
|
void setPtr(const MWWorld::Ptr& newPtr);
|
||||||
|
|
||||||
|
bool hasSentData;
|
||||||
bool wasDead;
|
bool wasDead;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -284,6 +284,7 @@ void LocalPlayer::updateAttributes(bool forceUpdate)
|
||||||
{
|
{
|
||||||
if (ptrNpcStats.getAttribute(i).getBase() != creatureStats.mAttributes[i].mBase ||
|
if (ptrNpcStats.getAttribute(i).getBase() != creatureStats.mAttributes[i].mBase ||
|
||||||
ptrNpcStats.getAttribute(i).getModifier() != creatureStats.mAttributes[i].mMod ||
|
ptrNpcStats.getAttribute(i).getModifier() != creatureStats.mAttributes[i].mMod ||
|
||||||
|
ptrNpcStats.getAttribute(i).getDamage() != creatureStats.mAttributes[i].mDamage ||
|
||||||
ptrNpcStats.getSkillIncrease(i) != npcStats.mSkillIncrease[i] ||
|
ptrNpcStats.getSkillIncrease(i) != npcStats.mSkillIncrease[i] ||
|
||||||
forceUpdate)
|
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
|
// 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 ||
|
if (ptrNpcStats.getSkill(i).getBase() != npcStats.mSkills[i].mBase ||
|
||||||
ptrNpcStats.getSkill(i).getModifier() != npcStats.mSkills[i].mMod ||
|
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 ||
|
abs(ptrNpcStats.getSkill(i).getProgress() - npcStats.mSkills[i].mProgress) > 0.75 ||
|
||||||
forceUpdate)
|
forceUpdate)
|
||||||
{
|
{
|
||||||
|
@ -920,7 +922,7 @@ void LocalPlayer::setAttributes()
|
||||||
{
|
{
|
||||||
MWWorld::Ptr ptrPlayer = getPlayerPtr();
|
MWWorld::Ptr ptrPlayer = getPlayerPtr();
|
||||||
|
|
||||||
MWMechanics::CreatureStats *ptrCreatureStats = &ptrPlayer.getClass().getCreatureStats(ptrPlayer);
|
MWMechanics::NpcStats *ptrNpcStats = &ptrPlayer.getClass().getNpcStats(ptrPlayer);
|
||||||
MWMechanics::AttributeValue attributeValue;
|
MWMechanics::AttributeValue attributeValue;
|
||||||
|
|
||||||
for (int attributeIndex = 0; attributeIndex < 8; ++attributeIndex)
|
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
|
// 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 spell effect causing it, to avoid an infinite loop where the effect keeps resetting
|
||||||
// the modifier
|
// 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);
|
MWBase::Environment::get().getMechanicsManager()->updateMagicEffects(ptrPlayer);
|
||||||
|
|
||||||
// Is the modifier for this attribute still higher than 0? If so, unequip items that
|
// Is the modifier for this attribute still higher than 0? If so, unequip items that
|
||||||
// fortify the attribute
|
// 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);
|
MechanicsHelper::unequipItemsByEffect(ptrPlayer, ESM::Enchantment::ConstantEffect, ESM::MagicEffect::FortifyAttribute, attributeIndex, -1);
|
||||||
mwmp::Main::get().getGUIController()->refreshGuiMode(MWGui::GM_Inventory);
|
mwmp::Main::get().getGUIController()->refreshGuiMode(MWGui::GM_Inventory);
|
||||||
|
@ -943,7 +945,9 @@ void LocalPlayer::setAttributes()
|
||||||
}
|
}
|
||||||
|
|
||||||
attributeValue.readState(creatureStats.mAttributes[attributeIndex]);
|
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]);
|
skillValue.readState(npcStats.mSkills[skillIndex]);
|
||||||
ptrNpcStats->setSkill(skillIndex, skillValue);
|
ptrNpcStats->setSkill(skillIndex, skillValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int attributeIndex = 0; attributeIndex < 8; ++attributeIndex)
|
|
||||||
ptrNpcStats->setSkillIncrease(attributeIndex, npcStats.mSkillIncrease[attributeIndex]);
|
|
||||||
|
|
||||||
ptrNpcStats->setLevelProgress(npcStats.mLevelProgress);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalPlayer::setLevel()
|
void LocalPlayer::setLevel()
|
||||||
|
@ -988,8 +987,9 @@ void LocalPlayer::setLevel()
|
||||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||||
MWWorld::Ptr ptrPlayer = world->getPlayerPtr();
|
MWWorld::Ptr ptrPlayer = world->getPlayerPtr();
|
||||||
|
|
||||||
MWMechanics::CreatureStats *ptrCreatureStats = &ptrPlayer.getClass().getCreatureStats(ptrPlayer);
|
MWMechanics::NpcStats *ptrNpcStats = &ptrPlayer.getClass().getNpcStats(ptrPlayer);
|
||||||
ptrCreatureStats->setLevel(creatureStats.mLevel);
|
ptrNpcStats->setLevel(creatureStats.mLevel);
|
||||||
|
ptrNpcStats->setLevelProgress(npcStats.mLevelProgress);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalPlayer::setBounty()
|
void LocalPlayer::setBounty()
|
||||||
|
@ -1403,31 +1403,23 @@ void LocalPlayer::sendInventory()
|
||||||
getNetworking()->getPlayerPacket(ID_PLAYER_INVENTORY)->Send();
|
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)
|
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",
|
mwmp::Item item = MechanicsHelper::getItem(itemPtr, count);
|
||||||
itemPtr.getCellRef().getRefId().c_str(), action, count);
|
sendItemChange(item, action);
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalPlayer::sendItemChange(const std::string& refId, int count, unsigned int action)
|
void LocalPlayer::sendItemChange(const std::string& refId, int count, unsigned int action)
|
||||||
|
|
|
@ -77,6 +77,7 @@ namespace mwmp
|
||||||
|
|
||||||
void sendClass();
|
void sendClass();
|
||||||
void sendInventory();
|
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 MWWorld::Ptr& itemPtr, int count, unsigned int action);
|
||||||
void sendItemChange(const std::string& refId, int count, unsigned int action);
|
void sendItemChange(const std::string& refId, int count, unsigned int action);
|
||||||
void sendSpellbook();
|
void sendSpellbook();
|
||||||
|
|
|
@ -51,8 +51,8 @@ using namespace mwmp;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
Main *Main::pMain = 0;
|
Main *Main::pMain = 0;
|
||||||
std::string Main::addr = "";
|
std::string Main::address = "";
|
||||||
std::string Main::passw = TES3MP_DEFAULT_PASSW;
|
std::string Main::serverPassword = TES3MP_DEFAULT_PASSW;
|
||||||
std::string Main::resourceDir = "";
|
std::string Main::resourceDir = "";
|
||||||
|
|
||||||
std::string Main::getResDir()
|
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)
|
void Main::configure(const boost::program_options::variables_map &variables)
|
||||||
{
|
{
|
||||||
Main::addr = variables["connect"].as<string>();
|
Main::address = variables["connect"].as<string>();
|
||||||
Main::passw = variables["password"].as<string>();
|
Main::serverPassword = variables["password"].as<string>();
|
||||||
resourceDir = variables["resources"].as<Files::EscapeHashString>().toStdString();
|
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");
|
int logLevel = mgr.getInt("logLevel", "General");
|
||||||
Log::SetLevel(logLevel);
|
Log::SetLevel(logLevel);
|
||||||
if (addr.empty())
|
if (address.empty())
|
||||||
{
|
{
|
||||||
pMain->server = mgr.getString("destinationAddress", "General");
|
pMain->server = mgr.getString("destinationAddress", "General");
|
||||||
pMain->port = (unsigned short) mgr.getInt("port", "General");
|
pMain->port = (unsigned short) mgr.getInt("port", "General");
|
||||||
|
|
||||||
passw = mgr.getString("password", "General");
|
serverPassword = mgr.getString("password", "General");
|
||||||
if (passw.empty())
|
if (serverPassword.empty())
|
||||||
passw = TES3MP_DEFAULT_PASSW;
|
serverPassword = TES3MP_DEFAULT_PASSW;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
size_t delim_pos = addr.find(':');
|
size_t delimPos = address.find(':');
|
||||||
pMain->server = addr.substr(0, delim_pos);
|
pMain->server = address.substr(0, delimPos);
|
||||||
pMain->port = atoi(addr.substr(delim_pos + 1).c_str());
|
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);
|
pMain->mNetworking->connect(pMain->server, pMain->port, content, collections);
|
||||||
RestoreMgr(mgr);
|
RestoreMgr(mgr);
|
||||||
|
|
|
@ -39,8 +39,8 @@ namespace mwmp
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static std::string resourceDir;
|
static std::string resourceDir;
|
||||||
static std::string addr;
|
static std::string address;
|
||||||
static std::string passw;
|
static std::string serverPassword;
|
||||||
Main (const Main&);
|
Main (const Main&);
|
||||||
///< not implemented
|
///< not implemented
|
||||||
Main& operator= (const Main&);
|
Main& operator= (const Main&);
|
||||||
|
|
|
@ -125,6 +125,23 @@ MWWorld::Ptr MechanicsHelper::getPlayerPtr(const Target& target)
|
||||||
return nullptr;
|
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 MechanicsHelper::getTarget(const MWWorld::Ptr& ptr)
|
||||||
{
|
{
|
||||||
mwmp::Target target;
|
mwmp::Target target;
|
||||||
|
@ -393,18 +410,14 @@ void MechanicsHelper::processAttack(Attack attack, const MWWorld::Ptr& attacker)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (it != inventoryStore.end())
|
// Add the item if it's missing
|
||||||
{
|
if (it == inventoryStore.end())
|
||||||
inventoryStore.setSelectedEnchantItem(it);
|
it = attacker.getClass().getContainerStore(attacker).add(attack.itemId, 1, attacker);
|
||||||
LOG_APPEND(Log::LOG_VERBOSE, "- itemId: %s", attack.itemId.c_str());
|
|
||||||
MWBase::Environment::get().getWorld()->castSpell(attacker);
|
inventoryStore.setSelectedEnchantItem(it);
|
||||||
inventoryStore.setSelectedEnchantItem(inventoryStore.end());
|
LOG_APPEND(Log::LOG_VERBOSE, "- itemId: %s", attack.itemId.c_str());
|
||||||
}
|
MWBase::Environment::get().getWorld()->castSpell(attacker);
|
||||||
else
|
inventoryStore.setSelectedEnchantItem(inventoryStore.end());
|
||||||
{
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ namespace MechanicsHelper
|
||||||
|
|
||||||
MWWorld::Ptr getPlayerPtr(const mwmp::Target& target);
|
MWWorld::Ptr getPlayerPtr(const mwmp::Target& target);
|
||||||
|
|
||||||
|
mwmp::Item getItem(const MWWorld::Ptr& itemPtr, int count);
|
||||||
mwmp::Target getTarget(const MWWorld::Ptr& ptr);
|
mwmp::Target getTarget(const MWWorld::Ptr& ptr);
|
||||||
void clearTarget(mwmp::Target& target);
|
void clearTarget(mwmp::Target& target);
|
||||||
bool isEmptyTarget(const mwmp::Target& target);
|
bool isEmptyTarget(const mwmp::Target& target);
|
||||||
|
|
|
@ -110,7 +110,7 @@ void RecordHelper::overrideCreatureRecord(const mwmp::CreatureRecord& record)
|
||||||
|
|
||||||
if (recordData.mId.empty())
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,6 +164,11 @@ void RecordHelper::overrideCreatureRecord(const mwmp::CreatureRecord& record)
|
||||||
|
|
||||||
world->getModifiableStore().overrideRecord(finalData);
|
world->getModifiableStore().overrideRecord(finalData);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with invalid baseId %s", record.baseId.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (isExistingId)
|
if (isExistingId)
|
||||||
world->updatePtrsWithRefId(recordData.mId);
|
world->updatePtrsWithRefId(recordData.mId);
|
||||||
|
@ -175,7 +180,7 @@ void RecordHelper::overrideNpcRecord(const mwmp::NpcRecord& record)
|
||||||
|
|
||||||
if (recordData.mId.empty())
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,12 +191,12 @@ void RecordHelper::overrideNpcRecord(const mwmp::NpcRecord& record)
|
||||||
{
|
{
|
||||||
if (!doesRaceRecordExist(recordData.mRace))
|
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;
|
return;
|
||||||
}
|
}
|
||||||
else if (!doesClassRecordExist(recordData.mClass))
|
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;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -272,6 +277,11 @@ void RecordHelper::overrideNpcRecord(const mwmp::NpcRecord& record)
|
||||||
|
|
||||||
world->getModifiableStore().overrideRecord(finalData);
|
world->getModifiableStore().overrideRecord(finalData);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with invalid baseId %s", record.baseId.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (isExistingId)
|
if (isExistingId)
|
||||||
world->updatePtrsWithRefId(recordData.mId);
|
world->updatePtrsWithRefId(recordData.mId);
|
||||||
|
@ -283,18 +293,17 @@ void RecordHelper::overrideEnchantmentRecord(const mwmp::EnchantmentRecord& reco
|
||||||
|
|
||||||
if (recordData.mId.empty())
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isExistingId = doesEnchantmentRecordExist(recordData.mId);
|
|
||||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||||
|
|
||||||
if (record.baseId.empty())
|
if (record.baseId.empty())
|
||||||
{
|
{
|
||||||
if (recordData.mEffects.mList.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;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -323,6 +332,11 @@ void RecordHelper::overrideEnchantmentRecord(const mwmp::EnchantmentRecord& reco
|
||||||
|
|
||||||
world->getModifiableStore().overrideRecord(finalData);
|
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)
|
void RecordHelper::overridePotionRecord(const mwmp::PotionRecord& record)
|
||||||
|
@ -331,7 +345,7 @@ void RecordHelper::overridePotionRecord(const mwmp::PotionRecord& record)
|
||||||
|
|
||||||
if (recordData.mId.empty())
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,6 +388,11 @@ void RecordHelper::overridePotionRecord(const mwmp::PotionRecord& record)
|
||||||
|
|
||||||
world->getModifiableStore().overrideRecord(finalData);
|
world->getModifiableStore().overrideRecord(finalData);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with invalid baseId %s", record.baseId.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (isExistingId)
|
if (isExistingId)
|
||||||
world->updatePtrsWithRefId(recordData.mId);
|
world->updatePtrsWithRefId(recordData.mId);
|
||||||
|
@ -385,7 +404,7 @@ void RecordHelper::overrideSpellRecord(const mwmp::SpellRecord& record)
|
||||||
|
|
||||||
if (recordData.mId.empty())
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -419,9 +438,11 @@ void RecordHelper::overrideSpellRecord(const mwmp::SpellRecord& record)
|
||||||
|
|
||||||
world->getModifiableStore().overrideRecord(finalData);
|
world->getModifiableStore().overrideRecord(finalData);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if (isExistingId)
|
{
|
||||||
world->updatePtrsWithRefId(recordData.mId);
|
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with invalid baseId %s", record.baseId.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecordHelper::overrideArmorRecord(const mwmp::ArmorRecord& record)
|
void RecordHelper::overrideArmorRecord(const mwmp::ArmorRecord& record)
|
||||||
|
@ -430,7 +451,7 @@ void RecordHelper::overrideArmorRecord(const mwmp::ArmorRecord& record)
|
||||||
|
|
||||||
if (recordData.mId.empty())
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -441,7 +462,7 @@ void RecordHelper::overrideArmorRecord(const mwmp::ArmorRecord& record)
|
||||||
{
|
{
|
||||||
if (!recordData.mEnchant.empty() && !doesEnchantmentRecordExist(recordData.mEnchant))
|
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;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -479,8 +500,13 @@ void RecordHelper::overrideArmorRecord(const mwmp::ArmorRecord& record)
|
||||||
if (record.baseOverrides.hasArmorRating)
|
if (record.baseOverrides.hasArmorRating)
|
||||||
finalData.mData.mArmor = recordData.mData.mArmor;
|
finalData.mData.mArmor = recordData.mData.mArmor;
|
||||||
|
|
||||||
if (record.baseOverrides.hasEnchantmentId && doesEnchantmentRecordExist(recordData.mEnchant))
|
if (record.baseOverrides.hasEnchantmentId)
|
||||||
finalData.mEnchant = recordData.mEnchant;
|
{
|
||||||
|
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)
|
if (record.baseOverrides.hasEnchantmentCharge)
|
||||||
finalData.mData.mEnchant = recordData.mData.mEnchant;
|
finalData.mData.mEnchant = recordData.mData.mEnchant;
|
||||||
|
@ -493,6 +519,11 @@ void RecordHelper::overrideArmorRecord(const mwmp::ArmorRecord& record)
|
||||||
|
|
||||||
world->getModifiableStore().overrideRecord(finalData);
|
world->getModifiableStore().overrideRecord(finalData);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with invalid baseId %s", record.baseId.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (isExistingId)
|
if (isExistingId)
|
||||||
world->updatePtrsWithRefId(recordData.mId);
|
world->updatePtrsWithRefId(recordData.mId);
|
||||||
|
@ -504,7 +535,7 @@ void RecordHelper::overrideBookRecord(const mwmp::BookRecord& record)
|
||||||
|
|
||||||
if (recordData.mId.empty())
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -515,7 +546,7 @@ void RecordHelper::overrideBookRecord(const mwmp::BookRecord& record)
|
||||||
{
|
{
|
||||||
if (!recordData.mEnchant.empty() && !doesEnchantmentRecordExist(recordData.mEnchant))
|
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;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -551,8 +582,13 @@ void RecordHelper::overrideBookRecord(const mwmp::BookRecord& record)
|
||||||
if (record.baseOverrides.hasSkillId)
|
if (record.baseOverrides.hasSkillId)
|
||||||
finalData.mData.mSkillId = recordData.mData.mSkillId;
|
finalData.mData.mSkillId = recordData.mData.mSkillId;
|
||||||
|
|
||||||
if (record.baseOverrides.hasEnchantmentId && doesEnchantmentRecordExist(recordData.mEnchant))
|
if (record.baseOverrides.hasEnchantmentId)
|
||||||
finalData.mEnchant = recordData.mEnchant;
|
{
|
||||||
|
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)
|
if (record.baseOverrides.hasEnchantmentCharge)
|
||||||
finalData.mData.mEnchant = recordData.mData.mEnchant;
|
finalData.mData.mEnchant = recordData.mData.mEnchant;
|
||||||
|
@ -562,6 +598,11 @@ void RecordHelper::overrideBookRecord(const mwmp::BookRecord& record)
|
||||||
|
|
||||||
world->getModifiableStore().overrideRecord(finalData);
|
world->getModifiableStore().overrideRecord(finalData);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with invalid baseId %s", record.baseId.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (isExistingId)
|
if (isExistingId)
|
||||||
world->updatePtrsWithRefId(recordData.mId);
|
world->updatePtrsWithRefId(recordData.mId);
|
||||||
|
@ -573,7 +614,7 @@ void RecordHelper::overrideClothingRecord(const mwmp::ClothingRecord& record)
|
||||||
|
|
||||||
if (recordData.mId.empty())
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -584,7 +625,7 @@ void RecordHelper::overrideClothingRecord(const mwmp::ClothingRecord& record)
|
||||||
{
|
{
|
||||||
if (!recordData.mEnchant.empty() && !doesEnchantmentRecordExist(recordData.mEnchant))
|
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;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -614,8 +655,13 @@ void RecordHelper::overrideClothingRecord(const mwmp::ClothingRecord& record)
|
||||||
if (record.baseOverrides.hasValue)
|
if (record.baseOverrides.hasValue)
|
||||||
finalData.mData.mValue = recordData.mData.mValue;
|
finalData.mData.mValue = recordData.mData.mValue;
|
||||||
|
|
||||||
if (record.baseOverrides.hasEnchantmentId && doesEnchantmentRecordExist(recordData.mEnchant))
|
if (record.baseOverrides.hasEnchantmentId)
|
||||||
finalData.mEnchant = recordData.mEnchant;
|
{
|
||||||
|
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)
|
if (record.baseOverrides.hasEnchantmentCharge)
|
||||||
finalData.mData.mEnchant = recordData.mData.mEnchant;
|
finalData.mData.mEnchant = recordData.mData.mEnchant;
|
||||||
|
@ -628,6 +674,11 @@ void RecordHelper::overrideClothingRecord(const mwmp::ClothingRecord& record)
|
||||||
|
|
||||||
world->getModifiableStore().overrideRecord(finalData);
|
world->getModifiableStore().overrideRecord(finalData);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with invalid baseId %s", record.baseId.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (isExistingId)
|
if (isExistingId)
|
||||||
world->updatePtrsWithRefId(recordData.mId);
|
world->updatePtrsWithRefId(recordData.mId);
|
||||||
|
@ -639,7 +690,7 @@ void RecordHelper::overrideMiscellaneousRecord(const mwmp::MiscellaneousRecord&
|
||||||
|
|
||||||
if (recordData.mId.empty())
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -679,6 +730,11 @@ void RecordHelper::overrideMiscellaneousRecord(const mwmp::MiscellaneousRecord&
|
||||||
|
|
||||||
world->getModifiableStore().overrideRecord(finalData);
|
world->getModifiableStore().overrideRecord(finalData);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with invalid baseId %s", record.baseId.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (isExistingId)
|
if (isExistingId)
|
||||||
world->updatePtrsWithRefId(recordData.mId);
|
world->updatePtrsWithRefId(recordData.mId);
|
||||||
|
@ -690,7 +746,7 @@ void RecordHelper::overrideWeaponRecord(const mwmp::WeaponRecord& record)
|
||||||
|
|
||||||
if (recordData.mId.empty())
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -701,7 +757,7 @@ void RecordHelper::overrideWeaponRecord(const mwmp::WeaponRecord& record)
|
||||||
{
|
{
|
||||||
if (!recordData.mEnchant.empty() && !doesEnchantmentRecordExist(recordData.mEnchant))
|
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;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -761,8 +817,13 @@ void RecordHelper::overrideWeaponRecord(const mwmp::WeaponRecord& record)
|
||||||
if (record.baseOverrides.hasFlags)
|
if (record.baseOverrides.hasFlags)
|
||||||
finalData.mData.mFlags = recordData.mData.mFlags;
|
finalData.mData.mFlags = recordData.mData.mFlags;
|
||||||
|
|
||||||
if (record.baseOverrides.hasEnchantmentId && doesEnchantmentRecordExist(recordData.mEnchant))
|
if (record.baseOverrides.hasEnchantmentId)
|
||||||
finalData.mEnchant = recordData.mEnchant;
|
{
|
||||||
|
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)
|
if (record.baseOverrides.hasEnchantmentCharge)
|
||||||
finalData.mData.mEnchant = recordData.mData.mEnchant;
|
finalData.mData.mEnchant = recordData.mData.mEnchant;
|
||||||
|
@ -772,6 +833,11 @@ void RecordHelper::overrideWeaponRecord(const mwmp::WeaponRecord& record)
|
||||||
|
|
||||||
world->getModifiableStore().overrideRecord(finalData);
|
world->getModifiableStore().overrideRecord(finalData);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with invalid baseId %s", record.baseId.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (isExistingId)
|
if (isExistingId)
|
||||||
world->updatePtrsWithRefId(recordData.mId);
|
world->updatePtrsWithRefId(recordData.mId);
|
||||||
|
|
|
@ -89,7 +89,7 @@
|
||||||
|
|
||||||
#include "WorldstateProcessor.hpp"
|
#include "WorldstateProcessor.hpp"
|
||||||
#include "worldstate/ProcessorCellCreate.hpp"
|
#include "worldstate/ProcessorCellCreate.hpp"
|
||||||
#include "worldstate/ProcessorCellReplace.hpp"
|
#include "worldstate/ProcessorCellReset.hpp"
|
||||||
#include "worldstate/ProcessorRecordDynamic.hpp"
|
#include "worldstate/ProcessorRecordDynamic.hpp"
|
||||||
#include "worldstate/ProcessorWorldCollisionOverride.hpp"
|
#include "worldstate/ProcessorWorldCollisionOverride.hpp"
|
||||||
#include "worldstate/ProcessorWorldMap.hpp"
|
#include "worldstate/ProcessorWorldMap.hpp"
|
||||||
|
@ -186,7 +186,7 @@ void ProcessorInitializer()
|
||||||
ActorProcessor::AddProcessor(new ProcessorActorTest());
|
ActorProcessor::AddProcessor(new ProcessorActorTest());
|
||||||
|
|
||||||
WorldstateProcessor::AddProcessor(new ProcessorCellCreate());
|
WorldstateProcessor::AddProcessor(new ProcessorCellCreate());
|
||||||
WorldstateProcessor::AddProcessor(new ProcessorCellReplace());
|
WorldstateProcessor::AddProcessor(new ProcessorCellReset());
|
||||||
WorldstateProcessor::AddProcessor(new ProcessorRecordDynamic());
|
WorldstateProcessor::AddProcessor(new ProcessorRecordDynamic());
|
||||||
WorldstateProcessor::AddProcessor(new ProcessorWorldCollisionOverride());
|
WorldstateProcessor::AddProcessor(new ProcessorWorldCollisionOverride());
|
||||||
WorldstateProcessor::AddProcessor(new ProcessorWorldMap());
|
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
|
Start of tes3mp addition
|
||||||
|
|
||||||
Send an ID_OBJECT_STATE packet whenever an object is enabled, as long as
|
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
|
the player is logged in on the server, the object is still disabled, and our last
|
||||||
enabled previously
|
packet regarding its state did not already attempt to enable it (to prevent
|
||||||
|
packet spam)
|
||||||
*/
|
*/
|
||||||
if (mwmp::Main::get().getLocalPlayer()->isLoggedIn())
|
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();
|
mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList();
|
||||||
objectList->reset();
|
objectList->reset();
|
||||||
objectList->packetOrigin = ScriptController::getPacketOriginFromContextType(getContextType());
|
objectList->packetOrigin = ScriptController::getPacketOriginFromContextType(getContextType());
|
||||||
|
@ -650,14 +654,18 @@ namespace MWScript
|
||||||
/*
|
/*
|
||||||
Start of tes3mp addition
|
Start of tes3mp addition
|
||||||
|
|
||||||
Send an ID_OBJECT_STATE packet whenever an object is disabled, as long as
|
Send an ID_OBJECT_STATE packet whenever an object should be disabled, as long as
|
||||||
the player is logged in on the server and the object wasn't already
|
the player is logged in on the server, the object is still enabled, and our last
|
||||||
disabled previously
|
packet regarding its state did not already attempt to disable it (to prevent
|
||||||
|
packet spam)
|
||||||
*/
|
*/
|
||||||
if (mwmp::Main::get().getLocalPlayer()->isLoggedIn())
|
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();
|
mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList();
|
||||||
objectList->reset();
|
objectList->reset();
|
||||||
objectList->packetOrigin = ScriptController::getPacketOriginFromContextType(getContextType());
|
objectList->packetOrigin = ScriptController::getPacketOriginFromContextType(getContextType());
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
Include additional headers for multiplayer purposes
|
Include additional headers for multiplayer purposes
|
||||||
*/
|
*/
|
||||||
|
#include <components/openmw-mp/Log.hpp>
|
||||||
#include "../mwmp/Main.hpp"
|
#include "../mwmp/Main.hpp"
|
||||||
#include "../mwmp/CellController.hpp"
|
#include "../mwmp/CellController.hpp"
|
||||||
#include "../mwmp/PlayerList.hpp"
|
#include "../mwmp/PlayerList.hpp"
|
||||||
|
@ -251,7 +252,19 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::findSlot (int slot) con
|
||||||
{
|
{
|
||||||
// Object has been deleted
|
// Object has been deleted
|
||||||
// This should no longer happen, since the new remove function will unequip first
|
// 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];
|
return mSlots[slot];
|
||||||
|
|
|
@ -138,6 +138,34 @@ namespace MWWorld
|
||||||
|
|
||||||
const ESM::AnimationState& getAnimationState() const;
|
const ESM::AnimationState& getAnimationState() const;
|
||||||
ESM::AnimationState& getAnimationState();
|
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
|
If this actor is a LocalPlayer or LocalActor, get their Attack and prepare
|
||||||
it for sending
|
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);
|
mwmp::Attack *localAttack = MechanicsHelper::getLocalAttack(actor);
|
||||||
|
|
||||||
if (localAttack)
|
if (localAttack)
|
||||||
|
@ -3271,6 +3272,8 @@ namespace MWWorld
|
||||||
localAttack->itemId = inv.getSelectedEnchantItem()->getCellRef().getRefId();
|
localAttack->itemId = inv.getSelectedEnchantItem()->getCellRef().getRefId();
|
||||||
localAttack->shouldSend = true;
|
localAttack->shouldSend = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cast.cast(*inv.getSelectedEnchantItem());
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
End of tes3mp addition
|
End of tes3mp addition
|
||||||
|
|
|
@ -202,7 +202,7 @@ add_component_dir (openmw-mp/Packets/Object
|
||||||
add_component_dir (openmw-mp/Packets/Worldstate
|
add_component_dir (openmw-mp/Packets/Worldstate
|
||||||
WorldstatePacket
|
WorldstatePacket
|
||||||
|
|
||||||
PacketCellCreate PacketCellReplace PacketRecordDynamic PacketWorldCollisionOverride PacketWorldMap
|
PacketCellCreate PacketCellReset PacketRecordDynamic PacketWorldCollisionOverride PacketWorldMap
|
||||||
PacketWorldRegionAuthority PacketWorldTime PacketWorldWeather
|
PacketWorldRegionAuthority PacketWorldTime PacketWorldWeather
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -232,6 +232,8 @@ namespace mwmp
|
||||||
}
|
}
|
||||||
|
|
||||||
RakNet::RakNetGUID guid;
|
RakNet::RakNetGUID guid;
|
||||||
|
std::string serverPassword;
|
||||||
|
|
||||||
GUIMessageBox guiMessageBox;
|
GUIMessageBox guiMessageBox;
|
||||||
|
|
||||||
// Track only the indexes of the attributes that have been changed,
|
// Track only the indexes of the attributes that have been changed,
|
||||||
|
@ -295,7 +297,6 @@ namespace mwmp
|
||||||
std::string birthsign;
|
std::string birthsign;
|
||||||
std::string chatMessage;
|
std::string chatMessage;
|
||||||
CharGenState charGenState;
|
CharGenState charGenState;
|
||||||
std::string passw;
|
|
||||||
|
|
||||||
std::string sound;
|
std::string sound;
|
||||||
Animation animation;
|
Animation animation;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#include "../Packets/Worldstate/PacketCellCreate.hpp"
|
#include "../Packets/Worldstate/PacketCellCreate.hpp"
|
||||||
#include "../Packets/Worldstate/PacketCellReplace.hpp"
|
#include "../Packets/Worldstate/PacketCellReset.hpp"
|
||||||
#include "../Packets/Worldstate/PacketRecordDynamic.hpp"
|
#include "../Packets/Worldstate/PacketRecordDynamic.hpp"
|
||||||
#include "../Packets/Worldstate/PacketWorldCollisionOverride.hpp"
|
#include "../Packets/Worldstate/PacketWorldCollisionOverride.hpp"
|
||||||
#include "../Packets/Worldstate/PacketWorldMap.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)
|
mwmp::WorldstatePacketController::WorldstatePacketController(RakNet::RakPeerInterface *peer)
|
||||||
{
|
{
|
||||||
AddPacket<PacketCellCreate>(&packets, peer);
|
AddPacket<PacketCellCreate>(&packets, peer);
|
||||||
AddPacket<PacketCellReplace>(&packets, peer);
|
AddPacket<PacketCellReset>(&packets, peer);
|
||||||
AddPacket<PacketRecordDynamic>(&packets, peer);
|
AddPacket<PacketRecordDynamic>(&packets, peer);
|
||||||
AddPacket<PacketWorldCollisionOverride>(&packets, peer);
|
AddPacket<PacketWorldCollisionOverride>(&packets, peer);
|
||||||
AddPacket<PacketWorldMap>(&packets, peer);
|
AddPacket<PacketWorldMap>(&packets, peer);
|
||||||
|
|
|
@ -104,7 +104,7 @@ enum GameMessages
|
||||||
ID_GAME_PREINIT,
|
ID_GAME_PREINIT,
|
||||||
|
|
||||||
ID_CELL_CREATE,
|
ID_CELL_CREATE,
|
||||||
ID_CELL_REPLACE,
|
ID_CELL_RESET,
|
||||||
ID_RECORD_DYNAMIC,
|
ID_RECORD_DYNAMIC,
|
||||||
ID_WORLD_COLLISION_OVERRIDE,
|
ID_WORLD_COLLISION_OVERRIDE,
|
||||||
ID_WORLD_MAP,
|
ID_WORLD_MAP,
|
||||||
|
|
|
@ -1,7 +1,3 @@
|
||||||
//
|
|
||||||
// Created by koncord on 28.04.16.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <components/openmw-mp/NetworkMessages.hpp>
|
#include <components/openmw-mp/NetworkMessages.hpp>
|
||||||
#include "PacketHandshake.hpp"
|
#include "PacketHandshake.hpp"
|
||||||
|
|
||||||
|
@ -17,8 +13,8 @@ void PacketHandshake::Packet(RakNet::BitStream *bs, bool send)
|
||||||
{
|
{
|
||||||
PlayerPacket::Packet(bs, send);
|
PlayerPacket::Packet(bs, send);
|
||||||
|
|
||||||
if (!RW(player->npc.mName, send, true, maxNameLen) ||
|
if (!RW(player->npc.mName, send, true, maxNameLength) ||
|
||||||
!RW(player->passw, send, true, maxPasswLen))
|
!RW(player->serverPassword, send, true, maxPasswordLength))
|
||||||
{
|
{
|
||||||
packetValid = false;
|
packetValid = false;
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -16,8 +16,8 @@ namespace mwmp
|
||||||
|
|
||||||
virtual void Packet(RakNet::BitStream *bs, bool send);
|
virtual void Packet(RakNet::BitStream *bs, bool send);
|
||||||
|
|
||||||
const static uint32_t maxNameLen = 256;
|
const static uint32_t maxNameLength = 256;
|
||||||
const static uint32_t maxPasswLen = 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
|
#ifndef OPENMW_PACKETCELLRESET_HPP
|
||||||
#define OPENMW_PACKETCELLREPLACE_HPP
|
#define OPENMW_PACKETCELLRESET_HPP
|
||||||
|
|
||||||
#include <components/openmw-mp/Packets/Worldstate/WorldstatePacket.hpp>
|
#include <components/openmw-mp/Packets/Worldstate/WorldstatePacket.hpp>
|
||||||
#include <components/openmw-mp/NetworkMessages.hpp>
|
#include <components/openmw-mp/NetworkMessages.hpp>
|
||||||
|
|
||||||
namespace mwmp
|
namespace mwmp
|
||||||
{
|
{
|
||||||
class PacketCellReplace: public WorldstatePacket
|
class PacketCellReset: public WorldstatePacket
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PacketCellReplace(RakNet::RakPeerInterface *peer);
|
PacketCellReset(RakNet::RakPeerInterface *peer);
|
||||||
|
|
||||||
virtual void Packet(RakNet::BitStream *bs, bool send);
|
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)
|
#if defined(__x86_64__) || defined(_M_X64)
|
||||||
return "64-bit";
|
return "64-bit";
|
||||||
#elif defined(__i386__) || defined(_M_I86)
|
#elif defined(__i386__) || defined(_M_I86) || defined(_M_IX86)
|
||||||
return "32-bit";
|
return "32-bit";
|
||||||
#elif defined(__ARM_ARCH)
|
#elif defined(__ARM_ARCH)
|
||||||
return "ARMv" + __ARM_ARCH;
|
std::string architectureType = "ARMv" + __ARM_ARCH;
|
||||||
#ifdef __aarch64__
|
#ifdef __aarch64__
|
||||||
return "64-bit";
|
architectureType = architectureType + " 64-bit";
|
||||||
#else
|
#else
|
||||||
return "32-bit";
|
architectureType = architectureType + " 32-bit";
|
||||||
#endif
|
#endif
|
||||||
|
return architectureType;
|
||||||
#else
|
#else
|
||||||
return "Unknown architecture";
|
return "Unknown architecture";
|
||||||
#endif
|
#endif
|
||||||
|
@ -211,7 +212,7 @@ void Utils::printVersion(std::string appName, std::string version, std::string c
|
||||||
cout << appName << " " << version;
|
cout << appName << " " << version;
|
||||||
cout << " (" << getOperatingSystemType() << " " << getArchitectureType() << ")" << endl;
|
cout << " (" << getOperatingSystemType() << " " << getArchitectureType() << ")" << endl;
|
||||||
cout << "Protocol version: " << protocol << 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;
|
cout << "------------------------------------------------------------" << endl;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#define TES3MP_DEFAULT_PASSW "SuperPassword"
|
#define TES3MP_DEFAULT_PASSW "SuperPassword"
|
||||||
#define TES3MP_MASTERSERVER_PASSW "12345"
|
#define TES3MP_MASTERSERVER_PASSW "12345"
|
||||||
|
|
||||||
#define TES3MP_CREDITS_CHECKSUM "BC39D2E9"
|
#define TES3MP_CREDITS_CHECKSUM "BAEFF920"
|
||||||
|
|
||||||
|
|
||||||
#endif //OPENMW_VERSION_HPP
|
#endif //OPENMW_VERSION_HPP
|
||||||
|
|
|
@ -4,14 +4,14 @@ tes3mp Credits
|
||||||
Programmers
|
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
|
David Cernat - World, NPC & quest sync, player sync improvements, state saving & loading, extensive bug fixes
|
||||||
|
|
||||||
|
|
||||||
Additional programming
|
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
|
Battlerax - Various small fixes
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@ Community administrators
|
||||||
Community moderators
|
Community moderators
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
|
Lysol
|
||||||
Michael Fitzmayer (mupf)
|
Michael Fitzmayer (mupf)
|
||||||
Nac
|
Nac
|
||||||
NicholasAH
|
NicholasAH
|
||||||
|
@ -53,6 +54,7 @@ Translation
|
||||||
Super special thanks
|
Super special thanks
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
|
Alexander Ovsyannikov
|
||||||
Bret Curtis (psi29a)
|
Bret Curtis (psi29a)
|
||||||
Gabriel Pascu (iGrebla)
|
Gabriel Pascu (iGrebla)
|
||||||
greetasdf
|
greetasdf
|
||||||
|
@ -73,8 +75,9 @@ Special thanks
|
||||||
Gluka
|
Gluka
|
||||||
Goodevil
|
Goodevil
|
||||||
Ignatious
|
Ignatious
|
||||||
James Wards of Gore Corps LAN Club (www.gorecorps.co.nz)
|
James Wards of Gore Corps LAN Club (gorecorps.co.nz)
|
||||||
Jeremiah
|
Jeremiah
|
||||||
|
Kyle Willey of Loreshaper Games (steempeak.com/@loreshapergames)
|
||||||
Lewis Sadlier
|
Lewis Sadlier
|
||||||
Luc Keating
|
Luc Keating
|
||||||
Michael Zagar (Zoops)
|
Michael Zagar (Zoops)
|
||||||
|
@ -84,6 +87,7 @@ Special thanks
|
||||||
Scorcio
|
Scorcio
|
||||||
Simon Nemes
|
Simon Nemes
|
||||||
Texafornian
|
Texafornian
|
||||||
|
Thrud
|
||||||
Zaphida
|
Zaphida
|
||||||
All the developers of OpenMW for creating an amazing open source project
|
All the developers of OpenMW for creating an amazing open source project
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue