Compare commits

..

2 Commits

Author SHA1 Message Date
hg 4a66c3918a Convert perl apis to perlbind 2022-06-12 19:56:46 -04:00
hg a2c6252c58 Add perlbind library 2022-06-12 19:56:45 -04:00
1300 changed files with 105929 additions and 141747 deletions
+21
View File
@@ -0,0 +1,21 @@
// For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.101.1/containers/ubuntu-18.04-git
{
"name": "Ubuntu 18.04 EQEMU",
// Moved from dockerfile to image so it builds faster
"image": "eqemu/devcontainer:0.0.2",
// Set *default* container specific settings.json values on container create.
"settings": {
"terminal.integrated.shell.linux": "/bin/bash"
},
"runArgs": [ "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined" ],
// Add the IDs of extensions you want installed when the container is created.
"extensions": ["ms-vscode.cpptools", "ms-azuretools.vscode-docker"],
"mounts": ["source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind"],
"remoteEnv": {
"HOST_PROJECT_PATH": "${localWorkspaceFolder}"
}
}
+8 -81
View File
@@ -1,8 +1,7 @@
--- ---
kind: pipeline kind: pipeline
type: docker type: docker
name: Build Linux name: EQEmulator Server Linux CI
# Limits how many of these builds can run on the drone runner at a time, this isn't about cores # Limits how many of these builds can run on the drone runner at a time, this isn't about cores
concurrency: concurrency:
@@ -11,88 +10,16 @@ concurrency:
volumes: volumes:
- name: cache - name: cache
host: host:
path: /var/lib/cache-release path: /var/lib/cache
steps: steps:
- name: Build Linux X64 - name: server-build
image: akkadius/eqemu-server:v11 # Source build script https://github.com/Akkadius/akk-stack/blob/master/containers/eqemu-server/Dockerfile#L20
environment: image: akkadius/eqemu-server:latest
GITHUB_TOKEN:
from_secret: GH_RELEASE_GITHUB_API_TOKEN
RCLONE_CONFIG_REMOTE_TYPE: ftp
RCLONE_FTP_HOST: drone.akkadius.com
RCLONE_FTP_USER: artifacts
RCLONE_FTP_PASS:
from_secret: RCLONE_FTP_PASS
commands: commands:
- ./utils/scripts/build/linux-build.sh - sudo chown eqemu:eqemu /drone/src/ * -R
- sudo chown eqemu:eqemu /home/eqemu/.ccache/ * -R
- git submodule init && git submodule update && mkdir -p build && cd build && cmake -DEQEMU_BUILD_LOGIN=ON -DEQEMU_ENABLE_BOTS=ON -DEQEMU_BUILD_LUA=ON -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING="-O0 -g -DNDEBUG" -G 'Unix Makefiles' .. && make -j$((`nproc`-4))
volumes: volumes:
- name: cache - name: cache
path: /home/eqemu/.ccache/ path: /home/eqemu/.ccache/
---
kind: pipeline
type: exec
name: Build Windows
# Limits how many of these builds can run on the drone runner at a time, this isn't about cores
concurrency:
limit: 1
platform:
os: windows
arch: amd64
steps:
- name: Build Windows X64
environment:
RCLONE_CONFIG_REMOTE_TYPE: ftp
RCLONE_FTP_HOST: drone.akkadius.com
RCLONE_FTP_USER: artifacts
RCLONE_FTP_PASS:
from_secret: RCLONE_FTP_PASS
GITHUB_TOKEN:
from_secret: GH_RELEASE_GITHUB_API_TOKEN
commands:
- .\utils\scripts\build\windows-build.ps1
---
kind: pipeline
type: docker
name: Publish Artifacts to Github
steps:
- name: Upload Artifacts
image: akkadius/eqemu-build-releaser:v3
environment:
RCLONE_CONFIG_REMOTE_TYPE: ftp
RCLONE_FTP_HOST: drone.akkadius.com
RCLONE_FTP_USER: artifacts
RCLONE_FTP_PASS:
from_secret: RCLONE_FTP_PASS
GH_RELEASE_GITHUB_API_TOKEN:
from_secret: GH_RELEASE_GITHUB_API_TOKEN
GITHUB_TOKEN:
from_secret: GH_RELEASE_GITHUB_API_TOKEN
commands:
- ./utils/scripts/build/should-release/should-release
- rclone config create remote ftp env_auth true > /dev/null
- |
rclone copy remote: --include "eqemu-server*.zip" .
- gh-release --assets=eqemu-server-linux-x64.zip,eqemu-server-windows-x64.zip -y
- |
rclone delete remote: --include "eqemu-server*.zip"
trigger:
branch:
- master
event:
- push
depends_on:
- Build Windows
- Build Linux
-15
View File
@@ -56,18 +56,3 @@ bin/
/client_files/**/CMakeFiles/ /client_files/**/CMakeFiles/
.idea .idea
# Clangd Generated Files.
compile_flags.txt
.cache/
# vscode generated settings
.vscode/
# Build pipeline
!utils/scripts/build/
!utils/scripts/build/should-release/should-release
!utils/scripts/build/should-release/should-release.exe
# CMake Files
cmake-build-relwithdebinfo/*
+19
View File
@@ -0,0 +1,19 @@
language: cpp
compiler: gcc
dist: bionic
addons:
apt:
packages:
- libmysqlclient-dev
- libperl-dev
- libboost-dev
- liblua5.1-0-dev
- zlib1g-dev
- uuid-dev
- libssl-dev
script:
- cmake -G "Unix Makefiles" -DEQEMU_BUILD_TESTS=ON -DEQEMU_ENABLE_BOTS=ON -DEQEMU_BUILD_LOGIN=ON
- make -j2
- ./bin/tests
+16
View File
@@ -0,0 +1,16 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"/usr/include/mysql"
],
"defines": [],
"compilerPath": "/usr/bin/gcc",
"cStandard": "c11",
"cppStandard": "c++17"
}
],
"version": 4
}
+164
View File
@@ -0,0 +1,164 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "make",
"type": "shell",
"command": "cd bin && make",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [
"$gcc"
]
},
{
"label": "make clean",
"type": "shell",
"command": "cd bin && make clean",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [
"$gcc"
]
},
{
"label": "cmake",
"type": "shell",
"command": "mkdir -p bin && cd bin && rm CMakeCache.txt && cmake -DEQEMU_BUILD_LOGIN=ON -DEQEMU_BUILD_LUA=ON -G 'Unix Makefiles' ..",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher":{
"owner": "cpp",
"fileLocation": "relative",
"pattern":[
{
"regexp": "([\\w+|\\\\]*\\.\\w+)\\((\\d+)\\)\\: (warning|error) (.*)$",
"file": 1,
"location": 2,
"severity": 3,
"message": 4
}
]
}
},
{
"label": "download maps",
"type": "shell",
"command": "mkdir -p bin && cd bin && wget https://codeload.github.com/Akkadius/EQEmuMaps/zip/master -O maps.zip && unzip -o maps.zip && rm ./maps -rf && mv EQEmuMaps-master maps && rm maps.zip",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [
"$gcc"
]
},
{
"label": "download quests",
"type": "shell",
"command": "mkdir -p bin && cd bin && cd server && git -C ./quests pull 2> /dev/null || git clone https://github.com/ProjectEQ/projecteqquests.git quests",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [
"$gcc"
]
},
{
"label": "download eqemu_config",
"type": "shell",
"command": "mkdir -p bin && cd bin && wget --no-check-certificate https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/eqemu_config_docker.json -O eqemu_config.json",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [
"$gcc"
]
},
{
"label": "rebuild database (mariadb must be started)",
"type": "shell",
"command": "mkdir -p bin && cd bin && docker run -i --rm --privileged -v ${HOST_PROJECT_PATH}/bin:/src --network=eqemu -it eqemu/server:0.0.3 bash -c './eqemu_server.pl source_peq_db && ./eqemu_server.pl check_db_updates && ./eqemu_server.pl linux_login_server_setup'",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [
"$gcc"
]
},
{
"label": "zone 7000",
"type": "shell",
"command": "docker stop zone7000 | true && docker network create eqemu | true && docker run -i --rm --name zone7000 --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --privileged -v ${HOST_PROJECT_PATH}/bin:/src --ulimit core=10000000 --network=eqemu -p 7000:7000/udp -e LD_LIBRARY_PATH=/src/ eqemu/server:0.0.3 gdb -ex run --args ./zone dynamic_zone7000:7000",
"group": {
"kind": "test",
"isDefault": true
}
},
{
"label": "zone 7001",
"type": "shell",
"command": "docker stop zone7001 | true && docker network create eqemu | true && docker run -i --rm --name zone7001 --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --privileged -v ${HOST_PROJECT_PATH}/bin:/src --ulimit core=10000000 --network=eqemu -p 7001:7001/udp -e LD_LIBRARY_PATH=/src/ eqemu/server:0.0.3 gdb -ex run --args ./zone dynamic_zone7001:7001",
"group": {
"kind": "test",
"isDefault": true
}
},
{
"label": "loginserver",
"type": "shell",
"command": "docker stop loginserver | true && docker network create eqemu | true && docker run -i --rm --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --privileged -v ${HOST_PROJECT_PATH}/bin:/src --ulimit core=10000000 --network=eqemu --name loginserver -p 5999:5999/udp -p 5998:5998/udp -e LD_LIBRARY_PATH=/src/ eqemu/server:0.0.3 gdb -ex run --args ./loginserver",
"group": {
"kind": "test",
"isDefault": true
}
},
{
"label": "shared_memory, world",
"type": "shell",
"command": "docker stop sharedmemory | true && docker stop world | true && docker network create eqemu | true && docker run --rm -v ${HOST_PROJECT_PATH}/bin:/src --network=eqemu --name sharedmemory eqemu/server:0.0.3 ./shared_memory && docker run --rm -v ${HOST_PROJECT_PATH}/bin:/src --ulimit core=10000000 -e LD_LIBRARY_PATH=/src/ --network=eqemu --name world -p 9000:9000 -p 9000:9000/udp -p 9001:9001 -p 9080:9080 eqemu/server:0.0.3 gdb -ex run ./world",
"group": {
"kind": "test",
"isDefault": true
}
},
{
"label": "queryserv",
"type": "shell",
"command": "docker stop queryserv | true && docker run --rm -v ${HOST_PROJECT_PATH}/bin:/src --ulimit core=10000000 -e LD_LIBRARY_PATH=/src/ --network=eqemu --name queryserv eqemu/server:0.0.3 gdb -ex run ./queryserv",
"group": {
"kind": "test",
"isDefault": true
}
},
{
"label": "mariadb",
"type": "shell",
"command": "docker stop mariadb | true && cd bin && docker network create eqemu | true && docker run --rm -v ${HOST_PROJECT_PATH}/bin/db:/bitnami/mariadb -p 3306:3306 -e MARIADB_DATABASE=peq -e MARIADB_USER=eqemu -e MARIADB_PASSWORD=eqemupass -e ALLOW_EMPTY_PASSWORD=yes --name mariadb --network=eqemu bitnami/mariadb:latest",
"group": {
"kind": "test",
"isDefault": true
}
},
{
"label": "ucs",
"type": "shell",
"command": "docker stop ucs | true && cd bin && docker network create eqemu | true && docker run --rm -v ${HOST_PROJECT_PATH}/bin:/src -p 7778:7778 --name ucs --network=eqemu eqemu/server:0.0.3 gdb -ex run ./ucs",
"group": {
"kind": "test",
"isDefault": true
}
}
]
}
+2 -2
View File
@@ -40,14 +40,14 @@ Assuming it is starting in c:/projects/eqemu and the x64 dependencies were extra
mkdir build mkdir build
cd build cd build
cmake -G "Visual Studio 15 2017 Win64" -DEQEMU_BUILD_TESTS=ON -DEQEMU_BUILD_LOGIN=ON -DEQEMU_BUILD_ZLIB=ON -DCMAKE_TOOLCHAIN_FILE="c:/projects/eqemu/vcpkg/vcpkg-export-20180828-145455/scripts/buildsystems/vcpkg.cmake" .. cmake -G "Visual Studio 15 2017 Win64" -DEQEMU_BUILD_TESTS=ON -DEQEMU_BUILD_LOGIN=ON -DEQEMU_BUILD_ZLIB=ON -DEQEMU_ENABLE_BOTS=ON -DCMAKE_TOOLCHAIN_FILE="c:/projects/eqemu/vcpkg/vcpkg-export-20180828-145455/scripts/buildsystems/vcpkg.cmake" ..
##### Linux ##### Linux
Similarly to Windows running CMake on Linux is simple it just omits the toolchain file and uses a different generator. Similarly to Windows running CMake on Linux is simple it just omits the toolchain file and uses a different generator.
mkdir build mkdir build
cd build cd build
cmake -G "Unix Makefiles" -DEQEMU_BUILD_TESTS=ON -DEQEMU_BUILD_LOGIN=ON .. cmake -G "Unix Makefiles" -DEQEMU_BUILD_TESTS=ON -DEQEMU_ENABLE_BOTS=ON -DEQEMU_BUILD_LOGIN=ON ..
### Building ### Building
-1465
View File
File diff suppressed because it is too large Load Diff
+12 -6
View File
@@ -1,4 +1,4 @@
CMAKE_MINIMUM_REQUIRED(VERSION 3.12) CMAKE_MINIMUM_REQUIRED(VERSION 3.7)
SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/" ${CMAKE_MODULE_PATH}) SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/" ${CMAKE_MODULE_PATH})
@@ -12,7 +12,7 @@ IF(NOT CMAKE_BUILD_TYPE)
SET(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build." FORCE) SET(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build." FORCE)
ENDIF(NOT CMAKE_BUILD_TYPE) ENDIF(NOT CMAKE_BUILD_TYPE)
SET(CMAKE_CXX_STANDARD 20) SET(CMAKE_CXX_STANDARD 14)
SET(CMAKE_CXX_STANDARD_REQUIRED ON) SET(CMAKE_CXX_STANDARD_REQUIRED ON)
SET(CMAKE_CXX_EXTENSIONS OFF) SET(CMAKE_CXX_EXTENSIONS OFF)
@@ -20,10 +20,8 @@ IF(MSVC)
ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS) ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS)
ADD_DEFINITIONS(-DNOMINMAX) ADD_DEFINITIONS(-DNOMINMAX)
ADD_DEFINITIONS(-DCRASH_LOGGING) ADD_DEFINITIONS(-DCRASH_LOGGING)
ADD_DEFINITIONS(-D_HAS_AUTO_PTR_ETC) # for Luabind on C++17
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
ADD_DEFINITIONS( "/W0 /D_CRT_SECURE_NO_WARNINGS /wd4005 /wd4996 /nologo /Os")
ELSE(MSVC) ELSE(MSVC)
ADD_DEFINITIONS(-DHAS_UNION_SEMUN) ADD_DEFINITIONS(-DHAS_UNION_SEMUN)
ENDIF(MSVC) ENDIF(MSVC)
@@ -123,6 +121,8 @@ ENDIF()
MESSAGE(STATUS "**************************************************") MESSAGE(STATUS "**************************************************")
#options #options
OPTION(EQEMU_DEPOP_INVALIDATES_CACHE "#repop invalidates the npc_types cache (will cause a larger database hit on #repop but is more convienent)." ON)
OPTION(EQEMU_ENABLE_BOTS "Enable Bots" OFF)
OPTION(EQEMU_COMMANDS_LOGGING "Enable GM Command logs" ON) OPTION(EQEMU_COMMANDS_LOGGING "Enable GM Command logs" ON)
OPTION(EQEMU_BUILD_SERVER "Build the game server." ON) OPTION(EQEMU_BUILD_SERVER "Build the game server." ON)
OPTION(EQEMU_BUILD_LOGIN "Build the login server." ON) OPTION(EQEMU_BUILD_LOGIN "Build the login server." ON)
@@ -176,6 +176,10 @@ IF(EQEMU_COMMANDS_LOGGING)
ADD_DEFINITIONS(-DCOMMANDS_LOGGING) ADD_DEFINITIONS(-DCOMMANDS_LOGGING)
ENDIF(EQEMU_COMMANDS_LOGGING) ENDIF(EQEMU_COMMANDS_LOGGING)
IF(EQEMU_ENABLE_BOTS)
ADD_DEFINITIONS(-DBOTS)
ENDIF(EQEMU_ENABLE_BOTS)
#database #database
IF(MySQL_FOUND AND MariaDB_FOUND) IF(MySQL_FOUND AND MariaDB_FOUND)
SET(DATABASE_LIBRARY_SELECTION MariaDB CACHE STRING "Database library to use: SET(DATABASE_LIBRARY_SELECTION MariaDB CACHE STRING "Database library to use:
@@ -336,8 +340,10 @@ INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/submodules/recastnavigat
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/submodules/recastnavigation/Recast/Include") INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/submodules/recastnavigation/Recast/Include")
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/submodules/websocketpp") INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/submodules/websocketpp")
# silence obnoxious deprecation message OPTION(EQEMU_BUILD_LOGGING "Build Logging (To speed up compilation)" ON)
ADD_DEFINITIONS(-DBOOST_BIND_GLOBAL_PLACEHOLDERS) IF(EQEMU_BUILD_LOGGING)
ADD_DEFINITIONS(-DBUILD_LOGGING)
ENDIF()
IF(TLS_LIBRARY_ENABLED) IF(TLS_LIBRARY_ENABLED)
SET(SERVER_LIBS ${SERVER_LIBS} ${TLS_LIBRARY_LIBS}) SET(SERVER_LIBS ${SERVER_LIBS} ${TLS_LIBRARY_LIBS})
+3 -3
View File
@@ -1,7 +1,7 @@
# EQEmulator Core Server # EQEmulator Core Server
| Drone (Linux x64) | Drone (Windows x64) | |Travis CI (Linux)|Appveyor (Windows x86) |Appveyor (Windows x64) |
|:---:|:---:| |:---:|:---:|:---:|
|[![Build Status](http://drone.akkadius.com/api/badges/EQEmu/Server/status.svg)](http://drone.akkadius.com/EQEmu/Server) |[![Build Status](http://drone.akkadius.com/api/badges/EQEmu/Server/status.svg)](http://drone.akkadius.com/EQEmu/Server) | |[![Linux CI](https://travis-ci.org/EQEmu/Server.svg?branch=master)](https://travis-ci.org/EQEmu/Server) |[![Build status](https://ci.appveyor.com/api/projects/status/v3utuu0dttm2cqd0?svg=true)](https://ci.appveyor.com/project/KimLS/server) |[![Build status](https://ci.appveyor.com/api/projects/status/scr25kmntx36c1ub?svg=true)](https://ci.appveyor.com/project/KimLS/server-87crp) |
*** ***
+21
View File
@@ -0,0 +1,21 @@
version: 1.0.{build}
branches:
only:
- master
image: Visual Studio 2017
configuration: RelWithDebInfo
clone_folder: c:\projects\eqemu
init:
- ps: git config --global core.autocrlf input
cache: c:\tools\vcpkg\installed\
before_build:
- ps: "$wc = New-Object System.Net.WebClient\n$wc.DownloadFile(\"http://strawberryperl.com/download/5.26.2.1/strawberry-perl-5.26.2.1-64bit-portable.zip\", \"c:\\projects\\eqemu\\strawberry-perl-5.26.2.1-64bit-portable.zip\")\ncd c:\\projects\\eqemu\n7z x c:/projects/eqemu/strawberry-perl-5.26.2.1-64bit-portable.zip -oc:/projects/eqemu/strawberry-perl-portable -y\n(Get-Content C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE/config.h).replace('#define PERL_STATIC_INLINE static __inline__', '#define PERL_STATIC_INLINE static __inline') | Set-Content C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE/config.h\nvcpkg install boost-geometry:x64-windows boost-dynamic-bitset:x64-windows luajit:x64-windows libsodium:x64-windows libmysql:x64-windows openssl:x64-windows zlib:x64-windows \nmkdir build\ncd build\ncmake -G \"Visual Studio 15 2017 Win64\" -DEQEMU_BUILD_TESTS=ON -DEQEMU_BUILD_LOGIN=ON -EQEMU_ENABLE_BOTS=ON -DPERL_EXECUTABLE=\"C:/projects/eqemu/strawberry-perl-portable/perl/bin/perl.exe\" -DPERL_INCLUDE_PATH=\"C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE\" -DPERL_LIBRARY=\"C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE/libperl526.a\" -DCMAKE_TOOLCHAIN_FILE=\"c:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake\" .."
build:
project: C:\projects\eqemu\build\EQEmu.sln
parallel: true
verbosity: minimal
after_build:
- cmd: >-
7z a build_x64-bots.zip C:\projects\eqemu\build\bin\RelWithDebInfo\*.exe C:\projects\eqemu\build\bin\RelWithDebInfo\*.dll C:\projects\eqemu\build\bin\RelWithDebInfo\*.pdb C:\projects\eqemu\build\libs\zlibng\RelWithDebInfo\*.dll
appveyor PushArtifact build_x64-bots.zip
+21
View File
@@ -0,0 +1,21 @@
version: 1.0.{build}
branches:
only:
- master
image: Visual Studio 2017
configuration: RelWithDebInfo
clone_folder: c:\projects\eqemu
init:
- ps: git config --global core.autocrlf input
cache: c:\tools\vcpkg\installed\
before_build:
- ps: "$wc = New-Object System.Net.WebClient\n$wc.DownloadFile(\"http://strawberryperl.com/download/5.26.2.1/strawberry-perl-5.26.2.1-64bit-portable.zip\", \"c:\\projects\\eqemu\\strawberry-perl-5.26.2.1-64bit-portable.zip\")\ncd c:\\projects\\eqemu\n7z x c:/projects/eqemu/strawberry-perl-5.26.2.1-64bit-portable.zip -oc:/projects/eqemu/strawberry-perl-portable -y\n(Get-Content C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE/config.h).replace('#define PERL_STATIC_INLINE static __inline__', '#define PERL_STATIC_INLINE static __inline') | Set-Content C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE/config.h\nvcpkg install boost-geometry:x64-windows boost-dynamic-bitset:x64-windows luajit:x64-windows libsodium:x64-windows libmysql:x64-windows openssl:x64-windows zlib:x64-windows \nmkdir build\ncd build\ncmake -G \"Visual Studio 15 2017 Win64\" -DEQEMU_BUILD_TESTS=ON -DEQEMU_BUILD_LOGIN=ON -EQEMU_ENABLE_BOTS=OFF -DPERL_EXECUTABLE=\"C:/projects/eqemu/strawberry-perl-portable/perl/bin/perl.exe\" -DPERL_INCLUDE_PATH=\"C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE\" -DPERL_LIBRARY=\"C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE/libperl526.a\" -DCMAKE_TOOLCHAIN_FILE=\"c:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake\" .."
build:
project: C:\projects\eqemu\build\EQEmu.sln
parallel: true
verbosity: minimal
after_build:
- cmd: >-
7z a build_x64-no-bots.zip C:\projects\eqemu\build\bin\RelWithDebInfo\*.exe C:\projects\eqemu\build\bin\RelWithDebInfo\*.dll C:\projects\eqemu\build\bin\RelWithDebInfo\*.pdb C:\projects\eqemu\build\libs\zlibng\RelWithDebInfo\*.dll
appveyor PushArtifact build_x64-no-bots.zip
+1 -1
View File
@@ -1,4 +1,4 @@
CMAKE_MINIMUM_REQUIRED(VERSION 3.12) CMAKE_MINIMUM_REQUIRED(VERSION 3.2)
SET(export_sources SET(export_sources
main.cpp main.cpp
+8 -19
View File
@@ -25,15 +25,11 @@
#include "../../common/platform.h" #include "../../common/platform.h"
#include "../../common/crash.h" #include "../../common/crash.h"
#include "../../common/rulesys.h" #include "../../common/rulesys.h"
#include "../../common/strings.h" #include "../../common/string_util.h"
#include "../../common/content/world_content_service.h" #include "../../common/content/world_content_service.h"
#include "../../common/zone_store.h"
#include "../../common/path_manager.h"
EQEmuLogSys LogSys; EQEmuLogSys LogSys;
WorldContentService content_service; WorldContentService content_service;
ZoneStore zone_store;
PathManager path;
void ExportSpells(SharedDatabase *db); void ExportSpells(SharedDatabase *db);
void ExportSkillCaps(SharedDatabase *db); void ExportSkillCaps(SharedDatabase *db);
@@ -46,8 +42,6 @@ int main(int argc, char **argv)
LogSys.LoadLogSettingsDefaults(); LogSys.LoadLogSettingsDefaults();
set_exception_handler(); set_exception_handler();
path.LoadPaths();
LogInfo("Client Files Export Utility"); LogInfo("Client Files Export Utility");
if (!EQEmuConfig::LoadConfig()) { if (!EQEmuConfig::LoadConfig()) {
LogError("Unable to load configuration file"); LogError("Unable to load configuration file");
@@ -86,11 +80,10 @@ int main(int argc, char **argv)
return 1; return 1;
} }
} else { } else {
content_db.SetMySQL(database); content_db.SetMysql(database.getMySQL());
} }
LogSys.SetDatabase(&database) LogSys.SetDatabase(&database)
->SetLogPath(path.GetLogPath())
->LoadLogDatabaseSettings() ->LoadLogDatabaseSettings()
->StartFileLogs(); ->StartFileLogs();
@@ -131,8 +124,7 @@ void ExportSpells(SharedDatabase *db)
{ {
LogInfo("Exporting Spells"); LogInfo("Exporting Spells");
std::string file = fmt::format("{}/export/spells_us.txt", path.GetServerPath()); FILE *f = fopen("export/spells_us.txt", "w");
FILE *f = fopen(file.c_str(), "w");
if (!f) { if (!f) {
LogError("Unable to open export/spells_us.txt to write, skipping."); LogError("Unable to open export/spells_us.txt to write, skipping.");
return; return;
@@ -183,7 +175,7 @@ bool SkillUsable(SharedDatabase *db, int skill_id, int class_id)
} }
auto row = results.begin(); auto row = results.begin();
if (row[0] && Strings::ToInt(row[0]) > 0) { if (row[0] && atoi(row[0]) > 0) {
return true; return true;
} }
@@ -207,15 +199,14 @@ int GetSkill(SharedDatabase *db, int skill_id, int class_id, int level)
} }
auto row = results.begin(); auto row = results.begin();
return Strings::ToInt(row[0]); return atoi(row[0]);
} }
void ExportSkillCaps(SharedDatabase *db) void ExportSkillCaps(SharedDatabase *db)
{ {
LogInfo("Exporting Skill Caps"); LogInfo("Exporting Skill Caps");
std::string file = fmt::format("{}/export/SkillCaps.txt", path.GetServerPath()); FILE *f = fopen("export/SkillCaps.txt", "w");
FILE *f = fopen(file.c_str(), "w");
if (!f) { if (!f) {
LogError("Unable to open export/SkillCaps.txt to write, skipping."); LogError("Unable to open export/SkillCaps.txt to write, skipping.");
return; return;
@@ -245,8 +236,7 @@ void ExportBaseData(SharedDatabase *db)
{ {
LogInfo("Exporting Base Data"); LogInfo("Exporting Base Data");
std::string file = fmt::format("{}/export/BaseData.txt", path.GetServerPath()); FILE *f = fopen("export/BaseData.txt", "w");
FILE *f = fopen(file.c_str(), "w");
if (!f) { if (!f) {
LogError("Unable to open export/BaseData.txt to write, skipping."); LogError("Unable to open export/BaseData.txt to write, skipping.");
return; return;
@@ -279,8 +269,7 @@ void ExportDBStrings(SharedDatabase *db)
{ {
LogInfo("Exporting DB Strings"); LogInfo("Exporting DB Strings");
std::string file = fmt::format("{}/export/dbstr_us.txt", path.GetServerPath()); FILE *f = fopen("export/dbstr_us.txt", "w");
FILE *f = fopen(file.c_str(), "w");
if (!f) { if (!f) {
LogError("Unable to open export/dbstr_us.txt to write, skipping."); LogError("Unable to open export/dbstr_us.txt to write, skipping.");
return; return;
+1 -1
View File
@@ -1,4 +1,4 @@
CMAKE_MINIMUM_REQUIRED(VERSION 3.12) CMAKE_MINIMUM_REQUIRED(VERSION 3.2)
SET(import_sources SET(import_sources
main.cpp main.cpp
+32 -43
View File
@@ -23,15 +23,11 @@
#include "../../common/platform.h" #include "../../common/platform.h"
#include "../../common/crash.h" #include "../../common/crash.h"
#include "../../common/rulesys.h" #include "../../common/rulesys.h"
#include "../../common/strings.h" #include "../../common/string_util.h"
#include "../../common/content/world_content_service.h" #include "../../common/content/world_content_service.h"
#include "../../common/zone_store.h"
#include "../../common/path_manager.h"
EQEmuLogSys LogSys; EQEmuLogSys LogSys;
WorldContentService content_service; WorldContentService content_service;
ZoneStore zone_store;
PathManager path;
void ImportSpells(SharedDatabase *db); void ImportSpells(SharedDatabase *db);
void ImportSkillCaps(SharedDatabase *db); void ImportSkillCaps(SharedDatabase *db);
@@ -43,8 +39,6 @@ int main(int argc, char **argv) {
LogSys.LoadLogSettingsDefaults(); LogSys.LoadLogSettingsDefaults();
set_exception_handler(); set_exception_handler();
path.LoadPaths();
LogInfo("Client Files Import Utility"); LogInfo("Client Files Import Utility");
if(!EQEmuConfig::LoadConfig()) { if(!EQEmuConfig::LoadConfig()) {
LogError("Unable to load configuration file."); LogError("Unable to load configuration file.");
@@ -83,11 +77,10 @@ int main(int argc, char **argv) {
return 1; return 1;
} }
} else { } else {
content_db.SetMySQL(database); content_db.SetMysql(database.getMySQL());
} }
LogSys.SetDatabase(&database) LogSys.SetDatabase(&database)
->SetLogPath(path.GetLogPath())
->LoadLogDatabaseSettings() ->LoadLogDatabaseSettings()
->StartFileLogs(); ->StartFileLogs();
@@ -132,10 +125,9 @@ bool IsStringField(int i) {
void ImportSpells(SharedDatabase *db) { void ImportSpells(SharedDatabase *db) {
LogInfo("Importing Spells"); LogInfo("Importing Spells");
std::string file = fmt::format("{}/import/spells_us.txt", path.GetServerPath()); FILE *f = fopen("import/spells_us.txt", "r");
FILE *f = fopen(file.c_str(), "r");
if(!f) { if(!f) {
LogError("Unable to open {} to read, skipping.", file); LogError("Unable to open import/spells_us.txt to read, skipping.");
return; return;
} }
@@ -154,8 +146,8 @@ void ImportSpells(SharedDatabase *db) {
} }
} }
std::string escaped = ::Strings::Escape(buffer); std::string escaped = ::EscapeString(buffer);
auto split = Strings::Split(escaped, '^'); auto split = SplitString(escaped, '^');
int line_columns = (int)split.size(); int line_columns = (int)split.size();
std::string sql; std::string sql;
@@ -222,10 +214,9 @@ void ImportSpells(SharedDatabase *db) {
void ImportSkillCaps(SharedDatabase *db) { void ImportSkillCaps(SharedDatabase *db) {
LogInfo("Importing Skill Caps"); LogInfo("Importing Skill Caps");
std::string file = fmt::format("{}/import/SkillCaps.txt", path.GetServerPath()); FILE *f = fopen("import/SkillCaps.txt", "r");
FILE *f = fopen(file.c_str(), "r");
if(!f) { if(!f) {
LogError("Unable to open {} to read, skipping.", file); LogError("Unable to open import/SkillCaps.txt to read, skipping.");
return; return;
} }
@@ -234,17 +225,17 @@ void ImportSkillCaps(SharedDatabase *db) {
char buffer[2048]; char buffer[2048];
while(fgets(buffer, 2048, f)) { while(fgets(buffer, 2048, f)) {
auto split = Strings::Split(buffer, '^'); auto split = SplitString(buffer, '^');
if(split.size() < 4) { if(split.size() < 4) {
continue; continue;
} }
int class_id, skill_id, level, cap; int class_id, skill_id, level, cap;
class_id = Strings::ToInt(split[0].c_str()); class_id = atoi(split[0].c_str());
skill_id = Strings::ToInt(split[1].c_str()); skill_id = atoi(split[1].c_str());
level = Strings::ToInt(split[2].c_str()); level = atoi(split[2].c_str());
cap = Strings::ToInt(split[3].c_str()); cap = atoi(split[3].c_str());
std::string sql = StringFormat("INSERT INTO skill_caps(class, skillID, level, cap) VALUES(%d, %d, %d, %d)", std::string sql = StringFormat("INSERT INTO skill_caps(class, skillID, level, cap) VALUES(%d, %d, %d, %d)",
class_id, skill_id, level, cap); class_id, skill_id, level, cap);
@@ -258,10 +249,9 @@ void ImportSkillCaps(SharedDatabase *db) {
void ImportBaseData(SharedDatabase *db) { void ImportBaseData(SharedDatabase *db) {
LogInfo("Importing Base Data"); LogInfo("Importing Base Data");
std::string file = fmt::format("{}/import/BaseData.txt", path.GetServerPath()); FILE *f = fopen("import/BaseData.txt", "r");
FILE *f = fopen(file.c_str(), "r");
if(!f) { if(!f) {
LogError("Unable to open {} to read, skipping.", file); LogError("Unable to open import/BaseData.txt to read, skipping.");
return; return;
} }
@@ -270,7 +260,7 @@ void ImportBaseData(SharedDatabase *db) {
char buffer[2048]; char buffer[2048];
while(fgets(buffer, 2048, f)) { while(fgets(buffer, 2048, f)) {
auto split = Strings::Split(buffer, '^'); auto split = SplitString(buffer, '^');
if(split.size() < 10) { if(split.size() < 10) {
continue; continue;
@@ -280,16 +270,16 @@ void ImportBaseData(SharedDatabase *db) {
int level, class_id; int level, class_id;
double hp, mana, end, unk1, unk2, hp_fac, mana_fac, end_fac; double hp, mana, end, unk1, unk2, hp_fac, mana_fac, end_fac;
level = Strings::ToInt(split[0].c_str()); level = atoi(split[0].c_str());
class_id = Strings::ToInt(split[1].c_str()); class_id = atoi(split[1].c_str());
hp = Strings::ToFloat(split[2].c_str()); hp = atof(split[2].c_str());
mana = Strings::ToFloat(split[3].c_str()); mana = atof(split[3].c_str());
end = Strings::ToFloat(split[4].c_str()); end = atof(split[4].c_str());
unk1 = Strings::ToFloat(split[5].c_str()); unk1 = atof(split[5].c_str());
unk2 = Strings::ToFloat(split[6].c_str()); unk2 = atof(split[6].c_str());
hp_fac = Strings::ToFloat(split[7].c_str()); hp_fac = atof(split[7].c_str());
mana_fac = Strings::ToFloat(split[8].c_str()); mana_fac = atof(split[8].c_str());
end_fac = Strings::ToFloat(split[9].c_str()); end_fac = atof(split[9].c_str());
sql = StringFormat("INSERT INTO base_data(level, class, hp, mana, end, unk1, unk2, hp_fac, " sql = StringFormat("INSERT INTO base_data(level, class, hp, mana, end, unk1, unk2, hp_fac, "
"mana_fac, end_fac) VALUES(%d, %d, %f, %f, %f, %f, %f, %f, %f, %f)", "mana_fac, end_fac) VALUES(%d, %d, %f, %f, %f, %f, %f, %f, %f, %f)",
@@ -304,10 +294,9 @@ void ImportBaseData(SharedDatabase *db) {
void ImportDBStrings(SharedDatabase *db) { void ImportDBStrings(SharedDatabase *db) {
LogInfo("Importing DB Strings"); LogInfo("Importing DB Strings");
std::string file = fmt::format("{}/import/dbstr_us.txt", path.GetServerPath()); FILE *f = fopen("import/dbstr_us.txt", "r");
FILE *f = fopen(file.c_str(), "r");
if(!f) { if(!f) {
LogError("Unable to open {} to read, skipping.", file); LogError("Unable to open import/dbstr_us.txt to read, skipping.");
return; return;
} }
@@ -329,7 +318,7 @@ void ImportDBStrings(SharedDatabase *db) {
} }
} }
auto split = Strings::Split(buffer, '^'); auto split = SplitString(buffer, '^');
if(split.size() < 2) { if(split.size() < 2) {
continue; continue;
@@ -339,11 +328,11 @@ void ImportDBStrings(SharedDatabase *db) {
int id, type; int id, type;
std::string value; std::string value;
id = Strings::ToInt(split[0].c_str()); id = atoi(split[0].c_str());
type = Strings::ToInt(split[1].c_str()); type = atoi(split[1].c_str());
if(split.size() >= 3) { if(split.size() >= 3) {
value = ::Strings::Escape(split[2]); value = ::EscapeString(split[2]);
} }
sql = StringFormat("INSERT INTO db_str(id, type, value) VALUES(%u, %u, '%s')", sql = StringFormat("INSERT INTO db_str(id, type, value) VALUES(%u, %u, '%s')",
+735 -757
View File
File diff suppressed because it is too large Load Diff
+190
View File
@@ -0,0 +1,190 @@
/*
* Boost Software License - Version 1.0 - August 17th, 2003
*
* Permission is hereby granted, free of charge, to any person or organization
* obtaining a copy of the software and accompanying documentation covered by
* this license (the "Software") to use, reproduce, display, distribute,
* execute, and transmit the Software, and to prepare derivative works of the
* Software, and to permit third-parties to whom the Software is furnished to
* do so, all subject to the following:
*
* The copyright notices in the Software and this entire statement, including
* the above license grant, this restriction and the following disclaimer,
* must be included in all copies of the Software, in whole or in part, and
* all derivative works of the Software, unless such copies or derivative
* works are solely in the form of machine-executable object code generated by
* a source language processor.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
* SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
* FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
// EQ::Any is a modified version of Boost::Any and as such retains the Boost licensing.
#ifndef EQEMU_COMMON_ANY_H
#define EQEMU_COMMON_ANY_H
#include <algorithm>
#include <typeinfo>
namespace EQ
{
class Any
{
public:
Any()
: content(nullptr)
{
}
template<typename ValueType>
Any(const ValueType &value)
: content(new Holder<ValueType>(value))
{
}
Any(const Any &other)
: content(other.content ? other.content->clone() : 0)
{
}
~Any()
{
if(content)
delete content;
}
Any& swap(Any &rhs)
{
std::swap(content, rhs.content);
return *this;
}
template<typename ValueType>
Any& operator=(const ValueType &rhs)
{
Any(rhs).swap(*this);
return *this;
}
Any& operator=(Any rhs)
{
rhs.swap(*this);
return *this;
}
bool empty() const
{
return !content;
}
const std::type_info& type() const
{
return content ? content->type() : typeid(void);
}
class Placeholder
{
public:
virtual ~Placeholder()
{
}
virtual const std::type_info& type() const = 0;
virtual Placeholder* clone() const = 0;
};
template<typename ValueType>
class Holder : public Placeholder
{
public:
Holder(const ValueType &value)
: held(value)
{
}
virtual const std::type_info& type() const
{
return typeid(ValueType);
}
virtual Placeholder* clone() const
{
return new Holder(held);
}
ValueType held;
private:
Holder& operator=(const Holder&);
};
private:
template<typename ValueType>
friend ValueType* any_cast(Any*);
template<typename ValueType>
friend ValueType* unsafe_any_cast(Any*);
Placeholder* content;
};
class bad_any_cast : public std::bad_cast
{
public:
virtual const char * what() const throw()
{
return "DBI::bad_any_cast: failed conversion using DBI::any_cast";
}
};
template<typename ValueType>
ValueType* any_cast(Any* operand)
{
return operand &&
operand->type() == typeid(ValueType) ? &static_cast<Any::Holder<ValueType>*>(operand->content)->held : nullptr;
}
template<typename ValueType>
inline const ValueType* any_cast(const Any* operand)
{
return any_cast<ValueType>(const_cast<Any*>(operand));
}
template<typename ValueType>
ValueType any_cast(Any& operand)
{
typedef typename std::remove_reference<ValueType>::type nonref;
nonref* result = any_cast<nonref>(&operand);
if(!result)
throw bad_any_cast();
return *result;
}
template<typename ValueType>
inline ValueType any_cast(const Any& operand)
{
typedef typename std::remove_reference<ValueType>::type nonref;
return any_cast<const nonref&>(const_cast<Any&>(operand));
}
template<typename ValueType>
inline ValueType* unsafe_any_cast(Any* operand)
{
return &static_cast<Any::Holder<ValueType>*>(operand->content)->held;
}
template<typename ValueType>
inline const ValueType* unsafe_any_cast(const Any* operand)
{
return unsafe_any_cast<ValueType>(const_cast<Any*>(operand));
}
}
#endif
-1
View File
@@ -20,7 +20,6 @@
#include "../common/types.h" #include "../common/types.h"
#define NO_CLASS 0
#define WARRIOR 1 #define WARRIOR 1
#define CLERIC 2 #define CLERIC 2
#define PALADIN 3 #define PALADIN 3
+1 -1
View File
@@ -160,7 +160,7 @@ namespace EQEmuCommand {
*/ */
std::string command_section; std::string command_section;
for (auto &it: in_function_map) { for (auto &it: in_function_map) {
description.clear(); description = "";
(it.second)(argc, argv, cmd, description); (it.second)(argc, argv, cmd, description);
+7 -7
View File
@@ -120,7 +120,7 @@ std::vector<std::string> WorldContentService::GetContentFlagsDisabled()
/** /**
* @param content_flags * @param content_flags
*/ */
void WorldContentService::SetContentFlags(const std::vector<ContentFlagsRepository::ContentFlags>& content_flags) void WorldContentService::SetContentFlags(std::vector<ContentFlagsRepository::ContentFlags> content_flags)
{ {
WorldContentService::content_flags = content_flags; WorldContentService::content_flags = content_flags;
} }
@@ -158,25 +158,25 @@ bool WorldContentService::IsContentFlagDisabled(const std::string &content_flag)
bool WorldContentService::DoesPassContentFiltering(const ContentFlags &f) bool WorldContentService::DoesPassContentFiltering(const ContentFlags &f)
{ {
// if we're not set to (-1 All) then fail when we aren't within minimum expansion // if we're not set to (-1 All) then fail when we aren't within minimum expansion
if (f.min_expansion > Expansion::EXPANSION_ALL && current_expansion < f.min_expansion && current_expansion != -1) { if (f.min_expansion > Expansion::EXPANSION_ALL && current_expansion < f.min_expansion) {
return false; return false;
} }
// if we're not set to (-1 All) then fail when we aren't within max expansion // if we're not set to (-1 All) then fail when we aren't within max expansion
if (f.max_expansion > Expansion::EXPANSION_ALL && current_expansion > f.max_expansion && current_expansion != -1) { if (f.max_expansion > Expansion::EXPANSION_ALL && current_expansion > f.max_expansion) {
return false; return false;
} }
// if we don't have any enabled flag in enabled flags, we fail // if we don't have any enabled flag in enabled flags, we fail
for (const auto& flag: Strings::Split(f.content_flags)) { for (const auto& flag: SplitString(f.content_flags)) {
if (!Strings::Contains(GetContentFlagsEnabled(), flag)) { if (!contains(GetContentFlagsEnabled(), flag)) {
return false; return false;
} }
} }
// if we don't have any disabled flag in disabled flags, we fail // if we don't have any disabled flag in disabled flags, we fail
for (const auto& flag: Strings::Split(f.content_flags_disabled)) { for (const auto& flag: SplitString(f.content_flags_disabled)) {
if (!Strings::Contains(GetContentFlagsDisabled(), flag)) { if (!contains(GetContentFlagsDisabled(), flag)) {
return false; return false;
} }
} }
+1 -1
View File
@@ -167,7 +167,7 @@ public:
std::vector<std::string> GetContentFlagsDisabled(); std::vector<std::string> GetContentFlagsDisabled();
bool IsContentFlagEnabled(const std::string& content_flag); bool IsContentFlagEnabled(const std::string& content_flag);
bool IsContentFlagDisabled(const std::string& content_flag); bool IsContentFlagDisabled(const std::string& content_flag);
void SetContentFlags(const std::vector<ContentFlagsRepository::ContentFlags>& content_flags); void SetContentFlags(std::vector<ContentFlagsRepository::ContentFlags> content_flags);
void ReloadContentFlags(); void ReloadContentFlags();
WorldContentService * SetExpansionContext(); WorldContentService * SetExpansionContext();
+9 -145
View File
@@ -1,98 +1,6 @@
#include "global_define.h" #include "global_define.h"
#include "eqemu_logsys.h" #include "eqemu_logsys.h"
#include "crash.h" #include "crash.h"
#include "strings.h"
#include "process/process.h"
#include "http/httplib.h"
#include "http/uri.h"
#include "json/json.h"
#include "version.h"
#include "eqemu_config.h"
#include "serverinfo.h"
#include "rulesys.h"
#include "platform.h"
#include <cstdio>
#include <vector>
#if WINDOWS
#define popen _popen
#endif
void SendCrashReport(const std::string &crash_report)
{
// can configure multiple endpoints if need be
std::vector<std::string> endpoints = {
"http://spire.akkadius.com/api/v1/analytics/server-crash-report",
// "http://localhost:3010/api/v1/analytics/server-crash-report", // development
};
auto config = EQEmuConfig::get();
for (auto &e: endpoints) {
uri u(e);
std::string base_url = fmt::format("{}://{}", u.get_scheme(), u.get_host());
if (u.get_port()) {
base_url += fmt::format(":{}", u.get_port());
}
// client
httplib::Client r(base_url);
r.set_connection_timeout(1, 0);
r.set_read_timeout(1, 0);
r.set_write_timeout(1, 0);
httplib::Headers headers = {
{"Content-Type", "application/json"}
};
// os info
auto os = EQ::GetOS();
auto cpus = EQ::GetCPUs();
auto process_id = EQ::GetPID();
auto rss = EQ::GetRSS() / 1048576.0;
auto uptime = static_cast<uint32>(EQ::GetUptime());
// payload
Json::Value p;
p["platform_name"] = GetPlatformName();
p["crash_report"] = crash_report;
p["server_version"] = CURRENT_VERSION;
p["compile_date"] = COMPILE_DATE;
p["compile_time"] = COMPILE_TIME;
p["server_name"] = config->LongName;
p["server_short_name"] = config->ShortName;
p["uptime"] = uptime;
p["os_machine"] = os.machine;
p["os_release"] = os.release;
p["os_version"] = os.version;
p["os_sysname"] = os.sysname;
p["process_id"] = process_id;
p["rss_memory"] = rss;
p["cpus"] = cpus.size();
p["origination_info"] = "";
if (!LogSys.origination_info.zone_short_name.empty()) {
p["origination_info"] = fmt::format(
"{} ({}) instance_id [{}]",
LogSys.origination_info.zone_short_name,
LogSys.origination_info.zone_long_name,
LogSys.origination_info.instance_id
);
}
std::stringstream payload;
payload << p;
if (auto res = r.Post(e, payload.str(), "application/json")) {
if (res->status == 200) {
LogInfo("Sent crash report");
}
else {
LogError("Failed to send crash report to [{}]", e);
}
}
}
}
#if defined(_WINDOWS) && defined(CRASH_LOGGING) #if defined(_WINDOWS) && defined(CRASH_LOGGING)
#include "StackWalker.h" #include "StackWalker.h"
@@ -104,30 +12,22 @@ public:
EQEmuStackWalker(DWORD dwProcessId, HANDLE hProcess) : StackWalker(dwProcessId, hProcess) { } EQEmuStackWalker(DWORD dwProcessId, HANDLE hProcess) : StackWalker(dwProcessId, hProcess) { }
virtual void OnOutput(LPCSTR szText) { virtual void OnOutput(LPCSTR szText) {
char buffer[4096]; char buffer[4096];
for (int i = 0; i < 4096; ++i) { for(int i = 0; i < 4096; ++i) {
if (szText[i] == 0) { if(szText[i] == 0) {
buffer[i] = '\0'; buffer[i] = '\0';
break; break;
} }
if (szText[i] == '\n' || szText[i] == '\r') { if(szText[i] == '\n' || szText[i] == '\r') {
buffer[i] = ' '; buffer[i] = ' ';
} } else {
else {
buffer[i] = szText[i]; buffer[i] = szText[i];
} }
} }
std::string line = buffer;
_lines.push_back(line);
Log(Logs::General, Logs::Crash, buffer); Log(Logs::General, Logs::Crash, buffer);
StackWalker::OnOutput(szText); StackWalker::OnOutput(szText);
} }
const std::vector<std::string>& GetLines() { return _lines; }
private:
std::vector<std::string> _lines;
}; };
LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS *ExceptionInfo) LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS *ExceptionInfo)
@@ -201,20 +101,7 @@ LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS *ExceptionInfo)
if(EXCEPTION_STACK_OVERFLOW != ExceptionInfo->ExceptionRecord->ExceptionCode) if(EXCEPTION_STACK_OVERFLOW != ExceptionInfo->ExceptionRecord->ExceptionCode)
{ {
EQEmuStackWalker sw; EQEmuStackWalker sw; sw.ShowCallstack(GetCurrentThread(), ExceptionInfo->ContextRecord);
sw.ShowCallstack(GetCurrentThread(), ExceptionInfo->ContextRecord);
if (RuleB(Analytics, CrashReporting)) {
std::string crash_report;
auto& lines = sw.GetLines();
for (auto& line : lines) {
crash_report += line;
crash_report += "\n";
}
SendCrashReport(crash_report);
}
} }
return EXCEPTION_EXECUTE_HANDLER; return EXCEPTION_EXECUTE_HANDLER;
@@ -238,27 +125,9 @@ void set_exception_handler() {
void print_trace() void print_trace()
{ {
bool does_gdb_exist = Strings::Contains(Process::execute("gdb -v"), "GNU"); auto uid = geteuid();
if (!does_gdb_exist) {
LogCrash(
"[Error] GDB is not installed, if you want crash dumps on Linux to work properly you will need GDB installed"
);
std::exit(1);
}
auto uid = geteuid(); std::string temp_output_file = "/tmp/dump-output";
std::string temp_output_file = fmt::format("/tmp/dump-output-{}", Strings::Random(10));
// check for passwordless sudo if not root
if (uid != 0) {
bool sudo_password_required = Strings::Contains(Process::execute("sudo -n true"), "a password is required");
if (sudo_password_required) {
LogCrash(
"[Error] Current user does not have passwordless sudo installed. It is required to automatically process crash dumps with GDB as non-root."
);
std::exit(1);
}
}
char pid_buf[30]; char pid_buf[30];
sprintf(pid_buf, "%d", getpid()); sprintf(pid_buf, "%d", getpid());
@@ -267,6 +136,7 @@ void print_trace()
int child_pid = fork(); int child_pid = fork();
if (!child_pid) { if (!child_pid) {
int fd = open(temp_output_file.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); int fd = open(temp_output_file.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
dup2(fd, 1); // redirect output to stderr dup2(fd, 1); // redirect output to stderr
fprintf(stdout, "stack trace for %s pid=%s\n", name_buf, pid_buf); fprintf(stdout, "stack trace for %s pid=%s\n", name_buf, pid_buf);
if (uid == 0) { if (uid == 0) {
@@ -281,22 +151,16 @@ void print_trace()
abort(); /* If gdb failed to start */ abort(); /* If gdb failed to start */
} }
else { else {
waitpid(child_pid, nullptr, 0); waitpid(child_pid, NULL, 0);
} }
std::ifstream input(temp_output_file); std::ifstream input(temp_output_file);
std::string crash_report;
for (std::string line; getline(input, line);) { for (std::string line; getline(input, line);) {
LogCrash("{}", line); LogCrash("{}", line);
crash_report += fmt::format("{}\n", line);
} }
std::remove(temp_output_file.c_str()); std::remove(temp_output_file.c_str());
if (RuleB(Analytics, CrashReporting)) {
SendCrashReport(crash_report);
}
exit(1); exit(1);
} }
+1 -1
View File
@@ -313,7 +313,7 @@ namespace cron
{ {
try try
{ {
return static_cast<cron_int>(Strings::ToUnsignedInt(text.data())); return static_cast<cron_int>(std::stoul(text.data()));
} }
catch (std::exception const & ex) catch (std::exception const & ex)
{ {
+379 -280
View File
File diff suppressed because it is too large Load Diff
+22 -14
View File
@@ -34,6 +34,8 @@
#include <vector> #include <vector>
#include <map> #include <map>
//atoi is not uint32 or uint32 safe!!!!
#define atoul(str) strtoul(str, nullptr, 10)
class MySQLRequestResult; class MySQLRequestResult;
class Client; class Client;
@@ -106,11 +108,14 @@ public:
bool MoveCharacterToZone(uint32 character_id, uint32 zone_id); bool MoveCharacterToZone(uint32 character_id, uint32 zone_id);
bool ReserveName(uint32 account_id, char *name); bool ReserveName(uint32 account_id, char *name);
bool SaveCharacterCreate(uint32 character_id, uint32 account_id, PlayerProfile_Struct *pp); bool SaveCharacterCreate(uint32 character_id, uint32 account_id, PlayerProfile_Struct *pp);
bool SetHackerFlag(const char *accountname, const char *charactername, const char *hacked);
bool SetMQDetectionFlag(const char *accountname, const char *charactername, const char *hacked, const char *zone);
bool SetMQDetectionFlag(const char *accountname, const char *charactername, const std::string &hacked, const char *zone);
bool UpdateName(const char *oldname, const char *newname); bool UpdateName(const char *oldname, const char *newname);
bool CopyCharacter( bool CopyCharacter(
const std::string& source_character_name, std::string source_character_name,
const std::string& destination_character_name, std::string destination_character_name,
const std::string& destination_account_name std::string destination_account_name
); );
/* General Information Queries */ /* General Information Queries */
@@ -140,30 +145,31 @@ public:
/* Instancing */ /* Instancing */
bool AddClientToInstance(uint16 instance_id, uint32 character_id); bool AddClientToInstance(uint16 instance_id, uint32 char_id);
bool CheckInstanceByCharID(uint16 instance_id, uint32 character_id); bool CharacterInInstanceGroup(uint16 instance_id, uint32 char_id);
bool CheckInstanceExists(uint16 instance_id); bool CheckInstanceExists(uint16 instance_id);
bool CheckInstanceExpired(uint16 instance_id); bool CheckInstanceExpired(uint16 instance_id);
bool CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version, uint32 duration); bool CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version, uint32 duration);
bool GetUnusedInstanceID(uint16 &instance_id); bool GetUnusedInstanceID(uint16 &instance_id);
bool IsGlobalInstance(uint16 instance_id); bool GlobalInstance(uint16 instance_id);
bool RemoveClientFromInstance(uint16 instance_id, uint32 char_id); bool RemoveClientFromInstance(uint16 instance_id, uint32 char_id);
bool RemoveClientsFromInstance(uint16 instance_id); bool RemoveClientsFromInstance(uint16 instance_id);
bool VerifyInstanceAlive(uint16 instance_id, uint32 character_id); bool VerifyInstanceAlive(uint16 instance_id, uint32 char_id);
bool VerifyZoneInstance(uint32 zone_id, uint16 instance_id); bool VerifyZoneInstance(uint32 zone_id, uint16 instance_id);
uint16 GetInstanceID(uint32 zone, uint32 charid, int16 version); uint16 GetInstanceID(uint32 zone, uint32 charid, int16 version);
std::vector<uint16> GetInstanceIDs(uint32 zone_id, uint32 character_id); uint16 GetInstanceVersion(uint16 instance_id);
uint8_t GetInstanceVersion(uint16 instance_id);
uint32 GetTimeRemainingInstance(uint16 instance_id, bool &is_perma); uint32 GetTimeRemainingInstance(uint16 instance_id, bool &is_perma);
uint32 GetInstanceZoneID(uint16 instance_id); uint32 VersionFromInstanceID(uint16 instance_id);
uint32 ZoneIDFromInstanceID(uint16 instance_id);
void AssignGroupToInstance(uint32 gid, uint32 instance_id); void AssignGroupToInstance(uint32 gid, uint32 instance_id);
void AssignRaidToInstance(uint32 rid, uint32 instance_id); void AssignRaidToInstance(uint32 rid, uint32 instance_id);
void BuryCorpsesInInstance(uint16 instance_id);
void DeleteInstance(uint16 instance_id); void DeleteInstance(uint16 instance_id);
void FlagInstanceByGroupLeader(uint32 zone_id, int16 version, uint32 charid, uint32 group_id); void FlagInstanceByGroupLeader(uint32 zone, int16 version, uint32 charid, uint32 gid);
void FlagInstanceByRaidLeader(uint32 zone_id, int16 version, uint32 charid, uint32 raid_id); void FlagInstanceByRaidLeader(uint32 zone, int16 version, uint32 charid, uint32 rid);
void GetCharactersInInstance(uint16 instance_id, std::list<uint32> &character_ids); void GetCharactersInInstance(uint16 instance_id, std::list<uint32> &charid_list);
void PurgeExpiredInstances(); void PurgeExpiredInstances();
void SetInstanceDuration(uint16 instance_id, uint32 new_duration); void SetInstanceDuration(uint16 instance_id, uint32 new_duration);
@@ -235,12 +241,14 @@ public:
/* Database Variables */ /* Database Variables */
bool GetVariable(std::string varname, std::string &varvalue); bool GetVariable(std::string varname, std::string &varvalue);
bool SetVariable(const std::string& varname, const std::string &varvalue); bool SetVariable(const std::string varname, const std::string &varvalue);
bool LoadVariables(); bool LoadVariables();
/* General Queries */ /* General Queries */
bool GetSafePoints(const char* zone_short_name, uint32 instance_version, float* safe_x = 0, float* safe_y = 0, float* safe_z = 0, float* safe_heading = 0, int16* minstatus = 0, uint8* minlevel = 0, char *flag_needed = nullptr);
bool GetZoneGraveyard(const uint32 graveyard_id, uint32* graveyard_zoneid = 0, float* graveyard_x = 0, float* graveyard_y = 0, float* graveyard_z = 0, float* graveyard_heading = 0); bool GetZoneGraveyard(const uint32 graveyard_id, uint32* graveyard_zoneid = 0, float* graveyard_x = 0, float* graveyard_y = 0, float* graveyard_z = 0, float* graveyard_heading = 0);
bool GetZoneLongName(const char* short_name, char** long_name, char* file_name = 0, float* safe_x = 0, float* safe_y = 0, float* safe_z = 0, uint32* graveyard_id = 0, uint32* maxclients = 0);
bool LoadPTimers(uint32 charid, PTimerList &into); bool LoadPTimers(uint32 charid, PTimerList &into);
uint8 GetPEQZone(uint32 zone_id, uint32 version); uint8 GetPEQZone(uint32 zone_id, uint32 version);
+132 -92
View File
@@ -23,12 +23,10 @@
#include <iterator> #include <iterator>
#include "database_dump_service.h" #include "database_dump_service.h"
#include "../eqemu_logsys.h" #include "../eqemu_logsys.h"
#include "../strings.h" #include "../string_util.h"
#include "../eqemu_config.h" #include "../eqemu_config.h"
#include "../database_schema.h" #include "../database_schema.h"
#include "../file.h" #include "../file_util.h"
#include "../process/process.h"
#include "../termcolor/rang.hpp"
#include <ctime> #include <ctime>
@@ -37,12 +35,43 @@
#else #else
#include <sys/time.h> #include <sys/time.h>
#include <thread>
#endif #endif
#define DATABASE_DUMP_PATH "backups/" #define DATABASE_DUMP_PATH "backups/"
/**
* @param cmd
* @param return_result
* @return
*/
std::string DatabaseDumpService::execute(const std::string &cmd, bool return_result = true)
{
const char *file_name = "db-exec-result.txt";
if (return_result) {
#ifdef _WINDOWS
std::system((cmd + " > " + file_name + " 2>&1").c_str());
#else
std::system((cmd + " > " + file_name).c_str());
#endif
}
else {
std::system((cmd).c_str());
}
std::string result;
if (return_result) {
std::ifstream file(file_name);
result = {std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>()};
std::remove(file_name);
}
return result;
}
/** /**
* @return bool * @return bool
*/ */
@@ -59,7 +88,7 @@ bool DatabaseDumpService::IsMySQLInstalled()
*/ */
bool DatabaseDumpService::IsTarAvailable() bool DatabaseDumpService::IsTarAvailable()
{ {
std::string version_output = Process::execute("tar --version"); std::string version_output = execute("tar --version");
return version_output.find("GNU tar") != std::string::npos; return version_output.find("GNU tar") != std::string::npos;
} }
@@ -70,7 +99,7 @@ bool DatabaseDumpService::IsTarAvailable()
*/ */
bool DatabaseDumpService::Is7ZipAvailable() bool DatabaseDumpService::Is7ZipAvailable()
{ {
std::string version_output = Process::execute("7z --help"); std::string version_output = execute("7z --help");
return version_output.find("7-Zip") != std::string::npos; return version_output.find("7-Zip") != std::string::npos;
} }
@@ -88,9 +117,9 @@ bool DatabaseDumpService::HasCompressionBinary()
*/ */
std::string DatabaseDumpService::GetMySQLVersion() std::string DatabaseDumpService::GetMySQLVersion()
{ {
std::string version_output = Process::execute("mysql --version"); std::string version_output = execute("mysql --version");
return Strings::Trim(version_output); return trim(version_output);
} }
/** /**
@@ -120,53 +149,109 @@ std::string DatabaseDumpService::GetBaseMySQLDumpCommand()
); );
} }
/**
* @return
*/
std::string DatabaseDumpService::GetPlayerTablesList() std::string DatabaseDumpService::GetPlayerTablesList()
{ {
return Strings::Join(DatabaseSchema::GetPlayerTables(), " "); std::string tables_list;
std::vector<std::string> tables = DatabaseSchema::GetPlayerTables();
for (const auto &table : tables) {
tables_list += table + " ";
}
return trim(tables_list);
} }
/**
* @return
*/
std::string DatabaseDumpService::GetBotTablesList() std::string DatabaseDumpService::GetBotTablesList()
{ {
return Strings::Join(DatabaseSchema::GetBotTables(), " "); std::string tables_list;
} std::vector<std::string> tables = DatabaseSchema::GetBotTables();
for (const auto &table : tables) {
std::string DatabaseDumpService::GetMercTablesList() tables_list += table + " ";
{ }
return Strings::Join(DatabaseSchema::GetMercTables(), " ");
return trim(tables_list);
} }
/**
* @return
*/
std::string DatabaseDumpService::GetLoginTableList() std::string DatabaseDumpService::GetLoginTableList()
{ {
return Strings::Join(DatabaseSchema::GetLoginTables(), " "); std::string tables_list;
std::vector<std::string> tables = DatabaseSchema::GetLoginTables();
for (const auto &table : tables) {
tables_list += table + " ";
}
return trim(tables_list);
} }
/**
* @return
*/
std::string DatabaseDumpService::GetQueryServTables() std::string DatabaseDumpService::GetQueryServTables()
{ {
return Strings::Join(DatabaseSchema::GetQueryServerTables(), " "); std::string tables_list;
std::vector<std::string> tables = DatabaseSchema::GetQueryServerTables();
for (const auto &table : tables) {
tables_list += table + " ";
}
return trim(tables_list);
} }
/**
* @return
*/
std::string DatabaseDumpService::GetSystemTablesList() std::string DatabaseDumpService::GetSystemTablesList()
{ {
auto system_tables = DatabaseSchema::GetServerTables(); std::string tables_list;
auto version_tables = DatabaseSchema::GetVersionTables();
system_tables.insert( std::vector<std::string> tables = DatabaseSchema::GetServerTables();
std::end(system_tables), for (const auto &table : tables) {
std::begin(version_tables), tables_list += table + " ";
std::end(version_tables) }
);
return Strings::Join(system_tables, " "); tables = DatabaseSchema::GetVersionTables();
for (const auto &table : tables) {
tables_list += table + " ";
}
return trim(tables_list);
} }
/**
* @return
*/
std::string DatabaseDumpService::GetStateTablesList() std::string DatabaseDumpService::GetStateTablesList()
{ {
return Strings::Join(DatabaseSchema::GetStateTables(), " "); std::string tables_list;
std::vector<std::string> tables = DatabaseSchema::GetStateTables();
for (const auto &table : tables) {
tables_list += table + " ";
}
return trim(tables_list);
} }
/**
* @return
*/
std::string DatabaseDumpService::GetContentTablesList() std::string DatabaseDumpService::GetContentTablesList()
{ {
return Strings::Join(DatabaseSchema::GetContentTables(), " "); std::string tables_list;
std::vector<std::string> tables = DatabaseSchema::GetContentTables();
for (const auto &table : tables) {
tables_list += table + " ";
}
return trim(tables_list);
} }
/** /**
@@ -201,7 +286,7 @@ std::string DatabaseDumpService::GetDumpFileNameWithPath()
return GetSetDumpPath() + GetDumpFileName(); return GetSetDumpPath() + GetDumpFileName();
} }
void DatabaseDumpService::DatabaseDump() void DatabaseDumpService::Dump()
{ {
if (!IsMySQLInstalled()) { if (!IsMySQLInstalled()) {
LogError("MySQL is not installed; Please check your PATH for a valid MySQL installation"); LogError("MySQL is not installed; Please check your PATH for a valid MySQL installation");
@@ -252,11 +337,6 @@ void DatabaseDumpService::DatabaseDump()
dump_descriptor += "-bots"; dump_descriptor += "-bots";
} }
if (IsDumpMercTables()) {
tables_to_dump += GetMercTablesList() + " ";
dump_descriptor += "-mercs";
}
if (IsDumpSystemTables()) { if (IsDumpSystemTables()) {
tables_to_dump += GetSystemTablesList() + " "; tables_to_dump += GetSystemTablesList() + " ";
dump_descriptor += "-system"; dump_descriptor += "-system";
@@ -295,14 +375,22 @@ void DatabaseDumpService::DatabaseDump()
pipe_file = fmt::format(" > {}.sql", GetDumpFileNameWithPath()); pipe_file = fmt::format(" > {}.sql", GetDumpFileNameWithPath());
} }
if (!File::Exists(GetSetDumpPath()) && !IsDumpOutputToConsole()) { std::string execute_command = fmt::format(
File::Makedir(GetSetDumpPath()); "{} {} {} {}",
GetBaseMySQLDumpCommand(),
options,
tables_to_dump,
pipe_file
);
if (!FileUtil::exists(GetSetDumpPath()) && !IsDumpOutputToConsole()) {
FileUtil::mkdir(GetSetDumpPath());
} }
if (IsDumpDropTableSyntaxOnly()) { if (IsDumpDropTableSyntaxOnly()) {
std::vector<std::string> tables = Strings::Split(tables_to_dump, ' '); std::vector<std::string> tables = SplitString(tables_to_dump, ' ');
for (auto &table: tables) { for (auto &table : tables) {
std::cout << "DROP TABLE IF EXISTS `" << table << "`;" << std::endl; std::cout << "DROP TABLE IF EXISTS `" << table << "`;" << std::endl;
} }
@@ -311,42 +399,14 @@ void DatabaseDumpService::DatabaseDump()
} }
} }
else { else {
const auto execute_command = fmt::format( std::string execution_result = execute(execute_command, IsDumpOutputToConsole());
"{} {} {} {}", if (!execution_result.empty()) {
GetBaseMySQLDumpCommand(),
options,
tables_to_dump,
pipe_file
);
std::string execution_result = Process::execute(execute_command);
if (!execution_result.empty() && IsDumpOutputToConsole()) {
std::cout << execution_result; std::cout << execution_result;
} }
} }
LogSys.EnableConsoleLogging();
if (!pipe_file.empty()) {
std::string file = fmt::format("{}.sql", GetDumpFileNameWithPath());
auto r = File::GetContents(file);
if (!r.error.empty()) {
LogError("{}", r.error);
}
for (auto &line: Strings::Split(r.contents, "\n")) {
if (Strings::Contains(line, "mysqldump:")) {
LogError("{}", line);
LogError("Database dump failed. Correct the error before continuing or trying again");
LogError("This is to prevent data loss on behalf of the server operator");
RemoveSqlBackup();
std::exit(1);
}
}
}
if (!tables_to_dump.empty()) { if (!tables_to_dump.empty()) {
LogInfo("Dumping Tables [{}]", Strings::Trim(tables_to_dump)); LogInfo("Dumping Tables [{}]", tables_to_dump);
} }
LogInfo("Database dump created at [{}.sql]", GetDumpFileNameWithPath()); LogInfo("Database dump created at [{}.sql]", GetDumpFileNameWithPath());
@@ -356,7 +416,7 @@ void DatabaseDumpService::DatabaseDump()
LogInfo("Compression requested... Compressing dump [{}.sql]", GetDumpFileNameWithPath()); LogInfo("Compression requested... Compressing dump [{}.sql]", GetDumpFileNameWithPath());
if (IsTarAvailable()) { if (IsTarAvailable()) {
Process::execute( execute(
fmt::format( fmt::format(
"tar -zcvf {}.tar.gz -C {} {}.sql", "tar -zcvf {}.tar.gz -C {} {}.sql",
GetDumpFileNameWithPath(), GetDumpFileNameWithPath(),
@@ -365,10 +425,9 @@ void DatabaseDumpService::DatabaseDump()
) )
); );
LogInfo("Compressed dump created at [{}.tar.gz]", GetDumpFileNameWithPath()); LogInfo("Compressed dump created at [{}.tar.gz]", GetDumpFileNameWithPath());
RemoveSqlBackup();
} }
else if (Is7ZipAvailable()) { else if (Is7ZipAvailable()) {
Process::execute( execute(
fmt::format( fmt::format(
"7z a -t7z {}.zip {}.sql", "7z a -t7z {}.zip {}.sql",
GetDumpFileNameWithPath(), GetDumpFileNameWithPath(),
@@ -376,7 +435,6 @@ void DatabaseDumpService::DatabaseDump()
) )
); );
LogInfo("Compressed dump created at [{}.zip]", GetDumpFileNameWithPath()); LogInfo("Compressed dump created at [{}.zip]", GetDumpFileNameWithPath());
RemoveSqlBackup();
} }
else { else {
LogInfo("Compression requested, but no available compression binary was found"); LogInfo("Compression requested, but no available compression binary was found");
@@ -549,21 +607,3 @@ void DatabaseDumpService::SetDumpBotTables(bool dump_bot_tables)
{ {
DatabaseDumpService::dump_bot_tables = dump_bot_tables; DatabaseDumpService::dump_bot_tables = dump_bot_tables;
} }
bool DatabaseDumpService::IsDumpMercTables() const
{
return dump_merc_tables;
}
void DatabaseDumpService::SetDumpMercTables(bool dump_merc_tables)
{
DatabaseDumpService::dump_merc_tables = dump_merc_tables;
}
void DatabaseDumpService::RemoveSqlBackup()
{
std::string file = fmt::format("{}.sql", GetDumpFileNameWithPath());
if (File::Exists(file)) {
std::filesystem::remove(file);
}
}
+2 -6
View File
@@ -24,7 +24,7 @@
class DatabaseDumpService { class DatabaseDumpService {
public: public:
void DatabaseDump(); void Dump();
bool IsDumpAllTables() const; bool IsDumpAllTables() const;
void SetDumpAllTables(bool dump_all_tables); void SetDumpAllTables(bool dump_all_tables);
bool IsDumpWithNoData() const; bool IsDumpWithNoData() const;
@@ -55,8 +55,6 @@ public:
void SetDumpStateTables(bool dump_state_tables); void SetDumpStateTables(bool dump_state_tables);
bool IsDumpBotTables() const; bool IsDumpBotTables() const;
void SetDumpBotTables(bool dump_bot_tables); void SetDumpBotTables(bool dump_bot_tables);
bool IsDumpMercTables() const;
void SetDumpMercTables(bool dump_bot_tables);
private: private:
bool dump_all_tables = false; bool dump_all_tables = false;
@@ -72,16 +70,15 @@ private:
bool dump_output_to_console = false; bool dump_output_to_console = false;
bool dump_drop_table_syntax_only = false; bool dump_drop_table_syntax_only = false;
bool dump_bot_tables = false; bool dump_bot_tables = false;
bool dump_merc_tables = false;
std::string dump_path; std::string dump_path;
std::string dump_file_name; std::string dump_file_name;
std::string execute(const std::string &cmd, bool return_result);
bool IsMySQLInstalled(); bool IsMySQLInstalled();
std::string GetMySQLVersion(); std::string GetMySQLVersion();
std::string GetBaseMySQLDumpCommand(); std::string GetBaseMySQLDumpCommand();
std::string GetPlayerTablesList(); std::string GetPlayerTablesList();
std::string GetBotTablesList(); std::string GetBotTablesList();
std::string GetMercTablesList();
std::string GetSystemTablesList(); std::string GetSystemTablesList();
std::string GetStateTablesList(); std::string GetStateTablesList();
std::string GetContentTablesList(); std::string GetContentTablesList();
@@ -92,7 +89,6 @@ private:
std::string GetDumpFileNameWithPath(); std::string GetDumpFileNameWithPath();
std::string GetSetDumpPath(); std::string GetSetDumpPath();
std::string GetQueryServTables(); std::string GetQueryServTables();
void RemoveSqlBackup();
}; };
+55 -65
View File
@@ -18,12 +18,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "../common/global_define.h" #include "../common/global_define.h"
#include "../common/rulesys.h" #include "../common/rulesys.h"
#include "../common/strings.h" #include "../common/string_util.h"
#include "../common/timer.h" #include "../common/timer.h"
#include "database.h" #include "database.h"
#include "extprofile.h" #include "extprofile.h"
#include "path_manager.h"
#include <iomanip> #include <iomanip>
#include <iostream> #include <iostream>
@@ -476,17 +475,8 @@ bool Database::CheckDatabaseConversions() {
CheckDatabaseConvertPPDeblob(); CheckDatabaseConvertPPDeblob();
CheckDatabaseConvertCorpseDeblob(); CheckDatabaseConvertCorpseDeblob();
auto *r = RuleManager::Instance();
r->LoadRules(this, "default", false);
if (!RuleB(Bots, Enabled) && DoesTableExist("bot_data")) {
LogInfo("Bot tables found but rule not enabled, enabling");
r->SetRule("Bots:Enabled", "true", this, true, true);
}
/* Run EQEmu Server script (Checks for database updates) */ /* Run EQEmu Server script (Checks for database updates) */
system("perl eqemu_server.pl ran_from_world");
const std::string file = fmt::format("{}/eqemu_server.pl", path.GetServerPath());
system(fmt::format("perl {} ran_from_world", file).c_str());
return true; return true;
} }
@@ -499,7 +489,7 @@ bool Database::CheckDatabaseConvertPPDeblob(){
ExtendedProfile_Struct* e_pp; ExtendedProfile_Struct* e_pp;
uint32 pplen = 0; uint32 pplen = 0;
uint32 i; uint32 i;
uint32 character_id = 0; int character_id = 0;
int account_id = 0; int account_id = 0;
int number_of_characters = 0; int number_of_characters = 0;
int printppdebug = 0; /* Prints Player Profile */ int printppdebug = 0; /* Prints Player Profile */
@@ -530,7 +520,7 @@ bool Database::CheckDatabaseConvertPPDeblob(){
rquery = StringFormat("SELECT COUNT(`id`) FROM `character_`"); rquery = StringFormat("SELECT COUNT(`id`) FROM `character_`");
results = QueryDatabase(rquery); results = QueryDatabase(rquery);
for (auto row = results.begin(); row != results.end(); ++row) { for (auto row = results.begin(); row != results.end(); ++row) {
number_of_characters = Strings::ToInt(row[0]); number_of_characters = atoi(row[0]);
printf("Number of Characters in Database: %i \n", number_of_characters); printf("Number of Characters in Database: %i \n", number_of_characters);
} }
@@ -929,19 +919,19 @@ bool Database::CheckDatabaseConvertPPDeblob(){
for (auto row = results.begin(); row != results.end(); ++row) { for (auto row = results.begin(); row != results.end(); ++row) {
char_iter_count++; char_iter_count++;
squery = StringFormat("SELECT `id`, `profile`, `name`, `level`, `account_id`, `firstlogon`, `lfg`, `lfp`, `mailkey`, `xtargets`, `inspectmessage`, `extprofile` FROM `character_` WHERE `id` = %i", Strings::ToUnsignedInt(row[0])); squery = StringFormat("SELECT `id`, `profile`, `name`, `level`, `account_id`, `firstlogon`, `lfg`, `lfp`, `mailkey`, `xtargets`, `inspectmessage`, `extprofile` FROM `character_` WHERE `id` = %i", atoi(row[0]));
auto results2 = QueryDatabase(squery); auto results2 = QueryDatabase(squery);
auto row2 = results2.begin(); auto row2 = results2.begin();
pp = (Convert::PlayerProfile_Struct*)row2[1]; pp = (Convert::PlayerProfile_Struct*)row2[1];
e_pp = (ExtendedProfile_Struct*)row2[11]; e_pp = (ExtendedProfile_Struct*)row2[11];
character_id = Strings::ToUnsignedInt(row[0]); character_id = atoi(row[0]);
account_id = Strings::ToInt(row2[4]); account_id = atoi(row2[4]);
/* Convert some data from the character_ table that is still relevant */ /* Convert some data from the character_ table that is still relevant */
firstlogon = Strings::ToUnsignedInt(row2[5]); firstlogon = atoi(row2[5]);
lfg = Strings::ToUnsignedInt(row2[6]); lfg = atoi(row2[6]);
lfp = Strings::ToUnsignedInt(row2[7]); lfp = atoi(row2[7]);
mailkey = row2[8]; mailkey = row2[8];
xtargets = Strings::ToUnsignedInt(row2[9]); xtargets = atoi(row2[9]);
inspectmessage = row2[10]; inspectmessage = row2[10];
/* Verify PP Integrity */ /* Verify PP Integrity */
@@ -967,11 +957,11 @@ bool Database::CheckDatabaseConvertPPDeblob(){
loadbar(char_iter_count, number_of_characters, 50); loadbar(char_iter_count, number_of_characters, 50);
/* Run inspect message convert */ /* Run inspect message convert */
if (!inspectmessage.empty()){ if (inspectmessage != ""){
std::string rquery = StringFormat("REPLACE INTO `character_inspect_messages` (id, inspect_message)" std::string rquery = StringFormat("REPLACE INTO `character_inspect_messages` (id, inspect_message)"
"VALUES (%u, '%s')", "VALUES (%u, '%s')",
character_id, character_id,
Strings::Escape(inspectmessage).c_str() EscapeString(inspectmessage).c_str()
); );
auto results = QueryDatabase(rquery); auto results = QueryDatabase(rquery);
} }
@@ -1208,8 +1198,8 @@ bool Database::CheckDatabaseConvertPPDeblob(){
")", ")",
character_id, character_id,
account_id, account_id,
Strings::Escape(pp->name).c_str(), EscapeString(pp->name).c_str(),
Strings::Escape(pp->last_name).c_str(), EscapeString(pp->last_name).c_str(),
pp->gender, pp->gender,
pp->race, pp->race,
pp->class_, pp->class_,
@@ -1233,8 +1223,8 @@ bool Database::CheckDatabaseConvertPPDeblob(){
pp->ability_number, pp->ability_number,
pp->ability_time_minutes, pp->ability_time_minutes,
pp->ability_time_hours, pp->ability_time_hours,
Strings::Escape(pp->title).c_str(), EscapeString(pp->title).c_str(),
Strings::Escape(pp->suffix).c_str(), EscapeString(pp->suffix).c_str(),
pp->exp, pp->exp,
pp->points, pp->points,
pp->mana, pp->mana,
@@ -1314,7 +1304,7 @@ bool Database::CheckDatabaseConvertPPDeblob(){
The speed difference is dramatic The speed difference is dramatic
*/ */
/* Run AA Convert */ /* Run AA Convert */
int first_entry = 0; rquery.clear(); int first_entry = 0; rquery = "";
for (i = 0; i < MAX_PP_AA_ARRAY; i++){ for (i = 0; i < MAX_PP_AA_ARRAY; i++){
if (pp->aa_array[i].AA > 0 && pp->aa_array[i].value > 0){ if (pp->aa_array[i].AA > 0 && pp->aa_array[i].value > 0){
if (first_entry != 1){ if (first_entry != 1){
@@ -1327,14 +1317,14 @@ bool Database::CheckDatabaseConvertPPDeblob(){
} }
} }
} }
if (!rquery.empty()){ results = QueryDatabase(rquery); } if (rquery != ""){ results = QueryDatabase(rquery); }
/* Run Bind Home Convert */ /* Run Bind Home Convert */
if (pp->binds[4].zone_id < 999 && !_ISNAN_(pp->binds[4].x) && !_ISNAN_(pp->binds[4].y) && !_ISNAN_(pp->binds[4].z) && !_ISNAN_(pp->binds[4].heading)) { if (pp->binds[4].zone_id < 999 && !_ISNAN_(pp->binds[4].x) && !_ISNAN_(pp->binds[4].y) && !_ISNAN_(pp->binds[4].z) && !_ISNAN_(pp->binds[4].heading)) {
rquery = StringFormat("REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, is_home)" rquery = StringFormat("REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, is_home)"
" VALUES (%u, %u, %u, %f, %f, %f, %f, 1)", " VALUES (%u, %u, %u, %f, %f, %f, %f, 1)",
character_id, pp->binds[4].zone_id, 0, pp->binds[4].x, pp->binds[4].y, pp->binds[4].z, pp->binds[4].heading); character_id, pp->binds[4].zone_id, 0, pp->binds[4].x, pp->binds[4].y, pp->binds[4].z, pp->binds[4].heading);
if (!rquery.empty()){ results = QueryDatabase(rquery); } if (rquery != ""){ results = QueryDatabase(rquery); }
} }
/* Run Bind Convert */ /* Run Bind Convert */
@@ -1342,10 +1332,10 @@ bool Database::CheckDatabaseConvertPPDeblob(){
rquery = StringFormat("REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, is_home)" rquery = StringFormat("REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, is_home)"
" VALUES (%u, %u, %u, %f, %f, %f, %f, 0)", " VALUES (%u, %u, %u, %f, %f, %f, %f, 0)",
character_id, pp->binds[0].zone_id, 0, pp->binds[0].x, pp->binds[0].y, pp->binds[0].z, pp->binds[0].heading); character_id, pp->binds[0].zone_id, 0, pp->binds[0].x, pp->binds[0].y, pp->binds[0].z, pp->binds[0].heading);
if (!rquery.empty()){ results = QueryDatabase(rquery); } if (rquery != ""){ results = QueryDatabase(rquery); }
} }
/* Run Language Convert */ /* Run Language Convert */
first_entry = 0; rquery.clear(); first_entry = 0; rquery = "";
for (i = 0; i < MAX_PP_LANGUAGE; i++){ for (i = 0; i < MAX_PP_LANGUAGE; i++){
if (pp->languages[i] > 0){ if (pp->languages[i] > 0){
if (first_entry != 1){ if (first_entry != 1){
@@ -1355,9 +1345,9 @@ bool Database::CheckDatabaseConvertPPDeblob(){
rquery = rquery + StringFormat(", (%u, %u, %u)", character_id, i, pp->languages[i]); rquery = rquery + StringFormat(", (%u, %u, %u)", character_id, i, pp->languages[i]);
} }
} }
if (!rquery.empty()){ results = QueryDatabase(rquery); } if (rquery != ""){ results = QueryDatabase(rquery); }
/* Run Skill Convert */ /* Run Skill Convert */
first_entry = 0; rquery.clear(); first_entry = 0; rquery = "";
for (i = 0; i < MAX_PP_SKILL; i++){ for (i = 0; i < MAX_PP_SKILL; i++){
if (pp->skills[i] > 0){ if (pp->skills[i] > 0){
if (first_entry != 1){ if (first_entry != 1){
@@ -1367,9 +1357,9 @@ bool Database::CheckDatabaseConvertPPDeblob(){
rquery = rquery + StringFormat(", (%u, %u, %u)", character_id, i, pp->skills[i]); rquery = rquery + StringFormat(", (%u, %u, %u)", character_id, i, pp->skills[i]);
} }
} }
if (!rquery.empty()){ results = QueryDatabase(rquery); } if (rquery != ""){ results = QueryDatabase(rquery); }
/* Run Spell Convert */ /* Run Spell Convert */
first_entry = 0; rquery.clear(); first_entry = 0; rquery = "";
for (i = 0; i < 480; i++){ for (i = 0; i < 480; i++){
if (pp->spell_book[i] > 0 && pp->spell_book[i] != 4294967295 && pp->spell_book[i] < 40000 && pp->spell_book[i] != 1){ if (pp->spell_book[i] > 0 && pp->spell_book[i] != 4294967295 && pp->spell_book[i] < 40000 && pp->spell_book[i] != 1){
if (first_entry != 1){ if (first_entry != 1){
@@ -1379,9 +1369,9 @@ bool Database::CheckDatabaseConvertPPDeblob(){
rquery = rquery + StringFormat(", (%u, %u, %u)", character_id, i, pp->spell_book[i]); rquery = rquery + StringFormat(", (%u, %u, %u)", character_id, i, pp->spell_book[i]);
} }
} }
if (!rquery.empty()){ results = QueryDatabase(rquery); } if (rquery != ""){ results = QueryDatabase(rquery); }
/* Run Max Memmed Spell Convert */ /* Run Max Memmed Spell Convert */
first_entry = 0; rquery.clear(); first_entry = 0; rquery = "";
for (i = 0; i < 9; i++){ for (i = 0; i < 9; i++){
if (pp->mem_spells[i] > 0 && pp->mem_spells[i] != 65535 && pp->mem_spells[i] != 4294967295){ if (pp->mem_spells[i] > 0 && pp->mem_spells[i] != 65535 && pp->mem_spells[i] != 4294967295){
if (first_entry != 1){ if (first_entry != 1){
@@ -1391,9 +1381,9 @@ bool Database::CheckDatabaseConvertPPDeblob(){
rquery = rquery + StringFormat(", (%u, %u, %u)", character_id, i, pp->mem_spells[i]); rquery = rquery + StringFormat(", (%u, %u, %u)", character_id, i, pp->mem_spells[i]);
} }
} }
if (!rquery.empty()){ results = QueryDatabase(rquery); } if (rquery != ""){ results = QueryDatabase(rquery); }
/* Run Discipline Convert */ /* Run Discipline Convert */
first_entry = 0; rquery.clear(); first_entry = 0; rquery = "";
for (i = 0; i < MAX_PP_DISCIPLINES; i++){ for (i = 0; i < MAX_PP_DISCIPLINES; i++){
if (pp->disciplines.values[i] > 0 && pp->disciplines.values[i] < 60000){ if (pp->disciplines.values[i] > 0 && pp->disciplines.values[i] < 60000){
if (first_entry != 1){ if (first_entry != 1){
@@ -1403,9 +1393,9 @@ bool Database::CheckDatabaseConvertPPDeblob(){
rquery = rquery + StringFormat(", (%u, %u, %u)", character_id, i, pp->disciplines.values[i]); rquery = rquery + StringFormat(", (%u, %u, %u)", character_id, i, pp->disciplines.values[i]);
} }
} }
if (!rquery.empty()){ results = QueryDatabase(rquery); } if (rquery != ""){ results = QueryDatabase(rquery); }
/* Run Material Color Convert */ /* Run Material Color Convert */
first_entry = 0; rquery.clear(); first_entry = 0; rquery = "";
for (i = EQ::textures::textureBegin; i < EQ::textures::materialCount; i++){ for (i = EQ::textures::textureBegin; i < EQ::textures::materialCount; i++){
if (pp->item_tint[i].color > 0){ if (pp->item_tint[i].color > 0){
if (first_entry != 1){ if (first_entry != 1){
@@ -1415,9 +1405,9 @@ bool Database::CheckDatabaseConvertPPDeblob(){
rquery = rquery + StringFormat(", (%u, %u, %u, %u, %u, %u, %u)", character_id, i, pp->item_tint[i].rgb.blue, pp->item_tint[i].rgb.green, pp->item_tint[i].rgb.red, pp->item_tint[i].rgb.use_tint, pp->item_tint[i].color); rquery = rquery + StringFormat(", (%u, %u, %u, %u, %u, %u, %u)", character_id, i, pp->item_tint[i].rgb.blue, pp->item_tint[i].rgb.green, pp->item_tint[i].rgb.red, pp->item_tint[i].rgb.use_tint, pp->item_tint[i].color);
} }
} }
if (!rquery.empty()){ results = QueryDatabase(rquery); } if (rquery != ""){ results = QueryDatabase(rquery); }
/* Run Tribute Convert */ /* Run Tribute Convert */
first_entry = 0; rquery.clear(); first_entry = 0; rquery = "";
for (i = 0; i < 5; i++){ for (i = 0; i < 5; i++){
if (pp->tributes[i].tribute > 0 && pp->tributes[i].tribute != 4294967295){ if (pp->tributes[i].tribute > 0 && pp->tributes[i].tribute != 4294967295){
if (first_entry != 1){ if (first_entry != 1){
@@ -1427,9 +1417,9 @@ bool Database::CheckDatabaseConvertPPDeblob(){
rquery = rquery + StringFormat(", (%u, %u, %u)", character_id, pp->tributes[i].tier, pp->tributes[i].tribute); rquery = rquery + StringFormat(", (%u, %u, %u)", character_id, pp->tributes[i].tier, pp->tributes[i].tribute);
} }
} }
if (!rquery.empty()){ results = QueryDatabase(rquery); } if (rquery != ""){ results = QueryDatabase(rquery); }
/* Run Bandolier Convert */ /* Run Bandolier Convert */
first_entry = 0; rquery.clear(); first_entry = 0; rquery = "";
for (i = 0; i < Convert::BANDOLIERS_SIZE; i++){ for (i = 0; i < Convert::BANDOLIERS_SIZE; i++){
if (strlen(pp->bandoliers[i].Name) < 32) { if (strlen(pp->bandoliers[i].Name) < 32) {
for (int si = 0; si < Convert::BANDOLIER_ITEM_COUNT; si++){ for (int si = 0; si < Convert::BANDOLIER_ITEM_COUNT; si++){
@@ -1443,9 +1433,9 @@ bool Database::CheckDatabaseConvertPPDeblob(){
} }
} }
} }
if (!rquery.empty()){ results = QueryDatabase(rquery); } if (rquery != ""){ results = QueryDatabase(rquery); }
/* Run Potion Belt Convert */ /* Run Potion Belt Convert */
first_entry = 0; rquery.clear(); first_entry = 0; rquery = "";
for (i = 0; i < Convert::POTION_BELT_ITEM_COUNT; i++){ for (i = 0; i < Convert::POTION_BELT_ITEM_COUNT; i++){
if (pp->potionbelt.Items[i].ID > 0){ if (pp->potionbelt.Items[i].ID > 0){
if (first_entry != 1){ if (first_entry != 1){
@@ -1456,9 +1446,9 @@ bool Database::CheckDatabaseConvertPPDeblob(){
} }
} }
if (!rquery.empty()){ results = QueryDatabase(rquery); } if (rquery != ""){ results = QueryDatabase(rquery); }
/* Run Leadership AA Convert */ /* Run Leadership AA Convert */
first_entry = 0; rquery.clear(); first_entry = 0; rquery = "";
for (i = 0; i < MAX_LEADERSHIP_AA_ARRAY; i++){ for (i = 0; i < MAX_LEADERSHIP_AA_ARRAY; i++){
if (pp->leader_abilities.ranks[i] > 0 && pp->leader_abilities.ranks[i] < 6){ if (pp->leader_abilities.ranks[i] > 0 && pp->leader_abilities.ranks[i] < 6){
if (first_entry != 1){ if (first_entry != 1){
@@ -1468,7 +1458,7 @@ bool Database::CheckDatabaseConvertPPDeblob(){
rquery = rquery + StringFormat(", (%i, %u, %u)", character_id, i, pp->leader_abilities.ranks[i]); rquery = rquery + StringFormat(", (%i, %u, %u)", character_id, i, pp->leader_abilities.ranks[i]);
} }
} }
if (!rquery.empty()){ results = QueryDatabase(rquery); } if (rquery != ""){ results = QueryDatabase(rquery); }
} }
} }
if (runconvert == 1){ if (runconvert == 1){
@@ -1567,7 +1557,7 @@ bool Database::CheckDatabaseConvertCorpseDeblob(){
rquery = StringFormat("SELECT DISTINCT charid FROM character_corpses"); rquery = StringFormat("SELECT DISTINCT charid FROM character_corpses");
results = QueryDatabase(rquery); results = QueryDatabase(rquery);
for (auto row = results.begin(); row != results.end(); ++row) { for (auto row = results.begin(); row != results.end(); ++row) {
std::string squery = StringFormat("SELECT id, charname, data, time_of_death, is_rezzed FROM character_corpses WHERE `charid` = %i", Strings::ToUnsignedInt(row[0])); std::string squery = StringFormat("SELECT id, charname, data, time_of_death, is_rezzed FROM character_corpses WHERE `charid` = %i", atoi(row[0]));
auto results2 = QueryDatabase(squery); auto results2 = QueryDatabase(squery);
for (auto row2 = results2.begin(); row2 != results2.end(); ++row2) { for (auto row2 = results2.begin(); row2 != results2.end(); ++row2) {
in_datasize = results2.LengthOfColumn(2); in_datasize = results2.LengthOfColumn(2);
@@ -1599,7 +1589,7 @@ bool Database::CheckDatabaseConvertCorpseDeblob(){
c_type = "NULL"; c_type = "NULL";
continue; continue;
} }
std::cout << "Converting Corpse: [OK] [" << c_type << "]: " << "ID: " << Strings::ToUnsignedInt(row2[0]) << std::endl; std::cout << "Converting Corpse: [OK] [" << c_type << "]: " << "ID: " << atoi(row2[0]) << std::endl;
if (is_sof){ if (is_sof){
scquery = StringFormat("UPDATE `character_corpses` SET \n" scquery = StringFormat("UPDATE `character_corpses` SET \n"
@@ -1670,19 +1660,19 @@ bool Database::CheckDatabaseConvertCorpseDeblob(){
dbpc->item_tint[6].color, dbpc->item_tint[6].color,
dbpc->item_tint[7].color, dbpc->item_tint[7].color,
dbpc->item_tint[8].color, dbpc->item_tint[8].color,
Strings::ToUnsignedInt(row2[0]) atoi(row2[0])
); );
if (!scquery.empty()){ auto sc_results = QueryDatabase(scquery); } if (scquery != ""){ auto sc_results = QueryDatabase(scquery); }
first_entry = 0; first_entry = 0;
scquery.clear(); scquery = "";
/* Print Items */ /* Print Items */
for (unsigned int i = 0; i < dbpc->itemcount; i++) { for (unsigned int i = 0; i < dbpc->itemcount; i++) {
if (first_entry != 1){ if (first_entry != 1){
scquery = StringFormat("REPLACE INTO `character_corpse_items` \n" scquery = StringFormat("REPLACE INTO `character_corpse_items` \n"
" (corpse_id, equip_slot, item_id, charges, aug_1, aug_2, aug_3, aug_4, aug_5, aug_6, attuned) \n" " (corpse_id, equip_slot, item_id, charges, aug_1, aug_2, aug_3, aug_4, aug_5, aug_6, attuned) \n"
" VALUES (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u) \n", " VALUES (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u) \n",
Strings::ToUnsignedInt(row2[0]), atoi(row2[0]),
dbpc->items[i].equipSlot, dbpc->items[i].equipSlot,
dbpc->items[i].item_id, dbpc->items[i].item_id,
dbpc->items[i].charges, dbpc->items[i].charges,
@@ -1698,7 +1688,7 @@ bool Database::CheckDatabaseConvertCorpseDeblob(){
} }
else{ else{
scquery = scquery + StringFormat(", (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u) \n", scquery = scquery + StringFormat(", (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u) \n",
Strings::ToUnsignedInt(row2[0]), atoi(row2[0]),
dbpc->items[i].equipSlot, dbpc->items[i].equipSlot,
dbpc->items[i].item_id, dbpc->items[i].item_id,
dbpc->items[i].charges, dbpc->items[i].charges,
@@ -1712,7 +1702,7 @@ bool Database::CheckDatabaseConvertCorpseDeblob(){
); );
} }
} }
if (!scquery.empty()){ auto sc_results = QueryDatabase(scquery); } if (scquery != ""){ auto sc_results = QueryDatabase(scquery); }
} }
else{ else{
/* Classic Converter */ /* Classic Converter */
@@ -1778,12 +1768,12 @@ bool Database::CheckDatabaseConvertCorpseDeblob(){
dbpc_c->item_tint[6].color, dbpc_c->item_tint[6].color,
dbpc_c->item_tint[7].color, dbpc_c->item_tint[7].color,
dbpc_c->item_tint[8].color, dbpc_c->item_tint[8].color,
Strings::ToUnsignedInt(row2[0]) atoi(row2[0])
); );
if (!scquery.empty()){ auto sc_results = QueryDatabase(scquery); } if (scquery != ""){ auto sc_results = QueryDatabase(scquery); }
first_entry = 0; first_entry = 0;
scquery.clear(); scquery = "";
/* Print Items */ /* Print Items */
for (unsigned int i = 0; i < dbpc_c->itemcount; i++) { for (unsigned int i = 0; i < dbpc_c->itemcount; i++) {
@@ -1791,7 +1781,7 @@ bool Database::CheckDatabaseConvertCorpseDeblob(){
scquery = StringFormat("REPLACE INTO `character_corpse_items` \n" scquery = StringFormat("REPLACE INTO `character_corpse_items` \n"
" (corpse_id, equip_slot, item_id, charges, aug_1, aug_2, aug_3, aug_4, aug_5, aug_6, attuned) \n" " (corpse_id, equip_slot, item_id, charges, aug_1, aug_2, aug_3, aug_4, aug_5, aug_6, attuned) \n"
" VALUES (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u) \n", " VALUES (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u) \n",
Strings::ToUnsignedInt(row2[0]), atoi(row2[0]),
dbpc_c->items[i].equipSlot, dbpc_c->items[i].equipSlot,
dbpc_c->items[i].item_id, dbpc_c->items[i].item_id,
dbpc_c->items[i].charges, dbpc_c->items[i].charges,
@@ -1807,7 +1797,7 @@ bool Database::CheckDatabaseConvertCorpseDeblob(){
} }
else{ else{
scquery = scquery + StringFormat(", (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u) \n", scquery = scquery + StringFormat(", (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u) \n",
Strings::ToUnsignedInt(row2[0]), atoi(row2[0]),
dbpc_c->items[i].equipSlot, dbpc_c->items[i].equipSlot,
dbpc_c->items[i].item_id, dbpc_c->items[i].item_id,
dbpc_c->items[i].charges, dbpc_c->items[i].charges,
@@ -1821,7 +1811,7 @@ bool Database::CheckDatabaseConvertCorpseDeblob(){
); );
} }
} }
if (!scquery.empty()){ auto sc_results = QueryDatabase(scquery); } if (scquery != ""){ auto sc_results = QueryDatabase(scquery); }
} }
} }
} }
+316 -253
View File
@@ -18,18 +18,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "../common/global_define.h" #include "../common/global_define.h"
#include "../common/rulesys.h" #include "../common/rulesys.h"
#include "../common/strings.h" #include "../common/string_util.h"
#include "../common/timer.h" #include "../common/timer.h"
#include "../common/repositories/character_corpses_repository.h"
#include "../common/repositories/dynamic_zone_members_repository.h" #include "../common/repositories/dynamic_zone_members_repository.h"
#include "../common/repositories/dynamic_zones_repository.h" #include "../common/repositories/dynamic_zones_repository.h"
#include "../common/repositories/group_id_repository.h"
#include "../common/repositories/instance_list_repository.h"
#include "../common/repositories/instance_list_player_repository.h"
#include "../common/repositories/raid_members_repository.h"
#include "../common/repositories/respawn_times_repository.h"
#include "../common/repositories/spawn_condition_values_repository.h"
#include "database.h" #include "database.h"
@@ -49,83 +41,115 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include <sys/time.h> #include <sys/time.h>
#endif #endif
bool Database::AddClientToInstance(uint16 instance_id, uint32 character_id) /**
* @param instance_id
* @param char_id
* @return
*/
bool Database::AddClientToInstance(uint16 instance_id, uint32 char_id)
{ {
auto e = InstanceListPlayerRepository::NewEntity(); std::string query = StringFormat(
"REPLACE INTO `instance_list_player` (id, charid) "
"VALUES "
"(%lu, %lu)",
(unsigned long) instance_id,
(unsigned long) char_id
);
e.id = instance_id; auto results = QueryDatabase(query);
e.charid = character_id;
return InstanceListPlayerRepository::ReplaceOne(*this, e); return results.Success();
} }
bool Database::CheckInstanceByCharID(uint16 instance_id, uint32 character_id) bool Database::CharacterInInstanceGroup(uint16 instance_id, uint32 char_id)
{ {
if (!instance_id) {
return false;
}
auto l = InstanceListPlayerRepository::GetWhere( std::string query = StringFormat("SELECT charid FROM instance_list_player where id=%u AND charid=%u", instance_id, char_id);
*this, auto results = QueryDatabase(query);
fmt::format(
"id = {} AND charid = {}", if (!results.Success())
instance_id, return false;
character_id
) if (results.RowCount() != 1)
);
if (l.empty()) {
return false; return false;
}
return true; return true;
} }
bool Database::CheckInstanceExists(uint16 instance_id) bool Database::CheckInstanceExists(uint16 instance_id) {
{ std::string query = StringFormat(
if (!instance_id) { "SELECT "
return false; "`id` "
} "FROM "
"`instance_list` "
"WHERE "
"`id` = %u",
instance_id
);
auto results = QueryDatabase(query);
auto i = InstanceListRepository::FindOne(*this, instance_id); if (!results.Success())
if (!i.id) { return false;
if (results.RowCount() == 0)
return false; return false;
}
return true; return true;
} }
bool Database::CheckInstanceExpired(uint16 instance_id) bool Database::CheckInstanceExpired(uint16 instance_id)
{ {
if (!instance_id) {
int32 start_time = 0;
int32 duration = 0;
uint32 never_expires = 0;
std::string query = StringFormat(
"SELECT start_time, duration, never_expires FROM instance_list WHERE id=%u",
instance_id
);
auto results = QueryDatabase(query);
if (!results.Success()) {
return true; return true;
} }
auto i = InstanceListRepository::FindOne(*this, instance_id); if (results.RowCount() == 0) {
if (!i.id) {
return true; return true;
} }
if (i.never_expires) { auto row = results.begin();
start_time = atoi(row[0]);
duration = atoi(row[1]);
never_expires = atoi(row[2]);
if (never_expires == 1) {
return false; return false;
} }
timeval tv{}; timeval tv{};
gettimeofday(&tv, nullptr); gettimeofday(&tv, nullptr);
return (i.start_time + i.duration) <= tv.tv_sec; return (start_time + duration) <= tv.tv_sec;
} }
bool Database::CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version, uint32 duration) bool Database::CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version, uint32 duration)
{ {
auto e = InstanceListRepository::NewEntity(); std::string query = StringFormat(
"INSERT INTO instance_list (id, zone, version, start_time, duration)"
" values (%u, %u, %u, UNIX_TIMESTAMP(), %u)",
instance_id,
zone_id,
version,
duration
);
e.id = instance_id; auto results = QueryDatabase(query);
e.zone = zone_id;
e.version = version;
e.start_time = std::time(nullptr);
e.duration = duration;
return InstanceListRepository::InsertOne(*this, e).id; return results.Success();
} }
bool Database::GetUnusedInstanceID(uint16 &instance_id) bool Database::GetUnusedInstanceID(uint16 &instance_id)
@@ -133,8 +157,8 @@ bool Database::GetUnusedInstanceID(uint16 &instance_id)
uint32 max_reserved_instance_id = RuleI(Instances, ReservedInstances); uint32 max_reserved_instance_id = RuleI(Instances, ReservedInstances);
uint32 max = 32000; uint32 max = 32000;
auto query = fmt::format( std::string query = StringFormat(
"SELECT IFNULL(MAX(id), {}) + 1 FROM instance_list WHERE id > {}", "SELECT IFNULL(MAX(id),%u)+1 FROM instance_list WHERE id > %u",
max_reserved_instance_id, max_reserved_instance_id,
max_reserved_instance_id max_reserved_instance_id
); );
@@ -167,8 +191,8 @@ bool Database::GetUnusedInstanceID(uint16 &instance_id)
auto row = results.begin(); auto row = results.begin();
if (Strings::ToInt(row[0]) <= max) { if (atoi(row[0]) <= max) {
instance_id = Strings::ToInt(row[0]); instance_id = atoi(row[0]);
return true; return true;
} }
@@ -178,7 +202,7 @@ bool Database::GetUnusedInstanceID(uint16 &instance_id)
return true; return true;
} }
query = fmt::format("SELECT id FROM instance_list where id > {} ORDER BY id", max_reserved_instance_id); query = StringFormat("SELECT id FROM instance_list where id > %u ORDER BY id", max_reserved_instance_id);
results = QueryDatabase(query); results = QueryDatabase(query);
if (!results.Success()) { if (!results.Success()) {
@@ -192,9 +216,8 @@ bool Database::GetUnusedInstanceID(uint16 &instance_id)
} }
max_reserved_instance_id++; max_reserved_instance_id++;
for (auto row = results.begin(); row != results.end(); ++row) {
for (auto row : results) { if (max_reserved_instance_id < atoi(row[0])) {
if (max_reserved_instance_id < Strings::ToUnsignedInt(row[0])) {
instance_id = max_reserved_instance_id; instance_id = max_reserved_instance_id;
return true; return true;
} }
@@ -212,45 +235,57 @@ bool Database::GetUnusedInstanceID(uint16 &instance_id)
return true; return true;
} }
bool Database::IsGlobalInstance(uint16 instance_id) bool Database::GlobalInstance(uint16 instance_id)
{ {
if (!instance_id) { std::string query = StringFormat(
return false; "SELECT "
} "is_global "
"FROM "
"instance_list "
"WHERE "
"id = %u "
"LIMIT 1 ",
instance_id
);
auto results = QueryDatabase(query);
auto i = InstanceListRepository::FindOne(*this, instance_id); if (!results.Success())
if (!i.id) {
return false; return false;
}
return i.is_global; if (results.RowCount() == 0)
return false;
auto row = results.begin();
return (atoi(row[0]) == 1) ? true : false;
} }
bool Database::RemoveClientFromInstance(uint16 instance_id, uint32 char_id) bool Database::RemoveClientFromInstance(uint16 instance_id, uint32 char_id)
{ {
return InstanceListPlayerRepository::DeleteWhere( std::string query = StringFormat("DELETE FROM instance_list_player WHERE id=%lu AND charid=%lu",
*this, (unsigned long)instance_id, (unsigned long)char_id);
fmt::format( auto results = QueryDatabase(query);
"id = {} AND charid = {}",
instance_id, return results.Success();
char_id
)
);
} }
bool Database::RemoveClientsFromInstance(uint16 instance_id) bool Database::RemoveClientsFromInstance(uint16 instance_id)
{ {
return InstanceListPlayerRepository::DeleteOne(*this, instance_id); std::string query = StringFormat("DELETE FROM instance_list_player WHERE id=%lu", (unsigned long)instance_id);
auto results = QueryDatabase(query);
return results.Success();
} }
bool Database::VerifyInstanceAlive(uint16 instance_id, uint32 character_id) bool Database::VerifyInstanceAlive(uint16 instance_id, uint32 char_id)
{ {
//we are not saved to this instance so set our instance to 0 //we are not saved to this instance so set our instance to 0
if (!IsGlobalInstance(instance_id) && !CheckInstanceByCharID(instance_id, character_id)) { if (!GlobalInstance(instance_id) && !CharacterInInstanceGroup(instance_id, char_id))
return false; return false;
}
if (CheckInstanceExpired(instance_id)) { if (CheckInstanceExpired(instance_id))
{
DeleteInstance(instance_id); DeleteInstance(instance_id);
return false; return false;
} }
@@ -260,102 +295,99 @@ bool Database::VerifyInstanceAlive(uint16 instance_id, uint32 character_id)
bool Database::VerifyZoneInstance(uint32 zone_id, uint16 instance_id) bool Database::VerifyZoneInstance(uint32 zone_id, uint16 instance_id)
{ {
auto l = InstanceListRepository::GetWhere(
*this, std::string query = StringFormat("SELECT id FROM instance_list where id=%u AND zone=%u", instance_id, zone_id);
fmt::format( auto results = QueryDatabase(query);
"id = {} AND zone = {}",
instance_id, if (!results.Success())
zone_id return false;
)
); if (results.RowCount() == 0)
if (l.empty()) {
return false; return false;
}
return true; return true;
} }
uint16 Database::GetInstanceID(uint32 zone_id, uint32 character_id, int16 version) uint16 Database::GetInstanceID(uint32 zone, uint32 character_id, int16 version)
{ {
if (!zone_id) { if (!zone)
return 0;
std::string query = StringFormat(
"SELECT "
"instance_list.id "
"FROM "
"instance_list, "
"instance_list_player "
"WHERE "
"instance_list.zone = %u "
"AND instance_list.version = %u "
"AND instance_list.id = instance_list_player.id "
"AND instance_list_player.charid = %u "
"LIMIT 1; ",
zone,
version,
character_id
);
auto results = QueryDatabase(query);
if (!results.Success())
return 0;
if (results.RowCount() == 0)
return 0;
auto row = results.begin();
return atoi(row[0]);
}
uint16 Database::GetInstanceVersion(uint16 instance_id) {
if (instance_id == 0)
return 0;
std::string query = StringFormat("SELECT version FROM instance_list where id=%u", instance_id);
auto results = QueryDatabase(query);
if (!results.Success())
return 0;
if (results.RowCount() == 0)
return 0;
auto row = results.begin();
return atoi(row[0]);
}
uint32 Database::GetTimeRemainingInstance(uint16 instance_id, bool &is_perma)
{
uint32 start_time = 0;
uint32 duration = 0;
uint32 never_expires = 0;
std::string query = StringFormat("SELECT start_time, duration, never_expires FROM instance_list WHERE id=%u", instance_id);
auto results = QueryDatabase(query);
if (!results.Success())
{
is_perma = false;
return 0; return 0;
} }
const auto query = fmt::format( if (results.RowCount() == 0)
"SELECT instance_list.id FROM " {
"instance_list, instance_list_player WHERE " is_perma = false;
"instance_list.zone = {} AND "
"instance_list.version = {} AND "
"instance_list.id = instance_list_player.id AND "
"instance_list_player.charid = {} "
"LIMIT 1;",
zone_id,
version,
character_id
);
auto results = QueryDatabase(query);
if (!results.Success() || !results.RowCount()) {
return 0; return 0;
} }
auto row = results.begin(); auto row = results.begin();
return static_cast<uint16>(Strings::ToUnsignedInt(row[0])); start_time = atoi(row[0]);
} duration = atoi(row[1]);
never_expires = atoi(row[2]);
std::vector<uint16> Database::GetInstanceIDs(uint32 zone_id, uint32 character_id) if (never_expires == 1)
{ {
std::vector<uint16> l;
if (!zone_id) {
return l;
}
const auto query = fmt::format(
"SELECT instance_list.id FROM "
"instance_list, instance_list_player WHERE "
"instance_list.zone = {} AND "
"instance_list.id = instance_list_player.id AND "
"instance_list_player.charid = {}",
zone_id,
character_id
);
auto results = QueryDatabase(query);
if (!results.Success() || !results.RowCount()) {
return l;
}
for (auto row : results) {
l.push_back(static_cast<uint16>(Strings::ToUnsignedInt(row[0])));
}
return l;
}
uint8_t Database::GetInstanceVersion(uint16 instance_id) {
if (!instance_id) {
return 0;
}
auto i = InstanceListRepository::FindOne(*this, instance_id);
if (!i.id) {
return 0;
}
return i.version;
}
uint32 Database::GetTimeRemainingInstance(uint16 instance_id, bool &is_perma)
{
auto i = InstanceListRepository::FindOne(*this, instance_id);
if (!i.id) {
is_perma = false;
return 0;
}
if (i.never_expires) {
is_perma = true; is_perma = true;
return 0; return 0;
} }
@@ -364,173 +396,204 @@ uint32 Database::GetTimeRemainingInstance(uint16 instance_id, bool &is_perma)
timeval tv; timeval tv;
gettimeofday(&tv, nullptr); gettimeofday(&tv, nullptr);
return ((i.start_time + i.duration) - tv.tv_sec); return ((start_time + duration) - tv.tv_sec);
} }
uint32 Database::GetInstanceZoneID(uint16 instance_id) uint32 Database::VersionFromInstanceID(uint16 instance_id)
{ {
if (!instance_id) {
return 0;
}
auto i = InstanceListRepository::FindOne(*this, instance_id); std::string query = StringFormat("SELECT version FROM instance_list where id=%u", instance_id);
if (!i.id) { auto results = QueryDatabase(query);
return 0;
}
return i.zone; if (!results.Success())
return 0;
if (results.RowCount() == 0)
return 0;
auto row = results.begin();
return atoi(row[0]);
}
uint32 Database::ZoneIDFromInstanceID(uint16 instance_id)
{
std::string query = StringFormat("SELECT zone FROM instance_list where id=%u", instance_id);
auto results = QueryDatabase(query);
if (!results.Success())
return 0;
if (results.RowCount() == 0)
return 0;
auto row = results.begin();
return atoi(row[0]);
} }
void Database::AssignGroupToInstance(uint32 group_id, uint32 instance_id) void Database::AssignGroupToInstance(uint32 group_id, uint32 instance_id)
{ {
auto zone_id = GetInstanceZoneID(instance_id);
auto version = GetInstanceVersion(instance_id);
auto l = GroupIdRepository::GetWhere( uint32 zone_id = ZoneIDFromInstanceID(instance_id);
*this, uint16 version = VersionFromInstanceID(instance_id);
fmt::format(
"groupid = {}", std::string query = StringFormat("SELECT `charid` FROM `group_id` WHERE `groupid` = %u", group_id);
group_id auto results = QueryDatabase(query);
)
); if (!results.Success())
if (l.empty()) {
return; return;
}
for (const auto& e : l) { for (auto row = results.begin(); row != results.end(); ++row)
if (!GetInstanceID(zone_id, e.charid, version)) { {
AddClientToInstance(instance_id, e.charid); uint32 charid = atoi(row[0]);
} if (GetInstanceID(zone_id, charid, version) == 0)
AddClientToInstance(instance_id, charid);
} }
} }
void Database::AssignRaidToInstance(uint32 raid_id, uint32 instance_id) void Database::AssignRaidToInstance(uint32 raid_id, uint32 instance_id)
{ {
auto zone_id = GetInstanceZoneID(instance_id);
auto version = GetInstanceVersion(instance_id);
auto l = RaidMembersRepository::GetWhere( uint32 zone_id = ZoneIDFromInstanceID(instance_id);
*this, uint16 version = VersionFromInstanceID(instance_id);
std::string query = StringFormat("SELECT `charid` FROM `raid_members` WHERE `raidid` = %u", raid_id);
auto results = QueryDatabase(query);
if (!results.Success())
return;
for (auto row = results.begin(); row != results.end(); ++row)
{
uint32 charid = atoi(row[0]);
if (GetInstanceID(zone_id, charid, version) == 0)
AddClientToInstance(instance_id, charid);
}
}
void Database::BuryCorpsesInInstance(uint16 instance_id) {
QueryDatabase(
fmt::format( fmt::format(
"raidid = {}", "UPDATE character_corpses SET is_buried = 1, instance_id = 0 WHERE instance_id = {}",
raid_id instance_id
) )
); );
if (l.empty()) {
return;
}
for (const auto& e : l) {
if (!GetInstanceID(zone_id, e.charid, version)) {
AddClientToInstance(instance_id, e.charid);
}
}
} }
void Database::DeleteInstance(uint16 instance_id) void Database::DeleteInstance(uint16 instance_id)
{ {
InstanceListPlayerRepository::DeleteWhere(*this, fmt::format("id = {}", instance_id)); std::string query;
RespawnTimesRepository::DeleteWhere(*this, fmt::format("instance_id = {}", instance_id)); query = StringFormat("DELETE FROM instance_list_player WHERE id=%u", instance_id);
QueryDatabase(query);
SpawnConditionValuesRepository::DeleteWhere(*this, fmt::format("instance_id = {}", instance_id)); query = StringFormat("DELETE FROM respawn_times WHERE instance_id=%u", instance_id);
QueryDatabase(query);
query = StringFormat("DELETE FROM spawn_condition_values WHERE instance_id=%u", instance_id);
QueryDatabase(query);
DynamicZoneMembersRepository::DeleteByInstance(*this, instance_id); DynamicZoneMembersRepository::DeleteByInstance(*this, instance_id);
DynamicZonesRepository::DeleteWhere(*this, fmt::format("instance_id = {}", instance_id)); DynamicZonesRepository::DeleteWhere(*this, fmt::format("instance_id = {}", instance_id));
CharacterCorpsesRepository::BuryInstance(*this, instance_id); BuryCorpsesInInstance(instance_id);
} }
void Database::FlagInstanceByGroupLeader(uint32 zone_id, int16 version, uint32 character_id, uint32 group_id) void Database::FlagInstanceByGroupLeader(uint32 zone, int16 version, uint32 charid, uint32 gid)
{ {
auto instance_id = GetInstanceID(zone_id, character_id, version); uint16 id = GetInstanceID(zone, charid, version);
if (instance_id) { if (id != 0)
return; return;
}
char ln[128]; char ln[128];
memset(ln, 0, 128); memset(ln, 0, 128);
GetGroupLeadershipInfo(group_id, ln); GetGroupLeadershipInfo(gid, ln);
uint32 l_charid = GetCharacterID((const char*)ln);
uint16 l_id = GetInstanceID(zone, l_charid, version);
auto group_leader_id = GetCharacterID((const char*)ln); if (l_id == 0)
auto group_leader_instance_id = GetInstanceID(zone_id, group_leader_id, version);
if (!group_leader_instance_id) {
return; return;
}
AddClientToInstance(group_leader_instance_id, character_id); AddClientToInstance(l_id, charid);
} }
void Database::FlagInstanceByRaidLeader(uint32 zone_id, int16 version, uint32 character_id, uint32 raid_id) void Database::FlagInstanceByRaidLeader(uint32 zone, int16 version, uint32 charid, uint32 rid)
{ {
uint16 instance_id = GetInstanceID(zone_id, character_id, version); uint16 id = GetInstanceID(zone, charid, version);
if (instance_id) { if (id != 0)
return; return;
}
auto raid_leader_id = GetCharacterID(GetRaidLeaderName(raid_id)); uint32 l_charid = GetCharacterID(GetRaidLeaderName(rid));
auto raid_leader_instance_id = GetInstanceID(zone_id, raid_leader_id, version); uint16 l_id = GetInstanceID(zone, l_charid, version);
if (!raid_leader_instance_id) { if (l_id == 0)
return; return;
}
AddClientToInstance(raid_leader_instance_id, character_id); AddClientToInstance(l_id, charid);
} }
void Database::GetCharactersInInstance(uint16 instance_id, std::list<uint32> &character_ids) void Database::GetCharactersInInstance(uint16 instance_id, std::list<uint32> &charid_list) {
{
auto l = InstanceListPlayerRepository::GetWhere(*this, fmt::format("id = {}", instance_id));
if (l.empty()) {
return;
}
for (const auto& e : l) { std::string query = StringFormat("SELECT `charid` FROM `instance_list_player` WHERE `id` = %u", instance_id);
character_ids.push_back(e.charid); auto results = QueryDatabase(query);
}
if (!results.Success())
return;
for (auto row = results.begin(); row != results.end(); ++row)
charid_list.push_back(atoi(row[0]));
} }
void Database::PurgeExpiredInstances() void Database::PurgeExpiredInstances()
{ {
/** /**
* Delay purging by a day so that we can continue using adjacent free instance id's * Delay purging by a day so that we can continue using adjacent free instance id's
* from the table without risking the chance we immediately re-allocate a zone that freshly expired but * from the table without risking the chance we immediately re-allocate a zone that freshly expired but
* has not been fully de-allocated * has not been fully de-allocated
*/ */
auto l = InstanceListRepository::GetWhere( std::string query =
*this, SQL(
"(start_time + duration) <= (UNIX_TIMESTAMP() - 86400) AND never_expires = 0" SELECT
); id
if (l.empty()) { FROM
instance_list
where
(start_time + duration) <= (UNIX_TIMESTAMP() - 86400)
and never_expires = 0
);
auto results = QueryDatabase(query);
if (!results.Success()) {
return;
}
if (results.RowCount() == 0) {
return; return;
} }
std::vector<std::string> instance_ids; std::vector<std::string> instance_ids;
for (const auto& e : l) { for (auto row = results.begin(); row != results.end(); ++row) {
instance_ids.emplace_back(std::to_string(e.id)); instance_ids.emplace_back(row[0]);
} }
const auto imploded_instance_ids = Strings::Implode(",", instance_ids); std::string imploded_instance_ids = implode(",", instance_ids);
InstanceListRepository::DeleteWhere(*this, fmt::format("id IN ({})", imploded_instance_ids)); QueryDatabase(fmt::format("DELETE FROM instance_list WHERE id IN ({})", imploded_instance_ids));
InstanceListPlayerRepository::DeleteWhere(*this, fmt::format("id IN ({})", imploded_instance_ids)); QueryDatabase(fmt::format("DELETE FROM instance_list_player WHERE id IN ({})", imploded_instance_ids));
RespawnTimesRepository::DeleteWhere(*this, fmt::format("instance_id IN ({})", imploded_instance_ids)); QueryDatabase(fmt::format("DELETE FROM respawn_times WHERE instance_id IN ({})", imploded_instance_ids));
SpawnConditionValuesRepository::DeleteWhere(*this, fmt::format("instance_id IN ({})", imploded_instance_ids)); QueryDatabase(fmt::format("DELETE FROM spawn_condition_values WHERE instance_id IN ({})", imploded_instance_ids));
CharacterCorpsesRepository::BuryInstances(*this, imploded_instance_ids); QueryDatabase(fmt::format("UPDATE character_corpses SET is_buried = 1, instance_id = 0 WHERE instance_id IN ({})", imploded_instance_ids));
DynamicZoneMembersRepository::DeleteByManyInstances(*this, imploded_instance_ids); DynamicZoneMembersRepository::DeleteByManyInstances(*this, imploded_instance_ids);
DynamicZonesRepository::DeleteWhere(*this, fmt::format("instance_id IN ({})", imploded_instance_ids)); DynamicZonesRepository::DeleteWhere(*this, fmt::format("instance_id IN ({})", imploded_instance_ids));
} }
void Database::SetInstanceDuration(uint16 instance_id, uint32 new_duration) void Database::SetInstanceDuration(uint16 instance_id, uint32 new_duration)
{ {
auto i = InstanceListRepository::FindOne(*this, instance_id); std::string query = StringFormat("UPDATE `instance_list` SET start_time=UNIX_TIMESTAMP(), "
if (!i.id) { "duration=%u WHERE id=%u", new_duration, instance_id);
return; auto results = QueryDatabase(query);
}
i.start_time = std::time(nullptr);
i.duration = new_duration;
InstanceListRepository::UpdateOne(*this, i);
} }
+10 -30
View File
@@ -189,14 +189,13 @@ namespace DatabaseSchema {
"char_create_point_allocations", "char_create_point_allocations",
"damageshieldtypes", "damageshieldtypes",
"doors", "doors",
"dynamic_zone_templates",
"faction_association",
"faction_base_data", "faction_base_data",
"faction_list", "faction_list",
"faction_list_mod", "faction_list_mod",
"fishing", "fishing",
"forage", "forage",
"global_loot", "global_loot",
"goallists",
"graveyard", "graveyard",
"grid", "grid",
"grid_entries", "grid_entries",
@@ -225,6 +224,7 @@ namespace DatabaseSchema {
"pets_beastlord_data", "pets_beastlord_data",
"pets_equipmentset", "pets_equipmentset",
"pets_equipmentset_entries", "pets_equipmentset_entries",
"proximities",
"skill_caps", "skill_caps",
"spawn2", "spawn2",
"spawn_conditions", "spawn_conditions",
@@ -318,21 +318,20 @@ namespace DatabaseSchema {
"completed_shared_task_activity_state", "completed_shared_task_activity_state",
"completed_shared_task_members", "completed_shared_task_members",
"completed_shared_tasks", "completed_shared_tasks",
"discord_webhooks",
"dynamic_zone_members", "dynamic_zone_members",
"dynamic_zones", "dynamic_zones",
"eventlog",
"expedition_lockouts", "expedition_lockouts",
"expeditions", "expeditions",
"gm_ips", "gm_ips",
"group_id", "group_id",
"group_leaders", "group_leaders",
"hackers",
"instance_list", "instance_list",
"ip_exemptions", "ip_exemptions",
"item_tick", "item_tick",
"lfguild", "lfguild",
"merc_buffs",
"merchantlist_temp", "merchantlist_temp",
"mercs",
"object_contents", "object_contents",
"raid_details", "raid_details",
"raid_leaders", "raid_leaders",
@@ -341,8 +340,6 @@ namespace DatabaseSchema {
"respawn_times", "respawn_times",
"saylink", "saylink",
"server_scheduled_events", "server_scheduled_events",
"player_event_log_settings",
"player_event_logs",
"shared_task_activity_state", "shared_task_activity_state",
"shared_task_dynamic_zones", "shared_task_dynamic_zones",
"shared_task_members", "shared_task_members",
@@ -392,6 +389,9 @@ namespace DatabaseSchema {
"bot_command_settings", "bot_command_settings",
"bot_create_combinations", "bot_create_combinations",
"bot_data", "bot_data",
"bot_group_members",
"bot_groups",
"bot_guild_members",
"bot_heal_rotation_members", "bot_heal_rotation_members",
"bot_heal_rotation_targets", "bot_heal_rotation_targets",
"bot_heal_rotations", "bot_heal_rotations",
@@ -402,31 +402,11 @@ namespace DatabaseSchema {
"bot_pet_inventories", "bot_pet_inventories",
"bot_pets", "bot_pets",
"bot_spell_casting_chances", "bot_spell_casting_chances",
"bot_spell_settings",
"bot_spells_entries", "bot_spells_entries",
"bot_stances", "bot_stances",
"bot_timers" "bot_timers",
}; "vw_bot_character_mobs",
} "vw_bot_groups"
static std::vector<std::string> GetMercTables()
{
return {
"merc_armorinfo",
"merc_inventory",
"merc_merchant_entries",
"merc_merchant_template_entries",
"merc_merchant_templates",
"merc_name_types",
"merc_npc_types",
"merc_spell_list_entries",
"merc_spell_lists",
"merc_stance_entries",
"merc_stats",
"merc_subtypes",
"merc_templates",
"merc_types",
"merc_weaponinfo"
}; };
} }
+52 -58
View File
@@ -34,16 +34,14 @@
DBcore::DBcore() DBcore::DBcore()
{ {
mysql = mysql_init(nullptr); mysql_init(&mysql);
mysqlOwner = true; pHost = nullptr;
pHost = nullptr; pUser = nullptr;
pUser = nullptr; pPassword = nullptr;
pPassword = nullptr; pDatabase = nullptr;
pDatabase = nullptr; pCompress = false;
pCompress = false; pSSL = false;
pSSL = false; pStatus = Closed;
pStatus = Closed;
m_mutex = new Mutex;
} }
DBcore::~DBcore() DBcore::~DBcore()
@@ -53,10 +51,16 @@ DBcore::~DBcore()
* are re-using the default database connection pointer when we dont have an * are re-using the default database connection pointer when we dont have an
* external configuration setup ex: (content_database) * external configuration setup ex: (content_database)
*/ */
if (mysqlOwner) { std::string mysql_connection_host;
mysql_close(mysql); if (mysql.host) {
mysql_connection_host = mysql.host;
} }
if (GetOriginHost() != mysql_connection_host) {
return;
}
mysql_close(&mysql);
safe_delete_array(pHost); safe_delete_array(pHost);
safe_delete_array(pUser); safe_delete_array(pUser);
safe_delete_array(pPassword); safe_delete_array(pPassword);
@@ -66,21 +70,20 @@ DBcore::~DBcore()
// Sends the MySQL server a keepalive // Sends the MySQL server a keepalive
void DBcore::ping() void DBcore::ping()
{ {
if (!m_mutex->trylock()) { if (!MDatabase.trylock()) {
// well, if's it's locked, someone's using it. If someone's using it, it doesnt need a keepalive // well, if's it's locked, someone's using it. If someone's using it, it doesnt need a keepalive
return; return;
} }
mysql_ping(mysql); mysql_ping(&mysql);
m_mutex->unlock(); MDatabase.unlock();
} }
MySQLRequestResult DBcore::QueryDatabase(const std::string& query, bool retryOnFailureOnce) MySQLRequestResult DBcore::QueryDatabase(std::string query, bool retryOnFailureOnce)
{ {
auto r = QueryDatabase(query.c_str(), query.length(), retryOnFailureOnce); return QueryDatabase(query.c_str(), query.length(), retryOnFailureOnce);
return r;
} }
bool DBcore::DoesTableExist(const std::string& table_name) bool DBcore::DoesTableExist(std::string table_name)
{ {
auto results = QueryDatabase(fmt::format("SHOW TABLES LIKE '{}'", table_name)); auto results = QueryDatabase(fmt::format("SHOW TABLES LIKE '{}'", table_name));
@@ -92,16 +95,18 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo
BenchTimer timer; BenchTimer timer;
timer.reset(); timer.reset();
LockMutex lock(m_mutex); LockMutex lock(&MDatabase);
// Reconnect if we are not connected before hand. // Reconnect if we are not connected before hand.
if (pStatus != Connected) { if (pStatus != Connected) {
Open(); Open();
} }
// request query. != 0 indicates some kind of error. // request query. != 0 indicates some kind of error.
if (mysql_real_query(mysql, query, querylen) != 0) { if (mysql_real_query(&mysql, query, querylen) != 0) {
unsigned int errorNumber = mysql_errno(mysql); unsigned int errorNumber = mysql_errno(&mysql);
if (errorNumber == CR_SERVER_GONE_ERROR) { if (errorNumber == CR_SERVER_GONE_ERROR) {
pStatus = Error; pStatus = Error;
@@ -125,26 +130,26 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo
auto errorBuffer = new char[MYSQL_ERRMSG_SIZE]; auto errorBuffer = new char[MYSQL_ERRMSG_SIZE];
snprintf(errorBuffer, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(mysql), mysql_error(mysql)); snprintf(errorBuffer, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(&mysql), mysql_error(&mysql));
return MySQLRequestResult(nullptr, 0, 0, 0, 0, (uint32) mysql_errno(mysql), errorBuffer); return MySQLRequestResult(nullptr, 0, 0, 0, 0, (uint32) mysql_errno(&mysql), errorBuffer);
} }
auto errorBuffer = new char[MYSQL_ERRMSG_SIZE]; auto errorBuffer = new char[MYSQL_ERRMSG_SIZE];
snprintf(errorBuffer, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(mysql), mysql_error(mysql)); snprintf(errorBuffer, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(&mysql), mysql_error(&mysql));
/** /**
* Error logging * Error logging
*/ */
if (mysql_errno(mysql) > 0 && query[0] != '\0') { if (mysql_errno(&mysql) > 0 && strlen(query) > 0) {
LogMySQLError("[{}] [{}]\n[{}]", mysql_errno(mysql), mysql_error(mysql), query); LogMySQLError("[{}] [{}]\n[{}]", mysql_errno(&mysql), mysql_error(&mysql), query);
} }
return MySQLRequestResult(nullptr, 0, 0, 0, 0, mysql_errno(mysql), errorBuffer); return MySQLRequestResult(nullptr, 0, 0, 0, 0, mysql_errno(&mysql), errorBuffer);
} }
// successful query. get results. // successful query. get results.
MYSQL_RES *res = mysql_store_result(mysql); MYSQL_RES *res = mysql_store_result(&mysql);
uint32 rowCount = 0; uint32 rowCount = 0;
if (res != nullptr) { if (res != nullptr) {
@@ -153,16 +158,16 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo
MySQLRequestResult requestResult( MySQLRequestResult requestResult(
res, res,
(uint32) mysql_affected_rows(mysql), (uint32) mysql_affected_rows(&mysql),
rowCount, rowCount,
(uint32) mysql_field_count(mysql), (uint32) mysql_field_count(&mysql),
(uint32) mysql_insert_id(mysql) (uint32) mysql_insert_id(&mysql)
); );
if (LogSys.log_settings[Logs::MySQLQuery].is_category_enabled == 1) { if (LogSys.log_settings[Logs::MySQLQuery].is_category_enabled == 1) {
if ((strncasecmp(query, "select", 6) == 0)) { if ((strncasecmp(query, "select", 6) == 0)) {
LogMySQLQuery( LogMySQLQuery(
"{0} -- ({1} row{2} returned) ({3}s)", "{0}; -- ({1} row{2} returned) ({3}s)",
query, query,
requestResult.RowCount(), requestResult.RowCount(),
requestResult.RowCount() == 1 ? "" : "s", requestResult.RowCount() == 1 ? "" : "s",
@@ -171,7 +176,7 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo
} }
else { else {
LogMySQLQuery( LogMySQLQuery(
"{0} -- ({1} row{2} affected) ({3}s)", "{0}; -- ({1} row{2} affected) ({3}s)",
query, query,
requestResult.RowsAffected(), requestResult.RowsAffected(),
requestResult.RowsAffected() == 1 ? "" : "s", requestResult.RowsAffected() == 1 ? "" : "s",
@@ -202,7 +207,7 @@ uint32 DBcore::DoEscapeString(char *tobuf, const char *frombuf, uint32 fromlen)
{ {
// No good reason to lock the DB, we only need it in the first place to check char encoding. // No good reason to lock the DB, we only need it in the first place to check char encoding.
// LockMutex lock(&MDatabase); // LockMutex lock(&MDatabase);
return mysql_real_escape_string(mysql, tobuf, frombuf, fromlen); return mysql_real_escape_string(&mysql, tobuf, frombuf, fromlen);
} }
bool DBcore::Open( bool DBcore::Open(
@@ -217,7 +222,7 @@ bool DBcore::Open(
bool iSSL bool iSSL
) )
{ {
LockMutex lock(m_mutex); LockMutex lock(&MDatabase);
safe_delete_array(pHost); safe_delete_array(pHost);
safe_delete_array(pUser); safe_delete_array(pUser);
safe_delete_array(pPassword); safe_delete_array(pPassword);
@@ -237,13 +242,13 @@ bool DBcore::Open(uint32 *errnum, char *errbuf)
if (errbuf) { if (errbuf) {
errbuf[0] = 0; errbuf[0] = 0;
} }
LockMutex lock(m_mutex); LockMutex lock(&MDatabase);
if (GetStatus() == Connected) { if (GetStatus() == Connected) {
return true; return true;
} }
if (GetStatus() == Error) { if (GetStatus() == Error) {
mysql_close(mysql); mysql_close(&mysql);
mysql_init(mysql); // Initialize structure again mysql_init(&mysql); // Initialize structure again
} }
if (!pHost) { if (!pHost) {
return false; return false;
@@ -260,7 +265,7 @@ bool DBcore::Open(uint32 *errnum, char *errbuf)
if (pSSL) { if (pSSL) {
flags |= CLIENT_SSL; flags |= CLIENT_SSL;
} }
if (mysql_real_connect(mysql, pHost, pUser, pPassword, pDatabase, pPort, 0, flags)) { if (mysql_real_connect(&mysql, pHost, pUser, pPassword, pDatabase, pPort, 0, flags)) {
pStatus = Connected; pStatus = Connected;
std::string connected_origin_host = pHost; std::string connected_origin_host = pHost;
@@ -270,16 +275,21 @@ bool DBcore::Open(uint32 *errnum, char *errbuf)
} }
else { else {
if (errnum) { if (errnum) {
*errnum = mysql_errno(mysql); *errnum = mysql_errno(&mysql);
} }
if (errbuf) { if (errbuf) {
snprintf(errbuf, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(mysql), mysql_error(mysql)); snprintf(errbuf, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(&mysql), mysql_error(&mysql));
} }
pStatus = Error; pStatus = Error;
return false; return false;
} }
} }
void DBcore::SetMysql(MYSQL *mysql)
{
DBcore::mysql = *mysql;
}
const std::string &DBcore::GetOriginHost() const const std::string &DBcore::GetOriginHost() const
{ {
return origin_host; return origin_host;
@@ -289,19 +299,3 @@ void DBcore::SetOriginHost(const std::string &origin_host)
{ {
DBcore::origin_host = origin_host; DBcore::origin_host = origin_host;
} }
std::string DBcore::Escape(const std::string& s)
{
const std::size_t s_len = s.length();
std::vector<char> temp((s_len * 2) + 1, '\0');
mysql_real_escape_string(mysql, temp.data(), s.c_str(), s_len);
return temp.data();
}
void DBcore::SetMutex(Mutex *mutex)
{
safe_delete(m_mutex);
DBcore::m_mutex = mutex;
}
+6 -16
View File
@@ -12,7 +12,6 @@
#include <mysql.h> #include <mysql.h>
#include <string.h> #include <string.h>
#include <mutex>
class DBcore { class DBcore {
public: public:
@@ -24,25 +23,19 @@ public:
~DBcore(); ~DBcore();
eStatus GetStatus() { return pStatus; } eStatus GetStatus() { return pStatus; }
MySQLRequestResult QueryDatabase(const char *query, uint32 querylen, bool retryOnFailureOnce = true); MySQLRequestResult QueryDatabase(const char *query, uint32 querylen, bool retryOnFailureOnce = true);
MySQLRequestResult QueryDatabase(const std::string& query, bool retryOnFailureOnce = true); MySQLRequestResult QueryDatabase(std::string query, bool retryOnFailureOnce = true);
void TransactionBegin(); void TransactionBegin();
void TransactionCommit(); void TransactionCommit();
void TransactionRollback(); void TransactionRollback();
std::string Escape(const std::string& s);
uint32 DoEscapeString(char *tobuf, const char *frombuf, uint32 fromlen); uint32 DoEscapeString(char *tobuf, const char *frombuf, uint32 fromlen);
void ping(); void ping();
MYSQL *getMySQL() { return &mysql; }
void SetMysql(MYSQL *mysql);
const std::string &GetOriginHost() const; const std::string &GetOriginHost() const;
void SetOriginHost(const std::string &origin_host); void SetOriginHost(const std::string &origin_host);
bool DoesTableExist(const std::string& table_name); bool DoesTableExist(std::string table_name);
void SetMySQL(const DBcore &o)
{
mysql = o.mysql;
mysqlOwner = false;
}
void SetMutex(Mutex *mutex);
protected: protected:
bool Open( bool Open(
@@ -60,13 +53,10 @@ protected:
private: private:
bool Open(uint32 *errnum = nullptr, char *errbuf = nullptr); bool Open(uint32 *errnum = nullptr, char *errbuf = nullptr);
MYSQL* mysql; MYSQL mysql;
bool mysqlOwner; Mutex MDatabase;
Mutex *m_mutex;
eStatus pStatus; eStatus pStatus;
std::mutex m_query_lock{};
std::string origin_host; std::string origin_host;
char *pHost; char *pHost;
+18 -92
View File
@@ -1,32 +1,40 @@
#include <cereal/archives/json.hpp>
#include <cereal/archives/binary.hpp>
#include "discord.h" #include "discord.h"
#include "../http/httplib.h" #include "../http/httplib.h"
#include "../json/json.h" #include "../json/json.h"
#include "../strings.h" #include "../string_util.h"
#include "../eqemu_logsys.h" #include "../eqemu_logsys.h"
#include "../events/player_event_logs.h"
constexpr int MAX_RETRIES = 10; constexpr int MAX_RETRIES = 10;
void Discord::SendWebhookMessage(const std::string &message, const std::string &webhook_url) void Discord::SendWebhookMessage(const std::string &message, const std::string &webhook_url)
{ {
if (!ValidateWebhookUrl(webhook_url)) { // validate
if (webhook_url.empty()) {
LogDiscord("[webhook_url] is empty");
return;
}
// validate
if (webhook_url.find("http://") == std::string::npos && webhook_url.find("https://") == std::string::npos) {
LogDiscord("[webhook_url] [{}] does not contain a valid http/s prefix.", webhook_url);
return; return;
} }
// split // split
auto s = Strings::Split(webhook_url, '/'); auto s = SplitString(webhook_url, '/');
// url // url
std::string base_url = fmt::format("{}//{}", s[0], s[2]); std::string base_url = fmt::format("{}//{}", s[0], s[2]);
std::string endpoint = Strings::Replace(webhook_url, base_url, ""); std::string endpoint = replace_string(webhook_url, base_url, "");
// client // client
httplib::Client cli(base_url); httplib::Client cli(base_url.c_str());
cli.set_connection_timeout(0, 15000000); // 15 sec cli.set_connection_timeout(0, 15000000); // 15 sec
cli.set_read_timeout(15, 0); // 15 seconds cli.set_read_timeout(15, 0); // 15 seconds
cli.set_write_timeout(15, 0); // 15 seconds cli.set_write_timeout(15, 0); // 15 seconds
httplib::Headers headers = {
{"Content-Type", "application/json"}
};
// payload // payload
Json::Value p; Json::Value p;
@@ -38,7 +46,7 @@ void Discord::SendWebhookMessage(const std::string &message, const std::string &
int retries = 0; int retries = 0;
int retry_timer = 1000; int retry_timer = 1000;
while (retry) { while (retry) {
if (auto res = cli.Post(endpoint, payload.str(), "application/json")) { if (auto res = cli.Post(endpoint.c_str(), payload.str(), "application/json")) {
if (res->status != 200 && res->status != 204) { if (res->status != 200 && res->status != 204) {
LogError("[Discord Client] Code [{}] Error [{}]", res->status, res->body); LogError("[Discord Client] Code [{}] Error [{}]", res->status, res->body);
} }
@@ -54,7 +62,7 @@ void Discord::SendWebhookMessage(const std::string &message, const std::string &
LogDiscord("JSON serialization failure [{}] via [{}]", ex.what(), res->body); LogDiscord("JSON serialization failure [{}] via [{}]", ex.what(), res->body);
} }
retry_timer = Strings::ToInt(response["retry_after"].asString()) + 500; retry_timer = std::stoi(response["retry_after"].asString()) + 500;
} }
LogDiscord("Rate limited... retrying message in [{}ms]", retry_timer); LogDiscord("Rate limited... retrying message in [{}ms]", retry_timer);
@@ -73,71 +81,6 @@ void Discord::SendWebhookMessage(const std::string &message, const std::string &
} }
} }
void Discord::SendPlayerEventMessage(
const PlayerEvent::PlayerEventContainer &e,
const std::string &webhook_url
)
{
if (!ValidateWebhookUrl(webhook_url)) {
return;
}
auto s = Strings::Split(webhook_url, '/');
// url
std::string base_url = fmt::format("{}//{}", s[0], s[2]);
std::string endpoint = Strings::Replace(webhook_url, base_url, "");
// client
httplib::Client cli(base_url);
cli.set_connection_timeout(0, 15000000); // 15 sec
cli.set_read_timeout(15, 0); // 15 seconds
cli.set_write_timeout(15, 0); // 15 seconds
std::string payload = PlayerEventLogs::GetDiscordPayloadFromEvent(e);
if (payload.empty()) {
return;
}
bool retry = true;
int retries = 0;
int retry_timer = 1000;
while (retry) {
if (auto res = cli.Post(endpoint, payload, "application/json")) {
if (res->status != 200 && res->status != 204) {
LogError("Code [{}] Error [{}]", res->status, res->body);
}
if (res->status == 429) {
if (!res->body.empty()) {
std::stringstream ss(res->body);
Json::Value response;
try {
ss >> response;
}
catch (std::exception const &ex) {
LogDiscord("JSON serialization failure [{}] via [{}]", ex.what(), res->body);
}
retry_timer = Strings::ToInt(response["retry_after"].asString()) + 500;
}
LogDiscord("Rate limited... retrying message in [{}ms]", retry_timer);
std::this_thread::sleep_for(std::chrono::milliseconds(retry_timer + 500));
}
if (res->status == 204) {
retry = false;
}
if (retries > MAX_RETRIES) {
LogDiscord("Retries exceeded for player event message");
retry = false;
}
retries++;
}
}
}
std::string Discord::FormatDiscordMessage(uint16 category_id, const std::string &message) std::string Discord::FormatDiscordMessage(uint16 category_id, const std::string &message)
{ {
if (category_id == Logs::LogCategory::MySQLQuery) { if (category_id == Logs::LogCategory::MySQLQuery) {
@@ -146,20 +89,3 @@ std::string Discord::FormatDiscordMessage(uint16 category_id, const std::string
return message + "\n"; return message + "\n";
} }
bool Discord::ValidateWebhookUrl(const std::string &webhook_url)
{
// validate
if (webhook_url.empty()) {
LogDiscord("[webhook_url] is empty");
return false;
}
// validate
if (!Strings::Contains(webhook_url, "http://") && !Strings::Contains(webhook_url, "https://")) {
LogDiscord("[webhook_url] [{}] does not contain a valid http/s prefix.", webhook_url);
return false;
}
return true;
}
-5
View File
@@ -4,16 +4,11 @@
#include <string> #include <string>
#include "../types.h" #include "../types.h"
#include "../http/httplib.h"
#include "../repositories/player_event_logs_repository.h"
#include "../events/player_events.h"
class Discord { class Discord {
public: public:
static void SendWebhookMessage(const std::string& message, const std::string& webhook_url); static void SendWebhookMessage(const std::string& message, const std::string& webhook_url);
static std::string FormatDiscordMessage(uint16 category_id, const std::string& message); static std::string FormatDiscordMessage(uint16 category_id, const std::string& message);
static void SendPlayerEventMessage(const PlayerEvent::PlayerEventContainer& e, const std::string &webhook_url);
static bool ValidateWebhookUrl(const std::string &webhook_url);
}; };
@@ -1,6 +1,7 @@
#include "discord_manager.h" #include "discord_manager.h"
#include "../../common/discord/discord.h" #include "../common/discord/discord.h"
#include "../events/player_event_logs.h" #include "../common/eqemu_logsys.h"
#include "../common/string_util.h"
void DiscordManager::QueueWebhookMessage(uint32 webhook_id, const std::string &message) void DiscordManager::QueueWebhookMessage(uint32 webhook_id, const std::string &message)
{ {
@@ -21,12 +22,7 @@ void DiscordManager::ProcessMessageQueue()
for (auto &q: webhook_message_queue) { for (auto &q: webhook_message_queue) {
LogDiscord("Processing [{}] messages in queue for webhook ID [{}]...", q.second.size(), q.first); LogDiscord("Processing [{}] messages in queue for webhook ID [{}]...", q.second.size(), q.first);
if (q.first >= MAX_DISCORD_WEBHOOK_ID) { auto webhook = LogSys.discord_webhooks[q.first];
LogDiscord("Out of bounds webhook ID [{}] max [{}]", q.first, MAX_DISCORD_WEBHOOK_ID);
continue;
}
auto webhook = LogSys.GetDiscordWebhooks()[q.first];
std::string message; std::string message;
for (auto &m: q.second) { for (auto &m: q.second) {
@@ -37,7 +33,7 @@ void DiscordManager::ProcessMessageQueue()
message, message,
webhook.webhook_url webhook.webhook_url
); );
message.clear(); message = "";
} }
message += m; message += m;
@@ -51,9 +47,10 @@ void DiscordManager::ProcessMessageQueue()
webhook.webhook_url webhook.webhook_url
); );
} }
message.clear(); message = "";
} }
} }
// final flush // final flush
if (!message.empty()) { if (!message.empty()) {
Discord::SendWebhookMessage( Discord::SendWebhookMessage(
@@ -61,15 +58,8 @@ void DiscordManager::ProcessMessageQueue()
webhook.webhook_url webhook.webhook_url
); );
} }
webhook_message_queue.erase(q.first);
} }
webhook_message_queue.clear();
webhook_queue_lock.unlock(); webhook_queue_lock.unlock();
} }
void DiscordManager::QueuePlayerEventMessage(const PlayerEvent::PlayerEventContainer& e)
{
auto w = player_event_logs.GetDiscordWebhookUrlFromEventType(e.player_event_log.event_type_id);
if (!w.empty()) {
Discord::SendPlayerEventMessage(e, w);
}
}
@@ -4,15 +4,12 @@
#include <mutex> #include <mutex>
#include <map> #include <map>
#include <vector> #include <vector>
#include "../../common/types.h" #include "../common/types.h"
#include "../repositories/player_event_logs_repository.h"
#include "../events/player_events.h"
class DiscordManager { class DiscordManager {
public: public:
void QueueWebhookMessage(uint32 webhook_id, const std::string& message); void QueueWebhookMessage(uint32 webhook_id, const std::string& message);
void ProcessMessageQueue(); void ProcessMessageQueue();
void QueuePlayerEventMessage(const PlayerEvent::PlayerEventContainer& e);
private: private:
std::mutex webhook_queue_lock{}; std::mutex webhook_queue_lock{};
std::map<uint32, std::vector<std::string>> webhook_message_queue{}; std::map<uint32, std::vector<std::string>> webhook_message_queue{};
-49
View File
@@ -79,7 +79,6 @@ void DynamicZoneBase::LoadRepositoryResult(DynamicZonesRepository::DynamicZoneIn
m_max_players = dz_entry.max_players; m_max_players = dz_entry.max_players;
m_instance_id = dz_entry.instance_id; m_instance_id = dz_entry.instance_id;
m_type = static_cast<DynamicZoneType>(dz_entry.type); m_type = static_cast<DynamicZoneType>(dz_entry.type);
m_dz_switch_id = dz_entry.dz_switch_id;
m_compass.zone_id = dz_entry.compass_zone_id; m_compass.zone_id = dz_entry.compass_zone_id;
m_compass.x = dz_entry.compass_x; m_compass.x = dz_entry.compass_x;
m_compass.y = dz_entry.compass_y; m_compass.y = dz_entry.compass_y;
@@ -130,7 +129,6 @@ uint32_t DynamicZoneBase::SaveToDatabase()
insert_dz.max_players = m_max_players; insert_dz.max_players = m_max_players;
insert_dz.instance_id = m_instance_id, insert_dz.instance_id = m_instance_id,
insert_dz.type = static_cast<int>(m_type); insert_dz.type = static_cast<int>(m_type);
insert_dz.dz_switch_id = m_dz_switch_id;
insert_dz.compass_zone_id = m_compass.zone_id; insert_dz.compass_zone_id = m_compass.zone_id;
insert_dz.compass_x = m_compass.x; insert_dz.compass_x = m_compass.x;
insert_dz.compass_y = m_compass.y; insert_dz.compass_y = m_compass.y;
@@ -318,17 +316,6 @@ void DynamicZoneBase::SetZoneInLocation(float x, float y, float z, float heading
SetZoneInLocation({ 0, x, y, z, heading }, update_db); SetZoneInLocation({ 0, x, y, z, heading }, update_db);
} }
void DynamicZoneBase::SetSwitchID(int dz_switch_id, bool update_db)
{
m_dz_switch_id = dz_switch_id;
if (update_db)
{
DynamicZonesRepository::UpdateSwitchID(GetDatabase(), m_id, dz_switch_id);
SendServerPacket(CreateServerDzSwitchIDPacket().get());
}
}
void DynamicZoneBase::SetLeader(const DynamicZoneMember& new_leader, bool update_db) void DynamicZoneBase::SetLeader(const DynamicZoneMember& new_leader, bool update_db)
{ {
m_leader = new_leader; m_leader = new_leader;
@@ -416,17 +403,6 @@ std::unique_ptr<ServerPacket> DynamicZoneBase::CreateServerDzLocationPacket(
return pack; return pack;
} }
std::unique_ptr<ServerPacket> DynamicZoneBase::CreateServerDzSwitchIDPacket()
{
constexpr uint32_t pack_size = sizeof(ServerDzSwitchID_Struct);
auto pack = std::make_unique<ServerPacket>(ServerOP_DzSetSwitchID, pack_size);
auto buf = reinterpret_cast<ServerDzSwitchID_Struct*>(pack->pBuffer);
buf->dz_id = GetID();
buf->dz_switch_id = GetSwitchID();
return pack;
}
std::unique_ptr<ServerPacket> DynamicZoneBase::CreateServerMemberStatusPacket( std::unique_ptr<ServerPacket> DynamicZoneBase::CreateServerMemberStatusPacket(
uint32_t character_id, DynamicZoneMemberStatus status) uint32_t character_id, DynamicZoneMemberStatus status)
{ {
@@ -622,28 +598,3 @@ void DynamicZoneBase::LoadSerializedDzPacket(char* cereal_data, uint32_t cereal_
cereal::BinaryInputArchive archive(ss); cereal::BinaryInputArchive archive(ss);
archive(*this); archive(*this);
} }
void DynamicZoneBase::LoadTemplate(const DynamicZoneTemplatesRepository::DynamicZoneTemplates& dz_template)
{
m_zone_id = dz_template.zone_id;
m_zone_version = dz_template.zone_version;
m_name = dz_template.name;
m_min_players = dz_template.min_players;
m_max_players = dz_template.max_players;
m_duration = std::chrono::seconds(dz_template.duration_seconds);
m_dz_switch_id = dz_template.dz_switch_id;
m_compass.zone_id = dz_template.compass_zone_id;
m_compass.x = dz_template.compass_x;
m_compass.y = dz_template.compass_y;
m_compass.z = dz_template.compass_z;
m_safereturn.zone_id = dz_template.return_zone_id;
m_safereturn.x = dz_template.return_x;
m_safereturn.y = dz_template.return_y;
m_safereturn.z = dz_template.return_z;
m_safereturn.heading = dz_template.return_h;
m_has_zonein = dz_template.override_zone_in;
m_zonein.x = dz_template.zone_in_x;
m_zonein.y = dz_template.zone_in_y;
m_zonein.z = dz_template.zone_in_z;
m_zonein.heading = dz_template.zone_in_h;
}
-9
View File
@@ -5,7 +5,6 @@
#include "net/packet.h" #include "net/packet.h"
#include "repositories/dynamic_zones_repository.h" #include "repositories/dynamic_zones_repository.h"
#include "repositories/dynamic_zone_members_repository.h" #include "repositories/dynamic_zone_members_repository.h"
#include "repositories/dynamic_zone_templates_repository.h"
#include <algorithm> #include <algorithm>
#include <chrono> #include <chrono>
#include <cstdint> #include <cstdint>
@@ -75,7 +74,6 @@ public:
virtual void SetSecondsRemaining(uint32_t seconds_remaining) = 0; virtual void SetSecondsRemaining(uint32_t seconds_remaining) = 0;
int GetDuration() const { return static_cast<int>(m_duration.count()); }
uint64_t GetExpireTime() const { return std::chrono::system_clock::to_time_t(m_expire_time); } uint64_t GetExpireTime() const { return std::chrono::system_clock::to_time_t(m_expire_time); }
uint32_t GetID() const { return m_id; } uint32_t GetID() const { return m_id; }
uint16_t GetInstanceID() const { return static_cast<uint16_t>(m_instance_id); } uint16_t GetInstanceID() const { return static_cast<uint16_t>(m_instance_id); }
@@ -87,7 +85,6 @@ public:
uint16_t GetZoneID() const { return static_cast<uint16_t>(m_zone_id); } uint16_t GetZoneID() const { return static_cast<uint16_t>(m_zone_id); }
uint32_t GetZoneIndex() const { return (m_instance_id << 16) | (m_zone_id & 0xffff); } uint32_t GetZoneIndex() const { return (m_instance_id << 16) | (m_zone_id & 0xffff); }
uint32_t GetZoneVersion() const { return m_zone_version; } uint32_t GetZoneVersion() const { return m_zone_version; }
int GetSwitchID() const { return m_dz_switch_id; }
DynamicZoneType GetType() const { return m_type; } DynamicZoneType GetType() const { return m_type; }
const std::string& GetLeaderName() const { return m_leader.name; } const std::string& GetLeaderName() const { return m_leader.name; }
const std::string& GetName() const { return m_name; } const std::string& GetName() const { return m_name; }
@@ -115,7 +112,6 @@ public:
bool IsValid() const { return m_instance_id != 0; } bool IsValid() const { return m_instance_id != 0; }
bool IsSameDz(uint32_t zone_id, uint32_t instance_id) const { return zone_id == m_zone_id && instance_id == m_instance_id; } bool IsSameDz(uint32_t zone_id, uint32_t instance_id) const { return zone_id == m_zone_id && instance_id == m_instance_id; }
void LoadSerializedDzPacket(char* cereal_data, uint32_t cereal_size); void LoadSerializedDzPacket(char* cereal_data, uint32_t cereal_size);
void LoadTemplate(const DynamicZoneTemplatesRepository::DynamicZoneTemplates& dz_template);
void RemoveAllMembers(); void RemoveAllMembers();
bool RemoveMember(uint32_t character_id); bool RemoveMember(uint32_t character_id);
bool RemoveMember(const std::string& character_name); bool RemoveMember(const std::string& character_name);
@@ -131,7 +127,6 @@ public:
void SetName(const std::string& name) { m_name = name; } void SetName(const std::string& name) { m_name = name; }
void SetSafeReturn(const DynamicZoneLocation& location, bool update_db = false); void SetSafeReturn(const DynamicZoneLocation& location, bool update_db = false);
void SetSafeReturn(uint32_t zone_id, float x, float y, float z, float heading, bool update_db = false); void SetSafeReturn(uint32_t zone_id, float x, float y, float z, float heading, bool update_db = false);
void SetSwitchID(int dz_switch_id, bool update_db = false);
void SetType(DynamicZoneType type) { m_type = type; } void SetType(DynamicZoneType type) { m_type = type; }
void SetUUID(std::string uuid) { m_uuid = std::move(uuid); } void SetUUID(std::string uuid) { m_uuid = std::move(uuid); }
void SetZoneInLocation(const DynamicZoneLocation& location, bool update_db = false); void SetZoneInLocation(const DynamicZoneLocation& location, bool update_db = false);
@@ -146,7 +141,6 @@ protected:
virtual void ProcessMemberAddRemove(const DynamicZoneMember& member, bool removed); virtual void ProcessMemberAddRemove(const DynamicZoneMember& member, bool removed);
virtual bool ProcessMemberStatusChange(uint32_t member_id, DynamicZoneMemberStatus status); virtual bool ProcessMemberStatusChange(uint32_t member_id, DynamicZoneMemberStatus status);
virtual void ProcessRemoveAllMembers(bool silent = false) { m_members.clear(); } virtual void ProcessRemoveAllMembers(bool silent = false) { m_members.clear(); }
virtual void ProcessSetSwitchID(int dz_switch_id) { m_dz_switch_id = dz_switch_id; }
virtual bool SendServerPacket(ServerPacket* packet) = 0; virtual bool SendServerPacket(ServerPacket* packet) = 0;
void AddInternalMember(const DynamicZoneMember& member); void AddInternalMember(const DynamicZoneMember& member);
@@ -159,7 +153,6 @@ protected:
std::unique_ptr<ServerPacket> CreateServerDzCreatePacket(uint16_t origin_zone_id, uint16_t origin_instance_id); std::unique_ptr<ServerPacket> CreateServerDzCreatePacket(uint16_t origin_zone_id, uint16_t origin_instance_id);
std::unique_ptr<ServerPacket> CreateServerDzLocationPacket(uint16_t server_opcode, const DynamicZoneLocation& location); std::unique_ptr<ServerPacket> CreateServerDzLocationPacket(uint16_t server_opcode, const DynamicZoneLocation& location);
std::unique_ptr<ServerPacket> CreateServerDzSwitchIDPacket();
std::unique_ptr<ServerPacket> CreateServerMemberAddRemovePacket(const DynamicZoneMember& member, bool removed); std::unique_ptr<ServerPacket> CreateServerMemberAddRemovePacket(const DynamicZoneMember& member, bool removed);
std::unique_ptr<ServerPacket> CreateServerMemberStatusPacket(uint32_t character_id, DynamicZoneMemberStatus status); std::unique_ptr<ServerPacket> CreateServerMemberStatusPacket(uint32_t character_id, DynamicZoneMemberStatus status);
std::unique_ptr<ServerPacket> CreateServerMemberSwapPacket(const DynamicZoneMember& remove_member, const DynamicZoneMember& add_member); std::unique_ptr<ServerPacket> CreateServerMemberSwapPacket(const DynamicZoneMember& remove_member, const DynamicZoneMember& add_member);
@@ -171,7 +164,6 @@ protected:
uint32_t m_zone_version = 0; uint32_t m_zone_version = 0;
uint32_t m_min_players = 0; uint32_t m_min_players = 0;
uint32_t m_max_players = 0; uint32_t m_max_players = 0;
int m_dz_switch_id = 0;
bool m_never_expires = false; bool m_never_expires = false;
bool m_has_zonein = false; bool m_has_zonein = false;
bool m_has_member_statuses = false; bool m_has_member_statuses = false;
@@ -198,7 +190,6 @@ public:
m_zone_version, m_zone_version,
m_min_players, m_min_players,
m_max_players, m_max_players,
m_dz_switch_id,
m_never_expires, m_never_expires,
m_has_zonein, m_has_zonein,
m_has_member_statuses, m_has_member_statuses,
+23 -171
View File
@@ -18,12 +18,9 @@
*/ */
#include "emu_constants.h" #include "emu_constants.h"
#include "bodytypes.h"
#include "data_verification.h"
#include "eqemu_logsys.h"
#include "eqemu_logsys_log_aliases.h"
#include "languages.h" #include "languages.h"
#include "rulesys.h" #include "data_verification.h"
#include "bodytypes.h"
int16 EQ::invtype::GetInvTypeSize(int16 inv_type) { int16 EQ::invtype::GetInvTypeSize(int16 inv_type) {
static const int16 local_array[] = { static const int16 local_array[] = {
@@ -197,11 +194,11 @@ const std::map<int, std::string>& EQ::constants::GetLanguageMap()
std::string EQ::constants::GetLanguageName(int language_id) std::string EQ::constants::GetLanguageName(int language_id)
{ {
if (!EQ::ValueWithin(language_id, LANG_COMMON_TONGUE, LANG_UNKNOWN)) { if (EQ::ValueWithin(language_id, LANG_COMMON_TONGUE, LANG_UNKNOWN)) {
return std::string(); return EQ::constants::GetLanguageMap().find(language_id)->second;
} }
return EQ::constants::GetLanguageMap().find(language_id)->second; return std::string();
} }
const std::map<uint32, std::string>& EQ::constants::GetLDoNThemeMap() const std::map<uint32, std::string>& EQ::constants::GetLDoNThemeMap()
@@ -220,11 +217,11 @@ const std::map<uint32, std::string>& EQ::constants::GetLDoNThemeMap()
std::string EQ::constants::GetLDoNThemeName(uint32 theme_id) std::string EQ::constants::GetLDoNThemeName(uint32 theme_id)
{ {
if (!EQ::ValueWithin(theme_id, LDoNThemes::Unused, LDoNThemes::TAK)) { if (EQ::ValueWithin(theme_id, LDoNThemes::Unused, LDoNThemes::TAK)) {
return std::string(); return EQ::constants::GetLDoNThemeMap().find(theme_id)->second;
} }
return EQ::constants::GetLDoNThemeMap().find(theme_id)->second; return std::string();
} }
const std::map<int8, std::string>& EQ::constants::GetFlyModeMap() const std::map<int8, std::string>& EQ::constants::GetFlyModeMap()
@@ -243,11 +240,11 @@ const std::map<int8, std::string>& EQ::constants::GetFlyModeMap()
std::string EQ::constants::GetFlyModeName(int8 flymode_id) std::string EQ::constants::GetFlyModeName(int8 flymode_id)
{ {
if (!EQ::ValueWithin(flymode_id, GravityBehavior::Ground, GravityBehavior::LevitateWhileRunning)) { if (EQ::ValueWithin(flymode_id, GravityBehavior::Ground, GravityBehavior::LevitateWhileRunning)) {
return std::string(); return EQ::constants::GetFlyModeMap().find(flymode_id)->second;
} }
return EQ::constants::GetFlyModeMap().find(flymode_id)->second; return std::string();
} }
const std::map<bodyType, std::string>& EQ::constants::GetBodyTypeMap() const std::map<bodyType, std::string>& EQ::constants::GetBodyTypeMap()
@@ -365,11 +362,11 @@ const std::map<uint8, std::string>& EQ::constants::GetConsiderLevelMap()
std::string EQ::constants::GetConsiderLevelName(uint8 faction_consider_level) std::string EQ::constants::GetConsiderLevelName(uint8 faction_consider_level)
{ {
if (!EQ::ValueWithin(faction_consider_level, ConsiderLevel::Ally, ConsiderLevel::Scowls)) { if (EQ::constants::GetConsiderLevelMap().find(faction_consider_level) != EQ::constants::GetConsiderLevelMap().end()) {
return std::string();; return EQ::constants::GetConsiderLevelMap().find(faction_consider_level)->second;
} }
return EQ::constants::GetConsiderLevelMap().find(faction_consider_level)->second; return std::string();
} }
const std::map<uint8, std::string>& EQ::constants::GetEnvironmentalDamageMap() const std::map<uint8, std::string>& EQ::constants::GetEnvironmentalDamageMap()
@@ -386,11 +383,11 @@ const std::map<uint8, std::string>& EQ::constants::GetEnvironmentalDamageMap()
std::string EQ::constants::GetEnvironmentalDamageName(uint8 damage_type) std::string EQ::constants::GetEnvironmentalDamageName(uint8 damage_type)
{ {
if (!EQ::ValueWithin(damage_type, EnvironmentalDamage::Lava, EnvironmentalDamage::Trap)) { if (EQ::ValueWithin(damage_type, EnvironmentalDamage::Lava, EnvironmentalDamage::Trap)) {
return std::string(); return EQ::constants::GetEnvironmentalDamageMap().find(damage_type)->second;
} }
return EQ::constants::GetEnvironmentalDamageMap().find(damage_type)->second; return std::string();
} }
const std::map<uint8, std::string>& EQ::constants::GetStuckBehaviorMap() const std::map<uint8, std::string>& EQ::constants::GetStuckBehaviorMap()
@@ -407,11 +404,11 @@ const std::map<uint8, std::string>& EQ::constants::GetStuckBehaviorMap()
std::string EQ::constants::GetStuckBehaviorName(uint8 behavior_id) std::string EQ::constants::GetStuckBehaviorName(uint8 behavior_id)
{ {
if (!EQ::ValueWithin(behavior_id, StuckBehavior::RunToTarget, StuckBehavior::EvadeCombat)) { if (EQ::ValueWithin(behavior_id, StuckBehavior::RunToTarget, StuckBehavior::EvadeCombat)) {
return std::string(); return EQ::constants::GetStuckBehaviorMap().find(behavior_id)->second;
} }
return EQ::constants::GetStuckBehaviorMap().find(behavior_id)->second; return std::string();
} }
const std::map<uint8, std::string>& EQ::constants::GetSpawnAnimationMap() const std::map<uint8, std::string>& EQ::constants::GetSpawnAnimationMap()
@@ -429,154 +426,9 @@ const std::map<uint8, std::string>& EQ::constants::GetSpawnAnimationMap()
std::string EQ::constants::GetSpawnAnimationName(uint8 animation_id) std::string EQ::constants::GetSpawnAnimationName(uint8 animation_id)
{ {
if (!EQ::ValueWithin(animation_id, SpawnAnimations::Standing, SpawnAnimations::Looting)) { if (EQ::ValueWithin(animation_id, SpawnAnimations::Standing, SpawnAnimations::Looting)) {
return std::string(); return EQ::constants::GetSpawnAnimationMap().find(animation_id)->second;
} }
return EQ::constants::GetSpawnAnimationMap().find(animation_id)->second; return std::string();
}
const std::map<int, std::string>& EQ::constants::GetObjectTypeMap()
{
static const std::map<int, std::string> object_type_map = {
{ ObjectTypes::SmallBag, "Small Bag" },
{ ObjectTypes::LargeBag, "Large Bag" },
{ ObjectTypes::Quiver, "Quiver" },
{ ObjectTypes::BeltPouch, "Belt Pouch" },
{ ObjectTypes::WristPouch, "Wrist Pouch" },
{ ObjectTypes::Backpack, "Backpack" },
{ ObjectTypes::SmallChest, "Small Chest" },
{ ObjectTypes::LargeChest, "Large Chest" },
{ ObjectTypes::Bandolier, "Bandolier" },
{ ObjectTypes::Medicine, "Medicine" },
{ ObjectTypes::Tinkering, "Tinkering" },
{ ObjectTypes::Lexicon, "Lexicon" },
{ ObjectTypes::PoisonMaking, "Mortar and Pestle" },
{ ObjectTypes::Quest, "Quest" },
{ ObjectTypes::MixingBowl, "Mixing Bowl" },
{ ObjectTypes::Baking, "Baking" },
{ ObjectTypes::Tailoring, "Tailoring" },
{ ObjectTypes::Blacksmithing, "Blacksmithing" },
{ ObjectTypes::Fletching, "Fletching" },
{ ObjectTypes::Brewing, "Brewing" },
{ ObjectTypes::JewelryMaking, "Jewelry Making" },
{ ObjectTypes::Pottery, "Pottery" },
{ ObjectTypes::Kiln, "Kiln" },
{ ObjectTypes::KeyMaker, "Key Maker" },
{ ObjectTypes::ResearchWIZ, "Lexicon" },
{ ObjectTypes::ResearchMAG, "Lexicon" },
{ ObjectTypes::ResearchNEC, "Lexicon" },
{ ObjectTypes::ResearchENC, "Lexicon" },
{ ObjectTypes::Unknown, "Unknown" },
{ ObjectTypes::ResearchPractice, "Lexicon" },
{ ObjectTypes::Alchemy, "Alchemy" },
{ ObjectTypes::HighElfForge, "High Elf Forge" },
{ ObjectTypes::DarkElfForge, "Dark Elf Forge" },
{ ObjectTypes::OgreForge, "Ogre Forge" },
{ ObjectTypes::DwarfForge, "Dwarf Forge" },
{ ObjectTypes::GnomeForge, "Gnome Forge" },
{ ObjectTypes::BarbarianForge, "Barbarian Forge" },
{ ObjectTypes::IksarForge, "Iksar Forge" },
{ ObjectTypes::HumanForgeOne, "Human Forge" },
{ ObjectTypes::HumanForgeTwo, "Human Forge" },
{ ObjectTypes::HalflingTailoringOne, "Halfling Tailoring" },
{ ObjectTypes::HalflingTailoringTwo, "Halfling Tailoring" },
{ ObjectTypes::EruditeTailoring, "Erudite Tailoring" },
{ ObjectTypes::WoodElfTailoring, "Wood Elf Tailoring" },
{ ObjectTypes::WoodElfFletching, "Wood Elf Fletching" },
{ ObjectTypes::IksarPottery, "Iksar Pottery" },
{ ObjectTypes::Fishing, "Fishing" },
{ ObjectTypes::TrollForge, "Troll Forge" },
{ ObjectTypes::WoodElfForge, "Wood Elf Forge" },
{ ObjectTypes::HalflingForge, "Halfling Forge" },
{ ObjectTypes::EruditeForge, "Erudite Forge" },
{ ObjectTypes::Merchant, "Merchant" },
{ ObjectTypes::FroglokForge, "Froglok Forge" },
{ ObjectTypes::Augmenter, "Augmenter" },
{ ObjectTypes::Churn, "Churn" },
{ ObjectTypes::TransformationMold, "Transformation Mold" },
{ ObjectTypes::DetransformationMold, "Detransformation Mold" },
{ ObjectTypes::Unattuner, "Unattuner" },
{ ObjectTypes::TradeskillBag, "Tradeskill Bag" },
{ ObjectTypes::CollectibleBag, "Collectible Bag" },
{ ObjectTypes::NoDeposit, "No Deposit" }
};
return object_type_map;
}
std::string EQ::constants::GetObjectTypeName(int object_type)
{
if (!EQ::ValueWithin(object_type, ObjectTypes::SmallBag, ObjectTypes::NoDeposit)) {
return std::string();
}
return EQ::constants::GetObjectTypeMap().find(object_type)->second;
}
const std::map<uint8, std::string> &EQ::constants::GetWeatherTypeMap()
{
static const std::map<uint8, std::string> weather_type_map = {
{WeatherTypes::None, "None"},
{WeatherTypes::Raining, "Raining"},
{WeatherTypes::Snowing, "Snowing"}
};
return weather_type_map;
}
std::string EQ::constants::GetWeatherTypeName(uint8 weather_type)
{
if (!EQ::ValueWithin(weather_type, WeatherTypes::None, WeatherTypes::Snowing)) {
return std::string();
}
return EQ::constants::GetWeatherTypeMap().find(weather_type)->second;
}
const std::map<uint8, std::string> &EQ::constants::GetEmoteEventTypeMap()
{
static const std::map<uint8, std::string> emote_event_type_map = {
{ EmoteEventTypes::LeaveCombat, "Leave Combat" },
{ EmoteEventTypes::EnterCombat, "Enter Combat" },
{ EmoteEventTypes::OnDeath, "On Death" },
{ EmoteEventTypes::AfterDeath, "After Death" },
{ EmoteEventTypes::Hailed, "Hailed" },
{ EmoteEventTypes::KilledPC, "Killed PC" },
{ EmoteEventTypes::KilledNPC, "Killed NPC" },
{ EmoteEventTypes::OnSpawn, "On Spawn" },
{ EmoteEventTypes::OnDespawn, "On Despawn" }
};
return emote_event_type_map;
}
std::string EQ::constants::GetEmoteEventTypeName(uint8 emote_event_type)
{
if (!EQ::ValueWithin(emote_event_type, EmoteEventTypes::LeaveCombat, EmoteEventTypes::OnDespawn)) {
return std::string();
}
return EQ::constants::GetEmoteEventTypeMap().find(emote_event_type)->second;
}
const std::map<uint8, std::string> &EQ::constants::GetEmoteTypeMap()
{
static const std::map<uint8, std::string> emote_type_map = {
{ EmoteTypes::Emote, "Emote" },
{ EmoteTypes::Shout, "Shout" },
{ EmoteTypes::Proximity, "Proximity" }
};
return emote_type_map;
}
std::string EQ::constants::GetEmoteTypeName(uint8 emote_type)
{
if (!EQ::ValueWithin(emote_type, EmoteTypes::Emote, EmoteTypes::Proximity)) {
return std::string();
}
return EQ::constants::GetEmoteTypeMap().find(emote_type)->second;
} }
+5 -158
View File
@@ -33,6 +33,10 @@ namespace EQ
using RoF2::IINVALID; using RoF2::IINVALID;
using RoF2::INULL; using RoF2::INULL;
namespace inventory {
} /*inventory*/
namespace invtype { namespace invtype {
using namespace RoF2::invtype::enum_; using namespace RoF2::invtype::enum_;
@@ -217,25 +221,6 @@ namespace EQ
stanceBurnAE stanceBurnAE
}; };
enum BotSpellIDs : int {
Warrior = 3001,
Cleric,
Paladin,
Ranger,
Shadowknight,
Druid,
Monk,
Bard,
Rogue,
Shaman,
Necromancer,
Wizard,
Magician,
Enchanter,
Beastlord,
Berserker
};
enum GravityBehavior : int8 { enum GravityBehavior : int8 {
Ground, Ground,
Flying, Flying,
@@ -267,94 +252,6 @@ namespace EQ
Looting Looting
}; };
enum ObjectTypes : int {
SmallBag,
LargeBag,
Quiver,
BeltPouch,
WristPouch,
Backpack,
SmallChest,
LargeChest,
Bandolier,
Medicine,
Tinkering,
Lexicon,
PoisonMaking,
Quest,
MixingBowl,
Baking,
Tailoring,
Blacksmithing,
Fletching,
Brewing,
JewelryMaking,
Pottery,
Kiln,
KeyMaker,
ResearchWIZ,
ResearchMAG,
ResearchNEC,
ResearchENC,
Unknown,
ResearchPractice,
Alchemy,
HighElfForge,
DarkElfForge,
OgreForge,
DwarfForge,
GnomeForge,
BarbarianForge,
IksarForge,
HumanForgeOne,
HumanForgeTwo,
HalflingTailoringOne,
HalflingTailoringTwo,
EruditeTailoring,
WoodElfTailoring,
WoodElfFletching,
IksarPottery,
Fishing,
TrollForge,
WoodElfForge,
HalflingForge,
EruditeForge,
Merchant,
FroglokForge,
Augmenter,
Churn,
TransformationMold,
DetransformationMold,
Unattuner,
TradeskillBag,
CollectibleBag,
NoDeposit
};
enum WeatherTypes : uint8 {
None,
Raining,
Snowing
};
enum EmoteEventTypes : uint8 {
LeaveCombat,
EnterCombat,
OnDeath,
AfterDeath,
Hailed,
KilledPC,
KilledNPC,
OnSpawn,
OnDespawn
};
enum EmoteTypes : uint8 {
Emote,
Shout,
Proximity
};
const char *GetStanceName(StanceType stance_type); const char *GetStanceName(StanceType stance_type);
int ConvertStanceTypeToIndex(StanceType stance_type); int ConvertStanceTypeToIndex(StanceType stance_type);
@@ -385,18 +282,6 @@ namespace EQ
extern const std::map<uint8, std::string>& GetSpawnAnimationMap(); extern const std::map<uint8, std::string>& GetSpawnAnimationMap();
std::string GetSpawnAnimationName(uint8 animation_id); std::string GetSpawnAnimationName(uint8 animation_id);
extern const std::map<int, std::string>& GetObjectTypeMap();
std::string GetObjectTypeName(int object_type);
extern const std::map<uint8, std::string>& GetWeatherTypeMap();
std::string GetWeatherTypeName(uint8 weather_type);
extern const std::map<uint8, std::string>& GetEmoteEventTypeMap();
std::string GetEmoteEventTypeName(uint8 emote_event_type);
extern const std::map<uint8, std::string>& GetEmoteTypeMap();
std::string GetEmoteTypeName(uint8 emote_type);
const int STANCE_TYPE_FIRST = stancePassive; const int STANCE_TYPE_FIRST = stancePassive;
const int STANCE_TYPE_LAST = stanceBurnAE; const int STANCE_TYPE_LAST = stanceBurnAE;
const int STANCE_TYPE_COUNT = stanceBurnAE; const int STANCE_TYPE_COUNT = stanceBurnAE;
@@ -567,7 +452,7 @@ enum ReloadWorld : uint8 {
ForceRepop ForceRepop
}; };
enum BucketComparison : uint8 { enum MerchantBucketComparison : uint8 {
BucketEqualTo = 0, BucketEqualTo = 0,
BucketNotEqualTo, BucketNotEqualTo,
BucketGreaterThanOrEqualTo, BucketGreaterThanOrEqualTo,
@@ -580,42 +465,4 @@ enum BucketComparison : uint8 {
BucketIsNotBetween BucketIsNotBetween
}; };
enum class EntityFilterType {
All,
Bots,
Clients,
NPCs
};
enum class ApplySpellType {
Solo,
Group,
Raid
};
namespace HeroicBonusBucket
{
const std::string WisMaxMana = "HWIS-MaxMana";
const std::string WisManaRegen = "HWIS-ManaRegen";
const std::string WisHealAmt = "HWIS-HealAmt";
const std::string IntMaxMana = "HINT-MaxMana";
const std::string IntManaRegen = "HINT-ManaRegen";
const std::string IntSpellDmg = "HINT-SpellDmg";
const std::string StrMeleeDamage = "HSTR-MeleeDamage";
const std::string StrShieldAC = "HSTR-ShieldAC";
const std::string StrMaxEndurance = "HSTR-MaxEndurance";
const std::string StrEnduranceRegen = "HSTR-EnduranceRegen";
const std::string StaMaxHP = "HSTA-MaxHP";
const std::string StaHPRegen = "HSTA-HPRegen";
const std::string StaMaxEndurance = "HSTA-MaxEndurance";
const std::string StaEnduranceRegen = "HSTA-EnduranceRegen";
const std::string AgiAvoidance = "HAGI-Avoidance";
const std::string AgiMaxEndurance = "HAGI-MaxEndurance";
const std::string AgiEnduranceRegen = "HAGI-EnduranceRegen";
const std::string DexRangedDamage = "HDEX-RangedDamage";
const std::string DexMaxEndurance = "HDEX-MaxEndurance";
const std::string DexEnduranceRegen = "HDEX-EnduranceRegen";
}
#endif /*COMMON_EMU_CONSTANTS_H*/ #endif /*COMMON_EMU_CONSTANTS_H*/
+1 -3
View File
@@ -35,7 +35,7 @@ N(OP_AltCurrencyMerchantRequest),
N(OP_AltCurrencyPurchase), N(OP_AltCurrencyPurchase),
N(OP_AltCurrencyReclaim), N(OP_AltCurrencyReclaim),
N(OP_AltCurrencySell), N(OP_AltCurrencySell),
N(OP_AltCurrencySellSelection), // Used by eqstr_us.txt 8066, 8068, 8069 N(OP_AltCurrencySellSelection),
N(OP_Animation), N(OP_Animation),
N(OP_AnnoyingZoneUnknown), N(OP_AnnoyingZoneUnknown),
N(OP_ApplyPoison), N(OP_ApplyPoison),
@@ -71,7 +71,6 @@ N(OP_Camp),
N(OP_CancelSneakHide), N(OP_CancelSneakHide),
N(OP_CancelTask), N(OP_CancelTask),
N(OP_CancelTrade), N(OP_CancelTrade),
N(OP_CashReward),
N(OP_CastSpell), N(OP_CastSpell),
N(OP_ChangeSize), N(OP_ChangeSize),
N(OP_ChannelMessage), N(OP_ChannelMessage),
@@ -304,7 +303,6 @@ N(OP_LockoutTimerInfo),
N(OP_Login), N(OP_Login),
N(OP_LoginAccepted), N(OP_LoginAccepted),
N(OP_LoginComplete), N(OP_LoginComplete),
N(OP_LoginExpansionPacketData), //added for Rof2 client to send expansion data packet. Requires login_opcodes_sod.conf to be updated.
N(OP_LoginUnknown1), N(OP_LoginUnknown1),
N(OP_LoginUnknown2), N(OP_LoginUnknown2),
N(OP_Logout), N(OP_Logout),
+9 -45
View File
@@ -79,8 +79,6 @@
#define ANIM_DEATH 0x73 #define ANIM_DEATH 0x73
#define ANIM_LOOT 0x69 #define ANIM_LOOT 0x69
constexpr int16 RECAST_TYPE_UNLINKED_ITEM = -1;
typedef enum { typedef enum {
eaStanding = 0, eaStanding = 0,
eaSitting, //1 eaSitting, //1
@@ -686,6 +684,14 @@ namespace Zones {
constexpr uint16 APPRENTICE = 999; // Designer Apprentice constexpr uint16 APPRENTICE = 999; // Designer Apprentice
} }
//ZoneChange_Struct->success values
#define ZONE_ERROR_NOMSG 0
#define ZONE_ERROR_NOTREADY -1
#define ZONE_ERROR_VALIDPC -2
#define ZONE_ERROR_STORYZONE -3
#define ZONE_ERROR_NOEXPANSION -6
#define ZONE_ERROR_NOEXPERIENCE -7
typedef enum { typedef enum {
FilterNone = 0, FilterNone = 0,
@@ -712,7 +718,7 @@ typedef enum {
FilterPetMisses = 21, //0=show, 1=hide FilterPetMisses = 21, //0=show, 1=hide
FilterFocusEffects = 22, //0=show, 1=hide FilterFocusEffects = 22, //0=show, 1=hide
FilterPetSpells = 23, //0=show, 1=hide FilterPetSpells = 23, //0=show, 1=hide
FilterHealOverTime = 24, //0=show, 1=mine only, 2=hide FilterHealOverTime = 24, //0=show, 1=hide
FilterUnknown25 = 25, FilterUnknown25 = 25,
FilterUnknown26 = 26, FilterUnknown26 = 26,
FilterUnknown27 = 27, FilterUnknown27 = 27,
@@ -1003,46 +1009,4 @@ enum StartZoneIndex {
SharVahl SharVahl
}; };
enum FVNoDropFlagRule
{
Disabled = 0,
Enabled = 1,
AdminOnly = 2
};
enum Anonymity : uint8
{
NotAnonymous,
Anonymous,
Roleplaying
};
enum ZoningMessage : int8 {
ZoneNoMessage = 0,
ZoneSuccess = 1,
ZoneNotReady = -1,
ZoneValidPC = -2,
ZoneStoryZone = -3,
ZoneNoExpansion = -6,
ZoneNoExperience = -7
};
enum class RecipeCountType : uint8
{
Component,
Container,
Fail,
Salvage,
Success
};
#define ALT_CURRENCY_ID_RADIANT 4
#define ALT_CURRENCY_ID_EBON 5
enum ResurrectionActions
{
Decline,
Accept
};
#endif /*COMMON_EQ_CONSTANTS_H*/ #endif /*COMMON_EQ_CONSTANTS_H*/
+1 -1
View File
@@ -26,7 +26,7 @@
static bool global_dictionary_init = false; static bool global_dictionary_init = false;
void EQ::InitializeDynamicLookups() { void EQ::InitializeDynamicLookups() {
if (global_dictionary_init) if (global_dictionary_init == true)
return; return;
constants::InitializeDynamicLookups(); constants::InitializeDynamicLookups();
+1 -1
View File
@@ -129,7 +129,7 @@ namespace EQ
LookupEntry(const LookupEntry *lookup_entry) { } LookupEntry(const LookupEntry *lookup_entry) { }
LookupEntry( LookupEntry(
const InventoryTypeSize_Struct& InventoryTypeSize, InventoryTypeSize_Struct InventoryTypeSize,
uint64 EquipmentBitmask, uint64 EquipmentBitmask,
uint64 GeneralBitmask, uint64 GeneralBitmask,
uint64 CursorBitmask, uint64 CursorBitmask,
+137
View File
@@ -236,6 +236,26 @@ uint32 EQApplicationPacket::serialize(uint16 opcode, unsigned char *dest) const
return size+OpCodeBytes; return size+OpCodeBytes;
} }
/*EQProtocolPacket::EQProtocolPacket(uint16 op, const unsigned char *buf, uint32 len)
: BasePacket(buf, len),
opcode(op)
{
uint32 offset;
opcode=ntohs(*(const uint16 *)buf);
offset=2;
if (len-offset) {
pBuffer= new unsigned char[len-offset];
memcpy(pBuffer,buf+offset,len-offset);
size=len-offset;
} else {
pBuffer=nullptr;
size=0;
}
OpMgr=&RawOpcodeManager;
}*/
bool EQProtocolPacket::combine(const EQProtocolPacket *rhs) bool EQProtocolPacket::combine(const EQProtocolPacket *rhs)
{ {
bool result=false; bool result=false;
@@ -267,6 +287,74 @@ bool result=false;
} }
/*
this is the code to do app-layer combining, instead of protocol layer.
this was taken out due to complex interactions with the opcode manager,
and will require a bit more thinking (likely moving into EQStream) to
get running again... but might be a good thing some day.
bool EQApplicationPacket::combine(const EQApplicationPacket *rhs)
{
uint32 newsize=0, offset=0;
unsigned char *tmpbuffer=nullptr;
if (opcode!=OP_AppCombined) {
newsize=app_opcode_size+size+(size>254?3:1)+app_opcode_size+rhs->size+(rhs->size>254?3:1);
tmpbuffer=new unsigned char [newsize];
offset=0;
if (size>254) {
tmpbuffer[offset++]=0xff;
*(uint16 *)(tmpbuffer+offset)=htons(size);
offset+=1;
} else {
tmpbuffer[offset++]=size;
}
offset+=serialize(tmpbuffer+offset);
} else {
newsize=size+app_opcode_size+rhs->size+(rhs->size>254?3:1);
tmpbuffer=new unsigned char [newsize];
memcpy(tmpbuffer,pBuffer,size);
offset=size;
}
if (rhs->size>254) {
tmpbuffer[offset++]=0xff;
*(uint16 *)(tmpbuffer+offset)=htons(rhs->size);
offset+=1;
} else {
tmpbuffer[offset++]=rhs->size;
}
offset+=rhs->serialize(tmpbuffer+offset);
size=offset;
opcode=OP_AppCombined;
delete[] pBuffer;
pBuffer=tmpbuffer;
return true;
}
*/
bool EQProtocolPacket::ValidateCRC(const unsigned char *buffer, int length, uint32 Key)
{
bool valid=false;
// OP_SessionRequest, OP_SessionResponse, OP_OutOfSession are not CRC'd
if (buffer[0]==0x00 && (buffer[1]==OP_SessionRequest || buffer[1]==OP_SessionResponse || buffer[1]==OP_OutOfSession)) {
valid=true;
} else {
uint16 comp_crc=CRC16(buffer,length-2,Key);
uint16 packet_crc=ntohs(*(const uint16 *)(buffer+length-2));
#ifdef EQN_DEBUG
if (packet_crc && comp_crc != packet_crc) {
std::cout << "CRC mismatch: comp=" << std::hex << comp_crc << ", packet=" << packet_crc << std::dec << std::endl;
}
#endif
valid = (!packet_crc || comp_crc == packet_crc);
}
return valid;
}
uint32 EQProtocolPacket::Decompress(const unsigned char *buffer, const uint32 length, unsigned char *newbuf, uint32 newbufsize) uint32 EQProtocolPacket::Decompress(const unsigned char *buffer, const uint32 length, unsigned char *newbuf, uint32 newbufsize)
{ {
uint32 newlen=0; uint32 newlen=0;
@@ -315,6 +403,55 @@ uint32 flag_offset=1,newlength;
return newlength; return newlength;
} }
void EQProtocolPacket::ChatDecode(unsigned char *buffer, int size, int DecodeKey)
{
if ((size >= 2) && buffer[1]!=0x01 && buffer[0]!=0x02 && buffer[0]!=0x1d) {
int Key=DecodeKey;
unsigned char *test=(unsigned char *)malloc(size);
buffer+=2;
size-=2;
int i;
for (i = 0 ; i+4 <= size ; i+=4)
{
int pt = (*(int*)&buffer[i])^(Key);
Key = (*(int*)&buffer[i]);
*(int*)&test[i]=pt;
}
unsigned char KC=Key&0xFF;
for ( ; i < size ; i++)
{
test[i]=buffer[i]^KC;
}
memcpy(buffer,test,size);
free(test);
}
}
void EQProtocolPacket::ChatEncode(unsigned char *buffer, int size, int EncodeKey)
{
if (buffer[1]!=0x01 && buffer[0]!=0x02 && buffer[0]!=0x1d) {
int Key=EncodeKey;
char *test=(char*)malloc(size);
int i;
buffer+=2;
size-=2;
for ( i = 0 ; i+4 <= size ; i+=4)
{
int pt = (*(int*)&buffer[i])^(Key);
Key = pt;
*(int*)&test[i]=pt;
}
unsigned char KC=Key&0xFF;
for ( ; i < size ; i++)
{
test[i]=buffer[i]^KC;
}
memcpy(buffer,test,size);
free(test);
}
}
EQApplicationPacket *EQApplicationPacket::Copy() const { EQApplicationPacket *EQApplicationPacket::Copy() const {
return(new EQApplicationPacket(*this)); return(new EQApplicationPacket(*this));
} }
+3
View File
@@ -80,8 +80,11 @@ public:
protected: protected:
static bool ValidateCRC(const unsigned char *buffer, int length, uint32 Key);
static uint32 Decompress(const unsigned char *buffer, const uint32 length, unsigned char *newbuf, uint32 newbufsize); static uint32 Decompress(const unsigned char *buffer, const uint32 length, unsigned char *newbuf, uint32 newbufsize);
static uint32 Compress(const unsigned char *buffer, const uint32 length, unsigned char *newbuf, uint32 newbufsize); static uint32 Compress(const unsigned char *buffer, const uint32 length, unsigned char *newbuf, uint32 newbufsize);
static void ChatDecode(unsigned char *buffer, int size, int DecodeKey);
static void ChatEncode(unsigned char *buffer, int size, int EncodeKey);
uint16 GetRawOpcode() const { return(opcode); } uint16 GetRawOpcode() const { return(opcode); }
+28 -42
View File
@@ -29,7 +29,7 @@
#include "textures.h" #include "textures.h"
static const uint32 BUFF_COUNT = 42; static const uint32 BUFF_COUNT = 25;
static const uint32 PET_BUFF_COUNT = 30; static const uint32 PET_BUFF_COUNT = 30;
static const uint32 MAX_MERC = 100; static const uint32 MAX_MERC = 100;
static const uint32 MAX_MERC_GRADES = 10; static const uint32 MAX_MERC_GRADES = 10;
@@ -374,18 +374,18 @@ struct NewZone_Struct {
/*0684*/ uint16 zone_id; /*0684*/ uint16 zone_id;
/*0686*/ uint16 zone_instance; /*0686*/ uint16 zone_instance;
/*0688*/ uint32 unknown688; /*0688*/ uint32 unknown688;
/*0692*/ uint8 unknown692[8]; /*0692*/ uint8 unknown692[8];
// Titanium doesn't have a translator, but we can still safely add stuff under here without issues since client memcpy's only what it knows // Titanium doesn't have a translator, but we can still safely add stuff under here without issues since client memcpy's only what it knows
// Just wastes some bandwidth sending to tit clients /shrug // Just wastes some bandwidth sending to tit clients /shrug
/*0700*/ float fog_density; /*0700*/ float fog_density;
/*0704*/ uint32 suspend_buffs; /*0704*/ uint32 SuspendBuffs;
/*0708*/ uint32 fast_regen_hp; /*0708*/ uint32 FastRegenHP;
/*0712*/ uint32 fast_regen_mana; /*0712*/ uint32 FastRegenMana;
/*0716*/ uint32 fast_regen_endurance; /*0716*/ uint32 FastRegenEndurance;
/*0720*/ uint32 npc_aggro_max_dist; /*0720*/ uint32 NPCAggroMaxDist;
/*0724*/ uint32 underworld_teleport_index; // > 0 teleports w/ zone point index, invalid succors, if this value is 0, it prevents you from running off edges that would end up underworld /*0724*/ uint32 underworld_teleport_index; // > 0 teleports w/ zone point index, invalid succors, if this value is 0, it prevents you from running off edges that would end up underworld
/*0728*/ uint32 lava_damage; // Seen 50 /*0728*/ uint32 LavaDamage; // Seen 50
/*0732*/ uint32 min_lava_damage; // Seen 10 /*0732*/ uint32 MinLavaDamage; // Seen 10
/*0736*/ /*0736*/
}; };
@@ -2192,19 +2192,11 @@ struct QuestReward_Struct
/*068*/ /*068*/
}; };
struct CashReward_Struct
{
/*000*/ uint32 copper;
/*004*/ uint32 silver;
/*008*/ uint32 gold;
/*012*/ uint32 platinum;
};
// Size: 8 // Size: 8
struct Camera_Struct struct Camera_Struct
{ {
uint32 duration; // Duration in ms uint32 duration; // Duration in ms
float intensity; uint32 intensity; // Between 1023410176 and 1090519040
}; };
struct ZonePoint_Entry { struct ZonePoint_Entry {
@@ -3632,19 +3624,17 @@ struct LevelAppearance_Struct { //Sends a little graphic on level up
}; };
struct MerchantList { struct MerchantList {
uint32 id; uint32 id;
uint32 slot; uint32 slot;
uint32 item; uint32 item;
int16 faction_required; int16 faction_required;
int8 level_required; int8 level_required;
uint8 min_status; uint16 alt_currency_cost;
uint8 max_status; uint32 classes_required;
uint16 alt_currency_cost; uint8 probability;
uint32 classes_required;
uint8 probability;
std::string bucket_name; std::string bucket_name;
std::string bucket_value; std::string bucket_value;
uint8 bucket_comparison; uint8 bucket_comparison;
}; };
struct TempMerchantList { struct TempMerchantList {
@@ -4547,7 +4537,7 @@ struct ItemVerifyReply_Struct {
struct ItemRecastDelay_Struct { struct ItemRecastDelay_Struct {
/*000*/ uint32 recast_delay; // in seconds /*000*/ uint32 recast_delay; // in seconds
/*004*/ uint32 recast_type; /*004*/ uint32 recast_type;
/*008*/ bool ignore_casting_requirement; //Ignores recast times allows items to be reset? /*008*/ uint32 unknown008;
/*012*/ /*012*/
}; };
@@ -5008,7 +4998,7 @@ struct DynamicZoneCompassEntry_Struct
/*000*/ uint16 dz_zone_id; // target dz id pair /*000*/ uint16 dz_zone_id; // target dz id pair
/*002*/ uint16 dz_instance_id; /*002*/ uint16 dz_instance_id;
/*004*/ uint32 dz_type; // 1: Expedition, 2: Tutorial (purple), 3: Task, 4: Mission, 5: Quest (green) /*004*/ uint32 dz_type; // 1: Expedition, 2: Tutorial (purple), 3: Task, 4: Mission, 5: Quest (green)
/*008*/ uint32 dz_switch_id; /*008*/ uint32 unknown008;
/*012*/ float y; /*012*/ float y;
/*016*/ float x; /*016*/ float x;
/*020*/ float z; /*020*/ float z;
@@ -5165,10 +5155,10 @@ struct AltCurrencySelectItemReply_Struct {
/*000*/ uint32 unknown000; /*000*/ uint32 unknown000;
/*004*/ uint8 unknown004; //0xff /*004*/ uint8 unknown004; //0xff
/*005*/ uint8 unknown005; //0xff /*005*/ uint8 unknown005; //0xff
/*006*/ uint16 unknown006; //0xffff /*006*/ uint8 unknown006; //0xff
/*008*/ uint16 unknown008; //0xffff /*007*/ uint8 unknown007; //0xff
/*010*/ char item_name[64]; /*008*/ char item_name[64];
/*074*/ uint16 unknown074; /*072*/ uint32 unknown074;
/*076*/ uint32 cost; /*076*/ uint32 cost;
/*080*/ uint32 unknown080; /*080*/ uint32 unknown080;
/*084*/ uint32 unknown084; /*084*/ uint32 unknown084;
@@ -5522,11 +5512,7 @@ struct ServerLootItem_Struct {
uint32 aug_4; // uint32 aug_4; uint32 aug_4; // uint32 aug_4;
uint32 aug_5; // uint32 aug_5; uint32 aug_5; // uint32 aug_5;
uint32 aug_6; // uint32 aug_5; uint32 aug_6; // uint32 aug_5;
bool attuned; uint8 attuned;
std::string custom_data;
uint32 ornamenticon {};
uint32 ornamentidfile {};
uint32 ornament_hero_model {};
uint16 trivial_min_level; uint16 trivial_min_level;
uint16 trivial_max_level; uint16 trivial_max_level;
uint16 npc_min_level; uint16 npc_min_level;
+1 -1
View File
@@ -23,7 +23,7 @@
#include "op_codes.h" #include "op_codes.h"
#include "crc16.h" #include "crc16.h"
#include "platform.h" #include "platform.h"
#include "strings.h" #include "string_util.h"
#include <string> #include <string>
#include <iomanip> #include <iomanip>
-5
View File
@@ -243,11 +243,6 @@ class EQStream : public EQStreamInterface {
virtual void SetOpcodeManager(OpcodeManager **opm) { OpMgr = opm; } virtual void SetOpcodeManager(OpcodeManager **opm) { OpMgr = opm; }
virtual OpcodeManager* GetOpcodeManager() const
{
return (*OpMgr);
};
void CheckTimeout(uint32 now, uint32 timeout=30); void CheckTimeout(uint32 now, uint32 timeout=30);
bool HasOutgoingData(); bool HasOutgoingData();
void Process(const unsigned char *data, const uint32 length); void Process(const unsigned char *data, const uint32 length);
+2 -2
View File
@@ -26,7 +26,7 @@ EQStreamIdentifier::~EQStreamIdentifier() {
} }
} }
void EQStreamIdentifier::RegisterPatch(EQStreamInterface::Signature sig, const char *name, OpcodeManager ** opcodes, const StructStrategy *structs) { void EQStreamIdentifier::RegisterPatch(const EQStreamInterface::Signature &sig, const char *name, OpcodeManager ** opcodes, const StructStrategy *structs) {
auto p = new Patch; auto p = new Patch;
p->signature = sig; p->signature = sig;
p->name = name; p->name = name;
@@ -145,7 +145,7 @@ void EQStreamIdentifier::Process() {
} }
void EQStreamIdentifier::AddStream(std::shared_ptr<EQStreamInterface> eqs) { void EQStreamIdentifier::AddStream(std::shared_ptr<EQStreamInterface> eqs) {
m_streams.emplace_back(Record(eqs)); m_streams.push_back(Record(eqs));
eqs = nullptr; eqs = nullptr;
} }
+1 -1
View File
@@ -18,7 +18,7 @@ public:
~EQStreamIdentifier(); ~EQStreamIdentifier();
//registration interface. //registration interface.
void RegisterPatch(EQStreamInterface::Signature sig, const char *name, OpcodeManager ** opcodes, const StructStrategy *structs); void RegisterPatch(const EQStreamInterface::Signature &sig, const char *name, OpcodeManager ** opcodes, const StructStrategy *structs);
//main processing interface //main processing interface
void Process(); void Process();
-1
View File
@@ -100,7 +100,6 @@ public:
virtual MatchState CheckSignature(const Signature *sig) { return MatchFailed; } virtual MatchState CheckSignature(const Signature *sig) { return MatchFailed; }
virtual EQStreamState GetState() = 0; virtual EQStreamState GetState() = 0;
virtual void SetOpcodeManager(OpcodeManager **opm) = 0; virtual void SetOpcodeManager(OpcodeManager **opm) = 0;
virtual OpcodeManager* GetOpcodeManager() const = 0;
virtual const EQ::versions::ClientVersion ClientVersion() const { return EQ::versions::ClientVersion::Unknown; } virtual const EQ::versions::ClientVersion ClientVersion() const { return EQ::versions::ClientVersion::Unknown; }
virtual Stats GetStats() const = 0; virtual Stats GetStats() const = 0;
virtual void ResetStats() = 0; virtual void ResetStats() = 0;
+5 -6
View File
@@ -38,8 +38,12 @@ void EQStreamProxy::SetOpcodeManager(OpcodeManager **opm)
} }
void EQStreamProxy::QueuePacket(const EQApplicationPacket *p, bool ack_req) { void EQStreamProxy::QueuePacket(const EQApplicationPacket *p, bool ack_req) {
if (p == nullptr) { if(p == nullptr)
return; return;
if (p->GetOpcode() != OP_SpecialMesg) {
Log(Logs::General, Logs::PacketServerClient, "[%s - 0x%04x] [Size: %u]", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size());
Log(Logs::General, Logs::PacketServerClientWithDump, "[%s - 0x%04x] [Size: %u] %s", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size(), DumpPacketToString(p).c_str());
} }
EQApplicationPacket *newp = p->Copy(); EQApplicationPacket *newp = p->Copy();
@@ -108,8 +112,3 @@ bool EQStreamProxy::CheckState(EQStreamState state) {
return false; return false;
} }
OpcodeManager *EQStreamProxy::GetOpcodeManager() const
{
return (*m_opcodes);
}
+1 -3
View File
@@ -34,15 +34,13 @@ public:
virtual Stats GetStats() const; virtual Stats GetStats() const;
virtual void ResetStats(); virtual void ResetStats();
virtual EQStreamManagerInterface* GetManager() const; virtual EQStreamManagerInterface* GetManager() const;
virtual OpcodeManager* GetOpcodeManager() const;
protected: protected:
std::shared_ptr<EQStreamInterface> const m_stream; //we own this stream object. std::shared_ptr<EQStreamInterface> const m_stream; //we own this stream object.
const StructStrategy *const m_structs; //we do not own this object. const StructStrategy *const m_structs; //we do not own this object.
//this is a pointer to a pointer to make it less likely that a packet will //this is a pointer to a pointer to make it less likely that a packet will
//reference an invalid opcode manager when they are being reloaded. //reference an invalid opcode manager when they are being reloaded.
OpcodeManager **const m_opcodes; OpcodeManager **const m_opcodes; //we do not own this object.
//we do not own this object.
}; };
#endif /*EQSTREAMPROXY_H_*/ #endif /*EQSTREAMPROXY_H_*/
+3
View File
@@ -23,6 +23,9 @@
EQDB EQDB::s_EQDB; EQDB EQDB::s_EQDB;
EQDB::EQDB() {
}
unsigned int EQDB::field_count() { unsigned int EQDB::field_count() {
return mysql_field_count(mysql_ref); return mysql_field_count(mysql_ref);
} }
+1 -1
View File
@@ -27,7 +27,7 @@
//this is the main object exported to perl. //this is the main object exported to perl.
class EQDB { class EQDB {
EQDB() = default; EQDB();
public: public:
static EQDB *Singleton() { return(&s_EQDB); } static EQDB *Singleton() { return(&s_EQDB); }
+18 -23
View File
@@ -19,7 +19,6 @@
#include "../common/global_define.h" #include "../common/global_define.h"
#include "eqemu_config.h" #include "eqemu_config.h"
#include "misc_functions.h" #include "misc_functions.h"
#include "strings.h"
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
@@ -34,13 +33,13 @@ void EQEmuConfig::parse_config()
LongName = _root["server"]["world"].get("longname", "").asString(); LongName = _root["server"]["world"].get("longname", "").asString();
WorldAddress = _root["server"]["world"].get("address", "").asString(); WorldAddress = _root["server"]["world"].get("address", "").asString();
LocalAddress = _root["server"]["world"].get("localaddress", "").asString(); LocalAddress = _root["server"]["world"].get("localaddress", "").asString();
MaxClients = Strings::ToInt(_root["server"]["world"].get("maxclients", "-1").asString()); MaxClients = atoi(_root["server"]["world"].get("maxclients", "-1").asString().c_str());
SharedKey = _root["server"]["world"].get("key", "").asString(); SharedKey = _root["server"]["world"].get("key", "").asString();
LoginCount = 0; LoginCount = 0;
if (_root["server"]["world"]["loginserver"].isObject()) { if (_root["server"]["world"]["loginserver"].isObject()) {
LoginHost = _root["server"]["world"]["loginserver"].get("host", "login.eqemulator.net").asString(); LoginHost = _root["server"]["world"]["loginserver"].get("host", "login.eqemulator.net").asString();
LoginPort = Strings::ToUnsignedInt(_root["server"]["world"]["loginserver"].get("port", "5998").asString()); LoginPort = atoi(_root["server"]["world"]["loginserver"].get("port", "5998").asString().c_str());
LoginLegacy = false; LoginLegacy = false;
if (_root["server"]["world"]["loginserver"].get("legacy", "0").asString() == "1") { LoginLegacy = true; } if (_root["server"]["world"]["loginserver"].get("legacy", "0").asString() == "1") { LoginLegacy = true; }
LoginAccount = _root["server"]["world"]["loginserver"].get("account", "").asString(); LoginAccount = _root["server"]["world"]["loginserver"].get("account", "").asString();
@@ -63,7 +62,7 @@ void EQEmuConfig::parse_config()
auto loginconfig = new LoginConfig; auto loginconfig = new LoginConfig;
loginconfig->LoginHost = _root["server"]["world"][str].get("host", "login.eqemulator.net").asString(); loginconfig->LoginHost = _root["server"]["world"][str].get("host", "login.eqemulator.net").asString();
loginconfig->LoginPort = Strings::ToUnsignedInt(_root["server"]["world"][str].get("port", "5998").asString()); loginconfig->LoginPort = atoi(_root["server"]["world"][str].get("port", "5998").asString().c_str());
loginconfig->LoginAccount = _root["server"]["world"][str].get("account", "").asString(); loginconfig->LoginAccount = _root["server"]["world"][str].get("account", "").asString();
loginconfig->LoginPassword = _root["server"]["world"][str].get("password", "").asString(); loginconfig->LoginPassword = _root["server"]["world"][str].get("password", "").asString();
@@ -86,32 +85,28 @@ void EQEmuConfig::parse_config()
Locked = false; Locked = false;
if (_root["server"]["world"].get("locked", "false").asString() == "true") { Locked = true; } if (_root["server"]["world"].get("locked", "false").asString() == "true") { Locked = true; }
WorldIP = _root["server"]["world"]["tcp"].get("host", "127.0.0.1").asString(); WorldIP = _root["server"]["world"]["tcp"].get("host", "127.0.0.1").asString();
WorldTCPPort = Strings::ToUnsignedInt(_root["server"]["world"]["tcp"].get("port", "9000").asString()); WorldTCPPort = atoi(_root["server"]["world"]["tcp"].get("port", "9000").asString().c_str());
TelnetIP = _root["server"]["world"]["telnet"].get("ip", "127.0.0.1").asString(); TelnetIP = _root["server"]["world"]["telnet"].get("ip", "127.0.0.1").asString();
TelnetTCPPort = Strings::ToUnsignedInt(_root["server"]["world"]["telnet"].get("port", "9001").asString()); TelnetTCPPort = atoi(_root["server"]["world"]["telnet"].get("port", "9001").asString().c_str());
TelnetEnabled = false; TelnetEnabled = false;
if (_root["server"]["world"]["telnet"].get("enabled", "false").asString() == "true") { TelnetEnabled = true; } if (_root["server"]["world"]["telnet"].get("enabled", "false").asString() == "true") { TelnetEnabled = true; }
WorldHTTPMimeFile = _root["server"]["world"]["http"].get("mimefile", "mime.types").asString(); WorldHTTPMimeFile = _root["server"]["world"]["http"].get("mimefile", "mime.types").asString();
WorldHTTPPort = Strings::ToUnsignedInt(_root["server"]["world"]["http"].get("port", "9080").asString()); WorldHTTPPort = atoi(_root["server"]["world"]["http"].get("port", "9080").asString().c_str());
WorldHTTPEnabled = false; WorldHTTPEnabled = false;
if (_root["server"]["world"]["http"].get("enabled", "false").asString() == "true") { if (_root["server"]["world"]["http"].get("enabled", "false").asString() == "true") {
WorldHTTPEnabled = true; WorldHTTPEnabled = true;
} }
if (_root["server"].get("disable_config_checks", "false").asString() == "true") {
DisableConfigChecks = true;
}
/** /**
* UCS * UCS
*/ */
ChatHost = _root["server"]["chatserver"].get("host", "eqchat.eqemulator.net").asString(); ChatHost = _root["server"]["chatserver"].get("host", "eqchat.eqemulator.net").asString();
ChatPort = Strings::ToUnsignedInt(_root["server"]["chatserver"].get("port", "7778").asString()); ChatPort = atoi(_root["server"]["chatserver"].get("port", "7778").asString().c_str());
MailHost = _root["server"]["mailserver"].get("host", "eqmail.eqemulator.net").asString(); MailHost = _root["server"]["mailserver"].get("host", "eqmail.eqemulator.net").asString();
MailPort = Strings::ToUnsignedInt(_root["server"]["mailserver"].get("port", "7778").asString()); MailPort = atoi(_root["server"]["mailserver"].get("port", "7778").asString().c_str());
/** /**
* Database * Database
@@ -119,7 +114,7 @@ void EQEmuConfig::parse_config()
DatabaseUsername = _root["server"]["database"].get("username", "eq").asString(); DatabaseUsername = _root["server"]["database"].get("username", "eq").asString();
DatabasePassword = _root["server"]["database"].get("password", "eq").asString(); DatabasePassword = _root["server"]["database"].get("password", "eq").asString();
DatabaseHost = _root["server"]["database"].get("host", "localhost").asString(); DatabaseHost = _root["server"]["database"].get("host", "localhost").asString();
DatabasePort = Strings::ToUnsignedInt(_root["server"]["database"].get("port", "3306").asString()); DatabasePort = atoi(_root["server"]["database"].get("port", "3306").asString().c_str());
DatabaseDB = _root["server"]["database"].get("db", "eq").asString(); DatabaseDB = _root["server"]["database"].get("db", "eq").asString();
/** /**
@@ -128,14 +123,14 @@ void EQEmuConfig::parse_config()
ContentDbUsername = _root["server"]["content_database"].get("username", "").asString(); ContentDbUsername = _root["server"]["content_database"].get("username", "").asString();
ContentDbPassword = _root["server"]["content_database"].get("password", "").asString(); ContentDbPassword = _root["server"]["content_database"].get("password", "").asString();
ContentDbHost = _root["server"]["content_database"].get("host", "").asString(); ContentDbHost = _root["server"]["content_database"].get("host", "").asString();
ContentDbPort = Strings::ToUnsignedInt(_root["server"]["content_database"].get("port", 0).asString()); ContentDbPort = atoi(_root["server"]["content_database"].get("port", 0).asString().c_str());
ContentDbName = _root["server"]["content_database"].get("db", "").asString(); ContentDbName = _root["server"]["content_database"].get("db", "").asString();
/** /**
* QS * QS
*/ */
QSDatabaseHost = _root["server"]["qsdatabase"].get("host", "localhost").asString(); QSDatabaseHost = _root["server"]["qsdatabase"].get("host", "localhost").asString();
QSDatabasePort = Strings::ToUnsignedInt(_root["server"]["qsdatabase"].get("port", "3306").asString()); QSDatabasePort = atoi(_root["server"]["qsdatabase"].get("port", "3306").asString().c_str());
QSDatabaseUsername = _root["server"]["qsdatabase"].get("username", "eq").asString(); QSDatabaseUsername = _root["server"]["qsdatabase"].get("username", "eq").asString();
QSDatabasePassword = _root["server"]["qsdatabase"].get("password", "eq").asString(); QSDatabasePassword = _root["server"]["qsdatabase"].get("password", "eq").asString();
QSDatabaseDB = _root["server"]["qsdatabase"].get("db", "eq").asString(); QSDatabaseDB = _root["server"]["qsdatabase"].get("db", "eq").asString();
@@ -143,9 +138,9 @@ void EQEmuConfig::parse_config()
/** /**
* Zones * Zones
*/ */
DefaultStatus = Strings::ToUnsignedInt(_root["server"]["zones"].get("defaultstatus", 0).asString()); DefaultStatus = atoi(_root["server"]["zones"].get("defaultstatus", 0).asString().c_str());
ZonePortLow = Strings::ToUnsignedInt(_root["server"]["zones"]["ports"].get("low", "7000").asString()); ZonePortLow = atoi(_root["server"]["zones"]["ports"].get("low", "7000").asString().c_str());
ZonePortHigh = Strings::ToUnsignedInt(_root["server"]["zones"]["ports"].get("high", "7999").asString()); ZonePortHigh = atoi(_root["server"]["zones"]["ports"].get("high", "7999").asString().c_str());
/** /**
* Files * Files
@@ -175,10 +170,10 @@ void EQEmuConfig::parse_config()
/** /**
* Launcher * Launcher
*/ */
RestartWait = Strings::ToInt(_root["server"]["launcher"]["timers"].get("restart", "10000").asString()); RestartWait = atoi(_root["server"]["launcher"]["timers"].get("restart", "10000").asString().c_str());
TerminateWait = Strings::ToInt(_root["server"]["launcher"]["timers"].get("reterminate", "10000").asString()); TerminateWait = atoi(_root["server"]["launcher"]["timers"].get("reterminate", "10000").asString().c_str());
InitialBootWait = Strings::ToInt(_root["server"]["launcher"]["timers"].get("initial", "20000").asString()); InitialBootWait = atoi(_root["server"]["launcher"]["timers"].get("initial", "20000").asString().c_str());
ZoneBootInterval = Strings::ToInt(_root["server"]["launcher"]["timers"].get("interval", "2000").asString()); ZoneBootInterval = atoi(_root["server"]["launcher"]["timers"].get("interval", "2000").asString().c_str());
#ifdef WIN32 #ifdef WIN32
ZoneExe = _root["server"]["launcher"].get("exe", "zone.exe").asString(); ZoneExe = _root["server"]["launcher"].get("exe", "zone.exe").asString();
#else #else
+11 -16
View File
@@ -20,9 +20,7 @@
#include "json/json.h" #include "json/json.h"
#include "linked_list.h" #include "linked_list.h"
#include "path_manager.h"
#include <fstream> #include <fstream>
#include <fmt/format.h>
struct LoginConfig { struct LoginConfig {
std::string LoginHost; std::string LoginHost;
@@ -60,7 +58,6 @@ class EQEmuConfig
uint16 WorldHTTPPort; uint16 WorldHTTPPort;
std::string WorldHTTPMimeFile; std::string WorldHTTPMimeFile;
std::string SharedKey; std::string SharedKey;
bool DisableConfigChecks;
// From <chatserver/> // From <chatserver/>
std::string ChatHost; std::string ChatHost;
@@ -147,32 +144,30 @@ class EQEmuConfig
return (_config); return (_config);
} }
// Allow the use to set the conf file to be used.
static void SetConfigFile(std::string file)
{
EQEmuConfig::ConfigFile = file;
}
// Load the config // Load the config
static bool LoadConfig(const std::string& path = "") static bool LoadConfig()
{ {
if (_config != nullptr) { if (_config != nullptr) {
return true; return true;
} }
_config = new EQEmuConfig; _config = new EQEmuConfig;
return parseFile(path); return parseFile();
} }
// Load config file and parse data // Load config file and parse data
static bool parseFile(const std::string& file_path = ".") static bool parseFile() {
{
if (_config == nullptr) { if (_config == nullptr) {
return LoadConfig(file_path); return LoadConfig();
} }
std::string file = fmt::format( std::ifstream fconfig(EQEmuConfig::ConfigFile, std::ifstream::binary);
"{}/{}",
(file_path.empty() ? path.GetServerPath() : file_path),
EQEmuConfig::ConfigFile
);
std::ifstream fconfig(file, std::ifstream::binary);
try { try {
fconfig >> _config->_root; fconfig >> _config->_root;
_config->parse_config(); _config->parse_config();
+270 -333
View File
@@ -21,20 +21,22 @@
#include "eqemu_logsys.h" #include "eqemu_logsys.h"
#include "rulesys.h" #include "rulesys.h"
#include "platform.h" #include "platform.h"
#include "strings.h" #include "string_util.h"
#include "misc.h"
#include "discord/discord.h"
#include "repositories/discord_webhooks_repository.h" #include "repositories/discord_webhooks_repository.h"
#include "repositories/logsys_categories_repository.h" #include "repositories/logsys_categories_repository.h"
#include "termcolor/rang.hpp"
#include <iostream> #include <iostream>
#include <fstream>
#include <string> #include <string>
#include <iomanip>
#include <time.h> #include <time.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <algorithm>
std::ofstream process_log; std::ofstream process_log;
#include <filesystem>
#ifdef _WINDOWS #ifdef _WINDOWS
#include <direct.h> #include <direct.h>
#include <conio.h> #include <conio.h>
@@ -50,13 +52,47 @@ std::ofstream process_log;
#endif #endif
/**
* Linux ANSI console color defines
*/
#define LC_RESET "\033[0m"
#define LC_BLACK "\033[30m" /* Black */
#define LC_RED "\033[31m" /* Red */
#define LC_GREEN "\033[32m" /* Green */
#define LC_YELLOW "\033[33m" /* Yellow */
#define LC_BLUE "\033[34m" /* Blue */
#define LC_MAGENTA "\033[35m" /* Magenta */
#define LC_CYAN "\033[36m" /* Cyan */
#define LC_WHITE "\033[37m" /* White */
namespace Console {
enum Color {
Black = 0,
Blue = 1,
Green = 2,
Cyan = 3,
Red = 4,
Magenta = 5,
Brown = 6,
LightGray = 7,
DarkGray = 8,
LightBlue = 9,
LightGreen = 10,
LightCyan = 11,
LightRed = 12,
LightMagenta = 13,
Yellow = 14,
White = 15
};
}
/** /**
* EQEmuLogSys Constructor * EQEmuLogSys Constructor
*/ */
EQEmuLogSys::EQEmuLogSys() EQEmuLogSys::EQEmuLogSys()
{ {
m_on_log_gmsay_hook = [](uint16 log_type, const char *func, const std::string &) {}; on_log_gmsay_hook = [](uint16 log_type, const std::string &) {};
m_on_log_console_hook = [](uint16 log_type, const std::string &) {}; on_log_console_hook = [](uint16 log_type, const std::string &) {};
} }
/** /**
@@ -69,7 +105,7 @@ EQEmuLogSys *EQEmuLogSys::LoadLogSettingsDefaults()
/** /**
* Get Executable platform currently running this code (Zone/World/etc) * Get Executable platform currently running this code (Zone/World/etc)
*/ */
m_log_platform = GetExecutablePlatformInt(); log_platform = GetExecutablePlatformInt();
for (int log_category_id = Logs::AA; log_category_id != Logs::MaxCategoryID; log_category_id++) { for (int log_category_id = Logs::AA; log_category_id != Logs::MaxCategoryID; log_category_id++) {
log_settings[log_category_id].log_to_console = 0; log_settings[log_category_id].log_to_console = 0;
@@ -79,13 +115,19 @@ EQEmuLogSys *EQEmuLogSys::LoadLogSettingsDefaults()
log_settings[log_category_id].is_category_enabled = 0; log_settings[log_category_id].is_category_enabled = 0;
} }
m_file_logs_enabled = false; file_logs_enabled = false;
/** /**
* Set Defaults * Set Defaults
*/ */
log_settings[Logs::WorldServer].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::ZoneServer].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::QSServer].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::UCSServer].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::Crash].log_to_console = static_cast<uint8>(Logs::General); log_settings[Logs::Crash].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::MySQLError].log_to_console = static_cast<uint8>(Logs::General); log_settings[Logs::MySQLError].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::Loginserver].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::HeadlessClient].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::NPCScaling].log_to_gmsay = static_cast<uint8>(Logs::General); log_settings[Logs::NPCScaling].log_to_gmsay = static_cast<uint8>(Logs::General);
log_settings[Logs::HotReload].log_to_gmsay = static_cast<uint8>(Logs::General); log_settings[Logs::HotReload].log_to_gmsay = static_cast<uint8>(Logs::General);
log_settings[Logs::HotReload].log_to_console = static_cast<uint8>(Logs::General); log_settings[Logs::HotReload].log_to_console = static_cast<uint8>(Logs::General);
@@ -98,14 +140,16 @@ EQEmuLogSys *EQEmuLogSys::LoadLogSettingsDefaults()
log_settings[Logs::ChecksumVerification].log_to_gmsay = static_cast<uint8>(Logs::General); log_settings[Logs::ChecksumVerification].log_to_gmsay = static_cast<uint8>(Logs::General);
log_settings[Logs::CombatRecord].log_to_gmsay = static_cast<uint8>(Logs::General); log_settings[Logs::CombatRecord].log_to_gmsay = static_cast<uint8>(Logs::General);
log_settings[Logs::Discord].log_to_console = static_cast<uint8>(Logs::General); log_settings[Logs::Discord].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::QuestErrors].log_to_gmsay = static_cast<uint8>(Logs::General);
log_settings[Logs::QuestErrors].log_to_console = static_cast<uint8>(Logs::General);
/** /**
* RFC 5424 * RFC 5424
*/ */
log_settings[Logs::Emergency].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::Alert].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::Critical].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::Error].log_to_console = static_cast<uint8>(Logs::General); log_settings[Logs::Error].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::Warning].log_to_console = static_cast<uint8>(Logs::General); log_settings[Logs::Warning].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::Notice].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::Info].log_to_console = static_cast<uint8>(Logs::General); log_settings[Logs::Info].log_to_console = static_cast<uint8>(Logs::General);
/** /**
@@ -125,31 +169,64 @@ EQEmuLogSys *EQEmuLogSys::LoadLogSettingsDefaults()
/** /**
* Declare process file names for log writing= * Declare process file names for log writing=
*/ */
if (EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformWorld) { if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformWorld) {
m_platform_file_name = "world"; platform_file_name = "world";
} }
else if (EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformQueryServ) { else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformQueryServ) {
m_platform_file_name = "query_server"; platform_file_name = "query_server";
} }
else if (EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformZone) { else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformZone) {
m_platform_file_name = "zone"; platform_file_name = "zone";
} }
else if (EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformUCS) { else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformUCS) {
m_platform_file_name = "ucs"; platform_file_name = "ucs";
} }
else if (EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformLogin) { else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformLogin) {
m_platform_file_name = "login"; platform_file_name = "login";
} }
else if (EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformLaunch) { else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformLaunch) {
m_platform_file_name = "launcher"; platform_file_name = "launcher";
} }
else if (EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformHC) { else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformHC) {
m_platform_file_name = "hc"; platform_file_name = "hc";
} }
return this; return this;
} }
/**
* @param log_category
* @return
*/
bool EQEmuLogSys::IsRfc5424LogCategory(uint16 log_category)
{
return (
log_category == Logs::Emergency ||
log_category == Logs::Alert ||
log_category == Logs::Critical ||
log_category == Logs::Error ||
log_category == Logs::Warning ||
log_category == Logs::Notice ||
log_category == Logs::Info ||
log_category == Logs::Debug
);
}
/**
* @param log_category
* @param in_message
* @return
*/
std::string EQEmuLogSys::FormatOutMessageString(
uint16 log_category,
const std::string &in_message
)
{
std::string return_string = "[" + GetPlatformName() + "] ";
return return_string + "[" + Logs::LogCategoryName[log_category] + "] " + in_message;
}
/** /**
* @param debug_level * @param debug_level
* @param log_category * @param log_category
@@ -166,7 +243,7 @@ void EQEmuLogSys::ProcessLogWrite(
std::ofstream crash_log; std::ofstream crash_log;
EQEmuLogSys::MakeDirectory("logs/crashes"); EQEmuLogSys::MakeDirectory("logs/crashes");
crash_log.open( crash_log.open(
StringFormat("logs/crashes/crash_%s_%i.log", m_platform_file_name.c_str(), getpid()), StringFormat("logs/crashes/crash_%s_%i.log", platform_file_name.c_str(), getpid()),
std::ios_base::app | std::ios_base::out std::ios_base::app | std::ios_base::out
); );
crash_log << time_stamp << " " << message << "\n"; crash_log << time_stamp << " " << message << "\n";
@@ -180,6 +257,64 @@ void EQEmuLogSys::ProcessLogWrite(
} }
} }
/**
* @param log_category
* @return
*/
uint16 EQEmuLogSys::GetWindowsConsoleColorFromCategory(uint16 log_category)
{
switch (log_category) {
case Logs::Status:
case Logs::Normal:
return Console::Color::Yellow;
case Logs::MySQLError:
case Logs::Error:
return Console::Color::LightRed;
case Logs::MySQLQuery:
case Logs::Debug:
return Console::Color::LightGreen;
case Logs::Quests:
return Console::Color::LightCyan;
case Logs::Commands:
case Logs::Mercenaries:
return Console::Color::LightMagenta;
case Logs::Crash:
return Console::Color::LightRed;
default:
return Console::Color::Yellow;
}
}
/**
* @param log_category
* @return
*/
std::string EQEmuLogSys::GetLinuxConsoleColorFromCategory(uint16 log_category)
{
switch (log_category) {
case Logs::Status:
case Logs::Normal:
return LC_YELLOW;
case Logs::MySQLError:
case Logs::Warning:
case Logs::Critical:
case Logs::Error:
return LC_RED;
case Logs::MySQLQuery:
case Logs::Debug:
return LC_GREEN;
case Logs::Quests:
return LC_CYAN;
case Logs::Commands:
case Logs::Mercenaries:
return LC_MAGENTA;
case Logs::Crash:
return LC_RED;
default:
return LC_YELLOW;
}
}
/** /**
* @param log_category * @param log_category
* @return * @return
@@ -187,10 +322,11 @@ void EQEmuLogSys::ProcessLogWrite(
uint16 EQEmuLogSys::GetGMSayColorFromCategory(uint16 log_category) uint16 EQEmuLogSys::GetGMSayColorFromCategory(uint16 log_category)
{ {
switch (log_category) { switch (log_category) {
case Logs::Crash: case Logs::Status:
case Logs::Error: case Logs::Normal:
return Chat::Yellow;
case Logs::MySQLError: case Logs::MySQLError:
case Logs::QuestErrors: case Logs::Error:
return Chat::Red; return Chat::Red;
case Logs::MySQLQuery: case Logs::MySQLQuery:
case Logs::Debug: case Logs::Debug:
@@ -200,151 +336,37 @@ uint16 EQEmuLogSys::GetGMSayColorFromCategory(uint16 log_category)
case Logs::Commands: case Logs::Commands:
case Logs::Mercenaries: case Logs::Mercenaries:
return Chat::Magenta; return Chat::Magenta;
case Logs::Crash:
return Chat::Red;
default: default:
return Chat::Yellow; return Chat::Yellow;
} }
} }
/** /**
* @param debug_level * @param debug_level
* @param log_category * @param log_category
* @param message * @param message
*/ */
void EQEmuLogSys::ProcessConsoleMessage( void EQEmuLogSys::ProcessConsoleMessage(uint16 log_category, const std::string &message)
uint16 log_category,
const std::string &message,
const char *file,
const char *func,
int line
)
{ {
bool is_error = ( #ifdef _WINDOWS
log_category == Logs::LogCategory::Error || HANDLE console_handle;
log_category == Logs::LogCategory::MySQLError || console_handle = GetStdHandle(STD_OUTPUT_HANDLE);
log_category == Logs::LogCategory::Crash || CONSOLE_FONT_INFOEX info = { 0 };
log_category == Logs::LogCategory::QuestErrors info.cbSize = sizeof(info);
); info.dwFontSize.Y = 12; // leave X as zero
bool is_warning = ( info.FontWeight = FW_NORMAL;
log_category == Logs::LogCategory::Warning wcscpy(info.FaceName, L"Lucida Console");
); SetCurrentConsoleFontEx(console_handle, NULL, &info);
SetConsoleTextAttribute(console_handle, EQEmuLogSys::GetWindowsConsoleColorFromCategory(log_category));
std::cout << message << "\n";
SetConsoleTextAttribute(console_handle, Console::Color::White);
#else
std::cout << EQEmuLogSys::GetLinuxConsoleColorFromCategory(log_category) << message << LC_RESET << std::endl;
#endif
(!is_error ? std::cout : std::cerr) on_log_console_hook(log_category, message);
<< ""
<< rang::fgB::black
<< rang::style::bold
<< fmt::format("{:>6}", GetPlatformName().substr(0, 6))
<< rang::style::reset
<< rang::fgB::gray
<< " | "
<< ((is_error || is_warning) ? rang::fgB::red : rang::fgB::gray)
<< rang::style::bold
<< fmt::format("{:^10}", fmt::format("{}", Logs::LogCategoryName[log_category]).substr(0, 10))
<< rang::style::reset
<< rang::fgB::gray
<< " | "
<< rang::fgB::gray
<< rang::style::bold
<< fmt::format("{}", func)
<< rang::style::reset
<< rang::fgB::gray
<< " ";
if (RuleB(Logging, PrintFileFunctionAndLine)) {
(!is_error ? std::cout : std::cerr)
<< ""
<< rang::fgB::green
<< rang::style::bold
<< fmt::format("{:}", fmt::format("{}:{}:{}", std::filesystem::path(file).filename().string(), func, line))
<< rang::style::reset
<< " | ";
}
if (log_category == Logs::LogCategory::MySQLQuery) {
auto s = Strings::Split(message, "--");
if (s.size() > 1) {
std::string query = Strings::Trim(s[0]);
std::string meta = Strings::Trim(s[1]);
std::cout <<
rang::fgB::green
<<
query
<<
rang::style::reset;
std::cout <<
rang::fgB::black
<<
" -- "
<<
meta
<<
rang::style::reset;
}
}
else if (Strings::Contains(message, "[")) {
for (auto &e: Strings::Split(message, " ")) {
if (Strings::Contains(e, "[") && Strings::Contains(e, "]")) {
e = Strings::Replace(e, "[", "");
e = Strings::Replace(e, "]", "");
bool is_upper = false;
for (int i = 0; i < strlen(e.c_str()); i++) {
if (isupper(e[i])) {
is_upper = true;
}
}
if (!is_upper) {
(!is_error ? std::cout : std::cerr)
<< rang::fgB::gray
<< "["
<< rang::style::bold
<< rang::fgB::yellow
<< e
<< rang::fgB::gray
<< "] "
;
}
else {
(!is_error ? std::cout : std::cerr) << rang::fgB::gray << "[" << e << "] ";
}
}
else {
(!is_error ? std::cout : std::cerr)
<< (is_error ? rang::fgB::red : rang::fgB::gray)
<< e
<< " ";
}
}
}
else {
(!is_error ? std::cout : std::cerr)
<< (is_error ? rang::fgB::red : rang::fgB::gray)
<< message
<< " ";
}
if (!origination_info.zone_short_name.empty()) {
(!is_error ? std::cout : std::cerr)
<<
rang::fgB::black
<<
"-- "
<<
fmt::format(
"[{}] ({}) inst_id [{}]",
origination_info.zone_short_name,
origination_info.zone_long_name,
origination_info.instance_id
);
}
(!is_error ? std::cout : std::cerr) << rang::style::reset << std::endl;
m_on_log_console_hook(log_category, message);
} }
/** /**
@@ -356,6 +378,33 @@ constexpr const char *str_end(const char *str)
return *str ? str_end(str + 1) : str; return *str ? str_end(str + 1) : str;
} }
/**
* @param str
* @return
*/
constexpr bool str_slant(const char *str)
{
return *str == '/' ? true : (*str ? str_slant(str + 1) : false);
}
/**
* @param str
* @return
*/
constexpr const char *r_slant(const char *str)
{
return *str == '/' ? (str + 1) : r_slant(str - 1);
}
/**
* @param str
* @return
*/
constexpr const char *base_file_name(const char *str)
{
return str_slant(str) ? r_slant(str_end(str)) : str;
}
/** /**
* Core logging function * Core logging function
* *
@@ -374,55 +423,50 @@ void EQEmuLogSys::Out(
... ...
) )
{ {
auto l = GetLogsEnabled(debug_level, log_category); bool log_to_console = log_settings[log_category].log_to_console > 0 &&
log_settings[log_category].log_to_console >= debug_level;
bool log_to_file = log_settings[log_category].log_to_file > 0 &&
log_settings[log_category].log_to_file >= debug_level;
bool log_to_gmsay = log_settings[log_category].log_to_gmsay > 0 &&
log_settings[log_category].log_to_gmsay >= debug_level &&
log_category != Logs::LogCategory::Netcode &&
(EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformZone ||
EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformWorld);
bool log_to_discord = EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformZone &&
log_settings[log_category].log_to_discord > 0 &&
log_settings[log_category].log_to_discord >= debug_level &&
log_settings[log_category].discord_webhook_id > 0 &&
log_settings[log_category].discord_webhook_id < MAX_DISCORD_WEBHOOK_ID;
// bail out if nothing to log // bail out if nothing to log
if (!l.log_enabled) { const bool nothing_to_log = !log_to_console && !log_to_file && !log_to_gmsay && !log_to_discord;
if (nothing_to_log) {
return; return;
} }
std::string prefix; std::string prefix;
if (RuleB(Logging, PrintFileFunctionAndLine)) { if (RuleB(Logging, PrintFileFunctionAndLine)) {
prefix = fmt::format("[{0}::{1}:{2}] ", std::filesystem::path(file).filename().string(), func, line); prefix = fmt::format("[{0}::{1}:{2}] ", base_file_name(file), func, line);
} }
// remove this when we remove all legacy logs va_list args;
bool ignore_log_legacy_format = ( va_start(args, message);
log_category == Logs::Netcode || std::string output_message = vStringFormat(message, args);
log_category == Logs::PacketServerClient || va_end(args);
log_category == Logs::PacketClientServer ||
log_category == Logs::PacketServerToServer
);
// remove this when we remove all legacy logs std::string output_debug_message = EQEmuLogSys::FormatOutMessageString(log_category, prefix + output_message);
std::string output_message = message;
if (!ignore_log_legacy_format) {
va_list args;
va_start(args, message);
output_message = vStringFormat(message, args);
va_end(args);
}
if (l.log_to_console_enabled) { if (log_to_console) {
EQEmuLogSys::ProcessConsoleMessage( EQEmuLogSys::ProcessConsoleMessage(log_category, output_debug_message);
log_category,
output_message,
file,
func,
line
);
} }
if (l.log_to_gmsay_enabled) { if (log_to_gmsay) {
m_on_log_gmsay_hook(log_category, func, output_message); on_log_gmsay_hook(log_category, message);
} }
if (l.log_to_file_enabled) { if (log_to_file) {
EQEmuLogSys::ProcessLogWrite( EQEmuLogSys::ProcessLogWrite(log_category, output_debug_message);
log_category,
fmt::format("[{}] [{}] {}", GetPlatformName(), Logs::LogCategoryName[log_category], prefix + output_message)
);
} }
if (l.log_to_discord_enabled && m_on_log_discord_hook) { if (log_to_discord && on_log_discord_hook) {
m_on_log_discord_hook(log_category, log_settings[log_category].discord_webhook_id, output_message); on_log_discord_hook(log_category, log_settings[log_category].discord_webhook_id, output_message);
} }
} }
@@ -435,7 +479,7 @@ void EQEmuLogSys::SetCurrentTimeStamp(char *time_stamp)
struct tm *time_info; struct tm *time_info;
time(&raw_time); time(&raw_time);
time_info = localtime(&raw_time); time_info = localtime(&raw_time);
strftime(time_stamp, 80, "[%m-%d-%Y %H:%M:%S]", time_info); strftime(time_stamp, 80, "[%m-%d-%Y :: %H:%M:%S]", time_info);
} }
/** /**
@@ -474,45 +518,53 @@ void EQEmuLogSys::StartFileLogs(const std::string &log_name)
/** /**
* When loading settings, we must have been given a reason in category based logging to output to a file in order to even create or open one... * When loading settings, we must have been given a reason in category based logging to output to a file in order to even create or open one...
*/ */
if (!m_file_logs_enabled) { if (!file_logs_enabled) {
return; return;
} }
/** /**
* Zone * Zone
*/ */
if (EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformZone) { if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformZone) {
if (!log_name.empty()) { if (!log_name.empty()) {
m_platform_file_name = log_name; platform_file_name = log_name;
} }
if (m_platform_file_name.empty()) { if (platform_file_name.empty()) {
return; return;
} }
LogInfo("Starting File Log [{}/zone/{}_{}.log]", GetLogPath(), m_platform_file_name.c_str(), getpid()); LogInfo("Starting File Log [logs/{}_{}.log]", platform_file_name.c_str(), getpid());
// Make directory if not exists /**
EQEmuLogSys::MakeDirectory(fmt::format("{}/zone", GetLogPath())); * Make directory if not exists
*/
EQEmuLogSys::MakeDirectory("logs/zone");
// Open file pointer /**
* Open file pointer
*/
process_log.open( process_log.open(
fmt::format("{}/zone/{}_{}.log", GetLogPath(), m_platform_file_name, getpid()), StringFormat("logs/zone/%s_%i.log", platform_file_name.c_str(), getpid()),
std::ios_base::app | std::ios_base::out std::ios_base::app | std::ios_base::out
); );
} }
else { else {
// All other processes /**
if (m_platform_file_name.empty()) { * All other processes
*/
if (platform_file_name.empty()) {
return; return;
} }
LogInfo("Starting File Log [{}/{}_{}.log]", GetLogPath(), m_platform_file_name.c_str(), getpid()); LogInfo("Starting File Log [logs/{}_{}.log]", platform_file_name.c_str(), getpid());
// Open file pointer /**
* Open file pointer
*/
process_log.open( process_log.open(
fmt::format("{}/{}_{}.log", GetLogPath(), m_platform_file_name.c_str(), getpid()), StringFormat("logs/%s_%i.log", platform_file_name.c_str(), getpid()),
std::ios_base::app | std::ios_base::out std::ios_base::app | std::ios_base::out
); );
} }
@@ -527,8 +579,6 @@ void EQEmuLogSys::SilenceConsoleLogging()
log_settings[log_index].log_to_console = 0; log_settings[log_index].log_to_console = 0;
log_settings[log_index].is_category_enabled = 0; log_settings[log_index].is_category_enabled = 0;
} }
log_settings[Logs::Crash].log_to_console = static_cast<uint8>(Logs::General);
} }
/** /**
@@ -544,8 +594,6 @@ void EQEmuLogSys::EnableConsoleLogging()
EQEmuLogSys *EQEmuLogSys::LoadLogDatabaseSettings() EQEmuLogSys *EQEmuLogSys::LoadLogDatabaseSettings()
{ {
InjectTablesIfNotExist();
auto categories = LogsysCategoriesRepository::GetWhere( auto categories = LogsysCategoriesRepository::GetWhere(
*m_database, *m_database,
"TRUE ORDER BY log_category_id" "TRUE ORDER BY log_category_id"
@@ -584,7 +632,7 @@ EQEmuLogSys *EQEmuLogSys::LoadLogDatabaseSettings()
// If we go through this whole loop and nothing is set to any debug level, there // If we go through this whole loop and nothing is set to any debug level, there
// is no point to create a file or keep anything open // is no point to create a file or keep anything open
if (log_settings[c.log_category_id].log_to_file > 0) { if (log_settings[c.log_category_id].log_to_file > 0) {
LogSys.m_file_logs_enabled = true; LogSys.file_logs_enabled = true;
} }
db_categories.emplace_back(c.log_category_id); db_categories.emplace_back(c.log_category_id);
@@ -592,28 +640,15 @@ EQEmuLogSys *EQEmuLogSys::LoadLogDatabaseSettings()
// Auto inject categories that don't exist in the database... // Auto inject categories that don't exist in the database...
for (int i = Logs::AA; i != Logs::MaxCategoryID; i++) { for (int i = Logs::AA; i != Logs::MaxCategoryID; i++) {
if (std::find(db_categories.begin(), db_categories.end(), i) == db_categories.end()) {
bool is_missing_in_database = std::find(db_categories.begin(), db_categories.end(), i) == db_categories.end();
bool is_deprecated_category = Strings::Contains(fmt::format("{}", Logs::LogCategoryName[i]), "Deprecated");
if (!is_missing_in_database && is_deprecated_category) {
LogInfo( LogInfo(
"Logging category [{}] ({}) is now deprecated, deleting from database", "Automatically adding new log category [{0}]",
Logs::LogCategoryName[i], Logs::LogCategoryName[i]
i
);
LogsysCategoriesRepository::DeleteOne(*m_database, i);
}
if (is_missing_in_database && !is_deprecated_category) {
LogInfo(
"Automatically adding new log category [{}] ({})",
Logs::LogCategoryName[i],
i
); );
auto new_category = LogsysCategoriesRepository::NewEntity(); auto new_category = LogsysCategoriesRepository::NewEntity();
new_category.log_category_id = i; new_category.log_category_id = i;
new_category.log_category_description = Strings::Escape(Logs::LogCategoryName[i]); new_category.log_category_description = EscapeString(Logs::LogCategoryName[i]);
new_category.log_to_console = log_settings[i].log_to_console; new_category.log_to_console = log_settings[i].log_to_console;
new_category.log_to_gmsay = log_settings[i].log_to_gmsay; new_category.log_to_gmsay = log_settings[i].log_to_gmsay;
new_category.log_to_file = log_settings[i].log_to_file; new_category.log_to_file = log_settings[i].log_to_file;
@@ -625,19 +660,14 @@ EQEmuLogSys *EQEmuLogSys::LoadLogDatabaseSettings()
LogInfo("Loaded [{}] log categories", categories.size()); LogInfo("Loaded [{}] log categories", categories.size());
auto webhooks = DiscordWebhooksRepository::GetWhere(*m_database, fmt::format("id < {}", MAX_DISCORD_WEBHOOK_ID)); auto webhooks = DiscordWebhooksRepository::All(*m_database);
if (!webhooks.empty()) { if (!webhooks.empty()) {
for (auto &w: webhooks) { for (auto &w: webhooks) {
m_discord_webhooks[w.id] = {w.id, w.webhook_name, w.webhook_url}; discord_webhooks[w.id] = {w.id, w.webhook_name, w.webhook_url};
} }
LogInfo("Loaded [{}] Discord webhooks", webhooks.size()); LogInfo("Loaded [{}] Discord webhooks", webhooks.size());
} }
// force override this setting
log_settings[Logs::Crash].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::Crash].log_to_gmsay = static_cast<uint8>(Logs::General);
log_settings[Logs::Crash].log_to_file = static_cast<uint8>(Logs::General);
return this; return this;
} }
@@ -648,96 +678,3 @@ EQEmuLogSys *EQEmuLogSys::SetDatabase(Database *db)
return this; return this;
} }
void EQEmuLogSys::InjectTablesIfNotExist()
{
// do not run injections for zone as its unnecessary hits every time a zone boots
// other processes less frequently ran can pick up injection
if (m_log_platform == EQEmuExePlatform::ExePlatformZone) {
return;
}
// inject discord_webhooks
if (!m_database->DoesTableExist("discord_webhooks")) {
LogInfo("Creating table [discord_webhooks]");
m_database->QueryDatabase(
SQL(
CREATE TABLE discord_webhooks
(
id INT auto_increment primary key NULL,
webhook_name varchar(100) NULL,
webhook_url varchar(255) NULL,
created_at DATETIME NULL,
deleted_at DATETIME NULL
) ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_general_ci;
)
);
}
// inject logsys_categories
if (!m_database->DoesTableExist("logsys_categories")) {
LogInfo("Creating table [logsys_categories]");
m_database->QueryDatabase(
SQL(
CREATE TABLE `logsys_categories` (
`log_category_id` int(11) NOT NULL,
`log_category_description` varchar(150) DEFAULT NULL,
`log_to_console` smallint(11) DEFAULT 0,
`log_to_file` smallint(11) DEFAULT 0,
`log_to_gmsay` smallint(11) DEFAULT 0,
`log_to_discord` smallint(11) DEFAULT 0,
`discord_webhook_id` int(11) DEFAULT 0,
PRIMARY KEY (`log_category_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
)
);
}
}
const EQEmuLogSys::DiscordWebhooks *EQEmuLogSys::GetDiscordWebhooks() const
{
return m_discord_webhooks;
}
EQEmuLogSys::LogEnabled EQEmuLogSys::GetLogsEnabled(const Logs::DebugLevel &debug_level, const uint16 &log_category)
{
auto e = LogEnabled{};
e.log_to_console_enabled = log_settings[log_category].log_to_console > 0 &&
log_settings[log_category].log_to_console >= debug_level;
e.log_to_file_enabled = log_settings[log_category].log_to_file > 0 &&
log_settings[log_category].log_to_file >= debug_level;
e.log_to_gmsay_enabled = log_settings[log_category].log_to_gmsay > 0 &&
log_settings[log_category].log_to_gmsay >= debug_level &&
log_category != Logs::LogCategory::Netcode &&
(EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformZone ||
EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformWorld);
e.log_to_discord_enabled = EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformZone &&
log_settings[log_category].log_to_discord > 0 &&
log_settings[log_category].log_to_discord >= debug_level &&
log_settings[log_category].discord_webhook_id > 0 &&
log_settings[log_category].discord_webhook_id < MAX_DISCORD_WEBHOOK_ID;
e.log_enabled =
e.log_to_console_enabled || e.log_to_file_enabled || e.log_to_gmsay_enabled || e.log_to_discord_enabled;
return e;
}
bool EQEmuLogSys::IsLogEnabled(const Logs::DebugLevel &debug_level, const uint16 &log_category)
{
return GetLogsEnabled(debug_level, log_category).log_enabled;
}
const std::string &EQEmuLogSys::GetLogPath() const
{
return m_log_path;
}
EQEmuLogSys *EQEmuLogSys::SetLogPath(const std::string &log_path)
{
EQEmuLogSys::m_log_path = log_path;
return this;
}
+66 -94
View File
@@ -39,7 +39,8 @@
namespace Logs { namespace Logs {
enum DebugLevel { enum DebugLevel {
General = 1, // 1 - Low-Level general debugging, useful info on single line General = 1, // 1 - Low-Level general debugging, useful info on single line
Detail // 2 - Use this for very chatty logging you want to leave in but don't want on by default Moderate, // 2 - Informational based, used in functions, when particular things load
Detail // 3 - Use this for extreme detail in logging, usually in extreme debugging in the stack or interprocess communication
}; };
/** /**
@@ -53,7 +54,7 @@ namespace Logs {
AI, AI,
Aggro, Aggro,
Attack, Attack,
DeprecatedCS, // deprecated PacketClientServer,
Combat, Combat,
Commands, Commands,
Crash, Crash,
@@ -64,36 +65,36 @@ namespace Logs {
Inventory, Inventory,
Launcher, Launcher,
Netcode, Netcode,
Normal, // deprecated Normal,
Object, Object,
Pathing, Pathing,
QSServer, // deprecated QSServer,
Quests, Quests,
Rules, Rules,
Skills, Skills,
Spawns, Spawns,
Spells, Spells,
Status, // deprecated Status,
TCPConnection, TCPConnection,
Tasks, Tasks,
Tradeskills, Tradeskills,
Trading, Trading,
Tribute, Tribute,
UCSServer, // deprecated UCSServer,
WebInterfaceServer, // deprecated WebInterfaceServer,
WorldServer, // deprecated WorldServer,
ZoneServer, // deprecated ZoneServer,
MySQLError, MySQLError,
MySQLQuery, MySQLQuery,
Mercenaries, Mercenaries,
QuestDebug, QuestDebug,
DeprecatedSC, // deprecated PacketServerClient,
DeprecatedCSU, // deprecated PacketClientServerUnhandled,
DeprecatedSCD, // deprecated PacketServerClientWithDump,
DeprecatedCSD, // deprecated PacketClientServerWithDump,
Loginserver, // deprecated Loginserver,
ClientLogin, ClientLogin,
HeadlessClient, // deprecated HeadlessClient,
HPUpdate, HPUpdate,
FixZ, FixZ,
Food, Food,
@@ -103,10 +104,10 @@ namespace Logs {
MobAppearance, MobAppearance,
Info, Info,
Warning, Warning,
Critical, // deprecated Critical,
Emergency, // deprecated Emergency,
Alert, // deprecated Alert,
Notice, // deprecated Notice,
AIScanClose, AIScanClose,
AIYellForHelp, AIYellForHelp,
AICastBeneficialClose, AICastBeneficialClose,
@@ -130,13 +131,6 @@ namespace Logs {
CombatRecord, CombatRecord,
Hate, Hate,
Discord, Discord,
Faction,
PacketServerClient,
PacketClientServer,
PacketServerToServer,
Bugs,
QuestErrors,
PlayerEvents,
MaxCategoryID /* Don't Remove this */ MaxCategoryID /* Don't Remove this */
}; };
@@ -149,7 +143,7 @@ namespace Logs {
"AI", "AI",
"Aggro", "Aggro",
"Attack", "Attack",
"Deprecated", "Packet :: Client -> Server",
"Combat", "Combat",
"Commands", "Commands",
"Crash", "Crash",
@@ -160,52 +154,52 @@ namespace Logs {
"Inventory", "Inventory",
"Launcher", "Launcher",
"Netcode", "Netcode",
"Normal (Deprecated)", "Normal",
"Object", "Object",
"Pathing", "Pathing",
"QS Server (Deprecated)", "QS Server",
"Quests", "Quests",
"Rules", "Rules",
"Skills", "Skills",
"Spawns", "Spawns",
"Spells", "Spells",
"Status (Deprecated)", "Status",
"TCP Connection", "TCP Connection",
"Tasks", "Tasks",
"Tradeskills", "Tradeskills",
"Trading", "Trading",
"Tribute", "Tribute",
"UCS Server (Deprecated)", "UCS Server",
"Web Interface (Deprecated)", "WebInterface Server",
"World Server (Deprecated)", "World Server",
"Zone Server (Deprecated)", "Zone Server",
"QueryErr", "MySQL Error",
"Query", "MySQL Query",
"Mercenaries", "Mercenaries",
"Quest Debug", "Quest Debug",
"Legacy Packet Logging (Deprecated)", "Packet :: Server -> Client",
"Legacy Packet Logging (Deprecated)", "Packet :: Client -> Server Unhandled",
"Legacy Packet Logging (Deprecated)", "Packet :: Server -> Client (Dump)",
"Legacy Packet Logging (Deprecated)", "Packet :: Client -> Server (Dump)",
"Login Server (Deprecated)", "Login Server",
"Client Login", "Client Login",
"Headless Client (Deprecated)", "Headless Client",
"HP Update", "HP Update",
"FixZ", "FixZ",
"Food", "Food",
"Traps", "Traps",
"NPC Roam Box", "NPC Roam Box",
"NPC Scaling", "NPC Scaling",
"MobAppearance", "Mob Appearance",
"Info", "Info",
"Warning", "Warning",
"Critical (Deprecated)", "Critical",
"Emergency (Deprecated)", "Emergency",
"Alert (Deprecated)", "Alert",
"Notice (Deprecated)", "Notice",
"AI Scan", "AI Scan Close",
"AI Yell", "AI Yell For Help",
"AI CastBeneficial", "AI Cast Beneficial Close",
"AOE Cast", "AOE Cast",
"Entity Management", "Entity Management",
"Flee", "Flee",
@@ -222,17 +216,10 @@ namespace Logs {
"DialogueWindow", "DialogueWindow",
"HTTP", "HTTP",
"Saylink", "Saylink",
"ChecksumVer", "ChecksumVerification",
"CombatRecord", "CombatRecord",
"Hate", "Hate",
"Discord", "Discord",
"Faction",
"Packet S->C",
"Packet C->S",
"Packet S->S",
"Bugs",
"QuestErrors",
"PlayerEvents",
}; };
} }
@@ -324,37 +311,32 @@ public:
*/ */
LogSettings log_settings[Logs::LogCategory::MaxCategoryID]{}; LogSettings log_settings[Logs::LogCategory::MaxCategoryID]{};
struct LogEnabled {
bool log_to_file_enabled;
bool log_to_console_enabled;
bool log_to_gmsay_enabled;
bool log_to_discord_enabled;
bool log_enabled;
};
LogEnabled GetLogsEnabled(const Logs::DebugLevel &debug_level, const uint16 &log_category);
bool IsLogEnabled(const Logs::DebugLevel &debug_level, const uint16 &log_category);
struct DiscordWebhooks { struct DiscordWebhooks {
int id; int id;
std::string webhook_name; std::string webhook_name;
std::string webhook_url; std::string webhook_url;
}; };
const DiscordWebhooks *GetDiscordWebhooks() const; DiscordWebhooks discord_webhooks[MAX_DISCORD_WEBHOOK_ID]{};
bool file_logs_enabled = false;
int log_platform = 0;
std::string platform_file_name;
// gmsay // gmsay
uint16 GetGMSayColorFromCategory(uint16 log_category); uint16 GetGMSayColorFromCategory(uint16 log_category);
EQEmuLogSys *SetGMSayHandler(const std::function<void(uint16 log_type, const char *func, const std::string &)>& f) EQEmuLogSys *SetGMSayHandler(std::function<void(uint16 log_type, const std::string &)> f)
{ {
m_on_log_gmsay_hook = f; on_log_gmsay_hook = f;
return this; return this;
} }
EQEmuLogSys *SetDiscordHandler(std::function<void(uint16 log_category, int webhook_id, const std::string &)> f) EQEmuLogSys *SetDiscordHandler(std::function<void(uint16 log_category, int webhook_id, const std::string &)> f)
{ {
m_on_log_discord_hook = f; on_log_discord_hook = f;
return this; return this;
} }
@@ -364,38 +346,28 @@ public:
uint16 log_type, uint16 log_type,
const std::string & const std::string &
)> f )> f
) { m_on_log_console_hook = f; } ) { on_log_console_hook = f; }
void SilenceConsoleLogging(); void SilenceConsoleLogging();
void EnableConsoleLogging(); void EnableConsoleLogging();
// database // database
EQEmuLogSys *SetDatabase(Database *db); EQEmuLogSys *SetDatabase(Database *db);
[[nodiscard]] const std::string &GetLogPath() const;
EQEmuLogSys * SetLogPath(const std::string &log_path);
private: private:
// reference to database // reference to database
Database *m_database; Database *m_database;
std::function<void(uint16 log_category, const char *func, const std::string &)> m_on_log_gmsay_hook; std::function<void(uint16 log_category, const std::string &)> on_log_gmsay_hook;
std::function<void(uint16 log_category, int webhook_id, const std::string &)> m_on_log_discord_hook; std::function<void(uint16 log_category, int webhook_id, const std::string &)> on_log_discord_hook;
std::function<void(uint16 log_category, const std::string &)> m_on_log_console_hook; std::function<void(uint16 log_category, const std::string &)> on_log_console_hook;
DiscordWebhooks m_discord_webhooks[MAX_DISCORD_WEBHOOK_ID]{};
bool m_file_logs_enabled = false;
int m_log_platform = 0;
std::string m_platform_file_name;
std::string m_log_path;
void ProcessConsoleMessage( std::string FormatOutMessageString(uint16 log_category, const std::string &in_message);
uint16 log_category, std::string GetLinuxConsoleColorFromCategory(uint16 log_category);
const std::string &message, uint16 GetWindowsConsoleColorFromCategory(uint16 log_category);
const char *file,
const char *func, void ProcessConsoleMessage(uint16 log_category, const std::string &message);
int line
);
void ProcessLogWrite(uint16 log_category, const std::string &message); void ProcessLogWrite(uint16 log_category, const std::string &message);
void InjectTablesIfNotExist(); bool IsRfc5424LogCategory(uint16 log_category);
}; };
extern EQEmuLogSys LogSys; extern EQEmuLogSys LogSys;
File diff suppressed because it is too large Load Diff
+4
View File
@@ -58,6 +58,10 @@ EQTime::EQTime()
SetCurrentEQTimeOfDay(start, time(0)); SetCurrentEQTimeOfDay(start, time(0));
} }
EQTime::~EQTime()
{
}
//getEQTimeOfDay - Reads timeConvert and writes the result to eqTimeOfDay //getEQTimeOfDay - Reads timeConvert and writes the result to eqTimeOfDay
//This function was written by the ShowEQ Project. //This function was written by the ShowEQ Project.
//Input: Current Time (as a time_t), a pointer to the TimeOfDay_Struct that will be written to. //Input: Current Time (as a time_t), a pointer to the TimeOfDay_Struct that will be written to.
+1 -1
View File
@@ -18,7 +18,7 @@ public:
//Constructor/destructor //Constructor/destructor
EQTime(TimeOfDay_Struct start_eq, time_t start_real); EQTime(TimeOfDay_Struct start_eq, time_t start_real);
EQTime(); EQTime();
~EQTime() = default; ~EQTime();
//Get functions //Get functions
int GetCurrentEQTimeOfDay( TimeOfDay_Struct *eqTimeOfDay ) { return(GetCurrentEQTimeOfDay(time(nullptr), eqTimeOfDay)); } int GetCurrentEQTimeOfDay( TimeOfDay_Struct *eqTimeOfDay ) { return(GetCurrentEQTimeOfDay(time(nullptr), eqTimeOfDay)); }
+4 -4
View File
@@ -1,14 +1,14 @@
#pragma once #pragma once
#include <any>
#include <functional> #include <functional>
#include <exception> #include <exception>
#include "event_loop.h" #include "event_loop.h"
#include "../any.h"
namespace EQ { namespace EQ {
class Task class Task
{ {
public: public:
typedef std::function<void(const std::any&)> ResolveFn; typedef std::function<void(const EQ::Any&)> ResolveFn;
typedef std::function<void(const std::exception&)> RejectFn; typedef std::function<void(const std::exception&)> RejectFn;
typedef std::function<void()> FinallyFn; typedef std::function<void()> FinallyFn;
typedef std::function<void(ResolveFn, RejectFn)> TaskFn; typedef std::function<void(ResolveFn, RejectFn)> TaskFn;
@@ -19,7 +19,7 @@ namespace EQ {
RejectFn on_catch; RejectFn on_catch;
FinallyFn on_finally; FinallyFn on_finally;
bool has_result; bool has_result;
std::any result; EQ::Any result;
bool has_error; bool has_error;
std::exception error; std::exception error;
}; };
@@ -63,7 +63,7 @@ namespace EQ {
uv_queue_work(EventLoop::Get().Handle(), m_work, [](uv_work_t* req) { uv_queue_work(EventLoop::Get().Handle(), m_work, [](uv_work_t* req) {
TaskBaton *baton = (TaskBaton*)req->data; TaskBaton *baton = (TaskBaton*)req->data;
baton->fn([baton](const std::any& result) { baton->fn([baton](const EQ::Any& result) {
baton->has_error = false; baton->has_error = false;
baton->has_result = true; baton->has_result = true;
baton->result = result; baton->result = result;
+3 -3
View File
@@ -38,7 +38,7 @@ namespace EQ
_running = true; _running = true;
for (size_t i = 0; i < threads; ++i) { for (size_t i = 0; i < threads; ++i) {
_threads.emplace_back(std::thread(std::bind(&TaskScheduler::ProcessWork, this))); _threads.push_back(std::thread(std::bind(&TaskScheduler::ProcessWork, this)));
} }
} }
@@ -60,8 +60,8 @@ namespace EQ
} }
template<typename Fn, typename... Args> template<typename Fn, typename... Args>
auto Enqueue(Fn&& fn, Args&&... args) -> std::future<typename std::invoke_result<Fn, Args...>::type> { auto Enqueue(Fn&& fn, Args&&... args) -> std::future<typename std::result_of<Fn(Args...)>::type> {
using return_type = typename std::invoke_result<Fn, Args...>::type; using return_type = typename std::result_of<Fn(Args...)>::type;
auto task = std::make_shared<std::packaged_task<return_type()>>( auto task = std::make_shared<std::packaged_task<return_type()>>(
std::bind(std::forward<Fn>(fn), std::forward<Args>(args)...) std::bind(std::forward<Fn>(fn), std::forward<Args>(args)...)
File diff suppressed because it is too large Load Diff
@@ -1,214 +0,0 @@
#ifndef EQEMU_PLAYER_EVENT_DISCORD_FORMATTER_H
#define EQEMU_PLAYER_EVENT_DISCORD_FORMATTER_H
#include <string>
#include "player_events.h"
#include "../repositories/base/base_player_event_logs_repository.h"
#include <cereal/archives/json.hpp>
#include <cereal/types/vector.hpp>
struct DiscordField {
std::string name;
std::string value;
bool is_inline;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(name),
CEREAL_NVP(value),
cereal::make_nvp("inline", is_inline)
);
}
};
struct DiscordAuthor {
std::string name;
std::string icon_url;
std::string url;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(name),
CEREAL_NVP(icon_url),
CEREAL_NVP(url)
);
}
};
struct DiscordEmbed {
std::vector<DiscordField> fields;
std::string title;
std::string description;
std::string timestamp;
DiscordAuthor author;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(fields),
CEREAL_NVP(title),
CEREAL_NVP(description),
CEREAL_NVP(timestamp),
CEREAL_NVP(author)
);
}
};
struct DiscordWebhook {
std::vector<DiscordEmbed> embeds;
std::string content;
std::string avatar_url;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(embeds),
CEREAL_NVP(avatar_url),
CEREAL_NVP(content)
);
}
};
class PlayerEventDiscordFormatter {
public:
static std::string GetCurrentTimestamp();
static std::string FormatEventSay(const PlayerEvent::PlayerEventContainer &c, const PlayerEvent::SayEvent &e);
static std::string
FormatGMCommand(const PlayerEvent::PlayerEventContainer &c, const PlayerEvent::GMCommandEvent &e);
static void BuildDiscordField(
std::vector<DiscordField> *f,
const std::string &name,
const std::string &value,
bool is_inline = true
);
static void BuildBaseEmbed(
std::vector<DiscordEmbed> *e,
const std::vector<DiscordField> &f,
PlayerEvent::PlayerEventContainer c
);
static std::string FormatWithNodata(const PlayerEvent::PlayerEventContainer &c);
static std::string FormatAAGainedEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::AAGainedEvent &e
);
static std::string FormatAAPurchasedEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::AAPurchasedEvent &e
);
static std::string FormatDeathEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::DeathEvent &e
);
static std::string FormatFishSuccessEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::FishSuccessEvent &e
);
static std::string FormatForageSuccessEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::ForageSuccessEvent &e
);
static std::string FormatDestroyItemEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::DestroyItemEvent &e
);
static std::string FormatDiscoverItemEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::DiscoverItemEvent &e
);
static std::string FormatDroppedItemEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::DroppedItemEvent &e
);
static std::string FormatLevelGainedEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::LevelGainedEvent &e
);
static std::string FormatLevelLostEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::LevelLostEvent &e
);
static std::string FormatLootItemEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::LootItemEvent &e
);
static std::string FormatGroundSpawnPickupEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::GroundSpawnPickupEvent &e
);
static std::string FormatMerchantPurchaseEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::MerchantPurchaseEvent &e
);
static std::string FormatMerchantSellEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::MerchantSellEvent &e
);
static std::string FormatNPCHandinEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::HandinEvent &e
);
static std::string FormatSkillUpEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::SkillUpEvent &e
);
static std::string FormatTaskAcceptEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::TaskAcceptEvent &e
);
static std::string FormatTaskCompleteEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::TaskCompleteEvent &e
);
static std::string FormatTaskUpdateEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::TaskUpdateEvent &e
);
static std::string FormatTradeEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::TradeEvent &e
);
static std::string FormatTraderPurchaseEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::TraderPurchaseEvent &e
);
static std::string FormatTraderSellEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::TraderSellEvent &e
);
static std::string FormatResurrectAcceptEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::ResurrectAcceptEvent &e
);
static std::string FormatSplitMoneyEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::SplitMoneyEvent &e
);
static std::string FormatCombineEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::CombineEvent &e
);
static std::string FormatZoningEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::ZoningEvent &e
);
static DiscordWebhook BuildDiscordWebhook(
const PlayerEvent::PlayerEventContainer &p,
std::vector<DiscordEmbed> &embeds
);
};
#endif //EQEMU_PLAYER_EVENT_DISCORD_FORMATTER_H
-702
View File
@@ -1,702 +0,0 @@
#include <cereal/archives/json.hpp>
#include "player_event_logs.h"
#include "player_event_discord_formatter.h"
#include "../platform.h"
#include "../rulesys.h"
const uint32 PROCESS_RETENTION_TRUNCATION_TIMER_INTERVAL = 60 * 60 * 1000; // 1 hour
// general initialization routine
void PlayerEventLogs::Init()
{
m_process_batch_events_timer.SetTimer(RuleI(Logging, BatchPlayerEventProcessIntervalSeconds) * 1000);
m_process_retention_truncation_timer.SetTimer(PROCESS_RETENTION_TRUNCATION_TIMER_INTERVAL);
ValidateDatabaseConnection();
// initialize settings array
for (int i = PlayerEvent::GM_COMMAND; i != PlayerEvent::MAX; i++) {
m_settings[i].id = i;
m_settings[i].event_name = PlayerEvent::EventName[i];
m_settings[i].event_enabled = 1;
m_settings[i].retention_days = 0;
m_settings[i].discord_webhook_id = 0;
}
SetSettingsDefaults();
// initialize settings from database
auto s = PlayerEventLogSettingsRepository::All(*m_database);
std::vector<int> db{};
db.reserve(s.size());
for (auto &e: s) {
if (e.id >= PlayerEvent::MAX) {
continue;
}
m_settings[e.id] = e;
db.emplace_back(e.id);
}
// insert entries that don't exist in database
for (int i = PlayerEvent::GM_COMMAND; i != PlayerEvent::MAX; i++) {
bool is_in_database = std::find(db.begin(), db.end(), i) != db.end();
bool is_deprecated = Strings::Contains(PlayerEvent::EventName[i], "Deprecated");
bool is_implemented = !Strings::Contains(PlayerEvent::EventName[i], "Unimplemented");
// remove when deprecated
if (is_deprecated && is_in_database) {
LogInfo("[Deprecated] Removing PlayerEvent [{}] ({})", PlayerEvent::EventName[i], i);
PlayerEventLogSettingsRepository::DeleteWhere(*m_database, fmt::format("id = {}", i));
}
// remove when unimplemented if present
if (!is_implemented && is_in_database) {
LogInfo("[Unimplemented] Removing PlayerEvent [{}] ({})", PlayerEvent::EventName[i], i);
PlayerEventLogSettingsRepository::DeleteWhere(*m_database, fmt::format("id = {}", i));
}
bool is_missing_in_database = std::find(db.begin(), db.end(), i) == db.end();
if (is_missing_in_database && is_implemented && !is_deprecated) {
LogInfo(
"[New] PlayerEvent [{}] ({})",
PlayerEvent::EventName[i],
i
);
auto c = PlayerEventLogSettingsRepository::NewEntity();
c.id = i;
c.event_name = PlayerEvent::EventName[i];
c.event_enabled = m_settings[i].event_enabled;
c.retention_days = m_settings[i].retention_days;
PlayerEventLogSettingsRepository::InsertOne(*m_database, c);
}
}
bool processing_in_world = !RuleB(Logging, PlayerEventsQSProcess) && IsWorld();
bool processing_in_qs = RuleB(Logging, PlayerEventsQSProcess) && IsQueryServ();
// on initial boot process truncation
if (processing_in_world || processing_in_qs) {
ProcessRetentionTruncation();
}
}
// set the database object, during initialization
PlayerEventLogs *PlayerEventLogs::SetDatabase(Database *db)
{
m_database = db;
return this;
}
// validates whether the connection is valid or not, used in initialization
bool PlayerEventLogs::ValidateDatabaseConnection()
{
if (!m_database) {
LogError("No database connection");
return false;
}
return true;
}
// determines if the passed in event is enabled or not
// this is used to gate logic or events from firing off
// this is used prior to building the events, we don't want to
// build the events, send them through the stack in a function call
// only to discard them immediately afterwards, very wasteful on resources
// the quest api currently does this
bool PlayerEventLogs::IsEventEnabled(PlayerEvent::EventType event)
{
return m_settings[event].event_enabled ? m_settings[event].event_enabled : false;
}
// this processes any current player events on the queue
void PlayerEventLogs::ProcessBatchQueue()
{
m_batch_queue_lock.lock();
if (m_record_batch_queue.empty()) {
m_batch_queue_lock.unlock();
return;
}
BenchTimer benchmark;
// flush many
PlayerEventLogsRepository::InsertMany(*m_database, m_record_batch_queue);
LogPlayerEventsDetail(
"Processing batch player event log queue of [{}] took [{}]",
m_record_batch_queue.size(),
benchmark.elapsed()
);
// empty
m_record_batch_queue = {};
m_batch_queue_lock.unlock();
}
// adds a player event to the queue
void PlayerEventLogs::AddToQueue(const PlayerEventLogsRepository::PlayerEventLogs &log)
{
m_batch_queue_lock.lock();
m_record_batch_queue.emplace_back(log);
m_batch_queue_lock.unlock();
}
// fills common event data in the SendEvent function
void PlayerEventLogs::FillPlayerEvent(
const PlayerEvent::PlayerEvent &p,
PlayerEventLogsRepository::PlayerEventLogs &n
)
{
n.account_id = p.account_id;
n.character_id = p.character_id;
n.zone_id = p.zone_id;
n.instance_id = p.instance_id;
n.x = p.x;
n.y = p.y;
n.z = p.z;
n.heading = p.heading;
}
// builds the dynamic packet used to ship the player event over the wire
// supports serializing the struct so it can be rebuilt on the other end
std::unique_ptr<ServerPacket>
PlayerEventLogs::BuildPlayerEventPacket(const PlayerEvent::PlayerEventContainer &e)
{
EQ::Net::DynamicPacket dyn_pack;
dyn_pack.PutSerialize(0, e);
auto pack_size = sizeof(ServerSendPlayerEvent_Struct) + dyn_pack.Length();
auto pack = std::make_unique<ServerPacket>(ServerOP_PlayerEvent, static_cast<uint32_t>(pack_size));
auto buf = reinterpret_cast<ServerSendPlayerEvent_Struct *>(pack->pBuffer);
buf->cereal_size = static_cast<uint32_t>(dyn_pack.Length());
memcpy(buf->cereal_data, dyn_pack.Data(), dyn_pack.Length());
return pack;
}
const PlayerEventLogSettingsRepository::PlayerEventLogSettings *PlayerEventLogs::GetSettings() const
{
return m_settings;
}
bool PlayerEventLogs::IsEventDiscordEnabled(int32_t event_type_id)
{
// out of bounds check
if (event_type_id >= PlayerEvent::EventType::MAX) {
return false;
}
// make sure webhook id is set
if (m_settings[event_type_id].discord_webhook_id == 0) {
return false;
}
// ensure there is a matching webhook to begin with
if (!LogSys.GetDiscordWebhooks()[m_settings[event_type_id].discord_webhook_id].webhook_url.empty()) {
return true;
}
return false;
}
std::string PlayerEventLogs::GetDiscordWebhookUrlFromEventType(int32_t event_type_id)
{
// out of bounds check
if (event_type_id >= PlayerEvent::EventType::MAX) {
return "";
}
// make sure webhook id is set
if (m_settings[event_type_id].discord_webhook_id == 0) {
return "";
}
// ensure there is a matching webhook to begin with
if (!LogSys.GetDiscordWebhooks()[m_settings[event_type_id].discord_webhook_id].webhook_url.empty()) {
return LogSys.GetDiscordWebhooks()[m_settings[event_type_id].discord_webhook_id].webhook_url;
}
return "";
}
// GM_COMMAND | [x] Implemented Formatter
// ZONING | [x] Implemented Formatter
// AA_GAIN | [x] Implemented Formatter
// AA_PURCHASE | [x] Implemented Formatter
// FORAGE_SUCCESS | [x] Implemented Formatter
// FORAGE_FAILURE | [x] Implemented Formatter
// FISH_SUCCESS | [x] Implemented Formatter
// FISH_FAILURE | [x] Implemented Formatter
// ITEM_DESTROY | [x] Implemented Formatter
// WENT_ONLINE | [x] Implemented Formatter
// WENT_OFFLINE | [x] Implemented Formatter
// LEVEL_GAIN | [x] Implemented Formatter
// LEVEL_LOSS | [x] Implemented Formatter
// LOOT_ITEM | [x] Implemented Formatter
// MERCHANT_PURCHASE | [x] Implemented Formatter
// MERCHANT_SELL | [x] Implemented Formatter
// GROUP_JOIN | [] Implemented Formatter
// GROUP_LEAVE | [] Implemented Formatter
// RAID_JOIN | [] Implemented Formatter
// RAID_LEAVE | [] Implemented Formatter
// GROUNDSPAWN_PICKUP | [x] Implemented Formatter
// NPC_HANDIN | [x] Implemented Formatter
// SKILL_UP | [x] Implemented Formatter
// TASK_ACCEPT | [x] Implemented Formatter
// TASK_UPDATE | [x] Implemented Formatter
// TASK_COMPLETE | [x] Implemented Formatter
// TRADE | [] Implemented Formatter
// GIVE_ITEM | [] Implemented Formatter
// SAY | [x] Implemented Formatter
// REZ_ACCEPTED | [x] Implemented Formatter
// DEATH | [x] Implemented Formatter
// COMBINE_FAILURE | [x] Implemented Formatter
// COMBINE_SUCCESS | [x] Implemented Formatter
// DROPPED_ITEM | [x] Implemented Formatter
// SPLIT_MONEY | [x] Implemented Formatter
// DZ_JOIN | [] Implemented Formatter
// DZ_LEAVE | [] Implemented Formatter
// TRADER_PURCHASE | [x] Implemented Formatter
// TRADER_SELL | [x] Implemented Formatter
// BANDOLIER_CREATE | [] Implemented Formatter
// BANDOLIER_SWAP | [] Implemented Formatter
// DISCOVER_ITEM | [X] Implemented Formatter
std::string PlayerEventLogs::GetDiscordPayloadFromEvent(const PlayerEvent::PlayerEventContainer &e)
{
std::string payload;
switch (e.player_event_log.event_type_id) {
case PlayerEvent::AA_GAIN: {
PlayerEvent::AAGainedEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatAAGainedEvent(e, n);
break;
}
case PlayerEvent::AA_PURCHASE: {
PlayerEvent::AAPurchasedEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatAAPurchasedEvent(e, n);
break;
}
case PlayerEvent::COMBINE_FAILURE:
case PlayerEvent::COMBINE_SUCCESS: {
PlayerEvent::CombineEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatCombineEvent(e, n);
break;
}
case PlayerEvent::DEATH: {
PlayerEvent::DeathEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatDeathEvent(e, n);
break;
}
case PlayerEvent::DISCOVER_ITEM: {
PlayerEvent::DiscoverItemEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatDiscoverItemEvent(e, n);
break;
}
case PlayerEvent::DROPPED_ITEM: {
PlayerEvent::DroppedItemEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatDroppedItemEvent(e, n);
break;
}
case PlayerEvent::FISH_FAILURE:
case PlayerEvent::FORAGE_FAILURE:
case PlayerEvent::WENT_ONLINE:
case PlayerEvent::WENT_OFFLINE: {
payload = PlayerEventDiscordFormatter::FormatWithNodata(e);
break;
}
case PlayerEvent::FISH_SUCCESS: {
PlayerEvent::FishSuccessEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatFishSuccessEvent(e, n);
break;
}
case PlayerEvent::FORAGE_SUCCESS: {
PlayerEvent::ForageSuccessEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatForageSuccessEvent(e, n);
break;
}
case PlayerEvent::ITEM_DESTROY: {
PlayerEvent::DestroyItemEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatDestroyItemEvent(e, n);
break;
}
case PlayerEvent::LEVEL_GAIN: {
PlayerEvent::LevelGainedEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatLevelGainedEvent(e, n);
break;
}
case PlayerEvent::LEVEL_LOSS: {
PlayerEvent::LevelLostEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatLevelLostEvent(e, n);
break;
}
case PlayerEvent::LOOT_ITEM: {
PlayerEvent::LootItemEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatLootItemEvent(e, n);
break;
}
case PlayerEvent::GROUNDSPAWN_PICKUP: {
PlayerEvent::GroundSpawnPickupEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatGroundSpawnPickupEvent(e, n);
break;
}
case PlayerEvent::NPC_HANDIN: {
PlayerEvent::HandinEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatNPCHandinEvent(e, n);
break;
}
case PlayerEvent::SAY: {
PlayerEvent::SayEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatEventSay(e, n);
break;
}
case PlayerEvent::GM_COMMAND: {
PlayerEvent::GMCommandEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatGMCommand(e, n);
break;
}
case PlayerEvent::SKILL_UP: {
PlayerEvent::SkillUpEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatSkillUpEvent(e, n);
break;
}
case PlayerEvent::SPLIT_MONEY: {
PlayerEvent::SplitMoneyEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatSplitMoneyEvent(e, n);
break;
}
case PlayerEvent::TASK_ACCEPT: {
PlayerEvent::TaskAcceptEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatTaskAcceptEvent(e, n);
break;
}
case PlayerEvent::TASK_COMPLETE: {
PlayerEvent::TaskCompleteEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatTaskCompleteEvent(e, n);
break;
}
case PlayerEvent::TASK_UPDATE: {
PlayerEvent::TaskUpdateEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatTaskUpdateEvent(e, n);
break;
}
case PlayerEvent::TRADE: {
PlayerEvent::TradeEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatTradeEvent(e, n);
break;
}
case PlayerEvent::TRADER_PURCHASE: {
PlayerEvent::TraderPurchaseEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatTraderPurchaseEvent(e, n);
break;
}
case PlayerEvent::TRADER_SELL: {
PlayerEvent::TraderSellEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatTraderSellEvent(e, n);
break;
}
case PlayerEvent::REZ_ACCEPTED: {
PlayerEvent::ResurrectAcceptEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatResurrectAcceptEvent(e, n);
break;
}
case PlayerEvent::MERCHANT_PURCHASE: {
PlayerEvent::MerchantPurchaseEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatMerchantPurchaseEvent(e, n);
break;
}
case PlayerEvent::MERCHANT_SELL: {
PlayerEvent::MerchantSellEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatMerchantSellEvent(e, n);
break;
}
case PlayerEvent::ZONING: {
PlayerEvent::ZoningEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatZoningEvent(e, n);
break;
}
default: {
LogInfo(
"Player event [{}] ({}) Discord formatter not implemented",
e.player_event_log.event_type_name,
e.player_event_log.event_type_id
);
}
}
return payload;
}
// general process function, used in world or QS depending on rule Logging:PlayerEventsQSProcess
void PlayerEventLogs::Process()
{
if (m_process_batch_events_timer.Check() || m_record_batch_queue.size() >= RuleI(Logging, BatchPlayerEventProcessChunkSize)) {
ProcessBatchQueue();
}
if (m_process_retention_truncation_timer.Check()) {
ProcessRetentionTruncation();
}
}
void PlayerEventLogs::ProcessRetentionTruncation()
{
LogInfo("Running truncation");
for (int i = PlayerEvent::GM_COMMAND; i != PlayerEvent::MAX; i++) {
if (m_settings[i].retention_days > 0) {
int deleted_count = PlayerEventLogsRepository::DeleteWhere(
*m_database,
fmt::format(
"event_type_id = {} AND created_at < (NOW() - INTERVAL {} DAY)",
i,
m_settings[i].retention_days
)
);
if (deleted_count > 0) {
LogInfo(
"Truncated [{}] events of type [{}] ({}) older than [{}] days",
deleted_count,
PlayerEvent::EventName[i],
i,
m_settings[i].retention_days
);
}
}
}
}
void PlayerEventLogs::ReloadSettings()
{
for (auto &e: PlayerEventLogSettingsRepository::All(*m_database)) {
m_settings[e.id] = e;
}
}
const int32_t RETENTION_DAYS_DEFAULT = 7;
void PlayerEventLogs::SetSettingsDefaults()
{
m_settings[PlayerEvent::GM_COMMAND].event_enabled = 1;
m_settings[PlayerEvent::ZONING].event_enabled = 1;
m_settings[PlayerEvent::AA_GAIN].event_enabled = 1;
m_settings[PlayerEvent::AA_PURCHASE].event_enabled = 1;
m_settings[PlayerEvent::FORAGE_SUCCESS].event_enabled = 0;
m_settings[PlayerEvent::FORAGE_FAILURE].event_enabled = 0;
m_settings[PlayerEvent::FISH_SUCCESS].event_enabled = 0;
m_settings[PlayerEvent::FISH_FAILURE].event_enabled = 0;
m_settings[PlayerEvent::ITEM_DESTROY].event_enabled = 1;
m_settings[PlayerEvent::WENT_ONLINE].event_enabled = 0;
m_settings[PlayerEvent::WENT_OFFLINE].event_enabled = 0;
m_settings[PlayerEvent::LEVEL_GAIN].event_enabled = 1;
m_settings[PlayerEvent::LEVEL_LOSS].event_enabled = 1;
m_settings[PlayerEvent::LOOT_ITEM].event_enabled = 1;
m_settings[PlayerEvent::MERCHANT_PURCHASE].event_enabled = 1;
m_settings[PlayerEvent::MERCHANT_SELL].event_enabled = 1;
m_settings[PlayerEvent::GROUP_JOIN].event_enabled = 0;
m_settings[PlayerEvent::GROUP_LEAVE].event_enabled = 0;
m_settings[PlayerEvent::RAID_JOIN].event_enabled = 0;
m_settings[PlayerEvent::RAID_LEAVE].event_enabled = 0;
m_settings[PlayerEvent::GROUNDSPAWN_PICKUP].event_enabled = 1;
m_settings[PlayerEvent::NPC_HANDIN].event_enabled = 1;
m_settings[PlayerEvent::SKILL_UP].event_enabled = 0;
m_settings[PlayerEvent::TASK_ACCEPT].event_enabled = 1;
m_settings[PlayerEvent::TASK_UPDATE].event_enabled = 1;
m_settings[PlayerEvent::TASK_COMPLETE].event_enabled = 1;
m_settings[PlayerEvent::TRADE].event_enabled = 1;
m_settings[PlayerEvent::GIVE_ITEM].event_enabled = 1;
m_settings[PlayerEvent::SAY].event_enabled = 0;
m_settings[PlayerEvent::REZ_ACCEPTED].event_enabled = 1;
m_settings[PlayerEvent::DEATH].event_enabled = 1;
m_settings[PlayerEvent::COMBINE_FAILURE].event_enabled = 1;
m_settings[PlayerEvent::COMBINE_SUCCESS].event_enabled = 1;
m_settings[PlayerEvent::DROPPED_ITEM].event_enabled = 1;
m_settings[PlayerEvent::SPLIT_MONEY].event_enabled = 1;
m_settings[PlayerEvent::DZ_JOIN].event_enabled = 1;
m_settings[PlayerEvent::DZ_LEAVE].event_enabled = 1;
m_settings[PlayerEvent::TRADER_PURCHASE].event_enabled = 1;
m_settings[PlayerEvent::TRADER_SELL].event_enabled = 1;
m_settings[PlayerEvent::BANDOLIER_CREATE].event_enabled = 0;
m_settings[PlayerEvent::BANDOLIER_SWAP].event_enabled = 0;
m_settings[PlayerEvent::DISCOVER_ITEM].event_enabled = 1;
m_settings[PlayerEvent::POSSIBLE_HACK].event_enabled = 1;
m_settings[PlayerEvent::KILLED_NPC].event_enabled = 0;
m_settings[PlayerEvent::KILLED_NAMED_NPC].event_enabled = 1;
m_settings[PlayerEvent::KILLED_RAID_NPC].event_enabled = 1;
m_settings[PlayerEvent::ITEM_CREATION].event_enabled = 1;
for (int i = PlayerEvent::GM_COMMAND; i != PlayerEvent::MAX; i++) {
m_settings[i].retention_days = RETENTION_DAYS_DEFAULT;
}
}
-85
View File
@@ -1,85 +0,0 @@
#ifndef EQEMU_PLAYER_EVENT_LOGS_H
#define EQEMU_PLAYER_EVENT_LOGS_H
#include "../repositories/player_event_log_settings_repository.h"
#include "player_events.h"
#include "../servertalk.h"
#include "../repositories/player_event_logs_repository.h"
#include "../timer.h"
#include "../json/json_archive_single_line.h"
#include <cereal/archives/json.hpp>
#include <mutex>
class PlayerEventLogs {
public:
void Init();
void ReloadSettings();
PlayerEventLogs *SetDatabase(Database *db);
bool ValidateDatabaseConnection();
bool IsEventEnabled(PlayerEvent::EventType event);
void Process();
// batch queue
void AddToQueue(const PlayerEventLogsRepository::PlayerEventLogs &logs);
// main event record generic function
// can ingest any struct event types
template<typename T>
std::unique_ptr<ServerPacket> RecordEvent(
PlayerEvent::EventType t,
const PlayerEvent::PlayerEvent &p,
T e
)
{
auto n = PlayerEventLogsRepository::NewEntity();
FillPlayerEvent(p, n);
n.event_type_id = t;
std::stringstream ss;
{
cereal::JSONOutputArchiveSingleLine ar(ss);
e.serialize(ar);
}
n.event_type_name = PlayerEvent::EventName[t];
n.event_data = Strings::Contains(ss.str(), "noop") ? "{}" : ss.str();
n.created_at = std::time(nullptr);
auto c = PlayerEvent::PlayerEventContainer{
.player_event = p,
.player_event_log = n
};
return BuildPlayerEventPacket(c);
}
[[nodiscard]] const PlayerEventLogSettingsRepository::PlayerEventLogSettings *GetSettings() const;
bool IsEventDiscordEnabled(int32_t event_type_id);
std::string GetDiscordWebhookUrlFromEventType(int32_t event_type_id);
static std::string GetDiscordPayloadFromEvent(const PlayerEvent::PlayerEventContainer &e);
private:
Database *m_database; // reference to database
PlayerEventLogSettingsRepository::PlayerEventLogSettings m_settings[PlayerEvent::EventType::MAX]{};
// batch queue is used to record events in batch
std::vector<PlayerEventLogsRepository::PlayerEventLogs> m_record_batch_queue{};
static void FillPlayerEvent(const PlayerEvent::PlayerEvent &p, PlayerEventLogsRepository::PlayerEventLogs &n);
static std::unique_ptr<ServerPacket>
BuildPlayerEventPacket(const PlayerEvent::PlayerEventContainer &e);
// timers
Timer m_process_batch_events_timer; // events processing timer
Timer m_process_retention_truncation_timer; // timer for truncating events based on retention settings
// processing
std::mutex m_batch_queue_lock{};
void ProcessBatchQueue();
void ProcessRetentionTruncation();
void SetSettingsDefaults();
};
extern PlayerEventLogs player_event_logs;
#endif //EQEMU_PLAYER_EVENT_LOGS_H
-971
View File
@@ -1,971 +0,0 @@
#ifndef EQEMU_PLAYER_EVENTS_H
#define EQEMU_PLAYER_EVENTS_H
#include <string>
#include <cereal/cereal.hpp>
#include "../types.h"
#include "../repositories/player_event_logs_repository.h"
namespace PlayerEvent {
enum EventType {
GM_COMMAND = 1,
ZONING,
AA_GAIN,
AA_PURCHASE,
FORAGE_SUCCESS,
FORAGE_FAILURE,
FISH_SUCCESS,
FISH_FAILURE,
ITEM_DESTROY,
WENT_ONLINE,
WENT_OFFLINE,
LEVEL_GAIN,
LEVEL_LOSS,
LOOT_ITEM,
MERCHANT_PURCHASE,
MERCHANT_SELL,
GROUP_JOIN, // unimplemented
GROUP_LEAVE, // unimplemented
RAID_JOIN, // unimplemented
RAID_LEAVE, // unimplemented
GROUNDSPAWN_PICKUP,
NPC_HANDIN,
SKILL_UP,
TASK_ACCEPT,
TASK_UPDATE,
TASK_COMPLETE,
TRADE,
GIVE_ITEM, // unimplemented
SAY,
REZ_ACCEPTED,
DEATH,
COMBINE_FAILURE,
COMBINE_SUCCESS,
DROPPED_ITEM,
SPLIT_MONEY,
DZ_JOIN, // unimplemented
DZ_LEAVE, // unimplemented
TRADER_PURCHASE,
TRADER_SELL,
BANDOLIER_CREATE, // unimplemented
BANDOLIER_SWAP, // unimplemented
DISCOVER_ITEM,
POSSIBLE_HACK,
KILLED_NPC,
KILLED_NAMED_NPC,
KILLED_RAID_NPC,
ITEM_CREATION,
MAX // dont remove
};
// Don't ever remove items, even if they are deprecated
// If event is deprecated just tag (Deprecated) in the name
// If event is unimplemented just tag (Unimplemented) in the name
// Events don't get saved to the database if unimplemented or deprecated
// Events tagged as deprecated will get automatically removed
static const char *EventName[PlayerEvent::MAX] = {
"None",
"GM Command",
"Zoning",
"AA Gain",
"AA Purchase",
"Forage Success",
"Forage Failure",
"Fish Success",
"Fish Failure",
"Item Destroy",
"Went Online",
"Went Offline",
"Level Gain",
"Level Loss",
"Loot Item",
"Merchant Purchase",
"Merchant Sell",
"Group Join (Unimplemented)",
"Group Leave (Unimplemented)",
"Raid Join (Unimplemented)",
"Raid Leave (Unimplemented)",
"Groundspawn Pickup",
"NPC Handin",
"Skill Up",
"Task Accept",
"Task Update",
"Task Complete",
"Trade",
"Given Item (Unimplemented)",
"Say",
"Rez Accepted",
"Death",
"Combine Failure",
"Combine Success",
"Dropped Item",
"Split Money",
"DZ Join (Unimplemented)",
"DZ Leave (Unimplemented)",
"Trader Purchase",
"Trader Sell",
"Bandolier Create (Unimplemented)",
"Bandolier Swap (Unimplemented)",
"Discover Item",
"Possible Hack",
"Killed NPC",
"Killed Named NPC",
"Killed Raid NPC",
"Item Creation"
};
// Generic struct used by all events
struct PlayerEvent {
int64 account_id;
std::string account_name;
int64 character_id;
std::string character_name;
int64 guild_id;
std::string guild_name;
int zone_id;
std::string zone_short_name;
std::string zone_long_name;
int instance_id;
float x;
float y;
float z;
float heading;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(account_id),
CEREAL_NVP(account_name),
CEREAL_NVP(character_id),
CEREAL_NVP(character_name),
CEREAL_NVP(guild_id),
CEREAL_NVP(guild_name),
CEREAL_NVP(zone_id),
CEREAL_NVP(zone_short_name),
CEREAL_NVP(zone_long_name),
CEREAL_NVP(instance_id),
CEREAL_NVP(x),
CEREAL_NVP(y),
CEREAL_NVP(z),
CEREAL_NVP(heading)
);
}
};
// contains metadata in use for things like log/discord formatters
// along with the actual event to be persisted
struct PlayerEventContainer {
PlayerEvent player_event;
PlayerEventLogsRepository::PlayerEventLogs player_event_log;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(player_event),
CEREAL_NVP(player_event_log)
);
}
};
// used in events with no extra data
struct EmptyEvent {
std::string noop; // noop, gets discard upstream
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(noop)
);
}
};
// used in Trade event
struct ItemCreationEvent {
int64 item_id;
std::string item_name;
uint16 to_slot;
int16 charges;
uint32 aug1;
uint32 aug2;
uint32 aug3;
uint32 aug4;
uint32 aug5;
uint32 aug6;
bool attuned;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(to_slot),
CEREAL_NVP(charges),
CEREAL_NVP(aug1),
CEREAL_NVP(aug2),
CEREAL_NVP(aug3),
CEREAL_NVP(aug4),
CEREAL_NVP(aug5),
CEREAL_NVP(aug6),
CEREAL_NVP(attuned)
);
}
};
// used in Trade event
struct TradeItem {
int64 item_id;
std::string item_name;
int32 slot;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(slot)
);
}
};
// used in Trade event
class TradeItemEntry {
public:
uint16 slot;
uint32 item_id;
std::string item_name;
uint16 charges;
uint32 aug_1_item_id;
std::string aug_1_item_name;
uint32 aug_2_item_id;
std::string aug_2_item_name;
uint32 aug_3_item_id;
std::string aug_3_item_name;
uint32 aug_4_item_id;
std::string aug_4_item_name;
uint32 aug_5_item_id;
std::string aug_5_item_name;
uint32 aug_6_item_id;
std::string aug_6_item_name;
bool in_bag;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(slot),
CEREAL_NVP(item_id),
CEREAL_NVP(charges),
CEREAL_NVP(aug_1_item_id),
CEREAL_NVP(aug_2_item_id),
CEREAL_NVP(aug_3_item_id),
CEREAL_NVP(aug_4_item_id),
CEREAL_NVP(aug_5_item_id),
CEREAL_NVP(in_bag)
);
}
};
/**
* Events
*/
struct Money {
int32 platinum;
int32 gold;
int32 silver;
int32 copper;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(platinum),
CEREAL_NVP(gold),
CEREAL_NVP(silver),
CEREAL_NVP(copper)
);
}
};
struct TradeEvent {
uint32 character_1_id;
std::string character_1_name;
uint32 character_2_id;
std::string character_2_name;
Money character_1_give_money;
Money character_2_give_money;
std::vector<TradeItemEntry> character_1_give_items;
std::vector<TradeItemEntry> character_2_give_items;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(character_1_id),
CEREAL_NVP(character_1_name),
CEREAL_NVP(character_2_id),
CEREAL_NVP(character_2_name),
CEREAL_NVP(character_1_give_money),
CEREAL_NVP(character_2_give_money),
CEREAL_NVP(character_1_give_items),
CEREAL_NVP(character_2_give_items)
);
}
};
struct GMCommandEvent {
std::string message;
std::string target;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(message),
CEREAL_NVP(target)
);
}
};
struct ZoningEvent {
std::string from_zone_long_name;
std::string from_zone_short_name;
int32 from_zone_id;
int32 from_instance_id;
int32 from_instance_version;
std::string to_zone_long_name;
std::string to_zone_short_name;
int32 to_zone_id;
int32 to_instance_id;
int32 to_instance_version;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(from_zone_long_name),
CEREAL_NVP(from_zone_short_name),
CEREAL_NVP(from_zone_id),
CEREAL_NVP(from_instance_id),
CEREAL_NVP(from_instance_version),
CEREAL_NVP(to_zone_long_name),
CEREAL_NVP(to_zone_short_name),
CEREAL_NVP(to_zone_id),
CEREAL_NVP(to_instance_id),
CEREAL_NVP(to_instance_version)
);
}
};
struct AAGainedEvent {
uint32 aa_gained;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(CEREAL_NVP(aa_gained));
}
};
struct AAPurchasedEvent {
uint32 aa_id;
int32 aa_cost;
int32 aa_previous_id;
int32 aa_next_id;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(aa_id),
CEREAL_NVP(aa_cost),
CEREAL_NVP(aa_previous_id),
CEREAL_NVP(aa_next_id)
);
}
};
struct ForageSuccessEvent {
uint32 item_id;
std::string item_name;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name)
);
}
};
struct FishSuccessEvent {
uint32 item_id;
std::string item_name;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name)
);
}
};
struct DestroyItemEvent {
uint32 item_id;
std::string item_name;
int16 charges;
std::string reason;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(reason),
CEREAL_NVP(charges)
);
}
};
struct LevelGainedEvent {
uint32 from_level;
uint8 to_level;
int levels_gained;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(from_level),
CEREAL_NVP(to_level),
CEREAL_NVP(levels_gained)
);
}
};
struct LevelLostEvent {
uint32 from_level;
uint8 to_level;
int levels_lost;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(from_level),
CEREAL_NVP(to_level),
CEREAL_NVP(levels_lost)
);
}
};
struct LootItemEvent {
uint32 item_id;
std::string item_name;
int16 charges;
uint32 npc_id;
std::string corpse_name;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(charges),
CEREAL_NVP(npc_id),
CEREAL_NVP(corpse_name)
);
}
};
struct MerchantPurchaseEvent {
uint32 npc_id;
std::string merchant_name;
uint32 merchant_type;
uint32 item_id;
std::string item_name;
int16 charges;
uint32 cost;
uint32 alternate_currency_id;
uint64 player_money_balance;
uint64 player_currency_balance;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(npc_id),
CEREAL_NVP(merchant_name),
CEREAL_NVP(merchant_type),
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(charges),
CEREAL_NVP(cost),
CEREAL_NVP(alternate_currency_id),
CEREAL_NVP(player_money_balance),
CEREAL_NVP(player_currency_balance)
);
}
};
struct MerchantSellEvent {
uint32 npc_id;
std::string merchant_name;
uint32 merchant_type;
uint32 item_id;
std::string item_name;
int16 charges;
uint32 cost;
uint32 alternate_currency_id;
uint64 player_money_balance;
uint64 player_currency_balance;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(npc_id),
CEREAL_NVP(merchant_name),
CEREAL_NVP(merchant_type),
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(charges),
CEREAL_NVP(cost),
CEREAL_NVP(alternate_currency_id),
CEREAL_NVP(player_money_balance),
CEREAL_NVP(player_currency_balance)
);
}
};
struct SkillUpEvent {
uint32 skill_id;
int value;
int16 max_skill;
std::string against_who;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(skill_id),
CEREAL_NVP(value),
CEREAL_NVP(max_skill),
CEREAL_NVP(against_who)
);
}
};
struct TaskAcceptEvent {
uint32 npc_id;
std::string npc_name;
uint32 task_id;
std::string task_name;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(npc_id),
CEREAL_NVP(npc_name),
CEREAL_NVP(task_id),
CEREAL_NVP(task_name)
);
}
};
struct TaskUpdateEvent {
uint32 task_id;
std::string task_name;
uint32 activity_id;
uint32 done_count;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(task_id),
CEREAL_NVP(task_name),
CEREAL_NVP(activity_id),
CEREAL_NVP(done_count)
);
}
};
struct TaskCompleteEvent {
uint32 task_id;
std::string task_name;
uint32 activity_id;
uint32 done_count;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(task_id),
CEREAL_NVP(task_name),
CEREAL_NVP(activity_id),
CEREAL_NVP(done_count)
);
}
};
struct GroundSpawnPickupEvent {
uint32 item_id;
std::string item_name;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name)
);
}
};
struct SayEvent {
std::string message;
std::string target;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(message),
CEREAL_NVP(target)
);
}
};
struct ResurrectAcceptEvent {
std::string resurrecter_name;
std::string spell_name;
uint32 spell_id;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(resurrecter_name),
CEREAL_NVP(spell_name),
CEREAL_NVP(spell_id)
);
}
};
struct CombineEvent {
uint32 recipe_id;
std::string recipe_name;
uint32 made_count;
uint32 tradeskill_id;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(recipe_id),
CEREAL_NVP(recipe_name),
CEREAL_NVP(made_count),
CEREAL_NVP(tradeskill_id)
);
}
};
struct DroppedItemEvent {
uint32 item_id;
std::string item_name;
int16 slot_id;
uint32 charges;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(slot_id),
CEREAL_NVP(charges)
);
}
};
struct DeathEvent {
uint32 killer_id;
std::string killer_name;
int64 damage;
uint32 spell_id;
std::string spell_name;
int skill_id;
std::string skill_name;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(killer_id),
CEREAL_NVP(killer_name),
CEREAL_NVP(damage),
CEREAL_NVP(spell_id),
CEREAL_NVP(spell_name),
CEREAL_NVP(skill_id),
CEREAL_NVP(skill_name)
);
}
};
struct SplitMoneyEvent {
uint32 copper;
uint32 silver;
uint32 gold;
uint32 platinum;
uint64 player_money_balance;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(copper),
CEREAL_NVP(silver),
CEREAL_NVP(gold),
CEREAL_NVP(platinum),
CEREAL_NVP(player_money_balance)
);
}
};
struct TraderPurchaseEvent {
uint32 item_id;
std::string item_name;
uint32 trader_id;
std::string trader_name;
uint32 price;
uint32 charges;
uint32 total_cost;
uint64 player_money_balance;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(trader_id),
CEREAL_NVP(trader_name),
CEREAL_NVP(price),
CEREAL_NVP(charges),
CEREAL_NVP(total_cost),
CEREAL_NVP(player_money_balance)
);
}
};
struct TraderSellEvent {
uint32 item_id;
std::string item_name;
uint32 buyer_id;
std::string buyer_name;
uint32 price;
uint32 charges;
uint32 total_cost;
uint64 player_money_balance;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(buyer_id),
CEREAL_NVP(buyer_name),
CEREAL_NVP(price),
CEREAL_NVP(charges),
CEREAL_NVP(total_cost),
CEREAL_NVP(player_money_balance)
);
}
};
struct DiscoverItemEvent {
uint32 item_id;
std::string item_name;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name)
);
}
};
class HandinEntry {
public:
uint32 item_id;
std::string item_name;
uint16 charges;
bool attuned;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(charges),
CEREAL_NVP(attuned)
);
}
};
class HandinMoney {
public:
uint32 copper;
uint32 silver;
uint32 gold;
uint32 platinum;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(copper),
CEREAL_NVP(silver),
CEREAL_NVP(gold),
CEREAL_NVP(platinum)
);
}
};
struct HandinEvent {
uint32 npc_id;
std::string npc_name;
std::vector<HandinEntry> handin_items;
HandinMoney handin_money;
std::vector<HandinEntry> return_items;
HandinMoney return_money;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(npc_id),
CEREAL_NVP(npc_name),
CEREAL_NVP(handin_items),
CEREAL_NVP(handin_money),
CEREAL_NVP(return_items),
CEREAL_NVP(return_money)
);
}
};
struct PossibleHackEvent {
std::string message;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(message)
);
}
};
struct KilledNPCEvent {
uint32 npc_id;
std::string npc_name;
uint32 combat_time_seconds;
uint64 total_damage_per_second_taken;
uint64 total_heal_per_second_taken;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(npc_id),
CEREAL_NVP(npc_name),
CEREAL_NVP(combat_time_seconds),
CEREAL_NVP(total_damage_per_second_taken),
CEREAL_NVP(total_heal_per_second_taken)
);
}
};
}
#endif //EQEMU_PLAYER_EVENTS_H
#define RecordPlayerEventLog(event_type, event_data) do {\
if (player_event_logs.IsEventEnabled(event_type)) {\
worldserver.SendPacket(\
player_event_logs.RecordEvent(\
event_type,\
GetPlayerEvent(),\
event_data\
).get()\
);\
}\
} while (0)
#define RecordPlayerEventLogWithClient(c, event_type, event_data) do {\
if (player_event_logs.IsEventEnabled(event_type)) {\
worldserver.SendPacket(\
player_event_logs.RecordEvent(\
event_type,\
(c)->GetPlayerEvent(),\
event_data\
).get()\
);\
}\
} while (0)
+1 -1
View File
@@ -19,7 +19,7 @@
*/ */
#include "expedition_lockout_timer.h" #include "expedition_lockout_timer.h"
#include "../common/strings.h" #include "../common/string_util.h"
#include "../common/rulesys.h" #include "../common/rulesys.h"
#include "../common/util/uuid.h" #include "../common/util/uuid.h"
#include <fmt/format.h> #include <fmt/format.h>
+2 -2
View File
@@ -96,12 +96,12 @@ bool IsOfEqualRace(int r1, int r2)
// TODO: add more values // TODO: add more values
switch (r1) { switch (r1) {
case DARK_ELF: case DARK_ELF:
if (r2 == RACE_NERIAK_CITIZEN_77) { if (r2 == 77) {
return true; return true;
} }
break; break;
case BARBARIAN: case BARBARIAN:
if (r2 == RACE_HALAS_CITIZEN_90) { if (r2 == 90) {
return true; return true;
} }
} }
-17
View File
@@ -75,23 +75,6 @@ struct NPCFaction
uint8 temp; uint8 temp;
}; };
// Faction Associations give a much more live like faction system
// Basically the primary faction and magnitude of a faction hit will generate the rest of them
// Largest faction I could find quickly was Lord Inquisitor Seru with 9 total hits (8 associations) so 8 + 2 for max for now
#define MAX_FACTION_ASSOC 10
// this is the ID of a faction association and it's multiplier
struct FactionAssociationHit {
int id;
float multiplier;
};
struct FactionAssociations {
// maybe there should be more data here, fine for now
FactionAssociationHit hits[MAX_FACTION_ASSOC];
};
const char *FactionValueToString(FACTION_VALUE faction_value); const char *FactionValueToString(FACTION_VALUE faction_value);
FACTION_VALUE CalculateFaction(FactionMods* fm, int32 tmpCharacter_value); FACTION_VALUE CalculateFaction(FactionMods* fm, int32 tmpCharacter_value);
#endif #endif
+4 -4
View File
@@ -132,7 +132,7 @@ enum { //reuse times
InstillDoubtReuseTime = 9, InstillDoubtReuseTime = 9,
FishingReuseTime = 11, FishingReuseTime = 11,
ForagingReuseTime = 50, ForagingReuseTime = 50,
MendReuseTime = 360, MendReuseTime = 290,
BashReuseTime = 5, BashReuseTime = 5,
BackstabReuseTime = 9, BackstabReuseTime = 9,
KickReuseTime = 5, KickReuseTime = 5,
@@ -218,14 +218,14 @@ enum { //some random constants
#define HARD_LEVEL_CAP 127 #define HARD_LEVEL_CAP 127
//the square of the maximum range at whihc you could possibly use NPC services (shop, tribute, etc) //the square of the maximum range at whihc you could possibly use NPC services (shop, tribute, etc)
#define USE_NPC_RANGE2 40000 //arbitrary right now #define USE_NPC_RANGE2 200*200 //arbitrary right now
// Squared range for rampage 75.0 * 75.0 for now // Squared range for rampage 75.0 * 75.0 for now
#define NPC_RAMPAGE_RANGE2 5625.0f #define NPC_RAMPAGE_RANGE2 5625.0f
//the formula for experience for killing a mob. //the formula for experience for killing a mob.
//level is the only valid variable to use //level is the only valid variable to use
#define EXP_FORMULA (level * level * 75 * 35 / 10) #define EXP_FORMULA level*level*75*35/10
#define HIGHEST_AA_VALUE 35 #define HIGHEST_AA_VALUE 35
@@ -295,7 +295,7 @@ Developer configuration
#define COMMON_PROFILE #define COMMON_PROFILE
#define PROFILE_DUMP_TIME 180 #define PROFILE_DUMP_TIME 3*60
#endif //EQPROFILE #endif //EQPROFILE
-106
View File
@@ -1,106 +0,0 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY except by those people which sell it, which
* are required to give you total support for your newly bought product;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <fstream>
#include "file.h"
#ifdef _WINDOWS
#include <direct.h>
#include <conio.h>
#include <iostream>
#include <dos.h>
#include <windows.h>
#include <process.h>
#else
#include <unistd.h>
#include <sys/stat.h>
#endif
#include <fmt/format.h>
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
/**
* @param name
* @return
*/
bool File::Exists(const std::string &name)
{
return fs::exists(fs::path{name});
}
/**
* @param directory_name
*/
void File::Makedir(const std::string &directory_name)
{
fs::create_directory(directory_name);
fs::permissions(directory_name, fs::perms::owner_all);
}
std::string File::FindEqemuConfigPath()
{
if (File::Exists(fs::path{File::GetCwd() + "/eqemu_config.json"}.string())) {
return File::GetCwd();
}
else if (File::Exists(fs::path{File::GetCwd() + "/../eqemu_config.json"}.string())) {
return canonical(fs::path{File::GetCwd() + "/../"}).string();
}
else if (File::Exists(fs::path{File::GetCwd() + "/login.json"}.string())) {
return File::GetCwd();
}
else if (File::Exists(fs::path{File::GetCwd() + "/../login.json"}.string())) {
return canonical(fs::path{File::GetCwd() + "/../"}).string();
}
return {};
}
std::string File::GetCwd()
{
return fs::current_path().string();
}
FileContentsResult File::GetContents(const std::string &file_name)
{
std::string error;
std::ifstream f;
f.open(file_name);
std::string line;
std::string lines;
if (f.is_open()) {
while (f) {
std::getline(f, line);
lines += line + "\n";
}
}
else {
error = fmt::format("Couldn't open file [{}]", file_name);
}
return FileContentsResult{
.contents = lines,
.error = error,
};
}
+72
View File
@@ -0,0 +1,72 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY except by those people which sell it, which
* are required to give you total support for your newly bought product;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <fstream>
#include "file_util.h"
#ifdef _WINDOWS
#include <direct.h>
#include <conio.h>
#include <iostream>
#include <dos.h>
#include <windows.h>
#include <process.h>
#else
#include <unistd.h>
#include <sys/stat.h>
#endif
/**
* @param name
* @return
*/
bool FileUtil::exists(const std::string &name)
{
std::ifstream f(name.c_str());
return f.good();
}
/**
* @param directory_name
*/
void FileUtil::mkdir(const std::string& directory_name)
{
#ifdef _WINDOWS
struct _stat st;
if (_stat(directory_name.c_str(), &st) == 0) // exists
return;
_mkdir(directory_name.c_str());
#else
struct stat st{};
if (stat(directory_name.c_str(), &st) == 0) { // exists
return;
}
::mkdir(directory_name.c_str(), 0755);
#endif
}
bool file_exists(const std::string& name) {
std::ifstream f(name.c_str());
return f.good();
}
+7 -18
View File
@@ -18,27 +18,16 @@
* *
*/ */
#ifndef EQEMU_FILE_H #ifndef EQEMU_FILE_UTIL_H
#define EQEMU_FILE_H #define EQEMU_FILE_UTIL_H
#include <filesystem>
namespace fs = std::filesystem; class FileUtil {
struct FileContentsResult {
std::string contents;
std::string error;
};
class File {
public: public:
static bool Exists(const std::string &name); static bool exists(const std::string &name);
static void Makedir(const std::string& directory_name); static void mkdir(const std::string& directory_name);
static FileContentsResult GetContents(const std::string &file_name);
static std::string FindEqemuConfigPath();
static std::string GetCwd();
}; };
bool Exists(const std::string& name); bool file_exists(const std::string& name);
#endif //EQEMU_FILE_H #endif //EQEMU_FILE_UTIL_H
+39 -23
View File
@@ -20,7 +20,7 @@
#include "database.h" #include "database.h"
//#include "misc_functions.h" //#include "misc_functions.h"
#include "strings.h" #include "string_util.h"
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
@@ -61,11 +61,9 @@ bool BaseGuildManager::LoadGuilds() {
} }
for (auto row=results.begin();row!=results.end();++row) for (auto row=results.begin();row!=results.end();++row)
_CreateGuild(Strings::ToUnsignedInt(row[0]), row[1], Strings::ToUnsignedInt(row[2]), Strings::ToUnsignedInt(row[3]), row[4], row[5], row[6], row[7]); _CreateGuild(atoi(row[0]), row[1], atoi(row[2]), atoi(row[3]), row[4], row[5], row[6], row[7]);
LogInfo("Loaded [{}] Guilds", Strings::Commify(std::to_string(results.RowCount()))); query = "SELECT guild_id,`rank`,title,can_hear,can_speak,can_invite,can_remove,can_promote,can_demote,can_motd,can_warpeace FROM guild_ranks";
query = "SELECT guild_id,`rank`,title,can_hear,can_speak,can_invite,can_remove,can_promote,can_demote,can_motd,can_warpeace FROM guild_ranks";
results = m_db->QueryDatabase(query); results = m_db->QueryDatabase(query);
if (!results.Success()) if (!results.Success())
@@ -75,8 +73,8 @@ bool BaseGuildManager::LoadGuilds() {
for (auto row=results.begin();row!=results.end();++row) for (auto row=results.begin();row!=results.end();++row)
{ {
uint32 guild_id = Strings::ToUnsignedInt(row[0]); uint32 guild_id = atoi(row[0]);
uint8 rankn = Strings::ToUnsignedInt(row[1]); uint8 rankn = atoi(row[1]);
if(rankn > GUILD_MAX_RANK) { if(rankn > GUILD_MAX_RANK) {
LogGuilds("Found invalid (too high) rank [{}] for guild [{}], skipping", rankn, guild_id); LogGuilds("Found invalid (too high) rank [{}] for guild [{}], skipping", rankn, guild_id);
@@ -131,7 +129,7 @@ bool BaseGuildManager::RefreshGuild(uint32 guild_id) {
auto row = results.begin(); auto row = results.begin();
info = _CreateGuild(guild_id, row[0], Strings::ToUnsignedInt(row[1]), Strings::ToUnsignedInt(row[2]), row[3], row[4], row[5], row[6]); info = _CreateGuild(guild_id, row[0], atoi(row[1]), atoi(row[2]), row[3], row[4], row[5], row[6]);
query = StringFormat("SELECT guild_id, `rank`, title, can_hear, can_speak, can_invite, can_remove, can_promote, can_demote, can_motd, can_warpeace " query = StringFormat("SELECT guild_id, `rank`, title, can_hear, can_speak, can_invite, can_remove, can_promote, can_demote, can_motd, can_warpeace "
"FROM guild_ranks WHERE guild_id=%lu", (unsigned long)guild_id); "FROM guild_ranks WHERE guild_id=%lu", (unsigned long)guild_id);
@@ -144,7 +142,7 @@ bool BaseGuildManager::RefreshGuild(uint32 guild_id) {
for (auto row=results.begin();row!=results.end();++row) for (auto row=results.begin();row!=results.end();++row)
{ {
uint8 rankn = Strings::ToUnsignedInt(row[1]); uint8 rankn = atoi(row[1]);
if(rankn > GUILD_MAX_RANK) { if(rankn > GUILD_MAX_RANK) {
LogGuilds("Found invalid (too high) rank [{}] for guild [{}], skipping", rankn, guild_id); LogGuilds("Found invalid (too high) rank [{}] for guild [{}], skipping", rankn, guild_id);
@@ -787,7 +785,9 @@ bool BaseGuildManager::GetBankerFlag(uint32 CharID)
auto row = results.begin(); auto row = results.begin();
return Strings::ToBool(row[0]); bool IsBanker = atoi(row[0]);
return IsBanker;
} }
bool BaseGuildManager::DBSetAltFlag(uint32 charid, bool is_alt) bool BaseGuildManager::DBSetAltFlag(uint32 charid, bool is_alt)
@@ -815,7 +815,9 @@ bool BaseGuildManager::GetAltFlag(uint32 CharID)
auto row = results.begin(); auto row = results.begin();
return Strings::ToBool(row[0]); bool IsAlt = atoi(row[0]);
return IsAlt;
} }
bool BaseGuildManager::DBSetTributeFlag(uint32 charid, bool enabled) { bool BaseGuildManager::DBSetTributeFlag(uint32 charid, bool enabled) {
@@ -862,26 +864,35 @@ bool BaseGuildManager::QueryWithLogging(std::string query, const char *errmsg) {
return(true); return(true);
} }
//factored out so I dont have to copy this crap.
#ifdef BOTS
#define GuildMemberBaseQuery \
"SELECT c.`id`, c.`name`, c.`class`, c.`level`, c.`last_login`, c.`zone_id`," \
" g.`guild_id`, g.`rank`, g.`tribute_enable`, g.`total_tribute`, g.`last_tribute`," \
" g.`banker`, g.`public_note`, g.`alt`" \
" FROM `vw_bot_character_mobs` AS c LEFT JOIN `vw_guild_members` AS g ON c.`id` = g.`char_id` AND c.`mob_type` = g.`mob_type` "
#else
#define GuildMemberBaseQuery \ #define GuildMemberBaseQuery \
"SELECT c.`id`, c.`name`, c.`class`, c.`level`, c.`last_login`, c.`zone_id`," \ "SELECT c.`id`, c.`name`, c.`class`, c.`level`, c.`last_login`, c.`zone_id`," \
" g.`guild_id`, g.`rank`, g.`tribute_enable`, g.`total_tribute`, g.`last_tribute`," \ " g.`guild_id`, g.`rank`, g.`tribute_enable`, g.`total_tribute`, g.`last_tribute`," \
" g.`banker`, g.`public_note`, g.`alt` " \ " g.`banker`, g.`public_note`, g.`alt` " \
" FROM `character_data` AS c LEFT JOIN `guild_members` AS g ON c.`id` = g.`char_id` " " FROM `character_data` AS c LEFT JOIN `guild_members` AS g ON c.`id` = g.`char_id` "
#endif
static void ProcessGuildMember(MySQLRequestRow row, CharGuildInfo &into) { static void ProcessGuildMember(MySQLRequestRow row, CharGuildInfo &into) {
//fields from `characer_` //fields from `characer_`
into.char_id = Strings::ToUnsignedInt(row[0]); into.char_id = atoi(row[0]);
into.char_name = row[1]; into.char_name = row[1];
into.class_ = Strings::ToUnsignedInt(row[2]); into.class_ = atoi(row[2]);
into.level = Strings::ToUnsignedInt(row[3]); into.level = atoi(row[3]);
into.time_last_on = Strings::ToUnsignedInt(row[4]); into.time_last_on = atoul(row[4]);
into.zone_id = Strings::ToUnsignedInt(row[5]); into.zone_id = atoi(row[5]);
//fields from `guild_members`, leave at defaults if missing //fields from `guild_members`, leave at defaults if missing
into.guild_id = row[6] ? Strings::ToUnsignedInt(row[6]) : GUILD_NONE; into.guild_id = row[6] ? atoi(row[6]) : GUILD_NONE;
into.rank = row[7] ? Strings::ToUnsignedInt(row[7]) : (GUILD_MAX_RANK+1); into.rank = row[7] ? atoi(row[7]) : (GUILD_MAX_RANK+1);
into.tribute_enable = row[8] ? (row[8][0] == '0'?false:true) : false; into.tribute_enable = row[8] ? (row[8][0] == '0'?false:true) : false;
into.total_tribute = row[9] ? Strings::ToUnsignedInt(row[9]) : 0; into.total_tribute = row[9] ? atoi(row[9]) : 0;
into.last_tribute = row[10]? Strings::ToUnsignedInt(row[10]) : 0; //timestamp into.last_tribute = row[10]? atoul(row[10]) : 0; //timestamp
into.banker = row[11]? (row[11][0] == '0'?false:true) : false; into.banker = row[11]? (row[11][0] == '0'?false:true) : false;
into.public_note = row[12]? row[12] : ""; into.public_note = row[12]? row[12] : "";
into.alt = row[13]? (row[13][0] == '0'?false:true) : false; into.alt = row[13]? (row[13][0] == '0'?false:true) : false;
@@ -956,8 +967,13 @@ bool BaseGuildManager::GetCharInfo(uint32 char_id, CharGuildInfo &into) {
} }
//load up the rank info for each guild. //load up the rank info for each guild.
std::string query = StringFormat(GuildMemberBaseQuery " WHERE c.id=%d AND c.deleted_at IS NULL", char_id); std::string query;
auto results = m_db->QueryDatabase(query); #ifdef BOTS
query = StringFormat(GuildMemberBaseQuery " WHERE c.id=%d AND c.mob_type = 'C' AND c.deleted_at IS NULL", char_id);
#else
query = StringFormat(GuildMemberBaseQuery " WHERE c.id=%d AND c.deleted_at IS NULL", char_id);
#endif
auto results = m_db->QueryDatabase(query);
if (!results.Success()) { if (!results.Success()) {
return false; return false;
} }
@@ -1254,7 +1270,7 @@ uint32 BaseGuildManager::GetGuildIDByCharacterID(uint32 character_id)
} }
auto row = results.begin(); auto row = results.begin();
auto guild_id = Strings::ToUnsignedInt(row[0]); auto guild_id = std::stoul(row[0]);
return guild_id; return guild_id;
} }
+2119 -2844
View File
File diff suppressed because it is too large Load Diff
+6 -21
View File
@@ -25,7 +25,7 @@
//#include "races.h" //#include "races.h"
//#include "rulesys.h" //#include "rulesys.h"
//#include "shareddb.h" //#include "shareddb.h"
#include "strings.h" #include "string_util.h"
#include "../common/light_source.h" #include "../common/light_source.h"
@@ -412,12 +412,11 @@ bool EQ::InventoryProfile::DeleteItem(int16 slot_id, int16 quantity) {
// If there are no charges left on the item, // If there are no charges left on the item,
if (item_to_delete->GetCharges() <= 0) { if (item_to_delete->GetCharges() <= 0) {
// If the item is stackable (e.g arrows), or // If the item is stackable (e.g arrows), or
// the item is not a charged item, or is expendable, delete it // the item is not stackable, and is not a charged item, or is expendable, delete it
if ( if (item_to_delete->IsStackable() ||
item_to_delete->IsStackable() || (!item_to_delete->IsStackable() &&
item_to_delete->GetItem()->MaxCharges == 0 || ((item_to_delete->GetItem()->MaxCharges == 0) || item_to_delete->IsExpendable()))
item_to_delete->IsExpendable() ) {
) {
// Item can now be destroyed // Item can now be destroyed
InventoryProfile::MarkDirty(item_to_delete); InventoryProfile::MarkDirty(item_to_delete);
return true; return true;
@@ -1719,17 +1718,3 @@ int16 EQ::InventoryProfile::_HasItemByLoreGroup(ItemInstQueue& iqueue, uint32 lo
return EQ::invslot::SLOT_INVALID; return EQ::invslot::SLOT_INVALID;
} }
std::vector<uint32> EQ::InventoryProfile::GetAugmentIDsBySlotID(int16 slot_id)
{
std::vector<uint32> augments;
const auto* item = GetItem(slot_id);
if (item) {
for (uint8 i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; i++) {
augments.push_back(item->GetAugment(i) ? item->GetAugmentItemID(i) : 0);
}
}
return augments;
}
+7 -13
View File
@@ -26,11 +26,8 @@
#include "item_instance.h" #include "item_instance.h"
#include "classes.h"
#include "races.h"
#include <list> #include <list>
#include <vector>
//FatherNitwit: location bits for searching specific //FatherNitwit: location bits for searching specific
@@ -132,7 +129,7 @@ namespace EQ
// Swap items in inventory // Swap items in inventory
enum SwapItemFailState : int8 { swapInvalid = -1, swapPass = 0, swapNotAllowed, swapNullData, swapRaceClass, swapDeity, swapLevel }; enum SwapItemFailState : int8 { swapInvalid = -1, swapPass = 0, swapNotAllowed, swapNullData, swapRaceClass, swapDeity, swapLevel };
bool SwapItem(int16 source_slot, int16 destination_slot, SwapItemFailState& fail_state, uint16 race_id = RACE_DOUG_0, uint8 class_id = NO_CLASS, uint16 deity_id = deity::DeityType::DeityUnknown, uint8 level = 0); bool SwapItem(int16 source_slot, int16 destination_slot, SwapItemFailState& fail_state, uint16 race_id = 0, uint8 class_id = 0, uint16 deity_id = 0, uint8 level = 0);
// Remove item from inventory // Remove item from inventory
bool DeleteItem(int16 slot_id, int16 quantity = 0); bool DeleteItem(int16 slot_id, int16 quantity = 0);
@@ -155,9 +152,6 @@ namespace EQ
// Check how many of a specific augment the player has equipped by Item ID // Check how many of a specific augment the player has equipped by Item ID
int CountAugmentEquippedByID(uint32 item_id); int CountAugmentEquippedByID(uint32 item_id);
// Get a list of augments from a specific slot ID
std::vector<uint32> GetAugmentIDsBySlotID(int16 slot_id);
// Check whether there is space for the specified number of the specified item. // Check whether there is space for the specified number of the specified item.
bool HasSpaceForItem(const ItemData *ItemToTry, int16 Quantity); bool HasSpaceForItem(const ItemData *ItemToTry, int16 Quantity);
@@ -203,12 +197,12 @@ namespace EQ
void dumpBankItems(); void dumpBankItems();
void dumpSharedBankItems(); void dumpSharedBankItems();
void SetCustomItemData(uint32 character_id, int16 slot_id, const std::string &identifier, const std::string& value); void SetCustomItemData(uint32 character_id, int16 slot_id, std::string identifier, std::string value);
void SetCustomItemData(uint32 character_id, int16 slot_id, const std::string &identifier, int value); void SetCustomItemData(uint32 character_id, int16 slot_id, std::string identifier, int value);
void SetCustomItemData(uint32 character_id, int16 slot_id, const std::string &identifier, float value); void SetCustomItemData(uint32 character_id, int16 slot_id, std::string identifier, float value);
void SetCustomItemData(uint32 character_id, int16 slot_id, const std::string &identifier, bool value); void SetCustomItemData(uint32 character_id, int16 slot_id, std::string identifier, bool value);
std::string GetCustomItemData(int16 slot_id, const std::string& identifier); std::string GetCustomItemData(int16 slot_id, std::string identifier);
static const int GetItemStatValue(uint32 item_id, const std::string& identifier); static int GetItemStatValue(uint32 item_id, const char* identifier);
protected: protected:
/////////////////////////////// ///////////////////////////////
// Protected Methods // Protected Methods
+1 -1
View File
@@ -19,7 +19,7 @@
#include "inventory_slot.h" #include "inventory_slot.h"
#include "textures.h" #include "textures.h"
#include "strings.h" #include "string_util.h"
int8 EQ::inventory::ConvertEquipmentIndexToTextureIndex(int16 slot_index) int8 EQ::inventory::ConvertEquipmentIndexToTextureIndex(int16 slot_index)
-155
View File
@@ -18,17 +18,7 @@
* *
*/ */
#include <cstring>
#include <fmt/format.h>
#include <csignal>
#include <vector>
#include "ip_util.h" #include "ip_util.h"
#include "http/httplib.h"
#include "http/uri.h"
#include "eqemu_logsys.h"
#include "event/event_loop.h"
#include "net/dns.h"
#include "event/task_scheduler.h"
/** /**
* @param ip * @param ip
@@ -80,148 +70,3 @@ bool IpUtil::IsIpInPrivateRfc1918(const std::string &ip)
IpUtil::IsIpInRange(ip, "192.168.0.0", "255.255.0.0") IpUtil::IsIpInRange(ip, "192.168.0.0", "255.255.0.0")
); );
} }
/**
* Gets local address - pings google to inspect what interface was used locally
* @return
*/
std::string IpUtil::GetLocalIPAddress()
{
char my_ip_address[16];
unsigned int my_port;
struct sockaddr_in server_address{};
struct sockaddr_in my_address{};
int sockfd;
// Connect to server
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
return "";
}
// Set server_addr
memset(&server_address, 0, sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = inet_addr("172.217.160.99");
server_address.sin_port = htons(80);
// Connect to server
if (connect(sockfd, (struct sockaddr *) &server_address, sizeof(server_address)) < 0) {
close(sockfd);
return "";
}
// Get my ip address and port
memset(&my_address, 0, sizeof(my_address));
socklen_t len = sizeof(my_address);
getsockname(sockfd, (struct sockaddr *) &my_address, &len);
inet_ntop(AF_INET, &my_address.sin_addr, my_ip_address, sizeof(my_ip_address));
my_port = ntohs(my_address.sin_port);
return fmt::format("{}", my_ip_address);
}
/**
* Gets public address
* Uses various websites as options to return raw public IP back to the client
* @return
*/
std::string IpUtil::GetPublicIPAddress()
{
std::vector<std::string> endpoints = {
"http://ifconfig.me",
"http://api.ipify.org",
"http://ipinfo.io/ip",
"http://ipecho.net/plain",
};
for (auto &s: endpoints) {
// http get request
uri u(s);
httplib::Client r(
fmt::format(
"{}://{}",
u.get_scheme(),
u.get_host()
).c_str()
);
httplib::Headers headers = {
{"Content-type", "text/plain; charset=utf-8"},
{"User-Agent", "curl/7.81.0"}
};
r.set_connection_timeout(1, 0);
r.set_read_timeout(1, 0);
r.set_write_timeout(1, 0);
if (auto res = r.Get(fmt::format("/{}", u.get_path()).c_str(), headers)) {
if (res->status == 200) {
if (res->body.find('.') != std::string::npos) {
return res->body;
}
}
}
}
return {};
}
std::string IpUtil::DNSLookupSync(const std::string &addr, int port)
{
auto task_runner = new EQ::Event::TaskScheduler();
auto res = task_runner->Enqueue(
[&]() -> std::string {
bool running = true;
std::string ret;
EQ::Net::DNSLookup(
addr, port, false, [&](const std::string &addr) {
ret = addr;
if (addr.empty()) {
ret = "";
running = false;
}
return ret;
}
);
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
auto &loop = EQ::EventLoop::Get();
while (running) {
if (!ret.empty()) {
running = false;
}
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
if (std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count() > 1500) {
LogInfo(
"Deadline exceeded [{}]",
1500
);
running = false;
}
loop.Process();
}
return ret;
}
);
std::string result = res.get();
safe_delete(task_runner);
return result;
}
bool IpUtil::IsIPAddress(const std::string &ip_address)
{
struct sockaddr_in sa{};
int result = inet_pton(AF_INET, ip_address.c_str(), &(sa.sin_addr));
return result != 0;
}
-7
View File
@@ -30,13 +30,6 @@ public:
static uint32_t IPToUInt(const std::string &ip); static uint32_t IPToUInt(const std::string &ip);
static bool IsIpInRange(const std::string &ip, const std::string &network, const std::string &mask); static bool IsIpInRange(const std::string &ip, const std::string &network, const std::string &mask);
static bool IsIpInPrivateRfc1918(const std::string &ip); static bool IsIpInPrivateRfc1918(const std::string &ip);
static std::string GetLocalIPAddress();
static std::string GetPublicIPAddress();
static std::string DNSLookupSync(
const std::string &addr,
int port
);
static bool IsIPAddress(const std::string &ip_address);
}; };
+6 -4
View File
@@ -30,7 +30,6 @@
#include "types.h" #include "types.h"
#include "eqemu_exception.h" #include "eqemu_exception.h"
#include "eqemu_config.h" #include "eqemu_config.h"
#include "path_manager.h"
namespace EQ { namespace EQ {
struct IPCMutex::Implementation { struct IPCMutex::Implementation {
@@ -41,11 +40,12 @@ namespace EQ {
#endif #endif
}; };
IPCMutex::IPCMutex(const std::string& name) : locked_(false) { IPCMutex::IPCMutex(std::string name) : locked_(false) {
imp_ = new Implementation; imp_ = new Implementation;
#ifdef _WINDOWS #ifdef _WINDOWS
auto Config = EQEmuConfig::get(); auto Config = EQEmuConfig::get();
std::string final_name = fmt::format("{}/EQEmuMutex_{}", Config->SharedMemDir, name); std::string final_name = Config->SharedMemDir + "EQEmuMutex_";
final_name += name;
imp_->mut_ = CreateMutex(nullptr, imp_->mut_ = CreateMutex(nullptr,
FALSE, FALSE,
@@ -55,7 +55,9 @@ namespace EQ {
EQ_EXCEPT("IPC Mutex", "Could not create mutex."); EQ_EXCEPT("IPC Mutex", "Could not create mutex.");
} }
#else #else
std::string final_name = fmt::format("{}/{}.lock", path.GetSharedMemoryPath(), name); auto Config = EQEmuConfig::get();
std::string final_name = Config->SharedMemDir + name;
final_name += ".lock";
#ifdef __DARWIN #ifdef __DARWIN
#if __DARWIN_C_LEVEL < 200809L #if __DARWIN_C_LEVEL < 200809L
+1 -1
View File
@@ -37,7 +37,7 @@ namespace EQ {
Creates a named binary semaphore, basically a semaphore that is init S <- 1 Creates a named binary semaphore, basically a semaphore that is init S <- 1
\param name The name of this mutex. \param name The name of this mutex.
*/ */
IPCMutex(const std::string& name); IPCMutex(std::string name);
//! Destructor //! Destructor
~IPCMutex(); ~IPCMutex();
+2 -24
View File
@@ -169,33 +169,11 @@ uint8 EQ::item::ConvertAugTypeBitToAugType(uint32 aug_type_bit)
bool EQ::ItemData::IsEquipable(uint16 race_id, uint16 class_id) const bool EQ::ItemData::IsEquipable(uint16 race_id, uint16 class_id) const
{ {
if (!(Races & GetPlayerRaceBit(race_id))) { if (!(Races & GetPlayerRaceBit(race_id)))
return false; return false;
}
if (!(Classes & GetPlayerClassBit(GetPlayerClassValue(class_id)))) { if (!(Classes & GetPlayerClassBit(GetPlayerClassValue(class_id))))
return false; return false;
}
return true;
}
bool EQ::ItemData::IsClassEquipable(uint16 class_id) const
{
if (!(Classes & GetPlayerClassBit(GetPlayerClassValue(class_id)))) {
return false;
}
return true;
}
bool EQ::ItemData::IsRaceEquipable(uint16 race_id) const
{
if (!(Races & GetPlayerRaceBit(race_id))) {
return false;
}
return true; return true;
} }
+159 -166
View File
@@ -355,191 +355,184 @@ namespace EQ
struct ItemData { struct ItemData {
// Non packet based fields // Non packet based fields
uint8 MinStatus {}; uint8 MinStatus;
// Packet based fields // Packet based fields
uint8 ItemClass {}; // Item Type: 0=common, 1=container, 2=book uint8 ItemClass; // Item Type: 0=common, 1=container, 2=book
char Name[64] {}; // Name char Name[64]; // Name
char Lore[80] {}; // Lore Name: *=lore, &=summoned, #=artifact, ~=pending lore char Lore[80]; // Lore Name: *=lore, &=summoned, #=artifact, ~=pending lore
char IDFile[30] {}; // Visible model char IDFile[30]; // Visible model
uint32 ID {}; // Unique ID (also PK for DB) uint32 ID; // Unique ID (also PK for DB)
int32 Weight {}; // Item weight * 10 int32 Weight; // Item weight * 10
uint8 NoRent{} ; // No Rent: 0=norent, 255=not norent uint8 NoRent; // No Rent: 0=norent, 255=not norent
uint8 NoDrop {}; // No Drop: 0=nodrop, 255=not nodrop uint8 NoDrop; // No Drop: 0=nodrop, 255=not nodrop
uint8 Size {}; // Size: 0=tiny, 1=small, 2=medium, 3=large, 4=giant uint8 Size; // Size: 0=tiny, 1=small, 2=medium, 3=large, 4=giant
uint32 Slots {}; // Bitfield for which slots this item can be used in uint32 Slots; // Bitfield for which slots this item can be used in
uint32 Price {}; // Item cost (?) uint32 Price; // Item cost (?)
uint32 Icon {}; // Icon Number uint32 Icon; // Icon Number
int32 LoreGroup {}; // Later items use LoreGroup instead of LoreFlag. we might want to see about changing this to int32 since it is commonly -1 and is constantly being cast from signed (-1) to unsigned (4294967295) int32 LoreGroup; // Later items use LoreGroup instead of LoreFlag. we might want to see about changing this to int32 since it is commonly -1 and is constantly being cast from signed (-1) to unsigned (4294967295)
bool LoreFlag {}; // This will be true if LoreGroup is non-zero bool LoreFlag; // This will be true if LoreGroup is non-zero
bool PendingLoreFlag {}; bool PendingLoreFlag;
bool ArtifactFlag {}; bool ArtifactFlag;
bool SummonedFlag {}; bool SummonedFlag;
uint8 FVNoDrop {}; // Firiona Vie nodrop flag uint8 FVNoDrop; // Firiona Vie nodrop flag
uint32 Favor {}; // Individual favor uint32 Favor; // Individual favor
uint32 GuildFavor {}; // Guild favor uint32 GuildFavor; // Guild favor
uint32 PointType {}; uint32 PointType;
//uint32 Unk117; //uint32 Unk117;
//uint32 Unk118; //uint32 Unk118;
//uint32 Unk121; //uint32 Unk121;
//uint32 Unk124; //uint32 Unk124;
uint8 BagType {}; // 0:Small Bag, 1:Large Bag, 2:Quiver, 3:Belt Pouch ... there are 50 types uint8 BagType; // 0:Small Bag, 1:Large Bag, 2:Quiver, 3:Belt Pouch ... there are 50 types
uint8 BagSlots {}; // Number of slots: can only be 2, 4, 6, 8, or 10 uint8 BagSlots; // Number of slots: can only be 2, 4, 6, 8, or 10
uint8 BagSize {}; // 0:TINY, 1:SMALL, 2:MEDIUM, 3:LARGE, 4:GIANT uint8 BagSize; // 0:TINY, 1:SMALL, 2:MEDIUM, 3:LARGE, 4:GIANT
uint8 BagWR {}; // 0->100 uint8 BagWR; // 0->100
bool BenefitFlag {}; bool BenefitFlag;
bool Tradeskills {}; // Is this a tradeskill item? bool Tradeskills; // Is this a tradeskill item?
int8 CR {}; // Save vs Cold int8 CR; // Save vs Cold
int8 DR {}; // Save vs Disease int8 DR; // Save vs Disease
int8 PR {}; // Save vs Poison int8 PR; // Save vs Poison
int8 MR {}; // Save vs Magic int8 MR; // Save vs Magic
int8 FR {}; // Save vs Fire int8 FR; // Save vs Fire
int8 AStr {}; // Strength int8 AStr; // Strength
int8 ASta {}; // Stamina int8 ASta; // Stamina
int8 AAgi {}; // Agility int8 AAgi; // Agility
int8 ADex {}; // Dexterity int8 ADex; // Dexterity
int8 ACha {}; // Charisma int8 ACha; // Charisma
int8 AInt {}; // Intelligence int8 AInt; // Intelligence
int8 AWis {}; // Wisdom int8 AWis; // Wisdom
int32 HP {}; // HP int32 HP; // HP
int32 Mana {}; // Mana int32 Mana; // Mana
int32 AC {}; // AC int32 AC; // AC
uint32 Deity {}; // Bitmask of Deities that can equip this item uint32 Deity; // Bitmask of Deities that can equip this item
//uint32 Unk033 //uint32 Unk033
int32 SkillModValue {}; // % Mod to skill specified in SkillModType int32 SkillModValue; // % Mod to skill specified in SkillModType
int32 SkillModMax {}; // Max skill point modification int32 SkillModMax; // Max skill point modification
uint32 SkillModType {}; // Type of skill for SkillModValue to apply to uint32 SkillModType; // Type of skill for SkillModValue to apply to
uint32 BaneDmgRace {}; // Bane Damage Race uint32 BaneDmgRace; // Bane Damage Race
int32 BaneDmgAmt {}; // Bane Damage Body Amount int32 BaneDmgAmt; // Bane Damage Body Amount
uint32 BaneDmgBody {}; // Bane Damage Body uint32 BaneDmgBody; // Bane Damage Body
bool Magic {}; // True=Magic Item, False=not bool Magic; // True=Magic Item, False=not
int32 CastTime_ {}; int32 CastTime_;
uint8 ReqLevel {}; // Required Level to use item uint8 ReqLevel; // Required Level to use item
uint32 BardType {}; // Bard Skill Type uint32 BardType; // Bard Skill Type
int32 BardValue {}; // Bard Skill Amount int32 BardValue; // Bard Skill Amount
int8 Light {}; // Light int8 Light; // Light
uint8 Delay {}; // Delay * 10 uint8 Delay; // Delay * 10
uint8 RecLevel {}; // Recommended level to use item uint8 RecLevel; // Recommended level to use item
uint8 RecSkill {}; // Recommended skill to use item (refers to primary skill of item) uint8 RecSkill; // Recommended skill to use item (refers to primary skill of item)
uint8 ElemDmgType {}; // Elemental Damage Type (1=magic, 2=fire) uint8 ElemDmgType; // Elemental Damage Type (1=magic, 2=fire)
uint8 ElemDmgAmt {}; // Elemental Damage uint8 ElemDmgAmt; // Elemental Damage
uint8 Range {}; // Range of item uint8 Range; // Range of item
uint32 Damage {}; // Delay between item usage (in 0.1 sec increments) uint32 Damage; // Delay between item usage (in 0.1 sec increments)
uint32 Color {}; // RR GG BB 00 <-- as it appears in pc uint32 Color; // RR GG BB 00 <-- as it appears in pc
uint32 Classes {}; // Bitfield of classes that can equip item (1 << class#) uint32 Classes; // Bitfield of classes that can equip item (1 << class#)
uint32 Races {}; // Bitfield of races that can equip item (1 << race#) uint32 Races; // Bitfield of races that can equip item (1 << race#)
//uint32 Unk054 {}; //uint32 Unk054;
int16 MaxCharges {}; // Maximum charges items can hold: -1 if not a chargeable item int16 MaxCharges; // Maximum charges items can hold: -1 if not a chargeable item
uint8 ItemType {}; // Item Type/Skill (itemClass* from above) uint8 ItemType; // Item Type/Skill (itemClass* from above)
int32 SubType {}; // Some items have sub types that can be used for other things (unbreakable fishing poles, SE_FFItemClass) int32 SubType; // Some items have sub types that can be used for other things (unbreakable fishing poles, SE_FFItemClass)
uint8 Material {}; // Item material type uint8 Material; // Item material type
uint32 HerosForgeModel {};// Hero's Forge Armor Model Type (2-13?) uint32 HerosForgeModel;// Hero's Forge Armor Model Type (2-13?)
float SellRate {}; // Sell rate float SellRate; // Sell rate
//uint32 Unk059 {}; //uint32 Unk059;
union { union {
uint32 Fulfilment; // Food fulfilment (How long it lasts) uint32 Fulfilment; // Food fulfilment (How long it lasts)
uint32 CastTime; // Cast Time for clicky effects, in milliseconds uint32 CastTime; // Cast Time for clicky effects, in milliseconds
}; };
uint32 EliteMaterial {}; uint32 EliteMaterial;
int32 ProcRate {}; int32 ProcRate;
int8 CombatEffects {}; // PoP: Combat Effects + int8 CombatEffects; // PoP: Combat Effects +
int8 Shielding {}; // PoP: Shielding % int8 Shielding; // PoP: Shielding %
int8 StunResist {}; // PoP: Stun Resist % int8 StunResist; // PoP: Stun Resist %
int8 StrikeThrough {}; // PoP: Strike Through % int8 StrikeThrough; // PoP: Strike Through %
int32 ExtraDmgSkill {}; uint32 ExtraDmgSkill;
int32 ExtraDmgAmt {}; uint32 ExtraDmgAmt;
int8 SpellShield {}; // PoP: Spell Shield % int8 SpellShield; // PoP: Spell Shield %
int8 Avoidance {}; // PoP: Avoidance + int8 Avoidance; // PoP: Avoidance +
int8 Accuracy {}; // PoP: Accuracy + int8 Accuracy; // PoP: Accuracy +
uint32 CharmFileID {}; uint32 CharmFileID;
int32 FactionMod1 {}; // Faction Mod 1 int32 FactionMod1; // Faction Mod 1
int32 FactionMod2 {}; // Faction Mod 2 int32 FactionMod2; // Faction Mod 2
int32 FactionMod3 {}; // Faction Mod 3 int32 FactionMod3; // Faction Mod 3
int32 FactionMod4 {}; // Faction Mod 4 int32 FactionMod4; // Faction Mod 4
int32 FactionAmt1 {}; // Faction Amt 1 int32 FactionAmt1; // Faction Amt 1
int32 FactionAmt2 {}; // Faction Amt 2 int32 FactionAmt2; // Faction Amt 2
int32 FactionAmt3 {}; // Faction Amt 3 int32 FactionAmt3; // Faction Amt 3
int32 FactionAmt4 {}; // Faction Amt 4 int32 FactionAmt4; // Faction Amt 4
char CharmFile[32] {}; // ? char CharmFile[32]; // ?
uint32 AugType {}; uint32 AugType;
uint8 AugSlotType[invaug::SOCKET_COUNT] {}; // RoF: Augment Slot 1-6 Type uint8 AugSlotType[invaug::SOCKET_COUNT]; // RoF: Augment Slot 1-6 Type
uint8 AugSlotVisible[invaug::SOCKET_COUNT] {}; // RoF: Augment Slot 1-6 Visible uint8 AugSlotVisible[invaug::SOCKET_COUNT]; // RoF: Augment Slot 1-6 Visible
uint8 AugSlotUnk2[invaug::SOCKET_COUNT] {}; // RoF: Augment Slot 1-6 Unknown Most likely Powersource related uint8 AugSlotUnk2[invaug::SOCKET_COUNT]; // RoF: Augment Slot 1-6 Unknown Most likely Powersource related
uint32 LDoNTheme {}; uint32 LDoNTheme;
uint32 LDoNPrice {}; uint32 LDoNPrice;
uint32 LDoNSold {}; uint32 LDoNSold;
uint32 BaneDmgRaceAmt {}; uint32 BaneDmgRaceAmt;
uint32 AugRestrict {}; uint32 AugRestrict;
int32 Endur {}; int32 Endur;
int32 DotShielding {}; int32 DotShielding;
int32 Attack {}; int32 Attack;
int32 Regen {}; int32 Regen;
int32 ManaRegen {}; int32 ManaRegen;
int32 EnduranceRegen {}; int32 EnduranceRegen;
int32 Haste {}; int32 Haste;
int32 DamageShield {}; int32 DamageShield;
uint32 RecastDelay {}; uint32 RecastDelay;
int RecastType {}; int RecastType;
uint32 AugDistiller {}; uint32 AugDistiller;
bool Attuneable {}; bool Attuneable;
bool NoPet {}; bool NoPet;
bool PotionBelt {}; bool PotionBelt;
bool Stackable {}; bool Stackable;
bool NoTransfer {}; bool NoTransfer;
bool QuestItemFlag {}; bool QuestItemFlag;
int16 StackSize {}; int16 StackSize;
uint8 PotionBeltSlots {}; uint8 PotionBeltSlots;
item::ItemEffect_Struct Click {}; item::ItemEffect_Struct Click, Proc, Worn, Focus, Scroll, Bard;
item::ItemEffect_Struct Proc {};
item::ItemEffect_Struct Worn {};
item::ItemEffect_Struct Focus {};
item::ItemEffect_Struct Scroll {};
item::ItemEffect_Struct Bard {};
uint8 Book {}; // 0=Not book, 1=Book uint8 Book; // 0=Not book, 1=Book
uint32 BookType {}; uint32 BookType;
char Filename[33] {}; // Filename for book data char Filename[33]; // Filename for book data
// Begin SoF Fields // Begin SoF Fields
int32 SVCorruption {}; int32 SVCorruption;
uint32 Purity {}; uint32 Purity;
uint8 EvolvingItem {}; uint8 EvolvingItem;
uint32 EvolvingID {}; uint32 EvolvingID;
uint8 EvolvingLevel {}; uint8 EvolvingLevel;
uint8 EvolvingMax {}; uint8 EvolvingMax;
uint32 BackstabDmg {}; uint32 BackstabDmg;
uint32 DSMitigation {}; uint32 DSMitigation;
int32 HeroicStr {}; int32 HeroicStr;
int32 HeroicInt {}; int32 HeroicInt;
int32 HeroicWis {}; int32 HeroicWis;
int32 HeroicAgi {}; int32 HeroicAgi;
int32 HeroicDex {}; int32 HeroicDex;
int32 HeroicSta {}; int32 HeroicSta;
int32 HeroicCha {}; int32 HeroicCha;
int32 HeroicMR {}; int32 HeroicMR;
int32 HeroicFR {}; int32 HeroicFR;
int32 HeroicCR {}; int32 HeroicCR;
int32 HeroicDR {}; int32 HeroicDR;
int32 HeroicPR {}; int32 HeroicPR;
int32 HeroicSVCorrup {}; int32 HeroicSVCorrup;
int32 HealAmt {}; int32 HealAmt;
int32 SpellDmg {}; int32 SpellDmg;
uint32 LDoNSellBackRate {}; uint32 LDoNSellBackRate;
uint32 ScriptFileID {}; uint32 ScriptFileID;
uint16 ExpendableArrow {}; uint16 ExpendableArrow;
uint32 Clairvoyance {}; uint32 Clairvoyance;
char ClickName[65] {}; char ClickName[65];
char ProcName[65] {}; char ProcName[65];
char WornName[65] {}; char WornName[65];
char FocusName[65] {}; char FocusName[65];
char ScrollName[65] {}; char ScrollName[65];
//BardName //BardName
bool IsEquipable(uint16 Race, uint16 Class) const; bool IsEquipable(uint16 Race, uint16 Class) const;
bool IsClassEquipable(uint16 Class) const;
bool IsRaceEquipable(uint16 Race) const;
bool IsClassCommon() const; bool IsClassCommon() const;
bool IsClassBag() const; bool IsClassBag() const;
bool IsClassBook() const; bool IsClassBook() const;
+184 -252
View File
@@ -17,14 +17,13 @@
*/ */
#include "inventory_profile.h" #include "inventory_profile.h"
#include "../common/data_verification.h"
//#include "classes.h" //#include "classes.h"
//#include "global_define.h" //#include "global_define.h"
//#include "item_instance.h" //#include "item_instance.h"
//#include "races.h" //#include "races.h"
#include "rulesys.h" #include "rulesys.h"
#include "shareddb.h" #include "shareddb.h"
#include "strings.h" #include "string_util.h"
//#include "../common/light_source.h" //#include "../common/light_source.h"
@@ -58,62 +57,108 @@ static inline int32 GetNextItemInstSerialNumber() {
// class EQ::ItemInstance // class EQ::ItemInstance
// //
EQ::ItemInstance::ItemInstance(const ItemData* item, int16 charges) { EQ::ItemInstance::ItemInstance(const ItemData* item, int16 charges) {
m_use_type = ItemInstNormal;
if (item) { if(item) {
m_item = new ItemData(*item); m_item = new ItemData(*item);
} else {
m_item = nullptr;
} }
m_charges = charges; m_charges = charges;
m_price = 0;
if (m_item && m_item->IsClassCommon()) { m_attuned = false;
m_merchantslot = 0;
if (m_item && m_item->IsClassCommon())
m_color = m_item->Color; m_color = m_item->Color;
} else
m_color = 0;
m_merchantcount = 1;
m_SerialNumber = GetNextItemInstSerialNumber();
m_SerialNumber = GetNextItemInstSerialNumber(); m_exp = 0;
m_evolveLvl = 0;
m_activated = false;
m_scaledItem = nullptr;
m_evolveInfo = nullptr;
m_scaling = false;
m_ornamenticon = 0;
m_ornamentidfile = 0;
m_ornament_hero_model = 0;
m_recast_timestamp = 0;
m_new_id_file = 0;
} }
EQ::ItemInstance::ItemInstance(SharedDatabase *db, uint32 item_id, int16 charges) { EQ::ItemInstance::ItemInstance(SharedDatabase *db, uint32 item_id, int16 charges) {
m_use_type = ItemInstNormal;
m_item = db->GetItem(item_id); m_item = db->GetItem(item_id);
if(m_item) {
if (m_item) {
m_item = new ItemData(*m_item); m_item = new ItemData(*m_item);
} }
else {
m_item = nullptr;
}
m_charges = charges; m_charges = charges;
m_price = 0;
if (m_item && m_item->IsClassCommon()) { m_merchantslot = 0;
m_attuned=false;
if (m_item && m_item->IsClassCommon())
m_color = m_item->Color; m_color = m_item->Color;
} else { else
m_color = 0; m_color = 0;
} m_merchantcount = 1;
m_SerialNumber = GetNextItemInstSerialNumber();
m_SerialNumber = GetNextItemInstSerialNumber(); m_exp = 0;
m_evolveLvl = 0;
m_activated = false;
m_scaledItem = nullptr;
m_evolveInfo = nullptr;
m_scaling = false;
m_ornamenticon = 0;
m_ornamentidfile = 0;
m_ornament_hero_model = 0;
m_recast_timestamp = 0;
m_new_id_file = 0;
} }
EQ::ItemInstance::ItemInstance(ItemInstTypes use_type) { EQ::ItemInstance::ItemInstance(ItemInstTypes use_type) {
m_use_type = use_type; m_use_type = use_type;
m_item = nullptr;
m_charges = 0;
m_price = 0;
m_attuned = false;
m_merchantslot = 0;
m_color = 0;
m_exp = 0;
m_evolveLvl = 0;
m_activated = false;
m_scaledItem = nullptr;
m_evolveInfo = nullptr;
m_scaling = false;
m_ornamenticon = 0;
m_ornamentidfile = 0;
m_ornament_hero_model = 0;
m_recast_timestamp = 0;
m_new_id_file = 0;
} }
// Make a copy of an EQ::ItemInstance object // Make a copy of an EQ::ItemInstance object
EQ::ItemInstance::ItemInstance(const ItemInstance& copy) EQ::ItemInstance::ItemInstance(const ItemInstance& copy)
{ {
m_use_type = copy.m_use_type; m_use_type=copy.m_use_type;
if(copy.m_item)
if (copy.m_item) {
m_item = new ItemData(*copy.m_item); m_item = new ItemData(*copy.m_item);
} else { else
m_item = nullptr; m_item = nullptr;
}
m_charges = copy.m_charges;
m_price = copy.m_price;
m_color = copy.m_color;
m_merchantslot = copy.m_merchantslot;
m_currentslot = copy.m_currentslot;
m_attuned = copy.m_attuned;
m_merchantcount = copy.m_merchantcount;
m_charges=copy.m_charges;
m_price=copy.m_price;
m_color=copy.m_color;
m_merchantslot=copy.m_merchantslot;
m_currentslot=copy.m_currentslot;
m_attuned=copy.m_attuned;
m_merchantcount=copy.m_merchantcount;
// Copy container contents // Copy container contents
for (auto it = copy.m_contents.begin(); it != copy.m_contents.end(); ++it) { for (auto it = copy.m_contents.begin(); it != copy.m_contents.end(); ++it) {
ItemInstance* inst_old = it->second; ItemInstance* inst_old = it->second;
@@ -123,42 +168,37 @@ EQ::ItemInstance::ItemInstance(const ItemInstance& copy)
inst_new = inst_old->Clone(); inst_new = inst_old->Clone();
} }
if (inst_new) { if (inst_new != nullptr) {
m_contents[it->first] = inst_new; m_contents[it->first] = inst_new;
} }
} }
std::map<std::string, std::string>::const_iterator iter; std::map<std::string, std::string>::const_iterator iter;
for (iter = copy.m_custom_data.begin(); iter != copy.m_custom_data.end(); ++iter) { for (iter = copy.m_custom_data.begin(); iter != copy.m_custom_data.end(); ++iter) {
m_custom_data[iter->first] = iter->second; m_custom_data[iter->first] = iter->second;
} }
m_SerialNumber = copy.m_SerialNumber; m_SerialNumber = copy.m_SerialNumber;
m_custom_data = copy.m_custom_data; m_custom_data = copy.m_custom_data;
m_timers = copy.m_timers; m_timers = copy.m_timers;
m_exp = copy.m_exp; m_exp = copy.m_exp;
m_evolveLvl = copy.m_evolveLvl; m_evolveLvl = copy.m_evolveLvl;
m_activated = copy.m_activated; m_activated = copy.m_activated;
if (copy.m_scaledItem)
if (copy.m_scaledItem) {
m_scaledItem = new ItemData(*copy.m_scaledItem); m_scaledItem = new ItemData(*copy.m_scaledItem);
} else { else
m_scaledItem = nullptr; m_scaledItem = nullptr;
}
if (copy.m_evolveInfo) { if(copy.m_evolveInfo)
m_evolveInfo = new EvolveInfo(*copy.m_evolveInfo); m_evolveInfo = new EvolveInfo(*copy.m_evolveInfo);
} else { else
m_evolveInfo = nullptr; m_evolveInfo = nullptr;
}
m_scaling = copy.m_scaling; m_scaling = copy.m_scaling;
m_ornamenticon = copy.m_ornamenticon; m_ornamenticon = copy.m_ornamenticon;
m_ornamentidfile = copy.m_ornamentidfile; m_ornamentidfile = copy.m_ornamentidfile;
m_ornament_hero_model = copy.m_ornament_hero_model; m_ornament_hero_model = copy.m_ornament_hero_model;
m_recast_timestamp = copy.m_recast_timestamp; m_recast_timestamp = copy.m_recast_timestamp;
m_new_id_file = copy.m_new_id_file; m_new_id_file = copy.m_new_id_file;
} }
// Clean up container contents // Clean up container contents
@@ -176,13 +216,11 @@ bool EQ::ItemInstance::IsType(item::ItemClass item_class) const
// IsType(<ItemClassTypes>) does not protect against 'm_item = nullptr' // IsType(<ItemClassTypes>) does not protect against 'm_item = nullptr'
// Check usage type // Check usage type
if (m_use_type == ItemInstWorldContainer && item_class == item::ItemClassBag) { if ((m_use_type == ItemInstWorldContainer) && (item_class == item::ItemClassBag))
return true; return true;
}
if (!m_item) { if (!m_item)
return false; return false;
}
return (m_item->ItemClass == item_class); return (m_item->ItemClass == item_class);
} }
@@ -205,145 +243,96 @@ bool EQ::ItemInstance::IsClassBook() const
// Is item stackable? // Is item stackable?
bool EQ::ItemInstance::IsStackable() const bool EQ::ItemInstance::IsStackable() const
{ {
return (m_item && m_item->Stackable); if (!m_item)
return false;
return m_item->Stackable;
} }
bool EQ::ItemInstance::IsCharged() const bool EQ::ItemInstance::IsCharged() const
{ {
if (!m_item) { if (!m_item)
return false; return false;
}
if (m_item->MaxCharges > 1) { if (m_item->MaxCharges > 1)
return true; return true;
} else { else
return false; return false;
}
} }
// Can item be equipped? // Can item be equipped?
bool EQ::ItemInstance::IsEquipable(uint16 race, uint16 class_) const bool EQ::ItemInstance::IsEquipable(uint16 race, uint16 class_) const
{ {
if (!m_item || !m_item->Slots) { if (!m_item || (m_item->Slots == 0))
return false; return false;
}
return m_item->IsEquipable(race, class_); return m_item->IsEquipable(race, class_);
} }
// Can item be equipped by Class?
bool EQ::ItemInstance::IsClassEquipable(uint16 class_) const
{
if (!m_item || !m_item->Slots) {
return false;
}
return m_item->IsClassEquipable(class_);
}
// Can item be equipped by Race?
bool EQ::ItemInstance::IsRaceEquipable(uint16 race) const
{
if (!m_item || !m_item->Slots) {
return false;
}
return m_item->IsRaceEquipable(race);
}
// Can equip at this slot? // Can equip at this slot?
bool EQ::ItemInstance::IsEquipable(int16 slot_id) const bool EQ::ItemInstance::IsEquipable(int16 slot_id) const
{ {
if (!m_item || !m_item->Slots) { if (!m_item)
return false; return false;
}
if (slot_id < EQ::invslot::EQUIPMENT_BEGIN || slot_id > EQ::invslot::EQUIPMENT_END) { if (slot_id < EQ::invslot::EQUIPMENT_BEGIN || slot_id > EQ::invslot::EQUIPMENT_END)
return false; return false;
}
return ((m_item->Slots & (1 << slot_id)) != 0); return ((m_item->Slots & (1 << slot_id)) != 0);
} }
bool EQ::ItemInstance::IsAugmentable() const bool EQ::ItemInstance::IsAugmentable() const
{ {
if (!m_item) { if (!m_item)
return false; return false;
}
for (int index = invaug::SOCKET_BEGIN; index <= invaug::SOCKET_END; ++index) { for (int index = invaug::SOCKET_BEGIN; index <= invaug::SOCKET_END; ++index) {
if (m_item->AugSlotType[index] != 0) { if (m_item->AugSlotType[index] != 0)
return true; return true;
}
} }
return false; return false;
} }
bool EQ::ItemInstance::AvailableWearSlot(uint32 aug_wear_slots) const { bool EQ::ItemInstance::AvailableWearSlot(uint32 aug_wear_slots) const {
if (!m_item || !m_item->IsClassCommon()) { if (!m_item || !m_item->IsClassCommon())
return false; return false;
}
int index = invslot::EQUIPMENT_BEGIN; int index = invslot::EQUIPMENT_BEGIN;
for (; index <= invslot::EQUIPMENT_END; ++index) { for (; index <= invslot::EQUIPMENT_END; ++index) {
if (m_item->Slots & (1 << index)) { if (m_item->Slots & (1 << index)) {
if (aug_wear_slots & (1 << index)) { if (aug_wear_slots & (1 << index))
break; break;
}
} }
} }
return (index <= EQ::invslot::EQUIPMENT_END); return (index <= EQ::invslot::EQUIPMENT_END);
} }
int8 EQ::ItemInstance::AvailableAugmentSlot(int32 augment_type) const int8 EQ::ItemInstance::AvailableAugmentSlot(int32 augtype) const
{ {
if (!m_item || !m_item->IsClassCommon()) { if (!m_item || !m_item->IsClassCommon())
return INVALID_INDEX; return INVALID_INDEX;
}
auto i = invaug::SOCKET_BEGIN; int index = invaug::SOCKET_BEGIN;
for (; i <= invaug::SOCKET_END; ++i) { for (; index <= invaug::SOCKET_END; ++index) {
if (GetItem(i)) { if (GetItem(index)) { continue; }
continue; if (augtype == -1 || (m_item->AugSlotType[index] && ((1 << (m_item->AugSlotType[index] - 1)) & augtype)))
}
if (
augment_type == -1 ||
(
m_item->AugSlotType[i] &&
((1 << (m_item->AugSlotType[i] - 1)) & augment_type)
)
) {
break; break;
}
} }
return (i <= invaug::SOCKET_END) ? i : INVALID_INDEX; return (index <= invaug::SOCKET_END) ? index : INVALID_INDEX;
} }
bool EQ::ItemInstance::IsAugmentSlotAvailable(int32 augment_type, uint8 slot) const bool EQ::ItemInstance::IsAugmentSlotAvailable(int32 augtype, uint8 slot) const
{ {
if (!m_item || !m_item->IsClassCommon()) { if (!m_item || !m_item->IsClassCommon())
return false; return false;
}
if ( if ((!GetItem(slot) && m_item->AugSlotVisible[slot]) && augtype == -1 || (m_item->AugSlotType[slot] && ((1 << (m_item->AugSlotType[slot] - 1)) & augtype))) {
(
!GetItem(slot) &&
m_item->AugSlotVisible[slot]
) &&
augment_type == -1 ||
(
m_item->AugSlotType[slot] &&
((1 << (m_item->AugSlotType[slot] - 1)) & augment_type)
)
) {
return true; return true;
} }
return false;
return false;
} }
// Retrieve item inside container // Retrieve item inside container
@@ -359,10 +348,9 @@ EQ::ItemInstance* EQ::ItemInstance::GetItem(uint8 index) const
uint32 EQ::ItemInstance::GetItemID(uint8 slot) const uint32 EQ::ItemInstance::GetItemID(uint8 slot) const
{ {
const auto item = GetItem(slot); ItemInstance *item = GetItem(slot);
if (item) { if (item)
return item->GetID(); return item->GetID();
}
return 0; return 0;
} }
@@ -486,21 +474,14 @@ uint8 EQ::ItemInstance::FirstOpenSlot() const
uint8 EQ::ItemInstance::GetTotalItemCount() const uint8 EQ::ItemInstance::GetTotalItemCount() const
{ {
if (!m_item) { if (!m_item)
return 0; return 0;
}
uint8 item_count = 1; uint8 item_count = 1;
if (!m_item->IsClassBag()) { if (m_item && !m_item->IsClassBag()) { return item_count; }
return item_count;
}
for (int index = invbag::SLOT_BEGIN; index < m_item->BagSlots; ++index) { for (int index = invbag::SLOT_BEGIN; index < m_item->BagSlots; ++index) { if (GetItem(index)) { ++item_count; } }
if (GetItem(index)) {
++item_count;
}
}
return item_count; return item_count;
} }
@@ -519,108 +500,86 @@ bool EQ::ItemInstance::IsNoneEmptyContainer()
} }
// Retrieve augment inside item // Retrieve augment inside item
EQ::ItemInstance* EQ::ItemInstance::GetAugment(uint8 augment_index) const EQ::ItemInstance* EQ::ItemInstance::GetAugment(uint8 slot) const
{ {
if (m_item && m_item->IsClassCommon()) { if (m_item && m_item->IsClassCommon())
return GetItem(augment_index); return GetItem(slot);
}
return nullptr; return nullptr;
} }
bool EQ::ItemInstance::IsOrnamentationAugment(EQ::ItemInstance* augment) const EQ::ItemInstance* EQ::ItemInstance::GetOrnamentationAug(int32 ornamentationAugtype) const
{ {
if (!m_item || !m_item->IsClassCommon() || !augment) { if (!m_item || !m_item->IsClassCommon()) { return nullptr; }
return false; if (ornamentationAugtype == 0) { return nullptr; }
}
const auto augment_item = augment->GetItem(); for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; i++)
if (!augment_item) { {
return false; if (GetAugment(i) && m_item->AugSlotType[i] == ornamentationAugtype)
} {
const char *item_IDFile = GetAugment(i)->GetItem()->IDFile;
const std::string& idfile = augment_item->IDFile; if (
(strncmp(item_IDFile, "IT64", strlen(item_IDFile)) == 0
if ( || strncmp(item_IDFile, "IT63", strlen(item_IDFile)) == 0)
EQ::ValueWithin( && GetAugment(i)->GetItem()->HerosForgeModel == 0
augment->GetAugmentType(), )
OrnamentationAugmentTypes::StandardOrnamentation, {
OrnamentationAugmentTypes::SpecialOrnamentation continue;
) || }
( return GetAugment(i);
idfile != "IT63" &&
idfile != "IT64"
) ||
augment_item->HerosForgeModel
) {
return true;
}
return false;
}
EQ::ItemInstance* EQ::ItemInstance::GetOrnamentationAugment() const
{
if (!m_item || !m_item->IsClassCommon()) {
return nullptr;
}
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; i++) {
const auto augment = GetAugment(i);
if (augment && IsOrnamentationAugment(augment)) {
return augment;
} }
} }
return nullptr; return nullptr;
} }
uint32 EQ::ItemInstance::GetOrnamentHeroModel(int32 material_slot) const uint32 EQ::ItemInstance::GetOrnamentHeroModel(int32 material_slot) const {
{
// Not a Hero Forge item. // Not a Hero Forge item.
if (m_ornament_hero_model == 0 || material_slot < 0) { if (m_ornament_hero_model == 0 || material_slot < 0)
return 0; return 0;
}
// Item is using an explicit Hero Forge ID // Item is using an explicit Hero Forge ID
if (m_ornament_hero_model >= 1000) { if (m_ornament_hero_model >= 1000)
return m_ornament_hero_model; return m_ornament_hero_model;
}
// Item is using a shorthand ID // Item is using a shorthand ID
return (m_ornament_hero_model * 100) + material_slot; return (m_ornament_hero_model * 100) + material_slot;
} }
bool EQ::ItemInstance::UpdateOrnamentationInfo() bool EQ::ItemInstance::UpdateOrnamentationInfo() {
{ if (!m_item || !m_item->IsClassCommon())
if (!m_item || !m_item->IsClassCommon()) {
return false; return false;
}
const auto augment = GetOrnamentationAugment(); bool ornamentSet = false;
if (augment) { int32 ornamentationAugtype = RuleI(Character, OrnamentationAugmentType);
const auto augment_item = GetOrnamentationAugment()->GetItem(); if (GetOrnamentationAug(ornamentationAugtype))
{
if (augment_item) { const ItemData* ornamentItem;
SetOrnamentIcon(augment_item->Icon); ornamentItem = GetOrnamentationAug(ornamentationAugtype)->GetItem();
SetOrnamentHeroModel(augment_item->HerosForgeModel); if (ornamentItem != nullptr)
{
if (strlen(augment_item->IDFile) > 2) { SetOrnamentIcon(ornamentItem->Icon);
SetOrnamentationIDFile(Strings::ToUnsignedInt(&augment_item->IDFile[2])); SetOrnamentHeroModel(ornamentItem->HerosForgeModel);
} else { if (strlen(ornamentItem->IDFile) > 2)
{
SetOrnamentationIDFile(atoi(&ornamentItem->IDFile[2]));
}
else
{
SetOrnamentationIDFile(0); SetOrnamentationIDFile(0);
} }
ornamentSet = true;
return true;
} }
} }
else
{
SetOrnamentIcon(0);
SetOrnamentHeroModel(0);
SetOrnamentationIDFile(0);
}
SetOrnamentIcon(0); return ornamentSet;
SetOrnamentHeroModel(0);
SetOrnamentationIDFile(0);
return false;
} }
bool EQ::ItemInstance::CanTransform(const ItemData *ItemToTry, const ItemData *Container, bool AllowAll) { bool EQ::ItemInstance::CanTransform(const ItemData *ItemToTry, const ItemData *Container, bool AllowAll) {
@@ -670,13 +629,12 @@ bool EQ::ItemInstance::CanTransform(const ItemData *ItemToTry, const ItemData *C
return false; return false;
} }
uint32 EQ::ItemInstance::GetAugmentItemID(uint8 augment_index) const uint32 EQ::ItemInstance::GetAugmentItemID(uint8 slot) const
{ {
if (!m_item || !m_item->IsClassCommon()) { if (!m_item || !m_item->IsClassCommon())
return 0; return 0;
}
return GetItemID(augment_index); return GetItemID(slot);
} }
// Add an augment to the item // Add an augment to the item
@@ -834,20 +792,7 @@ std::string EQ::ItemInstance::GetCustomDataString() const {
return ret_val; return ret_val;
} }
void EQ::ItemInstance::SetCustomDataString(const std::string& str) std::string EQ::ItemInstance::GetCustomData(std::string identifier) {
{
auto components = Strings::Split(str, "^");
auto value_count = components.size() / 2;
for (auto i = 0; i < value_count; i++) {
auto identifier = components[i * 2];
auto value = components[(i * 2) + 1];
SetCustomData(identifier, value);
}
}
std::string EQ::ItemInstance::GetCustomData(const std::string& identifier) {
std::map<std::string, std::string>::const_iterator iter = m_custom_data.find(identifier); std::map<std::string, std::string>::const_iterator iter = m_custom_data.find(identifier);
if (iter != m_custom_data.end()) { if (iter != m_custom_data.end()) {
return iter->second; return iter->second;
@@ -856,33 +801,33 @@ std::string EQ::ItemInstance::GetCustomData(const std::string& identifier) {
return ""; return "";
} }
void EQ::ItemInstance::SetCustomData(const std::string& identifier, const std::string& value) { void EQ::ItemInstance::SetCustomData(std::string identifier, std::string value) {
DeleteCustomData(identifier); DeleteCustomData(identifier);
m_custom_data[identifier] = value; m_custom_data[identifier] = value;
} }
void EQ::ItemInstance::SetCustomData(const std::string& identifier, int value) { void EQ::ItemInstance::SetCustomData(std::string identifier, int value) {
DeleteCustomData(identifier); DeleteCustomData(identifier);
std::stringstream ss; std::stringstream ss;
ss << value; ss << value;
m_custom_data[identifier] = ss.str(); m_custom_data[identifier] = ss.str();
} }
void EQ::ItemInstance::SetCustomData(const std::string& identifier, float value) { void EQ::ItemInstance::SetCustomData(std::string identifier, float value) {
DeleteCustomData(identifier); DeleteCustomData(identifier);
std::stringstream ss; std::stringstream ss;
ss << value; ss << value;
m_custom_data[identifier] = ss.str(); m_custom_data[identifier] = ss.str();
} }
void EQ::ItemInstance::SetCustomData(const std::string& identifier, bool value) { void EQ::ItemInstance::SetCustomData(std::string identifier, bool value) {
DeleteCustomData(identifier); DeleteCustomData(identifier);
std::stringstream ss; std::stringstream ss;
ss << value; ss << value;
m_custom_data[identifier] = ss.str(); m_custom_data[identifier] = ss.str();
} }
void EQ::ItemInstance::DeleteCustomData(const std::string& identifier) { void EQ::ItemInstance::DeleteCustomData(std::string identifier) {
auto iter = m_custom_data.find(identifier); auto iter = m_custom_data.find(identifier);
if (iter != m_custom_data.end()) { if (iter != m_custom_data.end()) {
m_custom_data.erase(iter); m_custom_data.erase(iter);
@@ -934,9 +879,8 @@ bool EQ::ItemInstance::IsDroppable(bool recurse) const
void EQ::ItemInstance::Initialize(SharedDatabase *db) { void EQ::ItemInstance::Initialize(SharedDatabase *db) {
// if there's no actual item, don't do anything // if there's no actual item, don't do anything
if (!m_item) { if (!m_item)
return; return;
}
// initialize scaling items // initialize scaling items
if (m_item->CharmFileID != 0) { if (m_item->CharmFileID != 0) {
@@ -945,7 +889,7 @@ void EQ::ItemInstance::Initialize(SharedDatabase *db) {
} }
// initialize evolving items // initialize evolving items
else if (db && m_item->LoreGroup >= 1000) { else if ((db) && m_item->LoreGroup >= 1000 && m_item->LoreGroup != -1) {
// not complete yet // not complete yet
} }
} }
@@ -1271,7 +1215,7 @@ int EQ::ItemInstance::GetItemBaneDamageBody(bool augments) const
int EQ::ItemInstance::GetItemBaneDamageRace(bool augments) const int EQ::ItemInstance::GetItemBaneDamageRace(bool augments) const
{ {
int race = RACE_DOUG_0; int race = 0;
const auto item = GetItem(); const auto item = GetItem();
if (item) { if (item) {
race = item->BaneDmgRace; race = item->BaneDmgRace;
@@ -1777,18 +1721,6 @@ int EQ::ItemInstance::GetItemHaste(bool augments) const
return total; return total;
} }
int EQ::ItemInstance::RemoveTaskDeliveredItems()
{
int count = IsStackable() ? GetCharges() : 1;
count -= GetTaskDeliveredCount();
if (IsStackable())
{
SetCharges(count);
}
SetTaskDeliveredCount(0);
return count;
}
// //
// class EvolveInfo // class EvolveInfo
// //
+37 -55
View File
@@ -51,11 +51,6 @@ typedef enum {
byFlagNotSet //apply action if the flag is NOT set byFlagNotSet //apply action if the flag is NOT set
} byFlagSetting; } byFlagSetting;
enum OrnamentationAugmentTypes {
StandardOrnamentation = 20,
SpecialOrnamentation = 21
};
class SharedDatabase; class SharedDatabase;
// ######################################## // ########################################
@@ -97,8 +92,6 @@ namespace EQ
// Can item be equipped by/at? // Can item be equipped by/at?
bool IsEquipable(uint16 race, uint16 class_) const; bool IsEquipable(uint16 race, uint16 class_) const;
bool IsClassEquipable(uint16 class_) const;
bool IsRaceEquipable(uint16 race) const;
bool IsEquipable(int16 slot_id) const; bool IsEquipable(int16 slot_id) const;
// //
@@ -106,8 +99,8 @@ namespace EQ
// //
bool IsAugmentable() const; bool IsAugmentable() const;
bool AvailableWearSlot(uint32 aug_wear_slots) const; bool AvailableWearSlot(uint32 aug_wear_slots) const;
int8 AvailableAugmentSlot(int32 augment_type) const; int8 AvailableAugmentSlot(int32 augtype) const;
bool IsAugmentSlotAvailable(int32 augment_type, uint8 slot) const; bool IsAugmentSlotAvailable(int32 augtype, uint8 slot) const;
inline int32 GetAugmentType() const { return ((m_item) ? m_item->AugType : 0); } inline int32 GetAugmentType() const { return ((m_item) ? m_item->AugType : 0); }
inline bool IsExpendable() const { return ((m_item) ? ((m_item->Click.Type == item::ItemEffectExpendable) || (m_item->ItemType == item::ItemTypePotion)) : false); } inline bool IsExpendable() const { return ((m_item) ? ((m_item->Click.Type == item::ItemEffectExpendable) || (m_item->ItemType == item::ItemTypePotion)) : false); }
@@ -132,8 +125,8 @@ namespace EQ
// //
// Augments // Augments
// //
ItemInstance* GetAugment(uint8 augment_index) const; ItemInstance* GetAugment(uint8 slot) const;
uint32 GetAugmentItemID(uint8 augment_index) const; uint32 GetAugmentItemID(uint8 slot) const;
void PutAugment(uint8 slot, const ItemInstance& inst); void PutAugment(uint8 slot, const ItemInstance& inst);
void PutAugment(SharedDatabase *db, uint8 slot, uint32 item_id); void PutAugment(SharedDatabase *db, uint8 slot, uint32 item_id);
void DeleteAugment(uint8 slot); void DeleteAugment(uint8 slot);
@@ -141,8 +134,7 @@ namespace EQ
bool IsAugmented(); bool IsAugmented();
bool ContainsAugmentByID(uint32 item_id); bool ContainsAugmentByID(uint32 item_id);
int CountAugmentByID(uint32 item_id); int CountAugmentByID(uint32 item_id);
bool IsOrnamentationAugment(EQ::ItemInstance* augment) const; ItemInstance* GetOrnamentationAug(int32 ornamentationAugtype) const;
ItemInstance* GetOrnamentationAugment() const;
bool UpdateOrnamentationInfo(); bool UpdateOrnamentationInfo();
static bool CanTransform(const ItemData *ItemToTry, const ItemData *Container, bool AllowAll = false); static bool CanTransform(const ItemData *ItemToTry, const ItemData *Container, bool AllowAll = false);
@@ -156,8 +148,6 @@ namespace EQ
const ItemData* GetItem() const; const ItemData* GetItem() const;
const ItemData* GetUnscaledItem() const; const ItemData* GetUnscaledItem() const;
const uint8 GetItemType() const { return m_item ? m_item->ItemType : 255; } // Return 255 so you know there's no valid item
int16 GetCharges() const { return m_charges; } int16 GetCharges() const { return m_charges; }
void SetCharges(int16 charges) { m_charges = charges; } void SetCharges(int16 charges) { m_charges = charges; }
@@ -181,13 +171,12 @@ namespace EQ
void SetAttuned(bool flag) { m_attuned = flag; } void SetAttuned(bool flag) { m_attuned = flag; }
std::string GetCustomDataString() const; std::string GetCustomDataString() const;
std::string GetCustomData(const std::string &identifier); std::string GetCustomData(std::string identifier);
void SetCustomDataString(const std::string& str); void SetCustomData(std::string identifier, std::string value);
void SetCustomData(const std::string &identifier, const std::string& value); void SetCustomData(std::string identifier, int value);
void SetCustomData(const std::string &identifier, int value); void SetCustomData(std::string identifier, float value);
void SetCustomData(const std::string &identifier, float value); void SetCustomData(std::string identifier, bool value);
void SetCustomData(const std::string &identifier, bool value); void DeleteCustomData(std::string identifier);
void DeleteCustomData(const std::string& identifier);
// Allows treatment of this object as though it were a pointer to m_item // Allows treatment of this object as though it were a pointer to m_item
operator bool() const { return (m_item != nullptr); } operator bool() const { return (m_item != nullptr); }
@@ -240,13 +229,6 @@ namespace EQ
void StopTimer(std::string name); void StopTimer(std::string name);
void ClearTimers(); void ClearTimers();
int GetTaskDeliveredCount() const { return m_task_delivered_count; }
void SetTaskDeliveredCount(int count) { m_task_delivered_count = count; }
// This function should only be used by trade return apis
// Removes delivered task items from stack count and returns remaining count
// Return value should be used to determine if an item still exists (for stackable and non-stackable)
int RemoveTaskDeliveredItems();
// Get a total of a stat, including augs // Get a total of a stat, including augs
// These functions should be used in place of other code manually totaling // These functions should be used in place of other code manually totaling
// to centralize where it is done to make future changes easier (ex. whenever powersources come around) // to centralize where it is done to make future changes easier (ex. whenever powersources come around)
@@ -310,33 +292,33 @@ namespace EQ
void _PutItem(uint8 index, ItemInstance* inst) { m_contents[index] = inst; } void _PutItem(uint8 index, ItemInstance* inst) { m_contents[index] = inst; }
ItemInstTypes m_use_type {ItemInstNormal}; // Usage type for item ItemInstTypes m_use_type; // Usage type for item
const ItemData* m_item {nullptr}; // Ptr to item data const ItemData* m_item; // Ptr to item data
int16 m_charges {0}; // # of charges for chargeable items int16 m_charges; // # of charges for chargeable items
uint32 m_price {0}; // Bazaar /trader price uint32 m_price; // Bazaar /trader price
uint32 m_color {0}; uint32 m_color;
uint32 m_merchantslot {0}; uint32 m_merchantslot;
int16 m_currentslot {0}; int16 m_currentslot;
bool m_attuned {false}; bool m_attuned;
int32 m_merchantcount {1}; //number avaliable on the merchant, -1=unlimited int32 m_merchantcount; //number avaliable on the merchant, -1=unlimited
int32 m_SerialNumber {0}; // Unique identifier for this instance of an item. Needed for Bazaar. int32 m_SerialNumber; // Unique identifier for this instance of an item. Needed for Bazaar.
uint32 m_exp {0}; uint32 m_exp;
int8 m_evolveLvl {0}; int8 m_evolveLvl;
bool m_activated {false}; bool m_activated;
ItemData* m_scaledItem {nullptr}; ItemData* m_scaledItem;
::EvolveInfo* m_evolveInfo {nullptr}; ::EvolveInfo* m_evolveInfo;
bool m_scaling {false}; bool m_scaling;
uint32 m_ornamenticon {0}; uint32 m_ornamenticon;
uint32 m_ornamentidfile {0}; uint32 m_ornamentidfile;
uint32 m_new_id_file {0}; uint32 m_new_id_file;
uint32 m_ornament_hero_model {0}; uint32 m_ornament_hero_model;
uint32 m_recast_timestamp {0}; uint32 m_recast_timestamp;
int m_task_delivered_count {0};
// Items inside of this item (augs or contents) {}; //
std::map<uint8, ItemInstance*> m_contents {}; // Zero-based index: min=0, max=9 // Items inside of this item (augs or contents);
std::map<std::string, std::string> m_custom_data {}; std::map<uint8, ItemInstance*> m_contents; // Zero-based index: min=0, max=9
std::map<std::string, ::Timer> m_timers {}; std::map<std::string, std::string> m_custom_data;
std::map<std::string, ::Timer> m_timers;
}; };
} }
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -9,7 +9,7 @@
*/ */
#include <string.h> /* for memcpy() */ #include <string.h> /* for memcpy() */
#include "../common/md5.h" #include "../common/md5.h"
#include "../common/strings.h" #include "../common/string_util.h"
#include "../common/seperator.h" #include "../common/seperator.h"
MD5::MD5() { MD5::MD5() {
+2 -2
View File
@@ -71,13 +71,13 @@ namespace EQ
template<typename T> template<typename T>
void Write(T val) { void Write(T val) {
static_assert(std::is_standard_layout<T>::value, "MemoryBuffer::Write<T>(T val) only works on pod and string types."); static_assert(std::is_pod<T>::value, "MemoryBuffer::Write<T>(T val) only works on pod and string types.");
Write((const char*)&val, sizeof(T)); Write((const char*)&val, sizeof(T));
} }
template<typename T> template<typename T>
T Read() { T Read() {
static_assert(std::is_standard_layout<T>::value, "MemoryBuffer::Read<T>() only works on pod and string types."); static_assert(std::is_pod<T>::value, "MemoryBuffer::Read<T>() only works on pod and string types.");
T temp; T temp;
Read((uchar*)&temp, sizeof(T)); Read((uchar*)&temp, sizeof(T));
return temp; return temp;
-3
View File
@@ -33,9 +33,6 @@
#include <sys/stat.h> #include <sys/stat.h>
#endif #endif
#include <filesystem>
namespace fs = std::filesystem;
namespace EQ { namespace EQ {
struct MemoryMappedFile::Implementation { struct MemoryMappedFile::Implementation {
+1 -2
View File
@@ -18,7 +18,6 @@
#include "misc.h" #include "misc.h"
#include "types.h" #include "types.h"
#include <cstring> #include <cstring>
#include "strings.h"
std::map<int,std::string> DBFieldNames; std::map<int,std::string> DBFieldNames;
@@ -151,7 +150,7 @@ static char *temp=nullptr;
return false; return false;
} }
ptr++; ptr++;
uint32 id = Strings::ToUnsignedInt(field[id_pos]); uint32 id = atoi(field[id_pos].c_str());
items[id]=field; items[id]=field;
for(i=0;i<10;i++) { for(i=0;i<10;i++) {
+1 -2
View File
@@ -21,7 +21,6 @@
#include "misc_functions.h" #include "misc_functions.h"
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include "strings.h"
#ifndef WIN32 #ifndef WIN32
#include <netinet/in.h> #include <netinet/in.h>
@@ -131,7 +130,7 @@ bool ParseAddress(const char* iAddress, uint32* oIP, uint16* oPort, char* errbuf
if (*oIP == 0) if (*oIP == 0)
return false; return false;
if (oPort) if (oPort)
*oPort = Strings::ToUnsignedInt(sep.arg[1]); *oPort = atoi(sep.arg[1]);
return true; return true;
} }
return false; return false;
+1 -7
View File
@@ -10,14 +10,8 @@
#include <iterator> #include <iterator>
#include "types.h" #include "types.h"
class MySQLRequestRow class MySQLRequestRow : public std::iterator<std::input_iterator_tag, MYSQL_ROW>
{ {
public:
using iterator_category = std::input_iterator_tag;
using value_type = MYSQL_ROW;
using difference_type = std::ptrdiff_t;
using pointer = MYSQL_ROW*;
using reference = MYSQL_ROW&;
private: private:
MYSQL_RES* m_Result; MYSQL_RES* m_Result;
+4 -4
View File
@@ -1,5 +1,5 @@
#include "console_server.h" #include "console_server.h"
#include "../strings.h" #include "../string_util.h"
#include <fmt/format.h> #include <fmt/format.h>
EQ::Net::ConsoleServer::ConsoleServer(const std::string &addr, int port) EQ::Net::ConsoleServer::ConsoleServer(const std::string &addr, int port)
@@ -7,7 +7,7 @@ EQ::Net::ConsoleServer::ConsoleServer(const std::string &addr, int port)
m_server = std::make_unique<EQ::Net::TCPServer>(); m_server = std::make_unique<EQ::Net::TCPServer>();
m_server->Listen(addr, port, false, [this](std::shared_ptr<EQ::Net::TCPConnection> connection) { m_server->Listen(addr, port, false, [this](std::shared_ptr<EQ::Net::TCPConnection> connection) {
ConsoleServerConnection *c = new ConsoleServerConnection(this, connection); ConsoleServerConnection *c = new ConsoleServerConnection(this, connection);
m_connections.emplace(std::make_pair(c->GetUUID(), std::unique_ptr<ConsoleServerConnection>(c))); m_connections.insert(std::make_pair(c->GetUUID(), std::unique_ptr<ConsoleServerConnection>(c)));
}); });
} }
@@ -52,11 +52,11 @@ void EQ::Net::ConsoleServer::ConnectionDisconnected(ConsoleServerConnection *c)
void EQ::Net::ConsoleServer::ProcessCommand(ConsoleServerConnection *c, const std::string &cmd) void EQ::Net::ConsoleServer::ProcessCommand(ConsoleServerConnection *c, const std::string &cmd)
{ {
auto split = Strings::Split(cmd, ' '); auto split = SplitString(cmd, ' ');
if (split.size() > 0) { if (split.size() > 0) {
auto command = split[0]; auto command = split[0];
command = Strings::ToLower(command); ToLowerString(command);
if (command == "help" || command == "?") { if (command == "help" || command == "?") {
c->SendLine("Commands:"); c->SendLine("Commands:");
+15 -14
View File
@@ -116,42 +116,43 @@ bool EQ::Net::ConsoleServerConnection::SendChannelMessage(const ServerChannelMes
} }
switch (scm->chan_num) { switch (scm->chan_num) {
case ChatChannel_Guild: { case 4: {
QueueMessage(fmt::format("{} tells the guild [{}], '{}'", scm->from, scm->guilddbid, scm->message));
break;
}
case ChatChannel_Auction: {
if (RuleB(Chat, ServerWideAuction)) { if (RuleB(Chat, ServerWideAuction)) {
QueueMessage(fmt::format("{} auctions, '{}'", scm->from, scm->message)); QueueMessage(fmt::format("{0} auctions, '{1}'", scm->from, scm->message));
break; break;
} else { // I think we want default action in this case? } else { // I think we want default action in this case?
return false; return false;
} }
} }
case ChatChannel_OOC: {
case 5: {
if (RuleB(Chat, ServerWideOOC)) { if (RuleB(Chat, ServerWideOOC)) {
QueueMessage(fmt::format("{} says ooc, '{}'", scm->from, scm->message)); QueueMessage(fmt::format("{0} says ooc, '{1}'", scm->from, scm->message));
break; break;
} else { // I think we want default action in this case? } else { // I think we want default action in this case?
return false; return false;
} }
} }
case ChatChannel_Broadcast: {
QueueMessage(fmt::format("{} BROADCASTS, '{}'", scm->from, scm->message)); case 6: {
QueueMessage(fmt::format("{0} BROADCASTS, '{1}'", scm->from, scm->message));
break; break;
} }
case ChatChannel_Tell: {
QueueMessage(fmt::format("[{}] tells {}, '{}'", scm->from, scm->to, scm->message)); case 7: {
QueueMessage(fmt::format("[{0}] tells you, '{1}'", scm->from, scm->message));
if (onTell) { if (onTell) {
onTell(); onTell();
} }
break; break;
} }
case ChatChannel_GMSAY: {
QueueMessage(fmt::format("{} GMSAYS, '{}'", scm->from, scm->message)); case 11: {
QueueMessage(fmt::format("{0} GMSAYS, '{1}'", scm->from, scm->message));
break; break;
} }
default: { default: {
return false; return false;
} }

Some files were not shown because too many files have changed in this diff Show More