mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-22 20:33:01 +00:00
Compare commits
261 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c90f42eb8b | |||
| 5ce1fef9ec | |||
| 874ca053f7 | |||
| b8e7e5bb0d | |||
| 15f3697df1 | |||
| 16cfad1966 | |||
| bffeee8d1a | |||
| d29c0fc332 | |||
| a031c20e7e | |||
| 67d3cab80b | |||
| b41f2dac66 | |||
| b5b473f25d | |||
| 0dc3e5ba35 | |||
| 499fe153ab | |||
| d1349e5ac9 | |||
| bd8e94ff17 | |||
| d89b2f11b5 | |||
| 88ff56b2f2 | |||
| 1728923bbb | |||
| cbd1f42a08 | |||
| f8735cf9ba | |||
| eb00667eab | |||
| cbc0ada454 | |||
| 54b33f959e | |||
| c6e4b5647f | |||
| 928070e994 | |||
| 40ef4c799b | |||
| 8ba7ddd054 | |||
| 973fd376e5 | |||
| b5575133cd | |||
| 6f846dc4ff | |||
| 0461fc1789 | |||
| aa6264266e | |||
| c3cbe90575 | |||
| c2c6282cc7 | |||
| fab071d9da | |||
| 358bd60716 | |||
| 03ca345b37 | |||
| 6ddcc2bb8a | |||
| 02cac686b6 | |||
| 4c348baabd | |||
| 035bac1044 | |||
| 5a8d467d25 | |||
| ae959be5ac | |||
| 4157a03f32 | |||
| 41d0b1a947 | |||
| 3c71e2c91d | |||
| 80d1601754 | |||
| cfcbfea3ab | |||
| 7aa8db76f4 | |||
| 561433902e | |||
| abeb93f1e6 | |||
| ef0b29dc8e | |||
| 42f959329d | |||
| a898a1d07b | |||
| 803c3aabe4 | |||
| 15dde4778a | |||
| f2b68e6783 | |||
| 8193b04627 | |||
| 47e56f9381 | |||
| 58b9b719f4 | |||
| a4bf484c74 | |||
| 4712b56078 | |||
| 9362890d26 | |||
| 6d3848b2c7 | |||
| 8974059577 | |||
| 963735e7dd | |||
| c94a2496ca | |||
| ceb8b31bc0 | |||
| 51b31b5e53 | |||
| 6fb6d8891d | |||
| d4ea9bbee0 | |||
| 3a7908b1de | |||
| 99c1c826a8 | |||
| 1b888784eb | |||
| 52a25c3b78 | |||
| 4b08ce1237 | |||
| b94fdda429 | |||
| a48153baa1 | |||
| e26b159efe | |||
| a2b381bc9e | |||
| 60e194e32b | |||
| 1cdf507b9f | |||
| 3e98e60877 | |||
| af5022b3db | |||
| 52d2469da2 | |||
| e431c56f7c | |||
| 0ab7291625 | |||
| e384cf6149 | |||
| 463c0d9e0e | |||
| 0f92287c02 | |||
| 6a61fd5df9 | |||
| dac7541d89 | |||
| e7266943e2 | |||
| 7f25f8a235 | |||
| 240d5c2a66 | |||
| 785804a936 | |||
| e451dad94e | |||
| 08414bda55 | |||
| c39978d3d8 | |||
| f3d8271066 | |||
| 431a325414 | |||
| c42d6dcd1b | |||
| fa12b146a3 | |||
| e7fab67d8a | |||
| 6438a37fb5 | |||
| 899e2d3397 | |||
| 53be04c39c | |||
| bfecd6ad14 | |||
| dd1470892d | |||
| d4a1ea82dc | |||
| 8d252dfd9a | |||
| 1577f2823b | |||
| cede38f562 | |||
| 201757567c | |||
| 2a9248697e | |||
| 3708efd8df | |||
| 1d907564e9 | |||
| 1b15ee141d | |||
| d838ac9582 | |||
| dce5dea609 | |||
| 581d5b1289 | |||
| 4915e86aba | |||
| 09e9c0b504 | |||
| a3eb74b855 | |||
| fb396e9f60 | |||
| d85469dff9 | |||
| 3f7ce5df72 | |||
| d5b3dc7c0a | |||
| ac3b4ade10 | |||
| 482584f95a | |||
| 57e7b4a2b8 | |||
| 7f6414d685 | |||
| 81e91d7956 | |||
| 3875485567 | |||
| eb104e40de | |||
| bec33e22da | |||
| ac104ed4e0 | |||
| 0ffb5c46a5 | |||
| 92638504db | |||
| 08002eacea | |||
| 79248cffec | |||
| 8787f51b58 | |||
| 69f4d90737 | |||
| 1371e1e7ed | |||
| 81ff7f5d57 | |||
| 8376ed5d3f | |||
| fe4a0cfdba | |||
| 0043f56984 | |||
| 6ddc5ea8e8 | |||
| be38a62d70 | |||
| fdc38315d3 | |||
| e7c000813f | |||
| 6fb0042e3f | |||
| 0a4429c0c0 | |||
| a63dc7d5e0 | |||
| 67449de27e | |||
| 10e5f0e949 | |||
| 141ecca2bc | |||
| bd4fa4fb6b | |||
| 5901df4485 | |||
| 8cda4257b4 | |||
| 709a25ba9e | |||
| ed09d4ae54 | |||
| 952fd43301 | |||
| 5f8d193d6a | |||
| a4a70cf225 | |||
| 29fccd9239 | |||
| cdc82f0ba7 | |||
| 78756f27b6 | |||
| 2f5909d4cb | |||
| 13c2df7eb1 | |||
| 16ac6f624b | |||
| 501204a4d2 | |||
| 8bcef6c2e7 | |||
| 2db47adf7b | |||
| 916c88939c | |||
| 1528e7cb09 | |||
| 8dacadb4f9 | |||
| e19db3b7f4 | |||
| e1adffc4be | |||
| 7eb71c5902 | |||
| da397606b6 | |||
| 6b27e88315 | |||
| 4accb4ea2a | |||
| c419df52ff | |||
| 46ff09f438 | |||
| b4f42c150f | |||
| 49134644bc | |||
| 861b879a94 | |||
| 929e4c1317 | |||
| 138cb80b19 | |||
| 86b6f543b9 | |||
| d7138e84c0 | |||
| 2d24cdf5e4 | |||
| 4416e774c2 | |||
| 342012c4f4 | |||
| 34005cd2ed | |||
| 6bc6b659d5 | |||
| ad1f18306b | |||
| 6a984a53b5 | |||
| f9b3b7aecf | |||
| 5fefdfcc17 | |||
| 00f118cfb4 | |||
| a7633f4ddf | |||
| f742d6427b | |||
| d65a97e556 | |||
| b8229c8459 | |||
| 424b669cbb | |||
| e09b0ae1e9 | |||
| c2300d514c | |||
| f195820854 | |||
| 59903313e4 | |||
| b351d3718a | |||
| ab3d65b2ea | |||
| b02e87cce7 | |||
| 50a39057e4 | |||
| c8e6d031cf | |||
| 158d8a011f | |||
| 14c070f845 | |||
| 6dee837f67 | |||
| 83ad9c86db | |||
| bcb08f99f0 | |||
| f968d0df4c | |||
| 712366293d | |||
| 9689787e56 | |||
| 92d32feb0d | |||
| 371265d143 | |||
| 43da07fb55 | |||
| f880663528 | |||
| 63b8df72b2 | |||
| c82d08cf11 | |||
| c6ba29f2e5 | |||
| 6514ccc41c | |||
| 2f49266d08 | |||
| ff897dc90a | |||
| f73f72b2b2 | |||
| c2b3e85272 | |||
| c590cf7c35 | |||
| 453bee511a | |||
| 1baeb01e65 | |||
| 8b37ef5e67 | |||
| caceae1028 | |||
| 8e6dd638ff | |||
| 51fb7d8b77 | |||
| f6ed4bb888 | |||
| 9cc73f2b4a | |||
| 6f73278cf8 | |||
| 6c91786cfb | |||
| 8eb60302a2 | |||
| 43df845233 | |||
| feefd7a23b | |||
| 5a1eac010b | |||
| d47bf6a73b | |||
| 6da0f84e18 | |||
| b2dd3df1e2 | |||
| 3ec500244e | |||
| 4425e3ab49 | |||
| 413c006785 | |||
| ae3052fbd1 | |||
| 8be23a1214 |
@@ -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}"
|
||||
}
|
||||
}
|
||||
+19
-1
@@ -17,6 +17,8 @@
|
||||
*.out
|
||||
*.app
|
||||
|
||||
.bash_history
|
||||
|
||||
# CMake
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
@@ -35,4 +37,20 @@ perl/
|
||||
submodules/*
|
||||
cmake-build-debug/
|
||||
|
||||
.nfs.*
|
||||
.nfs.*
|
||||
|
||||
# Visual Studio and CMAKE Generated Files
|
||||
/.vs/
|
||||
*.vcxproj
|
||||
*.vcxproj.filters
|
||||
*.vcxproj.user
|
||||
*.cmake
|
||||
*.ilk
|
||||
*.pdb
|
||||
*.sln
|
||||
*.dir/
|
||||
libs/
|
||||
bin/
|
||||
/Win32
|
||||
/x64
|
||||
/client_files/**/CMakeFiles/
|
||||
|
||||
@@ -16,3 +16,6 @@
|
||||
[submodule "submodules/recastnavigation"]
|
||||
path = submodules/recastnavigation
|
||||
url = https://github.com/EQEmu/recastnavigation.git
|
||||
[submodule "submodules/expected"]
|
||||
path = submodules/expected
|
||||
url = https://github.com/TartanLlama/expected.git
|
||||
|
||||
+11
-19
@@ -1,26 +1,18 @@
|
||||
language: cpp
|
||||
compiler: gcc
|
||||
dist: trusty
|
||||
dist: bionic
|
||||
|
||||
before_install:
|
||||
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
- sudo apt-get update -qq
|
||||
- mkdir $HOME/usr
|
||||
- export PATH="$HOME/usr/bin:$PATH"
|
||||
- wget https://cmake.org/files/v3.11/cmake-3.11.2-Linux-x86_64.sh
|
||||
- chmod +x cmake-3.11.2-Linux-x86_64.sh
|
||||
- ./cmake-3.11.2-Linux-x86_64.sh --prefix=$HOME/usr --exclude-subdir --skip-license
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libmysqlclient-dev
|
||||
- libperl-dev
|
||||
- libboost-dev
|
||||
- liblua5.1-0-dev
|
||||
- zlib1g-dev
|
||||
- uuid-dev
|
||||
- libssl-dev
|
||||
|
||||
install:
|
||||
- sudo apt-get install -qq g++-7
|
||||
- sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-7 90
|
||||
- sudo apt-get install libmysqlclient-dev
|
||||
- sudo apt-get install libperl-dev
|
||||
- sudo apt-get install libboost-dev
|
||||
- sudo apt-get install liblua5.1-0-dev
|
||||
- sudo apt-get install zlib1g-dev
|
||||
- sudo apt-get install uuid-dev
|
||||
- sudo apt-get install libssl-dev
|
||||
script:
|
||||
- cmake -G "Unix Makefiles" -DEQEMU_BUILD_TESTS=ON -DEQEMU_ENABLE_BOTS=ON -DEQEMU_BUILD_LOGIN=ON
|
||||
- make -j2
|
||||
|
||||
Vendored
+16
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**",
|
||||
"/usr/include/mysql"
|
||||
],
|
||||
"defines": [],
|
||||
"compilerPath": "/usr/bin/gcc",
|
||||
"cStandard": "c11",
|
||||
"cppStandard": "c++17"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
Vendored
+155
@@ -0,0 +1,155 @@
|
||||
{
|
||||
// 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 build && make",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"problemMatcher": [
|
||||
"$gcc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "make clean",
|
||||
"type": "shell",
|
||||
"command": "cd build && make clean",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"problemMatcher": [
|
||||
"$gcc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "cmake",
|
||||
"type": "shell",
|
||||
"command": "mkdir -p build && cd build && 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 build/bin && cd build/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 build/bin && cd build/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 build/bin && cd build/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 build/bin && cd build/bin && docker run -i --rm --privileged -v ${HOST_PROJECT_PATH}/build/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}/build/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}/build/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}/build/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}/build/bin:/src --network=eqemu --name sharedmemory eqemu/server:0.0.3 ./shared_memory && docker run --rm -v ${HOST_PROJECT_PATH}/build/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}/build/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 build/bin && docker network create eqemu | true && docker run --rm -v ${HOST_PROJECT_PATH}/build/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
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -270,6 +270,7 @@ INCLUDE_DIRECTORIES(SYSTEM "${ZLIB_LIBRARY_INCLUDE}")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${Boost_INCLUDE_DIRS}")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/submodules/glm")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/submodules/cereal/include")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/submodules/expected/include")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/submodules/fmt/include")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/submodules/libuv/include" )
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/submodules/recastnavigation/DebugUtils/Include")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# EQEmulator Core Server
|
||||
|Travis CI (Linux)|Appveyor w/ Bots (Windows) |Appveyor w/o Bots (Windows) |
|
||||
|Travis CI (Linux)|Appveyor (Windows x86) |Appveyor (Windows x64) |
|
||||
|:---:|:---:|:---:|
|
||||
|[](https://travis-ci.org/EQEmu/Server) |[](https://ci.appveyor.com/project/KimLS/server-87crp/branch/master) |[](https://ci.appveyor.com/project/KimLS/server-w0pq2/branch/master) |
|
||||
|[](https://travis-ci.org/EQEmu/Server) |[](https://ci.appveyor.com/project/KimLS/server) |[](https://ci.appveyor.com/project/KimLS/server-87crp) |
|
||||
|
||||
***
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|:---:|:---:|:---:|
|
||||
|**Install Count**|||
|
||||
### > Windows
|
||||
* [Install](https://github.com/EQEmu/Server/wiki/Windows-Server)
|
||||
* [Install](https://eqemu.gitbook.io/server/categories/how-to-guides/installation/server-installation-windows)
|
||||
|
||||
### > Debian/Ubuntu/CentOS/Fedora
|
||||
* You can use curl or wget to kick off the installer (whichever your OS has)
|
||||
@@ -52,7 +52,7 @@ forum, although pull requests will be much quicker and easier on all parties.
|
||||
|
||||
## Resources
|
||||
- [EQEmulator Forums](http://www.eqemulator.org/forums)
|
||||
- [EQEmulator Wiki](https://github.com/EQEmu/Server/wiki)
|
||||
- [EQEmulator Wiki](https://eqemu.gitbook.io/)
|
||||
|
||||
## Related Repositories
|
||||
* [ProjectEQ Quests](https://github.com/ProjectEQ/projecteqquests)
|
||||
|
||||
+22
-3
@@ -9,6 +9,7 @@ SET(common_sources
|
||||
crash.cpp
|
||||
crc16.cpp
|
||||
crc32.cpp
|
||||
database/database_dump_service.cpp
|
||||
database.cpp
|
||||
database_conversions.cpp
|
||||
database_instances.cpp
|
||||
@@ -31,6 +32,7 @@ SET(common_sources
|
||||
event_sub.cpp
|
||||
extprofile.cpp
|
||||
faction.cpp
|
||||
file_util.cpp
|
||||
guild_base.cpp
|
||||
guilds.cpp
|
||||
inventory_profile.cpp
|
||||
@@ -44,7 +46,6 @@ SET(common_sources
|
||||
md5.cpp
|
||||
memory_buffer.cpp
|
||||
memory_mapped_file.cpp
|
||||
metric_manager.cpp
|
||||
misc.cpp
|
||||
misc_functions.cpp
|
||||
mutex.cpp
|
||||
@@ -121,6 +122,7 @@ SET(common_headers
|
||||
cli/argh.h
|
||||
cli/eqemu_command_handler.h
|
||||
cli/terminal_color.hpp
|
||||
database/database_dump_service.h
|
||||
data_verification.h
|
||||
database.h
|
||||
database_schema.h
|
||||
@@ -149,8 +151,10 @@ SET(common_headers
|
||||
eqtime.h
|
||||
errmsg.h
|
||||
event_sub.h
|
||||
expected.h
|
||||
extprofile.h
|
||||
faction.h
|
||||
file_util.h
|
||||
features.h
|
||||
fixed_memory_hash_set.h
|
||||
fixed_memory_variable_hash_set.h
|
||||
@@ -174,8 +178,6 @@ SET(common_headers
|
||||
md5.h
|
||||
memory_buffer.h
|
||||
memory_mapped_file.h
|
||||
metric_event.h
|
||||
metric_manager.h
|
||||
misc.h
|
||||
misc_functions.h
|
||||
mutex.h
|
||||
@@ -266,6 +268,13 @@ SET(common_headers
|
||||
patches/uf_limits.h
|
||||
patches/uf_ops.h
|
||||
patches/uf_structs.h
|
||||
shared/shared_memory.h
|
||||
shared/shared_memory_error.h
|
||||
shared/shared_memory_handle.h
|
||||
shared/shared_memory_list.h
|
||||
shared/shared_memory_map.h
|
||||
shared/shared_memory_string.h
|
||||
shared/shared_memory_vector.h
|
||||
StackWalker/StackWalker.h
|
||||
util/memory_stream.h
|
||||
util/directory.h
|
||||
@@ -364,6 +373,16 @@ SOURCE_GROUP(Patches FILES
|
||||
patches/uf_limits.cpp
|
||||
)
|
||||
|
||||
SOURCE_GROUP(shared FILES
|
||||
shared/shared_memory.h
|
||||
shared/shared_memory_error.h
|
||||
shared/shared_memory_handle.h
|
||||
shared/shared_memory_list.h
|
||||
shared/shared_memory_map.h
|
||||
shared/shared_memory_string.h
|
||||
shared/shared_memory_vector.h
|
||||
)
|
||||
|
||||
SOURCE_GROUP(StackWalker FILES
|
||||
StackWalker/StackWalker.h
|
||||
StackWalker/StackWalker.cpp
|
||||
|
||||
@@ -96,7 +96,7 @@ namespace EQEmuCommand {
|
||||
"\nCommand" <<
|
||||
termcolor::reset << "\n\n" <<
|
||||
termcolor::green << argv[1] << arguments_string << termcolor::reset << "\n" <<
|
||||
termcolor::yellow << (!options_string.empty() ? "\nOptions\n" : "") <<
|
||||
termcolor::yellow << (!options_string.empty() ? "\nOptions\n\n" : "") <<
|
||||
termcolor::reset << termcolor::cyan << options_string << termcolor::reset;
|
||||
|
||||
std::cout << command_string.str() << std::endl;
|
||||
|
||||
+97
-37
@@ -45,6 +45,7 @@
|
||||
#include "eq_packet_structs.h"
|
||||
#include "extprofile.h"
|
||||
#include "string_util.h"
|
||||
#include "database_schema.h"
|
||||
|
||||
extern Client client;
|
||||
|
||||
@@ -338,6 +339,21 @@ bool Database::ReserveName(uint32 account_id, char* name) {
|
||||
query = StringFormat("INSERT INTO `character_data` SET `account_id` = %i, `name` = '%s'", account_id, name);
|
||||
results = QueryDatabase(query);
|
||||
if (!results.Success() || results.ErrorMessage() != ""){ return false; }
|
||||
|
||||
// Put character into the default guild if rule is being used.
|
||||
int guild_id = RuleI(Character, DefaultGuild);
|
||||
|
||||
if (guild_id != 0) {
|
||||
int character_id=results.LastInsertedID();
|
||||
if (character_id > -1) {
|
||||
query = StringFormat("INSERT INTO `guild_members` SET `char_id` = %i, `guild_id` = '%i'", character_id, guild_id);
|
||||
results = QueryDatabase(query);
|
||||
if (!results.Success() || results.ErrorMessage() != ""){
|
||||
LogInfo("Could not put character [{}] into default Guild", name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -371,6 +387,7 @@ bool Database::DeleteCharacter(char *character_name) {
|
||||
UPDATE
|
||||
character_data
|
||||
SET
|
||||
name = SUBSTRING(CONCAT(name, '-deleted-', UNIX_TIMESTAMP()), 1, 64),
|
||||
deleted_at = NOW()
|
||||
WHERE
|
||||
id = '{}'
|
||||
@@ -385,46 +402,18 @@ bool Database::DeleteCharacter(char *character_name) {
|
||||
|
||||
LogInfo("DeleteCharacter | Character [{}] ({}) is being [{}]", character_name, character_id, delete_type);
|
||||
|
||||
query = StringFormat("DELETE FROM `quest_globals` WHERE `charid` = '%d'", character_id); QueryDatabase(query);
|
||||
query = StringFormat("DELETE FROM `character_activities` WHERE `charid` = '%d'", character_id); QueryDatabase(query);
|
||||
query = StringFormat("DELETE FROM `character_enabledtasks` WHERE `charid` = '%d'", character_id); QueryDatabase(query);
|
||||
query = StringFormat("DELETE FROM `character_tasks` WHERE `charid` = '%d'", character_id); QueryDatabase(query);
|
||||
query = StringFormat("DELETE FROM `completed_tasks` WHERE `charid` = '%d'", character_id); QueryDatabase(query);
|
||||
query = StringFormat("DELETE FROM `friends` WHERE `charid` = '%d'", character_id); QueryDatabase(query);
|
||||
query = StringFormat("DELETE FROM `mail` WHERE `charid` = '%d'", character_id); QueryDatabase(query);
|
||||
query = StringFormat("DELETE FROM `timers` WHERE `char_id` = '%d'", character_id); QueryDatabase(query);
|
||||
query = StringFormat("DELETE FROM `inventory` WHERE `charid` = '%d'", character_id); QueryDatabase(query);
|
||||
query = StringFormat("DELETE FROM `char_recipe_list` WHERE `char_id` = '%d'", character_id); QueryDatabase(query);
|
||||
query = StringFormat("DELETE FROM `adventure_stats` WHERE `player_id` ='%d'", character_id); QueryDatabase(query);
|
||||
query = StringFormat("DELETE FROM `zone_flags` WHERE `charID` = '%d'", character_id); QueryDatabase(query);
|
||||
query = StringFormat("DELETE FROM `titles` WHERE `char_id` = '%d'", character_id); QueryDatabase(query);
|
||||
query = StringFormat("DELETE FROM `player_titlesets` WHERE `char_id` = '%d'", character_id); QueryDatabase(query);
|
||||
query = StringFormat("DELETE FROM `keyring` WHERE `char_id` = '%d'", character_id); QueryDatabase(query);
|
||||
query = StringFormat("DELETE FROM `faction_values` WHERE `char_id` = '%d'", character_id); QueryDatabase(query);
|
||||
query = StringFormat("DELETE FROM `instance_list_player` WHERE `charid` = '%d'", character_id); QueryDatabase(query);
|
||||
query = StringFormat("DELETE FROM `character_data` WHERE `id` = '%d'", character_id); QueryDatabase(query);
|
||||
query = StringFormat("DELETE FROM `character_skills` WHERE `id` = %u", character_id); QueryDatabase(query);
|
||||
query = StringFormat("DELETE FROM `character_languages` WHERE `id` = %u", character_id); QueryDatabase(query);
|
||||
query = StringFormat("DELETE FROM `character_bind` WHERE `id` = %u", character_id); QueryDatabase(query);
|
||||
query = StringFormat("DELETE FROM `character_alternate_abilities` WHERE `id` = %u", character_id); QueryDatabase(query);
|
||||
query = StringFormat("DELETE FROM `character_currency` WHERE `id` = %u", character_id); QueryDatabase(query);
|
||||
query = StringFormat("DELETE FROM `character_data` WHERE `id` = %u", character_id); QueryDatabase(query);
|
||||
query = StringFormat("DELETE FROM `character_spells` WHERE `id` = %u", character_id); QueryDatabase(query);
|
||||
query = StringFormat("DELETE FROM `character_memmed_spells` WHERE `id` = %u", character_id); QueryDatabase(query);
|
||||
query = StringFormat("DELETE FROM `character_disciplines` WHERE `id` = %u", character_id); QueryDatabase(query);
|
||||
query = StringFormat("DELETE FROM `character_material` WHERE `id` = %u", character_id); QueryDatabase(query);
|
||||
query = StringFormat("DELETE FROM `character_tribute` WHERE `id` = %u", character_id); QueryDatabase(query);
|
||||
query = StringFormat("DELETE FROM `character_bandolier` WHERE `id` = %u", character_id); QueryDatabase(query);
|
||||
query = StringFormat("DELETE FROM `character_potionbelt` WHERE `id` = %u", character_id); QueryDatabase(query);
|
||||
query = StringFormat("DELETE FROM `character_inspect_messages` WHERE `id` = %u", character_id); QueryDatabase(query);
|
||||
query = StringFormat("DELETE FROM `character_leadership_abilities` WHERE `id` = %u", character_id); QueryDatabase(query);
|
||||
query = StringFormat("DELETE FROM `character_alt_currency` WHERE `char_id` = '%d'", character_id); QueryDatabase(query);
|
||||
for (const auto& iter : DatabaseSchema::GetCharacterTables()) {
|
||||
std::string table_name = iter.first;
|
||||
std::string character_id_column_name = iter.second;
|
||||
|
||||
QueryDatabase(fmt::format("DELETE FROM {} WHERE {} = {}", table_name, character_id_column_name, character_id));
|
||||
}
|
||||
|
||||
#ifdef BOTS
|
||||
query = StringFormat("DELETE FROM `guild_members` WHERE `char_id` = '%d' AND GetMobTypeById(%i) = 'C'", character_id); // note: only use of GetMobTypeById()
|
||||
#else
|
||||
query = StringFormat("DELETE FROM `guild_members` WHERE `char_id` = '%d'", character_id);
|
||||
#endif
|
||||
QueryDatabase(query);
|
||||
#endif
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -936,6 +925,38 @@ void Database::GetCharName(uint32 char_id, char* name) {
|
||||
}
|
||||
}
|
||||
|
||||
const char* Database::GetCharNameByID(uint32 char_id) {
|
||||
std::string query = fmt::format("SELECT `name` FROM `character_data` WHERE id = {}", char_id);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (results.RowCount() == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
return row[0];
|
||||
}
|
||||
|
||||
const char* Database::GetNPCNameByID(uint32 npc_id) {
|
||||
std::string query = fmt::format("SELECT `name` FROM `npc_types` WHERE id = {}", npc_id);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (results.RowCount() == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
return row[0];
|
||||
}
|
||||
|
||||
bool Database::LoadVariables() {
|
||||
auto results = QueryDatabase(StringFormat("SELECT varname, value, unix_timestamp() FROM variables where unix_timestamp(ts) >= %d", varcache.last_update));
|
||||
|
||||
@@ -2169,6 +2190,44 @@ uint32 Database::GetGuildIDByCharID(uint32 character_id)
|
||||
return atoi(row[0]);
|
||||
}
|
||||
|
||||
uint32 Database::GetGroupIDByCharID(uint32 character_id)
|
||||
{
|
||||
std::string query = fmt::format(
|
||||
SQL(
|
||||
SELECT groupid
|
||||
FROM group_id
|
||||
WHERE charid = '{}'
|
||||
),
|
||||
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]);
|
||||
}
|
||||
|
||||
uint32 Database::GetRaidIDByCharID(uint32 character_id) {
|
||||
std::string query = fmt::format(
|
||||
SQL(
|
||||
SELECT raidid
|
||||
FROM raid_members
|
||||
WHERE charid = '{}'
|
||||
),
|
||||
character_id
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
return atoi(row[0]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param log_settings
|
||||
*/
|
||||
@@ -2346,3 +2405,4 @@ int Database::GetInstanceID(uint32 char_id, uint32 zone_id) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+8
-4
@@ -133,9 +133,13 @@ public:
|
||||
uint32 GetCharacterID(const char *name);
|
||||
uint32 GetCharacterInfo(const char* iName, uint32* oAccID = 0, uint32* oZoneID = 0, uint32* oInstanceID = 0, float* oX = 0, float* oY = 0, float* oZ = 0);
|
||||
uint32 GetGuildIDByCharID(uint32 char_id);
|
||||
uint32 GetGroupIDByCharID(uint32 char_id);
|
||||
uint32 GetRaidIDByCharID(uint32 char_id);
|
||||
|
||||
void GetAccountName(uint32 accountid, char* name, uint32* oLSAccountID = 0);
|
||||
void GetCharName(uint32 char_id, char* name);
|
||||
const char *GetCharNameByID(uint32 char_id);
|
||||
const char *GetNPCNameByID(uint32 npc_id);
|
||||
void LoginIP(uint32 AccountID, const char* LoginIP);
|
||||
|
||||
/* Instancing */
|
||||
@@ -192,19 +196,19 @@ public:
|
||||
|
||||
void GetAccountFromID(uint32 id, char* oAccountName, int16* oStatus);
|
||||
void SetAgreementFlag(uint32 acctid);
|
||||
|
||||
|
||||
int GetIPExemption(std::string account_ip);
|
||||
|
||||
int GetInstanceID(uint32 char_id, uint32 zone_id);
|
||||
|
||||
|
||||
/* Groups */
|
||||
|
||||
|
||||
char* GetGroupLeaderForLogin(const char* name,char* leaderbuf);
|
||||
char* GetGroupLeadershipInfo(uint32 gid, char* leaderbuf, char* maintank = nullptr, char* assist = nullptr, char* puller = nullptr, char *marknpc = nullptr, char *mentoree = nullptr, int *mentor_percent = nullptr, GroupLeadershipAA_Struct* GLAA = nullptr);
|
||||
|
||||
|
||||
uint32 GetGroupID(const char* name);
|
||||
|
||||
|
||||
void ClearGroup(uint32 gid = 0);
|
||||
void ClearGroupLeader(uint32 gid = 0);
|
||||
void SetGroupID(const char* name, uint32 id, uint32 charid, uint32 ismerc = false);
|
||||
|
||||
@@ -0,0 +1,569 @@
|
||||
/**
|
||||
* 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 <string>
|
||||
#include <cstdio>
|
||||
#include <iterator>
|
||||
#include "database_dump_service.h"
|
||||
#include "../eqemu_logsys.h"
|
||||
#include "../string_util.h"
|
||||
#include "../eqemu_config.h"
|
||||
#include "../database_schema.h"
|
||||
#include "../file_util.h"
|
||||
|
||||
#include <ctime>
|
||||
|
||||
#if _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
#endif
|
||||
|
||||
#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
|
||||
*/
|
||||
bool DatabaseDumpService::IsMySQLInstalled()
|
||||
{
|
||||
std::string version_output = GetMySQLVersion();
|
||||
|
||||
return version_output.find("mysql") != std::string::npos && version_output.find("Ver") != std::string::npos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Linux
|
||||
* @return bool
|
||||
*/
|
||||
bool DatabaseDumpService::IsTarAvailable()
|
||||
{
|
||||
std::string version_output = execute("tar --version");
|
||||
|
||||
return version_output.find("GNU tar") != std::string::npos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Windows
|
||||
* @return bool
|
||||
*/
|
||||
bool DatabaseDumpService::Is7ZipAvailable()
|
||||
{
|
||||
std::string version_output = execute("7z --help");
|
||||
|
||||
return version_output.find("7-Zip") != std::string::npos;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
bool DatabaseDumpService::HasCompressionBinary()
|
||||
{
|
||||
return IsTarAvailable() || Is7ZipAvailable();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
std::string DatabaseDumpService::GetMySQLVersion()
|
||||
{
|
||||
std::string version_output = execute("mysql --version");
|
||||
|
||||
return trim(version_output);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
std::string DatabaseDumpService::GetBaseMySQLDumpCommand()
|
||||
{
|
||||
auto config = EQEmuConfig::get();
|
||||
|
||||
return fmt::format(
|
||||
"mysqldump -u {} -p{} -h {} {}",
|
||||
config->DatabaseUsername,
|
||||
config->DatabasePassword,
|
||||
config->DatabaseHost,
|
||||
config->DatabaseDB
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
std::string DatabaseDumpService::GetPlayerTablesList()
|
||||
{
|
||||
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::GetLoginTableList()
|
||||
{
|
||||
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 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 tables_list;
|
||||
|
||||
std::vector<std::string> tables = DatabaseSchema::GetServerTables();
|
||||
for (const auto &table : tables) {
|
||||
tables_list += table + " ";
|
||||
}
|
||||
|
||||
tables = DatabaseSchema::GetVersionTables();
|
||||
for (const auto &table : tables) {
|
||||
tables_list += table + " ";
|
||||
}
|
||||
|
||||
return trim(tables_list);
|
||||
}
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
std::string DatabaseDumpService::GetStateTablesList()
|
||||
{
|
||||
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 tables_list;
|
||||
|
||||
std::vector<std::string> tables = DatabaseSchema::GetContentTables();
|
||||
for (const auto &table : tables) {
|
||||
tables_list += table + " ";
|
||||
}
|
||||
|
||||
return trim(tables_list);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
std::string GetDumpDate()
|
||||
{
|
||||
|
||||
time_t now = time(nullptr);
|
||||
struct tm time_struct{};
|
||||
char buf[80];
|
||||
time_struct = *localtime(&now);
|
||||
strftime(buf, sizeof(buf), "%Y-%m-%d", &time_struct);
|
||||
|
||||
std::string time = buf;
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
std::string DatabaseDumpService::GetSetDumpPath()
|
||||
{
|
||||
return !GetDumpPath().empty() ? GetDumpPath() : DATABASE_DUMP_PATH;
|
||||
}
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
std::string DatabaseDumpService::GetDumpFileNameWithPath()
|
||||
{
|
||||
return GetSetDumpPath() + GetDumpFileName();
|
||||
}
|
||||
|
||||
void DatabaseDumpService::Dump()
|
||||
{
|
||||
if (!IsMySQLInstalled()) {
|
||||
LogError("MySQL is not installed; Please check your PATH for a valid MySQL installation");
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsDumpDropTableSyntaxOnly()) {
|
||||
SetDumpOutputToConsole(true);
|
||||
}
|
||||
|
||||
if (IsDumpOutputToConsole()) {
|
||||
LogSys.SilenceConsoleLogging();
|
||||
}
|
||||
|
||||
LogInfo("MySQL installed [{}]", GetMySQLVersion());
|
||||
|
||||
SetDumpFileName(EQEmuConfig::get()->DatabaseDB + '-' + GetDumpDate());
|
||||
|
||||
auto config = EQEmuConfig::get();
|
||||
|
||||
LogInfo(
|
||||
"Database [{}] Host [{}] Username [{}]",
|
||||
config->DatabaseDB,
|
||||
config->DatabaseHost,
|
||||
config->DatabaseUsername
|
||||
);
|
||||
|
||||
std::string options = "--allow-keywords --extended-insert";
|
||||
|
||||
if (IsDumpWithNoData()) {
|
||||
options += " --no-data";
|
||||
}
|
||||
|
||||
if (!IsDumpTableLock()) {
|
||||
options += " --skip-lock-tables";
|
||||
}
|
||||
|
||||
std::string tables_to_dump;
|
||||
std::string dump_descriptor;
|
||||
|
||||
if (!IsDumpAllTables()) {
|
||||
if (IsDumpPlayerTables()) {
|
||||
tables_to_dump += GetPlayerTablesList() + " ";
|
||||
dump_descriptor += "-player";
|
||||
}
|
||||
|
||||
if (IsDumpSystemTables()) {
|
||||
tables_to_dump += GetSystemTablesList() + " ";
|
||||
dump_descriptor += "-system";
|
||||
}
|
||||
|
||||
if (IsDumpStateTables()) {
|
||||
tables_to_dump += GetStateTablesList() + " ";
|
||||
dump_descriptor += "-state";
|
||||
}
|
||||
|
||||
if (IsDumpContentTables()) {
|
||||
tables_to_dump += GetContentTablesList() + " ";
|
||||
dump_descriptor += "-content";
|
||||
}
|
||||
|
||||
if (IsDumpLoginServerTables()) {
|
||||
tables_to_dump += GetLoginTableList() + " ";
|
||||
dump_descriptor += "-login";
|
||||
}
|
||||
|
||||
if (IsDumpQueryServerTables()) {
|
||||
tables_to_dump += GetQueryServTables();
|
||||
dump_descriptor += "-queryserv";
|
||||
}
|
||||
}
|
||||
|
||||
if (!dump_descriptor.empty()) {
|
||||
SetDumpFileName(GetDumpFileName() + dump_descriptor);
|
||||
}
|
||||
|
||||
/**
|
||||
* If we are dumping to stdout then we don't generate a file
|
||||
*/
|
||||
std::string pipe_file;
|
||||
if (!IsDumpOutputToConsole()) {
|
||||
pipe_file = fmt::format(" > {}.sql", GetDumpFileNameWithPath());
|
||||
}
|
||||
|
||||
std::string execute_command = fmt::format(
|
||||
"{} {} {} {}",
|
||||
GetBaseMySQLDumpCommand(),
|
||||
options,
|
||||
tables_to_dump,
|
||||
pipe_file
|
||||
);
|
||||
|
||||
if (!FileUtil::exists(GetSetDumpPath()) && !IsDumpOutputToConsole()) {
|
||||
FileUtil::mkdir(GetSetDumpPath());
|
||||
}
|
||||
|
||||
if (IsDumpDropTableSyntaxOnly()) {
|
||||
std::vector<std::string> tables = SplitString(tables_to_dump, ' ');
|
||||
|
||||
for (auto &table : tables) {
|
||||
std::cout << "DROP TABLE IF EXISTS `" << table << "`;" << std::endl;
|
||||
}
|
||||
|
||||
if (tables_to_dump.empty()) {
|
||||
std::cerr << "No tables were specified" << std::endl;
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::string execution_result = execute(execute_command, IsDumpOutputToConsole());
|
||||
if (!execution_result.empty()) {
|
||||
std::cout << execution_result;
|
||||
}
|
||||
}
|
||||
|
||||
if (!tables_to_dump.empty()) {
|
||||
LogInfo("Dumping Tables [{}]", tables_to_dump);
|
||||
}
|
||||
|
||||
LogInfo("Database dump created at [{}.sql]", GetDumpFileNameWithPath());
|
||||
|
||||
if (IsDumpWithCompression() && !IsDumpOutputToConsole()) {
|
||||
if (HasCompressionBinary()) {
|
||||
LogInfo("Compression requested... Compressing dump [{}.sql]", GetDumpFileNameWithPath());
|
||||
|
||||
if (IsTarAvailable()) {
|
||||
execute(
|
||||
fmt::format(
|
||||
"tar -zcvf {}.tar.gz -C {} {}.sql",
|
||||
GetDumpFileNameWithPath(),
|
||||
GetSetDumpPath(),
|
||||
GetDumpFileName()
|
||||
)
|
||||
);
|
||||
LogInfo("Compressed dump created at [{}.tar.gz]", GetDumpFileNameWithPath());
|
||||
}
|
||||
else if (Is7ZipAvailable()) {
|
||||
execute(
|
||||
fmt::format(
|
||||
"7z a -t7z {}.zip {}.sql",
|
||||
GetDumpFileNameWithPath(),
|
||||
GetDumpFileNameWithPath()
|
||||
)
|
||||
);
|
||||
LogInfo("Compressed dump created at [{}.zip]", GetDumpFileNameWithPath());
|
||||
}
|
||||
else {
|
||||
LogInfo("Compression requested, but no available compression binary was found");
|
||||
}
|
||||
}
|
||||
else {
|
||||
LogWarning("Compression requested but binary not found... Skipping...");
|
||||
}
|
||||
}
|
||||
|
||||
// LogDebug("[{}] dump-to-console", IsDumpOutputToConsole());
|
||||
// LogDebug("[{}] dump-path", GetSetDumpPath());
|
||||
// LogDebug("[{}] compression", (IsDumpWithCompression() ? "true" : "false"));
|
||||
// LogDebug("[{}] query-serv", (IsDumpQueryServerTables() ? "true" : "false"));
|
||||
// LogDebug("[{}] has-compression-binary", (HasCompressionBinary() ? "true" : "false"));
|
||||
// LogDebug("[{}] content", (IsDumpContentTables() ? "true" : "false"));
|
||||
// LogDebug("[{}] no-data", (IsDumpWithNoData() ? "true" : "false"));
|
||||
// LogDebug("[{}] login", (IsDumpLoginServerTables() ? "true" : "false"));
|
||||
// LogDebug("[{}] player", (IsDumpPlayerTables() ? "true" : "false"));
|
||||
// LogDebug("[{}] system", (IsDumpSystemTables() ? "true" : "false"));
|
||||
}
|
||||
|
||||
bool DatabaseDumpService::IsDumpSystemTables() const
|
||||
{
|
||||
return dump_system_tables;
|
||||
}
|
||||
|
||||
void DatabaseDumpService::SetDumpSystemTables(bool dump_system_tables)
|
||||
{
|
||||
DatabaseDumpService::dump_system_tables = dump_system_tables;
|
||||
}
|
||||
|
||||
bool DatabaseDumpService::IsDumpContentTables() const
|
||||
{
|
||||
return dump_content_tables;
|
||||
}
|
||||
|
||||
void DatabaseDumpService::SetDumpContentTables(bool dump_content_tables)
|
||||
{
|
||||
DatabaseDumpService::dump_content_tables = dump_content_tables;
|
||||
}
|
||||
|
||||
bool DatabaseDumpService::IsDumpPlayerTables() const
|
||||
{
|
||||
return dump_player_tables;
|
||||
}
|
||||
|
||||
void DatabaseDumpService::SetDumpPlayerTables(bool dump_player_tables)
|
||||
{
|
||||
DatabaseDumpService::dump_player_tables = dump_player_tables;
|
||||
}
|
||||
|
||||
bool DatabaseDumpService::IsDumpLoginServerTables() const
|
||||
{
|
||||
return dump_login_server_tables;
|
||||
}
|
||||
|
||||
void DatabaseDumpService::SetDumpLoginServerTables(bool dump_login_server_tables)
|
||||
{
|
||||
DatabaseDumpService::dump_login_server_tables = dump_login_server_tables;
|
||||
}
|
||||
|
||||
bool DatabaseDumpService::IsDumpWithNoData() const
|
||||
{
|
||||
return dump_with_no_data;
|
||||
}
|
||||
|
||||
void DatabaseDumpService::SetDumpWithNoData(bool dump_with_no_data)
|
||||
{
|
||||
DatabaseDumpService::dump_with_no_data = dump_with_no_data;
|
||||
}
|
||||
|
||||
bool DatabaseDumpService::IsDumpAllTables() const
|
||||
{
|
||||
return dump_all_tables;
|
||||
}
|
||||
|
||||
void DatabaseDumpService::SetDumpAllTables(bool dump_all_tables)
|
||||
{
|
||||
DatabaseDumpService::dump_all_tables = dump_all_tables;
|
||||
}
|
||||
|
||||
bool DatabaseDumpService::IsDumpTableLock() const
|
||||
{
|
||||
return dump_table_lock;
|
||||
}
|
||||
|
||||
void DatabaseDumpService::SetDumpTableLock(bool dump_table_lock)
|
||||
{
|
||||
DatabaseDumpService::dump_table_lock = dump_table_lock;
|
||||
}
|
||||
|
||||
bool DatabaseDumpService::IsDumpWithCompression() const
|
||||
{
|
||||
return dump_with_compression;
|
||||
}
|
||||
|
||||
void DatabaseDumpService::SetDumpWithCompression(bool dump_with_compression)
|
||||
{
|
||||
DatabaseDumpService::dump_with_compression = dump_with_compression;
|
||||
}
|
||||
|
||||
const std::string &DatabaseDumpService::GetDumpPath() const
|
||||
{
|
||||
return dump_path;
|
||||
}
|
||||
|
||||
void DatabaseDumpService::SetDumpPath(const std::string &dump_path)
|
||||
{
|
||||
DatabaseDumpService::dump_path = dump_path;
|
||||
}
|
||||
|
||||
void DatabaseDumpService::SetDumpFileName(const std::string &dump_file_name)
|
||||
{
|
||||
DatabaseDumpService::dump_file_name = dump_file_name;
|
||||
}
|
||||
|
||||
const std::string &DatabaseDumpService::GetDumpFileName() const
|
||||
{
|
||||
return dump_file_name;
|
||||
}
|
||||
|
||||
bool DatabaseDumpService::IsDumpQueryServerTables() const
|
||||
{
|
||||
return dump_query_server_tables;
|
||||
}
|
||||
|
||||
void DatabaseDumpService::SetDumpQueryServerTables(bool dump_query_server_tables)
|
||||
{
|
||||
DatabaseDumpService::dump_query_server_tables = dump_query_server_tables;
|
||||
}
|
||||
|
||||
bool DatabaseDumpService::IsDumpOutputToConsole() const
|
||||
{
|
||||
return dump_output_to_console;
|
||||
}
|
||||
|
||||
void DatabaseDumpService::SetDumpOutputToConsole(bool dump_output_to_console)
|
||||
{
|
||||
DatabaseDumpService::dump_output_to_console = dump_output_to_console;
|
||||
}
|
||||
|
||||
bool DatabaseDumpService::IsDumpDropTableSyntaxOnly() const
|
||||
{
|
||||
return dump_drop_table_syntax_only;
|
||||
}
|
||||
|
||||
void DatabaseDumpService::SetDumpDropTableSyntaxOnly(bool dump_drop_table_syntax_only)
|
||||
{
|
||||
DatabaseDumpService::dump_drop_table_syntax_only = dump_drop_table_syntax_only;
|
||||
}
|
||||
|
||||
bool DatabaseDumpService::IsDumpStateTables() const
|
||||
{
|
||||
return dump_state_tables;
|
||||
}
|
||||
|
||||
void DatabaseDumpService::SetDumpStateTables(bool dump_state_tables)
|
||||
{
|
||||
DatabaseDumpService::dump_state_tables = dump_state_tables;
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_DATABASE_DUMP_SERVICE_H
|
||||
#define EQEMU_DATABASE_DUMP_SERVICE_H
|
||||
|
||||
|
||||
class DatabaseDumpService {
|
||||
public:
|
||||
void Dump();
|
||||
bool IsDumpAllTables() const;
|
||||
void SetDumpAllTables(bool dump_all_tables);
|
||||
bool IsDumpWithNoData() const;
|
||||
void SetDumpWithNoData(bool dump_with_no_data);
|
||||
bool IsDumpSystemTables() const;
|
||||
void SetDumpSystemTables(bool dump_system_tables);
|
||||
bool IsDumpContentTables() const;
|
||||
void SetDumpContentTables(bool dump_content_tables);
|
||||
bool IsDumpPlayerTables() const;
|
||||
void SetDumpPlayerTables(bool dump_player_tables);
|
||||
bool IsDumpLoginServerTables() const;
|
||||
void SetDumpLoginServerTables(bool dump_login_server_tables);
|
||||
bool IsDumpTableLock() const;
|
||||
void SetDumpTableLock(bool dump_table_lock);
|
||||
bool IsDumpWithCompression() const;
|
||||
void SetDumpWithCompression(bool dump_with_compression);
|
||||
const std::string &GetDumpPath() const;
|
||||
void SetDumpPath(const std::string &dump_path);
|
||||
const std::string &GetDumpFileName() const;
|
||||
void SetDumpFileName(const std::string &dump_file_name);
|
||||
bool IsDumpQueryServerTables() const;
|
||||
void SetDumpQueryServerTables(bool dump_query_server_tables);
|
||||
bool IsDumpOutputToConsole() const;
|
||||
void SetDumpOutputToConsole(bool dump_output_to_console);
|
||||
bool IsDumpDropTableSyntaxOnly() const;
|
||||
void SetDumpDropTableSyntaxOnly(bool dump_drop_table_syntax_only);
|
||||
bool IsDumpStateTables() const;
|
||||
void SetDumpStateTables(bool dump_state_tables);
|
||||
|
||||
private:
|
||||
bool dump_all_tables = false;
|
||||
bool dump_state_tables = false;
|
||||
bool dump_system_tables = false;
|
||||
bool dump_content_tables = false;
|
||||
bool dump_player_tables = false;
|
||||
bool dump_query_server_tables = false;
|
||||
bool dump_login_server_tables = false;
|
||||
bool dump_with_no_data = false;
|
||||
bool dump_table_lock = false;
|
||||
bool dump_with_compression = false;
|
||||
bool dump_output_to_console = false;
|
||||
bool dump_drop_table_syntax_only = false;
|
||||
std::string dump_path;
|
||||
std::string dump_file_name;
|
||||
|
||||
std::string execute(const std::string &cmd, bool return_result);
|
||||
bool IsMySQLInstalled();
|
||||
std::string GetMySQLVersion();
|
||||
std::string GetBaseMySQLDumpCommand();
|
||||
std::string GetPlayerTablesList();
|
||||
std::string GetSystemTablesList();
|
||||
std::string GetStateTablesList();
|
||||
std::string GetContentTablesList();
|
||||
std::string GetLoginTableList();
|
||||
bool IsTarAvailable();
|
||||
bool Is7ZipAvailable();
|
||||
bool HasCompressionBinary();
|
||||
std::string GetDumpFileNameWithPath();
|
||||
std::string GetSetDumpPath();
|
||||
std::string GetQueryServTables();
|
||||
};
|
||||
|
||||
|
||||
#endif //EQEMU_DATABASE_DUMP_SERVICE_H
|
||||
@@ -97,42 +97,53 @@ bool Database::CheckInstanceExists(uint16 instance_id) {
|
||||
bool Database::CheckInstanceExpired(uint16 instance_id)
|
||||
{
|
||||
|
||||
int32 start_time = 0;
|
||||
int32 duration = 0;
|
||||
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);
|
||||
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())
|
||||
if (!results.Success()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (results.RowCount() == 0)
|
||||
if (results.RowCount() == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
start_time = atoi(row[0]);
|
||||
duration = atoi(row[1]);
|
||||
start_time = atoi(row[0]);
|
||||
duration = atoi(row[1]);
|
||||
never_expires = atoi(row[2]);
|
||||
|
||||
if (never_expires == 1)
|
||||
if (never_expires == 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
timeval tv;
|
||||
timeval tv{};
|
||||
gettimeofday(&tv, nullptr);
|
||||
|
||||
if ((start_time + duration) <= tv.tv_sec)
|
||||
return true;
|
||||
return (start_time + duration) <= tv.tv_sec;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Database::CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version, uint32 duration)
|
||||
{
|
||||
std::string query = StringFormat("INSERT INTO instance_list (id, zone, version, start_time, duration)"
|
||||
" values(%lu, %lu, %lu, UNIX_TIMESTAMP(), %lu)",
|
||||
(unsigned long)instance_id, (unsigned long)zone_id, (unsigned long)version, (unsigned long)duration);
|
||||
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
|
||||
);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
return results.Success();
|
||||
@@ -140,66 +151,84 @@ bool Database::CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version
|
||||
|
||||
bool Database::GetUnusedInstanceID(uint16 &instance_id)
|
||||
{
|
||||
uint32 count = RuleI(Zone, ReservedInstances);
|
||||
uint32 max = 65535;
|
||||
uint32 max_reserved_instance_id = RuleI(Instances, ReservedInstances);
|
||||
uint32 max = 32000;
|
||||
|
||||
std::string query = StringFormat(
|
||||
"SELECT IFNULL(MAX(id),%u)+1 FROM instance_list WHERE id > %u",
|
||||
max_reserved_instance_id,
|
||||
max_reserved_instance_id
|
||||
);
|
||||
|
||||
if (RuleB(Instances, RecycleInstanceIds)) {
|
||||
query = (
|
||||
SQL(
|
||||
SELECT i.id + 1 AS next_available
|
||||
FROM instance_list i
|
||||
LEFT JOIN instance_list i2 ON i2.id = i.id + 1
|
||||
WHERE i2.id IS NULL
|
||||
ORDER BY i.id
|
||||
LIMIT 0, 1;
|
||||
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
std::string query = StringFormat("SELECT IFNULL(MAX(id),%u)+1 FROM instance_list WHERE id > %u", count, count);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
{
|
||||
if (!results.Success()) {
|
||||
instance_id = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (results.RowCount() == 0)
|
||||
{
|
||||
instance_id = 0;
|
||||
return false;
|
||||
if (results.RowCount() == 0) {
|
||||
instance_id = max_reserved_instance_id;
|
||||
return true;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
if (atoi(row[0]) <= max)
|
||||
{
|
||||
if (atoi(row[0]) <= max) {
|
||||
instance_id = atoi(row[0]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
query = StringFormat("SELECT id FROM instance_list where id > %u ORDER BY id", count);
|
||||
if (instance_id < max_reserved_instance_id) {
|
||||
instance_id = max_reserved_instance_id;
|
||||
return true;
|
||||
}
|
||||
|
||||
query = StringFormat("SELECT id FROM instance_list where id > %u ORDER BY id", max_reserved_instance_id);
|
||||
results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
{
|
||||
if (!results.Success()) {
|
||||
instance_id = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (results.RowCount() == 0)
|
||||
{
|
||||
if (results.RowCount() == 0) {
|
||||
instance_id = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
count++;
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
{
|
||||
if (count < atoi(row[0]))
|
||||
{
|
||||
instance_id = count;
|
||||
max_reserved_instance_id++;
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
if (max_reserved_instance_id < atoi(row[0])) {
|
||||
instance_id = max_reserved_instance_id;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (count > max)
|
||||
{
|
||||
if (max_reserved_instance_id > max) {
|
||||
instance_id = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
count++;
|
||||
max_reserved_instance_id++;
|
||||
}
|
||||
|
||||
instance_id = count;
|
||||
instance_id = max_reserved_instance_id;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -548,17 +577,36 @@ void Database::GetCharactersInInstance(uint16 instance_id, std::list<uint32> &ch
|
||||
|
||||
void Database::PurgeExpiredInstances()
|
||||
{
|
||||
std::string query("SELECT id FROM instance_list where (start_time+duration) <= UNIX_TIMESTAMP() and never_expires = 0");
|
||||
|
||||
/**
|
||||
* 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
|
||||
* has not been fully de-allocated
|
||||
*/
|
||||
std::string query =
|
||||
SQL(
|
||||
SELECT
|
||||
id
|
||||
FROM
|
||||
instance_list
|
||||
where
|
||||
(start_time + duration) <= (UNIX_TIMESTAMP() - 86400)
|
||||
and never_expires = 0
|
||||
);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
if (!results.Success()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (results.RowCount() == 0)
|
||||
if (results.RowCount() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
DeleteInstance(atoi(row[0]));
|
||||
}
|
||||
}
|
||||
|
||||
void Database::SetInstanceDuration(uint16 instance_id, uint32 new_duration)
|
||||
@@ -566,4 +614,4 @@ void Database::SetInstanceDuration(uint16 instance_id, uint32 new_duration)
|
||||
std::string query = StringFormat("UPDATE `instance_list` SET start_time=UNIX_TIMESTAMP(), "
|
||||
"duration=%u WHERE id=%u", new_duration, instance_id);
|
||||
auto results = QueryDatabase(query);
|
||||
}
|
||||
}
|
||||
|
||||
+107
-33
@@ -22,17 +22,77 @@
|
||||
#define EQEMU_DATABASE_SCHEMA_H
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
namespace DatabaseSchema {
|
||||
|
||||
/**
|
||||
* Gets player tables
|
||||
* Character-specific tables
|
||||
*
|
||||
* Does not included related meta-data tables such as 'guilds', 'accounts'
|
||||
* @return
|
||||
*/
|
||||
static std::map<std::string, std::string> GetCharacterTables()
|
||||
{
|
||||
return {
|
||||
{"adventure_stats", "player_id"},
|
||||
{"buyer", "charid"},
|
||||
{"char_recipe_list", "char_id"},
|
||||
{"character_activities", "charid"},
|
||||
{"character_alt_currency", "char_id"},
|
||||
{"character_alternate_abilities", "id"},
|
||||
{"character_auras", "id"},
|
||||
{"character_bandolier", "id"},
|
||||
{"character_bind", "id"},
|
||||
{"character_buffs", "character_id"},
|
||||
{"character_corpses", "id"},
|
||||
{"character_currency", "id"},
|
||||
{"character_data", "id"},
|
||||
{"character_disciplines", "id"},
|
||||
{"character_enabledtasks", "charid"},
|
||||
{"character_inspect_messages", "id"},
|
||||
{"character_item_recast", "id"},
|
||||
{"character_languages", "id"},
|
||||
{"character_leadership_abilities", "id"},
|
||||
{"character_material", "id"},
|
||||
{"character_memmed_spells", "id"},
|
||||
{"character_pet_buffs", "char_id"},
|
||||
{"character_pet_info", "char_id"},
|
||||
{"character_pet_inventory", "char_id"},
|
||||
{"character_potionbelt", "id"},
|
||||
{"character_skills", "id"},
|
||||
{"character_spells", "id"},
|
||||
{"character_tasks", "charid"},
|
||||
{"character_tribute", "id"},
|
||||
{"completed_tasks", "charid"},
|
||||
{"data_buckets", "id"},
|
||||
{"faction_values", "char_id"},
|
||||
{"friends", "charid"},
|
||||
{"guild_members", "char_id"},
|
||||
{"guilds", "id"},
|
||||
{"instance_list_player", "id"},
|
||||
{"inventory", "charid"},
|
||||
{"inventory_snapshots", "charid"},
|
||||
{"keyring", "char_id"},
|
||||
{"mail", "charid"},
|
||||
{"player_titlesets", "char_id"},
|
||||
{"quest_globals", "charid"},
|
||||
{"timers", "char_id"},
|
||||
{"titles", "char_id"},
|
||||
{"trader", "char_id"},
|
||||
{"zone_flags", "charID"}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Gets all player and meta-data tables
|
||||
* @note These tables have no content in the PEQ daily dump
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
static std::vector<std::string> GetPlayerTables()
|
||||
{
|
||||
std::vector<std::string> tables = {
|
||||
return {
|
||||
"account",
|
||||
"account_ip",
|
||||
"account_flags",
|
||||
@@ -70,6 +130,7 @@ namespace DatabaseSchema {
|
||||
"character_tribute",
|
||||
"completed_tasks",
|
||||
"data_buckets",
|
||||
"discovered_items",
|
||||
"faction_values",
|
||||
"friends",
|
||||
"guild_bank",
|
||||
@@ -82,17 +143,18 @@ namespace DatabaseSchema {
|
||||
"inventory_snapshots",
|
||||
"keyring",
|
||||
"mail",
|
||||
"petitions",
|
||||
"player_titlesets",
|
||||
"quest_globals",
|
||||
"sharedbank",
|
||||
"spell_buckets",
|
||||
"spell_globals",
|
||||
"timers",
|
||||
"titles",
|
||||
"trader",
|
||||
"trader_audit",
|
||||
"zone_flags"
|
||||
};
|
||||
|
||||
return tables;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -102,7 +164,7 @@ namespace DatabaseSchema {
|
||||
*/
|
||||
static std::vector<std::string> GetContentTables()
|
||||
{
|
||||
std::vector<std::string> tables = {
|
||||
return {
|
||||
"aa_ability",
|
||||
"aa_actions",
|
||||
"aa_effects",
|
||||
@@ -176,7 +238,6 @@ namespace DatabaseSchema {
|
||||
"task_activities",
|
||||
"tasks",
|
||||
"tasksets",
|
||||
"titles",
|
||||
"tradeskill_recipe",
|
||||
"tradeskill_recipe_entries",
|
||||
"traps",
|
||||
@@ -188,8 +249,6 @@ namespace DatabaseSchema {
|
||||
"zone_server",
|
||||
"zoneserver_auth",
|
||||
};
|
||||
|
||||
return tables;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -199,34 +258,48 @@ namespace DatabaseSchema {
|
||||
*/
|
||||
static std::vector<std::string> GetServerTables()
|
||||
{
|
||||
std::vector<std::string> tables = {
|
||||
"banned_ips",
|
||||
"bugs",
|
||||
"bug_reports",
|
||||
return {
|
||||
"chatchannels",
|
||||
"command_settings",
|
||||
"db_str",
|
||||
"discovered_items",
|
||||
"eqtime",
|
||||
"eventlog",
|
||||
"gm_ips",
|
||||
"hackers",
|
||||
"ip_exemptions",
|
||||
"launcher",
|
||||
"launcher_zones",
|
||||
"level_exp_mods",
|
||||
"logsys_categories",
|
||||
"name_filter",
|
||||
"perl_event_export_settings",
|
||||
"petitions",
|
||||
"profanity_list",
|
||||
"reports",
|
||||
"rule_sets",
|
||||
"rule_values",
|
||||
"saylink",
|
||||
"variables",
|
||||
};
|
||||
}
|
||||
|
||||
return tables;
|
||||
/**
|
||||
* Gets QueryServer tables
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
static std::vector<std::string> GetQueryServerTables()
|
||||
{
|
||||
return {
|
||||
"qs_merchant_transaction_record",
|
||||
"qs_merchant_transaction_record_entries",
|
||||
"qs_player_aa_rate_hourly",
|
||||
"qs_player_delete_record",
|
||||
"qs_player_delete_record_entries",
|
||||
"qs_player_events",
|
||||
"qs_player_handin_record",
|
||||
"qs_player_handin_record_entries",
|
||||
"qs_player_move_record",
|
||||
"qs_player_move_record_entries",
|
||||
"qs_player_npc_kill_record",
|
||||
"qs_player_npc_kill_record_entries",
|
||||
"qs_player_speech",
|
||||
"qs_player_trade_record",
|
||||
"qs_player_trade_record_entries",
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -237,11 +310,17 @@ namespace DatabaseSchema {
|
||||
*/
|
||||
static std::vector<std::string> GetStateTables()
|
||||
{
|
||||
std::vector<std::string> tables = {
|
||||
return {
|
||||
"adventure_members",
|
||||
"chatchannels",
|
||||
"banned_ips",
|
||||
"bug_reports",
|
||||
"bugs",
|
||||
"eventlog",
|
||||
"gm_ips",
|
||||
"group_id",
|
||||
"group_leaders",
|
||||
"hackers",
|
||||
"ip_exemptions",
|
||||
"item_tick",
|
||||
"lfguild",
|
||||
"merchantlist_temp",
|
||||
@@ -249,12 +328,11 @@ namespace DatabaseSchema {
|
||||
"raid_details",
|
||||
"raid_leaders",
|
||||
"raid_members",
|
||||
"reports",
|
||||
"respawn_times",
|
||||
"spell_buckets",
|
||||
"spell_globals",
|
||||
};
|
||||
"saylink",
|
||||
|
||||
return tables;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -264,15 +342,13 @@ namespace DatabaseSchema {
|
||||
*/
|
||||
static std::vector<std::string> GetLoginTables()
|
||||
{
|
||||
std::vector<std::string> tables = {
|
||||
return {
|
||||
"login_accounts",
|
||||
"login_api_tokens",
|
||||
"login_server_admins",
|
||||
"login_server_list_types",
|
||||
"login_world_servers",
|
||||
};
|
||||
|
||||
return tables;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -282,12 +358,10 @@ namespace DatabaseSchema {
|
||||
*/
|
||||
static std::vector<std::string> GetVersionTables()
|
||||
{
|
||||
std::vector<std::string> tables = {
|
||||
return {
|
||||
"db_version",
|
||||
"inventory_versions",
|
||||
};
|
||||
|
||||
return tables;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
-10
@@ -115,14 +115,14 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo
|
||||
auto errorBuffer = new char[MYSQL_ERRMSG_SIZE];
|
||||
snprintf(errorBuffer, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(&mysql), mysql_error(&mysql));
|
||||
|
||||
/* Implement Logging at the Root */
|
||||
/**
|
||||
* Error logging
|
||||
*/
|
||||
if (mysql_errno(&mysql) > 0 && strlen(query) > 0) {
|
||||
if (LogSys.log_settings[Logs::MySQLError].is_category_enabled == 1)
|
||||
Log(Logs::General, Logs::MySQLError, "%i: %s \n %s", 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);
|
||||
|
||||
}
|
||||
|
||||
// successful query. get results.
|
||||
@@ -143,9 +143,7 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo
|
||||
|
||||
if (LogSys.log_settings[Logs::MySQLQuery].is_category_enabled == 1) {
|
||||
if ((strncasecmp(query, "select", 6) == 0)) {
|
||||
LogF(
|
||||
Logs::General,
|
||||
Logs::MySQLQuery,
|
||||
LogMySQLQuery(
|
||||
"{0} ({1} row{2} returned) ({3}s)",
|
||||
query,
|
||||
requestResult.RowCount(),
|
||||
@@ -154,9 +152,7 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo
|
||||
);
|
||||
}
|
||||
else {
|
||||
LogF(
|
||||
Logs::General,
|
||||
Logs::MySQLQuery,
|
||||
LogMySQLQuery(
|
||||
"{0} ({1} row{2} affected) ({3}s)",
|
||||
query,
|
||||
requestResult.RowsAffected(),
|
||||
|
||||
@@ -317,6 +317,15 @@ namespace EQEmu
|
||||
QuestControlGrid = -1
|
||||
};
|
||||
|
||||
namespace consent {
|
||||
enum eConsentType : uint8 {
|
||||
Normal = 0,
|
||||
Group,
|
||||
Raid,
|
||||
Guild
|
||||
};
|
||||
}; // namespace consent
|
||||
|
||||
} /*EQEmu*/
|
||||
|
||||
#endif /*COMMON_EMU_CONSTANTS_H*/
|
||||
|
||||
@@ -35,6 +35,8 @@ static const uint32 MAX_MERC = 100;
|
||||
static const uint32 MAX_MERC_GRADES = 10;
|
||||
static const uint32 MAX_MERC_STANCES = 10;
|
||||
static const uint32 BLOCKED_BUFF_COUNT = 20;
|
||||
static const uint32 QUESTREWARD_COUNT = 8;
|
||||
static const uint32 ADVANCED_LORE_LENGTH = 8192;
|
||||
|
||||
|
||||
/*
|
||||
@@ -2180,14 +2182,7 @@ struct QuestReward_Struct
|
||||
/*024*/ uint32 silver; // Gives silver to the client
|
||||
/*028*/ uint32 gold; // Gives gold to the client
|
||||
/*032*/ uint32 platinum; // Gives platinum to the client
|
||||
/*036*/ uint32 item_id;
|
||||
/*040*/ uint32 unknown040;
|
||||
/*044*/ uint32 unknown044;
|
||||
/*048*/ uint32 unknown048;
|
||||
/*052*/ uint32 unknown052;
|
||||
/*056*/ uint32 unknown056;
|
||||
/*060*/ uint32 unknown060;
|
||||
/*064*/ uint32 unknown064;
|
||||
/*036*/ int32 item_id[QUESTREWARD_COUNT]; // -1 for nothing
|
||||
/*068*/
|
||||
};
|
||||
|
||||
@@ -2972,6 +2967,12 @@ struct ItemViewRequest_Struct {
|
||||
/*046*/ char unknown046[2];
|
||||
};
|
||||
|
||||
struct ItemAdvancedLoreText_Struct {
|
||||
int32 item_id;
|
||||
char item_name[64];
|
||||
char advanced_lore[ADVANCED_LORE_LENGTH];
|
||||
};
|
||||
|
||||
struct LDONItemViewRequest_Struct {
|
||||
uint32 item_id;
|
||||
uint8 unknown004[4];
|
||||
|
||||
@@ -124,6 +124,8 @@ void EQEmuLogSys::LoadLogSettingsDefaults()
|
||||
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::HotReload].log_to_gmsay = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::HotReload].log_to_console = static_cast<uint8>(Logs::General);
|
||||
|
||||
/**
|
||||
* RFC 5424
|
||||
|
||||
@@ -113,6 +113,8 @@ namespace Logs {
|
||||
AoeCast,
|
||||
EntityManagement,
|
||||
Flee,
|
||||
Aura,
|
||||
HotReload,
|
||||
MaxCategoryID /* Don't Remove this */
|
||||
};
|
||||
|
||||
@@ -185,6 +187,8 @@ namespace Logs {
|
||||
"AOE Cast",
|
||||
"Entity Management",
|
||||
"Flee",
|
||||
"Aura",
|
||||
"HotReload",
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -551,6 +551,26 @@
|
||||
OutF(LogSys, Logs::Detail, Logs::Flee, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogAura(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Aura].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Aura, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogAuraDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Aura].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::Aura, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogHotReload(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::HotReload].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::HotReload, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogHotReloadDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::HotReload].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::HotReload, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define Log(debug_level, log_category, message, ...) do {\
|
||||
if (LogSys.log_settings[log_category].is_category_enabled == 1)\
|
||||
LogSys.Out(debug_level, log_category, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
@@ -878,6 +898,18 @@
|
||||
#define LogFleeDetail(message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
#define LogAura(message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
#define LogAuraDetail(message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
#define LogHotReload(message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
#define LogHotReloadDetail(message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
#define Log(debug_level, log_category, message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
|
||||
@@ -25,6 +25,10 @@ namespace EQ
|
||||
uv_run(&m_loop, UV_RUN_DEFAULT);
|
||||
}
|
||||
|
||||
void Shutdown() {
|
||||
uv_stop(&m_loop);
|
||||
}
|
||||
|
||||
uv_loop_t* Handle() { return &m_loop; }
|
||||
|
||||
private:
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
|
||||
Copyright (C) 2001-2020 EQEMu Development Team (http://eqemulator.net)
|
||||
Copyright (C) EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
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
|
||||
@@ -11,25 +10,18 @@
|
||||
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
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 04111-1307 USA
|
||||
*/
|
||||
|
||||
#include "../common/metric_event.h"
|
||||
#include "npc.h"
|
||||
#pragma once
|
||||
|
||||
class NPC::EventNpcStatsMonitor : EQEmu::MetricEvent {
|
||||
public:
|
||||
#include <tl/expected.hpp>
|
||||
|
||||
virtual EventType GetEventType() const { return EventType::eventNpcStatsMonitor; }
|
||||
|
||||
virtual void Process() {}
|
||||
|
||||
virtual void Flush() {}
|
||||
|
||||
virtual void Finalize() { MetricEvent::Finalize(); }
|
||||
|
||||
virtual void Expire() { MetricEvent::Expire(); }
|
||||
};
|
||||
namespace eq
|
||||
{
|
||||
using tl::expected;
|
||||
using tl::make_unexpected;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* 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
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_FILE_UTIL_H
|
||||
#define EQEMU_FILE_UTIL_H
|
||||
|
||||
|
||||
class FileUtil {
|
||||
public:
|
||||
static bool exists(const std::string &name);
|
||||
static void mkdir(const std::string& directory_name);
|
||||
};
|
||||
|
||||
|
||||
#endif //EQEMU_FILE_UTIL_H
|
||||
@@ -912,7 +912,7 @@ bool BaseGuildManager::GetEntireGuild(uint32 guild_id, std::vector<CharGuildInfo
|
||||
return(false);
|
||||
|
||||
//load up the rank info for each guild.
|
||||
std::string query = StringFormat(GuildMemberBaseQuery " WHERE g.guild_id=%d", guild_id);
|
||||
std::string query = StringFormat(GuildMemberBaseQuery " WHERE g.guild_id=%d AND c.deleted_at IS NULL", guild_id);
|
||||
auto results = m_db->QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
@@ -941,7 +941,7 @@ bool BaseGuildManager::GetCharInfo(const char *char_name, CharGuildInfo &into) {
|
||||
m_db->DoEscapeString(esc, char_name, nl);
|
||||
|
||||
//load up the rank info for each guild.
|
||||
std::string query = StringFormat(GuildMemberBaseQuery " WHERE c.name='%s'", esc);
|
||||
std::string query = StringFormat(GuildMemberBaseQuery " WHERE c.name='%s' AND c.deleted_at IS NULL", esc);
|
||||
safe_delete_array(esc);
|
||||
auto results = m_db->QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
@@ -969,9 +969,9 @@ bool BaseGuildManager::GetCharInfo(uint32 char_id, CharGuildInfo &into) {
|
||||
//load up the rank info for each guild.
|
||||
std::string query;
|
||||
#ifdef BOTS
|
||||
query = StringFormat(GuildMemberBaseQuery " WHERE c.id=%d AND c.mob_type = 'C'", char_id);
|
||||
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", char_id);
|
||||
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()) {
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
|
||||
Copyright (C) 2001-2020 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
#ifndef METRIC_EVENT_H
|
||||
#define METRIC_EVENT_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
namespace EQEmu
|
||||
{
|
||||
class MetricEvent {
|
||||
public:
|
||||
|
||||
enum class EventType {
|
||||
eventNone,
|
||||
eventNpcStatsMonitor
|
||||
};
|
||||
|
||||
MetricEvent() {
|
||||
|
||||
m_finalized = false;
|
||||
m_expired = false;
|
||||
m_event_id = 0;
|
||||
}
|
||||
|
||||
virtual EventType GetEventType() const = 0;
|
||||
|
||||
virtual void Process() = 0;
|
||||
virtual void Flush() = 0;
|
||||
|
||||
virtual void Finalize() { m_finalized = true; } // invoke MetricEvent::Finalize() inside of derived class function if not handled locally
|
||||
bool IsFinalized() const { return m_finalized; }
|
||||
|
||||
virtual void Expire() { m_finalized = true; m_expired = true; } // invoke MetricEvent::Expire() inside of derived class function if not handled locally
|
||||
bool IsExpired() const { return m_expired; }
|
||||
|
||||
void SetEventId(int value) { if (m_event_id == 0) { m_event_id = value; } }
|
||||
int GetEventId() const { return m_event_id; }
|
||||
|
||||
private:
|
||||
|
||||
bool m_finalized;
|
||||
bool m_expired;
|
||||
int m_event_id;
|
||||
};
|
||||
|
||||
} // EQEmu
|
||||
|
||||
#endif // METRIC_EVENT_H
|
||||
@@ -1,112 +0,0 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
|
||||
Copyright (C) 2001-2020 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
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 "metric_manager.h"
|
||||
#include "metric_event.h"
|
||||
|
||||
EQEmu::MetricManager::MetricManager() {
|
||||
|
||||
m_current_event_id = 0;
|
||||
}
|
||||
|
||||
void EQEmu::MetricManager::Process() {
|
||||
|
||||
for (std::list<MetricEvent*>::iterator iter = m_event_list.begin(); iter != m_event_list.end(); ) {
|
||||
|
||||
if ((*iter)->IsExpired()) {
|
||||
|
||||
iter = m_event_list.erase(iter);
|
||||
continue;
|
||||
}
|
||||
|
||||
(*iter)->Process();
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
int EQEmu::MetricManager::RegisterEvent(MetricEvent* event_object) {
|
||||
|
||||
if (event_object == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
event_object->SetEventId(get_next_event_id());
|
||||
m_event_list.push_back(event_object);
|
||||
|
||||
return event_object->GetEventId();
|
||||
}
|
||||
|
||||
void EQEmu::MetricManager::FlushAll() {
|
||||
|
||||
for (auto iter : m_event_list) {
|
||||
iter->Flush();
|
||||
}
|
||||
}
|
||||
|
||||
void EQEmu::MetricManager::FlushById(int event_id) {
|
||||
|
||||
for (auto iter : m_event_list) {
|
||||
if (iter->GetEventId() == event_id) {
|
||||
|
||||
iter->Flush();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EQEmu::MetricManager::FinalizeAll() {
|
||||
|
||||
for (auto iter : m_event_list) {
|
||||
iter->Finalize();
|
||||
}
|
||||
}
|
||||
|
||||
void EQEmu::MetricManager::FinalizeById(int event_id) {
|
||||
|
||||
for (auto iter : m_event_list) {
|
||||
if (iter->GetEventId() == event_id) {
|
||||
|
||||
iter->Finalize();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EQEmu::MetricManager::ExpireAll() {
|
||||
|
||||
for (auto iter : m_event_list) {
|
||||
iter->Expire();
|
||||
}
|
||||
}
|
||||
|
||||
void EQEmu::MetricManager::ExpireById(int event_id) {
|
||||
|
||||
for (auto iter : m_event_list) {
|
||||
if (iter->GetEventId() == event_id) {
|
||||
|
||||
iter->Expire();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int EQEmu::MetricManager::get_next_event_id() {
|
||||
|
||||
return ++m_current_event_id;
|
||||
}
|
||||
@@ -1047,12 +1047,14 @@ void EQ::Net::DaybreakConnection::Compress(Packet &p, size_t offset, size_t leng
|
||||
uint8_t new_buffer[2048] = { 0 };
|
||||
uint8_t *buffer = (uint8_t*)p.Data() + offset;
|
||||
uint32_t new_length = 0;
|
||||
bool send_uncompressed = true;
|
||||
|
||||
if (length > 30) {
|
||||
new_length = Deflate(buffer, (uint32_t)length, new_buffer + 1, 2048) + 1;
|
||||
new_buffer[0] = 0x5a;
|
||||
send_uncompressed = (new_length > length);
|
||||
}
|
||||
else {
|
||||
if (send_uncompressed) {
|
||||
memcpy(new_buffer + 1, buffer, length);
|
||||
new_buffer[0] = 0xa5;
|
||||
new_length = length + 1;
|
||||
@@ -1380,7 +1382,7 @@ void EQ::Net::DaybreakConnection::InternalQueuePacket(Packet &p, int stream_id,
|
||||
}
|
||||
|
||||
auto stream = &m_streams[stream_id];
|
||||
auto max_raw_size = m_max_packet_size - m_crc_bytes - DaybreakReliableHeader::size();
|
||||
auto max_raw_size = m_max_packet_size - m_crc_bytes - DaybreakReliableHeader::size() - 1; // -1 for compress flag
|
||||
size_t length = p.Length();
|
||||
if (length > max_raw_size) {
|
||||
DaybreakReliableFragmentHeader first_header;
|
||||
|
||||
+4
-4
@@ -89,9 +89,9 @@ namespace EQ {
|
||||
public:
|
||||
StaticPacket(void *data, size_t size) { m_data = data; m_data_length = size; m_max_data_length = size; }
|
||||
virtual ~StaticPacket() { }
|
||||
StaticPacket(const StaticPacket &o) { m_data = o.m_data; m_data_length = o.m_data_length; }
|
||||
StaticPacket(const StaticPacket &o) { m_data = o.m_data; m_data_length = o.m_data_length; m_max_data_length = o.m_max_data_length; }
|
||||
StaticPacket& operator=(const StaticPacket &o) { m_data = o.m_data; m_data_length = o.m_data_length; return *this; }
|
||||
StaticPacket(StaticPacket &&o) { m_data = o.m_data; m_data_length = o.m_data_length; }
|
||||
StaticPacket(StaticPacket &&o) noexcept { m_data = o.m_data; m_data_length = o.m_data_length; }
|
||||
|
||||
virtual const void *Data() const { return m_data; }
|
||||
virtual void *Data() { return m_data; }
|
||||
@@ -112,7 +112,7 @@ namespace EQ {
|
||||
public:
|
||||
DynamicPacket() { }
|
||||
virtual ~DynamicPacket() { }
|
||||
DynamicPacket(DynamicPacket &&o) { m_data = std::move(o.m_data); }
|
||||
DynamicPacket(DynamicPacket &&o) noexcept { m_data = std::move(o.m_data); }
|
||||
DynamicPacket(const DynamicPacket &o) { m_data = o.m_data; }
|
||||
DynamicPacket& operator=(const DynamicPacket &o) { m_data = o.m_data; return *this; }
|
||||
|
||||
@@ -127,4 +127,4 @@ namespace EQ {
|
||||
std::vector<char> m_data;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4401,7 +4401,7 @@ struct SendAA_Struct {
|
||||
/*0104*/ uint32 special_category;
|
||||
/*0108*/ uint8 shroud;
|
||||
/*0109*/ uint8 unknown109;
|
||||
/*0110*/ uint8 layonhands; // 1 for lay on hands -- doesn't seem to matter?
|
||||
/*0110*/ uint8 reset_on_death; // timer is reset on death
|
||||
/*0111*/ uint8 unknown111;
|
||||
/*0112*/ uint32 total_abilities;
|
||||
/*0116*/ AA_Ability abilities[0];
|
||||
|
||||
@@ -4341,7 +4341,7 @@ struct SendAA_Struct {
|
||||
/*0104*/ uint32 special_category;
|
||||
/*0108*/ uint8 shroud;
|
||||
/*0109*/ uint8 unknown109;
|
||||
/*0110*/ uint8 layonhands; // 1 for lay on hands -- doesn't seem to matter?
|
||||
/*0110*/ uint8 reset_on_death; // timer is reset on death
|
||||
/*0111*/ uint8 unknown111;
|
||||
/*0112*/ uint32 total_abilities;
|
||||
/*0116*/ AA_Ability abilities[0];
|
||||
|
||||
@@ -3780,7 +3780,7 @@ struct SendAA_Struct {
|
||||
/*0092*/ uint32 special_category;
|
||||
/*0096*/ uint8 shroud;
|
||||
/*0097*/ uint8 unknown97;
|
||||
/*0098*/ uint8 layonhands; // 1 for lay on hands -- doesn't seem to matter?
|
||||
/*0098*/ uint8 reset_on_death; // timer is reset on death
|
||||
/*0099*/ uint8 unknown99;
|
||||
/*0100*/ uint32 total_abilities;
|
||||
/*0104*/ AA_Ability abilities[0];
|
||||
|
||||
@@ -3704,7 +3704,7 @@ struct SendAA_Struct {
|
||||
/*0088*/ uint32 aa_expansion;
|
||||
/*0092*/ uint32 special_category;
|
||||
/*0096*/ uint8 shroud;
|
||||
/*0097*/ uint8 unknown97;
|
||||
/*0097*/ uint8 reset_on_death; // timer is reset on death -- guess
|
||||
/*0098*/ uint32 total_abilities;
|
||||
/*0102*/ AA_Ability abilities[0];
|
||||
};
|
||||
|
||||
@@ -3835,7 +3835,7 @@ struct SendAA_Struct {
|
||||
/*0092*/ uint32 special_category;
|
||||
/*0096*/ uint8 shroud;
|
||||
/*0097*/ uint8 unknown97;
|
||||
/*0098*/ uint8 layonhands; // 1 for lay on hands -- doesn't seem to matter?
|
||||
/*0098*/ uint8 reset_on_death; // timer is reset on death
|
||||
/*0099*/ uint8 unknown99;
|
||||
/*0100*/ uint32 total_abilities;
|
||||
/*0104*/ AA_Ability abilities[0];
|
||||
|
||||
+20
-2
@@ -121,6 +121,7 @@ RULE_BOOL(Character, EnableAggroMeter, true, "Enable Aggro Meter, for users with
|
||||
RULE_BOOL(Character, KeepLevelOverMax, false, "Don't delevel a character that has somehow gone over the level cap")
|
||||
RULE_INT(Character, FoodLossPerUpdate, 32, "How much food/water you lose per stamina update")
|
||||
RULE_BOOL(Character, EnableHungerPenalties, false, "being hungry/thirsty has negative effects -- it does appear normal live servers do not have penalties")
|
||||
RULE_BOOL(Character, EnableFoodRequirement, true, "if disabled, food is no longer required")
|
||||
RULE_INT(Character, BaseInstrumentSoftCap, 36, "Softcap for instrument mods, 36 commonly referred to as \"3.6\" as well")
|
||||
RULE_BOOL(Character, UseSpellFileSongCap, true, "When they removed the AA that increased the cap they removed the above and just use the spell field")
|
||||
RULE_INT(Character, BaseRunSpeedCap, 158, "Base Run Speed Cap, on live it's 158% which will give you a runspeed of 1.580 hard capped to 225")
|
||||
@@ -159,6 +160,8 @@ RULE_BOOL(Character, PetsUseReagents, true, "Pets use reagent on spells")
|
||||
RULE_BOOL(Character, DismountWater, true, "Dismount horses when entering water")
|
||||
RULE_BOOL(Character, UseNoJunkFishing, false, "Disregards junk items when fishing")
|
||||
RULE_BOOL(Character, SoftDeletes, true, "When characters are deleted in character select, they are only soft deleted")
|
||||
RULE_INT(Character, DefaultGuild, 0, "If not 0, new characters placed into the guild # indicated")
|
||||
RULE_BOOL(Character, ProcessFearedProximity, false, "Processes proximity checks when feared")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Mercs)
|
||||
@@ -195,6 +198,7 @@ RULE_INT(Skills, SwimmingStartValue, 100, "")
|
||||
RULE_BOOL(Skills, TrainSenseHeading, false, "")
|
||||
RULE_INT(Skills, SenseHeadingStartValue, 200, "")
|
||||
RULE_BOOL(Skills, SelfLanguageLearning, true, "")
|
||||
RULE_BOOL(Skills, RequireTomeHandin, false, "Disable click-to-learn and force turnin to Guild Master")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Pets)
|
||||
@@ -266,7 +270,6 @@ RULE_INT(Zone, PEQZoneDebuff1, 4454, "First debuff casted by #peqzone Default is
|
||||
RULE_INT(Zone, PEQZoneDebuff2, 2209, "Second debuff casted by #peqzone Default is Tendrils of Apathy")
|
||||
RULE_BOOL(Zone, UsePEQZoneDebuffs, true, "Will determine if #peqzone will debuff players or not when used")
|
||||
RULE_REAL(Zone, HotZoneBonus, 0.75, "")
|
||||
RULE_INT(Zone, ReservedInstances, 30, "Will reserve this many instance ids for globals... probably not a good idea to change this while a server is running")
|
||||
RULE_INT(Zone, EbonCrystalItemID, 40902, "")
|
||||
RULE_INT(Zone, RadiantCrystalItemID, 40903, "")
|
||||
RULE_BOOL(Zone, LevelBasedEXPMods, false, "Allows you to use the level_exp_mods table in consideration to your players EXP hits")
|
||||
@@ -294,6 +297,7 @@ RULE_BOOL(Pathing, Find, true, "Enable pathing for FindPerson requests from the
|
||||
RULE_BOOL(Pathing, Fear, true, "Enable pathing for fear")
|
||||
RULE_REAL(Pathing, NavmeshStepSize, 100.0f, "")
|
||||
RULE_REAL(Pathing, ShortMovementUpdateRange, 130.0f, "")
|
||||
RULE_INT(Pathing, MaxNavmeshNodes, 4092, "Max navmesh nodes in a traversable path")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Watermap)
|
||||
@@ -492,6 +496,7 @@ RULE_INT(Combat, NPCAssistCapTimer, 6000, "Time in milliseconds a NPC will take
|
||||
RULE_BOOL(Combat, UseRevampHandToHand, false, "use h2h revamped dmg/delays I believe this was implemented during SoF")
|
||||
RULE_BOOL(Combat, ClassicMasterWu, false, "classic master wu uses a random special, modern doesn't")
|
||||
RULE_INT(Combat, LevelToStopDamageCaps, 0, "1 will effectively disable them, 20 should give basically same results as old incorrect system")
|
||||
RULE_INT(Combat, LevelToStopACTwinkControl, 50, "1 will effectively disable it, 50 should give basically same results as current system")
|
||||
RULE_BOOL(Combat, ClassicNPCBackstab, false, "true disables npc facestab - npcs get normal attack if not behind")
|
||||
RULE_BOOL(Combat, UseNPCDamageClassLevelMods, true, "Uses GetClassLevelDamageMod calc in npc_scale_manager")
|
||||
RULE_BOOL(Combat, UseExtendedPoisonProcs, false, "Allow old school poisons to last until characrer zones, at a lower proc rate")
|
||||
@@ -519,10 +524,11 @@ RULE_INT(NPC, NPCToNPCAggroTimerMin, 500, "")
|
||||
RULE_INT(NPC, NPCToNPCAggroTimerMax, 6000, "")
|
||||
RULE_BOOL(NPC, UseClassAsLastName, true, "Uses class archetype as LastName for npcs with none")
|
||||
RULE_BOOL(NPC, NewLevelScaling, true, "Better level scaling, use old if new formulas would break your server")
|
||||
RULE_INT(NPC, NPCGatePercent, 5, "% at which the NPC Will attempt to gate at")
|
||||
RULE_INT(NPC, NPCGatePercent, 20, "% at which the NPC Will attempt to gate at")
|
||||
RULE_BOOL(NPC, NPCGateNearBind, false, "Will NPC attempt to gate when near bind location?")
|
||||
RULE_INT(NPC, NPCGateDistanceBind, 75, "Distance from bind before NPC will attempt to gate")
|
||||
RULE_BOOL(NPC, NPCHealOnGate, true, "Will the NPC Heal on Gate")
|
||||
RULE_BOOL(NPC, UseMeditateBasedManaRegen, false, "Based NPC ooc regen on Meditate skill")
|
||||
RULE_REAL(NPC, NPCHealOnGateAmount, 25, "How much the npc will heal on gate if enabled")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
@@ -762,6 +768,18 @@ RULE_CATEGORY(Logging)
|
||||
RULE_BOOL(Logging, PrintFileFunctionAndLine, false, "Ex: [World Server] [net.cpp::main:309] Loading variables...")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(HotReload)
|
||||
RULE_BOOL(HotReload, QuestsRepopWithReload, true, "When a hot reload is triggered, the zone will repop")
|
||||
RULE_BOOL(HotReload, QuestsRepopWhenPlayersNotInCombat, true, "When a hot reload is triggered, the zone will repop when no clients are in combat")
|
||||
RULE_BOOL(HotReload, QuestsResetTimersWithReload, true, "When a hot reload is triggered, quest timers will be reset")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Instances)
|
||||
RULE_INT(Instances, ReservedInstances, 30, "Will reserve this many instance ids for globals... probably not a good idea to change this while a server is running")
|
||||
RULE_BOOL(Instances, RecycleInstanceIds, true, "Will recycle free instance ids instead of gradually running out at 32k")
|
||||
RULE_INT(Instances, GuildHallExpirationDays, 90, "Amount of days before a Guild Hall instance expires")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
#undef RULE_CATEGORY
|
||||
#undef RULE_INT
|
||||
#undef RULE_REAL
|
||||
|
||||
+14
-4
@@ -197,7 +197,11 @@
|
||||
#define ServerOP_CZSetEntityVariableByClientName 0x4012
|
||||
#define ServerOP_UCSServerStatusRequest 0x4013
|
||||
#define ServerOP_UCSServerStatusReply 0x4014
|
||||
/* Query Server OP Codes */
|
||||
#define ServerOP_HotReloadQuests 0x4015
|
||||
|
||||
/**
|
||||
* QueryServer
|
||||
*/
|
||||
#define ServerOP_QSPlayerLogTrades 0x5010
|
||||
#define ServerOP_QSPlayerLogHandins 0x5011
|
||||
#define ServerOP_QSPlayerLogNPCKills 0x5012
|
||||
@@ -866,10 +870,12 @@ struct SpawnPlayerCorpse_Struct {
|
||||
struct ServerOP_Consent_Struct {
|
||||
char grantname[64];
|
||||
char ownername[64];
|
||||
char zonename[32];
|
||||
uint8 permission;
|
||||
uint32 zone_id;
|
||||
uint16 instance_id;
|
||||
uint32 message_string_id;
|
||||
uint8 consent_type; // 0 = normal, 1 = group, 2 = raid, 3 = guild
|
||||
uint32 consent_id;
|
||||
};
|
||||
|
||||
struct ReloadTasks_Struct {
|
||||
@@ -1349,12 +1355,16 @@ struct CZSetEntVarByClientName_Struct {
|
||||
char m_var[256];
|
||||
};
|
||||
|
||||
struct ReloadWorld_Struct{
|
||||
struct ReloadWorld_Struct {
|
||||
uint32 Option;
|
||||
};
|
||||
|
||||
struct HotReloadQuestsStruct {
|
||||
char zone_short_name[200];
|
||||
};
|
||||
|
||||
struct ServerRequestTellQueue_Struct {
|
||||
char name[64];
|
||||
char name[64];
|
||||
};
|
||||
|
||||
struct UCSServerStatus_Struct {
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
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 04111-1307 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../expected.h"
|
||||
#include "shared_memory_error.h"
|
||||
#include "shared_memory_handle.h"
|
||||
|
||||
#include <boost/interprocess/managed_mapped_file.hpp>
|
||||
#include <memory>
|
||||
|
||||
namespace eq
|
||||
{
|
||||
namespace shared
|
||||
{
|
||||
namespace detail {
|
||||
typedef boost::interprocess::managed_mapped_file::segment_manager segment_manager_t;
|
||||
typedef boost::interprocess::allocator<void, segment_manager_t> allocator;
|
||||
}
|
||||
|
||||
using allocator = detail::allocator;
|
||||
|
||||
class shared_memory
|
||||
{
|
||||
public:
|
||||
shared_memory(const std::string &path, size_t sz) {
|
||||
_path = path;
|
||||
_sz = sz;
|
||||
}
|
||||
|
||||
~shared_memory() = default;
|
||||
|
||||
template<typename Ty>
|
||||
expected<handle<Ty>, shared_memory_error> map(const std::string& key) {
|
||||
if (!_memory) {
|
||||
try {
|
||||
_memory.reset(new boost::interprocess::managed_mapped_file(boost::interprocess::open_or_create, _path.c_str(), _sz));
|
||||
}
|
||||
catch (boost::interprocess::interprocess_exception) {
|
||||
return eq::make_unexpected(shared_memory_error::error_mapping_memory);
|
||||
}
|
||||
}
|
||||
|
||||
handle<Ty> inst;
|
||||
auto ir = inst.initialize(key, _memory.get());
|
||||
if (ir) {
|
||||
return eq::expected<handle<Ty>, shared_memory_error>(inst);
|
||||
}
|
||||
else {
|
||||
return make_unexpected(ir.error());
|
||||
}
|
||||
|
||||
return expected<handle<Ty>, shared_memory_error>(inst);
|
||||
}
|
||||
|
||||
template<typename Ty, typename... Args>
|
||||
Ty construct(Args&&... args) {
|
||||
return Ty(std::forward<Args>(args)..., _memory->get_allocator<void>());
|
||||
}
|
||||
private:
|
||||
std::unique_ptr<boost::interprocess::managed_mapped_file> _memory;
|
||||
std::string _path;
|
||||
size_t _sz;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,58 +1,32 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
|
||||
Copyright (C) 2001-2020 EQEMu Development Team (http://eqemulator.net)
|
||||
Copyright (C) EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
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
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 04111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef METRIC_MANAGER_H
|
||||
#define METRIC_MANAGER_H
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
|
||||
namespace EQEmu
|
||||
namespace eq
|
||||
{
|
||||
class MetricEvent;
|
||||
|
||||
class MetricManager {
|
||||
public:
|
||||
|
||||
MetricManager();
|
||||
|
||||
void Process();
|
||||
|
||||
int RegisterEvent(MetricEvent*);
|
||||
|
||||
void FlushAll();
|
||||
void FlushById(int);
|
||||
|
||||
void FinalizeAll();
|
||||
void FinalizeById(int);
|
||||
|
||||
void ExpireAll();
|
||||
void ExpireById(int);
|
||||
|
||||
private:
|
||||
|
||||
int get_next_event_id();
|
||||
|
||||
int m_current_event_id;
|
||||
|
||||
std::list<MetricEvent*> m_event_list;
|
||||
};
|
||||
|
||||
} // EQEmu
|
||||
|
||||
#endif // METRIC_MANAGER_H
|
||||
namespace shared
|
||||
{
|
||||
enum class shared_memory_error
|
||||
{
|
||||
no_error,
|
||||
error_mapping_memory,
|
||||
error_alloc
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
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 04111-1307 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "shared_memory_error.h"
|
||||
#include "../expected.h"
|
||||
|
||||
#include <boost/interprocess/managed_mapped_file.hpp>
|
||||
#include <boost/interprocess/allocators/allocator.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace eq
|
||||
{
|
||||
namespace shared
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template<typename Ty>
|
||||
struct type_factory {
|
||||
static_assert(std::is_trivially_constructible<Ty>::value,
|
||||
"Non-specialized types must be trivially constructible, consider creating a type_factory in eq::shared::detail if you want to use this type.");
|
||||
Ty* create(const std::string& key, boost::interprocess::managed_mapped_file* mmf) {
|
||||
return mmf->find_or_construct<Ty>(key.c_str())();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template<typename Ty>
|
||||
class handle {
|
||||
public:
|
||||
handle() = default;
|
||||
~handle() = default;
|
||||
|
||||
expected<void, shared_memory_error> initialize(const std::string& key, boost::interprocess::managed_mapped_file* mmf) {
|
||||
try {
|
||||
_mmf = mmf;
|
||||
detail::type_factory<Ty> fac;
|
||||
_ptr = fac.create(key, mmf);
|
||||
return expected<void, shared_memory_error>();
|
||||
}
|
||||
catch (boost::interprocess::interprocess_exception) {
|
||||
return make_unexpected(shared_memory_error::error_mapping_memory);
|
||||
}
|
||||
}
|
||||
|
||||
operator Ty& () {
|
||||
return *_ptr;
|
||||
}
|
||||
private:
|
||||
Ty* _ptr;
|
||||
boost::interprocess::managed_mapped_file* _mmf;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
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 04111-1307 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "shared_memory_handle.h"
|
||||
|
||||
#include <boost/interprocess/containers/list.hpp>
|
||||
|
||||
namespace eq
|
||||
{
|
||||
namespace shared
|
||||
{
|
||||
template<typename Ty>
|
||||
using list = boost::interprocess::list<Ty, boost::interprocess::allocator<Ty, boost::interprocess::managed_mapped_file::segment_manager>>;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template<typename Ty>
|
||||
struct type_factory<list<Ty>>
|
||||
{
|
||||
list<Ty>* create(const std::string& key, boost::interprocess::managed_mapped_file* mmf) {
|
||||
return mmf->find_or_construct<list<Ty>>(key.c_str())(mmf->get_allocator<void>());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
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 04111-1307 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "shared_memory_handle.h"
|
||||
|
||||
#include <boost/interprocess/containers/map.hpp>
|
||||
#include <boost/interprocess/containers/flat_map.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
namespace eq
|
||||
{
|
||||
namespace shared
|
||||
{
|
||||
template<typename Ky, typename Ty>
|
||||
using unordered_map = boost::unordered_map<int,
|
||||
Ty,
|
||||
boost::hash<Ky>,
|
||||
std::equal_to<Ky>,
|
||||
boost::interprocess::allocator<std::pair<const Ky, Ty>, boost::interprocess::managed_mapped_file::segment_manager>>;
|
||||
|
||||
template<typename Ky, typename Ty>
|
||||
using map = boost::interprocess::map<Ky,
|
||||
Ty,
|
||||
std::less<Ky>,
|
||||
boost::interprocess::allocator<std::pair<const Ky, Ty>, boost::interprocess::managed_mapped_file::segment_manager>>;
|
||||
|
||||
template<typename Ky, typename Ty>
|
||||
using flat_map = boost::interprocess::flat_map<Ky,
|
||||
Ty,
|
||||
std::less<Ky>,
|
||||
boost::interprocess::allocator<std::pair<const Ky, Ty>, boost::interprocess::managed_mapped_file::segment_manager>>;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template<typename Ky, typename Ty>
|
||||
struct type_factory<unordered_map<Ky, Ty>>
|
||||
{
|
||||
unordered_map<Ky, Ty>* create(const std::string& key, boost::interprocess::managed_mapped_file* mmf) {
|
||||
return mmf->find_or_construct<unordered_map<Ky, Ty>>(key.c_str())(3, boost::hash<Ky>(), std::equal_to<Ky>(), mmf->get_allocator<void>());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ky, typename Ty>
|
||||
struct type_factory<map<Ky, Ty>>
|
||||
{
|
||||
map<Ky, Ty>* create(const std::string& key, boost::interprocess::managed_mapped_file* mmf) {
|
||||
return mmf->find_or_construct<map<Ky, Ty>>(key.c_str())(std::less<Ky>(), mmf->get_allocator<void>());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ky, typename Ty>
|
||||
struct type_factory<flat_map<Ky, Ty>>
|
||||
{
|
||||
flat_map<Ky, Ty>* create(const std::string& key, boost::interprocess::managed_mapped_file* mmf) {
|
||||
return mmf->find_or_construct<flat_map<Ky, Ty>>(key.c_str())(std::less<Ky>(), mmf->get_allocator<void>());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
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 04111-1307 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "shared_memory_handle.h"
|
||||
|
||||
#include <boost/interprocess/containers/string.hpp>
|
||||
|
||||
namespace eq
|
||||
{
|
||||
namespace shared
|
||||
{
|
||||
template<typename Ty>
|
||||
using basic_string = boost::interprocess::basic_string<Ty, std::char_traits<Ty>, boost::interprocess::allocator<Ty, boost::interprocess::managed_mapped_file::segment_manager>>;
|
||||
|
||||
using string = basic_string<char>;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template<typename Ty>
|
||||
struct type_factory<basic_string<Ty>>
|
||||
{
|
||||
list<Ty>* create(const std::string& key, boost::interprocess::managed_mapped_file* mmf) {
|
||||
return mmf->find_or_construct<list<Ty>>(key.c_str())(mmf->get_allocator<void>());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template<typename Ty>
|
||||
std::basic_string<Ty> to_std_string(const eq::shared::basic_string<Ty> &in) {
|
||||
return std::basic_string<Ty>(in.begin(), in.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
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 04111-1307 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "shared_memory_handle.h"
|
||||
|
||||
#include <boost/interprocess/containers/vector.hpp>
|
||||
|
||||
namespace eq
|
||||
{
|
||||
namespace shared
|
||||
{
|
||||
template<typename Ty>
|
||||
using vector = boost::interprocess::vector<Ty, boost::interprocess::allocator<Ty, boost::interprocess::managed_mapped_file::segment_manager>>;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template<typename Ty>
|
||||
struct type_factory<vector<Ty>>
|
||||
{
|
||||
vector<Ty>* create(const std::string& key, boost::interprocess::managed_mapped_file* mmf) {
|
||||
return mmf->find_or_construct<vector<Ty>>(key.c_str())(mmf->get_allocator<void>());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
+139
-141
@@ -1656,21 +1656,19 @@ uint8 SharedDatabase::GetTrainLevel(uint8 Class_, EQEmu::skills::SkillType Skill
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SharedDatabase::LoadDamageShieldTypes(SPDat_Spell_Struct* sp, int32 iMaxSpellID) {
|
||||
int SharedDatabase::LoadDamageShieldType(int spell_id) {
|
||||
|
||||
std::string query = StringFormat("SELECT `spellid`, `type` FROM `damageshieldtypes` WHERE `spellid` > 0 "
|
||||
"AND `spellid` <= %i", iMaxSpellID);
|
||||
std::string query = StringFormat("SELECT `type` FROM `damageshieldtypes` WHERE `spellid` = %i", spell_id);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for(auto row = results.begin(); row != results.end(); ++row) {
|
||||
int spellID = atoi(row[0]);
|
||||
if((spellID > 0) && (spellID <= iMaxSpellID))
|
||||
sp[spellID].DamageShieldType = atoi(row[1]);
|
||||
for(auto &row : results) {
|
||||
return atoi(row[0]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const EvolveInfo* SharedDatabase::GetEvolveInfo(uint32 loregroup) {
|
||||
@@ -1689,6 +1687,18 @@ int SharedDatabase::GetMaxSpellID() {
|
||||
return atoi(row[0]);
|
||||
}
|
||||
|
||||
int SharedDatabase::GetSpellCount() {
|
||||
std::string query = "SELECT COUNT(id) FROM spells_new";
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
return atoi(row[0]);
|
||||
}
|
||||
|
||||
bool SharedDatabase::LoadSpells(const std::string &prefix, int32 *records, const SPDat_Spell_Struct **sp) {
|
||||
spells_mmf.reset(nullptr);
|
||||
|
||||
@@ -1710,175 +1720,163 @@ bool SharedDatabase::LoadSpells(const std::string &prefix, int32 *records, const
|
||||
return true;
|
||||
}
|
||||
|
||||
void SharedDatabase::LoadSpells(void *data, int max_spells) {
|
||||
*(uint32*)data = max_spells;
|
||||
SPDat_Spell_Struct *sp = reinterpret_cast<SPDat_Spell_Struct*>((char*)data + sizeof(uint32));
|
||||
|
||||
void SharedDatabase::LoadSpells(std::function<void(const SPDat_Spell_Struct & sp)> on_load) {
|
||||
const std::string query = "SELECT * FROM spells_new ORDER BY id ASC";
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if(results.ColumnCount() <= SPELL_LOAD_FIELD_COUNT) {
|
||||
LogSpells("Fatal error loading spells: Spell field count < SPELL_LOAD_FIELD_COUNT([{}])", SPELL_LOAD_FIELD_COUNT);
|
||||
return;
|
||||
}
|
||||
|
||||
int tempid = 0;
|
||||
int counter = 0;
|
||||
for (auto &row : results) {
|
||||
SPDat_Spell_Struct sp;
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
tempid = atoi(row[0]);
|
||||
if(tempid >= max_spells) {
|
||||
LogSpells("Non fatal error: spell.id >= max_spells, ignoring");
|
||||
continue;
|
||||
}
|
||||
sp.id = atoi(row[0]);
|
||||
strn0cpy(sp.name, row[1], sizeof(sp.name));
|
||||
strn0cpy(sp.player_1, row[2], sizeof(sp.player_1));
|
||||
strn0cpy(sp.teleport_zone, row[3], sizeof(sp.teleport_zone));
|
||||
strn0cpy(sp.you_cast, row[4], sizeof(sp.you_cast));
|
||||
strn0cpy(sp.other_casts, row[5], sizeof(sp.other_casts));
|
||||
strn0cpy(sp.cast_on_you, row[6], sizeof(sp.cast_on_you));
|
||||
strn0cpy(sp.cast_on_other, row[7], sizeof(sp.cast_on_other));
|
||||
strn0cpy(sp.spell_fades, row[8], sizeof(sp.spell_fades));
|
||||
|
||||
++counter;
|
||||
sp[tempid].id = tempid;
|
||||
strn0cpy(sp[tempid].name, row[1], sizeof(sp[tempid].name));
|
||||
strn0cpy(sp[tempid].player_1, row[2], sizeof(sp[tempid].player_1));
|
||||
strn0cpy(sp[tempid].teleport_zone, row[3], sizeof(sp[tempid].teleport_zone));
|
||||
strn0cpy(sp[tempid].you_cast, row[4], sizeof(sp[tempid].you_cast));
|
||||
strn0cpy(sp[tempid].other_casts, row[5], sizeof(sp[tempid].other_casts));
|
||||
strn0cpy(sp[tempid].cast_on_you, row[6], sizeof(sp[tempid].cast_on_you));
|
||||
strn0cpy(sp[tempid].cast_on_other, row[7], sizeof(sp[tempid].cast_on_other));
|
||||
strn0cpy(sp[tempid].spell_fades, row[8], sizeof(sp[tempid].spell_fades));
|
||||
sp.range = static_cast<float>(atof(row[9]));
|
||||
sp.aoerange = static_cast<float>(atof(row[10]));
|
||||
sp.pushback = static_cast<float>(atof(row[11]));
|
||||
sp.pushup = static_cast<float>(atof(row[12]));
|
||||
sp.cast_time = atoi(row[13]);
|
||||
sp.recovery_time = atoi(row[14]);
|
||||
sp.recast_time = atoi(row[15]);
|
||||
sp.buffdurationformula = atoi(row[16]);
|
||||
sp.buffduration = atoi(row[17]);
|
||||
sp.AEDuration = atoi(row[18]);
|
||||
sp.mana = atoi(row[19]);
|
||||
|
||||
sp[tempid].range=static_cast<float>(atof(row[9]));
|
||||
sp[tempid].aoerange=static_cast<float>(atof(row[10]));
|
||||
sp[tempid].pushback=static_cast<float>(atof(row[11]));
|
||||
sp[tempid].pushup=static_cast<float>(atof(row[12]));
|
||||
sp[tempid].cast_time=atoi(row[13]);
|
||||
sp[tempid].recovery_time=atoi(row[14]);
|
||||
sp[tempid].recast_time=atoi(row[15]);
|
||||
sp[tempid].buffdurationformula=atoi(row[16]);
|
||||
sp[tempid].buffduration=atoi(row[17]);
|
||||
sp[tempid].AEDuration=atoi(row[18]);
|
||||
sp[tempid].mana=atoi(row[19]);
|
||||
int y = 0;
|
||||
for (y = 0; y < EFFECT_COUNT; y++)
|
||||
sp.base[y] = atoi(row[20 + y]); // effect_base_value
|
||||
|
||||
int y=0;
|
||||
for(y=0; y< EFFECT_COUNT;y++)
|
||||
sp[tempid].base[y]=atoi(row[20+y]); // effect_base_value
|
||||
for (y = 0; y < EFFECT_COUNT; y++)
|
||||
sp.base2[y] = atoi(row[32 + y]); // effect_limit_value
|
||||
|
||||
for(y=0; y < EFFECT_COUNT; y++)
|
||||
sp[tempid].base2[y]=atoi(row[32+y]); // effect_limit_value
|
||||
for (y = 0; y < EFFECT_COUNT; y++)
|
||||
sp.max[y] = atoi(row[44 + y]);
|
||||
|
||||
for(y=0; y< EFFECT_COUNT;y++)
|
||||
sp[tempid].max[y]=atoi(row[44+y]);
|
||||
for (y = 0; y < 4; y++)
|
||||
sp.components[y] = atoi(row[58 + y]);
|
||||
|
||||
for(y=0; y< 4;y++)
|
||||
sp[tempid].components[y]=atoi(row[58+y]);
|
||||
for (y = 0; y < 4; y++)
|
||||
sp.component_counts[y] = atoi(row[62 + y]);
|
||||
|
||||
for(y=0; y< 4;y++)
|
||||
sp[tempid].component_counts[y]=atoi(row[62+y]);
|
||||
for (y = 0; y < 4; y++)
|
||||
sp.NoexpendReagent[y] = atoi(row[66 + y]);
|
||||
|
||||
for(y=0; y< 4;y++)
|
||||
sp[tempid].NoexpendReagent[y]=atoi(row[66+y]);
|
||||
for (y = 0; y < EFFECT_COUNT; y++)
|
||||
sp.formula[y] = atoi(row[70 + y]);
|
||||
|
||||
for(y=0; y< EFFECT_COUNT;y++)
|
||||
sp[tempid].formula[y]=atoi(row[70+y]);
|
||||
sp.goodEffect = atoi(row[83]);
|
||||
sp.Activated = atoi(row[84]);
|
||||
sp.resisttype = atoi(row[85]);
|
||||
|
||||
sp[tempid].goodEffect=atoi(row[83]);
|
||||
sp[tempid].Activated=atoi(row[84]);
|
||||
sp[tempid].resisttype=atoi(row[85]);
|
||||
for (y = 0; y < EFFECT_COUNT; y++)
|
||||
sp.effectid[y] = atoi(row[86 + y]);
|
||||
|
||||
for(y=0; y< EFFECT_COUNT;y++)
|
||||
sp[tempid].effectid[y]=atoi(row[86+y]);
|
||||
|
||||
sp[tempid].targettype = (SpellTargetType) atoi(row[98]);
|
||||
sp[tempid].basediff=atoi(row[99]);
|
||||
sp.targettype = (SpellTargetType)atoi(row[98]);
|
||||
sp.basediff = atoi(row[99]);
|
||||
|
||||
int tmp_skill = atoi(row[100]);;
|
||||
|
||||
if (tmp_skill < 0 || tmp_skill > EQEmu::skills::HIGHEST_SKILL)
|
||||
sp[tempid].skill = EQEmu::skills::SkillBegging; /* not much better we can do. */ // can probably be changed to client-based 'SkillNone' once activated
|
||||
else
|
||||
sp[tempid].skill = (EQEmu::skills::SkillType) tmp_skill;
|
||||
sp.skill = EQEmu::skills::SkillBegging; /* not much better we can do. */ // can probably be changed to client-based 'SkillNone' once activated
|
||||
else
|
||||
sp.skill = (EQEmu::skills::SkillType) tmp_skill;
|
||||
|
||||
sp[tempid].zonetype=atoi(row[101]);
|
||||
sp[tempid].EnvironmentType=atoi(row[102]);
|
||||
sp[tempid].TimeOfDay=atoi(row[103]);
|
||||
sp.zonetype = atoi(row[101]);
|
||||
sp.EnvironmentType = atoi(row[102]);
|
||||
sp.TimeOfDay = atoi(row[103]);
|
||||
|
||||
for(y=0; y < PLAYER_CLASS_COUNT;y++)
|
||||
sp[tempid].classes[y]=atoi(row[104+y]);
|
||||
for (y = 0; y < PLAYER_CLASS_COUNT; y++)
|
||||
sp.classes[y] = atoi(row[104 + y]);
|
||||
|
||||
sp[tempid].CastingAnim=atoi(row[120]);
|
||||
sp[tempid].SpellAffectIndex=atoi(row[123]);
|
||||
sp[tempid].disallow_sit=atoi(row[124]);
|
||||
sp[tempid].diety_agnostic=atoi(row[125]);
|
||||
sp.CastingAnim = atoi(row[120]);
|
||||
sp.SpellAffectIndex = atoi(row[123]);
|
||||
sp.disallow_sit = atoi(row[124]);
|
||||
sp.diety_agnostic = atoi(row[125]);
|
||||
|
||||
for (y = 0; y < 16; y++)
|
||||
sp[tempid].deities[y]=atoi(row[126+y]);
|
||||
sp.deities[y] = atoi(row[126 + y]);
|
||||
|
||||
sp[tempid].new_icon=atoi(row[144]);
|
||||
sp[tempid].uninterruptable=atoi(row[146]) != 0;
|
||||
sp[tempid].ResistDiff=atoi(row[147]);
|
||||
sp[tempid].dot_stacking_exempt = atoi(row[148]) != 0;
|
||||
sp[tempid].RecourseLink = atoi(row[150]);
|
||||
sp[tempid].no_partial_resist = atoi(row[151]) != 0;
|
||||
sp.new_icon = atoi(row[144]);
|
||||
sp.uninterruptable = atoi(row[146]) != 0;
|
||||
sp.ResistDiff = atoi(row[147]);
|
||||
sp.dot_stacking_exempt = atoi(row[148]) != 0;
|
||||
sp.RecourseLink = atoi(row[150]);
|
||||
sp.no_partial_resist = atoi(row[151]) != 0;
|
||||
|
||||
sp[tempid].short_buff_box = atoi(row[154]);
|
||||
sp[tempid].descnum = atoi(row[155]);
|
||||
sp[tempid].typedescnum = atoi(row[156]);
|
||||
sp[tempid].effectdescnum = atoi(row[157]);
|
||||
sp.short_buff_box = atoi(row[154]);
|
||||
sp.descnum = atoi(row[155]);
|
||||
sp.typedescnum = atoi(row[156]);
|
||||
sp.effectdescnum = atoi(row[157]);
|
||||
|
||||
sp[tempid].npc_no_los = atoi(row[159]) != 0;
|
||||
sp[tempid].reflectable = atoi(row[161]) != 0;
|
||||
sp[tempid].bonushate=atoi(row[162]);
|
||||
sp.npc_no_los = atoi(row[159]) != 0;
|
||||
sp.reflectable = atoi(row[161]) != 0;
|
||||
sp.bonushate = atoi(row[162]);
|
||||
|
||||
sp[tempid].ldon_trap = atoi(row[165]) != 0;
|
||||
sp[tempid].EndurCost=atoi(row[166]);
|
||||
sp[tempid].EndurTimerIndex=atoi(row[167]);
|
||||
sp[tempid].IsDisciplineBuff = atoi(row[168]) != 0;
|
||||
sp[tempid].HateAdded=atoi(row[173]);
|
||||
sp[tempid].EndurUpkeep=atoi(row[174]);
|
||||
sp[tempid].numhitstype = atoi(row[175]);
|
||||
sp[tempid].numhits = atoi(row[176]);
|
||||
sp[tempid].pvpresistbase=atoi(row[177]);
|
||||
sp[tempid].pvpresistcalc=atoi(row[178]);
|
||||
sp[tempid].pvpresistcap=atoi(row[179]);
|
||||
sp[tempid].spell_category=atoi(row[180]);
|
||||
sp[tempid].pcnpc_only_flag=atoi(row[183]);
|
||||
sp[tempid].cast_not_standing = atoi(row[184]) != 0;
|
||||
sp[tempid].can_mgb=atoi(row[185]);
|
||||
sp[tempid].dispel_flag = atoi(row[186]);
|
||||
sp[tempid].MinResist = atoi(row[189]);
|
||||
sp[tempid].MaxResist = atoi(row[190]);
|
||||
sp[tempid].viral_targets = atoi(row[191]);
|
||||
sp[tempid].viral_timer = atoi(row[192]);
|
||||
sp[tempid].NimbusEffect = atoi(row[193]);
|
||||
sp[tempid].directional_start = static_cast<float>(atoi(row[194]));
|
||||
sp[tempid].directional_end = static_cast<float>(atoi(row[195]));
|
||||
sp[tempid].sneak = atoi(row[196]) != 0;
|
||||
sp[tempid].not_focusable = atoi(row[197]) != 0;
|
||||
sp[tempid].no_detrimental_spell_aggro = atoi(row[198]) != 0;
|
||||
sp[tempid].suspendable = atoi(row[200]) != 0;
|
||||
sp[tempid].viral_range = atoi(row[201]);
|
||||
sp[tempid].songcap = atoi(row[202]);
|
||||
sp[tempid].no_block = atoi(row[205]);
|
||||
sp[tempid].spellgroup=atoi(row[207]);
|
||||
sp[tempid].rank = atoi(row[208]);
|
||||
sp[tempid].no_resist=atoi(row[209]);
|
||||
sp[tempid].CastRestriction = atoi(row[211]);
|
||||
sp[tempid].AllowRest = atoi(row[212]) != 0;
|
||||
sp[tempid].InCombat = atoi(row[213]) != 0;
|
||||
sp[tempid].OutofCombat = atoi(row[214]) != 0;
|
||||
sp[tempid].override_crit_chance = atoi(row[217]);
|
||||
sp[tempid].aemaxtargets = atoi(row[218]);
|
||||
sp[tempid].no_heal_damage_item_mod = atoi(row[219]);
|
||||
sp[tempid].persistdeath = atoi(row[224]) != 0;
|
||||
sp[tempid].min_dist = atof(row[227]);
|
||||
sp[tempid].min_dist_mod = atof(row[228]);
|
||||
sp[tempid].max_dist = atof(row[229]);
|
||||
sp[tempid].max_dist_mod = atof(row[230]);
|
||||
sp[tempid].min_range = static_cast<float>(atoi(row[231]));
|
||||
sp[tempid].no_remove = atoi(row[232]) != 0;
|
||||
sp[tempid].DamageShieldType = 0;
|
||||
sp.ldon_trap = atoi(row[165]) != 0;
|
||||
sp.EndurCost = atoi(row[166]);
|
||||
sp.EndurTimerIndex = atoi(row[167]);
|
||||
sp.IsDisciplineBuff = atoi(row[168]) != 0;
|
||||
sp.HateAdded = atoi(row[173]);
|
||||
sp.EndurUpkeep = atoi(row[174]);
|
||||
sp.numhitstype = atoi(row[175]);
|
||||
sp.numhits = atoi(row[176]);
|
||||
sp.pvpresistbase = atoi(row[177]);
|
||||
sp.pvpresistcalc = atoi(row[178]);
|
||||
sp.pvpresistcap = atoi(row[179]);
|
||||
sp.spell_category = atoi(row[180]);
|
||||
sp.pcnpc_only_flag = atoi(row[183]);
|
||||
sp.cast_not_standing = atoi(row[184]) != 0;
|
||||
sp.can_mgb = atoi(row[185]);
|
||||
sp.dispel_flag = atoi(row[186]);
|
||||
sp.MinResist = atoi(row[189]);
|
||||
sp.MaxResist = atoi(row[190]);
|
||||
sp.viral_targets = atoi(row[191]);
|
||||
sp.viral_timer = atoi(row[192]);
|
||||
sp.NimbusEffect = atoi(row[193]);
|
||||
sp.directional_start = static_cast<float>(atoi(row[194]));
|
||||
sp.directional_end = static_cast<float>(atoi(row[195]));
|
||||
sp.sneak = atoi(row[196]) != 0;
|
||||
sp.not_focusable = atoi(row[197]) != 0;
|
||||
sp.no_detrimental_spell_aggro = atoi(row[198]) != 0;
|
||||
sp.suspendable = atoi(row[200]) != 0;
|
||||
sp.viral_range = atoi(row[201]);
|
||||
sp.songcap = atoi(row[202]);
|
||||
sp.no_block = atoi(row[205]);
|
||||
sp.spellgroup = atoi(row[207]);
|
||||
sp.rank = atoi(row[208]);
|
||||
sp.no_resist = atoi(row[209]);
|
||||
sp.CastRestriction = atoi(row[211]);
|
||||
sp.AllowRest = atoi(row[212]) != 0;
|
||||
sp.InCombat = atoi(row[213]) != 0;
|
||||
sp.OutofCombat = atoi(row[214]) != 0;
|
||||
sp.override_crit_chance = atoi(row[217]);
|
||||
sp.aemaxtargets = atoi(row[218]);
|
||||
sp.no_heal_damage_item_mod = atoi(row[219]);
|
||||
sp.persistdeath = atoi(row[224]) != 0;
|
||||
sp.min_dist = atof(row[227]);
|
||||
sp.min_dist_mod = atof(row[228]);
|
||||
sp.max_dist = atof(row[229]);
|
||||
sp.max_dist_mod = atof(row[230]);
|
||||
sp.min_range = static_cast<float>(atoi(row[231]));
|
||||
sp.no_remove = atoi(row[232]) != 0;
|
||||
sp.DamageShieldType = LoadDamageShieldType(sp.id); //ideally we could do this with a simple join but we need to formalize the table first.
|
||||
on_load(sp);
|
||||
}
|
||||
|
||||
LoadDamageShieldTypes(sp, max_spells);
|
||||
}
|
||||
|
||||
int SharedDatabase::GetMaxBaseDataLevel() {
|
||||
|
||||
+3
-2
@@ -140,9 +140,10 @@ class SharedDatabase : public Database
|
||||
uint8 GetTrainLevel(uint8 Class_, EQEmu::skills::SkillType Skill, uint8 Level);
|
||||
|
||||
int GetMaxSpellID();
|
||||
int GetSpellCount();
|
||||
bool LoadSpells(const std::string &prefix, int32 *records, const SPDat_Spell_Struct **sp);
|
||||
void LoadSpells(void *data, int max_spells);
|
||||
void LoadDamageShieldTypes(SPDat_Spell_Struct* sp, int32 iMaxSpellID);
|
||||
void LoadSpells(std::function<void(const SPDat_Spell_Struct & sp)> on_load);
|
||||
int LoadDamageShieldType(int spell_id);
|
||||
|
||||
int GetMaxBaseDataLevel();
|
||||
bool LoadBaseData(const std::string &prefix);
|
||||
|
||||
+1
-1
@@ -607,7 +607,7 @@ typedef enum {
|
||||
#define SE_LimitSpellGroup 385 // implemented - Limits to spell group(ie type 3 reuse reduction augs that are class specific and thus all share s SG)
|
||||
#define SE_CastOnCurer 386 // implemented - Casts a spell on the person curing
|
||||
#define SE_CastOnCure 387 // implemented - Casts a spell on the cured person
|
||||
//#define SE_SummonCorpseZone 388 // *not implemented - summons a corpse from any zone(nec AA)
|
||||
#define SE_SummonCorpseZone 388 // implemented - summons a corpse from any zone(nec AA)
|
||||
#define SE_FcTimerRefresh 389 // implemented - Refresh spell icons
|
||||
//#define SE_FcTimerLockout 390 // *not implemented - Sets recast timers to specific value, focus limited.
|
||||
#define SE_LimitManaMax 391 // implemented
|
||||
|
||||
+8
-4
@@ -129,13 +129,17 @@ void Timer::SetTimer(uint32 set_timer_time) {
|
||||
}
|
||||
}
|
||||
|
||||
uint32 Timer::GetRemainingTime() const {
|
||||
uint32 Timer::GetRemainingTime() const
|
||||
{
|
||||
if (enabled) {
|
||||
if (current_time - start_time > timer_time)
|
||||
if (current_time - start_time > timer_time) {
|
||||
return 0;
|
||||
else
|
||||
}
|
||||
else {
|
||||
return (start_time + timer_time) - current_time;
|
||||
} else {
|
||||
}
|
||||
}
|
||||
else {
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -34,10 +34,10 @@
|
||||
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
||||
*/
|
||||
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9146
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9152
|
||||
|
||||
#ifdef BOTS
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9026
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9027
|
||||
#else
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 0 // must be 0
|
||||
#endif
|
||||
|
||||
+23
-16
@@ -19,28 +19,35 @@
|
||||
#include "spells.h"
|
||||
#include "../common/global_define.h"
|
||||
#include "../common/shareddb.h"
|
||||
#include "../common/ipc_mutex.h"
|
||||
#include "../common/memory_mapped_file.h"
|
||||
#include "../common/eqemu_exception.h"
|
||||
#include "../common/spdat.h"
|
||||
#include "../common/shared/shared_memory.h"
|
||||
#include "../common/shared/shared_memory_map.h"
|
||||
|
||||
namespace eqs = eq::shared;
|
||||
|
||||
void LoadSpells(SharedDatabase *database, const std::string &prefix) {
|
||||
EQEmu::IPCMutex mutex("spells");
|
||||
mutex.Lock();
|
||||
int records = database->GetMaxSpellID() + 1;
|
||||
if(records == 0) {
|
||||
EQ_EXCEPT("Shared Memory", "Unable to get any spells from the database.");
|
||||
int records = database->GetSpellCount();
|
||||
int max_spell_id = database->GetMaxSpellID() + 1;
|
||||
auto size = records * sizeof(SPDat_Spell_Struct) * 125 / 100 + (64 * 1024);
|
||||
eqs::shared_memory shared("shared/spells", size);
|
||||
|
||||
auto spells_result = shared.map<eqs::unordered_map<int, SPDat_Spell_Struct>>("spells");
|
||||
if (!spells_result) {
|
||||
//todo: get rid of the exceptions entirely.
|
||||
EQ_EXCEPT("Shared Memory", "Unable to map shared memory");
|
||||
}
|
||||
|
||||
uint32 size = records * sizeof(SPDat_Spell_Struct) + sizeof(uint32);
|
||||
auto max_spell_id_result = shared.map<int>("max_spell_id");
|
||||
if (!max_spell_id_result) {
|
||||
EQ_EXCEPT("Shared Memory", "Unable to map shared memory");
|
||||
}
|
||||
|
||||
auto Config = EQEmuConfig::get();
|
||||
std::string file_name = Config->SharedMemDir + prefix + std::string("spells");
|
||||
EQEmu::MemoryMappedFile mmf(file_name, size);
|
||||
mmf.ZeroFile();
|
||||
eqs::unordered_map<int, SPDat_Spell_Struct>& spells_shm = spells_result.value();
|
||||
int& max_spell_id_shm = max_spell_id_result.value();
|
||||
max_spell_id_shm = max_spell_id;
|
||||
|
||||
void *ptr = mmf.Get();
|
||||
database->LoadSpells(ptr, records);
|
||||
mutex.Unlock();
|
||||
database->LoadSpells([&spells_shm](const SPDat_Spell_Struct &spell) {
|
||||
spells_shm.insert_or_assign(spell.id, spell);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Submodule
+1
Submodule submodules/expected added at 3d741708b9
+17
-12
@@ -47,8 +47,13 @@ ChatChannel::ChatChannel(std::string inName, std::string inOwner, std::string in
|
||||
|
||||
Moderated = false;
|
||||
|
||||
LogInfo("New ChatChannel created: Name: [[{}]], Owner: [[{}]], Password: [[{}]], MinStatus: [{}]",
|
||||
Name.c_str(), Owner.c_str(), Password.c_str(), MinimumStatus);
|
||||
LogDebug(
|
||||
"New ChatChannel created: Name: [[{}]], Owner: [[{}]], Password: [[{}]], MinStatus: [{}]",
|
||||
Name.c_str(),
|
||||
Owner.c_str(),
|
||||
Password.c_str(),
|
||||
MinimumStatus
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
@@ -154,7 +159,7 @@ void ChatChannelList::SendAllChannels(Client *c) {
|
||||
|
||||
void ChatChannelList::RemoveChannel(ChatChannel *Channel) {
|
||||
|
||||
LogInfo("RemoveChannel([{}])", Channel->GetName().c_str());
|
||||
LogDebug("RemoveChannel ([{}])", Channel->GetName().c_str());
|
||||
|
||||
LinkedListIterator<ChatChannel*> iterator(ChatChannels);
|
||||
|
||||
@@ -175,7 +180,7 @@ void ChatChannelList::RemoveChannel(ChatChannel *Channel) {
|
||||
|
||||
void ChatChannelList::RemoveAllChannels() {
|
||||
|
||||
LogInfo("RemoveAllChannels");
|
||||
LogDebug("RemoveAllChannels");
|
||||
|
||||
LinkedListIterator<ChatChannel*> iterator(ChatChannels);
|
||||
|
||||
@@ -242,7 +247,7 @@ void ChatChannel::AddClient(Client *c) {
|
||||
|
||||
int AccountStatus = c->GetAccountStatus();
|
||||
|
||||
LogInfo("Adding [{}] to channel [{}]", c->GetName().c_str(), Name.c_str());
|
||||
LogDebug("Adding [{}] to channel [{}]", c->GetName().c_str(), Name.c_str());
|
||||
|
||||
LinkedListIterator<Client*> iterator(ClientsInChannel);
|
||||
|
||||
@@ -267,7 +272,7 @@ bool ChatChannel::RemoveClient(Client *c) {
|
||||
|
||||
if(!c) return false;
|
||||
|
||||
LogInfo("RemoveClient [{}] from channel [{}]", c->GetName().c_str(), GetName().c_str());
|
||||
LogDebug("RemoveClient [{}] from channel [{}]", c->GetName().c_str(), GetName().c_str());
|
||||
|
||||
bool HideMe = c->GetHideMe();
|
||||
|
||||
@@ -304,7 +309,7 @@ bool ChatChannel::RemoveClient(Client *c) {
|
||||
if((Password.length() == 0) || (RuleI(Channels, DeleteTimer) == 0))
|
||||
return false;
|
||||
|
||||
LogInfo("Starting delete timer for empty password protected channel [{}]", Name.c_str());
|
||||
LogDebug("Starting delete timer for empty password protected channel [{}]", Name.c_str());
|
||||
|
||||
DeleteTimer.Start(RuleI(Channels, DeleteTimer) * 60000);
|
||||
}
|
||||
@@ -402,7 +407,7 @@ void ChatChannel::SendMessageToChannel(std::string Message, Client* Sender) {
|
||||
|
||||
if(ChannelClient)
|
||||
{
|
||||
LogInfo("Sending message to [{}] from [{}]",
|
||||
LogDebug("Sending message to [{}] from [{}]",
|
||||
ChannelClient->GetName().c_str(), Sender->GetName().c_str());
|
||||
|
||||
if (cv_messages[static_cast<uint32>(ChannelClient->GetClientVersion())].length() == 0) {
|
||||
@@ -505,7 +510,7 @@ ChatChannel *ChatChannelList::AddClientToChannel(std::string ChannelName, Client
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LogInfo("AddClient to channel [[{}]] with password [[{}]]", NormalisedName.c_str(), Password.c_str());
|
||||
LogDebug("AddClient to channel [[{}]] with password [[{}]]", NormalisedName.c_str(), Password.c_str());
|
||||
|
||||
ChatChannel *RequiredChannel = FindChannel(NormalisedName);
|
||||
|
||||
@@ -581,7 +586,7 @@ void ChatChannelList::Process() {
|
||||
|
||||
if(CurrentChannel && CurrentChannel->ReadyToDelete()) {
|
||||
|
||||
LogInfo("Empty temporary password protected channel [{}] being destroyed",
|
||||
LogDebug("Empty temporary password protected channel [{}] being destroyed",
|
||||
CurrentChannel->GetName().c_str());
|
||||
|
||||
RemoveChannel(CurrentChannel);
|
||||
@@ -597,7 +602,7 @@ void ChatChannel::AddInvitee(const std::string &Invitee)
|
||||
if (!IsInvitee(Invitee)) {
|
||||
Invitees.push_back(Invitee);
|
||||
|
||||
LogInfo("Added [{}] as invitee to channel [{}]", Invitee.c_str(), Name.c_str());
|
||||
LogDebug("Added [{}] as invitee to channel [{}]", Invitee.c_str(), Name.c_str());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -608,7 +613,7 @@ void ChatChannel::RemoveInvitee(std::string Invitee)
|
||||
|
||||
if(it != std::end(Invitees)) {
|
||||
Invitees.erase(it);
|
||||
LogInfo("Removed [{}] as invitee to channel [{}]", Invitee.c_str(), Name.c_str());
|
||||
LogDebug("Removed [{}] as invitee to channel [{}]", Invitee.c_str(), Name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+35
-16
@@ -235,7 +235,7 @@ std::vector<std::string> ParseRecipients(std::string RecipientString) {
|
||||
|
||||
static void ProcessMailTo(Client *c, std::string MailMessage) {
|
||||
|
||||
LogInfo("MAILTO: From [{}], [{}]", c->MailBoxName().c_str(), MailMessage.c_str());
|
||||
LogDebug("MAILTO: From [{}], [{}]", c->MailBoxName().c_str(), MailMessage.c_str());
|
||||
|
||||
std::vector<std::string> Recipients;
|
||||
|
||||
@@ -304,7 +304,7 @@ static void ProcessMailTo(Client *c, std::string MailMessage) {
|
||||
|
||||
if (!database.SendMail(Recipient, c->MailBoxName(), Subject, Body, RecipientsString)) {
|
||||
|
||||
LogInfo("Failed in SendMail([{}], [{}], [{}], [{}])", Recipient.c_str(),
|
||||
LogError("Failed in SendMail([{}], [{}], [{}], [{}])", Recipient.c_str(),
|
||||
c->MailBoxName().c_str(), Subject.c_str(), RecipientsString.c_str());
|
||||
|
||||
int PacketLength = 10 + Recipient.length() + Subject.length();
|
||||
@@ -556,6 +556,17 @@ void Client::CloseConnection() {
|
||||
ClientStream->ReleaseFromUse();
|
||||
}
|
||||
|
||||
void Clientlist::CheckForStaleConnectionsAll()
|
||||
{
|
||||
LogDebug("Checking for stale connections");
|
||||
|
||||
auto it = ClientChatConnections.begin();
|
||||
while (it != ClientChatConnections.end()) {
|
||||
(*it)->SendKeepAlive();
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
void Clientlist::CheckForStaleConnections(Client *c) {
|
||||
|
||||
if (!c) return;
|
||||
@@ -634,10 +645,12 @@ void Clientlist::Process()
|
||||
//
|
||||
std::string::size_type LastPeriod = MailBoxString.find_last_of(".");
|
||||
|
||||
if (LastPeriod == std::string::npos)
|
||||
if (LastPeriod == std::string::npos) {
|
||||
CharacterName = MailBoxString;
|
||||
else
|
||||
}
|
||||
else {
|
||||
CharacterName = MailBoxString.substr(LastPeriod + 1);
|
||||
}
|
||||
|
||||
LogInfo("Received login for user [{}] with key [{}]",
|
||||
MailBox, Key);
|
||||
@@ -652,8 +665,9 @@ void Clientlist::Process()
|
||||
|
||||
database.GetAccountStatus((*it));
|
||||
|
||||
if ((*it)->GetConnectionType() == ConnectionTypeCombined)
|
||||
if ((*it)->GetConnectionType() == ConnectionTypeCombined) {
|
||||
(*it)->SendFriends();
|
||||
}
|
||||
|
||||
(*it)->SendMailBoxes();
|
||||
|
||||
@@ -865,7 +879,9 @@ void Clientlist::CloseAllConnections() {
|
||||
void Client::AddCharacter(int CharID, const char *CharacterName, int Level) {
|
||||
|
||||
if (!CharacterName) return;
|
||||
LogInfo("Adding character [{}] with ID [{}] for [{}]", CharacterName, CharID, GetName().c_str());
|
||||
|
||||
LogDebug("Adding character [{}] with ID [{}] for [{}]", CharacterName, CharID, GetName().c_str());
|
||||
|
||||
CharacterEntry NewCharacter;
|
||||
NewCharacter.CharID = CharID;
|
||||
NewCharacter.Name = CharacterName;
|
||||
@@ -874,6 +890,10 @@ void Client::AddCharacter(int CharID, const char *CharacterName, int Level) {
|
||||
Characters.push_back(NewCharacter);
|
||||
}
|
||||
|
||||
void Client::SendKeepAlive() {
|
||||
QueuePacket(new EQApplicationPacket(OP_SessionReady, 0));
|
||||
}
|
||||
|
||||
void Client::SendMailBoxes() {
|
||||
|
||||
int Count = Characters.size();
|
||||
@@ -930,7 +950,7 @@ void Client::AddToChannelList(ChatChannel *JoinedChannel) {
|
||||
for (int i = 0; i < MAX_JOINED_CHANNELS; i++)
|
||||
if (JoinedChannels[i] == nullptr) {
|
||||
JoinedChannels[i] = JoinedChannel;
|
||||
LogInfo("Added Channel [{}] to slot [{}] for [{}]", JoinedChannel->GetName().c_str(), i + 1, GetName().c_str());
|
||||
LogDebug("Added Channel [{}] to slot [{}] for [{}]", JoinedChannel->GetName().c_str(), i + 1, GetName().c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -2346,18 +2366,17 @@ void Client::SendFriends() {
|
||||
}
|
||||
}
|
||||
|
||||
std::string Client::MailBoxName() {
|
||||
std::string Client::MailBoxName()
|
||||
{
|
||||
if ((Characters.empty()) || (CurrentMailBox > (Characters.size() - 1))) {
|
||||
LogDebug("MailBoxName() called with CurrentMailBox set to [{}] and Characters.size() is [{}]",
|
||||
CurrentMailBox, Characters.size());
|
||||
|
||||
if ((Characters.empty()) || (CurrentMailBox > (Characters.size() - 1)))
|
||||
{
|
||||
LogInfo("MailBoxName() called with CurrentMailBox set to [{}] and Characters.size() is [{}]",
|
||||
CurrentMailBox, Characters.size());
|
||||
|
||||
return "";
|
||||
return std::string();
|
||||
}
|
||||
|
||||
LogInfo("MailBoxName() called with CurrentMailBox set to [{}] and Characters.size() is [{}]",
|
||||
CurrentMailBox, Characters.size());
|
||||
LogDebug("MailBoxName() called with CurrentMailBox set to [{}] and Characters.size() is [{}]",
|
||||
CurrentMailBox, Characters.size());
|
||||
|
||||
return Characters[CurrentMailBox].Name;
|
||||
|
||||
|
||||
+3
-1
@@ -143,7 +143,7 @@ public:
|
||||
void SetConnectionType(char c);
|
||||
ConnectionType GetConnectionType() { return TypeOfConnection; }
|
||||
EQEmu::versions::ClientVersion GetClientVersion() { return ClientVersion_; }
|
||||
|
||||
|
||||
inline bool IsMailConnection() { return (TypeOfConnection == ConnectionTypeMail) || (TypeOfConnection == ConnectionTypeCombined); }
|
||||
void SendNotification(int MailBoxNumber, std::string From, std::string Subject, int MessageID);
|
||||
void ChangeMailBox(int NewMailBox);
|
||||
@@ -151,6 +151,7 @@ public:
|
||||
void SendFriends();
|
||||
int GetCharID();
|
||||
void SendUptime();
|
||||
void SendKeepAlive();
|
||||
|
||||
private:
|
||||
unsigned int CurrentMailBox;
|
||||
@@ -183,6 +184,7 @@ public:
|
||||
void Process();
|
||||
void CloseAllConnections();
|
||||
Client *FindCharacter(std::string CharacterName);
|
||||
void CheckForStaleConnectionsAll();
|
||||
void CheckForStaleConnections(Client *c);
|
||||
Client *IsCharacterOnline(std::string CharacterName);
|
||||
void ProcessOPMailCommand(Client *c, std::string CommandString);
|
||||
|
||||
+3
-3
@@ -108,7 +108,7 @@ void Database::GetAccountStatus(Client *client)
|
||||
{
|
||||
|
||||
std::string query = StringFormat(
|
||||
"SELECT `status`, `hideme`, `karma`, `revoked` FROM `account` WHERE `id` = '%i' LIMIT 1",
|
||||
"SELECT `status`, `hideme`, `karma`, `revoked` FROM `account` WHERE `id` = %i LIMIT 1",
|
||||
client->GetAccountID()
|
||||
);
|
||||
|
||||
@@ -173,7 +173,7 @@ int Database::FindAccount(const char *characterName, Client *client)
|
||||
|
||||
query = StringFormat(
|
||||
"SELECT `id`, `name`, `level` FROM `character_data` "
|
||||
"WHERE `account_id` = %i AND `name` != '%s'",
|
||||
"WHERE `account_id` = %i AND `name` != '%s' AND deleted_at is NULL",
|
||||
accountID, characterName
|
||||
);
|
||||
|
||||
@@ -320,7 +320,7 @@ void Database::SendHeaders(Client *client)
|
||||
int unknownField3 = 1;
|
||||
int characterID = FindCharacter(client->MailBoxName().c_str());
|
||||
|
||||
LogInfo("Sendheaders for [{}], CharID is [{}]", client->MailBoxName().c_str(), characterID);
|
||||
LogDebug("Sendheaders for [{}], CharID is [{}]", client->MailBoxName().c_str(), characterID);
|
||||
|
||||
if (characterID <= 0) {
|
||||
return;
|
||||
|
||||
+16
-8
@@ -70,17 +70,18 @@ int main() {
|
||||
// Check every minute for unused channels we can delete
|
||||
//
|
||||
Timer ChannelListProcessTimer(60000);
|
||||
Timer ClientConnectionPruneTimer(60000);
|
||||
|
||||
Timer InterserverTimer(INTERSERVER_TIMER); // does auto-reconnect
|
||||
|
||||
LogInfo("Starting EQEmu Universal Chat Server");
|
||||
|
||||
if (!ucsconfig::LoadConfig()) {
|
||||
LogInfo("Loading server configuration failed");
|
||||
if (!ucsconfig::LoadConfig()) {
|
||||
LogInfo("Loading server configuration failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
Config = ucsconfig::get();
|
||||
Config = ucsconfig::get();
|
||||
|
||||
WorldShortName = Config->ShortName;
|
||||
|
||||
@@ -144,19 +145,26 @@ int main() {
|
||||
|
||||
worldserver = new WorldServer;
|
||||
|
||||
while(RunLoops) {
|
||||
auto loop_fn = [&](EQ::Timer* t) {
|
||||
|
||||
Timer::SetCurrentTime();
|
||||
|
||||
g_Clientlist->Process();
|
||||
|
||||
if(ChannelListProcessTimer.Check())
|
||||
if (ChannelListProcessTimer.Check()) {
|
||||
ChannelList->Process();
|
||||
}
|
||||
|
||||
EQ::EventLoop::Get().Process();
|
||||
if (ClientConnectionPruneTimer.Check()) {
|
||||
g_Clientlist->CheckForStaleConnectionsAll();
|
||||
}
|
||||
|
||||
Sleep(5);
|
||||
}
|
||||
};
|
||||
|
||||
EQ::Timer process_timer(loop_fn);
|
||||
process_timer.Start(32, true);
|
||||
|
||||
EQ::EventLoop::Get().Run();
|
||||
|
||||
ChannelList->RemoveAllChannels();
|
||||
|
||||
|
||||
+1
-1
@@ -61,7 +61,7 @@ void WorldServer::ProcessMessage(uint16 opcode, EQ::Net::Packet &p)
|
||||
ServerPacket tpack(opcode, p);
|
||||
ServerPacket *pack = &tpack;
|
||||
|
||||
LogInfo("Received Opcode: {:#04x}", opcode);
|
||||
LogNetcode("Received Opcode: {:#04x}", opcode);
|
||||
|
||||
switch (opcode)
|
||||
{
|
||||
|
||||
@@ -331,7 +331,7 @@ OP_LDoNButton=0x596e
|
||||
OP_SetStartCity=0x7936 # Was 0x2d1b
|
||||
OP_VoiceMacroIn=0x202e
|
||||
OP_VoiceMacroOut=0x3920
|
||||
OP_ItemViewUnknown=0x0b64
|
||||
OP_ItemAdvancedLoreText=0x0b64
|
||||
OP_VetRewardsAvaliable=0x05d9
|
||||
OP_VetClaimRequest=0xcdde
|
||||
OP_VetClaimReply=0x361b
|
||||
|
||||
@@ -448,6 +448,8 @@ OP_FinishWindow2=0x40ef
|
||||
OP_ItemVerifyRequest=0x189c
|
||||
OP_ItemVerifyReply=0x097b
|
||||
|
||||
OP_ItemAdvancedLoreText=0x023b
|
||||
|
||||
# merchant stuff
|
||||
OP_ShopPlayerSell=0x791b
|
||||
OP_ShopRequest=0x4fed
|
||||
|
||||
@@ -327,7 +327,7 @@ OP_LDoNButton=0x41b5 # C
|
||||
OP_SetStartCity=0x7bf6 # C
|
||||
OP_VoiceMacroIn=0x31b1 # C
|
||||
OP_VoiceMacroOut=0x7880 # C
|
||||
OP_ItemViewUnknown=0x21c7 # C
|
||||
OP_ItemAdvancedLoreText=0x21c7 # C
|
||||
OP_VetRewardsAvaliable=0x4e4e # C
|
||||
OP_VetClaimRequest=0x771f # C
|
||||
OP_VetClaimReply=0x2f95 # C
|
||||
|
||||
@@ -576,7 +576,7 @@ OP_QueryResponseThing=0x0000 #
|
||||
# realityincarnate: these are just here to stop annoying several thousand byte packet dumps
|
||||
OP_LoginUnknown1=0x22cf
|
||||
OP_LoginUnknown2=0x43ba
|
||||
OP_ItemViewUnknown=0x4db4
|
||||
OP_ItemAdvancedLoreText=0x4db4
|
||||
|
||||
#Petition Opcodes
|
||||
OP_PetitionSearch=0x0000 #search term for petition
|
||||
|
||||
@@ -336,7 +336,7 @@ OP_LDoNButton=0x1031 # C
|
||||
OP_SetStartCity=0x68f0 # C
|
||||
OP_VoiceMacroIn=0x1524 # C
|
||||
OP_VoiceMacroOut=0x1d99 # C
|
||||
OP_ItemViewUnknown=0x4eb3 # C
|
||||
OP_ItemAdvancedLoreText=0x4eb3 # C
|
||||
OP_VetRewardsAvaliable=0x0baa # C Mispelled?
|
||||
OP_VetClaimRequest=0x34f8 # C
|
||||
OP_VetClaimReply=0x6a5d # C
|
||||
|
||||
+216
-261
@@ -52,6 +52,10 @@ if (-e "eqemu_server_skip_update.txt") {
|
||||
$skip_self_update_check = 1;
|
||||
}
|
||||
|
||||
if (-e "eqemu_server_skip_maps_update.txt") {
|
||||
$skip_self_maps_update_check = 1;
|
||||
}
|
||||
|
||||
#::: Check for script self update
|
||||
check_xml_to_json_conversion() if $ARGV[0] eq "convert_xml";
|
||||
do_self_update_check_routine() if !$skip_self_update_check;
|
||||
@@ -460,7 +464,7 @@ sub do_installer_routines {
|
||||
get_remote_file($install_repository_request_url . "libmysql.dll", "libmysql.dll", 1);
|
||||
}
|
||||
|
||||
map_files_fetch_bulk();
|
||||
map_files_fetch_bulk() if !$skip_self_maps_update_check;
|
||||
opcodes_fetch();
|
||||
plugins_fetch();
|
||||
quest_files_fetch();
|
||||
@@ -493,9 +497,7 @@ sub do_installer_routines {
|
||||
|
||||
#::: Download PEQ latest
|
||||
fetch_peq_db_full();
|
||||
print "[Database] Fetching Latest Database Updates...\n";
|
||||
main_db_management();
|
||||
print "[Database] Applying Latest Database Updates...\n";
|
||||
print "[Database] Fetching and Applying Latest Database Updates...\n";
|
||||
main_db_management();
|
||||
|
||||
remove_duplicate_rule_values();
|
||||
@@ -531,35 +533,14 @@ sub check_for_world_bootup_database_update {
|
||||
}
|
||||
|
||||
$binary_database_version = trim($db_version[1]);
|
||||
$local_database_version = trim(get_mysql_result("SELECT version FROM db_version LIMIT 1"));
|
||||
|
||||
#::: Bots
|
||||
$bots_binary_version = trim($db_version[2]);
|
||||
if ($bots_binary_version > 0) {
|
||||
$bots_local_db_version = get_bots_db_version();
|
||||
#::: We ran world - Database needs to update, lets backup and run updates and continue world bootup
|
||||
|
||||
if ($bots_local_db_version < $bots_binary_version && $ARGV[0] eq "ran_from_world") {
|
||||
print "[Update] Bots Database not up to date with binaries... Automatically updating...\n";
|
||||
print "[Update] Issuing database backup first...\n";
|
||||
database_dump_compress();
|
||||
print "[Update] Updating bots database...\n";
|
||||
sleep(1);
|
||||
bots_db_management();
|
||||
run_database_check();
|
||||
print "[Update] Continuing bootup\n";
|
||||
analytics_insertion("auto database bots upgrade world", $db . " :: Binary DB Version / Local DB Version :: " . $binary_database_version . " / " . $local_database_version);
|
||||
|
||||
exit;
|
||||
}
|
||||
else {
|
||||
print "[Update] Bots database up to Date: Continuing World Bootup...\n";
|
||||
}
|
||||
}
|
||||
$local_database_version = get_main_db_version();
|
||||
|
||||
if ($binary_database_version == $local_database_version && $ARGV[0] eq "ran_from_world") {
|
||||
print "[Update] Database up to date...\n";
|
||||
exit;
|
||||
if (trim($db_version[2]) == 0) {
|
||||
print "[Update] Continuing bootup\n";
|
||||
exit;
|
||||
}
|
||||
}
|
||||
else {
|
||||
#::: We ran world - Database needs to update, lets backup and run updates and continue world bootup
|
||||
@@ -567,22 +548,61 @@ sub check_for_world_bootup_database_update {
|
||||
print "[Update] Database not up to date with binaries... Automatically updating...\n";
|
||||
print "[Update] Issuing database backup first...\n";
|
||||
database_dump_compress();
|
||||
$db_already_backed_up = 1;
|
||||
print "[Update] Updating database...\n";
|
||||
sleep(1);
|
||||
main_db_management();
|
||||
main_db_management();
|
||||
print "[Update] Continuing bootup\n";
|
||||
|
||||
analytics_insertion("auto database upgrade world", $db . " :: Binary DB Version / Local DB Version :: " . $binary_database_version . " / " . $local_database_version);
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
#::: Make sure that we didn't pass any arugments to the script
|
||||
else {
|
||||
if ($local_database_version > $binary_database_version) {
|
||||
print "[Update] Database version is ahead of current binaries...\n";
|
||||
}
|
||||
|
||||
if (!$db) { print "[eqemu_server.pl] No database connection found... Running without\n"; }
|
||||
show_menu_prompt();
|
||||
}
|
||||
}
|
||||
|
||||
#::: Bots
|
||||
$binary_database_version = trim($db_version[2]);
|
||||
if ($binary_database_version > 0) {
|
||||
$local_database_version = get_bots_db_version();
|
||||
|
||||
#::: We ran world - Database needs to update, lets backup and run updates and continue world bootup
|
||||
if ($binary_database_version == $local_database_version && $ARGV[0] eq "ran_from_world") {
|
||||
print "[Update] Bots database up to date...\n";
|
||||
}
|
||||
else {
|
||||
if ($local_database_version < $binary_database_version && $ARGV[0] eq "ran_from_world") {
|
||||
print "[Update] Bots Database not up to date with binaries... Automatically updating...\n";
|
||||
if (!$db_already_backed_up) {
|
||||
print "[Update] Issuing database backup first...\n";
|
||||
database_dump_compress();
|
||||
}
|
||||
print "[Update] Updating bots database...\n";
|
||||
sleep(1);
|
||||
bots_db_management();
|
||||
|
||||
analytics_insertion("auto database bots upgrade world", $db . " :: Binary DB Version / Local DB Version :: " . $binary_database_version . " / " . $local_database_version);
|
||||
}
|
||||
|
||||
#::: Make sure that we didn't pass any arugments to the script
|
||||
else {
|
||||
if ($local_database_version > $binary_database_version) {
|
||||
print "[Update] Bots database version is ahead of current binaries...\n";
|
||||
}
|
||||
|
||||
if (!$db) { print "[eqemu_server.pl] No database connection found... Running without\n"; }
|
||||
show_menu_prompt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
print "[Update] Continuing bootup\n";
|
||||
}
|
||||
|
||||
sub check_internet_connection {
|
||||
@@ -629,7 +649,7 @@ sub do_self_update_check_routine {
|
||||
|
||||
#::: Check for internet connection before updating
|
||||
if (!$has_internet_connection) {
|
||||
print "[Update] Cannot check update without internet connection...\n";
|
||||
print "[Update] Cannot check self-update without internet connection...\n";
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -819,7 +839,6 @@ sub setup_bots {
|
||||
build_linux_source("bots");
|
||||
}
|
||||
bots_db_management();
|
||||
run_database_check();
|
||||
|
||||
print "Bots should be setup, run your server and the bot command should be available in-game (type '^help')\n";
|
||||
}
|
||||
@@ -953,13 +972,11 @@ sub show_menu_prompt {
|
||||
$dc = 1;
|
||||
}
|
||||
elsif ($input eq "check_db_updates") {
|
||||
main_db_management();
|
||||
main_db_management();
|
||||
$dc = 1;
|
||||
}
|
||||
elsif ($input eq "check_bot_db_updates") {
|
||||
bots_db_management();
|
||||
run_database_check();
|
||||
$dc = 1;
|
||||
}
|
||||
elsif ($input eq "setup_loginserver") {
|
||||
@@ -1400,6 +1417,7 @@ sub remove_duplicate_rule_values {
|
||||
sub copy_file {
|
||||
$l_source_file = $_[0];
|
||||
$l_destination_file = $_[1];
|
||||
|
||||
if ($l_destination_file =~ /\//i) {
|
||||
my @directory_path = split('/', $l_destination_file);
|
||||
$build_path = "";
|
||||
@@ -1418,6 +1436,7 @@ sub copy_file {
|
||||
$directory_index++;
|
||||
}
|
||||
}
|
||||
|
||||
copy $l_source_file, $l_destination_file;
|
||||
}
|
||||
|
||||
@@ -1693,26 +1712,22 @@ sub fetch_server_dlls {
|
||||
|
||||
sub fetch_peq_db_full {
|
||||
print "[Install] Downloading latest PEQ Database... Please wait...\n";
|
||||
get_remote_file("http://edit.projecteq.net/weekly/peq_beta.zip", "updates_staged/peq_beta.zip", 1);
|
||||
get_remote_file("http://db.projecteq.net/api/v1/dump/latest", "updates_staged/peq-latest.zip", 1);
|
||||
print "[Install] Downloaded latest PEQ Database... Extracting...\n";
|
||||
unzip('updates_staged/peq_beta.zip', 'updates_staged/peq_db/');
|
||||
my $start_dir = "updates_staged/peq_db";
|
||||
unzip('updates_staged/peq-latest.zip', 'updates_staged/peq_db/');
|
||||
my $start_dir = "updates_staged/peq_db/peq-dump";
|
||||
find(
|
||||
sub { push @files, $File::Find::name unless -d; },
|
||||
$start_dir
|
||||
);
|
||||
for my $file (@files) {
|
||||
$destination_file = $file;
|
||||
$destination_file =~ s/updates_staged\/peq_db\///g;
|
||||
if ($file =~ /peqbeta|player_tables/i) {
|
||||
$destination_file =~ s/updates_staged\/peq_db\/peq-dump\///g;
|
||||
if ($file =~ /create_tables_content|create_tables_login|create_tables_player|create_tables_queryserv|create_tables_state|create_tables_system/i) {
|
||||
print "[Install] DB :: Installing :: " . $destination_file . "\n";
|
||||
get_mysql_result_from_file($file);
|
||||
}
|
||||
}
|
||||
|
||||
#::: PEQ DB baseline version
|
||||
print get_mysql_result("DELETE FROM db_version");
|
||||
print get_mysql_result("INSERT INTO `db_version` (`version`) VALUES (9130);");
|
||||
}
|
||||
|
||||
sub map_files_fetch_bulk {
|
||||
@@ -2001,15 +2016,6 @@ sub do_bots_db_schema_drop {
|
||||
print get_mysql_result_from_file("db_update/drop_bots.sql");
|
||||
|
||||
print "[Database] Removing bot database tables...\n";
|
||||
print get_mysql_result("DELETE FROM `rule_values` WHERE `rule_name` LIKE 'Bots:%';");
|
||||
|
||||
if (get_mysql_result("SHOW TABLES LIKE 'commands'") ne "" && $db) {
|
||||
print get_mysql_result("DELETE FROM `commands` WHERE `command` LIKE 'bot';");
|
||||
}
|
||||
|
||||
if (get_mysql_result("SHOW TABLES LIKE 'command_settings'") ne "" && $db) {
|
||||
print get_mysql_result("DELETE FROM `command_settings` WHERE `command` LIKE 'bot';");
|
||||
}
|
||||
|
||||
if (get_mysql_result("SHOW KEYS FROM `group_id` WHERE `Key_name` LIKE 'PRIMARY'") ne "" && $db) {
|
||||
print get_mysql_result("ALTER TABLE `group_id` DROP PRIMARY KEY;");
|
||||
@@ -2043,70 +2049,6 @@ sub modify_db_for_bots {
|
||||
}
|
||||
print get_mysql_result("ALTER TABLE `group_id` ADD PRIMARY KEY USING BTREE(`groupid`, `charid`, `name`, `ismerc`);");
|
||||
|
||||
if (get_mysql_result("SHOW TABLES LIKE 'command_settings'") ne "" && get_mysql_result("SELECT `command` FROM `command_settings` WHERE `command` LIKE 'bot'") eq "" && $db) {
|
||||
print get_mysql_result("INSERT INTO `command_settings` VALUES ('bot', '0', '');");
|
||||
}
|
||||
|
||||
if (get_mysql_result("SHOW TABLES LIKE 'commands'") ne "" && get_mysql_result("SELECT `command` FROM `commands` WHERE `command` LIKE 'bot'") eq "" && $db) {
|
||||
print get_mysql_result("INSERT INTO `commands` VALUES ('bot', '0');");
|
||||
}
|
||||
|
||||
if (get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:BotAAExpansion'") ne "" && $db) {
|
||||
print get_mysql_result("UPDATE `rule_values` SET `rule_name` = 'Bots:AAExpansion' WHERE `rule_name` LIKE 'Bots:BotAAExpansion';");
|
||||
}
|
||||
if (get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:AAExpansion'") eq "" && $db) {
|
||||
print get_mysql_result("INSERT INTO `rule_values` VALUES ('1', 'Bots:AAExpansion', '8', 'The expansion through which bots will obtain AAs');");
|
||||
}
|
||||
|
||||
if (get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:CreateBotCount'") ne "" && $db) {
|
||||
print get_mysql_result("UPDATE `rule_values` SET `rule_name` = 'Bots:CreationLimit' WHERE `rule_name` LIKE 'Bots:CreateBotCount';");
|
||||
}
|
||||
if (get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:CreationLimit'") eq "" && $db) {
|
||||
print get_mysql_result("INSERT INTO `rule_values` VALUES ('1', 'Bots:CreationLimit', '150', 'Number of bots that each account can create');");
|
||||
}
|
||||
|
||||
if (get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:BotFinishBuffing'") ne "" && $db) {
|
||||
print get_mysql_result("UPDATE `rule_values` SET `rule_name` = 'Bots:FinishBuffing' WHERE `rule_name` LIKE 'Bots:BotFinishBuffing';");
|
||||
}
|
||||
if (get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:FinishBuffing'") eq "" && $db) {
|
||||
print get_mysql_result("INSERT INTO `rule_values` VALUES ('1', 'Bots:FinishBuffing', 'false', 'Allow for buffs to complete even if the bot caster is out of mana. Only affects buffing out of combat.');");
|
||||
}
|
||||
|
||||
if (get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:BotGroupBuffing'") ne "" && $db) {
|
||||
print get_mysql_result("UPDATE `rule_values` SET `rule_name` = 'Bots:GroupBuffing' WHERE `rule_name` LIKE 'Bots:BotGroupBuffing';");
|
||||
}
|
||||
if (get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:GroupBuffing'") eq "" && $db) {
|
||||
print get_mysql_result("INSERT INTO `rule_values` VALUES ('1', 'Bots:GroupBuffing', 'false', 'Bots will cast single target buffs as group buffs, default is false for single. Does not make single target buffs work for MGB.');");
|
||||
}
|
||||
|
||||
if (get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:BotManaRegen'") ne "" && $db) {
|
||||
print get_mysql_result("UPDATE `rule_values` SET `rule_name` = 'Bots:ManaRegen' WHERE `rule_name` LIKE 'Bots:BotManaRegen';");
|
||||
}
|
||||
if (get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:ManaRegen'") eq "" && $db) {
|
||||
print get_mysql_result("INSERT INTO `rule_values` VALUES ('1', 'Bots:ManaRegen', '3.0', 'Adjust mana regen for bots, 1 is fast and higher numbers slow it down 3 is about the same as players.');");
|
||||
}
|
||||
|
||||
if (get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:BotQuest'") ne "" && $db) {
|
||||
print get_mysql_result("UPDATE `rule_values` SET `rule_name` = 'Bots:QuestableSpawnLimit' WHERE `rule_name` LIKE 'Bots:BotQuest';");
|
||||
}
|
||||
if (get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:QuestableSpawnLimit'") eq "" && $db) {
|
||||
print get_mysql_result("INSERT INTO `rule_values` VALUES ('1', 'Bots:QuestableSpawnLimit', 'false', 'Optional quest method to manage bot spawn limits using the quest_globals name bot_spawn_limit, see: /bazaar/Aediles_Thrall.pl');");
|
||||
}
|
||||
|
||||
if (get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:BotSpellQuest'") ne "" && $db) {
|
||||
print get_mysql_result("UPDATE `rule_values` SET `rule_name` = 'Bots:QuestableSpells' WHERE `rule_name` LIKE 'Bots:BotSpellQuest';");
|
||||
}
|
||||
if (get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:QuestableSpells'") eq "" && $db) {
|
||||
print get_mysql_result("INSERT INTO `rule_values` VALUES ('1', 'Bots:QuestableSpells', 'false', 'Anita Thrall\\\'s (Anita_Thrall.pl) Bot Spell Scriber quests.');");
|
||||
}
|
||||
|
||||
if (get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:SpawnBotCount'") ne "" && $db) {
|
||||
print get_mysql_result("UPDATE `rule_values` SET `rule_name` = 'Bots:SpawnLimit' WHERE `rule_name` LIKE 'Bots:SpawnBotCount';");
|
||||
}
|
||||
if (get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:SpawnLimit'") eq "" && $db) {
|
||||
print get_mysql_result("INSERT INTO `rule_values` VALUES ('1', 'Bots:SpawnLimit', '71', 'Number of bots a character can have spawned at one time, You + 71 bots is a 12 group raid');");
|
||||
}
|
||||
|
||||
convert_existing_bot_data();
|
||||
}
|
||||
|
||||
@@ -2205,47 +2147,49 @@ sub convert_existing_bot_data {
|
||||
}
|
||||
}
|
||||
|
||||
sub get_main_db_version {
|
||||
$main_local_db_version = trim(get_mysql_result("SELECT version FROM db_version LIMIT 1"));
|
||||
return $main_local_db_version;
|
||||
}
|
||||
|
||||
sub get_bots_db_version {
|
||||
#::: Check if bots_version column exists...
|
||||
if (get_mysql_result("SHOW COLUMNS FROM db_version LIKE 'bots_version'") eq "" && $db) {
|
||||
print get_mysql_result("ALTER TABLE db_version ADD bots_version int(11) DEFAULT '0' AFTER version;");
|
||||
print "[Database] Column 'bots_version' does not exists.... Adding to 'db_version' table...\n\n";
|
||||
}
|
||||
|
||||
$bots_local_db_version = trim(get_mysql_result("SELECT bots_version FROM db_version LIMIT 1"));
|
||||
return $bots_local_db_version;
|
||||
}
|
||||
|
||||
#::: Safe for call from world startup or menu option
|
||||
sub bots_db_management {
|
||||
if ($OS eq "Windows") {
|
||||
@db_version = split(': ', `world db_version`);
|
||||
}
|
||||
if ($OS eq "Linux") {
|
||||
@db_version = split(': ', `./world db_version`);
|
||||
}
|
||||
|
||||
#::: Main Binary Database version
|
||||
$binary_database_version = trim($db_version[2]);
|
||||
|
||||
#::: If we have stale data from main db run
|
||||
if ($db_run_stage > 0 && $bots_db_management == 0) {
|
||||
clear_database_runs();
|
||||
}
|
||||
|
||||
|
||||
#::: Main Binary Database version
|
||||
$binary_database_version = trim($db_version[2]);
|
||||
if ($binary_database_version == 0) {
|
||||
print "[Database] Your server binaries (world/zone) are not compiled for bots...\n\n";
|
||||
return;
|
||||
}
|
||||
|
||||
$local_database_version = get_bots_db_version();
|
||||
|
||||
#::: Set on flag for running bot updates...
|
||||
$bots_db_management = 1;
|
||||
|
||||
$bots_local_db_version = get_bots_db_version();
|
||||
|
||||
$local_database_version = $bots_local_db_version;
|
||||
|
||||
|
||||
if ($local_database_version > $binary_database_version) {
|
||||
print "[Update] Bots database version is ahead of current binaries...\n";
|
||||
return;
|
||||
}
|
||||
|
||||
run_database_check();
|
||||
}
|
||||
|
||||
#::: Safe for call from world startup or menu option
|
||||
sub main_db_management {
|
||||
#::: If we have stale data from bots db run
|
||||
if ($db_run_stage > 0 && $bots_db_management == 1) {
|
||||
@@ -2254,8 +2198,15 @@ sub main_db_management {
|
||||
|
||||
#::: Main Binary Database version
|
||||
$binary_database_version = trim($db_version[1]);
|
||||
$local_database_version = get_main_db_version();
|
||||
|
||||
$bots_db_management = 0;
|
||||
|
||||
if ($local_database_version > $binary_database_version) {
|
||||
print "[Update] Database version is ahead of current binaries...\n";
|
||||
return;
|
||||
}
|
||||
|
||||
run_database_check();
|
||||
}
|
||||
|
||||
@@ -2265,148 +2216,70 @@ sub clear_database_runs {
|
||||
%m_d = ();
|
||||
#::: Clear updates...
|
||||
@total_updates = ();
|
||||
#::: Clear stage
|
||||
$db_run_stage = 0;
|
||||
}
|
||||
|
||||
#::: Responsible for Database Upgrade Routines
|
||||
sub run_database_check {
|
||||
|
||||
|
||||
if (!$db) {
|
||||
print "No database present, check your eqemu_config.xml for proper MySQL/MariaDB configuration...\n";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!@total_updates) {
|
||||
#::: Pull down bots database manifest
|
||||
if ($bots_db_management == 1) {
|
||||
print "[Database] Retrieving latest bots database manifest...\n";
|
||||
get_remote_file($eqemu_repository_request_url . "utils/sql/git/bots/bots_db_update_manifest.txt", "db_update/db_update_manifest.txt");
|
||||
}
|
||||
#::: Pull down mainstream database manifest
|
||||
else {
|
||||
print "[Database] Retrieving latest database manifest...\n";
|
||||
get_remote_file($eqemu_repository_request_url . "utils/sql/db_update_manifest.txt", "db_update/db_update_manifest.txt");
|
||||
}
|
||||
|
||||
#::: Pull down bots database manifest
|
||||
if ($bots_db_management == 1) {
|
||||
print "[Database] Retrieving latest bots database manifest...\n";
|
||||
get_remote_file($eqemu_repository_request_url . "utils/sql/git/bots/bots_db_update_manifest.txt", "db_update/db_update_manifest.txt");
|
||||
}
|
||||
|
||||
#::: Run 2 - Running pending updates...
|
||||
if (@total_updates || $db_run_stage == 1) {
|
||||
@total_updates = sort @total_updates;
|
||||
foreach my $val (@total_updates) {
|
||||
$file_name = trim($m_d{$val}[1]);
|
||||
print "[Database] Running Update: " . $val . " - " . $file_name . "\n";
|
||||
print get_mysql_result_from_file("db_update/$file_name");
|
||||
print get_mysql_result("UPDATE db_version SET version = $val WHERE version < $val");
|
||||
|
||||
if ($bots_db_management == 1 && $val == 9000) {
|
||||
modify_db_for_bots();
|
||||
}
|
||||
|
||||
if ($val == 9138) {
|
||||
fix_quest_factions();
|
||||
}
|
||||
}
|
||||
$db_run_stage = 2;
|
||||
}
|
||||
#::: Run 1 - Initial checking of needed updates...
|
||||
#::: Pull down mainstream database manifest
|
||||
else {
|
||||
print "[Database] Reading manifest...\n";
|
||||
|
||||
use Data::Dumper;
|
||||
open(FILE, "db_update/db_update_manifest.txt");
|
||||
while (<FILE>) {
|
||||
chomp;
|
||||
$o = $_;
|
||||
if ($o =~ /#/i) {
|
||||
next;
|
||||
}
|
||||
|
||||
@manifest = split('\|', $o);
|
||||
$m_d{$manifest[0]} = [ @manifest ];
|
||||
}
|
||||
#::: Setting Manifest stage...
|
||||
$db_run_stage = 1;
|
||||
print "[Database] Retrieving latest database manifest...\n";
|
||||
get_remote_file($eqemu_repository_request_url . "utils/sql/db_update_manifest.txt", "db_update/db_update_manifest.txt");
|
||||
}
|
||||
|
||||
@total_updates = ();
|
||||
|
||||
|
||||
#::: Parse manifest
|
||||
print "[Database] Reading manifest...\n";
|
||||
|
||||
use Data::Dumper;
|
||||
open(FILE, "db_update/db_update_manifest.txt");
|
||||
while (<FILE>) {
|
||||
chomp;
|
||||
$o = $_;
|
||||
if ($o =~ /#/i) {
|
||||
next;
|
||||
}
|
||||
|
||||
@manifest = split('\|', $o);
|
||||
$m_d{$manifest[0]} = [ @manifest ];
|
||||
}
|
||||
|
||||
#::: This is where we set checkpoints for where a database might be so we don't check so far back in the manifest...
|
||||
if ($local_database_version >= 9000) {
|
||||
$revision_check = $local_database_version;
|
||||
$revision_check = $local_database_version + 1;
|
||||
}
|
||||
else {
|
||||
#::: This does not negatively affect bots
|
||||
$revision_check = 1000;
|
||||
if (get_mysql_result("SHOW TABLES LIKE 'character_data'") ne "") {
|
||||
$revision_check = 8999;
|
||||
}
|
||||
}
|
||||
|
||||
#::: Iterate through Manifest backwards from binary version down to local version...
|
||||
|
||||
@total_updates = ();
|
||||
|
||||
#::: Fetch and register sqls for this database update cycle
|
||||
for ($i = $revision_check; $i <= $binary_database_version; $i++) {
|
||||
if (!defined($m_d{$i}[0])) {
|
||||
next;
|
||||
}
|
||||
|
||||
$file_name = trim($m_d{$i}[1]);
|
||||
$query_check = trim($m_d{$i}[2]);
|
||||
$match_type = trim($m_d{$i}[3]);
|
||||
$match_text = trim($m_d{$i}[4]);
|
||||
|
||||
#::: Match type update
|
||||
if ($match_type eq "contains") {
|
||||
if (trim(get_mysql_result($query_check)) =~ /$match_text/i) {
|
||||
print "[Database] missing update: " . $i . " '" . $file_name . "' \n";
|
||||
fetch_missing_db_update($i, $file_name);
|
||||
push(@total_updates, $i);
|
||||
}
|
||||
else {
|
||||
print "[Database] has update (" . $i . ") '" . $file_name . "' \n";
|
||||
}
|
||||
print_match_debug();
|
||||
print_break();
|
||||
}
|
||||
if ($match_type eq "missing") {
|
||||
if (get_mysql_result($query_check) =~ /$match_text/i) {
|
||||
print "[Database] has update (" . $i . ") '" . $file_name . "' \n";
|
||||
next;
|
||||
}
|
||||
else {
|
||||
print "[Database] missing update: " . $i . " '" . $file_name . "' \n";
|
||||
fetch_missing_db_update($i, $file_name);
|
||||
push(@total_updates, $i);
|
||||
}
|
||||
print_match_debug();
|
||||
print_break();
|
||||
}
|
||||
if ($match_type eq "empty") {
|
||||
if (get_mysql_result($query_check) eq "") {
|
||||
print "[Database] missing update: " . $i . " '" . $file_name . "' \n";
|
||||
fetch_missing_db_update($i, $file_name);
|
||||
push(@total_updates, $i);
|
||||
}
|
||||
else {
|
||||
print "[Database] has update (" . $i . ") '" . $file_name . "' \n";
|
||||
}
|
||||
print_match_debug();
|
||||
print_break();
|
||||
}
|
||||
if ($match_type eq "not_empty") {
|
||||
if (get_mysql_result($query_check) ne "") {
|
||||
print "[Database] missing update: " . $i . " '" . $file_name . "' \n";
|
||||
fetch_missing_db_update($i, $file_name);
|
||||
push(@total_updates, $i);
|
||||
}
|
||||
else {
|
||||
print "[Database] has update (" . $i . ") '" . $file_name . "' \n";
|
||||
}
|
||||
print_match_debug();
|
||||
print_break();
|
||||
}
|
||||
|
||||
$file_name = trim($m_d{$i}[1]);
|
||||
print "[Database] fetching update: " . $i . " '" . $file_name . "' \n";
|
||||
fetch_missing_db_update($i, $file_name);
|
||||
push(@total_updates, $i);
|
||||
}
|
||||
print "\n";
|
||||
|
||||
if (scalar(@total_updates) == 0 && $db_run_stage == 2) {
|
||||
|
||||
if (scalar(@total_updates) == 0) {
|
||||
print "[Database] No updates need to be run...\n";
|
||||
if ($bots_db_management == 1) {
|
||||
print "[Database] Setting Database to Bots Binary Version (" . $binary_database_version . ") if not already...\n\n";
|
||||
@@ -2416,24 +2289,106 @@ sub run_database_check {
|
||||
print "[Database] Setting Database to Binary Version (" . $binary_database_version . ") if not already...\n\n";
|
||||
get_mysql_result("UPDATE db_version SET version = $binary_database_version ");
|
||||
}
|
||||
|
||||
|
||||
clear_database_runs();
|
||||
return;
|
||||
}
|
||||
|
||||
#::: Execute pending updates
|
||||
@total_updates = sort @total_updates;
|
||||
foreach my $val (@total_updates) {
|
||||
$file_name = trim($m_d{$val}[1]);
|
||||
$query_check = trim($m_d{$val}[2]);
|
||||
$match_type = trim($m_d{$val}[3]);
|
||||
$match_text = trim($m_d{$val}[4]);
|
||||
|
||||
#::: Match type update
|
||||
if ($match_type eq "contains") {
|
||||
if (trim(get_mysql_result($query_check)) =~ /$match_text/i) {
|
||||
print "[Database] Applying update [" . $val . "]:[" . $file_name . "]\n";
|
||||
print get_mysql_result_from_file("db_update/$file_name");
|
||||
}
|
||||
else {
|
||||
print "[Database] Has update [" . $val . "]:[" . $file_name . "]\n";
|
||||
}
|
||||
print_match_debug();
|
||||
print_break();
|
||||
}
|
||||
if ($match_type eq "missing") {
|
||||
if (get_mysql_result($query_check) =~ /$match_text/i) {
|
||||
print "[Database] Has update [" . $val . "]:[" . $file_name . "]\n";
|
||||
}
|
||||
else {
|
||||
print "[Database] Applying update [" . $val . "]:[" . $file_name . "]\n";
|
||||
print get_mysql_result_from_file("db_update/$file_name");
|
||||
}
|
||||
print_match_debug();
|
||||
print_break();
|
||||
}
|
||||
if ($match_type eq "empty") {
|
||||
if (get_mysql_result($query_check) eq "") {
|
||||
print "[Database] Applying update [" . $val . "]:[" . $file_name . "]\n";
|
||||
print get_mysql_result_from_file("db_update/$file_name");
|
||||
}
|
||||
else {
|
||||
print "[Database] Has update [" . $val . "]:[" . $file_name . "' \n";
|
||||
}
|
||||
print_match_debug();
|
||||
print_break();
|
||||
}
|
||||
if ($match_type eq "not_empty") {
|
||||
if (get_mysql_result($query_check) ne "") {
|
||||
print "[Database] Applying update [" . $val . "]:[" . $file_name . "]\n";
|
||||
print get_mysql_result_from_file("db_update/$file_name");
|
||||
}
|
||||
else {
|
||||
print "[Database] Has update [" . $val . "]:[" . $file_name . "]\n";
|
||||
}
|
||||
print_match_debug();
|
||||
print_break();
|
||||
}
|
||||
|
||||
if ($bots_db_management == 1) {
|
||||
print get_mysql_result("UPDATE db_version SET bots_version = $val WHERE bots_version < $val");
|
||||
|
||||
if ($val == 9000) {
|
||||
modify_db_for_bots();
|
||||
}
|
||||
}
|
||||
else {
|
||||
print get_mysql_result("UPDATE db_version SET version = $val WHERE version < $val");
|
||||
|
||||
if ($val == 9138) {
|
||||
fix_quest_factions();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($bots_db_management == 1) {
|
||||
print "[Database] Bots database update cycle complete at version [" . get_bots_db_version() . "]\n";
|
||||
}
|
||||
else {
|
||||
print "[Database] Mainstream database update cycle complete at version [" . get_main_db_version() . "]\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub fetch_missing_db_update {
|
||||
$db_update = $_[0];
|
||||
$update_file = $_[1];
|
||||
if ($db_update >= 9000) {
|
||||
if ($bots_db_management == 1) {
|
||||
|
||||
if ($bots_db_management == 1) {
|
||||
if ($db_update >= 9000) {
|
||||
get_remote_file($eqemu_repository_request_url . "utils/sql/git/bots/required/" . $update_file, "db_update/" . $update_file . "");
|
||||
}
|
||||
else {
|
||||
}
|
||||
else {
|
||||
if ($db_update >= 9000) {
|
||||
get_remote_file($eqemu_repository_request_url . "utils/sql/git/required/" . $update_file, "db_update/" . $update_file . "");
|
||||
}
|
||||
}
|
||||
elsif ($db_update >= 5000 && $db_update <= 9000) {
|
||||
get_remote_file($eqemu_repository_request_url . "utils/sql/svn/" . $update_file, "db_update/" . $update_file . "");
|
||||
elsif ($db_update >= 5000 && $db_update <= 9000) {
|
||||
get_remote_file($eqemu_repository_request_url . "utils/sql/svn/" . $update_file, "db_update/" . $update_file . "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
account
|
||||
account_ip
|
||||
account_flags
|
||||
account_rewards
|
||||
adventure_details
|
||||
adventure_stats
|
||||
buyer
|
||||
char_recipe_list
|
||||
character_activities
|
||||
character_alt_currency
|
||||
character_alternate_abilities
|
||||
character_auras
|
||||
character_bandolier
|
||||
character_bind
|
||||
character_buffs
|
||||
character_corpse_items
|
||||
character_corpses
|
||||
character_currency
|
||||
character_data
|
||||
character_disciplines
|
||||
character_enabledtasks
|
||||
character_inspect_messages
|
||||
character_item_recast
|
||||
character_languages
|
||||
character_leadership_abilities
|
||||
character_material
|
||||
character_memmed_spells
|
||||
character_pet_buffs
|
||||
character_pet_info
|
||||
character_pet_inventory
|
||||
character_potionbelt
|
||||
character_skills
|
||||
character_spells
|
||||
character_tasks
|
||||
character_tribute
|
||||
completed_tasks
|
||||
data_buckets
|
||||
faction_values
|
||||
friends
|
||||
guild_bank
|
||||
guild_members
|
||||
guild_ranks
|
||||
guild_relations
|
||||
guilds
|
||||
instance_list_player
|
||||
inventory
|
||||
inventory_snapshots
|
||||
keyring
|
||||
mail
|
||||
player_titlesets
|
||||
quest_globals
|
||||
sharedbank
|
||||
timers
|
||||
titles
|
||||
trader
|
||||
trader_audit
|
||||
zone_flags"
|
||||
@@ -1,6 +0,0 @@
|
||||
command_settings
|
||||
inventory_versions
|
||||
launcher
|
||||
rule_sets
|
||||
rule_values
|
||||
variables
|
||||
@@ -400,6 +400,12 @@
|
||||
9144|2019_11_09_logsys_description_update.sql|SELECT * FROM db_version WHERE version >= 9143|empty|
|
||||
9145|2019_12_24_banned_ips_update.sql|SHOW TABLES LIKE 'Banned_IPs'|not_empty|
|
||||
9146|2020_01_10_character_soft_deletes.sql|SHOW COLUMNS FROM `character_data` LIKE 'deleted_at'|empty|
|
||||
9147|2020_01_24_grid_centerpoint_wp.sql|SHOW COLUMNS FROM `grid_entries` LIKE 'centerpoint'|empty|
|
||||
9148|2020_01_28_corpse_guild_consent_id.sql|SHOW COLUMNS FROM `character_corpses` LIKE 'guild_consent_id'|empty|
|
||||
9149|2020_02_06_globalloot.sql|SHOW COLUMNS FROM `global_loot` LIKE 'hot_zone'|empty|
|
||||
9150|2020_02_06_aa_reset_on_death.sql|SHOW COLUMNS FROM `aa_ability` LIKE 'reset_on_death'|empty|
|
||||
9151|2020_03_05_npc_always_aggro.sql|SHOW COLUMNS FROM `npc_types` LIKE 'always_aggro'|empty|
|
||||
9152|2020_03_09_convert_myisam_to_innodb.sql|SELECT * FROM db_version WHERE version >= 9152|empty|
|
||||
|
||||
# Upgrade conditions:
|
||||
# This won't be needed after this system is implemented, but it is used database that are not
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
9024|2019_06_27_bots_pet_get_lost.sql|SELECT `bot_command` FROM `bot_command_settings` WHERE `bot_command` LIKE 'petgetlost'|empty|
|
||||
9025|2019_08_26_bots_owner_option_spawn_message.sql|SELECT * FROM db_version WHERE bots_version >= 9025|empty|
|
||||
9026|2019_09_09_bots_owner_options_rework.sql|SHOW COLUMNS FROM `bot_owner_options` LIKE 'option_type'|empty|
|
||||
9027|2020_03_30_bots_view_update.sql|SELECT * FROM db_version WHERE bots_version >= 9027|empty|
|
||||
|
||||
# Upgrade conditions:
|
||||
# This won't be needed after this system is implemented, but it is used database that are not
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
DROP VIEW IF EXISTS `vw_bot_character_mobs`;
|
||||
|
||||
-- Views
|
||||
CREATE VIEW `vw_bot_character_mobs` AS
|
||||
SELECT
|
||||
_utf8'C' AS mob_type,
|
||||
c.`id`,
|
||||
c.`name`,
|
||||
c.`class`,
|
||||
c.`level`,
|
||||
c.`last_login`,
|
||||
c.`zone_id`,
|
||||
c.`deleted_at`
|
||||
FROM `character_data` AS c
|
||||
UNION ALL
|
||||
SELECT _utf8'B' AS mob_type,
|
||||
b.`bot_id` AS id,
|
||||
b.`name`,
|
||||
b.`class`,
|
||||
b.`level`,
|
||||
b.`last_spawn` AS last_login,
|
||||
b.`zone_id`,
|
||||
NULL AS `deleted_at`
|
||||
FROM `bot_data` AS b;
|
||||
@@ -0,0 +1,12 @@
|
||||
-- Run this to un-reserve deleted characters
|
||||
UPDATE
|
||||
character_data
|
||||
SET
|
||||
name = SUBSTRING(
|
||||
CONCAT(name, '-deleted-', UNIX_TIMESTAMP()),
|
||||
1,
|
||||
64
|
||||
)
|
||||
WHERE
|
||||
deleted_at IS NOT NULL
|
||||
AND name NOT LIKE '%-deleted-%';
|
||||
@@ -0,0 +1,2 @@
|
||||
alter table grid_entries add column `centerpoint` tinyint(4) not null default 0;
|
||||
alter table spawngroup add column `wp_spawns` tinyint(1) unsigned not null default 0;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE `character_corpses` ADD COLUMN `guild_consent_id` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `time_of_death`;
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE `aa_ability` ADD `reset_on_death` TINYINT(4) NOT NULL DEFAULT '0';
|
||||
UPDATE `aa_ability` SET `reset_on_death` = '1' WHERE `id` = 6001;
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE `global_loot` ADD `hot_zone` TINYINT NULL;
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE `npc_types` ADD COLUMN `always_aggro` tinyint(1) NOT NULL DEFAULT 0;
|
||||
@@ -0,0 +1,95 @@
|
||||
ALTER TABLE `account_flags` ENGINE=InnoDB;
|
||||
ALTER TABLE `account_ip` ENGINE=InnoDB;
|
||||
ALTER TABLE `account` ENGINE=InnoDB;
|
||||
ALTER TABLE `adventure_template_entry_flavor` ENGINE=InnoDB;
|
||||
ALTER TABLE `adventure_template_entry` ENGINE=InnoDB;
|
||||
ALTER TABLE `altadv_vars` ENGINE=InnoDB;
|
||||
ALTER TABLE `alternate_currency` ENGINE=InnoDB;
|
||||
ALTER TABLE `banned_ips` ENGINE=InnoDB;
|
||||
ALTER TABLE `base_data` ENGINE=InnoDB;
|
||||
ALTER TABLE `blocked_spells` ENGINE=InnoDB;
|
||||
ALTER TABLE `buyer` ENGINE=InnoDB;
|
||||
ALTER TABLE `char_create_combinations` ENGINE=InnoDB;
|
||||
ALTER TABLE `char_create_point_allocations` ENGINE=InnoDB;
|
||||
ALTER TABLE `character_activities` ENGINE=InnoDB;
|
||||
ALTER TABLE `character_enabledtasks` ENGINE=InnoDB;
|
||||
ALTER TABLE `character_tasks` ENGINE=InnoDB;
|
||||
ALTER TABLE `chatchannels` ENGINE=InnoDB;
|
||||
ALTER TABLE `completed_tasks` ENGINE=InnoDB;
|
||||
ALTER TABLE `damageshieldtypes` ENGINE=InnoDB;
|
||||
ALTER TABLE `discovered_items` ENGINE=InnoDB;
|
||||
ALTER TABLE `eqtime` ENGINE=InnoDB;
|
||||
ALTER TABLE `eventlog` ENGINE=InnoDB;
|
||||
ALTER TABLE `faction_list_mod` ENGINE=InnoDB;
|
||||
ALTER TABLE `faction_list` ENGINE=InnoDB;
|
||||
ALTER TABLE `faction_values` ENGINE=InnoDB;
|
||||
ALTER TABLE `friends` ENGINE=InnoDB;
|
||||
ALTER TABLE `goallists` ENGINE=InnoDB;
|
||||
ALTER TABLE `guild_bank` ENGINE=InnoDB;
|
||||
ALTER TABLE `guild_members` ENGINE=InnoDB;
|
||||
ALTER TABLE `guild_ranks` ENGINE=InnoDB;
|
||||
ALTER TABLE `guild_relations` ENGINE=InnoDB;
|
||||
ALTER TABLE `guilds` ENGINE=InnoDB;
|
||||
ALTER TABLE `hackers` ENGINE=InnoDB;
|
||||
ALTER TABLE `horses` ENGINE=InnoDB;
|
||||
ALTER TABLE `inventory_versions` ENGINE=InnoDB;
|
||||
ALTER TABLE `item_tick` ENGINE=InnoDB;
|
||||
ALTER TABLE `items` ENGINE=InnoDB;
|
||||
ALTER TABLE `keyring` ENGINE=InnoDB;
|
||||
ALTER TABLE `launcher_zones` ENGINE=InnoDB;
|
||||
ALTER TABLE `launcher` ENGINE=InnoDB;
|
||||
ALTER TABLE `ldon_trap_entries` ENGINE=InnoDB;
|
||||
ALTER TABLE `ldon_trap_templates` ENGINE=InnoDB;
|
||||
ALTER TABLE `lfguild` ENGINE=InnoDB;
|
||||
ALTER TABLE `lootdrop_entries` ENGINE=InnoDB;
|
||||
ALTER TABLE `lootdrop` ENGINE=InnoDB;
|
||||
ALTER TABLE `loottable_entries` ENGINE=InnoDB;
|
||||
ALTER TABLE `loottable` ENGINE=InnoDB;
|
||||
ALTER TABLE `mail` ENGINE=InnoDB;
|
||||
ALTER TABLE `merc_armorinfo` ENGINE=InnoDB;
|
||||
ALTER TABLE `merc_buffs` ENGINE=InnoDB;
|
||||
ALTER TABLE `merc_inventory` ENGINE=InnoDB;
|
||||
ALTER TABLE `merc_merchant_entries` ENGINE=InnoDB;
|
||||
ALTER TABLE `merc_merchant_template_entries` ENGINE=InnoDB;
|
||||
ALTER TABLE `merc_merchant_templates` ENGINE=InnoDB;
|
||||
ALTER TABLE `merc_name_types` ENGINE=InnoDB;
|
||||
ALTER TABLE `merc_npc_types` ENGINE=InnoDB;
|
||||
ALTER TABLE `merc_spell_list_entries` ENGINE=InnoDB;
|
||||
ALTER TABLE `merc_spell_lists` ENGINE=InnoDB;
|
||||
ALTER TABLE `merc_stance_entries` ENGINE=InnoDB;
|
||||
ALTER TABLE `merc_stats` ENGINE=InnoDB;
|
||||
ALTER TABLE `merc_subtypes` ENGINE=InnoDB;
|
||||
ALTER TABLE `merc_templates` ENGINE=InnoDB;
|
||||
ALTER TABLE `merc_types` ENGINE=InnoDB;
|
||||
ALTER TABLE `merc_weaponinfo` ENGINE=InnoDB;
|
||||
ALTER TABLE `mercs` ENGINE=InnoDB;
|
||||
ALTER TABLE `name_filter` ENGINE=InnoDB;
|
||||
ALTER TABLE `npc_types` ENGINE=InnoDB;
|
||||
ALTER TABLE `object_contents` ENGINE=InnoDB;
|
||||
ALTER TABLE `petitions` ENGINE=InnoDB;
|
||||
ALTER TABLE `pets_equipmentset_entries` ENGINE=InnoDB;
|
||||
ALTER TABLE `pets_equipmentset` ENGINE=InnoDB;
|
||||
ALTER TABLE `player_titlesets` ENGINE=InnoDB;
|
||||
ALTER TABLE `proximities` ENGINE=InnoDB;
|
||||
ALTER TABLE `races` ENGINE=InnoDB;
|
||||
ALTER TABLE `raid_details` ENGINE=InnoDB;
|
||||
ALTER TABLE `raid_leaders` ENGINE=InnoDB;
|
||||
ALTER TABLE `raid_members` ENGINE=InnoDB;
|
||||
ALTER TABLE `rule_sets` ENGINE=InnoDB;
|
||||
ALTER TABLE `rule_values` ENGINE=InnoDB;
|
||||
ALTER TABLE `saylink` ENGINE=InnoDB;
|
||||
ALTER TABLE `sharedbank` ENGINE=InnoDB;
|
||||
ALTER TABLE `skill_caps` ENGINE=InnoDB;
|
||||
ALTER TABLE `spell_globals` ENGINE=InnoDB;
|
||||
ALTER TABLE `spells_new` ENGINE=InnoDB;
|
||||
ALTER TABLE `task_activities` ENGINE=InnoDB;
|
||||
ALTER TABLE `tasks` ENGINE=InnoDB;
|
||||
ALTER TABLE `tasksets` ENGINE=InnoDB;
|
||||
ALTER TABLE `timers` ENGINE=InnoDB;
|
||||
ALTER TABLE `titles` ENGINE=InnoDB;
|
||||
ALTER TABLE `trader_audit` ENGINE=InnoDB;
|
||||
ALTER TABLE `trader` ENGINE=InnoDB;
|
||||
ALTER TABLE `tradeskill_recipe_entries` ENGINE=InnoDB;
|
||||
ALTER TABLE `tradeskill_recipe` ENGINE=InnoDB;
|
||||
ALTER TABLE `variables` ENGINE=InnoDB;
|
||||
ALTER TABLE `veteran_reward_templates` ENGINE=InnoDB;
|
||||
Executable
+71
@@ -0,0 +1,71 @@
|
||||
#!/usr/bin/env bash
|
||||
# Run from the context of server directory
|
||||
|
||||
world_path=""
|
||||
|
||||
#############################################
|
||||
# world path
|
||||
#############################################
|
||||
if [ -d "bin" ]
|
||||
then
|
||||
world_path="bin/"
|
||||
fi
|
||||
|
||||
world_bin="${world_path}world"
|
||||
|
||||
echo "World path is [$world_path] bin is [$world_bin]"
|
||||
|
||||
#############################################
|
||||
# dump
|
||||
#############################################
|
||||
|
||||
dump_path=/tmp/peq-dump/
|
||||
echo "Generating dump path [${dump_path}]"
|
||||
rm -rf ${dump_path}
|
||||
mkdir -p ${dump_path}
|
||||
|
||||
#############################################
|
||||
# generate "drop_" table files
|
||||
#############################################
|
||||
echo "Generating [drop_*] table exports..."
|
||||
bash -c "${world_bin} database:dump --content-tables --drop-table-syntax-only --dump-output-to-console > ${dump_path}drop_tables_content.sql"
|
||||
bash -c "${world_bin} database:dump --login-tables --drop-table-syntax-only --dump-output-to-console > ${dump_path}drop_tables_login.sql"
|
||||
bash -c "${world_bin} database:dump --player-tables --drop-table-syntax-only --dump-output-to-console > ${dump_path}drop_tables_player.sql"
|
||||
bash -c "${world_bin} database:dump --system-tables --drop-table-syntax-only --dump-output-to-console > ${dump_path}drop_tables_system.sql"
|
||||
bash -c "${world_bin} database:dump --state-tables --drop-table-syntax-only --dump-output-to-console > ${dump_path}drop_tables_state.sql"
|
||||
bash -c "${world_bin} database:dump --query-serv-tables --drop-table-syntax-only --dump-output-to-console > ${dump_path}drop_tables_queryserv.sql"
|
||||
|
||||
#############################################
|
||||
# generate "create_" table files
|
||||
#############################################
|
||||
echo "Generating [create_*] table exports..."
|
||||
|
||||
# structure only
|
||||
bash -c "${world_bin} database:dump --login-tables --table-structure-only --dump-output-to-console | sed 's/ AUTO_INCREMENT=[0-9]*\b//g' > ${dump_path}create_tables_login.sql"
|
||||
bash -c "${world_bin} database:dump --player-tables --table-structure-only --dump-output-to-console | sed 's/ AUTO_INCREMENT=[0-9]*\b//g' > ${dump_path}create_tables_player.sql"
|
||||
bash -c "${world_bin} database:dump --state-tables --table-structure-only --dump-output-to-console | sed 's/ AUTO_INCREMENT=[0-9]*\b//g' > ${dump_path}create_tables_state.sql"
|
||||
echo 'REPLACE INTO `instance_list` VALUES (1,25,1,1,0,0,1),(2,25,2,1,0,0,1),(3,151,1,1,0,0,1),(4,114,1,1,0,0,1),(5,344,1,1,0,0,1),(6,202,0,1,0,0,1);' >> "${dump_path}create_tables_state.sql"
|
||||
bash -c "${world_bin} database:dump --query-serv-tables --table-structure-only --dump-output-to-console | sed 's/ AUTO_INCREMENT=[0-9]*\b//g' > ${dump_path}create_tables_queryserv.sql"
|
||||
|
||||
# with content
|
||||
bash -c "${world_bin} database:dump --content-tables --dump-output-to-console > ${dump_path}create_tables_content.sql"
|
||||
bash -c "${world_bin} database:dump --system-tables --dump-output-to-console > ${dump_path}create_tables_system.sql"
|
||||
|
||||
#############################################
|
||||
# "all" exports
|
||||
#############################################
|
||||
bash -c "cd ${dump_path} && ls * | grep create | sed 's/.*/source &;/' > create_all_tables.sql"
|
||||
bash -c "cd ${dump_path} && ls * | grep drop | sed 's/.*/source &;/' > drop_all_tables.sql"
|
||||
|
||||
#############################################
|
||||
# zip
|
||||
#############################################
|
||||
human_date=$(date +"%B-%d-%Y" | tr '[:upper:]' '[:lower:]')
|
||||
|
||||
echo "Compressing..."
|
||||
bash -c "cd /tmp/ && rm -rf peq-latest.zip && zip peq-latest.zip peq-dump/* && mv ${dump_path}peq-latest.zip /tmp/peq-latest.zip"
|
||||
|
||||
echo "Cleaning up..."
|
||||
rm -rf ${dump_path}
|
||||
|
||||
echo "Dump located [/tmp/peq-latest.zip]"
|
||||
@@ -1,113 +0,0 @@
|
||||
aa_ability
|
||||
aa_actions
|
||||
aa_effects
|
||||
aa_rank_effects
|
||||
aa_rank_prereqs
|
||||
aa_ranks
|
||||
aa_required_level_cost
|
||||
adventure_template
|
||||
adventure_template_entry
|
||||
adventure_template_entry_flavor
|
||||
altadv_vars
|
||||
alternate_currency
|
||||
auras
|
||||
base_data
|
||||
blocked_spells
|
||||
books
|
||||
bug_reports
|
||||
char_create_combinations
|
||||
char_create_point_allocations
|
||||
class_skill
|
||||
damageshieldtypes
|
||||
data_buckets
|
||||
db_str
|
||||
doors
|
||||
eqtime
|
||||
faction_base_data
|
||||
faction_list
|
||||
faction_list_mod
|
||||
fear_hints
|
||||
fishing
|
||||
forage
|
||||
global_loot
|
||||
goallists
|
||||
graveyard
|
||||
grid
|
||||
grid_entries
|
||||
ground_spawns
|
||||
horses
|
||||
instance_list
|
||||
items
|
||||
ip_exemptions
|
||||
ldon_trap_entries
|
||||
ldon_trap_templates
|
||||
level_exp_mods
|
||||
logsys_categories
|
||||
lootdrop
|
||||
lootdrop_entries
|
||||
loottable
|
||||
loottable_entries
|
||||
merc_armorinfo
|
||||
merc_buffs
|
||||
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
|
||||
merchantlist
|
||||
mercs
|
||||
name_filter
|
||||
npc_emotes
|
||||
npc_faction
|
||||
npc_faction_entries
|
||||
npc_scale_global_base
|
||||
npc_spells
|
||||
npc_spells_effects
|
||||
npc_spells_effects_entries
|
||||
npc_spells_entries
|
||||
npc_types
|
||||
npc_types_metadata
|
||||
npc_types_tint
|
||||
object
|
||||
perl_event_export_settings
|
||||
pets
|
||||
pets_equipmentset
|
||||
pets_equipmentset_entries
|
||||
profanity_list
|
||||
proximities
|
||||
races
|
||||
saylink
|
||||
skill_caps
|
||||
spawn2
|
||||
spawn_condition_values
|
||||
spawn_conditions
|
||||
spawn_events
|
||||
spawnentry
|
||||
spawngroup
|
||||
spells_new
|
||||
start_zones
|
||||
starting_items
|
||||
task_activities
|
||||
tasks
|
||||
tasksets
|
||||
titles
|
||||
tradeskill_recipe
|
||||
tradeskill_recipe_entries
|
||||
traps
|
||||
tribute_levels
|
||||
tributes
|
||||
veteran_reward_templates
|
||||
zone
|
||||
zone_points
|
||||
zone_server
|
||||
zone_state_dump
|
||||
zoneserver_auth
|
||||
@@ -1,94 +0,0 @@
|
||||
aa_timers
|
||||
account
|
||||
account_flags
|
||||
account_ip
|
||||
account_rewards
|
||||
adventure_details
|
||||
adventure_members
|
||||
adventure_stats
|
||||
banned_ips
|
||||
bugs
|
||||
buyer
|
||||
char_recipe_list
|
||||
character_activities
|
||||
character_alt_currency
|
||||
character_alternate_abilities
|
||||
character_auras
|
||||
character_bandolier
|
||||
character_bind
|
||||
character_buffs
|
||||
character_corpse_items
|
||||
character_corpses
|
||||
character_currency
|
||||
character_data
|
||||
character_disciplines
|
||||
character_enabledtasks
|
||||
character_inspect_messages
|
||||
character_item_recast
|
||||
character_languages
|
||||
character_leadership_abilities
|
||||
character_material
|
||||
character_memmed_spells
|
||||
character_pet_buffs
|
||||
character_pet_info
|
||||
character_pet_inventory
|
||||
character_potionbelt
|
||||
character_skills
|
||||
character_spells
|
||||
character_tasks
|
||||
character_tribute
|
||||
chatchannels
|
||||
completed_tasks
|
||||
discovered_items
|
||||
eventlog
|
||||
faction_values
|
||||
friends
|
||||
gm_ips
|
||||
group_id
|
||||
group_leaders
|
||||
guild_bank
|
||||
guild_members
|
||||
guild_ranks
|
||||
guild_relations
|
||||
guilds
|
||||
hackers
|
||||
instance_list_player
|
||||
inventory
|
||||
inventory_snapshots
|
||||
item_tick
|
||||
keyring
|
||||
launcher_zones
|
||||
lfguild
|
||||
mail
|
||||
merchantlist_temp
|
||||
object_contents
|
||||
petitions
|
||||
player_titlesets
|
||||
qs_merchant_transaction_record
|
||||
qs_merchant_transaction_record_entries
|
||||
qs_player_aa_rate_hourly
|
||||
qs_player_delete_record
|
||||
qs_player_delete_record_entries
|
||||
qs_player_events
|
||||
qs_player_handin_record
|
||||
qs_player_handin_record_entries
|
||||
qs_player_move_record
|
||||
qs_player_move_record_entries
|
||||
qs_player_npc_kill_record
|
||||
qs_player_npc_kill_record_entries
|
||||
qs_player_speech
|
||||
qs_player_trade_record
|
||||
qs_player_trade_record_entries
|
||||
quest_globals
|
||||
raid_details
|
||||
raid_leaders
|
||||
raid_members
|
||||
reports
|
||||
respawn_times
|
||||
sharedbank
|
||||
spell_buckets
|
||||
spell_globals
|
||||
timers
|
||||
trader
|
||||
trader_audit
|
||||
zone_flags
|
||||
+36
-7
@@ -802,9 +802,9 @@ void ConsoleIpLookup(
|
||||
const std::vector<std::string> &args
|
||||
)
|
||||
{
|
||||
if (args.size() > 0) {
|
||||
if (!args.empty()) {
|
||||
WorldConsoleTCPConnection console_connection(connection);
|
||||
client_list.SendCLEList(connection->Admin(), 0, &console_connection, args[0].c_str());
|
||||
client_list.SendCLEList(connection->Admin(), nullptr, &console_connection, args[0].c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -855,6 +855,34 @@ void ConsoleReloadWorld(
|
||||
safe_delete(pack);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param connection
|
||||
* @param command
|
||||
* @param args
|
||||
*/
|
||||
void ConsoleReloadZoneQuests(
|
||||
EQ::Net::ConsoleServerConnection *connection,
|
||||
const std::string &command,
|
||||
const std::vector<std::string> &args
|
||||
)
|
||||
{
|
||||
if (args.empty()) {
|
||||
connection->SendLine("[zone_short_name] required as argument");
|
||||
return;
|
||||
}
|
||||
|
||||
std::string zone_short_name = args[0];
|
||||
|
||||
connection->SendLine(fmt::format("Reloading Zone [{}]...", zone_short_name));
|
||||
|
||||
auto pack = new ServerPacket(ServerOP_HotReloadQuests, sizeof(HotReloadQuestsStruct));
|
||||
auto *hot_reload_quests = (HotReloadQuestsStruct *) pack->pBuffer;
|
||||
strn0cpy(hot_reload_quests->zone_short_name, (char *) zone_short_name.c_str(), 200);
|
||||
|
||||
zoneserver_list.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param connection
|
||||
* @param command
|
||||
@@ -892,18 +920,19 @@ void RegisterConsoleFunctions(std::unique_ptr<EQ::Net::ConsoleServer>& console)
|
||||
console->RegisterCall("md5", 50, "md5", std::bind(ConsoleMd5, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
console->RegisterCall("ooc", 50, "ooc [message]", std::bind(ConsoleOOC, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
console->RegisterCall("reloadworld", 200, "reloadworld", std::bind(ConsoleReloadWorld, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
console->RegisterCall("setpass", 200, "setpass [accountname] [newpass]", std::bind(ConsoleSetPass, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
console->RegisterCall("reloadzonequests", 200, "reloadzonequests [zone_short_name]", std::bind(ConsoleReloadZoneQuests, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
console->RegisterCall("setpass", 200, "setpass [account_name] [new_password]", std::bind(ConsoleSetPass, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
console->RegisterCall("signalcharbyname", 50, "signalcharbyname charname ID", std::bind(ConsoleSignalCharByName, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
console->RegisterCall("tell", 50, "tell [name] [message]", std::bind(ConsoleTell, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
console->RegisterCall("unlock", 150, "unlock", std::bind(ConsoleUnlock, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
console->RegisterCall("uptime", 50, "uptime [zoneID#]", std::bind(ConsoleUptime, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
console->RegisterCall("uptime", 50, "uptime [zone_server_id]", std::bind(ConsoleUptime, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
console->RegisterCall("version", 50, "version", std::bind(ConsoleVersion, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
console->RegisterCall("who", 50, "who", std::bind(ConsoleWho, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
console->RegisterCall("whoami", 50, "whoami", std::bind(ConsoleWhoami, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
console->RegisterCall("worldshutdown", 200, "worldshutdown", std::bind(ConsoleWorldShutdown, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
console->RegisterCall("zonebootup", 150, "zonebootup [ZoneServerID] [zonename]", std::bind(ConsoleZoneBootup, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
console->RegisterCall("zonelock", 150, "zonelock [list|lock|unlock] [zonename]", std::bind(ConsoleZoneLock, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
console->RegisterCall("zoneshutdown", 150, "zoneshutdown [zonename or ZoneServerID]", std::bind(ConsoleZoneShutdown, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
console->RegisterCall("zonebootup", 150, "zonebootup [zone_server_id] [zone_short_name]", std::bind(ConsoleZoneBootup, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
console->RegisterCall("zonelock", 150, "zonelock [list|lock|unlock] [zone_short_name]", std::bind(ConsoleZoneLock, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
console->RegisterCall("zoneshutdown", 150, "zoneshutdown [zone_short_name or zone_server_id]", std::bind(ConsoleZoneShutdown, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
console->RegisterCall("zonestatus", 50, "zonestatus", std::bind(ConsoleZoneStatus, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));console->RegisterCall("ping", 50, "ping", std::bind(ConsoleNull, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
console->RegisterCall("quit", 50, "quit", std::bind(ConsoleQuit, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
console->RegisterCall("exit", 50, "exit", std::bind(ConsoleQuit, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
|
||||
@@ -415,6 +415,7 @@ int main(int argc, char** argv) {
|
||||
RegisterConsoleFunctions(console);
|
||||
}
|
||||
|
||||
zoneserver_list.Init();
|
||||
std::unique_ptr<EQ::Net::ServertalkServer> server_connection;
|
||||
server_connection.reset(new EQ::Net::ServertalkServer());
|
||||
|
||||
|
||||
+30
-11
@@ -6,29 +6,38 @@
|
||||
#include "../common/misc_functions.h"
|
||||
#include "../common/md5.h"
|
||||
#include "../common/packet_dump.h"
|
||||
#include "../common/event/timer.h"
|
||||
|
||||
UCSConnection::UCSConnection()
|
||||
{
|
||||
Stream = 0;
|
||||
connection = 0;
|
||||
}
|
||||
|
||||
void UCSConnection::SetConnection(std::shared_ptr<EQ::Net::ServertalkServerConnection> inStream)
|
||||
{
|
||||
if (Stream && Stream->Handle())
|
||||
{
|
||||
if (inStream && connection && connection->Handle()) {
|
||||
LogInfo("Incoming UCS Connection while we were already connected to a UCS");
|
||||
Stream->Handle()->Disconnect();
|
||||
connection->Handle()->Disconnect();
|
||||
}
|
||||
|
||||
connection = inStream;
|
||||
if (connection) {
|
||||
connection->OnMessage(
|
||||
std::bind(
|
||||
&UCSConnection::ProcessPacket,
|
||||
this,
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Stream = inStream;
|
||||
if (Stream) {
|
||||
Stream->OnMessage(std::bind(&UCSConnection::ProcessPacket, this, std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
m_keepalive.reset(new EQ::Timer(5000, true, std::bind(&UCSConnection::OnKeepAlive, this, std::placeholders::_1)));
|
||||
}
|
||||
|
||||
void UCSConnection::ProcessPacket(uint16 opcode, EQ::Net::Packet &p)
|
||||
{
|
||||
if (!Stream)
|
||||
if (!connection)
|
||||
return;
|
||||
|
||||
ServerPacket tpack(opcode, p);
|
||||
@@ -60,10 +69,10 @@ void UCSConnection::ProcessPacket(uint16 opcode, EQ::Net::Packet &p)
|
||||
|
||||
void UCSConnection::SendPacket(ServerPacket* pack)
|
||||
{
|
||||
if (!Stream)
|
||||
if (!connection)
|
||||
return;
|
||||
|
||||
Stream->SendPacket(pack);
|
||||
connection->SendPacket(pack);
|
||||
}
|
||||
|
||||
void UCSConnection::SendMessage(const char *From, const char *Message)
|
||||
@@ -78,3 +87,13 @@ void UCSConnection::SendMessage(const char *From, const char *Message)
|
||||
SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
}
|
||||
|
||||
void UCSConnection::OnKeepAlive(EQ::Timer *t)
|
||||
{
|
||||
if (!connection) {
|
||||
return;
|
||||
}
|
||||
|
||||
ServerPacket pack(ServerOP_KeepAlive, 0);
|
||||
connection->SendPacket(&pack);
|
||||
}
|
||||
|
||||
+10
-3
@@ -4,6 +4,7 @@
|
||||
#include "../common/types.h"
|
||||
#include "../common/net/servertalk_server_connection.h"
|
||||
#include "../common/servertalk.h"
|
||||
#include "../common/event/timer.h"
|
||||
#include <memory>
|
||||
|
||||
class UCSConnection
|
||||
@@ -13,11 +14,17 @@ public:
|
||||
void SetConnection(std::shared_ptr<EQ::Net::ServertalkServerConnection> connection);
|
||||
void ProcessPacket(uint16 opcode, EQ::Net::Packet &p);
|
||||
void SendPacket(ServerPacket* pack);
|
||||
void Disconnect() { if(Stream && Stream->Handle()) Stream->Handle()->Disconnect(); }
|
||||
void Disconnect() { if(connection && connection->Handle()) connection->Handle()->Disconnect(); }
|
||||
void SendMessage(const char *From, const char *Message);
|
||||
private:
|
||||
inline std::string GetIP() const { return (Stream && Stream->Handle()) ? Stream->Handle()->RemoteIP() : 0; }
|
||||
std::shared_ptr<EQ::Net::ServertalkServerConnection> Stream;
|
||||
inline std::string GetIP() const { return (connection && connection->Handle()) ? connection->Handle()->RemoteIP() : 0; }
|
||||
std::shared_ptr<EQ::Net::ServertalkServerConnection> connection;
|
||||
|
||||
/**
|
||||
* Keepalive
|
||||
*/
|
||||
std::unique_ptr<EQ::Timer> m_keepalive;
|
||||
void OnKeepAlive(EQ::Timer *t);
|
||||
};
|
||||
|
||||
#endif /*UCS_H_*/
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "../common/version.h"
|
||||
#include "worlddb.h"
|
||||
#include "../common/database_schema.h"
|
||||
#include "../common/database/database_dump_service.h"
|
||||
|
||||
namespace WorldserverCommandHandler {
|
||||
|
||||
@@ -51,6 +52,7 @@ namespace WorldserverCommandHandler {
|
||||
function_map["database:version"] = &WorldserverCommandHandler::DatabaseVersion;
|
||||
function_map["database:set-account-status"] = &WorldserverCommandHandler::DatabaseSetAccountStatus;
|
||||
function_map["database:schema"] = &WorldserverCommandHandler::DatabaseGetSchema;
|
||||
function_map["database:dump"] = &WorldserverCommandHandler::DatabaseDump;
|
||||
|
||||
EQEmuCommand::HandleMenu(function_map, cmd, argc, argv);
|
||||
}
|
||||
@@ -145,7 +147,7 @@ namespace WorldserverCommandHandler {
|
||||
*/
|
||||
void DatabaseGetSchema(int argc, char **argv, argh::parser &cmd, std::string &description)
|
||||
{
|
||||
description = "Displays server database schema";
|
||||
description = "Displays server database schema";
|
||||
|
||||
if (cmd[{"-h", "--help"}]) {
|
||||
return;
|
||||
@@ -202,4 +204,71 @@ namespace WorldserverCommandHandler {
|
||||
std::cout << payload.str() << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param argc
|
||||
* @param argv
|
||||
* @param cmd
|
||||
* @param description
|
||||
*/
|
||||
void DatabaseDump(int argc, char **argv, argh::parser &cmd, std::string &description)
|
||||
{
|
||||
description = "Dumps server database tables";
|
||||
|
||||
if (cmd[{"-h", "--help"}]) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::string> arguments = {};
|
||||
std::vector<std::string> options = {
|
||||
"--all",
|
||||
"--content-tables",
|
||||
"--login-tables",
|
||||
"--player-tables",
|
||||
"--state-tables",
|
||||
"--system-tables",
|
||||
"--query-serv-tables",
|
||||
"--table-structure-only",
|
||||
"--table-lock",
|
||||
"--dump-path=",
|
||||
"--dump-output-to-console",
|
||||
"--drop-table-syntax-only",
|
||||
"--compress"
|
||||
};
|
||||
|
||||
|
||||
if (argc < 3) {
|
||||
EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv);
|
||||
return;
|
||||
}
|
||||
|
||||
auto database_dump_service = new DatabaseDumpService();
|
||||
bool dump_all = cmd[{"-a", "--all"}];
|
||||
|
||||
if (!cmd("--dump-path").str().empty()) {
|
||||
database_dump_service->SetDumpPath(cmd("--dump-path").str());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Option
|
||||
*/
|
||||
database_dump_service->SetDumpContentTables(cmd[{"--content-tables"}] || dump_all);
|
||||
database_dump_service->SetDumpLoginServerTables(cmd[{"--login-tables"}] || dump_all);
|
||||
database_dump_service->SetDumpPlayerTables(cmd[{"--player-tables"}] || dump_all);
|
||||
database_dump_service->SetDumpStateTables(cmd[{"--state-tables"}] || dump_all);
|
||||
database_dump_service->SetDumpSystemTables(cmd[{"--system-tables"}] || dump_all);
|
||||
database_dump_service->SetDumpQueryServerTables(cmd[{"--query-serv-tables"}] || dump_all);
|
||||
database_dump_service->SetDumpAllTables(dump_all);
|
||||
|
||||
database_dump_service->SetDumpWithNoData(cmd[{"--table-structure-only"}]);
|
||||
database_dump_service->SetDumpTableLock(cmd[{"--table-lock"}]);
|
||||
database_dump_service->SetDumpWithCompression(cmd[{"--compress"}]);
|
||||
database_dump_service->SetDumpOutputToConsole(cmd[{"--dump-output-to-console"}]);
|
||||
database_dump_service->SetDumpDropTableSyntaxOnly(cmd[{"--drop-table-syntax-only"}]);
|
||||
|
||||
/**
|
||||
* Dump
|
||||
*/
|
||||
database_dump_service->Dump();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -30,6 +30,7 @@ namespace WorldserverCommandHandler {
|
||||
void DatabaseVersion(int argc, char **argv, argh::parser &cmd, std::string &description);
|
||||
void DatabaseSetAccountStatus(int argc, char **argv, argh::parser &cmd, std::string &description);
|
||||
void DatabaseGetSchema(int argc, char **argv, argh::parser &cmd, std::string &description);
|
||||
void DatabaseDump(int argc, char **argv, argh::parser &cmd, std::string &description);
|
||||
};
|
||||
|
||||
|
||||
|
||||
+19
-22
@@ -39,7 +39,6 @@ ZSList::ZSList()
|
||||
{
|
||||
NextID = 1;
|
||||
CurGroupID = 1;
|
||||
LastAllocatedPort = 0;
|
||||
memset(pLockedZones, 0, sizeof(pLockedZones));
|
||||
|
||||
m_tick.reset(new EQ::Timer(5000, true, std::bind(&ZSList::OnTick, this, std::placeholders::_1)));
|
||||
@@ -76,7 +75,12 @@ void ZSList::Remove(const std::string &uuid)
|
||||
auto iter = zone_server_list.begin();
|
||||
while (iter != zone_server_list.end()) {
|
||||
if ((*iter)->GetUUID().compare(uuid) == 0) {
|
||||
auto port = (*iter)->GetCPort();
|
||||
zone_server_list.erase(iter);
|
||||
|
||||
if (port != 0) {
|
||||
m_ports_free.push_back(port);
|
||||
}
|
||||
return;
|
||||
}
|
||||
iter++;
|
||||
@@ -239,6 +243,14 @@ bool ZSList::SetLockedZone(uint16 iZoneID, bool iLock) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void ZSList::Init()
|
||||
{
|
||||
const WorldConfig* Config = WorldConfig::get();
|
||||
for (uint16 i = Config->ZonePortLow; i <= Config->ZonePortHigh; ++i) {
|
||||
m_ports_free.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
bool ZSList::IsZoneLocked(uint16 iZoneID) {
|
||||
for (auto &zone : pLockedZones) {
|
||||
if (zone == iZoneID)
|
||||
@@ -577,30 +589,15 @@ void ZSList::RebootZone(const char* ip1, uint16 port, const char* ip2, uint32 sk
|
||||
safe_delete_array(tmp);
|
||||
}
|
||||
|
||||
uint16 ZSList::GetAvailableZonePort()
|
||||
uint16 ZSList::GetAvailableZonePort()
|
||||
{
|
||||
const WorldConfig *Config = WorldConfig::get();
|
||||
int i;
|
||||
uint16 port = 0;
|
||||
|
||||
if (LastAllocatedPort == 0)
|
||||
i = Config->ZonePortLow;
|
||||
else
|
||||
i = LastAllocatedPort + 1;
|
||||
|
||||
while (i != LastAllocatedPort && port == 0) {
|
||||
if (i>Config->ZonePortHigh)
|
||||
i = Config->ZonePortLow;
|
||||
|
||||
if (!FindByPort(i)) {
|
||||
port = i;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
if (m_ports_free.empty()) {
|
||||
return 0;
|
||||
}
|
||||
LastAllocatedPort = port;
|
||||
|
||||
return port;
|
||||
auto first = m_ports_free.front();
|
||||
m_ports_free.pop_front();
|
||||
return first;
|
||||
}
|
||||
|
||||
uint32 ZSList::TriggerBootup(uint32 iZoneID, uint32 iInstanceID) {
|
||||
|
||||
+3
-2
@@ -7,6 +7,7 @@
|
||||
#include "../common/event/timer.h"
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <deque>
|
||||
|
||||
class WorldTCPConnection;
|
||||
class ServerPacket;
|
||||
@@ -22,6 +23,7 @@ public:
|
||||
ZSList();
|
||||
~ZSList();
|
||||
|
||||
void Init();
|
||||
bool IsZoneLocked(uint16 iZoneID);
|
||||
bool SendPacket(ServerPacket *pack);
|
||||
bool SendPacket(uint32 zoneid, ServerPacket *pack);
|
||||
@@ -73,8 +75,7 @@ private:
|
||||
uint32 NextID;
|
||||
uint16 pLockedZones[MaxLockedZones];
|
||||
uint32 CurGroupID;
|
||||
uint16 LastAllocatedPort;
|
||||
|
||||
std::deque<uint16> m_ports_free;
|
||||
std::unique_ptr<EQ::Timer> m_tick;
|
||||
std::unique_ptr<EQ::Timer> m_keepalive;
|
||||
|
||||
|
||||
+31
-99
@@ -1057,110 +1057,42 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
||||
break;
|
||||
}
|
||||
case ServerOP_Consent: {
|
||||
// Message string id's likely to be used here are:
|
||||
// CONSENT_YOURSELF = 399
|
||||
// CONSENT_INVALID_NAME = 397
|
||||
// TARGET_NOT_FOUND = 101
|
||||
ZoneServer* zs;
|
||||
ServerOP_Consent_Struct* s = (ServerOP_Consent_Struct*)pack->pBuffer;
|
||||
ClientListEntry* cle = client_list.FindCharacter(s->grantname);
|
||||
if (cle) {
|
||||
if (cle->instance() != 0)
|
||||
{
|
||||
zs = zoneserver_list.FindByInstanceID(cle->instance());
|
||||
if (zs) {
|
||||
zs->SendPacket(pack);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct));
|
||||
ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer;
|
||||
strcpy(scs->grantname, s->grantname);
|
||||
strcpy(scs->ownername, s->ownername);
|
||||
scs->permission = s->permission;
|
||||
scs->zone_id = s->zone_id;
|
||||
scs->instance_id = s->instance_id;
|
||||
scs->message_string_id = 101;
|
||||
zs = zoneserver_list.FindByInstanceID(s->instance_id);
|
||||
if (zs) {
|
||||
zs->SendPacket(pack);
|
||||
}
|
||||
else {
|
||||
LogInfo("Unable to locate zone record for instance id [{}] in zoneserver list for ServerOP_Consent_Response operation", s->instance_id);
|
||||
}
|
||||
safe_delete(pack);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
zs = zoneserver_list.FindByZoneID(cle->zone());
|
||||
if (zs) {
|
||||
zs->SendPacket(pack);
|
||||
}
|
||||
else {
|
||||
// send target not found back to requester
|
||||
auto pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct));
|
||||
ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer;
|
||||
strcpy(scs->grantname, s->grantname);
|
||||
strcpy(scs->ownername, s->ownername);
|
||||
scs->permission = s->permission;
|
||||
scs->zone_id = s->zone_id;
|
||||
scs->message_string_id = 101;
|
||||
zs = zoneserver_list.FindByZoneID(s->zone_id);
|
||||
if (zs) {
|
||||
zs->SendPacket(pack);
|
||||
}
|
||||
else {
|
||||
LogInfo("Unable to locate zone record for zone id [{}] in zoneserver list for ServerOP_Consent_Response operation", s->zone_id);
|
||||
}
|
||||
safe_delete(pack);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// send target not found back to requester
|
||||
auto pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct));
|
||||
ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer;
|
||||
strcpy(scs->grantname, s->grantname);
|
||||
strcpy(scs->ownername, s->ownername);
|
||||
scs->permission = s->permission;
|
||||
scs->zone_id = s->zone_id;
|
||||
scs->message_string_id = 397;
|
||||
zs = zoneserver_list.FindByZoneID(s->zone_id);
|
||||
if (zs) {
|
||||
zs->SendPacket(pack);
|
||||
}
|
||||
else {
|
||||
LogInfo("Unable to locate zone record for zone id [{}] in zoneserver list for ServerOP_Consent_Response operation", s->zone_id);
|
||||
}
|
||||
safe_delete(pack);
|
||||
}
|
||||
zoneserver_list.SendPacket(pack); // update corpses in all zones
|
||||
break;
|
||||
}
|
||||
case ServerOP_Consent_Response: {
|
||||
// Message string id's likely to be used here are:
|
||||
// CONSENT_YOURSELF = 399
|
||||
// CONSENT_INVALID_NAME = 397
|
||||
// TARGET_NOT_FOUND = 101
|
||||
ServerOP_Consent_Struct* s = (ServerOP_Consent_Struct*)pack->pBuffer;
|
||||
if (s->instance_id != 0)
|
||||
{
|
||||
ZoneServer* zs = zoneserver_list.FindByInstanceID(s->instance_id);
|
||||
if (zs) {
|
||||
zs->SendPacket(pack);
|
||||
}
|
||||
else {
|
||||
LogInfo("Unable to locate zone record for instance id [{}] in zoneserver list for ServerOP_Consent_Response operation", s->instance_id);
|
||||
}
|
||||
|
||||
ZoneServer* owner_zs = nullptr;
|
||||
if (s->instance_id == 0) {
|
||||
owner_zs = zoneserver_list.FindByZoneID(s->zone_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
ZoneServer* zs = zoneserver_list.FindByZoneID(s->zone_id);
|
||||
if (zs) {
|
||||
zs->SendPacket(pack);
|
||||
}
|
||||
else {
|
||||
LogInfo("Unable to locate zone record for zone id [{}] in zoneserver list for ServerOP_Consent_Response operation", s->zone_id);
|
||||
else {
|
||||
owner_zs = zoneserver_list.FindByInstanceID(s->instance_id);
|
||||
}
|
||||
|
||||
if (owner_zs) {
|
||||
owner_zs->SendPacket(pack);
|
||||
}
|
||||
else {
|
||||
LogInfo("Unable to locate zone record for zone id [{}] or instance id [{}] in zoneserver list for ServerOP_Consent_Response operation", s->zone_id, s->instance_id);
|
||||
}
|
||||
|
||||
if (s->consent_type == EQEmu::consent::Normal) {
|
||||
// send the message to the client being granted or denied permission
|
||||
ClientListEntry* cle = client_list.FindCharacter(s->grantname);
|
||||
if (cle) {
|
||||
ZoneServer* granted_zs = nullptr;
|
||||
if (cle->instance() == 0) {
|
||||
granted_zs = zoneserver_list.FindByZoneID(cle->zone());
|
||||
}
|
||||
else {
|
||||
granted_zs = zoneserver_list.FindByInstanceID(cle->instance());
|
||||
}
|
||||
// avoid sending twice if owner and granted are in same zone
|
||||
if (granted_zs && granted_zs != owner_zs) {
|
||||
granted_zs->SendPacket(pack);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
+3
-2
@@ -82,7 +82,6 @@ SET(zone_sources
|
||||
main.cpp
|
||||
map.cpp
|
||||
merc.cpp
|
||||
metric_event_types.cpp
|
||||
mob.cpp
|
||||
mob_ai.cpp
|
||||
mob_appearance.cpp
|
||||
@@ -142,6 +141,7 @@ SET(zone_sources
|
||||
zone.cpp
|
||||
zone_config.cpp
|
||||
zonedb.cpp
|
||||
zone_reload.cpp
|
||||
zoning.cpp
|
||||
)
|
||||
|
||||
@@ -248,7 +248,8 @@ SET(zone_headers
|
||||
zone.h
|
||||
zone_config.h
|
||||
zonedb.h
|
||||
zonedump.h)
|
||||
zonedump.h
|
||||
zone_reload.h )
|
||||
|
||||
ADD_EXECUTABLE(zone ${zone_sources} ${zone_headers})
|
||||
|
||||
|
||||
+21
-2
@@ -1023,6 +1023,24 @@ void Client::ResetAlternateAdvancementTimers() {
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
void Client::ResetOnDeathAlternateAdvancement() {
|
||||
for (const auto &aa : aa_ranks) {
|
||||
auto ability_rank = zone->GetAlternateAdvancementAbilityAndRank(aa.first, aa.second.first);
|
||||
auto ability = ability_rank.first;
|
||||
auto rank = ability_rank.second;
|
||||
|
||||
if (!ability)
|
||||
continue;
|
||||
|
||||
if (!rank)
|
||||
continue;
|
||||
|
||||
// since they're dying, we just need to clear the DB
|
||||
if (ability->reset_on_death)
|
||||
p_timers.Clear(&database, rank->spell_type + pTimerAAStart);
|
||||
}
|
||||
}
|
||||
|
||||
void Client::PurchaseAlternateAdvancementRank(int rank_id) {
|
||||
AA::Rank *rank = zone->GetAlternateAdvancementRank(rank_id);
|
||||
if(!rank) {
|
||||
@@ -1646,7 +1664,7 @@ bool ZoneDatabase::LoadAlternateAdvancementAbilities(std::unordered_map<int, std
|
||||
LogInfo("Loading Alternate Advancement Abilities");
|
||||
abilities.clear();
|
||||
std::string query = "SELECT id, name, category, classes, races, deities, drakkin_heritage, status, type, charges, "
|
||||
"grant_only, first_rank_id FROM aa_ability WHERE enabled = 1";
|
||||
"grant_only, reset_on_death, first_rank_id FROM aa_ability WHERE enabled = 1";
|
||||
auto results = QueryDatabase(query);
|
||||
if(results.Success()) {
|
||||
for(auto row = results.begin(); row != results.end(); ++row) {
|
||||
@@ -1663,7 +1681,8 @@ bool ZoneDatabase::LoadAlternateAdvancementAbilities(std::unordered_map<int, std
|
||||
ability->type = atoi(row[8]);
|
||||
ability->charges = atoi(row[9]);
|
||||
ability->grant_only = atoi(row[10]) != 0 ? true : false;
|
||||
ability->first_rank_id = atoi(row[11]);
|
||||
ability->reset_on_death = atoi(row[11]) != 0 ? true : false;
|
||||
ability->first_rank_id = atoi(row[12]);
|
||||
ability->first = nullptr;
|
||||
|
||||
abilities[ability->id] = std::unique_ptr<AA::Ability>(ability);
|
||||
|
||||
@@ -50,6 +50,7 @@ public:
|
||||
int drakkin_heritage;
|
||||
int status;
|
||||
bool grant_only;
|
||||
bool reset_on_death;
|
||||
int type;
|
||||
int charges;
|
||||
int first_rank_id;
|
||||
|
||||
+11
-3
@@ -32,6 +32,7 @@
|
||||
#endif
|
||||
|
||||
#include "map.h"
|
||||
#include "water_map.h"
|
||||
|
||||
extern Zone* zone;
|
||||
//#define LOSDEBUG 6
|
||||
@@ -139,7 +140,7 @@ void NPC::DescribeAggro(Client *towho, Mob *mob, bool verbose) {
|
||||
|
||||
if (RuleB(Aggro, UseLevelAggro))
|
||||
{
|
||||
if (GetLevel() < RuleI(Aggro, MinAggroLevel) && mob->GetLevelCon(GetLevel()) == CON_GRAY && GetBodyType() != 3)
|
||||
if (GetLevel() < RuleI(Aggro, MinAggroLevel) && mob->GetLevelCon(GetLevel()) == CON_GRAY && GetBodyType() != 3 && !AlwaysAggro())
|
||||
{
|
||||
towho->Message(Chat::White, "...%s is red to me (basically)", mob->GetName(), dist2, iAggroRange2);
|
||||
return;
|
||||
@@ -147,7 +148,7 @@ void NPC::DescribeAggro(Client *towho, Mob *mob, bool verbose) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if(GetINT() > RuleI(Aggro, IntAggroThreshold) && mob->GetLevelCon(GetLevel()) == CON_GRAY ) {
|
||||
if(GetINT() > RuleI(Aggro, IntAggroThreshold) && mob->GetLevelCon(GetLevel()) == CON_GRAY && !AlwaysAggro()) {
|
||||
towho->Message(Chat::White, "...%s is red to me (basically)", mob->GetName(),
|
||||
dist2, iAggroRange2);
|
||||
return;
|
||||
@@ -237,6 +238,11 @@ bool Mob::CheckWillAggro(Mob *mob) {
|
||||
if (!mob->CastToClient()->ClientFinishedLoading() || mob->CastToClient()->IsHoveringForRespawn() || mob->CastToClient()->bZoning)
|
||||
return false;
|
||||
}
|
||||
|
||||
// We don't want to aggro clients outside of water if we're water only.
|
||||
if (mob->IsClient() && mob->CastToClient()->GetLastRegion() != RegionTypeWater && IsUnderwaterOnly()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pets shouldn't scan for aggro
|
||||
@@ -318,7 +324,7 @@ bool Mob::CheckWillAggro(Mob *mob) {
|
||||
//old InZone check taken care of above by !mob->CastToClient()->Connected()
|
||||
(
|
||||
( GetLevel() >= RuleI(Aggro, MinAggroLevel))
|
||||
||(GetBodyType() == 3)
|
||||
||(GetBodyType() == 3) || AlwaysAggro()
|
||||
||( mob->IsClient() && mob->CastToClient()->IsSitting() )
|
||||
||( mob->GetLevelCon(GetLevel()) != CON_GRAY)
|
||||
|
||||
@@ -352,6 +358,7 @@ bool Mob::CheckWillAggro(Mob *mob) {
|
||||
//old InZone check taken care of above by !mob->CastToClient()->Connected()
|
||||
(
|
||||
( GetINT() <= RuleI(Aggro, IntAggroThreshold) )
|
||||
|| AlwaysAggro()
|
||||
||( mob->IsClient() && mob->CastToClient()->IsSitting() )
|
||||
||( mob->GetLevelCon(GetLevel()) != CON_GRAY)
|
||||
|
||||
@@ -383,6 +390,7 @@ bool Mob::CheckWillAggro(Mob *mob) {
|
||||
LogAggro("Dist^2: [{}]\n", dist2);
|
||||
LogAggro("Range^2: [{}]\n", iAggroRange2);
|
||||
LogAggro("Faction: [{}]\n", fv);
|
||||
LogAggro("AlwaysAggroFlag: [{}]\n", AlwaysAggro());
|
||||
LogAggro("Int: [{}]\n", GetINT());
|
||||
LogAggro("Con: [{}]\n", GetLevelCon(mob->GetLevel()));
|
||||
|
||||
|
||||
+21
-10
@@ -724,20 +724,20 @@ int Mob::GetClassRaceACBonus()
|
||||
hardcap = 32;
|
||||
softcap = 15;
|
||||
}
|
||||
int weight = IsClient() ? CastToClient()->CalcCurrentWeight() : 0;
|
||||
int weight = IsClient() ? CastToClient()->CalcCurrentWeight()/10 : 0;
|
||||
if (weight < hardcap - 1) {
|
||||
int temp = level + 5;
|
||||
double temp = level + 5;
|
||||
if (weight > softcap) {
|
||||
double redux = (weight - softcap) * 6.66667;
|
||||
double redux = static_cast<double>(weight - softcap) * 6.66667;
|
||||
redux = (100.0 - std::min(100.0, redux)) * 0.01;
|
||||
temp = std::max(0, static_cast<int>(temp * redux));
|
||||
temp = std::max(0.0, temp * redux);
|
||||
}
|
||||
ac_bonus = (4 * temp) / 3;
|
||||
ac_bonus = static_cast<int>((4.0 * temp) / 3.0);
|
||||
}
|
||||
else if (weight > hardcap + 1) {
|
||||
int temp = level + 5;
|
||||
double multiplier = std::min(1.0, (weight - (hardcap - 10.0)) / 100.0);
|
||||
temp = (4 * temp) / 3;
|
||||
double temp = level + 5;
|
||||
double multiplier = std::min(1.0, (weight - (static_cast<double>(hardcap) - 10.0)) / 100.0);
|
||||
temp = (4.0 * temp) / 3.0;
|
||||
ac_bonus -= static_cast<int>(temp * multiplier);
|
||||
}
|
||||
}
|
||||
@@ -799,7 +799,7 @@ int Mob::ACSum()
|
||||
// EQ math
|
||||
ac = (ac * 4) / 3;
|
||||
// anti-twink
|
||||
if (IsClient() && GetLevel() < 50)
|
||||
if (IsClient() && GetLevel() < RuleI(Combat, LevelToStopACTwinkControl))
|
||||
ac = std::min(ac, 25 + 6 * GetLevel());
|
||||
ac = std::max(0, ac + GetClassRaceACBonus());
|
||||
if (IsNPC()) {
|
||||
@@ -1852,6 +1852,17 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, EQEmu::skills::Sk
|
||||
BuffFadeDetrimental();
|
||||
}
|
||||
|
||||
/*
|
||||
Reset AA reuse timers that need to be, live-like this is only Lay on Hands
|
||||
*/
|
||||
ResetOnDeathAlternateAdvancement();
|
||||
|
||||
/*
|
||||
Reset reuse timer for classic skill based Lay on Hands (For tit I guess)
|
||||
*/
|
||||
if (GetClass() == PALADIN) // we could check if it's not expired I guess, but should be fine not to
|
||||
p_timers.Clear(&database, pTimerLayHands);
|
||||
|
||||
/*
|
||||
Finally, send em home
|
||||
|
||||
@@ -5491,4 +5502,4 @@ int32 Mob::GetHPRegen() const
|
||||
int32 Mob::GetManaRegen() const
|
||||
{
|
||||
return mana_regen;
|
||||
}
|
||||
}
|
||||
|
||||
+431
-242
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -73,7 +73,7 @@ private:
|
||||
int m_owner;
|
||||
int aura_id; // spell ID of the aura spell -1 if aura isn't from a casted spell
|
||||
int spell_id; // spell we cast
|
||||
int distance; // distance we remove
|
||||
float distance; // distance we remove
|
||||
Timer remove_timer; // when we depop
|
||||
Timer process_timer; // rate limit process calls
|
||||
Timer cast_timer; // some auras pulse
|
||||
|
||||
+1
-1
@@ -56,7 +56,7 @@ Beacon::Beacon(Mob *at_mob, int lifetime)
|
||||
:Mob
|
||||
(
|
||||
nullptr, nullptr, 0, 0, 0, INVISIBLE_MAN, 0, BT_NoTarget, 0, 0, 0, 0, 0, at_mob->GetPosition(), 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, EQEmu::TintProfile(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, EQEmu::TintProfile(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false
|
||||
),
|
||||
remove_timer(lifetime),
|
||||
spell_timer(0)
|
||||
|
||||
+153
-30
@@ -6421,32 +6421,52 @@ void Bot::DoClassAttacks(Mob *target, bool IsRiposte) {
|
||||
|
||||
bool taunt_time = taunt_timer.Check();
|
||||
bool ca_time = classattack_timer.Check(false);
|
||||
bool ma_time = monkattack_timer.Check(false);
|
||||
bool ka_time = knightattack_timer.Check(false);
|
||||
if((taunt_time || ca_time || ka_time) && !IsAttackAllowed(target))
|
||||
|
||||
if (taunt_time) {
|
||||
|
||||
// Bots without this skill shouldn't be 'checking' on this timer..let's just disable it and avoid the extra IsAttackAllowed() checks
|
||||
// Note: this is done here instead of NPC::ctor() because taunt skill can be acquired during level ups (the timer is re-enabled in CalcBotStats())
|
||||
if (!GetSkill(EQEmu::skills::SkillTaunt)) {
|
||||
|
||||
taunt_timer.Disable();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsAttackAllowed(target)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ((ca_time || ma_time || ka_time) && !IsAttackAllowed(target)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(ka_time){
|
||||
int knightreuse = 1000;
|
||||
|
||||
switch(GetClass()){
|
||||
case SHADOWKNIGHT:
|
||||
case SHADOWKNIGHTGM: {
|
||||
case SHADOWKNIGHT: {
|
||||
CastSpell(SPELL_NPC_HARM_TOUCH, target->GetID());
|
||||
knightreuse = (HarmTouchReuseTime * 1000);
|
||||
knightattack_timer.Start(HarmTouchReuseTime * 1000);
|
||||
|
||||
break;
|
||||
}
|
||||
case PALADIN:
|
||||
case PALADINGM: {
|
||||
case PALADIN: {
|
||||
if(GetHPRatio() < 20) {
|
||||
CastSpell(SPELL_LAY_ON_HANDS, GetID());
|
||||
knightreuse = (LayOnHandsReuseTime * 1000);
|
||||
knightattack_timer.Start(LayOnHandsReuseTime * 1000);
|
||||
}
|
||||
else {
|
||||
knightattack_timer.Start(2000);
|
||||
}
|
||||
else
|
||||
knightreuse = 2000;
|
||||
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
knightattack_timer.Start(knightreuse);
|
||||
}
|
||||
|
||||
if(taunting && target && target->IsNPC() && taunt_time) {
|
||||
@@ -6457,8 +6477,66 @@ void Bot::DoClassAttacks(Mob *target, bool IsRiposte) {
|
||||
}
|
||||
}
|
||||
|
||||
if(!ca_time)
|
||||
if (ma_time) {
|
||||
switch (GetClass()) {
|
||||
case MONK: {
|
||||
int reuse = (MonkSpecialAttack(target, EQEmu::skills::SkillTigerClaw) - 1);
|
||||
|
||||
// Live AA - Technique of Master Wu
|
||||
int wuchance = itembonuses.DoubleSpecialAttack + spellbonuses.DoubleSpecialAttack + aabonuses.DoubleSpecialAttack;
|
||||
|
||||
if (wuchance) {
|
||||
const int MonkSPA[5] = {
|
||||
EQEmu::skills::SkillFlyingKick,
|
||||
EQEmu::skills::SkillDragonPunch,
|
||||
EQEmu::skills::SkillEagleStrike,
|
||||
EQEmu::skills::SkillTigerClaw,
|
||||
EQEmu::skills::SkillRoundKick
|
||||
};
|
||||
int extra = 0;
|
||||
// always 1/4 of the double attack chance, 25% at rank 5 (100/4)
|
||||
while (wuchance > 0) {
|
||||
if (zone->random.Roll(wuchance)) {
|
||||
++extra;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
wuchance /= 4;
|
||||
}
|
||||
|
||||
Mob* bo = GetBotOwner();
|
||||
if (bo && bo->IsClient() && bo->CastToClient()->GetBotOption(Client::booMonkWuMessage)) {
|
||||
|
||||
bo->Message(
|
||||
GENERIC_EMOTE,
|
||||
"The spirit of Master Wu fills %s! %s gains %d additional attack(s).",
|
||||
GetCleanName(),
|
||||
GetCleanName(),
|
||||
extra
|
||||
);
|
||||
}
|
||||
|
||||
auto classic = RuleB(Combat, ClassicMasterWu);
|
||||
while (extra) {
|
||||
MonkSpecialAttack(GetTarget(), (classic ? MonkSPA[zone->random.Int(0, 4)] : EQEmu::skills::SkillTigerClaw));
|
||||
--extra;
|
||||
}
|
||||
}
|
||||
|
||||
float HasteModifier = (GetHaste() * 0.01f);
|
||||
monkattack_timer.Start((reuse * 1000) / HasteModifier);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ca_time) {
|
||||
return;
|
||||
}
|
||||
|
||||
float HasteModifier = (GetHaste() * 0.01f);
|
||||
uint16 skill_to_use = -1;
|
||||
@@ -6493,18 +6571,22 @@ void Bot::DoClassAttacks(Mob *target, bool IsRiposte) {
|
||||
}
|
||||
break;
|
||||
case MONK:
|
||||
if(GetLevel() >= 30)
|
||||
if (GetLevel() >= 30) {
|
||||
skill_to_use = EQEmu::skills::SkillFlyingKick;
|
||||
else if(GetLevel() >= 25)
|
||||
}
|
||||
else if (GetLevel() >= 25) {
|
||||
skill_to_use = EQEmu::skills::SkillDragonPunch;
|
||||
else if(GetLevel() >= 20)
|
||||
}
|
||||
else if (GetLevel() >= 20) {
|
||||
skill_to_use = EQEmu::skills::SkillEagleStrike;
|
||||
else if(GetLevel() >= 10)
|
||||
skill_to_use = EQEmu::skills::SkillTigerClaw;
|
||||
else if(GetLevel() >= 5)
|
||||
}
|
||||
else if (GetLevel() >= 5) {
|
||||
skill_to_use = EQEmu::skills::SkillRoundKick;
|
||||
else
|
||||
}
|
||||
else {
|
||||
skill_to_use = EQEmu::skills::SkillKick;
|
||||
}
|
||||
|
||||
break;
|
||||
case ROGUE:
|
||||
skill_to_use = EQEmu::skills::SkillBackstab;
|
||||
@@ -6555,19 +6637,54 @@ void Bot::DoClassAttacks(Mob *target, bool IsRiposte) {
|
||||
}
|
||||
}
|
||||
|
||||
if (skill_to_use == EQEmu::skills::SkillFlyingKick || skill_to_use == EQEmu::skills::SkillDragonPunch || skill_to_use == EQEmu::skills::SkillEagleStrike || skill_to_use == EQEmu::skills::SkillTigerClaw || skill_to_use == EQEmu::skills::SkillRoundKick) {
|
||||
if (
|
||||
skill_to_use == EQEmu::skills::SkillFlyingKick ||
|
||||
skill_to_use == EQEmu::skills::SkillDragonPunch ||
|
||||
skill_to_use == EQEmu::skills::SkillEagleStrike ||
|
||||
skill_to_use == EQEmu::skills::SkillRoundKick
|
||||
) {
|
||||
reuse = (MonkSpecialAttack(target, skill_to_use) - 1);
|
||||
MonkSpecialAttack(target, skill_to_use);
|
||||
uint32 bDoubleSpecialAttack = (itembonuses.DoubleSpecialAttack + spellbonuses.DoubleSpecialAttack + aabonuses.DoubleSpecialAttack);
|
||||
if(bDoubleSpecialAttack && (bDoubleSpecialAttack >= 100 || bDoubleSpecialAttack > zone->random.Int(0, 100))) {
|
||||
int MonkSPA[5] = { EQEmu::skills::SkillFlyingKick, EQEmu::skills::SkillDragonPunch, EQEmu::skills::SkillEagleStrike, EQEmu::skills::SkillTigerClaw, EQEmu::skills::SkillRoundKick };
|
||||
MonkSpecialAttack(target, MonkSPA[zone->random.Int(0, 4)]);
|
||||
int TripleChance = 25;
|
||||
if (bDoubleSpecialAttack > 100)
|
||||
TripleChance += (TripleChance * (100 - bDoubleSpecialAttack) / 100);
|
||||
|
||||
// Live AA - Technique of Master Wu
|
||||
int wuchance = itembonuses.DoubleSpecialAttack + spellbonuses.DoubleSpecialAttack + aabonuses.DoubleSpecialAttack;
|
||||
|
||||
if(TripleChance > zone->random.Int(0,100))
|
||||
MonkSpecialAttack(target, MonkSPA[zone->random.Int(0, 4)]);
|
||||
if (wuchance) {
|
||||
const int MonkSPA[5] = {
|
||||
EQEmu::skills::SkillFlyingKick,
|
||||
EQEmu::skills::SkillDragonPunch,
|
||||
EQEmu::skills::SkillEagleStrike,
|
||||
EQEmu::skills::SkillTigerClaw,
|
||||
EQEmu::skills::SkillRoundKick
|
||||
};
|
||||
int extra = 0;
|
||||
// always 1/4 of the double attack chance, 25% at rank 5 (100/4)
|
||||
while (wuchance > 0) {
|
||||
if (zone->random.Roll(wuchance)) {
|
||||
++extra;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
wuchance /= 4;
|
||||
}
|
||||
|
||||
Mob* bo = GetBotOwner();
|
||||
if (bo && bo->IsClient() && bo->CastToClient()->GetBotOption(Client::booMonkWuMessage)) {
|
||||
|
||||
bo->Message(
|
||||
GENERIC_EMOTE,
|
||||
"The spirit of Master Wu fills %s! %s gains %d additional attack(s).",
|
||||
GetCleanName(),
|
||||
GetCleanName(),
|
||||
extra
|
||||
);
|
||||
}
|
||||
|
||||
auto classic = RuleB(Combat, ClassicMasterWu);
|
||||
while (extra) {
|
||||
MonkSpecialAttack(GetTarget(), (classic ? MonkSPA[zone->random.Int(0, 4)] : skill_to_use));
|
||||
--extra;
|
||||
}
|
||||
}
|
||||
|
||||
reuse *= 1000;
|
||||
@@ -8966,6 +9083,12 @@ void Bot::CalcBotStats(bool showtext) {
|
||||
skills[sindex] = database.GetSkillCap(GetClass(), (EQEmu::skills::SkillType)sindex, GetLevel());
|
||||
}
|
||||
|
||||
taunt_timer.Start(1000);
|
||||
|
||||
if (GetClass() == MONK && GetLevel() >= 10) {
|
||||
monkattack_timer.Start(1000);
|
||||
}
|
||||
|
||||
LoadAAs();
|
||||
GenerateSpecialAttacks();
|
||||
|
||||
|
||||
+36
-8
@@ -3928,6 +3928,16 @@ void bot_command_owner_option(Client *c, const Seperator *sep)
|
||||
"<td><c \"#00CCCC\">null</td>"
|
||||
"<td><c \"#888888\">(toggles)</td>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<td><c \"#CCCCCC\">monkwumessage</td>"
|
||||
"<td><c \"#00CC00\">enable <c \"#CCCCCC\">| <c \"#00CC00\">disable</td>"
|
||||
"<td><c \"#888888\">displays monk wu trigger messages</td>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<td></td>"
|
||||
"<td><c \"#00CCCC\">null</td>"
|
||||
"<td><c \"#888888\">(toggles)</td>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<td><c \"#CCCCCC\">current</td>"
|
||||
"<td></td>"
|
||||
@@ -4103,6 +4113,22 @@ void bot_command_owner_option(Client *c, const Seperator *sep)
|
||||
|
||||
c->Message(m_action, "Bot 'buff counter' is now %s.", (c->GetBotOption(Client::booBuffCounter) == true ? "enabled" : "disabled"));
|
||||
}
|
||||
else if (!owner_option.compare("monkwumessage")) {
|
||||
|
||||
if (!argument.compare("enable")) {
|
||||
c->SetBotOption(Client::booMonkWuMessage, true);
|
||||
}
|
||||
else if (!argument.compare("disable")) {
|
||||
c->SetBotOption(Client::booMonkWuMessage, false);
|
||||
}
|
||||
else {
|
||||
c->SetBotOption(Client::booMonkWuMessage, !c->GetBotOption(Client::booMonkWuMessage));
|
||||
}
|
||||
|
||||
database.botdb.SaveOwnerOption(c->CharacterID(), Client::booMonkWuMessage, c->GetBotOption(Client::booMonkWuMessage));
|
||||
|
||||
c->Message(m_action, "Bot 'monk wu message' is now %s.", (c->GetBotOption(Client::booMonkWuMessage) == true ? "enabled" : "disabled"));
|
||||
}
|
||||
else if (!owner_option.compare("current")) {
|
||||
|
||||
std::string window_title = "Current Bot Owner Options Settings";
|
||||
@@ -4112,13 +4138,14 @@ void bot_command_owner_option(Client *c, const Seperator *sep)
|
||||
"<td><c \"#FFFFFF\">Option<br>------</td>"
|
||||
"<td><c \"#00FF00\">Argument<br>-------</td>"
|
||||
"</tr>"
|
||||
"<tr>" "<td><c \"#CCCCCC\">deathmarquee</td>" "<td><c \"#00CC00\">{}</td>" "</tr>"
|
||||
"<tr>" "<td><c \"#CCCCCC\">statsupdate</td>" "<td><c \"#00CC00\">{}</td>" "</tr>"
|
||||
"<tr>" "<td><c \"#CCCCCC\">spawnmessage</td>" "<td><c \"#00CC00\">{}</td>" "</tr>"
|
||||
"<tr>" "<td><c \"#CCCCCC\">spawnmessage</td>" "<td><c \"#00CC00\">{}</td>" "</tr>"
|
||||
"<tr>" "<td><c \"#CCCCCC\">altcombat</td>" "<td><c \"#00CC00\">{}</td>" "</tr>"
|
||||
"<tr>" "<td><c \"#CCCCCC\">autodefend</td>" "<td><c \"#00CC00\">{}</td>" "</tr>"
|
||||
"<tr>" "<td><c \"#CCCCCC\">buffcounter</td>" "<td><c \"#00CC00\">{}</td>" "</tr>"
|
||||
"<tr>" "<td><c \"#CCCCCC\">deathmarquee</td>" "<td><c \"#00CC00\">{}</td>" "</tr>"
|
||||
"<tr>" "<td><c \"#CCCCCC\">statsupdate</td>" "<td><c \"#00CC00\">{}</td>" "</tr>"
|
||||
"<tr>" "<td><c \"#CCCCCC\">spawnmessage</td>" "<td><c \"#00CC00\">{}</td>" "</tr>"
|
||||
"<tr>" "<td><c \"#CCCCCC\">spawnmessage</td>" "<td><c \"#00CC00\">{}</td>" "</tr>"
|
||||
"<tr>" "<td><c \"#CCCCCC\">altcombat</td>" "<td><c \"#00CC00\">{}</td>" "</tr>"
|
||||
"<tr>" "<td><c \"#CCCCCC\">autodefend</td>" "<td><c \"#00CC00\">{}</td>" "</tr>"
|
||||
"<tr>" "<td><c \"#CCCCCC\">buffcounter</td>" "<td><c \"#00CC00\">{}</td>" "</tr>"
|
||||
"<tr>" "<td><c \"#CCCCCC\">monkwumessage</td>" "<td><c \"#00CC00\">{}</td>" "</tr>"
|
||||
"</table>",
|
||||
(c->GetBotOption(Client::booDeathMarquee) ? "enabled" : "disabled"),
|
||||
(c->GetBotOption(Client::booStatsUpdate) ? "enabled" : "disabled"),
|
||||
@@ -4126,7 +4153,8 @@ void bot_command_owner_option(Client *c, const Seperator *sep)
|
||||
(c->GetBotOption(Client::booSpawnMessageClassSpecific) ? "class" : "default"),
|
||||
(RuleB(Bots, AllowOwnerOptionAltCombat) ? (c->GetBotOption(Client::booAltCombat) ? "enabled" : "disabled") : "restricted"),
|
||||
(RuleB(Bots, AllowOwnerOptionAutoDefend) ? (c->GetBotOption(Client::booAutoDefend) ? "enabled" : "disabled") : "restricted"),
|
||||
(c->GetBotOption(Client::booBuffCounter) ? "enabled" : "disabled")
|
||||
(c->GetBotOption(Client::booBuffCounter) ? "enabled" : "disabled"),
|
||||
(c->GetBotOption(Client::booMonkWuMessage) ? "enabled" : "disabled")
|
||||
);
|
||||
|
||||
c->SendPopupToClient(window_title.c_str(), window_text.c_str());
|
||||
|
||||
@@ -2257,6 +2257,7 @@ bool BotDatabase::SaveOwnerOption(const uint32 owner_id, size_t type, const bool
|
||||
case Client::booAltCombat:
|
||||
case Client::booAutoDefend:
|
||||
case Client::booBuffCounter:
|
||||
case Client::booMonkWuMessage:
|
||||
{
|
||||
query = fmt::format(
|
||||
"REPLACE INTO `bot_owner_options`(`owner_id`, `option_type`, `option_value`) VALUES ('{}', '{}', '{}')",
|
||||
|
||||
+137
-6
@@ -121,7 +121,8 @@ Client::Client(EQStreamInterface* ieqs)
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
0,
|
||||
false
|
||||
),
|
||||
hpupdate_timer(2000),
|
||||
camp_timer(29000),
|
||||
@@ -165,6 +166,7 @@ Client::Client(EQStreamInterface* ieqs)
|
||||
hp_self_update_throttle_timer(300),
|
||||
hp_other_update_throttle_timer(500),
|
||||
position_update_timer(10000),
|
||||
consent_throttle_timer(2000),
|
||||
tmSitting(0)
|
||||
{
|
||||
|
||||
@@ -254,6 +256,7 @@ Client::Client(EQStreamInterface* ieqs)
|
||||
TotalSecondsPlayed = 0;
|
||||
keyring.clear();
|
||||
bind_sight_target = nullptr;
|
||||
p_raid_instance = nullptr;
|
||||
mercid = 0;
|
||||
mercSlot = 0;
|
||||
InitializeMercInfo();
|
||||
@@ -357,6 +360,7 @@ Client::Client(EQStreamInterface* ieqs)
|
||||
bot_owner_options[booAltCombat] = RuleB(Bots, AllowOwnerOptionAltCombat);
|
||||
bot_owner_options[booAutoDefend] = RuleB(Bots, AllowOwnerOptionAutoDefend);
|
||||
bot_owner_options[booBuffCounter] = false;
|
||||
bot_owner_options[booMonkWuMessage] = false;
|
||||
|
||||
SetBotPulling(false);
|
||||
SetBotPrecombat(false);
|
||||
@@ -1915,7 +1919,7 @@ void Client::CheckManaEndUpdate() {
|
||||
else if (group) {
|
||||
group->SendEndurancePacketFrom(this);
|
||||
}
|
||||
|
||||
|
||||
auto endurance_packet = new EQApplicationPacket(OP_EnduranceUpdate, sizeof(EnduranceUpdate_Struct));
|
||||
EnduranceUpdate_Struct* endurance_update = (EnduranceUpdate_Struct*)endurance_packet->pBuffer;
|
||||
endurance_update->cur_end = GetEndurance();
|
||||
@@ -6254,6 +6258,52 @@ void Client::DragCorpses()
|
||||
}
|
||||
}
|
||||
|
||||
void Client::ConsentCorpses(std::string consent_name, bool deny)
|
||||
{
|
||||
if (strcasecmp(consent_name.c_str(), GetName()) == 0) {
|
||||
MessageString(Chat::Red, CONSENT_YOURSELF);
|
||||
}
|
||||
else if (!consent_throttle_timer.Check()) {
|
||||
MessageString(Chat::Red, CONSENT_WAIT);
|
||||
}
|
||||
else {
|
||||
auto pack = new ServerPacket(ServerOP_Consent, sizeof(ServerOP_Consent_Struct));
|
||||
ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer;
|
||||
strn0cpy(scs->grantname, consent_name.c_str(), sizeof(scs->grantname));
|
||||
strn0cpy(scs->ownername, GetName(), sizeof(scs->ownername));
|
||||
strn0cpy(scs->zonename, "Unknown", sizeof(scs->zonename));
|
||||
scs->permission = deny ? 0 : 1;
|
||||
scs->zone_id = zone->GetZoneID();
|
||||
scs->instance_id = zone->GetInstanceID();
|
||||
scs->consent_type = EQEmu::consent::Normal;
|
||||
scs->consent_id = 0;
|
||||
if (strcasecmp(scs->grantname, "group") == 0) {
|
||||
if (!deny) {
|
||||
Group* grp = GetGroup();
|
||||
scs->consent_id = grp ? grp->GetID() : 0;
|
||||
}
|
||||
scs->consent_type = EQEmu::consent::Group;
|
||||
}
|
||||
else if (strcasecmp(scs->grantname, "raid") == 0) {
|
||||
if (!deny) {
|
||||
Raid* raid = GetRaid();
|
||||
scs->consent_id = raid ? raid->GetID() : 0;
|
||||
}
|
||||
scs->consent_type = EQEmu::consent::Raid;
|
||||
}
|
||||
else if (strcasecmp(scs->grantname, "guild") == 0) {
|
||||
if (!deny) {
|
||||
scs->consent_id = GuildID();
|
||||
}
|
||||
scs->consent_type = EQEmu::consent::Guild;
|
||||
// update all corpses in db so buried/unloaded corpses see new consent id
|
||||
database.UpdateCharacterCorpseConsent(CharacterID(), scs->consent_id);
|
||||
}
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
}
|
||||
}
|
||||
|
||||
void Client::Doppelganger(uint16 spell_id, Mob *target, const char *name_override, int pet_count, int pet_duration)
|
||||
{
|
||||
if(!target || !IsValidSpell(spell_id) || this->GetID() == target->GetID())
|
||||
@@ -7748,6 +7798,8 @@ FACTION_VALUE Client::GetFactionLevel(uint32 char_id, uint32 npc_id, uint32 p_ra
|
||||
// few optimizations
|
||||
if (GetFeigned())
|
||||
return FACTION_INDIFFERENT;
|
||||
if(!zone->CanDoCombat())
|
||||
return FACTION_INDIFFERENT;
|
||||
if (invisible_undead && tnpc && !tnpc->SeeInvisibleUndead())
|
||||
return FACTION_INDIFFERENT;
|
||||
if (IsInvisible(tnpc))
|
||||
@@ -8533,13 +8585,13 @@ void Client::QuestReward(Mob* target, uint32 copper, uint32 silver, uint32 gold,
|
||||
memset(outapp->pBuffer, 0, sizeof(QuestReward_Struct));
|
||||
QuestReward_Struct* qr = (QuestReward_Struct*)outapp->pBuffer;
|
||||
|
||||
qr->mob_id = target->GetID(); // Entity ID for the from mob name
|
||||
qr->mob_id = target ? target->GetID() : 0; // Entity ID for the from mob name
|
||||
qr->target_id = GetID(); // The Client ID (this)
|
||||
qr->copper = copper;
|
||||
qr->silver = silver;
|
||||
qr->gold = gold;
|
||||
qr->platinum = platinum;
|
||||
qr->item_id = itemid;
|
||||
qr->item_id[0] = itemid;
|
||||
qr->exp_reward = exp;
|
||||
|
||||
if (copper > 0 || silver > 0 || gold > 0 || platinum > 0)
|
||||
@@ -8550,7 +8602,7 @@ void Client::QuestReward(Mob* target, uint32 copper, uint32 silver, uint32 gold,
|
||||
|
||||
if (faction)
|
||||
{
|
||||
if (target->IsNPC())
|
||||
if (target && target->IsNPC())
|
||||
{
|
||||
int32 nfl_id = target->CastToNPC()->GetNPCFactionID();
|
||||
SetFactionLevel(CharacterID(), nfl_id, GetBaseClass(), GetBaseRace(), GetDeity(), true);
|
||||
@@ -8566,6 +8618,42 @@ void Client::QuestReward(Mob* target, uint32 copper, uint32 silver, uint32 gold,
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
void Client::QuestReward(Mob* target, const QuestReward_Struct &reward, bool faction)
|
||||
{
|
||||
auto outapp = new EQApplicationPacket(OP_Sound, sizeof(QuestReward_Struct));
|
||||
memset(outapp->pBuffer, 0, sizeof(QuestReward_Struct));
|
||||
QuestReward_Struct* qr = (QuestReward_Struct*)outapp->pBuffer;
|
||||
|
||||
memcpy(qr, &reward, sizeof(QuestReward_Struct));
|
||||
|
||||
// not set in caller because reasons
|
||||
qr->mob_id = target ? target->GetID() : 0; // Entity ID for the from mob name
|
||||
|
||||
if (reward.copper > 0 || reward.silver > 0 || reward.gold > 0 || reward.platinum > 0)
|
||||
AddMoneyToPP(reward.copper, reward.silver, reward.gold, reward.platinum, false);
|
||||
|
||||
for (int i = 0; i < QUESTREWARD_COUNT; ++i)
|
||||
if (reward.item_id[i] > 0)
|
||||
SummonItem(reward.item_id[i], 0, 0, 0, 0, 0, 0, false, EQEmu::invslot::slotCursor);
|
||||
|
||||
if (faction)
|
||||
{
|
||||
if (target && target->IsNPC())
|
||||
{
|
||||
int32 nfl_id = target->CastToNPC()->GetNPCFactionID();
|
||||
SetFactionLevel(CharacterID(), nfl_id, GetBaseClass(), GetBaseRace(), GetDeity(), true);
|
||||
qr->faction = target->CastToNPC()->GetPrimaryFaction();
|
||||
qr->faction_mod = 1; // Too lazy to get real value, not sure if this is even used by client anyhow.
|
||||
}
|
||||
}
|
||||
|
||||
if (reward.exp_reward> 0)
|
||||
AddEXP(reward.exp_reward);
|
||||
|
||||
QueuePacket(outapp, true, Client::CLIENT_CONNECTED);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
void Client::SendHPUpdateMarquee(){
|
||||
if (!this || !this->IsClient() || !this->current_hp || !this->max_hp)
|
||||
return;
|
||||
@@ -8670,6 +8758,11 @@ void Client::CheckRegionTypeChanges()
|
||||
if (last_region_type == new_region)
|
||||
return;
|
||||
|
||||
// If we got out of water clear any water aggro for water only npcs
|
||||
if (last_region_type == RegionTypeWater) {
|
||||
entity_list.ClearWaterAggro(this);
|
||||
}
|
||||
|
||||
// region type changed
|
||||
last_region_type = new_region;
|
||||
|
||||
@@ -9111,7 +9204,7 @@ void Client::SetSecondaryWeaponOrnamentation(uint32 model_id)
|
||||
secondary_item->SetOrnamentationIDFile(model_id);
|
||||
SendItemPacket(EQEmu::invslot::slotSecondary, secondary_item, ItemPacketTrade);
|
||||
WearChange(EQEmu::textures::weaponSecondary, static_cast<uint16>(model_id), 0);
|
||||
|
||||
|
||||
Message(Chat::Yellow, "Your secondary weapon appearance has been modified");
|
||||
}
|
||||
}
|
||||
@@ -9200,3 +9293,41 @@ void Client::SetBotOption(BotOwnerOption boo, bool flag) {
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void Client::SendToGuildHall()
|
||||
{
|
||||
std::string zone_short_name = "guildhall";
|
||||
uint32 zone_id = database.GetZoneID(zone_short_name.c_str());
|
||||
if (zone_id == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 expiration_time = (RuleI(Instances, GuildHallExpirationDays) * 86400);
|
||||
uint16 instance_id = 0;
|
||||
std::string guild_hall_instance_key = fmt::format("guild-hall-instance-{}", GuildID());
|
||||
std::string instance_data = DataBucket::GetData(guild_hall_instance_key);
|
||||
if (!instance_data.empty() && std::stoi(instance_data) > 0) {
|
||||
instance_id = std::stoi(instance_data);
|
||||
}
|
||||
|
||||
if (instance_id <= 0) {
|
||||
if (!database.GetUnusedInstanceID(instance_id)) {
|
||||
Message(Chat::Red, "Server was unable to find a free instance id.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!database.CreateInstance(instance_id, zone_id, 1, expiration_time)) {
|
||||
Message(Chat::Red, "Server was unable to create a new instance.");
|
||||
return;
|
||||
}
|
||||
|
||||
DataBucket::SetData(
|
||||
guild_hall_instance_key,
|
||||
std::to_string(instance_id),
|
||||
std::to_string(expiration_time)
|
||||
);
|
||||
}
|
||||
|
||||
AssignToInstance(instance_id);
|
||||
MovePC(345, instance_id, -1.00, -1.00, 3.34, 0, 1);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user