forked from mirror/openmw-tes3mp
Compare commits
2 commits
0.7.0
...
fix/skillc
Author | SHA1 | Date | |
---|---|---|---|
27eca7b196 | |||
7e858cdfc7 |
100 changed files with 1038 additions and 1779 deletions
26
.travis.yml
26
.travis.yml
|
@ -4,7 +4,7 @@ os:
|
|||
osx_image: xcode9.4
|
||||
language: cpp
|
||||
sudo: required
|
||||
dist: xenial
|
||||
dist: trusty
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
@ -15,18 +15,18 @@ env:
|
|||
global:
|
||||
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
|
||||
# via the "travis encrypt" command using the project repo's public key
|
||||
- secure: 1QK0yVyoOB+gf2I7XzvhXu9w/5lq4stBXIwJbVCTjz4Q4XVHCosURaW1MAgKzMrPnbFEwjyn5uQ8BwsvvfkuN1AZD0YXITgc7gyI+J1wQ/p/ljxRxglakU6WEgsTs2J5z9UmGac4YTXg+quK7YP3rv+zuGim2I2rhzImejyzp0Ym3kRCnNcy+SGBsiRaevRJMe00Ch8zGAbEhduQGeSoS6W0rcu02DNlQKiq5NktWsXR+TWWWVfIeIlQR/lbPsCd0pdxMaMv2QCY0rVbwrYxWJwr/Qe45dAdWp+8/C3PbXpeMSGxlLa33nJNX4Lf/djxbjm8KWk6edaXPajrjR/0iwcpwq0jg2Jt6XfEdnJt35F1gpXlc04sxStjG45uloOKCFYT0wdhIO1Lq+hDP54wypQl+JInd5qC001O7pwhVxO36EgKWqo8HD+BqGDBwsNj2engy9Qcp3wO6G0rLBPB3CrZsk9wrHVv5cSiQSLMhId3Xviu3ZI2qEDA+kgTvxrKrsnMj4bILVCyG5Ka2Mj22wIDW9e8oIab9oTdujax3DTN1GkD6QuOAGzwDsNwGASsgfoeZ+FUhgM75RlBWGMilgkmnF7EJ0oAXLEpjtABnEr2d4qHv+y08kOuTDBLB9ExzCIj024dYYYNLZrqPKx0ncHuCMG2QNj2aJAJEZtj1rQ=
|
||||
|
||||
- secure: NZmvVuA0O9NJXVQ12tXQZHDJC2mbFgYNFcsicw0DgW1It2Nk5hxIkF0pfu4/Z59mhQuOPgRVjl5b0FKy2Axh0gkWc1DJEXGwNaiW5lpTMNWR1LJG5rxa8LrDUpFkycpbzfAFuTUZu5z3iYVv64XzELvBuqNGhPMu1LeBnrlech0jFNjkR9p5qtJGWb8zYcPMCC57rig8a9g1ABoVYS6UXjrKpx0946ZLRsE5ukc9pXsypGwPmOMyfzZkxxzIqFaxoE5JIEdaJTWba/6Za315ozYYIi/N35ROI1YAv5GHRe/Iw9XAa4vQpbDzjM7ZSsZdTvvQsSU598gD2xC6jFUKSrpW6GZKwM2x236fZLGnOk5Uw7DUbG+AwpcEmxBwoy9PjBl9ZF3tJykI0gROewCy8MODhdsVMKr1HGIMVBIJySm/RnNqtoDbYV8mYnSl5b8rwJiCajoiR8Zuv4CIfGneeH1a3DOQDPH/qkDsU6ilzF4ANsBlMUUpgY653KBMBmTlNuVZSH527tnD7Fg6JgHVuSQkTbRa1vSkR7Zcre604RZcAoaEdbX3bhVDasPPghU/I742L0RH3oQNlR09pPBDZ8kG7ydl4aPHwpCWnvXNM1vgxtGvnYLztwrse7IoaRXRYiMFmrso78WhMWUDKgvY4wV9aeUu0DtnMezZVIQwCKg=
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: 'ppa:openmw/openmw'
|
||||
- sourceline: 'ppa:rakhimov/boost'
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-precise-3.8
|
||||
packages: [
|
||||
# Dev
|
||||
cmake, clang-6.0, libunshield-dev, libtinyxml-dev,
|
||||
g++-8,
|
||||
cmake, clang-3.8, libunshield-dev, libtinyxml-dev,
|
||||
g++-6,
|
||||
# Tests
|
||||
libgtest-dev, google-mock,
|
||||
# Boost
|
||||
|
@ -45,7 +45,7 @@ addons:
|
|||
project:
|
||||
name: "TES3MP/openmw-tes3mp"
|
||||
description: "<Your project description here>"
|
||||
notification_email: koncord@tes3mp.com
|
||||
notification_email: stas5978@gmail.com
|
||||
build_command_prepend: "cmake . -DBUILD_UNITTESTS=FALSE -DBUILD_OPENCS=FALSE -DBUILD_BSATOOL=FALSE -DBUILD_ESMTOOL=FALSE -DBUILD_MWINIIMPORTER=FALSE -DBUILD_LAUNCHER=FALSE"
|
||||
build_command: "make -j3"
|
||||
branch_pattern: coverity_scan
|
||||
|
@ -53,21 +53,21 @@ matrix:
|
|||
include:
|
||||
- os: linux
|
||||
env:
|
||||
- ANALYZE="scan-build-6.0 --use-cc clang-6.0 --use-c++ clang++-6.0 "
|
||||
- MATRIX_CC="CC=clang-6.0 && CXX=clang++-6.0"
|
||||
- ANALYZE="scan-build-3.8 --use-cc clang-3.8 --use-c++ clang++-3.8 "
|
||||
- MATRIX_CC="CC=clang-3.8 && CXX=clang++-3.8"
|
||||
compiler: clang
|
||||
- os: linux
|
||||
env:
|
||||
- MATRIX_CC="CC=gcc-8 && CXX=g++-8"
|
||||
- MATRIX_CC="CC=gcc-6 && CXX=g++-6"
|
||||
- os: linux
|
||||
env:
|
||||
- MATRIX_CC="CC=clang-6.0 && CXX=clang++-6.0"
|
||||
- MATRIX_CC="CC=clang-3.8 && CXX=clang++-3.8"
|
||||
allow_failures:
|
||||
- env:
|
||||
- MATRIX_CC="CC=clang-6.0 && CXX=clang++-6.0"
|
||||
- MATRIX_CC="CC=clang-3.8 && CXX=clang++-3.8"
|
||||
- env:
|
||||
- ANALYZE="scan-build-6.0 --use-cc clang-6.0 --use-c++ clang++-6.0 "
|
||||
- MATRIX_CC="CC=clang-6.0 && CXX=clang++-6.0"
|
||||
- ANALYZE="scan-build-3.8 --use-cc clang-3.8 --use-c++ clang++-3.8 "
|
||||
- MATRIX_CC="CC=clang-3.8 && CXX=clang++-3.8"
|
||||
|
||||
before_install:
|
||||
- ./CI/before_install.${TRAVIS_OS_NAME}.sh
|
||||
|
|
|
@ -15,8 +15,19 @@ sudo ln -s /usr/src/gtest/build/libgtest.so /usr/lib/libgtest.so
|
|||
sudo ln -s /usr/src/gtest/build/libgtest_main.so /usr/lib/libgtest_main.so
|
||||
|
||||
cd ~/
|
||||
git clone https://github.com/TES3MP/CrabNet
|
||||
cd CrabNet
|
||||
cmake . -DCRABNET_ENABLE_DLL=OFF -DCRABNET_ENABLE_SAMPLES=OFF -DCMAKE_BUILD_TYPE=Release
|
||||
git clone https://github.com/TES3MP/RakNet
|
||||
cd RakNet
|
||||
cmake . -DRAKNET_ENABLE_DLL=OFF -DRAKNET_ENABLE_SAMPLES=OFF -DCMAKE_BUILD_TYPE=Release
|
||||
make -j3
|
||||
|
||||
cd ~/
|
||||
git clone https://github.com/Koncord/CallFF
|
||||
cd CallFF
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ../
|
||||
make -j3
|
||||
|
||||
cd ~/
|
||||
wget https://github.com/zdevito/terra/releases/download/release-2016-03-25/terra-Linux-x86_64-332a506.zip
|
||||
unzip terra-Linux-x86_64-332a506.zip
|
||||
|
|
|
@ -9,7 +9,8 @@ if [ ! -z "${MATRIX_CC}" ]; then
|
|||
eval "${MATRIX_CC}"
|
||||
fi
|
||||
|
||||
export RAKNET_ROOT=~/CrabNet
|
||||
export RAKNET_ROOT=~/RakNet
|
||||
export Terra_ROOT=~/terra-Linux-x86_64-332a506
|
||||
|
||||
export CODE_COVERAGE=0
|
||||
if [ ! -z "${ANALYZE}" ]; then
|
||||
|
@ -35,5 +36,7 @@ ${ANALYZE}cmake .. \
|
|||
-DBINDIR=/usr/games \
|
||||
-DCMAKE_BUILD_TYPE="None" \
|
||||
-DUSE_SYSTEM_TINYXML=TRUE \
|
||||
-DRakNet_LIBRARY_RELEASE=~/CrabNet/lib/libRakNetLibStatic.a \
|
||||
-DRakNet_LIBRARY_DEBUG=~/CrabNet/lib/libRakNetLibStatic.a
|
||||
-DRakNet_LIBRARY_RELEASE=~/RakNet/lib/libRakNetLibStatic.a \
|
||||
-DRakNet_LIBRARY_DEBUG=~/RakNet/lib/libRakNetLibStatic.a \
|
||||
-DCallFF_INCLUDES=~/CallFF/include \
|
||||
-DCallFF_LIBRARY=~/CallFF/build/src/libcallff.a
|
||||
|
|
|
@ -736,10 +736,7 @@ if (WIN32)
|
|||
endforeach(d)
|
||||
|
||||
set_target_properties(components PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
|
||||
|
||||
if (BUILD_OPENMW)
|
||||
set_target_properties(osg-ffmpeg-videoplayer PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
|
||||
endif()
|
||||
set_target_properties(osg-ffmpeg-videoplayer PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
|
||||
|
||||
if (BUILD_BSATOOL)
|
||||
set_target_properties(bsatool PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
|
||||
|
|
33
README.md
33
README.md
|
@ -2,11 +2,11 @@ TES3MP
|
|||
======
|
||||
|
||||
Copyright (c) 2008-2015, OpenMW Team
|
||||
Copyright (c) 2016-2019, Stanislav Zhukov & David Cernat
|
||||
Copyright (c) 2016-2018, TES3MP Team
|
||||
|
||||
[![Build Status](https://travis-ci.org/TES3MP/openmw-tes3mp.svg?branch=0.7.0)](https://travis-ci.org/TES3MP/openmw-tes3mp)
|
||||
[![Build Status](https://travis-ci.org/TES3MP/openmw-tes3mp.svg?branch=master)](https://travis-ci.org/TES3MP/openmw-tes3mp)
|
||||
|
||||
TES3MP is a project adding multiplayer functionality to [OpenMW](https://github.com/OpenMW/openmw), an open-source game engine that supports playing "The Elder Scrolls III: Morrowind" by Bethesda Softworks.
|
||||
TES3MP is a project aiming to add multiplayer functionality to [OpenMW](https://github.com/OpenMW/openmw), an open-source game engine that supports playing "The Elder Scrolls III: Morrowind" by Bethesda Softworks.
|
||||
|
||||
* TES3MP version: 0.7.0-alpha
|
||||
* OpenMW version: 0.44.0
|
||||
|
@ -15,35 +15,34 @@ TES3MP is a project adding multiplayer functionality to [OpenMW](https://github.
|
|||
Font Licenses:
|
||||
* DejaVuLGCSansMono.ttf: custom (see [files/mygui/DejaVu Font License.txt](https://github.com/TES3MP/openmw-tes3mp/blob/master/files/mygui/DejaVu%20Font%20License.txt) for more information)
|
||||
|
||||
Project status
|
||||
Project Status
|
||||
--------------
|
||||
|
||||
[Version changelog](https://github.com/TES3MP/openmw-tes3mp/blob/master/tes3mp-changelog.md)
|
||||
|
||||
As of version 0.7.0, TES3MP is fully playable, providing very extensive player, NPC, world and quest synchronization, as well as state saving and loading, all of which are highly customizable via [serverside Lua scripts](https://github.com/TES3MP/CoreScripts).
|
||||
TES3MP is now playable in most respects. Player and NPC movement, animations, combat and spell casting are properly synchronized with small exceptions, as is picking up and dropping items in the world, using doors and levers, and adding and removing items from containers. Journal entries, faction stats and dialogue topics are also synchronized, allowing the majority of quests to work fine.
|
||||
|
||||
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).
|
||||
[Serverside Lua scripts](https://github.com/TES3MP/CoreScripts) are used to save and load the state of most of the aforementioned.
|
||||
|
||||
Contributing
|
||||
---------------
|
||||
--------------
|
||||
|
||||
Helping us with documentation, bug hunting and video showcases is always greatly appreciated.
|
||||
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.
|
||||
|
||||
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.
|
||||
Test sessions are often advertised on [our Discord server](https://discord.gg/ECJk293) or in [our Steam group](https://steamcommunity.com/groups/mwmulti).
|
||||
|
||||
Feel free to contact the [team members](https://github.com/TES3MP/openmw-tes3mp/blob/master/tes3mp-credits.md) for any questions you might have.
|
||||
|
||||
Getting started
|
||||
Getting Started
|
||||
---------------
|
||||
|
||||
* [Quickstart guide](https://github.com/TES3MP/openmw-tes3mp/wiki/Quickstart-guide)
|
||||
* [Steam group](https://steamcommunity.com/groups/mwmulti) and its [detailed FAQ](https://steamcommunity.com/groups/mwmulti/discussions/1/353916184342480541/)
|
||||
* [TES3MP section on OpenMW forums](https://forum.openmw.org/viewforum.php?f=45)
|
||||
* [Discord server](https://discord.gg/ECJk293)
|
||||
* [TES3MP section on OpenMW forums](https://forum.openmw.org/viewforum.php?f=44)
|
||||
* [Subreddit](https://www.reddit.com/r/tes3mp)
|
||||
* [Known issues and bug reports](https://github.com/TES3MP/openmw-tes3mp/issues)
|
||||
|
||||
Donations
|
||||
---------------
|
||||
|
||||
You can benefit the project by contributing to the Patreon pages of our two developers, [Koncord](https://www.patreon.com/Koncord) and [David Cernat](https://www.patreon.com/davidcernat), as well as by supporting [OpenMW](https://openmw.org).
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
project(tes3mp-server)
|
||||
|
||||
if(UNIX) #temporarily disabled for non-unix
|
||||
if(NOT (${CMAKE_CXX_COMPILER} MATCHES "aarch64" OR ${CMAKE_CXX_COMPILER} MATCHES "arm")) #temporarily disabled for arm
|
||||
find_package(CallFF REQUIRED)
|
||||
include_directories(${CallFF_INCLUDES})
|
||||
endif(NOT (${CMAKE_CXX_COMPILER} MATCHES "aarch64" OR ${CMAKE_CXX_COMPILER} MATCHES "arm"))
|
||||
endif(UNIX)
|
||||
|
||||
option(ENABLE_BREAKPAD "Enable Google Breakpad for Crash reporting" OFF)
|
||||
|
||||
if(ENABLE_BREAKPAD)
|
||||
|
@ -29,7 +36,7 @@ if(BUILD_WITH_LUA)
|
|||
Script/LangLua/LangLua.hpp)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DENABLE_LUA")
|
||||
include_directories(SYSTEM ${LuaJit_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR}/extern/LuaBridge)
|
||||
include_directories(${LuaJit_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR}/extern/LuaBridge)
|
||||
endif(BUILD_WITH_LUA)
|
||||
|
||||
set(NativeScript_Sources
|
||||
|
@ -73,6 +80,7 @@ set(SERVER_HEADER
|
|||
Script/ScriptFunctions.hpp Script/API/TimerAPI.hpp Script/API/PublicFnAPI.hpp
|
||||
${LuaScript_Headers}
|
||||
${NativeScript_Headers}
|
||||
${CallFF_INCLUDES}
|
||||
)
|
||||
source_group(tes3mp-server FILES ${SERVER} ${SERVER_HEADER})
|
||||
|
||||
|
@ -152,22 +160,7 @@ add_executable(tes3mp-server
|
|||
${PROCESSORS_ACTOR} ${PROCESSORS_PLAYER} ${PROCESSORS_OBJECT} ${PROCESSORS_WORLDSTATE} ${PROCESSORS}
|
||||
${APPLE_BUNDLE_RESOURCES}
|
||||
)
|
||||
|
||||
target_compile_options(tes3mp-server PRIVATE $<$<CXX_COMPILER_ID:MSVC>:/permissive->)
|
||||
|
||||
if (OPENMW_MP_BUILD)
|
||||
target_compile_options(tes3mp-server PRIVATE $<$<CXX_COMPILER_ID:MSVC>:/MP>)
|
||||
endif()
|
||||
|
||||
set_target_properties(tes3mp-server PROPERTIES
|
||||
CXX_STANDARD 14
|
||||
CXX_STANDARD_REQUIRED YES
|
||||
CXX_EXTENSIONS YES
|
||||
)
|
||||
|
||||
if (UNIX)
|
||||
target_compile_options(tes3mp-server PRIVATE -Wno-ignored-qualifiers)
|
||||
endif()
|
||||
add_definitions(-std=gnu++14 -Wno-ignored-qualifiers)
|
||||
|
||||
target_link_libraries(tes3mp-server
|
||||
#${Boost_SYSTEM_LIBRARY}
|
||||
|
@ -178,6 +171,7 @@ target_link_libraries(tes3mp-server
|
|||
components
|
||||
${LuaJit_LIBRARIES}
|
||||
${Breakpad_Library}
|
||||
${CallFF_LIBRARY}
|
||||
)
|
||||
|
||||
if (UNIX)
|
||||
|
|
|
@ -53,21 +53,18 @@ void Cell::addPlayer(Player *player)
|
|||
players.push_back(player);
|
||||
}
|
||||
|
||||
void Cell::removePlayer(Player *player, bool cleanPlayer)
|
||||
void Cell::removePlayer(Player *player)
|
||||
{
|
||||
for (Iterator it = begin(); it != end(); it++)
|
||||
{
|
||||
if (*it == player)
|
||||
{
|
||||
if (cleanPlayer)
|
||||
auto it2 = find(player->cells.begin(), player->cells.end(), this);
|
||||
if (it2 != player->cells.end())
|
||||
{
|
||||
auto it2 = find(player->cells.begin(), player->cells.end(), this);
|
||||
if (it2 != player->cells.end())
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "- Removing %s from Player %s", getDescription().c_str(), player->npc.mName.c_str());
|
||||
LOG_APPEND(Log::LOG_INFO, "- Removing %s from Player %s", getDescription().c_str(), player->npc.mName.c_str());
|
||||
|
||||
player->cells.erase(it2);
|
||||
}
|
||||
player->cells.erase(it2);
|
||||
}
|
||||
|
||||
LOG_APPEND(Log::LOG_INFO, "- Removing %s from Cell %s", player->npc.mName.c_str(), getDescription().c_str());
|
||||
|
|
|
@ -28,7 +28,7 @@ public:
|
|||
Iterator end() const;
|
||||
|
||||
void addPlayer(Player *player);
|
||||
void removePlayer(Player *player, bool cleanPlayer = true);
|
||||
void removePlayer(Player *player);
|
||||
|
||||
void readActorList(unsigned char packetID, const mwmp::BaseActorList *newActorList);
|
||||
bool containsActor(int refNum, int mpNum);
|
||||
|
|
|
@ -134,35 +134,28 @@ void CellController::removeCell(Cell *cell)
|
|||
}
|
||||
}
|
||||
|
||||
void CellController::deletePlayer(Player *player)
|
||||
void CellController::removePlayer(Cell *cell, Player *player)
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "- Iterating through Cells from Player %s", player->npc.mName.c_str());
|
||||
cell->removePlayer(player);
|
||||
|
||||
std::vector<Cell*> toDelete;
|
||||
|
||||
auto it = player->getCells()->begin();
|
||||
const auto endIter = player->getCells()->end();
|
||||
|
||||
for (; it != endIter; ++it)
|
||||
{
|
||||
Cell *c = *it;
|
||||
c->removePlayer(player, false);
|
||||
if (c->players.empty())
|
||||
toDelete.push_back(c);
|
||||
}
|
||||
|
||||
for (auto &&cell : toDelete)
|
||||
if (cell->players.empty())
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "- Cell %s has no players left", cell->getDescription().c_str());
|
||||
removeCell(cell);
|
||||
}
|
||||
}
|
||||
|
||||
void CellController::deletePlayer(Player *player)
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "- Iterating through Cells from Player %s", player->npc.mName.c_str());
|
||||
|
||||
for (auto it = player->getCells()->begin(); player->getCells()->size() != 0; ++it)
|
||||
removePlayer(*it, player);
|
||||
}
|
||||
|
||||
void CellController::update(Player *player)
|
||||
{
|
||||
std::vector<Cell*> toDelete;
|
||||
|
||||
for (auto &&cell : player->cellStateChanges.cellStates)
|
||||
for (auto cell : player->cellStateChanges.cellStates)
|
||||
{
|
||||
if (cell.type == mwmp::CellState::LOAD)
|
||||
{
|
||||
|
@ -178,16 +171,7 @@ void CellController::update(Player *player)
|
|||
c = getCellByXY(cell.cell.getGridX(), cell.cell.getGridY());
|
||||
|
||||
if (c != nullptr)
|
||||
{
|
||||
c->removePlayer(player);
|
||||
if (c->players.empty())
|
||||
toDelete.push_back(c);
|
||||
}
|
||||
removePlayer(c, player);
|
||||
}
|
||||
}
|
||||
for (auto &&cell : toDelete)
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "- Cell %s has no players left", cell->getDescription().c_str());
|
||||
removeCell(cell);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ public:
|
|||
Cell * addCell(ESM::Cell cell);
|
||||
void removeCell(Cell *);
|
||||
|
||||
void removePlayer(Cell *cell, Player *player);
|
||||
void deletePlayer(Player *player);
|
||||
|
||||
Cell *getCell(ESM::Cell *esmCell);
|
||||
|
|
|
@ -31,7 +31,6 @@ Networking *Networking::sThis = 0;
|
|||
|
||||
static int currentMpNum = 0;
|
||||
static bool pluginEnforcementState = true;
|
||||
static bool scriptErrorIgnoringState = false;
|
||||
|
||||
Networking::Networking(RakNet::RakPeerInterface *peer) : mclient(nullptr)
|
||||
{
|
||||
|
@ -75,9 +74,9 @@ Networking::~Networking()
|
|||
delete worldstatePacketController;
|
||||
}
|
||||
|
||||
void Networking::setServerPassword(std::string password) noexcept
|
||||
void Networking::setServerPassword(std::string passw) noexcept
|
||||
{
|
||||
serverPassword = password.empty() ? TES3MP_DEFAULT_PASSW : password;
|
||||
serverPassword = passw.empty() ? TES3MP_DEFAULT_PASSW : passw;
|
||||
}
|
||||
|
||||
bool Networking::isPassworded() const
|
||||
|
@ -98,32 +97,25 @@ void Networking::processPlayerPacket(RakNet::Packet *packet)
|
|||
|
||||
if (!myPacket->isPacketValid())
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Invalid handshake packet from client at %s", packet->systemAddress.ToString());
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Invalid handshake packet from %d", player->getId());
|
||||
kickPlayer(player->guid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (player->isHandshaked())
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Wrong handshake with client at %s", packet->systemAddress.ToString());
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Wrong handshake with player %d, name: %s", player->getId(),
|
||||
player->npc.mName.c_str());
|
||||
kickPlayer(player->guid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (player->serverPassword != serverPassword)
|
||||
if (player->passw != serverPassword)
|
||||
{
|
||||
if (isPassworded())
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Wrong server password %s used by client at %s",
|
||||
player->serverPassword.c_str(), packet->systemAddress.ToString());
|
||||
kickPlayer(player->guid);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Client at %s tried to join using password, despite the server not being passworded",
|
||||
packet->systemAddress.ToString());
|
||||
}
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Wrong server password for player %d, name: %s (pass: %s)",
|
||||
player->getId(), player->npc.mName.c_str(), player->passw.c_str());
|
||||
kickPlayer(player->guid);
|
||||
return;
|
||||
}
|
||||
player->setHandshake();
|
||||
return;
|
||||
|
@ -132,8 +124,9 @@ void Networking::processPlayerPacket(RakNet::Packet *packet)
|
|||
if (!player->isHandshaked())
|
||||
{
|
||||
player->incrementHandshakeAttempts();
|
||||
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, "Have not completed handshake with player %d", player->getId());
|
||||
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Attempts so far: %i", player->getHandshakeAttempts());
|
||||
|
||||
if (player->getHandshakeAttempts() > 20)
|
||||
kickPlayer(player->guid, false);
|
||||
|
@ -147,10 +140,11 @@ void Networking::processPlayerPacket(RakNet::Packet *packet)
|
|||
{
|
||||
player->setLoadState(Player::LOADED);
|
||||
|
||||
unsigned short pid = Players::getPlayer(packet->guid)->getId();
|
||||
Script::Call<Script::CallbackIdentity("OnPlayerConnect")>(pid);
|
||||
static constexpr unsigned int ident = Script::CallbackIdentity("OnPlayerConnect");
|
||||
Script::CallBackReturn<ident> result = true;
|
||||
Script::Call<ident>(result, Players::getPlayer(packet->guid)->getId());
|
||||
|
||||
if (player->getLoadState() == Player::KICKED) // kicked inside in OnPlayerConnect
|
||||
if (!result)
|
||||
{
|
||||
playerPacketController->GetPacket(ID_USER_DISCONNECTED)->setPlayer(Players::getPlayer(packet->guid));
|
||||
playerPacketController->GetPacket(ID_USER_DISCONNECTED)->Send(false);
|
||||
|
@ -437,16 +431,6 @@ void Networking::setPluginEnforcementState(bool state)
|
|||
pluginEnforcementState = state;
|
||||
}
|
||||
|
||||
bool Networking::getScriptErrorIgnoringState()
|
||||
{
|
||||
return scriptErrorIgnoringState;
|
||||
}
|
||||
|
||||
void Networking::setScriptErrorIgnoringState(bool state)
|
||||
{
|
||||
scriptErrorIgnoringState = state;
|
||||
}
|
||||
|
||||
const Networking &Networking::get()
|
||||
{
|
||||
return *sThis;
|
||||
|
@ -463,6 +447,32 @@ RakNet::SystemAddress Networking::getSystemAddress(RakNet::RakNetGUID guid)
|
|||
return peer->GetSystemAddressFromGuid(guid);
|
||||
}
|
||||
|
||||
PacketPreInit::PluginContainer Networking::getPluginListSample()
|
||||
{
|
||||
PacketPreInit::PluginContainer pls;
|
||||
unsigned id = 0;
|
||||
while (true)
|
||||
{
|
||||
unsigned field = 0;
|
||||
auto name = "";
|
||||
Script::Call<Script::CallbackIdentity("OnRequestPluginList")>(name, id, field++);
|
||||
if (strlen(name) == 0)
|
||||
break;
|
||||
PacketPreInit::HashList hashList;
|
||||
while (true)
|
||||
{
|
||||
auto hash = "";
|
||||
Script::Call<Script::CallbackIdentity("OnRequestPluginList")>(hash, id, field++);
|
||||
if (strlen(hash) == 0)
|
||||
break;
|
||||
hashList.push_back((unsigned)stoul(hash));
|
||||
}
|
||||
pls.push_back({name, hashList});
|
||||
id++;
|
||||
}
|
||||
return pls;
|
||||
}
|
||||
|
||||
void Networking::stopServer(int code)
|
||||
{
|
||||
running = false;
|
||||
|
@ -585,11 +595,16 @@ void Networking::InitQuery(std::string queryAddr, unsigned short queryPort)
|
|||
|
||||
void Networking::postInit()
|
||||
{
|
||||
Script::Call<Script::CallbackIdentity("OnRequestDataFileList")>();
|
||||
Script::Call<Script::CallbackIdentity("OnServerPostInit")>();
|
||||
}
|
||||
|
||||
PacketPreInit::PluginContainer &Networking::getSamples()
|
||||
{
|
||||
return samples;
|
||||
samples = getPluginListSample();
|
||||
if (mclient)
|
||||
{
|
||||
for (auto plugin : samples)
|
||||
{
|
||||
if (!plugin.second.empty())
|
||||
mclient->PushPlugin({plugin.first, plugin.second[0]});
|
||||
else
|
||||
mclient->PushPlugin({plugin.first, 0});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,9 +56,6 @@ namespace mwmp
|
|||
bool getPluginEnforcementState();
|
||||
void setPluginEnforcementState(bool state);
|
||||
|
||||
bool getScriptErrorIgnoringState();
|
||||
void setScriptErrorIgnoringState(bool state);
|
||||
|
||||
MasterClient *getMasterClient();
|
||||
void InitQuery(std::string queryAddr, unsigned short queryPort);
|
||||
void setServerPassword(std::string passw) noexcept;
|
||||
|
@ -68,10 +65,9 @@ namespace mwmp
|
|||
static Networking *getPtr();
|
||||
|
||||
void postInit();
|
||||
|
||||
PacketPreInit::PluginContainer &getSamples();
|
||||
private:
|
||||
bool preInit(RakNet::Packet *packet, RakNet::BitStream &bsIn);
|
||||
PacketPreInit::PluginContainer getPluginListSample();
|
||||
std::string serverPassword;
|
||||
static Networking *sThis;
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "Cell.hpp"
|
||||
#include "CellController.hpp"
|
||||
|
||||
struct Player;
|
||||
typedef std::map<RakNet::RakNetGUID, Player*> TPlayers;
|
||||
typedef std::map<unsigned short, Player*> TSlots;
|
||||
|
||||
|
@ -50,8 +51,7 @@ public:
|
|||
{
|
||||
NOTLOADED=0,
|
||||
LOADED,
|
||||
POSTLOADED,
|
||||
KICKED
|
||||
POSTLOADED
|
||||
};
|
||||
Player(RakNet::RakNetGUID guid);
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
//
|
||||
// Created by koncord on 15.03.16.
|
||||
//
|
||||
|
||||
#include "TimerAPI.hpp"
|
||||
|
||||
#include <chrono>
|
||||
|
@ -10,7 +14,7 @@ Timer::Timer(ScriptFunc callback, long msec, const std::string& def, std::vector
|
|||
{
|
||||
targetMsec = msec;
|
||||
this->args = args;
|
||||
isEnded = true;
|
||||
end = true;
|
||||
}
|
||||
|
||||
#if defined(ENABLE_LUA)
|
||||
|
@ -18,13 +22,13 @@ Timer::Timer(lua_State *lua, ScriptFuncLua callback, long msec, const std::strin
|
|||
{
|
||||
targetMsec = msec;
|
||||
this->args = args;
|
||||
isEnded = true;
|
||||
end = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void Timer::Tick()
|
||||
{
|
||||
if (isEnded)
|
||||
if (end)
|
||||
return;
|
||||
|
||||
const auto duration = chrono::system_clock::now().time_since_epoch();
|
||||
|
@ -32,19 +36,19 @@ void Timer::Tick()
|
|||
|
||||
if (time - startTime >= targetMsec)
|
||||
{
|
||||
isEnded = true;
|
||||
end = true;
|
||||
Call(args);
|
||||
}
|
||||
}
|
||||
|
||||
bool Timer::IsEnded()
|
||||
bool Timer::IsEnd()
|
||||
{
|
||||
return isEnded;
|
||||
return end;
|
||||
}
|
||||
|
||||
void Timer::Stop()
|
||||
{
|
||||
isEnded = true;
|
||||
end = true;
|
||||
}
|
||||
|
||||
void Timer::Restart(int msec)
|
||||
|
@ -55,7 +59,7 @@ void Timer::Restart(int msec)
|
|||
|
||||
void Timer::Start()
|
||||
{
|
||||
isEnded = false;
|
||||
end = false;
|
||||
|
||||
const auto duration = chrono::system_clock::now().time_since_epoch();
|
||||
const auto msec = chrono::duration_cast<chrono::milliseconds>(duration).count();
|
||||
|
@ -168,12 +172,12 @@ void TimerAPI::StopTimer(int timerid)
|
|||
}
|
||||
}
|
||||
|
||||
bool TimerAPI::IsTimerElapsed(int timerid)
|
||||
bool TimerAPI::IsEndTimer(int timerid)
|
||||
{
|
||||
bool ret = false;
|
||||
try
|
||||
{
|
||||
ret = timers.at(timerid)->IsEnded();
|
||||
ret = timers.at(timerid)->IsEnd();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
//
|
||||
// Created by koncord on 15.03.16.
|
||||
//
|
||||
|
||||
#ifndef OPENMW_TIMERAPI_HPP
|
||||
#define OPENMW_TIMERAPI_HPP
|
||||
|
||||
|
@ -23,7 +27,7 @@ namespace mwmp
|
|||
#endif
|
||||
void Tick();
|
||||
|
||||
bool IsEnded();
|
||||
bool IsEnd();
|
||||
void Stop();
|
||||
void Start();
|
||||
void Restart(int msec);
|
||||
|
@ -32,7 +36,7 @@ namespace mwmp
|
|||
std::string publ, arg_types;
|
||||
std::vector<boost::any> args;
|
||||
Script *scr;
|
||||
bool isEnded;
|
||||
bool end;
|
||||
};
|
||||
|
||||
class TimerAPI
|
||||
|
@ -46,7 +50,7 @@ namespace mwmp
|
|||
static void ResetTimer(int timerid, long msec);
|
||||
static void StartTimer(int timerid);
|
||||
static void StopTimer(int timerid);
|
||||
static bool IsTimerElapsed(int timerid);
|
||||
static bool IsEndTimer(int timerid);
|
||||
|
||||
static void Terminate();
|
||||
|
||||
|
|
|
@ -537,7 +537,7 @@ void ActorFunctions::InitializeActorList(unsigned short pid) noexcept
|
|||
|
||||
void ActorFunctions::CopyLastActorListToStore() noexcept
|
||||
{
|
||||
CopyReceivedActorListToStore();
|
||||
CopyLastActorListToStore();
|
||||
}
|
||||
|
||||
unsigned int ActorFunctions::GetActorRefNumIndex(unsigned int index) noexcept
|
||||
|
|
|
@ -1,12 +1,38 @@
|
|||
#include "Miscellaneous.hpp"
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
#include <components/openmw-mp/Log.hpp>
|
||||
|
||||
#include <apps/openmw-mp/Script/ScriptFunctions.hpp>
|
||||
#include <apps/openmw-mp/Networking.hpp>
|
||||
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
static std::string tempFilename;
|
||||
|
||||
bool MiscellaneousFunctions::DoesFileExist(const char *filePath) noexcept
|
||||
{
|
||||
return boost::filesystem::exists(filePath);
|
||||
}
|
||||
|
||||
const char *MiscellaneousFunctions::GetCaseInsensitiveFilename(const char *folderPath, const char *filename) noexcept
|
||||
{
|
||||
if (!boost::filesystem::exists(folderPath)) return "invalid";
|
||||
|
||||
boost::filesystem::directory_iterator end_itr; // default construction yields past-the-end
|
||||
|
||||
for (boost::filesystem::directory_iterator itr(folderPath); itr != end_itr; ++itr)
|
||||
{
|
||||
if (Misc::StringUtils::ciEqual(itr->path().filename().string(), filename))
|
||||
{
|
||||
tempFilename = itr->path().filename().string();
|
||||
return tempFilename.c_str();
|
||||
}
|
||||
}
|
||||
return "invalid";
|
||||
}
|
||||
|
||||
unsigned int MiscellaneousFunctions::GetLastPlayerId() noexcept
|
||||
{
|
||||
return Players::getLastPlayerId();
|
||||
|
@ -21,3 +47,23 @@ void MiscellaneousFunctions::SetCurrentMpNum(int mpNum) noexcept
|
|||
{
|
||||
mwmp::Networking::getPtr()->setCurrentMpNum(mpNum);
|
||||
}
|
||||
|
||||
int MiscellaneousFunctions::GetPluginEnforcementState() noexcept
|
||||
{
|
||||
return mwmp::Networking::getPtr()->getPluginEnforcementState();
|
||||
}
|
||||
|
||||
void MiscellaneousFunctions::SetPluginEnforcementState(bool state) noexcept
|
||||
{
|
||||
mwmp::Networking::getPtr()->setPluginEnforcementState(state);
|
||||
}
|
||||
|
||||
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,15 +4,45 @@
|
|||
#include "../Types.hpp"
|
||||
|
||||
#define MISCELLANEOUSAPI \
|
||||
{"DoesFileExist", MiscellaneousFunctions::DoesFileExist},\
|
||||
{"GetCaseInsensitiveFilename", MiscellaneousFunctions::GetCaseInsensitiveFilename},\
|
||||
\
|
||||
{"GetLastPlayerId", MiscellaneousFunctions::GetLastPlayerId},\
|
||||
\
|
||||
{"GetCurrentMpNum", MiscellaneousFunctions::GetCurrentMpNum},\
|
||||
{"SetCurrentMpNum", MiscellaneousFunctions::SetCurrentMpNum}
|
||||
{"SetCurrentMpNum", MiscellaneousFunctions::SetCurrentMpNum},\
|
||||
\
|
||||
{"GetPluginEnforcementState", MiscellaneousFunctions::GetPluginEnforcementState},\
|
||||
{"SetPluginEnforcementState", MiscellaneousFunctions::SetPluginEnforcementState},\
|
||||
\
|
||||
{"LogMessage", MiscellaneousFunctions::LogMessage},\
|
||||
{"LogAppend", MiscellaneousFunctions::LogAppend}
|
||||
|
||||
class MiscellaneousFunctions
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* \brief Check whether a certain file exists.
|
||||
*
|
||||
* This will be a case sensitive check on case sensitive filesystems.
|
||||
*
|
||||
* Whenever you want to enforce case insensitivity, use GetCaseInsensitiveFilename() instead.
|
||||
*
|
||||
* \return Whether the file exists or not.
|
||||
*/
|
||||
static bool DoesFileExist(const char *filePath) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the first filename in a folder that has a case insensitive match with the filename
|
||||
* argument.
|
||||
*
|
||||
* This is used to retain case insensitivity when opening data files on Linux.
|
||||
*
|
||||
* \return The filename that matches.
|
||||
*/
|
||||
static const char *GetCaseInsensitiveFilename(const char *folderPath, const char *filename) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the last player ID currently connected to the server.
|
||||
*
|
||||
|
@ -48,6 +78,49 @@ public:
|
|||
* \return void
|
||||
*/
|
||||
static void SetCurrentMpNum(int mpNum) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the plugin enforcement state of the server.
|
||||
*
|
||||
* If true, clients are required to use the same plugins as set for the server.
|
||||
*
|
||||
* \return The enforcement state.
|
||||
*/
|
||||
static int GetPluginEnforcementState() noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the plugin enforcement state of the server.
|
||||
*
|
||||
* If true, clients are required to use the same plugins as set for the server.
|
||||
*
|
||||
* \param state The new enforcement state.
|
||||
* \return void
|
||||
*/
|
||||
static void SetPluginEnforcementState(bool state) 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
|
||||
|
|
|
@ -399,15 +399,6 @@ void ObjectFunctions::SetObjectRotation(double x, double y, double z) noexcept
|
|||
tempObject.position.rot[2] = z;
|
||||
}
|
||||
|
||||
void ObjectFunctions::SetObjectActivatingPid(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, );
|
||||
|
||||
tempObject.activatingActor.guid = player->guid;
|
||||
tempObject.activatingActor.isPlayer = true;
|
||||
}
|
||||
|
||||
void ObjectFunctions::SetObjectDoorState(int doorState) noexcept
|
||||
{
|
||||
tempObject.doorState = doorState;
|
||||
|
|
|
@ -85,8 +85,6 @@
|
|||
{"SetObjectPosition", ObjectFunctions::SetObjectPosition},\
|
||||
{"SetObjectRotation", ObjectFunctions::SetObjectRotation},\
|
||||
\
|
||||
{"SetObjectActivatingPid", ObjectFunctions::SetObjectActivatingPid},\
|
||||
\
|
||||
{"SetObjectDoorState", ObjectFunctions::SetObjectDoorState},\
|
||||
{"SetObjectDoorTeleportState", ObjectFunctions::SetObjectDoorTeleportState},\
|
||||
{"SetObjectDoorDestinationCell", ObjectFunctions::SetObjectDoorDestinationCell},\
|
||||
|
@ -778,15 +776,6 @@ public:
|
|||
*/
|
||||
static void SetObjectRotation(double x, double y, double z) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the player ID of the player activating the temporary object stored on the
|
||||
* server. Currently only used for ObjectActivate packets.
|
||||
*
|
||||
* \param pid The pid of the player.
|
||||
* \return void
|
||||
*/
|
||||
static void SetObjectActivatingPid(unsigned short pid) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the door state of the temporary object stored on the server.
|
||||
*
|
||||
|
|
|
@ -7,6 +7,20 @@
|
|||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
void PositionFunctions::GetPos(unsigned short pid, float *x, float *y, float *z) noexcept
|
||||
{
|
||||
*x = 0.00;
|
||||
*y = 0.00;
|
||||
*z = 0.00;
|
||||
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player,);
|
||||
|
||||
*x = player->position.pos[0];
|
||||
*y = player->position.pos[1];
|
||||
*z = player->position.pos[2];
|
||||
}
|
||||
|
||||
double PositionFunctions::GetPosX(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
|
@ -55,6 +69,20 @@ double PositionFunctions::GetPreviousCellPosZ(unsigned short pid) noexcept
|
|||
return player->previousCellPosition.pos[2];
|
||||
}
|
||||
|
||||
void PositionFunctions::GetRot(unsigned short pid, float *x, float *y, float *z) noexcept
|
||||
{
|
||||
*x = 0.00;
|
||||
*y = 0.00;
|
||||
*z = 0.00;
|
||||
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, );
|
||||
|
||||
*x = player->position.rot[0];
|
||||
*y = player->position.rot[1];
|
||||
*z = player->position.rot[2];
|
||||
}
|
||||
|
||||
double PositionFunctions::GetRotX(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "../Types.hpp"
|
||||
|
||||
#define POSITIONAPI \
|
||||
{"GetPos", PositionFunctions::GetPos},\
|
||||
{"GetPosX", PositionFunctions::GetPosX},\
|
||||
{"GetPosY", PositionFunctions::GetPosY},\
|
||||
{"GetPosZ", PositionFunctions::GetPosZ},\
|
||||
|
@ -12,6 +13,7 @@
|
|||
{"GetPreviousCellPosY", PositionFunctions::GetPreviousCellPosY},\
|
||||
{"GetPreviousCellPosZ", PositionFunctions::GetPreviousCellPosZ},\
|
||||
\
|
||||
{"GetRot", PositionFunctions::GetRot},\
|
||||
{"GetRotX", PositionFunctions::GetRotX},\
|
||||
{"GetRotZ", PositionFunctions::GetRotZ},\
|
||||
\
|
||||
|
@ -27,6 +29,18 @@ class PositionFunctions
|
|||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* \brief Assign the player's positional coordinate values to the variables passed as
|
||||
* parameters.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \param x The variable for the X position.
|
||||
* \param y The variable for the Y position.
|
||||
* \param z The variable for the Z position.
|
||||
* \return void
|
||||
*/
|
||||
static void GetPos(unsigned short pid, float *x, float *y, float *z) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the X position of a player.
|
||||
*
|
||||
|
@ -75,6 +89,18 @@ public:
|
|||
*/
|
||||
static double GetPreviousCellPosZ(unsigned short pid) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Assign the player's rotational coordinate values to the variables passed as
|
||||
* parameters.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \param x The variable for the X rotation.
|
||||
* \param y The variable for the Y rotation.
|
||||
* \param z The variable for the Z rotation.
|
||||
* \return void
|
||||
*/
|
||||
static void GetRot(unsigned short pid, float *x, float *y, float *z) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the X rotation of a player.
|
||||
*
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#include "Server.hpp"
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
#include <components/openmw-mp/NetworkMessages.hpp>
|
||||
#include <components/openmw-mp/Log.hpp>
|
||||
#include <components/openmw-mp/Version.hpp>
|
||||
|
@ -8,20 +7,7 @@
|
|||
#include <apps/openmw-mp/Script/ScriptFunctions.hpp>
|
||||
#include <apps/openmw-mp/Networking.hpp>
|
||||
#include <apps/openmw-mp/MasterClient.hpp>
|
||||
#include <Script/Script.hpp>
|
||||
|
||||
static std::string tempFilename;
|
||||
static std::chrono::high_resolution_clock::time_point startupTime = std::chrono::high_resolution_clock::now();
|
||||
|
||||
void ServerFunctions::LogMessage(unsigned short level, const char *message) noexcept
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(level, "[Script]: %s", message);
|
||||
}
|
||||
|
||||
void ServerFunctions::LogAppend(unsigned short level, const char *message) noexcept
|
||||
{
|
||||
LOG_APPEND(level, "[Script]: %s", message);
|
||||
}
|
||||
|
||||
void ServerFunctions::StopServer(int code) noexcept
|
||||
{
|
||||
|
@ -32,10 +18,7 @@ void ServerFunctions::Kick(unsigned short pid) noexcept
|
|||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player,);
|
||||
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Kicking player %s (%i)", player->npc.mName.c_str(), player->getId());
|
||||
mwmp::Networking::getPtr()->kickPlayer(player->guid);
|
||||
player->setLoadState(Player::KICKED);
|
||||
}
|
||||
|
||||
void ServerFunctions::BanAddress(const char *ipAddress) noexcept
|
||||
|
@ -48,50 +31,6 @@ void ServerFunctions::UnbanAddress(const char *ipAddress) noexcept
|
|||
mwmp::Networking::getPtr()->unbanAddress(ipAddress);
|
||||
}
|
||||
|
||||
bool ServerFunctions::DoesFilePathExist(const char *filePath) noexcept
|
||||
{
|
||||
return boost::filesystem::exists(filePath);
|
||||
}
|
||||
|
||||
const char *ServerFunctions::GetCaseInsensitiveFilename(const char *folderPath, const char *filename) noexcept
|
||||
{
|
||||
if (!boost::filesystem::exists(folderPath)) return "invalid";
|
||||
|
||||
boost::filesystem::directory_iterator end_itr; // default construction yields past-the-end
|
||||
|
||||
for (boost::filesystem::directory_iterator itr(folderPath); itr != end_itr; ++itr)
|
||||
{
|
||||
if (Misc::StringUtils::ciEqual(itr->path().filename().string(), filename))
|
||||
{
|
||||
tempFilename = itr->path().filename().string();
|
||||
return tempFilename.c_str();
|
||||
}
|
||||
}
|
||||
return "invalid";
|
||||
}
|
||||
|
||||
const char* ServerFunctions::GetDataPath() noexcept
|
||||
{
|
||||
return Script::GetModDir();
|
||||
}
|
||||
|
||||
unsigned int ServerFunctions::GetMillisecondsSinceServerStart() noexcept
|
||||
{
|
||||
std::chrono::high_resolution_clock::time_point currentTime = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::milliseconds milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(currentTime - startupTime);
|
||||
return milliseconds.count();
|
||||
}
|
||||
|
||||
const char *ServerFunctions::GetOperatingSystemType() noexcept
|
||||
{
|
||||
return Utils::getOperatingSystemType().c_str();
|
||||
}
|
||||
|
||||
const char *ServerFunctions::GetArchitectureType() noexcept
|
||||
{
|
||||
return Utils::getArchitectureType().c_str();
|
||||
}
|
||||
|
||||
const char *ServerFunctions::GetServerVersion() noexcept
|
||||
{
|
||||
return TES3MP_VERSION;
|
||||
|
@ -133,16 +72,6 @@ bool ServerFunctions::HasPassword() noexcept
|
|||
return mwmp::Networking::get().isPassworded();
|
||||
}
|
||||
|
||||
bool ServerFunctions::GetPluginEnforcementState() noexcept
|
||||
{
|
||||
return mwmp::Networking::getPtr()->getPluginEnforcementState();
|
||||
}
|
||||
|
||||
bool ServerFunctions::GetScriptErrorIgnoringState() noexcept
|
||||
{
|
||||
return mwmp::Networking::getPtr()->getScriptErrorIgnoringState();
|
||||
}
|
||||
|
||||
void ServerFunctions::SetGameMode(const char *gameMode) noexcept
|
||||
{
|
||||
if (mwmp::Networking::getPtr()->getMasterClient())
|
||||
|
@ -160,16 +89,6 @@ void ServerFunctions::SetServerPassword(const char *password) noexcept
|
|||
mwmp::Networking::getPtr()->setServerPassword(password);
|
||||
}
|
||||
|
||||
void ServerFunctions::SetPluginEnforcementState(bool state) noexcept
|
||||
{
|
||||
mwmp::Networking::getPtr()->setPluginEnforcementState(state);
|
||||
}
|
||||
|
||||
void ServerFunctions::SetScriptErrorIgnoringState(bool state) noexcept
|
||||
{
|
||||
mwmp::Networking::getPtr()->setScriptErrorIgnoringState(state);
|
||||
}
|
||||
|
||||
void ServerFunctions::SetRuleString(const char *key, const char *value) noexcept
|
||||
{
|
||||
auto mc = mwmp::Networking::getPtr()->getMasterClient();
|
||||
|
@ -183,47 +102,3 @@ void ServerFunctions::SetRuleValue(const char *key, double value) noexcept
|
|||
if (mc)
|
||||
mc->SetRuleValue(key, value);
|
||||
}
|
||||
|
||||
void ServerFunctions::AddDataFileRequirement(const char *dataFilename, const char *checksumString) noexcept
|
||||
{
|
||||
auto &samples = mwmp::Networking::getPtr()->getSamples();
|
||||
auto it = std::find_if(samples.begin(), samples.end(), [&dataFilename](mwmp::PacketPreInit::PluginPair &item) {
|
||||
return item.first == dataFilename;
|
||||
});
|
||||
if (it != samples.end())
|
||||
it->second.push_back((unsigned) std::stoul(checksumString));
|
||||
else
|
||||
{
|
||||
mwmp::PacketPreInit::HashList checksumList;
|
||||
|
||||
unsigned checksum = 0;
|
||||
|
||||
if (strlen(checksumString) != 0)
|
||||
{
|
||||
checksum = (unsigned) std::stoul(checksumString);
|
||||
checksumList.push_back(checksum);
|
||||
}
|
||||
samples.emplace_back(dataFilename, checksumList);
|
||||
|
||||
auto mclient = mwmp::Networking::getPtr()->getMasterClient();
|
||||
if (mclient)
|
||||
mclient->PushPlugin({dataFilename, checksum});
|
||||
}
|
||||
}
|
||||
|
||||
// All methods below are deprecated versions of methods from above
|
||||
|
||||
bool ServerFunctions::DoesFileExist(const char *filePath) noexcept
|
||||
{
|
||||
return DoesFilePathExist(filePath);
|
||||
}
|
||||
|
||||
const char* ServerFunctions::GetModDir() noexcept
|
||||
{
|
||||
return GetDataPath();
|
||||
}
|
||||
|
||||
void ServerFunctions::AddPluginHash(const char *pluginName, const char *checksumString) noexcept
|
||||
{
|
||||
AddDataFileRequirement(pluginName, checksumString);
|
||||
}
|
||||
|
|
|
@ -4,73 +4,30 @@
|
|||
#include "../Types.hpp"
|
||||
|
||||
#define SERVERAPI \
|
||||
{"LogMessage", ServerFunctions::LogMessage},\
|
||||
{"LogAppend", ServerFunctions::LogAppend},\
|
||||
{"StopServer", ServerFunctions::StopServer},\
|
||||
\
|
||||
{"StopServer", ServerFunctions::StopServer},\
|
||||
{"Kick", ServerFunctions::Kick},\
|
||||
{"BanAddress", ServerFunctions::BanAddress},\
|
||||
{"UnbanAddress", ServerFunctions::UnbanAddress},\
|
||||
\
|
||||
{"Kick", ServerFunctions::Kick},\
|
||||
{"BanAddress", ServerFunctions::BanAddress},\
|
||||
{"UnbanAddress", ServerFunctions::UnbanAddress},\
|
||||
{"GetServerVersion", ServerFunctions::GetServerVersion},\
|
||||
{"GetProtocolVersion", ServerFunctions::GetProtocolVersion},\
|
||||
{"GetAvgPing", ServerFunctions::GetAvgPing},\
|
||||
{"GetIP", ServerFunctions::GetIP},\
|
||||
{"GetMaxPlayers", ServerFunctions::GetMaxPlayers},\
|
||||
{"GetPort", ServerFunctions::GetPort},\
|
||||
{"HasPassword", ServerFunctions::HasPassword},\
|
||||
\
|
||||
{"DoesFilePathExist", ServerFunctions::DoesFilePathExist},\
|
||||
{"GetCaseInsensitiveFilename", ServerFunctions::GetCaseInsensitiveFilename},\
|
||||
{"GetDataPath", ServerFunctions::GetDataPath},\
|
||||
{"GetMillisecondsSinceServerStart", ServerFunctions::GetMillisecondsSinceServerStart},\
|
||||
{"GetOperatingSystemType", ServerFunctions::GetOperatingSystemType},\
|
||||
{"GetArchitectureType", ServerFunctions::GetArchitectureType},\
|
||||
{"GetServerVersion", ServerFunctions::GetServerVersion},\
|
||||
{"GetProtocolVersion", ServerFunctions::GetProtocolVersion},\
|
||||
{"GetAvgPing", ServerFunctions::GetAvgPing},\
|
||||
{"GetIP", ServerFunctions::GetIP},\
|
||||
{"GetMaxPlayers", ServerFunctions::GetMaxPlayers},\
|
||||
{"GetPort", ServerFunctions::GetPort},\
|
||||
{"HasPassword", ServerFunctions::HasPassword},\
|
||||
{"GetPluginEnforcementState", ServerFunctions::GetPluginEnforcementState},\
|
||||
{"GetScriptErrorIgnoringState", ServerFunctions::GetScriptErrorIgnoringState},\
|
||||
\
|
||||
{"SetGameMode", ServerFunctions::SetGameMode},\
|
||||
{"SetHostname", ServerFunctions::SetHostname},\
|
||||
{"SetServerPassword", ServerFunctions::SetServerPassword},\
|
||||
{"SetPluginEnforcementState", ServerFunctions::SetPluginEnforcementState},\
|
||||
{"SetScriptErrorIgnoringState", ServerFunctions::SetScriptErrorIgnoringState},\
|
||||
{"SetRuleString", ServerFunctions::SetRuleString},\
|
||||
{"SetRuleValue", ServerFunctions::SetRuleValue},\
|
||||
\
|
||||
{"AddDataFileRequirement", ServerFunctions::AddDataFileRequirement},\
|
||||
\
|
||||
{"DoesFileExist", ServerFunctions::DoesFileExist},\
|
||||
{"GetModDir", ServerFunctions::GetModDir},\
|
||||
{"AddPluginHash", ServerFunctions::AddPluginHash}
|
||||
{"SetGameMode", ServerFunctions::SetGameMode},\
|
||||
{"SetHostname", ServerFunctions::SetHostname},\
|
||||
{"SetServerPassword", ServerFunctions::SetServerPassword},\
|
||||
{"SetRuleString", ServerFunctions::SetRuleString},\
|
||||
{"SetRuleValue", ServerFunctions::SetRuleValue}
|
||||
|
||||
class ServerFunctions
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* \brief Write a log message with its own timestamp.
|
||||
*
|
||||
* It will have "[Script]:" prepended to it so as to mark it as a script-generated log message.
|
||||
*
|
||||
* \param level The logging level used (0 for LOG_VERBOSE, 1 for LOG_INFO, 2 for LOG_WARN,
|
||||
* 3 for LOG_ERROR, 4 for LOG_FATAL).
|
||||
* \param message The message logged.
|
||||
* \return void
|
||||
*/
|
||||
static void LogMessage(unsigned short level, const char *message) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Write a log message without its own timestamp.
|
||||
*
|
||||
* It will have "[Script]:" prepended to it so as to mark it as a script-generated log message.
|
||||
*
|
||||
* \param level The logging level used (0 for LOG_VERBOSE, 1 for LOG_INFO, 2 for LOG_WARN,
|
||||
* 3 for LOG_ERROR, 4 for LOG_FATAL).
|
||||
* \param message The message logged.
|
||||
* \return void
|
||||
*/
|
||||
static void LogAppend(unsigned short level, const char *message) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Shut down the server.
|
||||
*
|
||||
|
@ -103,59 +60,6 @@ public:
|
|||
*/
|
||||
static void UnbanAddress(const char *ipAddress) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Check whether a certain file path exists.
|
||||
*
|
||||
* This will be a case sensitive check on case sensitive filesystems.
|
||||
*
|
||||
* Whenever you want to enforce case insensitivity, use GetCaseInsensitiveFilename() instead.
|
||||
*
|
||||
* \return Whether the file exists or not.
|
||||
*/
|
||||
static bool DoesFilePathExist(const char *filePath) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the first filename in a folder that has a case insensitive match with the filename
|
||||
* argument.
|
||||
*
|
||||
* This is used to retain case insensitivity when opening data files on Linux.
|
||||
*
|
||||
* \return The filename that matches.
|
||||
*/
|
||||
static const char *GetCaseInsensitiveFilename(const char *folderPath, const char *filename) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the path of the server's data folder.
|
||||
*
|
||||
* \return The data path.
|
||||
*/
|
||||
static const char *GetDataPath() noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the milliseconds elapsed since the server was started.
|
||||
*
|
||||
* \return The time since the server's startup in milliseconds.
|
||||
*/
|
||||
static unsigned int GetMillisecondsSinceServerStart() noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the type of the operating system used by the server.
|
||||
*
|
||||
* Note: Currently, the type can be "Windows", "Linux", "OS X" or "Unknown OS".
|
||||
*
|
||||
* \return The type of the operating system.
|
||||
*/
|
||||
static const char *GetOperatingSystemType() noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the architecture type used by the server.
|
||||
*
|
||||
* Note: Currently, the type can be "64-bit", "32-bit", "ARMv#" or "Unknown architecture".
|
||||
*
|
||||
* \return The architecture type.
|
||||
*/
|
||||
static const char *GetArchitectureType() noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the TES3MP version of the server.
|
||||
*
|
||||
|
@ -189,7 +93,7 @@ public:
|
|||
/**
|
||||
* \brief Get the port used by the server.
|
||||
*
|
||||
* \return The port.
|
||||
* \return Port
|
||||
*/
|
||||
static unsigned short GetPort() noexcept;
|
||||
|
||||
|
@ -207,24 +111,6 @@ public:
|
|||
*/
|
||||
static bool HasPassword() noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the plugin enforcement state of the server.
|
||||
*
|
||||
* If true, clients are required to use the same plugins as set for the server.
|
||||
*
|
||||
* \return The enforcement state.
|
||||
*/
|
||||
static bool GetPluginEnforcementState() noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the script error ignoring state of the server.
|
||||
*
|
||||
* If true, script errors will not crash the server.
|
||||
*
|
||||
* \return The script error ignoring state.
|
||||
*/
|
||||
static bool GetScriptErrorIgnoringState() noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the game mode of the server, as displayed in the server browser.
|
||||
*
|
||||
|
@ -247,29 +133,7 @@ public:
|
|||
* \param password The password.
|
||||
* \return void
|
||||
*/
|
||||
static void SetServerPassword(const char *password) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the plugin enforcement state of the server.
|
||||
*
|
||||
* If true, clients are required to use the same plugins as set for the server.
|
||||
*
|
||||
* \param state The new enforcement state.
|
||||
* \return void
|
||||
*/
|
||||
static void SetPluginEnforcementState(bool state) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set whether script errors should be ignored or not.
|
||||
*
|
||||
* If true, script errors will not crash the server, but could have any number
|
||||
* of unforeseen consequences, which is why this is a highly experimental
|
||||
* setting.
|
||||
*
|
||||
* \param state The new script error ignoring state.
|
||||
* \return void
|
||||
*/
|
||||
static void SetScriptErrorIgnoringState(bool state) noexcept;
|
||||
static void SetServerPassword(const char *passw) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set a rule string for the server details displayed in the server browser.
|
||||
|
@ -288,26 +152,6 @@ public:
|
|||
* \return void
|
||||
*/
|
||||
static void SetRuleValue(const char *key, double value) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Add a data file and a corresponding CRC32 checksum to the data file loadout
|
||||
* that connecting clients need to match.
|
||||
*
|
||||
* It can be used multiple times to set multiple checksums for the same data file.
|
||||
*
|
||||
* Note: If an empty string is provided for the checksum, a checksum will not be
|
||||
* required for that data file.
|
||||
*
|
||||
* @param dataFilename The filename of the data file.
|
||||
* @param checksumString A string with the CRC32 checksum required.
|
||||
*/
|
||||
static void AddDataFileRequirement(const char *dataFilename, const char *checksumString) noexcept;
|
||||
|
||||
// All methods below are deprecated versions of methods from above
|
||||
|
||||
static bool DoesFileExist(const char *filePath) noexcept;
|
||||
static const char *GetModDir() noexcept;
|
||||
static void AddPluginHash(const char *pluginName, const char *checksumString) noexcept;
|
||||
};
|
||||
|
||||
#endif //OPENMW_SERVERAPI_HPP
|
||||
|
|
|
@ -201,17 +201,6 @@ int StatsFunctions::GetAttributeModifier(unsigned short pid, unsigned short attr
|
|||
return player->creatureStats.mAttributes[attributeId].mMod;
|
||||
}
|
||||
|
||||
double StatsFunctions::GetAttributeDamage(unsigned short pid, unsigned short attributeId) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, 0);
|
||||
|
||||
if (attributeId >= Attribute::Length)
|
||||
return 0;
|
||||
|
||||
return player->creatureStats.mAttributes[attributeId].mDamage;
|
||||
}
|
||||
|
||||
int StatsFunctions::GetSkillBase(unsigned short pid, unsigned short skillId) noexcept
|
||||
{
|
||||
Player *player;
|
||||
|
@ -234,17 +223,6 @@ int StatsFunctions::GetSkillModifier(unsigned short pid, unsigned short skillId)
|
|||
return player->npcStats.mSkills[skillId].mMod;
|
||||
}
|
||||
|
||||
double StatsFunctions::GetSkillDamage(unsigned short pid, unsigned short skillId) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, 0);
|
||||
|
||||
if (skillId >= Skill::Length)
|
||||
return 0;
|
||||
|
||||
return player->npcStats.mSkills[skillId].mDamage;
|
||||
}
|
||||
|
||||
double StatsFunctions::GetSkillProgress(unsigned short pid, unsigned short skillId) noexcept
|
||||
{
|
||||
Player *player;
|
||||
|
@ -459,20 +437,6 @@ void StatsFunctions::ClearAttributeModifier(unsigned short pid, unsigned short a
|
|||
player->attributeIndexChanges.push_back(attributeId);
|
||||
}
|
||||
|
||||
void StatsFunctions::SetAttributeDamage(unsigned short pid, unsigned short attributeId, double value) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, );
|
||||
|
||||
if (attributeId >= Attribute::Length)
|
||||
return;
|
||||
|
||||
player->creatureStats.mAttributes[attributeId].mDamage = value;
|
||||
|
||||
if (!Utils::vectorContains(player->attributeIndexChanges, attributeId))
|
||||
player->attributeIndexChanges.push_back(attributeId);
|
||||
}
|
||||
|
||||
void StatsFunctions::SetSkillBase(unsigned short pid, unsigned short skillId, int value) noexcept
|
||||
{
|
||||
Player *player;
|
||||
|
@ -501,20 +465,6 @@ void StatsFunctions::ClearSkillModifier(unsigned short pid, unsigned short skill
|
|||
player->skillIndexChanges.push_back(skillId);
|
||||
}
|
||||
|
||||
void StatsFunctions::SetSkillDamage(unsigned short pid, unsigned short skillId, double value) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, );
|
||||
|
||||
if (skillId >= Skill::Length)
|
||||
return;
|
||||
|
||||
player->npcStats.mSkills[skillId].mDamage = value;
|
||||
|
||||
if (!Utils::vectorContains(player->skillIndexChanges, skillId))
|
||||
player->skillIndexChanges.push_back(skillId);
|
||||
}
|
||||
|
||||
void StatsFunctions::SetSkillProgress(unsigned short pid, unsigned short skillId, double value) noexcept
|
||||
{
|
||||
Player *player;
|
||||
|
|
|
@ -30,11 +30,9 @@
|
|||
\
|
||||
{"GetAttributeBase", StatsFunctions::GetAttributeBase},\
|
||||
{"GetAttributeModifier", StatsFunctions::GetAttributeModifier},\
|
||||
{"GetAttributeDamage", StatsFunctions::GetAttributeDamage},\
|
||||
\
|
||||
{"GetSkillBase", StatsFunctions::GetSkillBase},\
|
||||
{"GetSkillModifier", StatsFunctions::GetSkillModifier},\
|
||||
{"GetSkillDamage", StatsFunctions::GetSkillDamage},\
|
||||
{"GetSkillProgress", StatsFunctions::GetSkillProgress},\
|
||||
{"GetSkillIncrease", StatsFunctions::GetSkillIncrease},\
|
||||
\
|
||||
|
@ -60,11 +58,9 @@
|
|||
\
|
||||
{"SetAttributeBase", StatsFunctions::SetAttributeBase},\
|
||||
{"ClearAttributeModifier", StatsFunctions::ClearAttributeModifier},\
|
||||
{"SetAttributeDamage", StatsFunctions::SetAttributeDamage},\
|
||||
\
|
||||
{"SetSkillBase", StatsFunctions::SetSkillBase},\
|
||||
{"ClearSkillModifier", StatsFunctions::ClearSkillModifier},\
|
||||
{"SetSkillDamage", StatsFunctions::SetSkillDamage},\
|
||||
{"SetSkillProgress", StatsFunctions::SetSkillProgress},\
|
||||
{"SetSkillIncrease", StatsFunctions::SetSkillIncrease},\
|
||||
\
|
||||
|
@ -271,16 +267,6 @@ public:
|
|||
*/
|
||||
static int GetAttributeModifier(unsigned short pid, unsigned short attributeId) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the amount of damage (as caused through the Damage Attribute effect)
|
||||
* to a player's attribute.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \param attributeId The attribute ID.
|
||||
* \return The amount of damage to the attribute.
|
||||
*/
|
||||
static double GetAttributeDamage(unsigned short pid, unsigned short attributeId) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the base value of a player's skill.
|
||||
*
|
||||
|
@ -299,16 +285,6 @@ public:
|
|||
*/
|
||||
static int GetSkillModifier(unsigned short pid, unsigned short skillId) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the amount of damage (as caused through the Damage Skill effect)
|
||||
* to a player's skill.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \param skillId The skill ID.
|
||||
* \return The amount of damage to the skill.
|
||||
*/
|
||||
static double GetSkillDamage(unsigned short pid, unsigned short skillId) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the progress the player has made towards increasing a certain skill by 1.
|
||||
*
|
||||
|
@ -501,17 +477,6 @@ public:
|
|||
*/
|
||||
static void ClearAttributeModifier(unsigned short pid, unsigned short attributeId) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the amount of damage (as caused through the Damage Attribute effect) to
|
||||
* a player's attribute.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \param attributeId The attribute ID.
|
||||
* \param value The amount of damage to the player's attribute.
|
||||
* \return void
|
||||
*/
|
||||
static void SetAttributeDamage(unsigned short pid, unsigned short attributeId, double value) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the base value of a player's skill.
|
||||
*
|
||||
|
@ -536,17 +501,6 @@ public:
|
|||
*/
|
||||
static void ClearSkillModifier(unsigned short pid, unsigned short skillId) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the amount of damage (as caused through the Damage Skill effect) to
|
||||
* a player's skill.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \param skillId The skill ID.
|
||||
* \param value The amount of damage to the player's skill.
|
||||
* \return void
|
||||
*/
|
||||
static void SetSkillDamage(unsigned short pid, unsigned short skillId, double value) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the progress the player has made towards increasing a certain skill by 1.
|
||||
*
|
||||
|
|
|
@ -21,7 +21,7 @@ int ScriptFunctions::CreateTimerEx(ScriptFunc callback, int msec, const char *ty
|
|||
try
|
||||
{
|
||||
vector<boost::any> params;
|
||||
Utils::getArguments(params, args, types);
|
||||
GetArguments(params, args, types);
|
||||
|
||||
return mwmp::TimerAPI::CreateTimer(callback, msec, types, params);
|
||||
}
|
||||
|
@ -54,5 +54,5 @@ void ScriptFunctions::FreeTimer(int timerId) noexcept
|
|||
|
||||
bool ScriptFunctions::IsTimerElapsed(int timerId) noexcept
|
||||
{
|
||||
return TimerAPI::IsTimerElapsed(timerId);
|
||||
return TimerAPI::IsEndTimer(timerId);
|
||||
}
|
||||
|
|
|
@ -9,24 +9,6 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
std::set<std::string> LangLua::packagePath;
|
||||
std::set<std::string> LangLua::packageCPath;
|
||||
|
||||
void setLuaPath(lua_State* L, const char* path, bool cpath = false)
|
||||
{
|
||||
string field = cpath ? "cpath" : "path";
|
||||
lua_getglobal(L, "package");
|
||||
|
||||
lua_getfield(L, -1, field.c_str());
|
||||
std::string cur_path = lua_tostring(L, -1);
|
||||
cur_path.append(";");
|
||||
cur_path.append(path);
|
||||
lua_pop(L, 1);
|
||||
lua_pushstring(L, cur_path.c_str());
|
||||
lua_setfield(L, -2, field.c_str());
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
lib_t LangLua::GetInterface()
|
||||
{
|
||||
return reinterpret_cast<lib_t>(lua);
|
||||
|
@ -41,17 +23,6 @@ LangLua::LangLua()
|
|||
{
|
||||
lua = luaL_newstate();
|
||||
luaL_openlibs(lua); // load all lua std libs
|
||||
|
||||
std::string p, cp;
|
||||
for (auto& path : packagePath)
|
||||
p += path + ';';
|
||||
|
||||
for (auto& path : packageCPath)
|
||||
cp += path + ';';
|
||||
|
||||
setLuaPath(lua, p.c_str());
|
||||
setLuaPath(lua, cp.c_str(), true);
|
||||
|
||||
}
|
||||
|
||||
LangLua::~LangLua()
|
||||
|
@ -107,18 +78,8 @@ template<> struct F_<1> { static constexpr LuaFuctionData F{"CreateTimerEx", Lan
|
|||
template<> struct F_<2> { static constexpr LuaFuctionData F{"MakePublic", LangLua::MakePublic}; };
|
||||
template<> struct F_<3> { static constexpr LuaFuctionData F{"CallPublic", LangLua::CallPublic}; };
|
||||
|
||||
#ifdef __arm__
|
||||
template<std::size_t... Is>
|
||||
struct indices {};
|
||||
template<std::size_t N, std::size_t... Is>
|
||||
struct build_indices : build_indices<N-1, N-1, Is...> {};
|
||||
template<std::size_t... Is>
|
||||
struct build_indices<0, Is...> : indices<Is...> {};
|
||||
template<std::size_t N>
|
||||
using IndicesFor = build_indices<N>;
|
||||
|
||||
template<size_t... Indices>
|
||||
LuaFuctionData *functions(indices<Indices...>)
|
||||
inline LuaFuctionData *LangLua::functions(indices<Indices...>)
|
||||
{
|
||||
|
||||
static LuaFuctionData functions_[sizeof...(Indices)]{
|
||||
|
@ -132,41 +93,6 @@ LuaFuctionData *functions(indices<Indices...>)
|
|||
|
||||
return functions_;
|
||||
}
|
||||
#else
|
||||
template<unsigned int I>
|
||||
struct C
|
||||
{
|
||||
constexpr static void Fn(LuaFuctionData *functions_)
|
||||
{
|
||||
functions_[I] = F_<I>::F;
|
||||
C<I - 1>::Fn(functions_);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct C<0>
|
||||
{
|
||||
constexpr static void Fn(LuaFuctionData *functions_)
|
||||
{
|
||||
functions_[0] = F_<0>::F;
|
||||
}
|
||||
};
|
||||
|
||||
template<size_t LastI>
|
||||
LuaFuctionData *functions()
|
||||
{
|
||||
|
||||
static LuaFuctionData functions_[LastI];
|
||||
C<LastI - 1>::Fn(functions_);
|
||||
|
||||
static_assert(
|
||||
sizeof(functions_) / sizeof(functions_[0]) ==
|
||||
sizeof(ScriptFunctions::functions) / sizeof(ScriptFunctions::functions[0]),
|
||||
"Not all functions have been mapped to Lua");
|
||||
|
||||
return functions_;
|
||||
}
|
||||
#endif
|
||||
|
||||
void LangLua::LoadProgram(const char *filename)
|
||||
{
|
||||
|
@ -178,11 +104,8 @@ void LangLua::LoadProgram(const char *filename)
|
|||
|
||||
constexpr auto functions_n = sizeof(ScriptFunctions::functions) / sizeof(ScriptFunctions::functions[0]);
|
||||
|
||||
#if __arm__
|
||||
LuaFuctionData *functions_ = functions(IndicesFor<functions_n>{});
|
||||
#else
|
||||
LuaFuctionData *functions_ = functions<sizeof(ScriptFunctions::functions) / sizeof(ScriptFunctions::functions[0])>();
|
||||
#endif
|
||||
|
||||
luabridge::Namespace tes3mp = luabridge::getGlobalNamespace(lua).beginNamespace("tes3mp");
|
||||
|
||||
for (unsigned i = 0; i < functions_n; i++)
|
||||
|
@ -210,65 +133,20 @@ boost::any LangLua::Call(const char *name, const char *argl, int buf, ...)
|
|||
{
|
||||
va_list vargs;
|
||||
va_start(vargs, buf);
|
||||
std::vector<boost::any> args;
|
||||
|
||||
int n_args = (int)(strlen(argl));
|
||||
ScriptFunctions::GetArguments(args, vargs, argl);
|
||||
|
||||
lua_getglobal(lua, name);
|
||||
|
||||
for (int index = 0; index < n_args; index++)
|
||||
{
|
||||
switch (argl[index])
|
||||
{
|
||||
case 'i':
|
||||
luabridge::Stack<unsigned int>::push(lua,va_arg(vargs, unsigned int));
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
luabridge::Stack<signed int>::push(lua,va_arg(vargs, signed int));
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
luabridge::Stack<unsigned long long>::push(lua, va_arg(vargs, unsigned long long));
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
luabridge::Stack<signed long long>::push(lua, va_arg(vargs, signed long long));
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
luabridge::Stack<double>::push(lua, va_arg(vargs, double));
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
luabridge::Stack<void*>::push(lua, va_arg(vargs, void*));
|
||||
break;
|
||||
|
||||
case 's':
|
||||
luabridge::Stack<const char*>::push(lua, va_arg(vargs, const char*));
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
luabridge::Stack<bool>::push(lua, (bool) va_arg(vargs, int));
|
||||
break;
|
||||
|
||||
default:
|
||||
throw runtime_error("C++ call: Unknown argument identifier " + argl[index]);
|
||||
}
|
||||
}
|
||||
|
||||
va_end(vargs);
|
||||
|
||||
luabridge::LuaException::pcall(lua, n_args, 1);
|
||||
return boost::any(luabridge::LuaRef::fromStack(lua, -1));
|
||||
return Call(name, argl, args);
|
||||
}
|
||||
|
||||
boost::any LangLua::Call(const char *name, const char *argl, const std::vector<boost::any> &args)
|
||||
{
|
||||
int n_args = (int)(strlen(argl));
|
||||
int n_args = (int)(strlen(argl)) ;
|
||||
|
||||
lua_getglobal(lua, name);
|
||||
lua_getglobal (lua, name);
|
||||
|
||||
for (int index = 0; index < n_args; index++)
|
||||
for (intptr_t index = 0; index < n_args; index++)
|
||||
{
|
||||
switch (argl[index])
|
||||
{
|
||||
|
@ -308,16 +186,6 @@ boost::any LangLua::Call(const char *name, const char *argl, const std::vector<b
|
|||
}
|
||||
}
|
||||
|
||||
luabridge::LuaException::pcall(lua, n_args, 1);
|
||||
luabridge::LuaException::pcall (lua, n_args, 1);
|
||||
return boost::any(luabridge::LuaRef::fromStack(lua, -1));
|
||||
}
|
||||
|
||||
void LangLua::AddPackagePath(const std::string& path)
|
||||
{
|
||||
packagePath.emplace(path);
|
||||
}
|
||||
|
||||
void LangLua::AddPackageCPath(const std::string& path)
|
||||
{
|
||||
packageCPath.emplace(path);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#include <extern/LuaBridge/LuaBridge.h>
|
||||
#include <LuaBridge.h>
|
||||
#include <set>
|
||||
|
||||
#include <boost/any.hpp>
|
||||
#include "../ScriptFunction.hpp"
|
||||
|
@ -23,17 +22,25 @@ struct LuaFuctionData
|
|||
|
||||
class LangLua: public Language
|
||||
{
|
||||
private:
|
||||
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>;
|
||||
|
||||
public:
|
||||
virtual lib_t GetInterface() override;
|
||||
template<std::size_t... Indices>
|
||||
static LuaFuctionData* functions(indices<Indices...>);
|
||||
lua_State *lua;
|
||||
public:
|
||||
LangLua();
|
||||
LangLua(lua_State *lua);
|
||||
~LangLua();
|
||||
|
||||
static void AddPackagePath(const std::string &path);
|
||||
static void AddPackageCPath(const std::string &path);
|
||||
|
||||
static int MakePublic(lua_State *lua) noexcept;
|
||||
static int CallPublic(lua_State *lua);
|
||||
|
||||
|
@ -45,9 +52,6 @@ public:
|
|||
virtual bool IsCallbackPresent(const char *name) override;
|
||||
virtual boost::any Call(const char *name, const char *argl, int buf, ...) override;
|
||||
virtual boost::any Call(const char *name, const char *argl, const std::vector<boost::any> &args) override;
|
||||
private:
|
||||
static std::set<std::string> packageCPath;
|
||||
static std::set<std::string> packagePath;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
using namespace std;
|
||||
|
||||
Script::ScriptList Script::scripts;
|
||||
std::string Script::moddir;
|
||||
|
||||
Script::Script(const char *path)
|
||||
{
|
||||
|
@ -95,14 +94,3 @@ void Script::LoadScript(const char *script, const char *base)
|
|||
snprintf(path, sizeof(path), Utils::convertPath("%s/%s/%s").c_str(), base, "scripts", script);
|
||||
Script::scripts.emplace_back(new Script(path));
|
||||
}
|
||||
|
||||
void Script::SetModDir(const std::string &moddir)
|
||||
{
|
||||
if (Script::moddir.empty()) // do not allow to change in runtime
|
||||
Script::moddir = moddir;
|
||||
}
|
||||
|
||||
const char* Script::GetModDir()
|
||||
{
|
||||
return moddir.c_str();
|
||||
}
|
||||
|
|
|
@ -4,18 +4,15 @@
|
|||
|
||||
#ifndef PLUGINSYSTEM3_SCRIPT_HPP
|
||||
#define PLUGINSYSTEM3_SCRIPT_HPP
|
||||
|
||||
#include <boost/any.hpp>
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
|
||||
#include "Types.hpp"
|
||||
#include "SystemInterface.hpp"
|
||||
#include "ScriptFunction.hpp"
|
||||
#include "ScriptFunctions.hpp"
|
||||
#include "Language.hpp"
|
||||
|
||||
#include "Networking.hpp"
|
||||
#include <boost/any.hpp>
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
|
||||
class Script : private ScriptFunctions
|
||||
{
|
||||
|
@ -54,27 +51,60 @@ private:
|
|||
Script(const Script&) = delete;
|
||||
Script& operator=(const Script&) = delete;
|
||||
|
||||
protected:
|
||||
static std::string moddir;
|
||||
public:
|
||||
~Script();
|
||||
|
||||
static void LoadScript(const char *script, const char* base);
|
||||
static void LoadScripts(char* scripts, const char* base);
|
||||
static void UnloadScripts();
|
||||
static void SetModDir(const std::string &moddir);
|
||||
static const char* GetModDir();
|
||||
|
||||
static constexpr ScriptCallbackData const& CallBackData(const unsigned int I, const unsigned int N = 0) {
|
||||
return callbacks[N].index == I ? callbacks[N] : CallBackData(I, N + 1);
|
||||
}
|
||||
|
||||
template<unsigned int I>
|
||||
using CallBackReturn = typename CharType<CallBackData(I).callback.ret>::type;
|
||||
|
||||
template<size_t N>
|
||||
static constexpr unsigned int CallbackIdentity(const char(&str)[N])
|
||||
{
|
||||
return Utils::hash(str);
|
||||
}
|
||||
|
||||
|
||||
template<unsigned int I, bool B = false, typename... Args>
|
||||
static unsigned int Call(CallBackReturn<I>& result, Args&&... args) {
|
||||
constexpr ScriptCallbackData const& data = CallBackData(I);
|
||||
static_assert(data.callback.matches(TypeString<typename std::remove_reference<Args>::type...>::value),
|
||||
"Wrong number or types of arguments");
|
||||
|
||||
unsigned int count = 0;
|
||||
|
||||
for (auto& script : scripts)
|
||||
{
|
||||
if (!script->callbacks_.count(I))
|
||||
script->callbacks_.emplace(I, script->GetScript<FunctionEllipsis<void>>(data.name));
|
||||
|
||||
auto callback = script->callbacks_[I];
|
||||
|
||||
if (!callback)
|
||||
continue;
|
||||
|
||||
if (script->script_type == SCRIPT_CPP)
|
||||
result = reinterpret_cast<FunctionEllipsis<CallBackReturn<I>>>(callback)(std::forward<Args>(args)...);
|
||||
#if defined (ENABLE_LUA)
|
||||
else if (script->script_type == SCRIPT_LUA)
|
||||
{
|
||||
boost::any any = script->lang->Call(data.name, data.callback.types, B, std::forward<Args>(args)...);
|
||||
result = static_cast<CallBackReturn<I>>(boost::any_cast<luabridge::LuaRef>(any).cast<CallBackReturn<I>>());
|
||||
}
|
||||
#endif
|
||||
++count;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
template<unsigned int I, bool B = false, typename... Args>
|
||||
static unsigned int Call(Args&&... args) {
|
||||
constexpr ScriptCallbackData const& data = CallBackData(I);
|
||||
|
@ -94,23 +124,10 @@ public:
|
|||
continue;
|
||||
|
||||
if (script->script_type == SCRIPT_CPP)
|
||||
(callback)(std::forward<Args>(args)...);
|
||||
reinterpret_cast<FunctionEllipsis<CallBackReturn<I>>>(callback)(std::forward<Args>(args)...);
|
||||
#if defined (ENABLE_LUA)
|
||||
else if (script->script_type == SCRIPT_LUA)
|
||||
{
|
||||
try
|
||||
{
|
||||
script->lang->Call(data.name, data.callback.types, B, std::forward<Args>(args)...);
|
||||
}
|
||||
catch (std::exception &e)
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, e.what());
|
||||
Script::Call<Script::CallbackIdentity("OnServerScriptCrash")>(e.what());
|
||||
|
||||
if (!mwmp::Networking::getPtr()->getScriptErrorIgnoringState())
|
||||
throw;
|
||||
}
|
||||
}
|
||||
script->lang->Call(data.name, data.callback.types, B, std::forward<Args>(args)...);
|
||||
#endif
|
||||
++count;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
#include <stdexcept>
|
||||
#include "ScriptFunction.hpp"
|
||||
|
||||
#if !defined(_WIN32) && !defined(__ARM_ARCH) // temporarily disabled
|
||||
#include <call.hpp>
|
||||
#endif
|
||||
|
||||
#if defined (ENABLE_LUA)
|
||||
#include "LangLua/LangLua.hpp"
|
||||
#endif
|
||||
|
@ -68,6 +72,46 @@ boost::any ScriptFunction::Call(const vector<boost::any> &args)
|
|||
}
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
#if !defined(_WIN32) && !defined(__ARM_ARCH) // temporarily disabled
|
||||
string::iterator it;
|
||||
vector<boost::any>::const_iterator it2;
|
||||
vector<intptr_t> data;
|
||||
CallArgs callArgs;
|
||||
|
||||
for (it = def.begin(), it2 = args.begin(); it != def.end(); ++it, ++it2)
|
||||
{
|
||||
switch (*it)
|
||||
{
|
||||
case 'i':
|
||||
callArgs.push_integer(boost::any_cast<unsigned int>(*it2));
|
||||
break;
|
||||
case 'q':
|
||||
callArgs.push_integer(boost::any_cast<signed int>(*it2));
|
||||
break;
|
||||
case 'f':
|
||||
callArgs.push_double(boost::any_cast<double>(*it2));
|
||||
break;
|
||||
case 'd':
|
||||
callArgs.push_double(boost::any_cast<double*>(*it2));
|
||||
break;
|
||||
case 's':
|
||||
callArgs.push_stringPtr(boost::any_cast<const char *>(*it2));
|
||||
break;
|
||||
case 'v':
|
||||
result = boost::any();
|
||||
break;
|
||||
default:
|
||||
throw runtime_error("C++ call: Unknown argument identifier " + *it);
|
||||
}
|
||||
}
|
||||
Func f = reinterpret_cast<Func>(fCpp);
|
||||
result = ::Call(f, callArgs);
|
||||
#else
|
||||
throw runtime_error("C++ call: Windows and ARM not supported yet.");
|
||||
#endif
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,62 @@ constexpr ScriptCallbackData ScriptFunctions::callbacks[];
|
|||
|
||||
using namespace std;
|
||||
|
||||
void ScriptFunctions::GetArguments(std::vector<boost::any> ¶ms, va_list args, const std::string &def)
|
||||
{
|
||||
params.reserve(def.length());
|
||||
|
||||
try
|
||||
{
|
||||
for (char c : def)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'i':
|
||||
params.emplace_back(va_arg(args, unsigned int));
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
params.emplace_back(va_arg(args, signed int));
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
params.emplace_back(va_arg(args, unsigned long long));
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
params.emplace_back(va_arg(args, signed long long));
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
params.emplace_back(va_arg(args, double));
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
params.emplace_back(va_arg(args, void*));
|
||||
break;
|
||||
|
||||
case 's':
|
||||
params.emplace_back(va_arg(args, const char*));
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
params.emplace_back(va_arg(args, int));
|
||||
break;
|
||||
|
||||
default:
|
||||
throw runtime_error("C++ call: Unknown argument identifier " + c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
catch (...)
|
||||
{
|
||||
va_end(args);
|
||||
throw;
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void ScriptFunctions::MakePublic(ScriptFunc _public, const char *name, char ret_type, const char *def) noexcept
|
||||
{
|
||||
Public::MakePublic(_public, name, ret_type, def);
|
||||
|
@ -25,7 +81,7 @@ boost::any ScriptFunctions::CallPublic(const char *name, va_list args) noexcept
|
|||
try
|
||||
{
|
||||
string def = Public::GetDefinition(name);
|
||||
Utils::getArguments(params, args, def);
|
||||
GetArguments(params, args, def);
|
||||
|
||||
return Public::Call(name, params);
|
||||
}
|
||||
|
|
|
@ -30,10 +30,6 @@
|
|||
|
||||
#include <components/openmw-mp/Log.hpp>
|
||||
|
||||
#ifndef __PRETTY_FUNCTION__
|
||||
#define __PRETTY_FUNCTION__ __FUNCTION__
|
||||
#endif
|
||||
|
||||
#define GET_PLAYER(pid, pl, retvalue) \
|
||||
pl = Players::getPlayer(pid); \
|
||||
if (player == 0) {\
|
||||
|
@ -47,6 +43,7 @@ class ScriptFunctions
|
|||
{
|
||||
public:
|
||||
|
||||
static void GetArguments(std::vector<boost::any> ¶ms, va_list args, const std::string &def);
|
||||
static void MakePublic(ScriptFunc _public, const char *name, char ret_type, const char *def) noexcept;
|
||||
static boost::any CallPublic(const char *name, va_list args) noexcept;
|
||||
|
||||
|
@ -119,9 +116,9 @@ public:
|
|||
|
||||
static constexpr ScriptFunctionData functions[]{
|
||||
{"CreateTimer", ScriptFunctions::CreateTimer},
|
||||
{"CreateTimerEx", ScriptFunctions::CreateTimerEx},
|
||||
{"CreateTimerEx", reinterpret_cast<Function<void>>(ScriptFunctions::CreateTimerEx)},
|
||||
{"MakePublic", ScriptFunctions::MakePublic},
|
||||
{"CallPublic", ScriptFunctions::CallPublic},
|
||||
{"CallPublic", reinterpret_cast<Function<void>>(ScriptFunctions::CallPublic)},
|
||||
|
||||
{"StartTimer", ScriptFunctions::StartTimer},
|
||||
{"StopTimer", ScriptFunctions::StopTimer},
|
||||
|
@ -153,63 +150,63 @@ public:
|
|||
};
|
||||
|
||||
static constexpr ScriptCallbackData callbacks[]{
|
||||
{"OnServerInit", Callback<>()},
|
||||
{"OnServerPostInit", Callback<>()},
|
||||
{"OnServerExit", Callback<bool>()},
|
||||
{"OnServerScriptCrash", Callback<const char*>()},
|
||||
{"OnPlayerConnect", Callback<unsigned short>()},
|
||||
{"OnPlayerDisconnect", Callback<unsigned short>()},
|
||||
{"OnPlayerDeath", Callback<unsigned short>()},
|
||||
{"OnPlayerResurrect", Callback<unsigned short>()},
|
||||
{"OnPlayerCellChange", Callback<unsigned short>()},
|
||||
{"OnPlayerAttribute", Callback<unsigned short>()},
|
||||
{"OnPlayerSkill", Callback<unsigned short>()},
|
||||
{"OnPlayerLevel", Callback<unsigned short>()},
|
||||
{"OnPlayerBounty", Callback<unsigned short>()},
|
||||
{"OnPlayerReputation", Callback<unsigned short>()},
|
||||
{"OnPlayerEquipment", Callback<unsigned short>()},
|
||||
{"OnPlayerInventory", Callback<unsigned short>()},
|
||||
{"OnPlayerJournal", Callback<unsigned short>()},
|
||||
{"OnPlayerFaction", Callback<unsigned short>()},
|
||||
{"OnPlayerShapeshift", Callback<unsigned short>()},
|
||||
{"OnPlayerSpellbook", Callback<unsigned short>()},
|
||||
{"OnPlayerQuickKeys", Callback<unsigned short>()},
|
||||
{"OnPlayerTopic", Callback<unsigned short>()},
|
||||
{"OnPlayerDisposition", Callback<unsigned short>()},
|
||||
{"OnPlayerBook", Callback<unsigned short>()},
|
||||
{"OnPlayerItemUse", Callback<unsigned short>()},
|
||||
{"OnPlayerMiscellaneous", Callback<unsigned short>()},
|
||||
{"OnPlayerInput", Callback<unsigned short>()},
|
||||
{"OnPlayerRest", Callback<unsigned short>()},
|
||||
{"OnRecordDynamic", Callback<unsigned short>()},
|
||||
{"OnCellLoad", Callback<unsigned short, const char*>()},
|
||||
{"OnCellUnload", Callback<unsigned short, const char*>()},
|
||||
{"OnCellDeletion", Callback<const char*>()},
|
||||
{"OnContainer", Callback<unsigned short, const char*>()},
|
||||
{"OnDoorState", Callback<unsigned short, const char*>()},
|
||||
{"OnObjectActivate", Callback<unsigned short, const char*>()},
|
||||
{"OnObjectPlace", Callback<unsigned short, const char*>()},
|
||||
{"OnObjectState", Callback<unsigned short, const char*>()},
|
||||
{"OnObjectSpawn", Callback<unsigned short, const char*>()},
|
||||
{"OnObjectDelete", Callback<unsigned short, const char*>()},
|
||||
{"OnObjectLock", Callback<unsigned short, const char*>()},
|
||||
{"OnObjectScale", Callback<unsigned short, const char*>()},
|
||||
{"OnObjectTrap", Callback<unsigned short, const char*>()},
|
||||
{"OnVideoPlay", Callback<unsigned short, const char*>()},
|
||||
{"OnActorList", Callback<unsigned short, const char*>()},
|
||||
{"OnActorEquipment", Callback<unsigned short, const char*>()},
|
||||
{"OnActorAI", Callback<unsigned short, const char*>()},
|
||||
{"OnActorDeath", Callback<unsigned short, const char*>()},
|
||||
{"OnActorCellChange", Callback<unsigned short, const char*>()},
|
||||
{"OnActorTest", Callback<unsigned short, const char*>()},
|
||||
{"OnPlayerSendMessage", Callback<unsigned short, const char*>()},
|
||||
{"OnPlayerEndCharGen", Callback<unsigned short>()},
|
||||
{"OnGUIAction", Callback<unsigned short, int, const char*>()},
|
||||
{"OnWorldKillCount", Callback<unsigned short>()},
|
||||
{"OnWorldMap", Callback<unsigned short>()},
|
||||
{"OnWorldWeather", Callback<unsigned short>() },
|
||||
{"OnMpNumIncrement", Callback<int>()},
|
||||
{"OnRequestDataFileList", Callback<>()}
|
||||
{"Main", Function<int, int, int>()},
|
||||
{"OnServerInit", Function<void>()},
|
||||
{"OnServerPostInit", Function<void>()},
|
||||
{"OnServerExit", Function<void, bool>()},
|
||||
{"OnPlayerConnect", Function<bool, unsigned short>()},
|
||||
{"OnPlayerDisconnect", Function<void, unsigned short>()},
|
||||
{"OnPlayerDeath", Function<void, unsigned short>()},
|
||||
{"OnPlayerResurrect", Function<void, unsigned short>()},
|
||||
{"OnPlayerCellChange", Function<void, unsigned short>()},
|
||||
{"OnPlayerAttribute", Function<void, unsigned short>()},
|
||||
{"OnPlayerSkill", Function<void, unsigned short>()},
|
||||
{"OnPlayerLevel", Function<void, unsigned short>()},
|
||||
{"OnPlayerBounty", Function<void, unsigned short>()},
|
||||
{"OnPlayerReputation", Function<void, unsigned short>()},
|
||||
{"OnPlayerEquipment", Function<void, unsigned short>()},
|
||||
{"OnPlayerInventory", Function<void, unsigned short>()},
|
||||
{"OnPlayerJournal", Function<void, unsigned short>()},
|
||||
{"OnPlayerFaction", Function<void, unsigned short>()},
|
||||
{"OnPlayerShapeshift", Function<void, unsigned short>()},
|
||||
{"OnPlayerSpellbook", Function<void, unsigned short>()},
|
||||
{"OnPlayerQuickKeys", Function<void, unsigned short>()},
|
||||
{"OnPlayerTopic", Function<void, unsigned short>()},
|
||||
{"OnPlayerDisposition", Function<void, unsigned short>()},
|
||||
{"OnPlayerBook", Function<void, unsigned short>()},
|
||||
{"OnPlayerItemUse", Function<void, unsigned short>()},
|
||||
{"OnPlayerMiscellaneous", Function<void, unsigned short>()},
|
||||
{"OnPlayerInput", Function<void, unsigned short>()},
|
||||
{"OnPlayerRest", Function<void, unsigned short>()},
|
||||
{"OnRecordDynamic", Function<void, unsigned short>()},
|
||||
{"OnCellLoad", Function<void, unsigned short, const char*>()},
|
||||
{"OnCellUnload", Function<void, unsigned short, const char*>()},
|
||||
{"OnCellDeletion", Function<void, const char*>()},
|
||||
{"OnContainer", Function<void, unsigned short, const char*>()},
|
||||
{"OnDoorState", Function<void, unsigned short, const char*>()},
|
||||
{"OnObjectActivate", Function<void, unsigned short, const char*>()},
|
||||
{"OnObjectPlace", Function<void, unsigned short, const char*>()},
|
||||
{"OnObjectState", Function<void, unsigned short, const char*>()},
|
||||
{"OnObjectSpawn", Function<void, unsigned short, const char*>()},
|
||||
{"OnObjectDelete", Function<void, unsigned short, const char*>()},
|
||||
{"OnObjectLock", Function<void, unsigned short, const char*>()},
|
||||
{"OnObjectScale", Function<void, unsigned short, const char*>()},
|
||||
{"OnObjectTrap", Function<void, unsigned short, const char*>()},
|
||||
{"OnVideoPlay", Function<void, unsigned short, const char*>()},
|
||||
{"OnActorList", Function<void, unsigned short, const char*>()},
|
||||
{"OnActorEquipment", Function<void, unsigned short, const char*>()},
|
||||
{"OnActorAI", Function<void, unsigned short, const char*>()},
|
||||
{"OnActorDeath", Function<void, unsigned short, const char*>()},
|
||||
{"OnActorCellChange", Function<void, unsigned short, const char*>()},
|
||||
{"OnActorTest", Function<void, unsigned short, const char*>()},
|
||||
{"OnPlayerSendMessage", Function<bool, unsigned short, const char*>()},
|
||||
{"OnPlayerEndCharGen", Function<void, unsigned short>()},
|
||||
{"OnGUIAction", Function<void, unsigned short, int, const char*>()},
|
||||
{"OnWorldKillCount", Function<void, unsigned short>()},
|
||||
{"OnWorldMap", Function<void, unsigned short>()},
|
||||
{"OnWorldWeather", Function<void, unsigned short>() },
|
||||
{"OnMpNumIncrement", Function<void, int>()},
|
||||
{"OnRequestPluginList", Function<const char *, unsigned int, unsigned int>()}
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -82,34 +82,14 @@ struct ScriptIdentity
|
|||
constexpr ScriptIdentity(Function<R, Types...>) : types(TypeString<Types...>::value), ret(TypeChar<R, sizeof_void<R>::value>::value), numargs(sizeof(TypeString<Types...>::value) - 1) {}
|
||||
};
|
||||
|
||||
template<typename... Types>
|
||||
using Callback = void (*)(Types...);
|
||||
|
||||
struct CallbackIdentity
|
||||
{
|
||||
const char* types;
|
||||
const unsigned int numargs;
|
||||
|
||||
constexpr bool matches(const char* types, const unsigned int N = 0) const
|
||||
{
|
||||
return N < numargs ? this->types[N] == types[N] && matches(types, N + 1) : this->types[N] == types[N];
|
||||
}
|
||||
|
||||
template<typename... Types>
|
||||
constexpr CallbackIdentity(Callback<Types...>) : types(TypeString<Types...>::value), numargs(sizeof(TypeString<Types...>::value) - 1) {}
|
||||
};
|
||||
|
||||
|
||||
struct ScriptFunctionPointer : public ScriptIdentity
|
||||
{
|
||||
void *addr;
|
||||
#if (!defined(__clang__) && defined(__GNUC__))
|
||||
Function<void> addr;
|
||||
|
||||
template<typename R, typename... Types>
|
||||
constexpr ScriptFunctionPointer(Function<R, Types...> addr) : ScriptIdentity(addr), addr((void*)(addr)) {}
|
||||
#else
|
||||
template<typename R, typename... Types>
|
||||
constexpr ScriptFunctionPointer(Function<R, Types...> addr) : ScriptIdentity(addr), addr(addr) {}
|
||||
#endif
|
||||
constexpr ScriptFunctionPointer(Function<R, Types...> addr) : ScriptIdentity(addr), addr(reinterpret_cast<Function<void>>(addr)) {}
|
||||
};
|
||||
|
||||
struct ScriptFunctionData
|
||||
|
@ -124,10 +104,10 @@ struct ScriptCallbackData
|
|||
{
|
||||
const char* name;
|
||||
const unsigned int index;
|
||||
const CallbackIdentity callback;
|
||||
const ScriptIdentity callback;
|
||||
|
||||
template<size_t N>
|
||||
constexpr ScriptCallbackData(const char(&name)[N], CallbackIdentity _callback) : name(name), index(Utils::hash(name)), callback(_callback) {}
|
||||
constexpr ScriptCallbackData(const char(&name)[N], ScriptIdentity _callback) : name(name), index(Utils::hash(name)), callback(_callback) {}
|
||||
};
|
||||
|
||||
#endif //TMPTYPES_HPP
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#include "Utils.hpp"
|
||||
//
|
||||
// Created by koncord on 04.03.17.
|
||||
//
|
||||
|
||||
#include <cstdarg>
|
||||
#include "Utils.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -50,59 +52,3 @@ ESM::Cell Utils::getCellFromDescription(std::string cellDescription)
|
|||
|
||||
return cell;
|
||||
}
|
||||
|
||||
void Utils::getArguments(std::vector<boost::any> ¶ms, va_list args, const std::string &def)
|
||||
{
|
||||
params.reserve(def.length());
|
||||
|
||||
try
|
||||
{
|
||||
for (char c : def)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'i':
|
||||
params.emplace_back(va_arg(args, unsigned int));
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
params.emplace_back(va_arg(args, signed int));
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
params.emplace_back(va_arg(args, unsigned long long));
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
params.emplace_back(va_arg(args, signed long long));
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
params.emplace_back(va_arg(args, double));
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
params.emplace_back(va_arg(args, void*));
|
||||
break;
|
||||
|
||||
case 's':
|
||||
params.emplace_back(va_arg(args, const char*));
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
params.emplace_back(va_arg(args, int));
|
||||
break;
|
||||
|
||||
default:
|
||||
throw runtime_error("C++ call: Unknown argument identifier " + c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
catch (...)
|
||||
{
|
||||
va_end(args);
|
||||
throw;
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
//
|
||||
// Created by koncord on 04.03.17.
|
||||
//
|
||||
|
||||
#ifndef OPENMW_UTILS_HPP
|
||||
#define OPENMW_UTILS_HPP
|
||||
|
||||
|
@ -5,8 +9,6 @@
|
|||
#include <regex>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/any.hpp>
|
||||
|
||||
#include <components/esm/loadcell.hpp>
|
||||
|
||||
#include <components/openmw-mp/Utils.hpp>
|
||||
|
@ -25,8 +27,6 @@ namespace Utils
|
|||
|
||||
ESM::Cell getCellFromDescription(std::string cellDescription);
|
||||
|
||||
void getArguments(std::vector<boost::any> ¶ms, va_list args, const std::string &def);
|
||||
|
||||
template<size_t N>
|
||||
constexpr unsigned int hash(const char(&str)[N], size_t I = N)
|
||||
{
|
||||
|
|
|
@ -190,29 +190,48 @@ int main(int argc, char *argv[])
|
|||
LOG_INIT(logLevel);
|
||||
|
||||
int players = mgr.getInt("maximumPlayers", "General");
|
||||
string address = mgr.getString("localAddress", "General");
|
||||
string addr = mgr.getString("localAddress", "General");
|
||||
int port = mgr.getInt("port", "General");
|
||||
|
||||
string password = mgr.getString("password", "General");
|
||||
string passw = mgr.getString("password", "General");
|
||||
|
||||
string pluginHome = mgr.getString("home", "Plugins");
|
||||
string dataDirectory = Utils::convertPath(pluginHome + "/data");
|
||||
string plugin_home = mgr.getString("home", "Plugins");
|
||||
string moddir = Utils::convertPath(plugin_home + "/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);
|
||||
|
||||
Script::SetModDir(dataDirectory);
|
||||
|
||||
#ifdef ENABLE_LUA
|
||||
LangLua::AddPackagePath(Utils::convertPath(pluginHome + "/scripts/?.lua" + ";"
|
||||
+ pluginHome + "/lib/lua/?.lua" + ";"));
|
||||
// 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;
|
||||
}
|
||||
|
||||
setenv("MOD_DIR", moddir.c_str(), 1); // hack for lua
|
||||
|
||||
setenv("LUA_PATH", Utils::convertPath(plugin_home + "/scripts/?.lua" + ";"
|
||||
+ plugin_home + "/scripts/?.t" + ";"
|
||||
+ plugin_home + "/lib/lua/?.lua" + ";"
|
||||
+ plugin_home + "/lib/lua/?.t").c_str(), 1);
|
||||
#ifdef _WIN32
|
||||
LangLua::AddPackageCPath(Utils::convertPath(pluginHome + "/lib/?.dll"));
|
||||
setenv("LUA_CPATH", Utils::convertPath(plugin_home + "/lib/?.dll").c_str(), 1);
|
||||
#else
|
||||
LangLua::AddPackageCPath(Utils::convertPath(pluginHome + "/lib/?.so"));
|
||||
#endif
|
||||
|
||||
setenv("LUA_CPATH", Utils::convertPath(plugin_home + "/lib/?.so").c_str(), 1);
|
||||
#endif
|
||||
|
||||
int code;
|
||||
|
@ -226,18 +245,18 @@ int main(int argc, char *argv[])
|
|||
|
||||
peer->SetIncomingPassword(sstr.str().c_str(), (int) sstr.str().size());
|
||||
|
||||
if (RakNet::NonNumericHostString(address.c_str()))
|
||||
if (RakNet::NonNumericHostString(addr.c_str()))
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "You cannot use non-numeric addresses for the server.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
RakNet::SocketDescriptor sd((unsigned short) port, address.c_str());
|
||||
RakNet::SocketDescriptor sd((unsigned short) port, addr.c_str());
|
||||
|
||||
try
|
||||
{
|
||||
for (auto plugin : plugins)
|
||||
Script::LoadScript(plugin.c_str(), pluginHome.c_str());
|
||||
Script::LoadScript(plugin.c_str(), plugin_home.c_str());
|
||||
|
||||
switch (peer->Startup((unsigned) players, &sd, 1))
|
||||
{
|
||||
|
@ -252,7 +271,7 @@ int main(int argc, char *argv[])
|
|||
case RakNet::SOCKET_FAILED_TO_BIND:
|
||||
case RakNet::SOCKET_PORT_ALREADY_IN_USE:
|
||||
case RakNet::PORT_CANNOT_BE_ZERO:
|
||||
throw runtime_error("Failed to bind port. Make sure a server isn't already running on that port.");
|
||||
throw runtime_error("Failed to bind port");
|
||||
case RakNet::SOCKET_FAILED_TEST_SEND:
|
||||
case RakNet::SOCKET_FAMILY_NOT_SUPPORTED:
|
||||
case RakNet::FAILED_TO_CREATE_NETWORK_THREAD:
|
||||
|
@ -264,7 +283,7 @@ int main(int argc, char *argv[])
|
|||
peer->SetMaximumIncomingConnections((unsigned short) (players));
|
||||
|
||||
Networking networking(peer);
|
||||
networking.setServerPassword(password);
|
||||
networking.setServerPassword(passw);
|
||||
|
||||
if (mgr.getBool("enabled", "MasterServer"))
|
||||
{
|
||||
|
@ -307,7 +326,6 @@ int main(int argc, char *argv[])
|
|||
catch (std::exception &e)
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, e.what());
|
||||
Script::Call<Script::CallbackIdentity("OnServerScriptCrash")>(e.what());
|
||||
throw; //fall through
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,16 @@ namespace mwmp
|
|||
{
|
||||
DEBUG_PRINTF(strPacketID.c_str());
|
||||
|
||||
Script::Call<Script::CallbackIdentity("OnPlayerSendMessage")>(player.getId(), player.chatMessage.c_str());
|
||||
Script::CallBackReturn<Script::CallbackIdentity("OnPlayerSendMessage")> result = true;
|
||||
Script::Call<Script::CallbackIdentity("OnPlayerSendMessage")>(result, player.getId(), player.chatMessage.c_str());
|
||||
|
||||
if (result)
|
||||
{
|
||||
player.chatMessage = player.npc.mName + " (" + std::to_string(player.getId()) + "): "
|
||||
+ player.chatMessage + "\n";
|
||||
packet.Send(false);
|
||||
packet.Send(true);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
//
|
||||
// Created by koncord on 31.03.17.
|
||||
//
|
||||
|
||||
#ifndef OPENMW_PROCESSORPLAYERPOSITION_HPP
|
||||
#define OPENMW_PROCESSORPLAYERPOSITION_HPP
|
||||
|
||||
|
@ -15,7 +19,11 @@ namespace mwmp
|
|||
|
||||
void Do(PlayerPacket &packet, Player &player) override
|
||||
{
|
||||
player.sendToLoaded(&packet);
|
||||
//DEBUG_PRINTF(strPacketID);
|
||||
if (!player.creatureStats.mDead)
|
||||
{
|
||||
player.sendToLoaded(&packet);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -134,7 +134,7 @@ add_openmw_dir (mwmp/processors/object BaseObjectProcessor
|
|||
ProcessorScriptGlobalFloat
|
||||
)
|
||||
|
||||
add_openmw_dir (mwmp/processors/worldstate ProcessorCellCreate ProcessorCellReset ProcessorRecordDynamic
|
||||
add_openmw_dir (mwmp/processors/worldstate ProcessorCellCreate ProcessorCellReplace ProcessorRecordDynamic
|
||||
ProcessorWorldCollisionOverride ProcessorWorldMap ProcessorWorldRegionAuthority ProcessorWorldTime
|
||||
ProcessorWorldWeather
|
||||
)
|
||||
|
|
|
@ -221,11 +221,10 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
|||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Check for unmodified tes3mp-credits file on Windows; this makes it so people can't repackage official
|
||||
releases with their own made-up credits, though it obviously has no bearing on unofficial releases that
|
||||
change the checksum below
|
||||
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
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
boost::filesystem::path folderPath(boost::filesystem::initial_path<boost::filesystem::path>());
|
||||
folderPath = boost::filesystem::system_complete(boost::filesystem::path(argv[0])).remove_filename();
|
||||
std::string creditsPath = folderPath.string() + "/tes3mp-credits";
|
||||
|
@ -243,7 +242,6 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
|||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "tes3mp", TES3MP_CREDITS_ERROR, 0);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
|
|
|
@ -553,10 +553,9 @@ namespace MWClass
|
|||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
If the attacker was the LocalPlayer or LocalActor, record their target and send a
|
||||
packet with it
|
||||
If the attacker was the LocalPlayer or LocalActor, record their target and send a packet with it
|
||||
|
||||
If the victim was a LocalActor who died, record their attacker as the killer
|
||||
If the victim was a LocalActor who died, record their attacker as the deathReason
|
||||
*/
|
||||
mwmp::Attack *localAttack = MechanicsHelper::getLocalAttack(attacker);
|
||||
|
||||
|
|
|
@ -133,9 +133,9 @@ namespace
|
|||
}
|
||||
modifierSum += add;
|
||||
}
|
||||
creatureStats.setAttribute(attribute, std::min(
|
||||
round_ieee_754(creatureStats.getAttribute(attribute).getBase()
|
||||
+ (level-1) * modifierSum), 100) );
|
||||
|
||||
creatureStats.setAttribute(attribute,
|
||||
round_ieee_754(creatureStats.getAttribute(attribute).getBase() + (level-1) * modifierSum) );
|
||||
}
|
||||
|
||||
// initial health
|
||||
|
@ -230,13 +230,12 @@ namespace
|
|||
}
|
||||
|
||||
npcStats.getSkill(skillIndex).setBase(
|
||||
std::min(
|
||||
round_ieee_754(
|
||||
npcStats.getSkill(skillIndex).getBase()
|
||||
+ 5
|
||||
+ raceBonus
|
||||
+ specBonus
|
||||
+(int(level)-1) * (majorMultiplier + specMultiplier)), 100)); // Must gracefully handle level 0
|
||||
+(int(level)-1) * (majorMultiplier + specMultiplier))); // Must gracefully handle level 0
|
||||
}
|
||||
|
||||
int skills[ESM::Skill::Length];
|
||||
|
@ -966,13 +965,12 @@ namespace MWClass
|
|||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
If the attacker was the LocalPlayer or LocalActor, record their target and send a
|
||||
packet with it
|
||||
If the attacker was the LocalPlayer or LocalActor, record their target and send a packet with it
|
||||
|
||||
If the victim was the LocalPlayer, check whether packets should be sent about
|
||||
their new dynamic stats and position
|
||||
|
||||
If the victim was a LocalActor who died, record their attacker as the killer
|
||||
If the victim was a LocalActor who died, record their attacker as the deathReason
|
||||
*/
|
||||
mwmp::Attack *localAttack = MechanicsHelper::getLocalAttack(attacker);
|
||||
|
||||
|
|
|
@ -197,15 +197,14 @@ namespace MWGui
|
|||
/*
|
||||
Start of tes3mp change (major)
|
||||
|
||||
For valid drops, avoid running the original code for the item transfer, to prevent unilateral
|
||||
item duping or interaction on this client
|
||||
Avoid running any of the original code for dropping items, to prevent possibilities
|
||||
for item duping or interaction with restricted containers
|
||||
|
||||
Instead, finish the drag in a way that removes the items in it, and let the server's reply handle
|
||||
the rest
|
||||
Instead, finish the drag in a way that removes the items in it
|
||||
*/
|
||||
if (success)
|
||||
// mDragAndDrop->drop(mModel, mItemView);
|
||||
mDragAndDrop->finish(true);
|
||||
//if (success)
|
||||
// mDragAndDrop->drop(mModel, mItemView);
|
||||
mDragAndDrop->finish(true);
|
||||
/*
|
||||
End of tes3mp change (major)
|
||||
*/
|
||||
|
|
|
@ -458,15 +458,6 @@ namespace MWGui
|
|||
|
||||
updateMagicMarkers();
|
||||
updateCustomMarkers();
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Update player markers when cell changes to fix their locations
|
||||
*/
|
||||
updatePlayerMarkers();
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
}
|
||||
|
||||
void LocalMapBase::requestMapRender(const MWWorld::CellStore *cell)
|
||||
|
|
|
@ -164,10 +164,10 @@ namespace MWGui
|
|||
Start of tes3mp addition
|
||||
|
||||
Send a PLAYER_QUICKKEYS packet whenever a key is unassigned, but only if the player
|
||||
is logged in on the server, so as to avoid doing anything doing at startup when all
|
||||
has finished character generation, so as to avoid doing anything doing startup when all
|
||||
quick keys get unassigned by default
|
||||
*/
|
||||
if (mwmp::Main::get().getLocalPlayer()->isLoggedIn() && !mwmp::Main::get().getLocalPlayer()->isReceivingQuickKeys)
|
||||
if (mwmp::Main::get().getLocalPlayer()->hasFinishedCharGen() && !mwmp::Main::get().getLocalPlayer()->isReceivingQuickKeys)
|
||||
{
|
||||
mwmp::Main::get().getLocalPlayer()->sendQuickKey(key->index, Type_Unassigned);
|
||||
}
|
||||
|
|
|
@ -9,19 +9,6 @@
|
|||
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Include additional headers for multiplayer purposes
|
||||
*/
|
||||
#include "../mwmp/Main.hpp"
|
||||
#include "../mwmp/Networking.hpp"
|
||||
#include "../mwmp/LocalPlayer.hpp"
|
||||
#include "../mwmp/MechanicsHelper.hpp"
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
|
@ -176,26 +163,9 @@ void Recharge::onItemClicked(MyGUI::Widget *sender, const MWWorld::Ptr& item)
|
|||
|
||||
const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().find(
|
||||
item.getClass().getEnchantment(item));
|
||||
|
||||
/*
|
||||
Start of tes3mp change (minor)
|
||||
|
||||
Send PlayerInventory packets that replace the original item with the new one
|
||||
*/
|
||||
mwmp::LocalPlayer *localPlayer = mwmp::Main::get().getLocalPlayer();
|
||||
mwmp::Item removedItem = MechanicsHelper::getItem(item, 1);
|
||||
|
||||
item.getCellRef().setEnchantmentCharge(
|
||||
std::min(item.getCellRef().getEnchantmentCharge() + restored, static_cast<float>(enchantment->mData.mCharge)));
|
||||
|
||||
mwmp::Item addedItem = MechanicsHelper::getItem(item, 1);
|
||||
|
||||
localPlayer->sendItemChange(addedItem, mwmp::InventoryChanges::ADD);
|
||||
localPlayer->sendItemChange(removedItem, mwmp::InventoryChanges::REMOVE);
|
||||
/*
|
||||
End of tes3mp change (minor)
|
||||
*/
|
||||
|
||||
MWBase::Environment::get().getWindowManager()->playSound("Enchant Success");
|
||||
|
||||
player.getClass().getContainerStore(player).restack(item);
|
||||
|
|
|
@ -244,33 +244,18 @@ namespace MWGui
|
|||
nameWidget->setSize(nameWidget->getWidth() - (widthAfter-widthBefore), nameWidget->getHeight());
|
||||
}
|
||||
|
||||
if (value.getBase() < 100)
|
||||
{
|
||||
nameWidget->setUserString("Visible_SkillMaxed", "false");
|
||||
nameWidget->setUserString("UserData^Hidden_SkillMaxed", "true");
|
||||
nameWidget->setUserString("Visible_SkillProgressVBox", "true");
|
||||
nameWidget->setUserString("UserData^Hidden_SkillProgressVBox", "false");
|
||||
nameWidget->setUserString("Visible_SkillMaxed", "false");
|
||||
nameWidget->setUserString("UserData^Hidden_SkillMaxed", "true");
|
||||
nameWidget->setUserString("Visible_SkillProgressVBox", "true");
|
||||
nameWidget->setUserString("UserData^Hidden_SkillProgressVBox", "false");
|
||||
|
||||
valueWidget->setUserString("Visible_SkillMaxed", "false");
|
||||
valueWidget->setUserString("UserData^Hidden_SkillMaxed", "true");
|
||||
valueWidget->setUserString("Visible_SkillProgressVBox", "true");
|
||||
valueWidget->setUserString("UserData^Hidden_SkillProgressVBox", "false");
|
||||
valueWidget->setUserString("Visible_SkillMaxed", "false");
|
||||
valueWidget->setUserString("UserData^Hidden_SkillMaxed", "true");
|
||||
valueWidget->setUserString("Visible_SkillProgressVBox", "true");
|
||||
valueWidget->setUserString("UserData^Hidden_SkillProgressVBox", "false");
|
||||
|
||||
setSkillProgress(nameWidget, value.getProgress(), parSkill);
|
||||
setSkillProgress(valueWidget, value.getProgress(), parSkill);
|
||||
}
|
||||
else
|
||||
{
|
||||
nameWidget->setUserString("Visible_SkillMaxed", "true");
|
||||
nameWidget->setUserString("UserData^Hidden_SkillMaxed", "false");
|
||||
nameWidget->setUserString("Visible_SkillProgressVBox", "false");
|
||||
nameWidget->setUserString("UserData^Hidden_SkillProgressVBox", "true");
|
||||
|
||||
valueWidget->setUserString("Visible_SkillMaxed", "true");
|
||||
valueWidget->setUserString("UserData^Hidden_SkillMaxed", "false");
|
||||
valueWidget->setUserString("Visible_SkillProgressVBox", "false");
|
||||
valueWidget->setUserString("UserData^Hidden_SkillProgressVBox", "true");
|
||||
}
|
||||
setSkillProgress(nameWidget, value.getProgress(), parSkill);
|
||||
setSkillProgress(valueWidget, value.getProgress(), parSkill);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1070,9 +1070,9 @@ namespace MWInput
|
|||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Ignore attempts to rest if the player has not logged in on the server yet
|
||||
Ignore attempts to rest if the player has not finished character generation yet
|
||||
*/
|
||||
if (!mwmp::Main::get().getLocalPlayer()->isLoggedIn())
|
||||
if (!mwmp::Main::get().getLocalPlayer()->hasFinishedCharGen())
|
||||
return;
|
||||
/*
|
||||
End of tes3mp addition
|
||||
|
@ -1133,21 +1133,10 @@ namespace MWInput
|
|||
{
|
||||
if (!mControlSwitch["playercontrols"])
|
||||
return;
|
||||
|
||||
|
||||
if (MyGUI::InputManager::getInstance ().isModalAny())
|
||||
return;
|
||||
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Ignore attempts to open inventory if the player has not logged in on the server yet
|
||||
*/
|
||||
if (!mwmp::Main::get().getLocalPlayer()->isLoggedIn())
|
||||
return;
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
|
||||
|
||||
// Toggle between game mode and inventory mode
|
||||
if(!MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||
MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Inventory);
|
||||
|
|
|
@ -240,22 +240,8 @@ namespace MWMechanics
|
|||
|
||||
// Set the soul on just one of the gems, not the whole stack
|
||||
gem->getContainerStore()->unstack(*gem, caster);
|
||||
|
||||
/*
|
||||
Start of tes3mp change (minor)
|
||||
|
||||
Send PlayerInventory packets that replace the original gem with the new one
|
||||
*/
|
||||
mwmp::LocalPlayer *localPlayer = mwmp::Main::get().getLocalPlayer();
|
||||
localPlayer->sendItemChange(*gem, 1, mwmp::InventoryChanges::REMOVE);
|
||||
|
||||
gem->getCellRef().setSoul(mCreature.getCellRef().getRefId());
|
||||
|
||||
localPlayer->sendItemChange(*gem, 1, mwmp::InventoryChanges::ADD);
|
||||
/*
|
||||
End of tes3mp change (minor)
|
||||
*/
|
||||
|
||||
// Restack the gem with other gems with the same soul
|
||||
gem->getContainerStore()->restack(*gem);
|
||||
|
||||
|
@ -842,22 +828,6 @@ namespace MWMechanics
|
|||
|
||||
if (isDamageEffect)
|
||||
{
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
If the victim was a LocalActor who died, record the caster as the killer
|
||||
*/
|
||||
if (mwmp::Main::get().getCellController()->isLocalActor(ptr))
|
||||
{
|
||||
bool isSuicide = ptr == caster || caster.isEmpty();
|
||||
|
||||
mwmp::Main::get().getCellController()->getLocalActor(ptr)->killer = isSuicide ?
|
||||
MechanicsHelper::getTarget(ptr) : MechanicsHelper::getTarget(caster);
|
||||
}
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
|
||||
if (caster == player || playerFollowers.find(caster) != playerFollowers.end())
|
||||
{
|
||||
if (caster.getClass().getNpcStats(caster).isWerewolf())
|
||||
|
|
|
@ -578,7 +578,7 @@ namespace MWMechanics
|
|||
if (localAttack && localAttack->pressed != true)
|
||||
{
|
||||
MechanicsHelper::resetAttack(localAttack);
|
||||
localAttack->type = distantCombat ? mwmp::Attack::RANGED : mwmp::Attack::MELEE;
|
||||
localAttack->type = distantCombat ? mwmp::Attack::MELEE : mwmp::Attack::RANGED;
|
||||
localAttack->pressed = true;
|
||||
localAttack->shouldSend = true;
|
||||
}
|
||||
|
|
|
@ -218,9 +218,6 @@ void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &clas
|
|||
{
|
||||
int base = getSkill (skillIndex).getBase();
|
||||
|
||||
if (base >= 100)
|
||||
return;
|
||||
|
||||
base += 1;
|
||||
|
||||
const MWWorld::Store<ESM::GameSetting> &gmst =
|
||||
|
|
|
@ -4,19 +4,6 @@
|
|||
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Include additional headers for multiplayer purposes
|
||||
*/
|
||||
#include "../mwmp/Main.hpp"
|
||||
#include "../mwmp/Networking.hpp"
|
||||
#include "../mwmp/LocalPlayer.hpp"
|
||||
#include "../mwmp/MechanicsHelper.hpp"
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
|
@ -70,25 +57,8 @@ void Repair::repair(const MWWorld::Ptr &itemToRepair)
|
|||
// repair by 'y' points
|
||||
int charge = itemToRepair.getClass().getItemHealth(itemToRepair);
|
||||
charge = std::min(charge + y, itemToRepair.getClass().getItemMaxHealth(itemToRepair));
|
||||
|
||||
/*
|
||||
Start of tes3mp change (minor)
|
||||
|
||||
Send PlayerInventory packets that replace the original item with the new one
|
||||
*/
|
||||
mwmp::LocalPlayer *localPlayer = mwmp::Main::get().getLocalPlayer();
|
||||
mwmp::Item removedItem = MechanicsHelper::getItem(itemToRepair, 1);
|
||||
|
||||
itemToRepair.getCellRef().setCharge(charge);
|
||||
|
||||
mwmp::Item addedItem = MechanicsHelper::getItem(itemToRepair, 1);
|
||||
|
||||
localPlayer->sendItemChange(addedItem, mwmp::InventoryChanges::ADD);
|
||||
localPlayer->sendItemChange(removedItem, mwmp::InventoryChanges::REMOVE);
|
||||
/*
|
||||
End of tes3mp change (minor)
|
||||
*/
|
||||
|
||||
// attempt to re-stack item, in case it was fully repaired
|
||||
MWWorld::ContainerStoreIterator stacked = player.getClass().getContainerStore(player).restack(itemToRepair);
|
||||
|
||||
|
|
|
@ -537,7 +537,7 @@ namespace MWMechanics
|
|||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
If the victim was a LocalPlayer or LocalActor who died, record the caster as the killer
|
||||
If the victim was a LocalPlayer or LocalActor who died, record their attacker as the deathReason
|
||||
*/
|
||||
if (!wasDead && isDead)
|
||||
{
|
||||
|
|
|
@ -82,10 +82,8 @@ void Cell::updateLocal(bool forceUpdate)
|
|||
}
|
||||
else
|
||||
{
|
||||
// Forcibly update this local actor if its data has never been sent before;
|
||||
// otherwise, use the current forceUpdate value
|
||||
if (actor->getPtr().getRefData().isEnabled())
|
||||
actor->update(actor->hasSentData ? forceUpdate : true);
|
||||
actor->update(forceUpdate);
|
||||
|
||||
++it;
|
||||
}
|
||||
|
@ -399,9 +397,6 @@ void Cell::readCellChange(ActorList& actorList)
|
|||
|
||||
void Cell::initializeLocalActor(const MWWorld::Ptr& ptr)
|
||||
{
|
||||
std::string mapIndex = Main::get().getCellController()->generateMapIndex(ptr);
|
||||
LOG_APPEND(Log::LOG_VERBOSE, "- Initializing LocalActor %s in %s", mapIndex.c_str(), getDescription().c_str());
|
||||
|
||||
LocalActor *actor = new LocalActor();
|
||||
actor->cell = *store->getCell();
|
||||
actor->setPtr(ptr);
|
||||
|
@ -411,17 +406,16 @@ void Cell::initializeLocalActor(const MWWorld::Ptr& ptr)
|
|||
if (ptr.getClass().getCreatureStats(ptr).isDead())
|
||||
actor->wasDead = true;
|
||||
|
||||
std::string mapIndex = Main::get().getCellController()->generateMapIndex(ptr);
|
||||
localActors[mapIndex] = actor;
|
||||
|
||||
Main::get().getCellController()->setLocalActorRecord(mapIndex, getDescription());
|
||||
|
||||
LOG_APPEND(Log::LOG_VERBOSE, "- Successfully initialized LocalActor %s in %s", mapIndex.c_str(), getDescription().c_str());
|
||||
LOG_APPEND(Log::LOG_VERBOSE, "- Initialized LocalActor %s in %s", mapIndex.c_str(), getDescription().c_str());
|
||||
}
|
||||
|
||||
void Cell::initializeLocalActors()
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Initializing LocalActors in %s", getDescription().c_str());
|
||||
|
||||
for (const auto &mergedRef : store->getMergedRefs())
|
||||
{
|
||||
if (mergedRef->mClass->isActor())
|
||||
|
@ -438,24 +432,20 @@ void Cell::initializeLocalActors()
|
|||
initializeLocalActor(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
LOG_APPEND(Log::LOG_VERBOSE, "- Successfully initialized LocalActors in %s", getDescription().c_str());
|
||||
}
|
||||
|
||||
void Cell::initializeDedicatedActor(const MWWorld::Ptr& ptr)
|
||||
{
|
||||
std::string mapIndex = Main::get().getCellController()->generateMapIndex(ptr);
|
||||
LOG_APPEND(Log::LOG_VERBOSE, "- Initializing DedicatedActor %s in %s", mapIndex.c_str(), getDescription().c_str());
|
||||
|
||||
DedicatedActor *actor = new DedicatedActor();
|
||||
actor->cell = *store->getCell();
|
||||
actor->setPtr(ptr);
|
||||
|
||||
std::string mapIndex = Main::get().getCellController()->generateMapIndex(ptr);
|
||||
dedicatedActors[mapIndex] = actor;
|
||||
|
||||
Main::get().getCellController()->setDedicatedActorRecord(mapIndex, getDescription());
|
||||
|
||||
LOG_APPEND(Log::LOG_VERBOSE, "- Successfully initialized DedicatedActor %s in %s", mapIndex.c_str(), getDescription().c_str());
|
||||
LOG_APPEND(Log::LOG_VERBOSE, "- Initialized DedicatedActor %s in %s", mapIndex.c_str(), getDescription().c_str());
|
||||
}
|
||||
|
||||
void Cell::initializeDedicatedActors(ActorList& actorList)
|
||||
|
|
|
@ -77,8 +77,6 @@ void CellController::initializeCell(const ESM::Cell& cell)
|
|||
// If this key doesn't exist, create it
|
||||
if (cellsInitialized.count(mapIndex) == 0)
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Initializing mwmp::Cell %s", cell.getDescription().c_str());
|
||||
|
||||
MWWorld::CellStore *cellStore = getCellStore(cell);
|
||||
|
||||
if (!cellStore) return;
|
||||
|
@ -86,7 +84,7 @@ void CellController::initializeCell(const ESM::Cell& cell)
|
|||
mwmp::Cell *mpCell = new mwmp::Cell(cellStore);
|
||||
cellsInitialized[mapIndex] = mpCell;
|
||||
|
||||
LOG_APPEND(Log::LOG_VERBOSE, "- Successfully initialized mwmp::Cell %s", cell.getDescription().c_str());
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "- Initialized mwmp::Cell %s", mpCell->getDescription().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -71,13 +71,6 @@ DedicatedPlayer::~DedicatedPlayer()
|
|||
|
||||
void DedicatedPlayer::update(float dt)
|
||||
{
|
||||
// Only move and set anim flags if the framerate isn't too low
|
||||
if (dt < 0.1)
|
||||
{
|
||||
move(dt);
|
||||
setAnimFlags();
|
||||
}
|
||||
|
||||
MWMechanics::CreatureStats *ptrCreatureStats = &ptr.getClass().getCreatureStats(ptr);
|
||||
|
||||
MWMechanics::DynamicStat<float> value;
|
||||
|
@ -107,6 +100,13 @@ void DedicatedPlayer::update(float dt)
|
|||
ptrCreatureStats->setAiSetting(MWMechanics::CreatureStats::AI_Fight, 0);
|
||||
ptrCreatureStats->setAiSetting(MWMechanics::CreatureStats::AI_Flee, 0);
|
||||
ptrCreatureStats->setAiSetting(MWMechanics::CreatureStats::AI_Hello, 0);
|
||||
|
||||
// Only move and set anim flags if the framerate isn't too low
|
||||
if (dt < 0.1)
|
||||
{
|
||||
move(dt);
|
||||
setAnimFlags();
|
||||
}
|
||||
}
|
||||
|
||||
void DedicatedPlayer::move(float dt)
|
||||
|
|
|
@ -162,9 +162,9 @@ namespace mwmp
|
|||
windowState++;
|
||||
if (windowState == 3) windowState = 0;
|
||||
|
||||
std::string chatMode = windowState == CHAT_DISABLED ? "Chat hidden" :
|
||||
windowState == CHAT_ENABLED ? "Chat visible" :
|
||||
"Chat appearing when needed";
|
||||
std::string chatMode = windowState == CHAT_DISABLED ? "Chat disabled" :
|
||||
windowState == CHAT_ENABLED ? "Chat enabled" :
|
||||
"Chat in hidden mode";
|
||||
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Switch chat mode to %s", chatMode.c_str());
|
||||
MWBase::Environment::get().getWindowManager()->messageBox(chatMode);
|
||||
|
|
|
@ -22,7 +22,6 @@ using namespace std;
|
|||
|
||||
LocalActor::LocalActor()
|
||||
{
|
||||
hasSentData = false;
|
||||
posWasChanged = false;
|
||||
equipmentChanged = false;
|
||||
|
||||
|
@ -62,16 +61,14 @@ void LocalActor::update(bool forceUpdate)
|
|||
updateSpeech();
|
||||
updateAttack();
|
||||
}
|
||||
|
||||
hasSentData = true;
|
||||
}
|
||||
|
||||
void LocalActor::updateCell()
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Sending ID_ACTOR_CELL_CHANGE about %s %i-%i in cell %s to server",
|
||||
refId.c_str(), refNum, mpNum, cell.getDescription().c_str());
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Sending ID_ACTOR_CELL_CHANGE about %s %i-%i to server",
|
||||
refId.c_str(), refNum, mpNum);
|
||||
|
||||
LOG_APPEND(Log::LOG_VERBOSE, "- Moved to cell %s", ptr.getCell()->getCell()->getDescription().c_str());
|
||||
LOG_APPEND(Log::LOG_VERBOSE, "- Moved from %s to %s", cell.getDescription().c_str(), ptr.getCell()->getCell()->getDescription().c_str());
|
||||
|
||||
cell = *ptr.getCell()->getCell();
|
||||
position = ptr.getRefData().getPosition();
|
||||
|
@ -194,8 +191,8 @@ void LocalActor::updateStatsDynamic(bool forceUpdate)
|
|||
if (MechanicsHelper::isEmptyTarget(killer))
|
||||
killer = MechanicsHelper::getTarget(ptr);
|
||||
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Sending ID_ACTOR_DEATH about %s %i-%i in cell %s to server",
|
||||
refId.c_str(), refNum, mpNum, cell.getDescription().c_str());
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Sending ID_ACTOR_DEATH about %s %i-%i to server",
|
||||
refId.c_str(), refNum, mpNum);
|
||||
|
||||
mwmp::Main::get().getNetworking()->getActorList()->addDeathActor(*this);
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@ namespace mwmp
|
|||
MWWorld::Ptr getPtr();
|
||||
void setPtr(const MWWorld::Ptr& newPtr);
|
||||
|
||||
bool hasSentData;
|
||||
bool wasDead;
|
||||
|
||||
private:
|
||||
|
|
|
@ -46,7 +46,6 @@ using namespace std;
|
|||
LocalPlayer::LocalPlayer()
|
||||
{
|
||||
deathTime = time(0);
|
||||
receivedCharacter = false;
|
||||
|
||||
charGenState.currentStage = 0;
|
||||
charGenState.endStage = 1;
|
||||
|
@ -194,12 +193,9 @@ bool LocalPlayer::processCharGen()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool LocalPlayer::isLoggedIn()
|
||||
bool LocalPlayer::hasFinishedCharGen()
|
||||
{
|
||||
if (charGenState.isFinished && (charGenState.endStage > 1 || receivedCharacter))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
return charGenState.isFinished;
|
||||
}
|
||||
|
||||
void LocalPlayer::updateStatsDynamic(bool forceUpdate)
|
||||
|
@ -225,16 +221,16 @@ void LocalPlayer::updateStatsDynamic(bool forceUpdate)
|
|||
|| abs(oldVal.getCurrent() - newVal.getCurrent()) >= limit);
|
||||
};
|
||||
|
||||
if (forceUpdate || needUpdate(oldHealth, health, 2))
|
||||
if (needUpdate(oldHealth, health, 2))
|
||||
statsDynamicIndexChanges.push_back(0);
|
||||
|
||||
if (forceUpdate || needUpdate(oldMagicka, magicka, 4))
|
||||
if (needUpdate(oldMagicka, magicka, 4))
|
||||
statsDynamicIndexChanges.push_back(1);
|
||||
|
||||
if (forceUpdate || needUpdate(oldFatigue, fatigue, 4))
|
||||
if (needUpdate(oldFatigue, fatigue, 4))
|
||||
statsDynamicIndexChanges.push_back(2);
|
||||
|
||||
if (forceUpdate || statsDynamicIndexChanges.size() > 0)
|
||||
if (statsDynamicIndexChanges.size() > 0 || forceUpdate)
|
||||
{
|
||||
oldHealth = health;
|
||||
oldMagicka = magicka;
|
||||
|
@ -284,7 +280,6 @@ void LocalPlayer::updateAttributes(bool forceUpdate)
|
|||
{
|
||||
if (ptrNpcStats.getAttribute(i).getBase() != creatureStats.mAttributes[i].mBase ||
|
||||
ptrNpcStats.getAttribute(i).getModifier() != creatureStats.mAttributes[i].mMod ||
|
||||
ptrNpcStats.getAttribute(i).getDamage() != creatureStats.mAttributes[i].mDamage ||
|
||||
ptrNpcStats.getSkillIncrease(i) != npcStats.mSkillIncrease[i] ||
|
||||
forceUpdate)
|
||||
{
|
||||
|
@ -319,7 +314,6 @@ void LocalPlayer::updateSkills(bool forceUpdate)
|
|||
// Update a skill if its base value has changed at all or its progress has changed enough
|
||||
if (ptrNpcStats.getSkill(i).getBase() != npcStats.mSkills[i].mBase ||
|
||||
ptrNpcStats.getSkill(i).getModifier() != npcStats.mSkills[i].mMod ||
|
||||
ptrNpcStats.getSkill(i).getDamage() != npcStats.mSkills[i].mDamage ||
|
||||
abs(ptrNpcStats.getSkill(i).getProgress() - npcStats.mSkills[i].mProgress) > 0.75 ||
|
||||
forceUpdate)
|
||||
{
|
||||
|
@ -677,7 +671,6 @@ void LocalPlayer::updateAnimFlags(bool forceUpdate)
|
|||
void LocalPlayer::addItems()
|
||||
{
|
||||
MWWorld::Ptr ptrPlayer = getPlayerPtr();
|
||||
const MWWorld::ESMStore &esmStore = MWBase::Environment::get().getWorld()->getStore();
|
||||
MWWorld::ContainerStore &ptrStore = ptrPlayer.getClass().getContainerStore(ptrPlayer);
|
||||
|
||||
for (const auto &item : inventoryChanges.items)
|
||||
|
@ -688,9 +681,7 @@ void LocalPlayer::addItems()
|
|||
|
||||
try
|
||||
{
|
||||
MWWorld::ManualRef itemRef(esmStore, item.refId, item.count);
|
||||
MWWorld::Ptr itemPtr = itemRef.getPtr();
|
||||
|
||||
MWWorld::Ptr itemPtr = *ptrStore.add(item.refId, item.count, ptrPlayer);
|
||||
if (item.charge != -1)
|
||||
itemPtr.getCellRef().setCharge(item.charge);
|
||||
|
||||
|
@ -699,8 +690,6 @@ void LocalPlayer::addItems()
|
|||
|
||||
if (!item.soul.empty())
|
||||
itemPtr.getCellRef().setSoul(item.soul);
|
||||
|
||||
ptrStore.add(itemPtr, item.count, ptrPlayer);
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
|
@ -843,11 +832,11 @@ void LocalPlayer::resurrect()
|
|||
|
||||
// Ensure we unequip any items with constant effects that can put us into an infinite
|
||||
// death loop
|
||||
static const int damageEffects[5] = { ESM::MagicEffect::DrainHealth, ESM::MagicEffect::FireDamage,
|
||||
ESM::MagicEffect::FrostDamage, ESM::MagicEffect::ShockDamage, ESM::MagicEffect::SunDamage };
|
||||
|
||||
for (const auto &damageEffect : damageEffects)
|
||||
MechanicsHelper::unequipItemsByEffect(ptrPlayer, ESM::Enchantment::ConstantEffect, damageEffect);
|
||||
MechanicsHelper::unequipItemsByEffect(ptrPlayer, ESM::Enchantment::ConstantEffect, ESM::MagicEffect::DrainHealth);
|
||||
MechanicsHelper::unequipItemsByEffect(ptrPlayer, ESM::Enchantment::ConstantEffect, ESM::MagicEffect::FireDamage);
|
||||
MechanicsHelper::unequipItemsByEffect(ptrPlayer, ESM::Enchantment::ConstantEffect, ESM::MagicEffect::FrostDamage);
|
||||
MechanicsHelper::unequipItemsByEffect(ptrPlayer, ESM::Enchantment::ConstantEffect, ESM::MagicEffect::ShockDamage);
|
||||
MechanicsHelper::unequipItemsByEffect(ptrPlayer, ESM::Enchantment::ConstantEffect, ESM::MagicEffect::SunDamage);
|
||||
|
||||
Main::get().getNetworking()->getPlayerPacket(ID_PLAYER_RESURRECT)->setPlayer(this);
|
||||
Main::get().getNetworking()->getPlayerPacket(ID_PLAYER_RESURRECT)->Send();
|
||||
|
@ -866,8 +855,6 @@ void LocalPlayer::closeInventoryWindows()
|
|||
|
||||
void LocalPlayer::setCharacter()
|
||||
{
|
||||
receivedCharacter = true;
|
||||
|
||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
|
||||
// Ignore invalid races
|
||||
|
@ -922,7 +909,7 @@ void LocalPlayer::setAttributes()
|
|||
{
|
||||
MWWorld::Ptr ptrPlayer = getPlayerPtr();
|
||||
|
||||
MWMechanics::NpcStats *ptrNpcStats = &ptrPlayer.getClass().getNpcStats(ptrPlayer);
|
||||
MWMechanics::CreatureStats *ptrCreatureStats = &ptrPlayer.getClass().getCreatureStats(ptrPlayer);
|
||||
MWMechanics::AttributeValue attributeValue;
|
||||
|
||||
for (int attributeIndex = 0; attributeIndex < 8; ++attributeIndex)
|
||||
|
@ -930,14 +917,14 @@ void LocalPlayer::setAttributes()
|
|||
// If the server wants to clear our attribute's non-zero modifier, we need to remove
|
||||
// the spell effect causing it, to avoid an infinite loop where the effect keeps resetting
|
||||
// the modifier
|
||||
if (creatureStats.mAttributes[attributeIndex].mMod == 0 && ptrNpcStats->getAttribute(attributeIndex).getModifier() > 0)
|
||||
if (creatureStats.mAttributes[attributeIndex].mMod == 0 && ptrCreatureStats->getAttribute(attributeIndex).getModifier() > 0)
|
||||
{
|
||||
ptrNpcStats->getActiveSpells().purgeEffectByArg(ESM::MagicEffect::FortifyAttribute, attributeIndex);
|
||||
ptrCreatureStats->getActiveSpells().purgeEffectByArg(ESM::MagicEffect::FortifyAttribute, attributeIndex);
|
||||
MWBase::Environment::get().getMechanicsManager()->updateMagicEffects(ptrPlayer);
|
||||
|
||||
// Is the modifier for this attribute still higher than 0? If so, unequip items that
|
||||
// fortify the attribute
|
||||
if (ptrNpcStats->getAttribute(attributeIndex).getModifier() > 0)
|
||||
if (ptrCreatureStats->getAttribute(attributeIndex).getModifier() > 0)
|
||||
{
|
||||
MechanicsHelper::unequipItemsByEffect(ptrPlayer, ESM::Enchantment::ConstantEffect, ESM::MagicEffect::FortifyAttribute, attributeIndex, -1);
|
||||
mwmp::Main::get().getGUIController()->refreshGuiMode(MWGui::GM_Inventory);
|
||||
|
@ -945,9 +932,7 @@ void LocalPlayer::setAttributes()
|
|||
}
|
||||
|
||||
attributeValue.readState(creatureStats.mAttributes[attributeIndex]);
|
||||
ptrNpcStats->setAttribute(attributeIndex, attributeValue);
|
||||
|
||||
ptrNpcStats->setSkillIncrease(attributeIndex, npcStats.mSkillIncrease[attributeIndex]);
|
||||
ptrCreatureStats->setAttribute(attributeIndex, attributeValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -980,6 +965,11 @@ void LocalPlayer::setSkills()
|
|||
skillValue.readState(npcStats.mSkills[skillIndex]);
|
||||
ptrNpcStats->setSkill(skillIndex, skillValue);
|
||||
}
|
||||
|
||||
for (int attributeIndex = 0; attributeIndex < 8; ++attributeIndex)
|
||||
ptrNpcStats->setSkillIncrease(attributeIndex, npcStats.mSkillIncrease[attributeIndex]);
|
||||
|
||||
ptrNpcStats->setLevelProgress(npcStats.mLevelProgress);
|
||||
}
|
||||
|
||||
void LocalPlayer::setLevel()
|
||||
|
@ -987,9 +977,8 @@ void LocalPlayer::setLevel()
|
|||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
MWWorld::Ptr ptrPlayer = world->getPlayerPtr();
|
||||
|
||||
MWMechanics::NpcStats *ptrNpcStats = &ptrPlayer.getClass().getNpcStats(ptrPlayer);
|
||||
ptrNpcStats->setLevel(creatureStats.mLevel);
|
||||
ptrNpcStats->setLevelProgress(npcStats.mLevelProgress);
|
||||
MWMechanics::CreatureStats *ptrCreatureStats = &ptrPlayer.getClass().getCreatureStats(ptrPlayer);
|
||||
ptrCreatureStats->setLevel(creatureStats.mLevel);
|
||||
}
|
||||
|
||||
void LocalPlayer::setBounty()
|
||||
|
@ -1370,7 +1359,7 @@ void LocalPlayer::sendClass()
|
|||
|
||||
void LocalPlayer::sendInventory()
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Sending entire inventory to server");
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Sending entire inventory to server");
|
||||
|
||||
MWWorld::Ptr ptrPlayer = getPlayerPtr();
|
||||
MWWorld::InventoryStore &ptrInventory = ptrPlayer.getClass().getInventoryStore(ptrPlayer);
|
||||
|
@ -1403,28 +1392,36 @@ void LocalPlayer::sendInventory()
|
|||
getNetworking()->getPlayerPacket(ID_PLAYER_INVENTORY)->Send();
|
||||
}
|
||||
|
||||
void LocalPlayer::sendItemChange(const mwmp::Item& item, 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",
|
||||
item.refId.c_str(), action, item.count);
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Sending item change for %s with action %i, count %i",
|
||||
itemPtr.getCellRef().getRefId().c_str(), action, count);
|
||||
|
||||
inventoryChanges.items.clear();
|
||||
inventoryChanges.items.push_back(item);
|
||||
inventoryChanges.action = action;
|
||||
|
||||
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 MWWorld::Ptr& itemPtr, int count, unsigned int action)
|
||||
{
|
||||
mwmp::Item item = MechanicsHelper::getItem(itemPtr, count);
|
||||
sendItemChange(item, action);
|
||||
}
|
||||
|
||||
void LocalPlayer::sendItemChange(const std::string& refId, int count, unsigned int action)
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Sending item change for %s with action %i, count %i",
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Sending item change for %s with action %i, count %i",
|
||||
refId.c_str(), action, count);
|
||||
|
||||
inventoryChanges.items.clear();
|
||||
|
|
|
@ -16,7 +16,6 @@ namespace mwmp
|
|||
virtual ~LocalPlayer();
|
||||
|
||||
time_t deathTime;
|
||||
bool receivedCharacter;
|
||||
|
||||
bool isReceivingInventory;
|
||||
bool isReceivingQuickKeys;
|
||||
|
@ -26,7 +25,7 @@ namespace mwmp
|
|||
void update();
|
||||
|
||||
bool processCharGen();
|
||||
bool isLoggedIn();
|
||||
bool hasFinishedCharGen();
|
||||
|
||||
void updateStatsDynamic(bool forceUpdate = false);
|
||||
void updateAttributes(bool forceUpdate = false);
|
||||
|
@ -77,7 +76,6 @@ namespace mwmp
|
|||
|
||||
void sendClass();
|
||||
void sendInventory();
|
||||
void sendItemChange(const mwmp::Item& item, unsigned int action);
|
||||
void sendItemChange(const MWWorld::Ptr& itemPtr, int count, unsigned int action);
|
||||
void sendItemChange(const std::string& refId, int count, unsigned int action);
|
||||
void sendSpellbook();
|
||||
|
|
|
@ -51,8 +51,8 @@ using namespace mwmp;
|
|||
using namespace std;
|
||||
|
||||
Main *Main::pMain = 0;
|
||||
std::string Main::address = "";
|
||||
std::string Main::serverPassword = TES3MP_DEFAULT_PASSW;
|
||||
std::string Main::addr = "";
|
||||
std::string Main::passw = TES3MP_DEFAULT_PASSW;
|
||||
std::string Main::resourceDir = "";
|
||||
|
||||
std::string Main::getResDir()
|
||||
|
@ -118,8 +118,8 @@ void Main::optionsDesc(boost::program_options::options_description *desc)
|
|||
|
||||
void Main::configure(const boost::program_options::variables_map &variables)
|
||||
{
|
||||
Main::address = variables["connect"].as<string>();
|
||||
Main::serverPassword = variables["password"].as<string>();
|
||||
Main::addr = variables["connect"].as<string>();
|
||||
Main::passw = variables["password"].as<string>();
|
||||
resourceDir = variables["resources"].as<Files::EscapeHashString>().toStdString();
|
||||
}
|
||||
|
||||
|
@ -155,22 +155,22 @@ bool Main::init(std::vector<std::string> &content, Files::Collections &collectio
|
|||
|
||||
int logLevel = mgr.getInt("logLevel", "General");
|
||||
Log::SetLevel(logLevel);
|
||||
if (address.empty())
|
||||
if (addr.empty())
|
||||
{
|
||||
pMain->server = mgr.getString("destinationAddress", "General");
|
||||
pMain->port = (unsigned short) mgr.getInt("port", "General");
|
||||
|
||||
serverPassword = mgr.getString("password", "General");
|
||||
if (serverPassword.empty())
|
||||
serverPassword = TES3MP_DEFAULT_PASSW;
|
||||
passw = mgr.getString("password", "General");
|
||||
if (passw.empty())
|
||||
passw = TES3MP_DEFAULT_PASSW;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t delimPos = address.find(':');
|
||||
pMain->server = address.substr(0, delimPos);
|
||||
pMain->port = atoi(address.substr(delimPos + 1).c_str());
|
||||
size_t delim_pos = addr.find(':');
|
||||
pMain->server = addr.substr(0, delim_pos);
|
||||
pMain->port = atoi(addr.substr(delim_pos + 1).c_str());
|
||||
}
|
||||
get().mLocalPlayer->serverPassword = serverPassword;
|
||||
get().mLocalPlayer->passw = passw;
|
||||
|
||||
pMain->mNetworking->connect(pMain->server, pMain->port, content, collections);
|
||||
RestoreMgr(mgr);
|
||||
|
|
|
@ -39,8 +39,8 @@ namespace mwmp
|
|||
|
||||
private:
|
||||
static std::string resourceDir;
|
||||
static std::string address;
|
||||
static std::string serverPassword;
|
||||
static std::string addr;
|
||||
static std::string passw;
|
||||
Main (const Main&);
|
||||
///< not implemented
|
||||
Main& operator= (const Main&);
|
||||
|
|
|
@ -83,7 +83,7 @@ bool MechanicsHelper::isUsingRangedWeapon(const MWWorld::Ptr& ptr)
|
|||
MWWorld::ContainerStoreIterator weaponSlot = inventoryStore.getSlot(
|
||||
MWWorld::InventoryStore::Slot_CarriedRight);
|
||||
|
||||
if (weaponSlot != inventoryStore.end() && weaponSlot->getTypeName() == typeid(ESM::Weapon).name())
|
||||
if (weaponSlot != inventoryStore.end())
|
||||
{
|
||||
const ESM::Weapon* weaponRecord = weaponSlot->get<ESM::Weapon>()->mBase;
|
||||
|
||||
|
@ -125,23 +125,6 @@ MWWorld::Ptr MechanicsHelper::getPlayerPtr(const Target& target)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
mwmp::Item MechanicsHelper::getItem(const MWWorld::Ptr& itemPtr, int count)
|
||||
{
|
||||
mwmp::Item item;
|
||||
|
||||
if (itemPtr.getClass().isGold(itemPtr))
|
||||
item.refId = MWWorld::ContainerStore::sGoldId;
|
||||
else
|
||||
item.refId = itemPtr.getCellRef().getRefId();
|
||||
|
||||
item.count = count;
|
||||
item.charge = itemPtr.getCellRef().getCharge();
|
||||
item.enchantmentCharge = itemPtr.getCellRef().getEnchantmentCharge();
|
||||
item.soul = itemPtr.getCellRef().getSoul();
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
mwmp::Target MechanicsHelper::getTarget(const MWWorld::Ptr& ptr)
|
||||
{
|
||||
mwmp::Target target;
|
||||
|
@ -410,14 +393,18 @@ void MechanicsHelper::processAttack(Attack attack, const MWWorld::Ptr& attacker)
|
|||
break;
|
||||
}
|
||||
|
||||
// Add the item if it's missing
|
||||
if (it == inventoryStore.end())
|
||||
it = attacker.getClass().getContainerStore(attacker).add(attack.itemId, 1, attacker);
|
||||
|
||||
inventoryStore.setSelectedEnchantItem(it);
|
||||
LOG_APPEND(Log::LOG_VERBOSE, "- itemId: %s", attack.itemId.c_str());
|
||||
MWBase::Environment::get().getWorld()->castSpell(attacker);
|
||||
inventoryStore.setSelectedEnchantItem(inventoryStore.end());
|
||||
if (it != inventoryStore.end())
|
||||
{
|
||||
inventoryStore.setSelectedEnchantItem(it);
|
||||
LOG_APPEND(Log::LOG_VERBOSE, "- itemId: %s", attack.itemId.c_str());
|
||||
MWBase::Environment::get().getWorld()->castSpell(attacker);
|
||||
inventoryStore.setSelectedEnchantItem(inventoryStore.end());
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Could not find item %s used by %s to cast item spell!",
|
||||
attack.itemId.c_str(), attacker.getCellRef().getRefId().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -465,25 +452,17 @@ void MechanicsHelper::unequipItemsByEffect(const MWWorld::Ptr& ptr, short enchan
|
|||
|
||||
MWWorld::Ptr MechanicsHelper::getItemPtrFromStore(const mwmp::Item& item, MWWorld::ContainerStore& store)
|
||||
{
|
||||
MWWorld::Ptr closestPtr;
|
||||
|
||||
for (MWWorld::ContainerStoreIterator storeIterator = store.begin(); storeIterator != store.end(); ++storeIterator)
|
||||
{
|
||||
// Enchantment charges are often in the process of refilling themselves, so don't check for them here
|
||||
if (Misc::StringUtils::ciEqual(item.refId, storeIterator->getCellRef().getRefId()) &&
|
||||
item.count == storeIterator->getRefData().getCount() &&
|
||||
item.charge == storeIterator->getCellRef().getCharge() &&
|
||||
item.enchantmentCharge == storeIterator->getCellRef().getEnchantmentCharge() &&
|
||||
Misc::StringUtils::ciEqual(item.soul, storeIterator->getCellRef().getSoul()))
|
||||
{
|
||||
// If we have no closestPtr, set it to the Ptr corresponding to this storeIterator; otherwise, make
|
||||
// sure the storeIterator's enchantmentCharge is closer to our goal than that of the previous closestPtr
|
||||
if (!closestPtr || abs(storeIterator->getCellRef().getEnchantmentCharge() - item.enchantmentCharge) <
|
||||
abs(closestPtr.getCellRef().getEnchantmentCharge() - item.enchantmentCharge))
|
||||
{
|
||||
closestPtr = *storeIterator;
|
||||
}
|
||||
return *storeIterator;
|
||||
}
|
||||
}
|
||||
|
||||
return closestPtr;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ namespace MechanicsHelper
|
|||
|
||||
MWWorld::Ptr getPlayerPtr(const mwmp::Target& target);
|
||||
|
||||
mwmp::Item getItem(const MWWorld::Ptr& itemPtr, int count);
|
||||
mwmp::Target getTarget(const MWWorld::Ptr& ptr);
|
||||
void clearTarget(mwmp::Target& target);
|
||||
bool isEmptyTarget(const mwmp::Target& target);
|
||||
|
|
|
@ -45,7 +45,7 @@ using namespace mwmp;
|
|||
string listDiscrepancies(PacketPreInit::PluginContainer checksums, PacketPreInit::PluginContainer checksumsResponse)
|
||||
{
|
||||
std::ostringstream sstr;
|
||||
sstr << "Your plugins or their load order don't match the server's. A full comparison is included in your debug window and latest log file. In short, the following discrepancies have been found:\n\n";
|
||||
sstr << "Your plugins or their load order don't match the server's. A full comparison is included in your client console and latest log file. In short, the following discrepancies have been found:\n\n";
|
||||
|
||||
int discrepancyCount = 0;
|
||||
|
||||
|
|
|
@ -333,7 +333,7 @@ void ObjectList::placeObjects(MWWorld::CellStore* cellStore)
|
|||
|
||||
for (const auto &baseObject : baseObjects)
|
||||
{
|
||||
LOG_APPEND(Log::LOG_VERBOSE, "- cellRef: %s %i-%i, count: %i, charge: %i, enchantmentCharge: %.2f, soul: %s",
|
||||
LOG_APPEND(Log::LOG_VERBOSE, "- cellRef: %s %i-%i, count: %i, charge: %i, enchantmentCharge: %i, soul: %s",
|
||||
baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum, baseObject.count, baseObject.charge,
|
||||
baseObject.enchantmentCharge, baseObject.soul.c_str());
|
||||
|
||||
|
|
|
@ -110,7 +110,7 @@ void RecordHelper::overrideCreatureRecord(const mwmp::CreatureRecord& record)
|
|||
|
||||
if (recordData.mId.empty())
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with no id provided");
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Ignoring record override with no id provided");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -164,11 +164,6 @@ void RecordHelper::overrideCreatureRecord(const mwmp::CreatureRecord& record)
|
|||
|
||||
world->getModifiableStore().overrideRecord(finalData);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with invalid baseId %s", record.baseId.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (isExistingId)
|
||||
world->updatePtrsWithRefId(recordData.mId);
|
||||
|
@ -180,7 +175,7 @@ void RecordHelper::overrideNpcRecord(const mwmp::NpcRecord& record)
|
|||
|
||||
if (recordData.mId.empty())
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with no id provided");
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Ignoring record override with no id provided");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -191,12 +186,12 @@ void RecordHelper::overrideNpcRecord(const mwmp::NpcRecord& record)
|
|||
{
|
||||
if (!doesRaceRecordExist(recordData.mRace))
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring new NPC record with invalid race provided");
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Ignoring new NPC record with invalid race provided");
|
||||
return;
|
||||
}
|
||||
else if (!doesClassRecordExist(recordData.mClass))
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring new NPC record with invalid class provided");
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Ignoring new NPC record with invalid class provided");
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
@ -277,11 +272,6 @@ void RecordHelper::overrideNpcRecord(const mwmp::NpcRecord& record)
|
|||
|
||||
world->getModifiableStore().overrideRecord(finalData);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with invalid baseId %s", record.baseId.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (isExistingId)
|
||||
world->updatePtrsWithRefId(recordData.mId);
|
||||
|
@ -293,17 +283,18 @@ void RecordHelper::overrideEnchantmentRecord(const mwmp::EnchantmentRecord& reco
|
|||
|
||||
if (recordData.mId.empty())
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with no id provided");
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Ignoring record override with no id provided");
|
||||
return;
|
||||
}
|
||||
|
||||
bool isExistingId = doesEnchantmentRecordExist(recordData.mId);
|
||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
|
||||
if (record.baseId.empty())
|
||||
{
|
||||
if (recordData.mEffects.mList.empty())
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring new enchantment record with no effects");
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Ignoring new enchantment record with no effects");
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
@ -332,11 +323,6 @@ void RecordHelper::overrideEnchantmentRecord(const mwmp::EnchantmentRecord& reco
|
|||
|
||||
world->getModifiableStore().overrideRecord(finalData);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with invalid baseId %s", record.baseId.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void RecordHelper::overridePotionRecord(const mwmp::PotionRecord& record)
|
||||
|
@ -345,7 +331,7 @@ void RecordHelper::overridePotionRecord(const mwmp::PotionRecord& record)
|
|||
|
||||
if (recordData.mId.empty())
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with no id provided");
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Ignoring record override with no id provided");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -388,11 +374,6 @@ void RecordHelper::overridePotionRecord(const mwmp::PotionRecord& record)
|
|||
|
||||
world->getModifiableStore().overrideRecord(finalData);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with invalid baseId %s", record.baseId.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (isExistingId)
|
||||
world->updatePtrsWithRefId(recordData.mId);
|
||||
|
@ -404,7 +385,7 @@ void RecordHelper::overrideSpellRecord(const mwmp::SpellRecord& record)
|
|||
|
||||
if (recordData.mId.empty())
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with no id provided");
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Ignoring record override with no id provided");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -438,11 +419,9 @@ void RecordHelper::overrideSpellRecord(const mwmp::SpellRecord& record)
|
|||
|
||||
world->getModifiableStore().overrideRecord(finalData);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with invalid baseId %s", record.baseId.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (isExistingId)
|
||||
world->updatePtrsWithRefId(recordData.mId);
|
||||
}
|
||||
|
||||
void RecordHelper::overrideArmorRecord(const mwmp::ArmorRecord& record)
|
||||
|
@ -451,7 +430,7 @@ void RecordHelper::overrideArmorRecord(const mwmp::ArmorRecord& record)
|
|||
|
||||
if (recordData.mId.empty())
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with no id provided");
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Ignoring record override with no id provided");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -462,7 +441,7 @@ void RecordHelper::overrideArmorRecord(const mwmp::ArmorRecord& record)
|
|||
{
|
||||
if (!recordData.mEnchant.empty() && !doesEnchantmentRecordExist(recordData.mEnchant))
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring new armor record with invalid enchantmentId %s", recordData.mEnchant.c_str());
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Ignoring new armor record with invalid enchantment provided");
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
@ -500,13 +479,8 @@ void RecordHelper::overrideArmorRecord(const mwmp::ArmorRecord& record)
|
|||
if (record.baseOverrides.hasArmorRating)
|
||||
finalData.mData.mArmor = recordData.mData.mArmor;
|
||||
|
||||
if (record.baseOverrides.hasEnchantmentId)
|
||||
{
|
||||
if (doesEnchantmentRecordExist(recordData.mEnchant))
|
||||
finalData.mEnchant = recordData.mEnchant;
|
||||
else
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring invalid enchantmentId %s", recordData.mEnchant.c_str());
|
||||
}
|
||||
if (record.baseOverrides.hasEnchantmentId && doesEnchantmentRecordExist(recordData.mEnchant))
|
||||
finalData.mEnchant = recordData.mEnchant;
|
||||
|
||||
if (record.baseOverrides.hasEnchantmentCharge)
|
||||
finalData.mData.mEnchant = recordData.mData.mEnchant;
|
||||
|
@ -519,11 +493,6 @@ void RecordHelper::overrideArmorRecord(const mwmp::ArmorRecord& record)
|
|||
|
||||
world->getModifiableStore().overrideRecord(finalData);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with invalid baseId %s", record.baseId.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (isExistingId)
|
||||
world->updatePtrsWithRefId(recordData.mId);
|
||||
|
@ -535,7 +504,7 @@ void RecordHelper::overrideBookRecord(const mwmp::BookRecord& record)
|
|||
|
||||
if (recordData.mId.empty())
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with no id provided");
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Ignoring record override with no id provided");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -546,7 +515,7 @@ void RecordHelper::overrideBookRecord(const mwmp::BookRecord& record)
|
|||
{
|
||||
if (!recordData.mEnchant.empty() && !doesEnchantmentRecordExist(recordData.mEnchant))
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring new book record with invalid enchantmentId %s", recordData.mEnchant.c_str());
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Ignoring new book record with invalid enchantment provided");
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
@ -582,13 +551,8 @@ void RecordHelper::overrideBookRecord(const mwmp::BookRecord& record)
|
|||
if (record.baseOverrides.hasSkillId)
|
||||
finalData.mData.mSkillId = recordData.mData.mSkillId;
|
||||
|
||||
if (record.baseOverrides.hasEnchantmentId)
|
||||
{
|
||||
if (doesEnchantmentRecordExist(recordData.mEnchant))
|
||||
finalData.mEnchant = recordData.mEnchant;
|
||||
else
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring invalid enchantmentId %s", recordData.mEnchant.c_str());
|
||||
}
|
||||
if (record.baseOverrides.hasEnchantmentId && doesEnchantmentRecordExist(recordData.mEnchant))
|
||||
finalData.mEnchant = recordData.mEnchant;
|
||||
|
||||
if (record.baseOverrides.hasEnchantmentCharge)
|
||||
finalData.mData.mEnchant = recordData.mData.mEnchant;
|
||||
|
@ -598,11 +562,6 @@ void RecordHelper::overrideBookRecord(const mwmp::BookRecord& record)
|
|||
|
||||
world->getModifiableStore().overrideRecord(finalData);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with invalid baseId %s", record.baseId.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (isExistingId)
|
||||
world->updatePtrsWithRefId(recordData.mId);
|
||||
|
@ -614,7 +573,7 @@ void RecordHelper::overrideClothingRecord(const mwmp::ClothingRecord& record)
|
|||
|
||||
if (recordData.mId.empty())
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with no id provided");
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Ignoring record override with no id provided");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -625,7 +584,7 @@ void RecordHelper::overrideClothingRecord(const mwmp::ClothingRecord& record)
|
|||
{
|
||||
if (!recordData.mEnchant.empty() && !doesEnchantmentRecordExist(recordData.mEnchant))
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring new clothing record with invalid enchantmentId %s", recordData.mEnchant.c_str());
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Ignoring new clothing record with invalid enchantment provided");
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
@ -655,13 +614,8 @@ void RecordHelper::overrideClothingRecord(const mwmp::ClothingRecord& record)
|
|||
if (record.baseOverrides.hasValue)
|
||||
finalData.mData.mValue = recordData.mData.mValue;
|
||||
|
||||
if (record.baseOverrides.hasEnchantmentId)
|
||||
{
|
||||
if (doesEnchantmentRecordExist(recordData.mEnchant))
|
||||
finalData.mEnchant = recordData.mEnchant;
|
||||
else
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring invalid enchantmentId %s", recordData.mEnchant.c_str());
|
||||
}
|
||||
if (record.baseOverrides.hasEnchantmentId && doesEnchantmentRecordExist(recordData.mEnchant))
|
||||
finalData.mEnchant = recordData.mEnchant;
|
||||
|
||||
if (record.baseOverrides.hasEnchantmentCharge)
|
||||
finalData.mData.mEnchant = recordData.mData.mEnchant;
|
||||
|
@ -674,11 +628,6 @@ void RecordHelper::overrideClothingRecord(const mwmp::ClothingRecord& record)
|
|||
|
||||
world->getModifiableStore().overrideRecord(finalData);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with invalid baseId %s", record.baseId.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (isExistingId)
|
||||
world->updatePtrsWithRefId(recordData.mId);
|
||||
|
@ -690,7 +639,7 @@ void RecordHelper::overrideMiscellaneousRecord(const mwmp::MiscellaneousRecord&
|
|||
|
||||
if (recordData.mId.empty())
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with no id provided");
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Ignoring record override with no id provided");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -730,11 +679,6 @@ void RecordHelper::overrideMiscellaneousRecord(const mwmp::MiscellaneousRecord&
|
|||
|
||||
world->getModifiableStore().overrideRecord(finalData);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with invalid baseId %s", record.baseId.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (isExistingId)
|
||||
world->updatePtrsWithRefId(recordData.mId);
|
||||
|
@ -746,7 +690,7 @@ void RecordHelper::overrideWeaponRecord(const mwmp::WeaponRecord& record)
|
|||
|
||||
if (recordData.mId.empty())
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with no id provided");
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Ignoring record override with no id provided");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -757,7 +701,7 @@ void RecordHelper::overrideWeaponRecord(const mwmp::WeaponRecord& record)
|
|||
{
|
||||
if (!recordData.mEnchant.empty() && !doesEnchantmentRecordExist(recordData.mEnchant))
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring new weapon record with invalid enchantmentId %s", recordData.mEnchant.c_str());
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Ignoring new weapon record with invalid enchantment provided");
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
@ -817,13 +761,8 @@ void RecordHelper::overrideWeaponRecord(const mwmp::WeaponRecord& record)
|
|||
if (record.baseOverrides.hasFlags)
|
||||
finalData.mData.mFlags = recordData.mData.mFlags;
|
||||
|
||||
if (record.baseOverrides.hasEnchantmentId)
|
||||
{
|
||||
if (doesEnchantmentRecordExist(recordData.mEnchant))
|
||||
finalData.mEnchant = recordData.mEnchant;
|
||||
else
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring invalid enchantmentId %s", recordData.mEnchant.c_str());
|
||||
}
|
||||
if (record.baseOverrides.hasEnchantmentId && doesEnchantmentRecordExist(recordData.mEnchant))
|
||||
finalData.mEnchant = recordData.mEnchant;
|
||||
|
||||
if (record.baseOverrides.hasEnchantmentCharge)
|
||||
finalData.mData.mEnchant = recordData.mData.mEnchant;
|
||||
|
@ -833,11 +772,6 @@ void RecordHelper::overrideWeaponRecord(const mwmp::WeaponRecord& record)
|
|||
|
||||
world->getModifiableStore().overrideRecord(finalData);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with invalid baseId %s", record.baseId.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (isExistingId)
|
||||
world->updatePtrsWithRefId(recordData.mId);
|
||||
|
|
|
@ -35,7 +35,7 @@ Networking *Worldstate::getNetworking()
|
|||
|
||||
void Worldstate::addRecords()
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Received ID_RECORD_DYNAMIC with %i records of type %i",
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Received ID_RECORD_DYNAMIC with %i records of type %i",
|
||||
recordsCount, recordsType);
|
||||
|
||||
if (recordsType == mwmp::RECORD_TYPE::SPELL)
|
||||
|
@ -44,7 +44,7 @@ void Worldstate::addRecords()
|
|||
{
|
||||
bool hasBaseId = !record.baseId.empty();
|
||||
|
||||
LOG_APPEND(Log::LOG_INFO, "- spell record %s, %s\n-- baseId is %s", record.data.mId.c_str(), record.data.mName.c_str(),
|
||||
LOG_APPEND(Log::LOG_ERROR, "- spell record %s, %s\n-- baseId is %s", record.data.mId.c_str(), record.data.mName.c_str(),
|
||||
hasBaseId ? record.baseId.c_str() : "empty");
|
||||
|
||||
RecordHelper::overrideSpellRecord(record);
|
||||
|
@ -56,7 +56,7 @@ void Worldstate::addRecords()
|
|||
{
|
||||
bool hasBaseId = !record.baseId.empty();
|
||||
|
||||
LOG_APPEND(Log::LOG_INFO, "- potion record %s, %s\n-- baseId is %s", record.data.mId.c_str(), record.data.mName.c_str(),
|
||||
LOG_APPEND(Log::LOG_ERROR, "- potion record %s, %s\n-- baseId is %s", record.data.mId.c_str(), record.data.mName.c_str(),
|
||||
hasBaseId ? record.baseId.c_str() : "empty");
|
||||
|
||||
RecordHelper::overridePotionRecord(record);
|
||||
|
@ -68,7 +68,7 @@ void Worldstate::addRecords()
|
|||
{
|
||||
bool hasBaseId = !record.baseId.empty();
|
||||
|
||||
LOG_APPEND(Log::LOG_INFO, "- enchantment record %s, %i\n-- baseId is %s", record.data.mId.c_str(), record.data.mData.mType,
|
||||
LOG_APPEND(Log::LOG_ERROR, "- enchantment record %s, %i\n-- baseId is %s", record.data.mId.c_str(), record.data.mData.mType,
|
||||
hasBaseId ? record.baseId.c_str() : "empty");
|
||||
|
||||
RecordHelper::overrideEnchantmentRecord(record);
|
||||
|
@ -80,7 +80,7 @@ void Worldstate::addRecords()
|
|||
{
|
||||
bool hasBaseId = !record.baseId.empty();
|
||||
|
||||
LOG_APPEND(Log::LOG_INFO, "- creature record %s, %s\n-- baseId is %s", record.data.mId.c_str(), record.data.mName.c_str(),
|
||||
LOG_APPEND(Log::LOG_ERROR, "- creature record %s, %s\n-- baseId is %s", record.data.mId.c_str(), record.data.mName.c_str(),
|
||||
hasBaseId ? record.baseId.c_str() : "empty");
|
||||
|
||||
RecordHelper::overrideCreatureRecord(record);
|
||||
|
@ -92,7 +92,7 @@ void Worldstate::addRecords()
|
|||
{
|
||||
bool hasBaseId = !record.baseId.empty();
|
||||
|
||||
LOG_APPEND(Log::LOG_INFO, "- NPC record %s, %s\n-- baseId is %s", record.data.mId.c_str(), record.data.mName.c_str(),
|
||||
LOG_APPEND(Log::LOG_ERROR, "- NPC record %s, %s\n-- baseId is %s", record.data.mId.c_str(), record.data.mName.c_str(),
|
||||
hasBaseId ? record.baseId.c_str() : "empty");
|
||||
|
||||
RecordHelper::overrideNpcRecord(record);
|
||||
|
@ -104,7 +104,7 @@ void Worldstate::addRecords()
|
|||
{
|
||||
bool hasBaseId = !record.baseId.empty();
|
||||
|
||||
LOG_APPEND(Log::LOG_INFO, "- armor record %s, %s\n-- baseId is %s", record.data.mId.c_str(), record.data.mName.c_str(),
|
||||
LOG_APPEND(Log::LOG_ERROR, "- armor record %s, %s\n-- baseId is %s", record.data.mId.c_str(), record.data.mName.c_str(),
|
||||
hasBaseId ? record.baseId.c_str() : "empty");
|
||||
|
||||
RecordHelper::overrideArmorRecord(record);
|
||||
|
@ -116,7 +116,7 @@ void Worldstate::addRecords()
|
|||
{
|
||||
bool hasBaseId = !record.baseId.empty();
|
||||
|
||||
LOG_APPEND(Log::LOG_INFO, "- book record %s, %s\n-- baseId is %s", record.data.mId.c_str(), record.data.mName.c_str(),
|
||||
LOG_APPEND(Log::LOG_ERROR, "- book record %s, %s\n-- baseId is %s", record.data.mId.c_str(), record.data.mName.c_str(),
|
||||
hasBaseId ? record.baseId.c_str() : "empty");
|
||||
|
||||
RecordHelper::overrideBookRecord(record);
|
||||
|
@ -128,7 +128,7 @@ void Worldstate::addRecords()
|
|||
{
|
||||
bool hasBaseId = !record.baseId.empty();
|
||||
|
||||
LOG_APPEND(Log::LOG_INFO, "- clothing record %s, %s\n-- baseId is %s", record.data.mId.c_str(), record.data.mName.c_str(),
|
||||
LOG_APPEND(Log::LOG_ERROR, "- clothing record %s, %s\n-- baseId is %s", record.data.mId.c_str(), record.data.mName.c_str(),
|
||||
hasBaseId ? record.baseId.c_str() : "empty");
|
||||
|
||||
RecordHelper::overrideClothingRecord(record);
|
||||
|
@ -140,7 +140,7 @@ void Worldstate::addRecords()
|
|||
{
|
||||
bool hasBaseId = !record.baseId.empty();
|
||||
|
||||
LOG_APPEND(Log::LOG_INFO, "- miscellaneous record %s, %s\n-- baseId is %s", record.data.mId.c_str(), record.data.mName.c_str(),
|
||||
LOG_APPEND(Log::LOG_ERROR, "- miscellaneous record %s, %s\n-- baseId is %s", record.data.mId.c_str(), record.data.mName.c_str(),
|
||||
hasBaseId ? record.baseId.c_str() : "empty");
|
||||
|
||||
RecordHelper::overrideMiscellaneousRecord(record);
|
||||
|
@ -152,7 +152,7 @@ void Worldstate::addRecords()
|
|||
{
|
||||
bool hasBaseId = !record.baseId.empty();
|
||||
|
||||
LOG_APPEND(Log::LOG_INFO, "- weapon record %s, %s\n-- baseId is %s", record.data.mId.c_str(), record.data.mName.c_str(),
|
||||
LOG_APPEND(Log::LOG_ERROR, "- weapon record %s, %s\n-- baseId is %s", record.data.mId.c_str(), record.data.mName.c_str(),
|
||||
hasBaseId ? record.baseId.c_str() : "empty");
|
||||
|
||||
RecordHelper::overrideWeaponRecord(record);
|
||||
|
@ -251,7 +251,7 @@ void Worldstate::sendEnchantmentRecord(const ESM::Enchantment* enchantment)
|
|||
{
|
||||
enchantmentRecords.clear();
|
||||
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Sending ID_RECORD_DYNAMIC with enchantment");
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Sending ID_RECORD_DYNAMIC with enchantment");
|
||||
|
||||
recordsType = mwmp::RECORD_TYPE::ENCHANTMENT;
|
||||
|
||||
|
@ -267,7 +267,7 @@ void Worldstate::sendPotionRecord(const ESM::Potion* potion)
|
|||
{
|
||||
potionRecords.clear();
|
||||
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Sending ID_RECORD_DYNAMIC with potion %s", potion->mName.c_str());
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Sending ID_RECORD_DYNAMIC with potion %s", potion->mName.c_str());
|
||||
|
||||
recordsType = mwmp::RECORD_TYPE::POTION;
|
||||
|
||||
|
@ -283,7 +283,7 @@ void Worldstate::sendSpellRecord(const ESM::Spell* spell)
|
|||
{
|
||||
spellRecords.clear();
|
||||
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Sending ID_RECORD_DYNAMIC with spell %s", spell->mName.c_str());
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Sending ID_RECORD_DYNAMIC with spell %s", spell->mName.c_str());
|
||||
|
||||
recordsType = mwmp::RECORD_TYPE::SPELL;
|
||||
|
||||
|
@ -299,7 +299,7 @@ void Worldstate::sendArmorRecord(const ESM::Armor* armor, std::string baseId)
|
|||
{
|
||||
armorRecords.clear();
|
||||
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Sending ID_RECORD_DYNAMIC with armor %s", armor->mName.c_str());
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Sending ID_RECORD_DYNAMIC with armor %s", armor->mName.c_str());
|
||||
|
||||
recordsType = mwmp::RECORD_TYPE::ARMOR;
|
||||
|
||||
|
@ -319,7 +319,7 @@ void Worldstate::sendBookRecord(const ESM::Book* book, std::string baseId)
|
|||
{
|
||||
bookRecords.clear();
|
||||
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Sending ID_RECORD_DYNAMIC with book %s", book->mName.c_str());
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Sending ID_RECORD_DYNAMIC with book %s", book->mName.c_str());
|
||||
|
||||
recordsType = mwmp::RECORD_TYPE::BOOK;
|
||||
|
||||
|
@ -339,7 +339,7 @@ void Worldstate::sendClothingRecord(const ESM::Clothing* clothing, std::string b
|
|||
{
|
||||
clothingRecords.clear();
|
||||
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Sending ID_RECORD_DYNAMIC with clothing %s", clothing->mName.c_str());
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Sending ID_RECORD_DYNAMIC with clothing %s", clothing->mName.c_str());
|
||||
|
||||
recordsType = mwmp::RECORD_TYPE::CLOTHING;
|
||||
|
||||
|
@ -359,7 +359,7 @@ void Worldstate::sendWeaponRecord(const ESM::Weapon* weapon, std::string baseId)
|
|||
{
|
||||
weaponRecords.clear();
|
||||
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Sending ID_RECORD_DYNAMIC with weapon %s", weapon->mName.c_str());
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Sending ID_RECORD_DYNAMIC with weapon %s", weapon->mName.c_str());
|
||||
|
||||
recordsType = mwmp::RECORD_TYPE::WEAPON;
|
||||
|
||||
|
|
|
@ -89,7 +89,7 @@
|
|||
|
||||
#include "WorldstateProcessor.hpp"
|
||||
#include "worldstate/ProcessorCellCreate.hpp"
|
||||
#include "worldstate/ProcessorCellReset.hpp"
|
||||
#include "worldstate/ProcessorCellReplace.hpp"
|
||||
#include "worldstate/ProcessorRecordDynamic.hpp"
|
||||
#include "worldstate/ProcessorWorldCollisionOverride.hpp"
|
||||
#include "worldstate/ProcessorWorldMap.hpp"
|
||||
|
@ -186,7 +186,7 @@ void ProcessorInitializer()
|
|||
ActorProcessor::AddProcessor(new ProcessorActorTest());
|
||||
|
||||
WorldstateProcessor::AddProcessor(new ProcessorCellCreate());
|
||||
WorldstateProcessor::AddProcessor(new ProcessorCellReset());
|
||||
WorldstateProcessor::AddProcessor(new ProcessorCellReplace());
|
||||
WorldstateProcessor::AddProcessor(new ProcessorRecordDynamic());
|
||||
WorldstateProcessor::AddProcessor(new ProcessorWorldCollisionOverride());
|
||||
WorldstateProcessor::AddProcessor(new ProcessorWorldMap());
|
||||
|
|
|
@ -28,7 +28,7 @@ namespace mwmp
|
|||
|
||||
if (!isRequest())
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "- refId: %s, count: %i, charge: %i, enchantmentCharge: %f, soul: %s",
|
||||
LOG_APPEND(Log::LOG_INFO, "- refId: %s, count: %i, charge: %f, enchantmentCharge: %f, soul: %s",
|
||||
player->usedItem.refId.c_str(), player->usedItem.count, player->usedItem.charge,
|
||||
player->usedItem.enchantmentCharge, player->usedItem.soul.c_str());
|
||||
|
||||
|
@ -36,11 +36,7 @@ namespace mwmp
|
|||
MWWorld::InventoryStore &inventoryStore = playerPtr.getClass().getInventoryStore(playerPtr);
|
||||
|
||||
MWWorld::Ptr itemPtr = MechanicsHelper::getItemPtrFromStore(player->usedItem, inventoryStore);
|
||||
|
||||
if (itemPtr)
|
||||
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->useItem(itemPtr);
|
||||
else
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Cannot use non-existent item %s", player->usedItem.refId.c_str());
|
||||
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->useItem(itemPtr);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
#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
|
|
@ -1,23 +0,0 @@
|
|||
#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
|
|
@ -80,24 +80,18 @@ namespace MWScript
|
|||
/*
|
||||
Start of tes3mp change (major)
|
||||
|
||||
Allow unilateral item removal on this client from client scripts and dialogue (but not console commands)
|
||||
to prevent infinite loops in certain mods. Otherwise, expect the server's reply to our packet to do the
|
||||
removal instead, except for changes to player inventories which still require the PlayerInventory to be
|
||||
reworked.
|
||||
Disable unilateral item addition on this client and expect the server's reply to our
|
||||
packet to do it instead, except for changes to player inventories which still require
|
||||
the PlayerInventory to be reworked
|
||||
*/
|
||||
unsigned char packetOrigin = ScriptController::getPacketOriginFromContextType(runtime.getContext().getContextType());
|
||||
|
||||
MWWorld::Ptr itemPtr;
|
||||
|
||||
if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr() || packetOrigin != mwmp::CLIENT_CONSOLE)
|
||||
itemPtr = *ptr.getClass().getContainerStore(ptr).add(item, count, ptr);
|
||||
// Spawn a messagebox (only for items added to player's inventory and if player is talking to someone)
|
||||
if (ptr == MWBase::Environment::get().getWorld ()->getPlayerPtr() )
|
||||
{
|
||||
MWWorld::Ptr itemPtr = *ptr.getClass().getContainerStore(ptr).add(item, count, ptr);
|
||||
/*
|
||||
End of tes3mp change (major)
|
||||
*/
|
||||
|
||||
// Spawn a messagebox (only for items added to player's inventory and if player is talking to someone)
|
||||
if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr())
|
||||
{
|
||||
// The two GMST entries below expand to strings informing the player of what, and how many of it has been added to their inventory
|
||||
std::string msgBox;
|
||||
std::string itemName = itemPtr.getClass().getName(itemPtr);
|
||||
|
@ -119,12 +113,11 @@ namespace MWScript
|
|||
Send an ID_CONTAINER packet every time an item is added to a Ptr
|
||||
that doesn't belong to a DedicatedPlayer
|
||||
*/
|
||||
else if (mwmp::Main::get().getLocalPlayer()->isLoggedIn() &&
|
||||
(!ptr.getClass().isActor() || !mwmp::PlayerList::isDedicatedPlayer(ptr)))
|
||||
else if (!ptr.getClass().isActor() || !mwmp::PlayerList::isDedicatedPlayer(ptr))
|
||||
{
|
||||
mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList();
|
||||
objectList->reset();
|
||||
objectList->packetOrigin = packetOrigin;
|
||||
objectList->packetOrigin = ScriptController::getPacketOriginFromContextType(runtime.getContext().getContextType());
|
||||
objectList->cell = *ptr.getCell()->getCell();
|
||||
objectList->action = mwmp::BaseObjectList::ADD;
|
||||
objectList->containerSubAction = mwmp::BaseObjectList::NONE;
|
||||
|
@ -209,15 +202,13 @@ namespace MWScript
|
|||
/*
|
||||
Start of tes3mp change (major)
|
||||
|
||||
Allow unilateral item removal on this client from client scripts and dialogue (but not console commands)
|
||||
to prevent infinite loops in certain mods. Otherwise, expect the server's reply to our packet to do the
|
||||
removal instead, except for changes to player inventories which still require the PlayerInventory to be
|
||||
reworked.
|
||||
Disable unilateral item removal on this client and expect the server's reply to our
|
||||
packet to do it instead, except for changes to player inventories which still require
|
||||
the PlayerInventory to be reworked
|
||||
*/
|
||||
unsigned char packetOrigin = ScriptController::getPacketOriginFromContextType(runtime.getContext().getContextType());
|
||||
int numRemoved = 0;
|
||||
|
||||
if (ptr == MWMechanics::getPlayer() || packetOrigin != mwmp::CLIENT_CONSOLE)
|
||||
if (ptr == MWMechanics::getPlayer())
|
||||
numRemoved = store.remove(item, count, ptr);
|
||||
|
||||
// Spawn a messagebox (only for items removed from player's inventory)
|
||||
|
@ -249,12 +240,11 @@ namespace MWScript
|
|||
Send an ID_CONTAINER packet every time an item is removed from a Ptr
|
||||
that doesn't belong to a DedicatedPlayer
|
||||
*/
|
||||
else if (mwmp::Main::get().getLocalPlayer()->isLoggedIn() &&
|
||||
(!ptr.getClass().isActor() || !mwmp::PlayerList::isDedicatedPlayer(ptr)))
|
||||
else if (!ptr.getClass().isActor() || !mwmp::PlayerList::isDedicatedPlayer(ptr))
|
||||
{
|
||||
mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList();
|
||||
objectList->reset();
|
||||
objectList->packetOrigin = packetOrigin;
|
||||
objectList->packetOrigin = ScriptController::getPacketOriginFromContextType(runtime.getContext().getContextType());
|
||||
objectList->cell = *ptr.getCell()->getCell();
|
||||
objectList->action = mwmp::BaseObjectList::REMOVE;
|
||||
objectList->containerSubAction = mwmp::BaseObjectList::NONE;
|
||||
|
|
|
@ -63,7 +63,7 @@ namespace MWScript
|
|||
Send an ID_PLAYER_JOURNAL packet every time a new journal entry is added
|
||||
through a script
|
||||
*/
|
||||
if (mwmp::Main::get().getLocalPlayer()->isLoggedIn() && !MWBase::Environment::get().getJournal()->hasEntry(quest, index))
|
||||
if (!MWBase::Environment::get().getJournal()->hasEntry(quest, index))
|
||||
mwmp::Main::get().getLocalPlayer()->sendJournalEntry(quest, index, ptr);
|
||||
/*
|
||||
End of tes3mp addition
|
||||
|
@ -99,8 +99,7 @@ namespace MWScript
|
|||
Send an ID_PLAYER_JOURNAL packet every time a journal index is set
|
||||
through a script
|
||||
*/
|
||||
if (mwmp::Main::get().getLocalPlayer()->isLoggedIn())
|
||||
mwmp::Main::get().getLocalPlayer()->sendJournalIndex(quest, index);
|
||||
mwmp::Main::get().getLocalPlayer()->sendJournalIndex(quest, index);
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
|
@ -138,8 +137,7 @@ namespace MWScript
|
|||
Send an ID_PLAYER_TOPIC packet every time a new topic is added
|
||||
through a script
|
||||
*/
|
||||
if (mwmp::Main::get().getLocalPlayer()->isLoggedIn() &&
|
||||
MWBase::Environment::get().getDialogueManager()->isNewTopic(Misc::StringUtils::lowerCase(topic)))
|
||||
if (MWBase::Environment::get().getDialogueManager()->isNewTopic(Misc::StringUtils::lowerCase(topic)))
|
||||
mwmp::Main::get().getLocalPlayer()->sendTopic(Misc::StringUtils::lowerCase(topic));
|
||||
/*
|
||||
End of tes3mp addition
|
||||
|
|
|
@ -613,17 +613,13 @@ namespace MWScript
|
|||
Start of tes3mp addition
|
||||
|
||||
Send an ID_OBJECT_STATE packet whenever an object is enabled, as long as
|
||||
the player is logged in on the server, the object is still disabled, and our last
|
||||
packet regarding its state did not already attempt to enable it (to prevent
|
||||
packet spam)
|
||||
the player has finished character generation and the object wasn't already
|
||||
enabled previously
|
||||
*/
|
||||
if (mwmp::Main::get().getLocalPlayer()->isLoggedIn())
|
||||
if (mwmp::Main::get().getLocalPlayer()->hasFinishedCharGen())
|
||||
{
|
||||
if (ref.isInCell() && !ref.getRefData().isEnabled() &&
|
||||
ref.getRefData().getLastCommunicatedState() != MWWorld::RefData::StateCommunication::Enabled)
|
||||
if (ref.isInCell() && !ref.getRefData().isEnabled())
|
||||
{
|
||||
ref.getRefData().setLastCommunicatedState(MWWorld::RefData::StateCommunication::Enabled);
|
||||
|
||||
mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList();
|
||||
objectList->reset();
|
||||
objectList->packetOrigin = ScriptController::getPacketOriginFromContextType(getContextType());
|
||||
|
@ -654,18 +650,14 @@ namespace MWScript
|
|||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Send an ID_OBJECT_STATE packet whenever an object should be disabled, as long as
|
||||
the player is logged in on the server, the object is still enabled, and our last
|
||||
packet regarding its state did not already attempt to disable it (to prevent
|
||||
packet spam)
|
||||
Send an ID_OBJECT_STATE packet whenever an object is disabled, as long as
|
||||
the player has finished character generation and the object wasn't already
|
||||
disabled previously
|
||||
*/
|
||||
if (mwmp::Main::get().getLocalPlayer()->isLoggedIn())
|
||||
if (mwmp::Main::get().getLocalPlayer()->hasFinishedCharGen())
|
||||
{
|
||||
if (ref.isInCell() && ref.getRefData().isEnabled() &&
|
||||
ref.getRefData().getLastCommunicatedState() != MWWorld::RefData::StateCommunication::Disabled)
|
||||
if (ref.isInCell() && ref.getRefData().isEnabled())
|
||||
{
|
||||
ref.getRefData().setLastCommunicatedState(MWWorld::RefData::StateCommunication::Disabled);
|
||||
|
||||
mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList();
|
||||
objectList->reset();
|
||||
objectList->packetOrigin = ScriptController::getPacketOriginFromContextType(getContextType());
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
*/
|
||||
#include "../mwmp/Main.hpp"
|
||||
#include "../mwmp/Networking.hpp"
|
||||
#include "../mwmp/LocalPlayer.hpp"
|
||||
#include "../mwmp/ObjectList.hpp"
|
||||
#include "../mwmp/ScriptController.hpp"
|
||||
/*
|
||||
|
@ -106,14 +105,11 @@ namespace MWScript
|
|||
Send an ID_VIDEO_PLAY packet every time a video is played
|
||||
through a script
|
||||
*/
|
||||
if (mwmp::Main::get().getLocalPlayer()->isLoggedIn())
|
||||
{
|
||||
mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList();
|
||||
objectList->reset();
|
||||
objectList->packetOrigin = ScriptController::getPacketOriginFromContextType(runtime.getContext().getContextType());
|
||||
objectList->addVideoPlay(name, allowSkipping);
|
||||
objectList->sendVideoPlay();
|
||||
}
|
||||
mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList();
|
||||
objectList->reset();
|
||||
objectList->packetOrigin = ScriptController::getPacketOriginFromContextType(runtime.getContext().getContextType());
|
||||
objectList->addVideoPlay(name, allowSkipping);
|
||||
objectList->sendVideoPlay();
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
|
@ -220,14 +216,11 @@ namespace MWScript
|
|||
Send an ID_OBJECT_LOCK packet every time an object is locked
|
||||
through a script
|
||||
*/
|
||||
if (mwmp::Main::get().getLocalPlayer()->isLoggedIn())
|
||||
{
|
||||
mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList();
|
||||
objectList->reset();
|
||||
objectList->packetOrigin = ScriptController::getPacketOriginFromContextType(runtime.getContext().getContextType());
|
||||
objectList->addObjectLock(ptr, lockLevel);
|
||||
objectList->sendObjectLock();
|
||||
}
|
||||
mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList();
|
||||
objectList->reset();
|
||||
objectList->packetOrigin = ScriptController::getPacketOriginFromContextType(runtime.getContext().getContextType());
|
||||
objectList->addObjectLock(ptr, lockLevel);
|
||||
objectList->sendObjectLock();
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
|
@ -273,14 +266,11 @@ namespace MWScript
|
|||
Send an ID_OBJECT_LOCK packet every time an object is unlocked
|
||||
through a script
|
||||
*/
|
||||
if (mwmp::Main::get().getLocalPlayer()->isLoggedIn())
|
||||
{
|
||||
mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList();
|
||||
objectList->reset();
|
||||
objectList->packetOrigin = ScriptController::getPacketOriginFromContextType(runtime.getContext().getContextType());
|
||||
objectList->addObjectLock(ptr, 0);
|
||||
objectList->sendObjectLock();
|
||||
}
|
||||
mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList();
|
||||
objectList->reset();
|
||||
objectList->packetOrigin = ScriptController::getPacketOriginFromContextType(runtime.getContext().getContextType());
|
||||
objectList->addObjectLock(ptr, 0);
|
||||
objectList->sendObjectLock();
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
|
@ -780,14 +770,11 @@ namespace MWScript
|
|||
Send an ID_OBJECT_DELETE packet every time an object is deleted
|
||||
through a script
|
||||
*/
|
||||
if (mwmp::Main::get().getLocalPlayer()->isLoggedIn())
|
||||
{
|
||||
mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList();
|
||||
objectList->reset();
|
||||
objectList->packetOrigin = ScriptController::getPacketOriginFromContextType(runtime.getContext().getContextType());
|
||||
objectList->addObjectDelete(ptr);
|
||||
objectList->sendObjectDelete();
|
||||
}
|
||||
mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList();
|
||||
objectList->reset();
|
||||
objectList->packetOrigin = ScriptController::getPacketOriginFromContextType(runtime.getContext().getContextType());
|
||||
objectList->addObjectDelete(ptr);
|
||||
objectList->sendObjectDelete();
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
|
|
|
@ -470,24 +470,18 @@ namespace MWScript
|
|||
// make sure a spell with this ID actually exists.
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find (id);
|
||||
|
||||
ptr.getClass().getCreatureStats (ptr).getSpells().add (id);
|
||||
|
||||
/*
|
||||
Start of tes3mp change (major)
|
||||
Start of tes3mp addition
|
||||
|
||||
Only add the spell if the target doesn't already have it
|
||||
|
||||
Send an ID_PLAYER_SPELLBOOK packet every time a player gains a spell here
|
||||
Send an ID_PLAYER_SPELLBOOK packet every time a player gains a spell
|
||||
through a script
|
||||
*/
|
||||
MWMechanics::Spells &spells = ptr.getClass().getCreatureStats(ptr).getSpells();
|
||||
|
||||
if (!spells.hasSpell(id))
|
||||
{
|
||||
spells.add(id);
|
||||
|
||||
if (mwmp::Main::get().getLocalPlayer()->isLoggedIn() && ptr == MWMechanics::getPlayer())
|
||||
mwmp::Main::get().getLocalPlayer()->sendSpellChange(id, mwmp::SpellbookChanges::ADD);
|
||||
}
|
||||
if (ptr == MWMechanics::getPlayer())
|
||||
mwmp::Main::get().getLocalPlayer()->sendSpellChange(id, mwmp::SpellbookChanges::ADD);
|
||||
/*
|
||||
End of tes3mp change (major)
|
||||
End of tes3mp addition
|
||||
*/
|
||||
}
|
||||
};
|
||||
|
@ -504,32 +498,26 @@ namespace MWScript
|
|||
std::string id = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
|
||||
/*
|
||||
Start of tes3mp change (major)
|
||||
ptr.getClass().getCreatureStats (ptr).getSpells().remove (id);
|
||||
|
||||
Only remove the spell if the target has it
|
||||
MWBase::WindowManager *wm = MWBase::Environment::get().getWindowManager();
|
||||
|
||||
Send an ID_PLAYER_SPELLBOOK packet every time a player loses a spell here
|
||||
*/
|
||||
MWMechanics::Spells &spells = ptr.getClass().getCreatureStats(ptr).getSpells();
|
||||
|
||||
if (spells.hasSpell(id))
|
||||
if (ptr == MWMechanics::getPlayer() &&
|
||||
id == wm->getSelectedSpell())
|
||||
{
|
||||
ptr.getClass().getCreatureStats(ptr).getSpells().remove(id);
|
||||
|
||||
if (ptr == MWMechanics::getPlayer())
|
||||
{
|
||||
MWBase::WindowManager *wm = MWBase::Environment::get().getWindowManager();
|
||||
|
||||
if (id == wm->getSelectedSpell())
|
||||
wm->unsetSelectedSpell();
|
||||
|
||||
if (mwmp::Main::get().getLocalPlayer()->isLoggedIn())
|
||||
mwmp::Main::get().getLocalPlayer()->sendSpellChange(id, mwmp::SpellbookChanges::REMOVE);
|
||||
}
|
||||
wm->unsetSelectedSpell();
|
||||
}
|
||||
|
||||
/*
|
||||
End of tes3mp change (major)
|
||||
Start of tes3mp addition
|
||||
|
||||
Send an ID_PLAYER_SPELLBOOK packet every time a player loses a spell
|
||||
through a script
|
||||
*/
|
||||
if (ptr == MWMechanics::getPlayer())
|
||||
mwmp::Main::get().getLocalPlayer()->sendSpellChange(id, mwmp::SpellbookChanges::REMOVE);
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
}
|
||||
};
|
||||
|
|
|
@ -63,14 +63,15 @@ namespace MWScript
|
|||
|
||||
Prevent players from changing their own scale
|
||||
|
||||
Send an ID_OBJECT_SCALE every time an object's scale is changed through a script
|
||||
Send an ID_OBJECT_SCALE every time an object's
|
||||
scale is changed through a script
|
||||
*/
|
||||
if (ptr == MWMechanics::getPlayer())
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->
|
||||
messageBox("You can't change your own scale in multiplayer. Only the server can.");
|
||||
}
|
||||
else if (mwmp::Main::get().getLocalPlayer()->isLoggedIn() && ptr.isInCell() && ptr.getCellRef().getScale() != scale)
|
||||
else if (ptr.isInCell() && ptr.getCellRef().getScale() != scale)
|
||||
{
|
||||
// Ignore attempts to change another player's scale
|
||||
if (mwmp::PlayerList::isDedicatedPlayer(ptr))
|
||||
|
@ -503,44 +504,6 @@ namespace MWScript
|
|||
ref.getPtr().getCellRef().setPosition(pos);
|
||||
MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->placeObject(ref.getPtr(),store,pos);
|
||||
placed.getClass().adjustPosition(placed, true);
|
||||
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Send an ID_OBJECT_PLACE or ID_OBJECT_SPAWN packet every time an object is placed
|
||||
in the world through a script
|
||||
*/
|
||||
if (mwmp::Main::get().getLocalPlayer()->isLoggedIn())
|
||||
{
|
||||
mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList();
|
||||
objectList->reset();
|
||||
objectList->packetOrigin = ScriptController::getPacketOriginFromContextType(runtime.getContext().getContextType());
|
||||
|
||||
if (placed.getClass().isActor())
|
||||
{
|
||||
objectList->addObjectSpawn(placed);
|
||||
objectList->sendObjectSpawn();
|
||||
}
|
||||
else
|
||||
{
|
||||
objectList->addObjectPlace(placed);
|
||||
objectList->sendObjectPlace();
|
||||
}
|
||||
}
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
|
||||
/*
|
||||
Start of tes3mp change (major)
|
||||
|
||||
Instead of actually keeping this object as is, delete it after sending the packet
|
||||
and wait for the server to send it back with a unique mpNum of its own
|
||||
*/
|
||||
MWBase::Environment::get().getWorld()->deleteObject(placed);
|
||||
/*
|
||||
End of tes3mp change (major)
|
||||
*/
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -589,44 +552,6 @@ namespace MWScript
|
|||
ref.getPtr().getCellRef().setPosition(pos);
|
||||
MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->placeObject(ref.getPtr(),store,pos);
|
||||
placed.getClass().adjustPosition(placed, true);
|
||||
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Send an ID_OBJECT_PLACE or ID_OBJECT_SPAWN packet every time an object is placed
|
||||
in the world through a script
|
||||
*/
|
||||
if (mwmp::Main::get().getLocalPlayer()->isLoggedIn())
|
||||
{
|
||||
mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList();
|
||||
objectList->reset();
|
||||
objectList->packetOrigin = ScriptController::getPacketOriginFromContextType(runtime.getContext().getContextType());
|
||||
|
||||
if (placed.getClass().isActor())
|
||||
{
|
||||
objectList->addObjectSpawn(placed);
|
||||
objectList->sendObjectSpawn();
|
||||
}
|
||||
else
|
||||
{
|
||||
objectList->addObjectPlace(placed);
|
||||
objectList->sendObjectPlace();
|
||||
}
|
||||
}
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
|
||||
/*
|
||||
Start of tes3mp change (major)
|
||||
|
||||
Instead of actually keeping this object as is, delete it after sending the packet
|
||||
and wait for the server to send it back with a unique mpNum of its own
|
||||
*/
|
||||
MWBase::Environment::get().getWorld()->deleteObject(placed);
|
||||
/*
|
||||
End of tes3mp change (major)
|
||||
*/
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -674,22 +599,19 @@ namespace MWScript
|
|||
Send an ID_OBJECT_PLACE or ID_OBJECT_SPAWN packet every time an object is placed
|
||||
in the world through a script
|
||||
*/
|
||||
if (mwmp::Main::get().getLocalPlayer()->isLoggedIn())
|
||||
{
|
||||
mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList();
|
||||
objectList->reset();
|
||||
objectList->packetOrigin = ScriptController::getPacketOriginFromContextType(runtime.getContext().getContextType());
|
||||
mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList();
|
||||
objectList->reset();
|
||||
objectList->packetOrigin = ScriptController::getPacketOriginFromContextType(runtime.getContext().getContextType());
|
||||
|
||||
if (ptr.getClass().isActor())
|
||||
{
|
||||
objectList->addObjectSpawn(ptr);
|
||||
objectList->sendObjectSpawn();
|
||||
}
|
||||
else
|
||||
{
|
||||
objectList->addObjectPlace(ptr);
|
||||
objectList->sendObjectPlace();
|
||||
}
|
||||
if (ptr.getClass().isActor())
|
||||
{
|
||||
objectList->addObjectSpawn(ptr);
|
||||
objectList->sendObjectSpawn();
|
||||
}
|
||||
else
|
||||
{
|
||||
objectList->addObjectPlace(ptr);
|
||||
objectList->sendObjectPlace();
|
||||
}
|
||||
/*
|
||||
End of tes3mp addition
|
||||
|
|
|
@ -194,25 +194,6 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::unstack(const Ptr &ptr,
|
|||
if (ptr.getRefData().getCount() <= count)
|
||||
return end();
|
||||
MWWorld::ContainerStoreIterator it = addNewStack(ptr, ptr.getRefData().getCount()-count);
|
||||
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Send an ID_PLAYER_INVENTORY packet every time an item stack gets added for a player here
|
||||
*/
|
||||
Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
|
||||
if (container == player && this == &player.getClass().getContainerStore(player))
|
||||
{
|
||||
mwmp::LocalPlayer *localPlayer = mwmp::Main::get().getLocalPlayer();
|
||||
|
||||
if (!localPlayer->isReceivingInventory)
|
||||
localPlayer->sendItemChange(ptr, ptr.getRefData().getCount() - count, mwmp::InventoryChanges::ADD);
|
||||
}
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
|
||||
const std::string script = it->getClass().getScript(*it);
|
||||
if (!script.empty())
|
||||
MWBase::Environment::get().getWorld()->getLocalScripts().add(script, *it);
|
||||
|
@ -385,18 +366,8 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr
|
|||
item.getRefData().getLocals().setVarByInt(script, "onpcadd", 1);
|
||||
}
|
||||
|
||||
/*
|
||||
Start of tes3mp change (major)
|
||||
|
||||
Disable the listener here because it keeps causing crashes; this should only be
|
||||
a temporary solution that doesn't affect much anyway given that the listener is
|
||||
only used in relation to light-emitting items
|
||||
*/
|
||||
//if (mListener)
|
||||
// mListener->itemAdded(item, count);
|
||||
/*
|
||||
End of tes3mp change (major)
|
||||
*/
|
||||
if (mListener)
|
||||
mListener->itemAdded(item, count);
|
||||
|
||||
return it;
|
||||
}
|
||||
|
@ -522,18 +493,8 @@ int MWWorld::ContainerStore::remove(const Ptr& item, int count, const Ptr& actor
|
|||
|
||||
flagAsModified();
|
||||
|
||||
/*
|
||||
Start of tes3mp change (major)
|
||||
|
||||
Disable the listener here because it keeps causing crashes; this should only be
|
||||
a temporary solution that doesn't affect much anyway given that the listener is
|
||||
only used in relation to light-emitting items
|
||||
*/
|
||||
//if (mListener)
|
||||
// mListener->itemRemoved(item, count - toRemove);
|
||||
/*
|
||||
End of tes3mp change (major)
|
||||
*/
|
||||
if (mListener)
|
||||
mListener->itemRemoved(item, count - toRemove);
|
||||
|
||||
// number of removed items
|
||||
return count - toRemove;
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
Include additional headers for multiplayer purposes
|
||||
*/
|
||||
#include <components/openmw-mp/Log.hpp>
|
||||
#include "../mwmp/Main.hpp"
|
||||
#include "../mwmp/CellController.hpp"
|
||||
#include "../mwmp/PlayerList.hpp"
|
||||
|
@ -252,19 +251,7 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::findSlot (int slot) con
|
|||
{
|
||||
// Object has been deleted
|
||||
// This should no longer happen, since the new remove function will unequip first
|
||||
|
||||
/*
|
||||
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)
|
||||
*/
|
||||
throw std::runtime_error("Invalid slot, make sure you are not calling RefData::setCount for a container object");
|
||||
}
|
||||
|
||||
return mSlots[slot];
|
||||
|
|
|
@ -138,34 +138,6 @@ namespace MWWorld
|
|||
|
||||
const ESM::AnimationState& getAnimationState() const;
|
||||
ESM::AnimationState& getAnimationState();
|
||||
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Track the last state communicated to the server for this reference,
|
||||
to avoid packet spam when the server denies our state change request or
|
||||
is slow to reply
|
||||
*/
|
||||
enum StateCommunication
|
||||
{
|
||||
None = 0,
|
||||
Enabled = 1,
|
||||
Disabled = 2
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
short mLastCommunicatedState = StateCommunication::None;
|
||||
|
||||
public:
|
||||
|
||||
short getLastCommunicatedState() { return mLastCommunicatedState; };
|
||||
|
||||
void setLastCommunicatedState(short communicationState) { mLastCommunicatedState = communicationState; };
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -489,9 +489,9 @@ namespace MWWorld
|
|||
Start of tes3mp addition
|
||||
|
||||
Send an ID_PLAYER_CELL_STATE packet with all cell states stored in LocalPlayer
|
||||
and then clear them, but only if the player is logged in on the server
|
||||
and then clear them, but only if the player has finished character generation
|
||||
*/
|
||||
if (mwmp::Main::get().getLocalPlayer()->isLoggedIn())
|
||||
if (mwmp::Main::get().getLocalPlayer()->hasFinishedCharGen())
|
||||
{
|
||||
mwmp::Main::get().getLocalPlayer()->sendCellStates();
|
||||
mwmp::Main::get().getLocalPlayer()->clearCellStates();
|
||||
|
@ -631,9 +631,9 @@ namespace MWWorld
|
|||
Start of tes3mp addition
|
||||
|
||||
Send an ID_PLAYER_CELL_STATE packet with all cell states stored in LocalPlayer
|
||||
and then clear them, but only if the player is logged in on the server
|
||||
and then clear them, but only if the player has finished character generation
|
||||
*/
|
||||
if (mwmp::Main::get().getLocalPlayer()->isLoggedIn())
|
||||
if (mwmp::Main::get().getLocalPlayer()->hasFinishedCharGen())
|
||||
{
|
||||
mwmp::Main::get().getLocalPlayer()->sendCellStates();
|
||||
mwmp::Main::get().getLocalPlayer()->clearCellStates();
|
||||
|
|
|
@ -282,16 +282,24 @@ namespace MWWorld
|
|||
/*
|
||||
Start of tes3mp change (major)
|
||||
|
||||
Spawn at 0, -7 by default
|
||||
If Pelagiad exists, spawn there; otherwise, spawn at 0 ,0
|
||||
*/
|
||||
const int cellSize = 8192;
|
||||
pos.pos[0] = cellSize / 2;
|
||||
pos.pos[1] = cellSize * -7 + cellSize / 2;
|
||||
pos.pos[2] = 0;
|
||||
pos.rot[0] = 0;
|
||||
pos.rot[1] = 0;
|
||||
pos.rot[2] = 0;
|
||||
mWorldScene->changeToExteriorCell(pos, true);
|
||||
if (findExteriorPosition("Pelagiad", pos))
|
||||
{
|
||||
changeToExteriorCell(pos, true);
|
||||
fixPosition(getPlayerPtr());
|
||||
}
|
||||
else
|
||||
{
|
||||
const int cellSize = 8192;
|
||||
pos.pos[0] = cellSize / 2;
|
||||
pos.pos[1] = cellSize / 2;
|
||||
pos.pos[2] = 0;
|
||||
pos.rot[0] = 0;
|
||||
pos.rot[1] = 0;
|
||||
pos.rot[2] = 0;
|
||||
mWorldScene->changeToExteriorCell(pos, true);
|
||||
}
|
||||
/*
|
||||
End of tes3mp change (major)
|
||||
*/
|
||||
|
@ -3258,11 +3266,10 @@ namespace MWWorld
|
|||
|
||||
If this actor is a LocalPlayer or LocalActor, get their Attack and prepare
|
||||
it for sending
|
||||
|
||||
Set the attack details before going through with the casting, in case it's
|
||||
a one use item that would get removed through the casting (like a scroll)
|
||||
*/
|
||||
{
|
||||
cast.cast(*inv.getSelectedEnchantItem());
|
||||
|
||||
mwmp::Attack *localAttack = MechanicsHelper::getLocalAttack(actor);
|
||||
|
||||
if (localAttack)
|
||||
|
@ -3272,8 +3279,6 @@ namespace MWWorld
|
|||
localAttack->itemId = inv.getSelectedEnchantItem()->getCellRef().getRefId();
|
||||
localAttack->shouldSend = true;
|
||||
}
|
||||
|
||||
cast.cast(*inv.getSelectedEnchantItem());
|
||||
}
|
||||
/*
|
||||
End of tes3mp addition
|
||||
|
|
|
@ -202,7 +202,7 @@ add_component_dir (openmw-mp/Packets/Object
|
|||
add_component_dir (openmw-mp/Packets/Worldstate
|
||||
WorldstatePacket
|
||||
|
||||
PacketCellCreate PacketCellReset PacketRecordDynamic PacketWorldCollisionOverride PacketWorldMap
|
||||
PacketCellCreate PacketCellReplace PacketRecordDynamic PacketWorldCollisionOverride PacketWorldMap
|
||||
PacketWorldRegionAuthority PacketWorldTime PacketWorldWeather
|
||||
)
|
||||
|
||||
|
|
|
@ -232,8 +232,6 @@ namespace mwmp
|
|||
}
|
||||
|
||||
RakNet::RakNetGUID guid;
|
||||
std::string serverPassword;
|
||||
|
||||
GUIMessageBox guiMessageBox;
|
||||
|
||||
// Track only the indexes of the attributes that have been changed,
|
||||
|
@ -297,6 +295,7 @@ namespace mwmp
|
|||
std::string birthsign;
|
||||
std::string chatMessage;
|
||||
CharGenState charGenState;
|
||||
std::string passw;
|
||||
|
||||
std::string sound;
|
||||
Animation animation;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include "../Packets/Worldstate/PacketCellCreate.hpp"
|
||||
#include "../Packets/Worldstate/PacketCellReset.hpp"
|
||||
#include "../Packets/Worldstate/PacketCellReplace.hpp"
|
||||
#include "../Packets/Worldstate/PacketRecordDynamic.hpp"
|
||||
#include "../Packets/Worldstate/PacketWorldCollisionOverride.hpp"
|
||||
#include "../Packets/Worldstate/PacketWorldMap.hpp"
|
||||
|
@ -20,7 +20,7 @@ inline void AddPacket(mwmp::WorldstatePacketController::packets_t *packets, RakN
|
|||
mwmp::WorldstatePacketController::WorldstatePacketController(RakNet::RakPeerInterface *peer)
|
||||
{
|
||||
AddPacket<PacketCellCreate>(&packets, peer);
|
||||
AddPacket<PacketCellReset>(&packets, peer);
|
||||
AddPacket<PacketCellReplace>(&packets, peer);
|
||||
AddPacket<PacketRecordDynamic>(&packets, peer);
|
||||
AddPacket<PacketWorldCollisionOverride>(&packets, peer);
|
||||
AddPacket<PacketWorldMap>(&packets, peer);
|
||||
|
|
|
@ -104,7 +104,7 @@ enum GameMessages
|
|||
ID_GAME_PREINIT,
|
||||
|
||||
ID_CELL_CREATE,
|
||||
ID_CELL_RESET,
|
||||
ID_CELL_REPLACE,
|
||||
ID_RECORD_DYNAMIC,
|
||||
ID_WORLD_COLLISION_OVERRIDE,
|
||||
ID_WORLD_MAP,
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
//
|
||||
// Created by koncord on 28.04.16.
|
||||
//
|
||||
|
||||
#include <components/openmw-mp/NetworkMessages.hpp>
|
||||
#include "PacketHandshake.hpp"
|
||||
|
||||
|
@ -13,8 +17,8 @@ void PacketHandshake::Packet(RakNet::BitStream *bs, bool send)
|
|||
{
|
||||
PlayerPacket::Packet(bs, send);
|
||||
|
||||
if (!RW(player->npc.mName, send, true, maxNameLength) ||
|
||||
!RW(player->serverPassword, send, true, maxPasswordLength))
|
||||
if (!RW(player->npc.mName, send, true, maxNameLen) ||
|
||||
!RW(player->passw, send, true, maxPasswLen))
|
||||
{
|
||||
packetValid = false;
|
||||
return;
|
||||
|
|
|
@ -16,8 +16,8 @@ namespace mwmp
|
|||
|
||||
virtual void Packet(RakNet::BitStream *bs, bool send);
|
||||
|
||||
const static uint32_t maxNameLength = 256;
|
||||
const static uint32_t maxPasswordLength = 256;
|
||||
const static uint32_t maxNameLen = 256;
|
||||
const static uint32_t maxPasswLen = 256;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
#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
|
||||
}
|
|
@ -1,18 +1,18 @@
|
|||
#ifndef OPENMW_PACKETCELLRESET_HPP
|
||||
#define OPENMW_PACKETCELLRESET_HPP
|
||||
#ifndef OPENMW_PACKETCELLREPLACE_HPP
|
||||
#define OPENMW_PACKETCELLREPLACE_HPP
|
||||
|
||||
#include <components/openmw-mp/Packets/Worldstate/WorldstatePacket.hpp>
|
||||
#include <components/openmw-mp/NetworkMessages.hpp>
|
||||
|
||||
namespace mwmp
|
||||
{
|
||||
class PacketCellReset: public WorldstatePacket
|
||||
class PacketCellReplace: public WorldstatePacket
|
||||
{
|
||||
public:
|
||||
PacketCellReset(RakNet::RakPeerInterface *peer);
|
||||
PacketCellReplace(RakNet::RakPeerInterface *peer);
|
||||
|
||||
virtual void Packet(RakNet::BitStream *bs, bool send);
|
||||
};
|
||||
}
|
||||
|
||||
#endif //OPENMW_PACKETCELLRESET_HPP
|
||||
#endif //OPENMW_PACKETCELLREPLACE_HPP
|
|
@ -1,17 +0,0 @@
|
|||
#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
|
||||
}
|
|
@ -117,7 +117,7 @@ std::string Utils::toString(int num)
|
|||
return stream.str();
|
||||
}
|
||||
|
||||
std::string Utils::replaceString(const string& source, const char* find, const char* replace)
|
||||
string Utils::replaceString(const string& source, const char* find, const char* replace)
|
||||
{
|
||||
unsigned int find_len = strlen(find);
|
||||
unsigned int replace_len = strlen(replace);
|
||||
|
@ -175,44 +175,37 @@ unsigned int ::Utils::crc32Checksum(const std::string &file)
|
|||
return crc32.checksum();
|
||||
}
|
||||
|
||||
std::string Utils::getOperatingSystemType()
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return "Windows";
|
||||
#elif defined(__linux)
|
||||
return "Linux";
|
||||
#elif defined(__APPLE__)
|
||||
return "OS X";
|
||||
#else
|
||||
return "Unknown OS";
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string Utils::getArchitectureType()
|
||||
{
|
||||
#if defined(__x86_64__) || defined(_M_X64)
|
||||
return "64-bit";
|
||||
#elif defined(__i386__) || defined(_M_I86) || defined(_M_IX86)
|
||||
return "32-bit";
|
||||
#elif defined(__ARM_ARCH)
|
||||
std::string architectureType = "ARMv" + __ARM_ARCH;
|
||||
#ifdef __aarch64__
|
||||
architectureType = architectureType + " 64-bit";
|
||||
#else
|
||||
architectureType = architectureType + " 32-bit";
|
||||
#endif
|
||||
return architectureType;
|
||||
#else
|
||||
return "Unknown architecture";
|
||||
#endif
|
||||
}
|
||||
|
||||
void Utils::printVersion(std::string appName, std::string version, std::string commitHash, int protocol)
|
||||
{
|
||||
cout << appName << " " << version;
|
||||
cout << " (" << getOperatingSystemType() << " " << getArchitectureType() << ")" << endl;
|
||||
cout << " (";
|
||||
#if defined(_WIN32)
|
||||
cout << "Windows";
|
||||
#elif defined(__linux)
|
||||
cout << "Linux";
|
||||
#elif defined(__APPLE__)
|
||||
cout << "OS X";
|
||||
#else
|
||||
cout << "Unknown OS";
|
||||
#endif
|
||||
cout << " ";
|
||||
#if defined(__x86_64__) || defined(_M_X64)
|
||||
cout << "64-bit";
|
||||
#elif defined(__i386__) || defined(_M_I86)
|
||||
cout << "32-bit";
|
||||
#elif defined(__ARM_ARCH)
|
||||
cout << "ARMv" << __ARM_ARCH << " ";
|
||||
#ifdef __aarch64__
|
||||
cout << "64-bit";
|
||||
#else
|
||||
cout << "32-bit";
|
||||
#endif
|
||||
#else
|
||||
cout << "Unknown architecture";
|
||||
#endif
|
||||
cout << ")" << endl;
|
||||
cout << "Protocol version: " << protocol << endl;
|
||||
cout << "Oldest compatible commit hash: " << commitHash.substr(0, 10) << endl;
|
||||
cout << "Commit hash: " << commitHash.substr(0, 10) << endl;
|
||||
|
||||
cout << "------------------------------------------------------------" << endl;
|
||||
}
|
||||
|
|
|
@ -60,9 +60,6 @@ namespace Utils
|
|||
|
||||
unsigned int crc32Checksum(const std::string &file);
|
||||
|
||||
std::string getOperatingSystemType();
|
||||
std::string getArchitectureType();
|
||||
|
||||
void printVersion(std::string appName, std::string version, std::string commitHash, int protocol);
|
||||
|
||||
void printWithWidth(std::ostringstream &sstr, std::string str, size_t width);
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#define TES3MP_DEFAULT_PASSW "SuperPassword"
|
||||
#define TES3MP_MASTERSERVER_PASSW "12345"
|
||||
|
||||
#define TES3MP_CREDITS_CHECKSUM "BAEFF920"
|
||||
|
||||
#define TES3MP_CREDITS_CHECKSUM "BC39D2E9"
|
||||
|
||||
#endif //OPENMW_VERSION_HPP
|
||||
|
|
|
@ -9,7 +9,7 @@ logLevel = 1
|
|||
password =
|
||||
|
||||
[Plugins]
|
||||
home = ./server
|
||||
home = ~/local/openmw/tes3mp
|
||||
plugins = serverCore.lua
|
||||
|
||||
[MasterServer]
|
||||
|
|
|
@ -4,14 +4,14 @@ tes3mp Credits
|
|||
Programmers
|
||||
----------------
|
||||
|
||||
Stanislav Zhukov (Koncord) - Architecture, networking & scripting systems, player sync, server browser & master server
|
||||
Stanislav Zhukov (Koncord) - Overall architecture, networking & scripting systems, player sync, server browser & master server
|
||||
David Cernat - World, NPC & quest sync, player sync improvements, state saving & loading, extensive bug fixes
|
||||
|
||||
|
||||
Additional programming
|
||||
----------------------
|
||||
|
||||
Grim Kriegor - Linux deployment scripts, Lua teleportation commands, early script fixes
|
||||
Grim Kriegor - Lua teleportation commands, early script fixes
|
||||
Battlerax - Various small fixes
|
||||
|
||||
|
||||
|
@ -26,7 +26,6 @@ Community administrators
|
|||
Community moderators
|
||||
--------------------
|
||||
|
||||
Lysol
|
||||
Michael Fitzmayer (mupf)
|
||||
Nac
|
||||
NicholasAH
|
||||
|
@ -54,7 +53,6 @@ Translation
|
|||
Super special thanks
|
||||
--------------------
|
||||
|
||||
Alexander Ovsyannikov
|
||||
Bret Curtis (psi29a)
|
||||
Gabriel Pascu (iGrebla)
|
||||
greetasdf
|
||||
|
@ -75,9 +73,8 @@ Special thanks
|
|||
Gluka
|
||||
Goodevil
|
||||
Ignatious
|
||||
James Wards of Gore Corps LAN Club (gorecorps.co.nz)
|
||||
James Wards of Gore Corps LAN Club (www.gorecorps.co.nz)
|
||||
Jeremiah
|
||||
Kyle Willey of Loreshaper Games (steempeak.com/@loreshapergames)
|
||||
Lewis Sadlier
|
||||
Luc Keating
|
||||
Michael Zagar (Zoops)
|
||||
|
@ -87,7 +84,6 @@ Special thanks
|
|||
Scorcio
|
||||
Simon Nemes
|
||||
Texafornian
|
||||
Thrud
|
||||
Zaphida
|
||||
All the developers of OpenMW for creating an amazing open source project
|
||||
|
||||
|
|
Loading…
Reference in a new issue