mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-22 20:33:01 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b7eeb3b2f9 | |||
| d2f8eead1f |
@@ -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}"
|
||||
}
|
||||
}
|
||||
+6
-82
@@ -1,92 +1,16 @@
|
||||
---
|
||||
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: Build Linux
|
||||
|
||||
clone:
|
||||
depth: 1
|
||||
name: EQEmulator Server Linux CI
|
||||
|
||||
# Limits how many of these builds can run on the drone runner at a time, this isn't about cores
|
||||
concurrency:
|
||||
limit: 1
|
||||
|
||||
volumes:
|
||||
- name: cache
|
||||
host:
|
||||
path: /var/lib/cache-release
|
||||
|
||||
steps:
|
||||
- name: Build Linux X64
|
||||
image: akkadius/eqemu-server:v11
|
||||
environment:
|
||||
GITHUB_TOKEN:
|
||||
from_secret: GH_RELEASE_GITHUB_API_TOKEN
|
||||
RCLONE_CONFIG_REMOTE_TYPE: ftp
|
||||
RCLONE_FTP_HOST: drone.akkadius.com
|
||||
RCLONE_FTP_USER: artifacts
|
||||
RCLONE_FTP_PASS:
|
||||
from_secret: RCLONE_FTP_PASS
|
||||
- name: server-build
|
||||
# Source build script https://github.com/Akkadius/akk-stack/blob/master/containers/eqemu-server/Dockerfile#L20
|
||||
image: akkadius/eqemu-server:latest
|
||||
commands:
|
||||
- ./utils/scripts/build/linux-build.sh
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /home/eqemu/.ccache/
|
||||
|
||||
---
|
||||
|
||||
kind: pipeline
|
||||
type: exec
|
||||
name: Build Windows
|
||||
|
||||
clone:
|
||||
depth: 1
|
||||
|
||||
platform:
|
||||
os: windows
|
||||
arch: amd64
|
||||
|
||||
steps:
|
||||
- name: Build Windows X64
|
||||
environment:
|
||||
RCLONE_CONFIG_REMOTE_TYPE: ftp
|
||||
RCLONE_FTP_HOST: drone.akkadius.com
|
||||
RCLONE_FTP_USER: artifacts
|
||||
RCLONE_FTP_PASS:
|
||||
from_secret: RCLONE_FTP_PASS
|
||||
GITHUB_TOKEN:
|
||||
from_secret: GH_RELEASE_GITHUB_API_TOKEN
|
||||
commands:
|
||||
- .\utils\scripts\build\windows-build.ps1
|
||||
|
||||
---
|
||||
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: Publish Artifacts to Github
|
||||
|
||||
steps:
|
||||
- name: Upload Artifacts
|
||||
image: akkadius/eqemu-build-releaser:v3
|
||||
environment:
|
||||
RCLONE_CONFIG_REMOTE_TYPE: ftp
|
||||
RCLONE_FTP_HOST: drone.akkadius.com
|
||||
RCLONE_FTP_USER: artifacts
|
||||
RCLONE_FTP_PASS:
|
||||
from_secret: RCLONE_FTP_PASS
|
||||
GH_RELEASE_GITHUB_API_TOKEN:
|
||||
from_secret: GH_RELEASE_GITHUB_API_TOKEN
|
||||
GITHUB_TOKEN:
|
||||
from_secret: GH_RELEASE_GITHUB_API_TOKEN
|
||||
commands:
|
||||
- ./utils/scripts/build/should-release/should-release
|
||||
- rclone config create remote ftp env_auth true > /dev/null
|
||||
- |
|
||||
rclone copy remote: --include "eqemu-server*.zip" .
|
||||
- gh-release --assets=eqemu-server-linux-x64.zip,eqemu-server-windows-x64.zip -y
|
||||
- |
|
||||
rclone delete remote: --include "eqemu-server*.zip"
|
||||
|
||||
depends_on:
|
||||
- Build Windows
|
||||
- Build Linux
|
||||
- sudo chown eqemu:eqemu /drone/src/ * -R
|
||||
- git submodule init && git submodule update && mkdir -p build && cd build && cmake -DEQEMU_BUILD_LOGIN=ON -DEQEMU_BUILD_BOTS=ON -DEQEMU_BUILD_LUA=ON -G 'Unix Makefiles' .. && make -j$((`nproc`-4))
|
||||
-14
@@ -54,17 +54,3 @@ bin/
|
||||
/Win32
|
||||
/x64
|
||||
/client_files/**/CMakeFiles/
|
||||
|
||||
.idea
|
||||
|
||||
# Clangd Generated Files.
|
||||
compile_flags.txt
|
||||
.cache/
|
||||
|
||||
# vscode generated settings
|
||||
.vscode/
|
||||
|
||||
# Build pipeline
|
||||
!utils/scripts/build/
|
||||
!utils/scripts/build/should-release/should-release
|
||||
!utils/scripts/build/should-release/should-release.exe
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
language: cpp
|
||||
compiler: gcc
|
||||
dist: bionic
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libmysqlclient-dev
|
||||
- libperl-dev
|
||||
- libboost-dev
|
||||
- liblua5.1-0-dev
|
||||
- zlib1g-dev
|
||||
- uuid-dev
|
||||
- libssl-dev
|
||||
|
||||
script:
|
||||
- cmake -G "Unix Makefiles" -DEQEMU_BUILD_TESTS=ON -DEQEMU_ENABLE_BOTS=ON -DEQEMU_BUILD_LOGIN=ON
|
||||
- make -j2
|
||||
- ./bin/tests
|
||||
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
+164
@@ -0,0 +1,164 @@
|
||||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "make",
|
||||
"type": "shell",
|
||||
"command": "cd bin && make",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"problemMatcher": [
|
||||
"$gcc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "make clean",
|
||||
"type": "shell",
|
||||
"command": "cd bin && make clean",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"problemMatcher": [
|
||||
"$gcc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "cmake",
|
||||
"type": "shell",
|
||||
"command": "mkdir -p bin && cd bin && rm CMakeCache.txt && cmake -DEQEMU_BUILD_LOGIN=ON -DEQEMU_BUILD_LUA=ON -G 'Unix Makefiles' ..",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"problemMatcher":{
|
||||
"owner": "cpp",
|
||||
"fileLocation": "relative",
|
||||
"pattern":[
|
||||
{
|
||||
"regexp": "([\\w+|\\\\]*\\.\\w+)\\((\\d+)\\)\\: (warning|error) (.*)$",
|
||||
"file": 1,
|
||||
"location": 2,
|
||||
"severity": 3,
|
||||
"message": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "download maps",
|
||||
"type": "shell",
|
||||
"command": "mkdir -p bin && cd bin && wget https://codeload.github.com/Akkadius/EQEmuMaps/zip/master -O maps.zip && unzip -o maps.zip && rm ./maps -rf && mv EQEmuMaps-master maps && rm maps.zip",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"problemMatcher": [
|
||||
"$gcc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "download quests",
|
||||
"type": "shell",
|
||||
"command": "mkdir -p bin && cd bin && cd server && git -C ./quests pull 2> /dev/null || git clone https://github.com/ProjectEQ/projecteqquests.git quests",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"problemMatcher": [
|
||||
"$gcc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "download eqemu_config",
|
||||
"type": "shell",
|
||||
"command": "mkdir -p bin && cd bin && wget --no-check-certificate https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/eqemu_config_docker.json -O eqemu_config.json",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"problemMatcher": [
|
||||
"$gcc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "rebuild database (mariadb must be started)",
|
||||
"type": "shell",
|
||||
"command": "mkdir -p bin && cd bin && docker run -i --rm --privileged -v ${HOST_PROJECT_PATH}/bin:/src --network=eqemu -it eqemu/server:0.0.3 bash -c './eqemu_server.pl source_peq_db && ./eqemu_server.pl check_db_updates && ./eqemu_server.pl linux_login_server_setup'",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"problemMatcher": [
|
||||
"$gcc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "zone 7000",
|
||||
"type": "shell",
|
||||
"command": "docker stop zone7000 | true && docker network create eqemu | true && docker run -i --rm --name zone7000 --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --privileged -v ${HOST_PROJECT_PATH}/bin:/src --ulimit core=10000000 --network=eqemu -p 7000:7000/udp -e LD_LIBRARY_PATH=/src/ eqemu/server:0.0.3 gdb -ex run --args ./zone dynamic_zone7000:7000",
|
||||
"group": {
|
||||
"kind": "test",
|
||||
"isDefault": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "zone 7001",
|
||||
"type": "shell",
|
||||
"command": "docker stop zone7001 | true && docker network create eqemu | true && docker run -i --rm --name zone7001 --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --privileged -v ${HOST_PROJECT_PATH}/bin:/src --ulimit core=10000000 --network=eqemu -p 7001:7001/udp -e LD_LIBRARY_PATH=/src/ eqemu/server:0.0.3 gdb -ex run --args ./zone dynamic_zone7001:7001",
|
||||
"group": {
|
||||
"kind": "test",
|
||||
"isDefault": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "loginserver",
|
||||
"type": "shell",
|
||||
"command": "docker stop loginserver | true && docker network create eqemu | true && docker run -i --rm --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --privileged -v ${HOST_PROJECT_PATH}/bin:/src --ulimit core=10000000 --network=eqemu --name loginserver -p 5999:5999/udp -p 5998:5998/udp -e LD_LIBRARY_PATH=/src/ eqemu/server:0.0.3 gdb -ex run --args ./loginserver",
|
||||
"group": {
|
||||
"kind": "test",
|
||||
"isDefault": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "shared_memory, world",
|
||||
"type": "shell",
|
||||
"command": "docker stop sharedmemory | true && docker stop world | true && docker network create eqemu | true && docker run --rm -v ${HOST_PROJECT_PATH}/bin:/src --network=eqemu --name sharedmemory eqemu/server:0.0.3 ./shared_memory && docker run --rm -v ${HOST_PROJECT_PATH}/bin:/src --ulimit core=10000000 -e LD_LIBRARY_PATH=/src/ --network=eqemu --name world -p 9000:9000 -p 9000:9000/udp -p 9001:9001 -p 9080:9080 eqemu/server:0.0.3 gdb -ex run ./world",
|
||||
"group": {
|
||||
"kind": "test",
|
||||
"isDefault": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "queryserv",
|
||||
"type": "shell",
|
||||
"command": "docker stop queryserv | true && docker run --rm -v ${HOST_PROJECT_PATH}/bin:/src --ulimit core=10000000 -e LD_LIBRARY_PATH=/src/ --network=eqemu --name queryserv eqemu/server:0.0.3 gdb -ex run ./queryserv",
|
||||
"group": {
|
||||
"kind": "test",
|
||||
"isDefault": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "mariadb",
|
||||
"type": "shell",
|
||||
"command": "docker stop mariadb | true && cd bin && docker network create eqemu | true && docker run --rm -v ${HOST_PROJECT_PATH}/bin/db:/bitnami/mariadb -p 3306:3306 -e MARIADB_DATABASE=peq -e MARIADB_USER=eqemu -e MARIADB_PASSWORD=eqemupass -e ALLOW_EMPTY_PASSWORD=yes --name mariadb --network=eqemu bitnami/mariadb:latest",
|
||||
"group": {
|
||||
"kind": "test",
|
||||
"isDefault": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "ucs",
|
||||
"type": "shell",
|
||||
"command": "docker stop ucs | true && cd bin && docker network create eqemu | true && docker run --rm -v ${HOST_PROJECT_PATH}/bin:/src -p 7778:7778 --name ucs --network=eqemu eqemu/server:0.0.3 gdb -ex run ./ucs",
|
||||
"group": {
|
||||
"kind": "test",
|
||||
"isDefault": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -40,14 +40,14 @@ Assuming it is starting in c:/projects/eqemu and the x64 dependencies were extra
|
||||
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -G "Visual Studio 15 2017 Win64" -DEQEMU_BUILD_TESTS=ON -DEQEMU_BUILD_LOGIN=ON -DEQEMU_BUILD_ZLIB=ON -DCMAKE_TOOLCHAIN_FILE="c:/projects/eqemu/vcpkg/vcpkg-export-20180828-145455/scripts/buildsystems/vcpkg.cmake" ..
|
||||
cmake -G "Visual Studio 15 2017 Win64" -DEQEMU_BUILD_TESTS=ON -DEQEMU_BUILD_LOGIN=ON -DEQEMU_BUILD_ZLIB=ON -DEQEMU_ENABLE_BOTS=ON -DCMAKE_TOOLCHAIN_FILE="c:/projects/eqemu/vcpkg/vcpkg-export-20180828-145455/scripts/buildsystems/vcpkg.cmake" ..
|
||||
|
||||
##### Linux
|
||||
Similarly to Windows running CMake on Linux is simple it just omits the toolchain file and uses a different generator.
|
||||
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -G "Unix Makefiles" -DEQEMU_BUILD_TESTS=ON -DEQEMU_BUILD_LOGIN=ON ..
|
||||
cmake -G "Unix Makefiles" -DEQEMU_BUILD_TESTS=ON -DEQEMU_ENABLE_BOTS=ON -DEQEMU_BUILD_LOGIN=ON ..
|
||||
|
||||
### Building
|
||||
|
||||
|
||||
-692
@@ -1,692 +0,0 @@
|
||||
## [22.1.0] - 01/22/2022
|
||||
|
||||
This is a first release using the new build system. Changelog entry representative of last year. Subsequent releases will consist of incremental changes since the last release.
|
||||
|
||||
### AA
|
||||
|
||||
* Fix AA tables dump ([#2769](https://github.com/EQEmu/Server/pull/2769)) ([Akkadius](https://github.com/Akkadius)) 2023-01-22
|
||||
|
||||
### AI
|
||||
|
||||
* Add Support to Heals to allow Trigger based spells ([#2709](https://github.com/EQEmu/Server/pull/2709)) ([Aeadoin](https://github.com/Aeadoin)) 2023-01-08
|
||||
* Spell Type (1024) InCombatBuff were spam casting ([#2030](https://github.com/EQEmu/Server/pull/2030)) ([noudess](https://github.com/noudess)) 2022-03-07
|
||||
|
||||
### API
|
||||
|
||||
* Apply spells with custom buff durations and adjust existing spell buff durations. ([#1997](https://github.com/EQEmu/Server/pull/1997)) ([KayenEQ](https://github.com/KayenEQ)) 2022-02-15
|
||||
* Fix for SetBuffDuration function to check bard slots. ([#2009](https://github.com/EQEmu/Server/pull/2009)) ([KayenEQ](https://github.com/KayenEQ)) 2022-02-17
|
||||
* GetNPCStat can now return default stat values. ([#2048](https://github.com/EQEmu/Server/pull/2048)) ([KayenEQ](https://github.com/KayenEQ)) 2022-03-11
|
||||
* GetNPCStat default better naming ([#2053](https://github.com/EQEmu/Server/pull/2053)) ([KayenEQ](https://github.com/KayenEQ)) 2022-03-13
|
||||
* Methods for getting more information on quest timers. ([#2060](https://github.com/EQEmu/Server/pull/2060)) ([KayenEQ](https://github.com/KayenEQ)) 2022-04-13
|
||||
* Perl functions added to apply spell effects directly to NPCs without requiring buffs. ([#1975](https://github.com/EQEmu/Server/pull/1975)) ([KayenEQ](https://github.com/KayenEQ)) 2022-02-08
|
||||
* Perl functions to set invulnerable to and modify environmental damage. ([#2044](https://github.com/EQEmu/Server/pull/2044)) ([KayenEQ](https://github.com/KayenEQ)) 2022-03-09
|
||||
* Reload API ([#2716](https://github.com/EQEmu/Server/pull/2716)) ([Akkadius](https://github.com/Akkadius)) 2023-01-11
|
||||
* perl added GetNPCStat(identifier) ([#2012](https://github.com/EQEmu/Server/pull/2012)) ([KayenEQ](https://github.com/KayenEQ)) 2022-02-20
|
||||
|
||||
### Aggro
|
||||
|
||||
* Cleanup Mob::CombatRange ([#2652](https://github.com/EQEmu/Server/pull/2652)) ([Aeadoin](https://github.com/Aeadoin)) 2022-12-20
|
||||
* Rooted mobs will add other hated targets to Hate list ([#2180](https://github.com/EQEmu/Server/pull/2180)) ([noudess](https://github.com/noudess)) 2022-05-27
|
||||
|
||||
### Appveyor
|
||||
|
||||
* Remove bots preprocessor ([Akkadius](https://github.com/Akkadius)) 2023-01-20
|
||||
|
||||
### Backups
|
||||
|
||||
* Use World CLI for Database Backups ([#2286](https://github.com/EQEmu/Server/pull/2286)) ([Akkadius](https://github.com/Akkadius)) 2022-07-07
|
||||
|
||||
### Bot/Merc
|
||||
|
||||
* Cleanup methods, and virtual overrides. ([#2734](https://github.com/EQEmu/Server/pull/2734)) ([Aeadoin](https://github.com/Aeadoin)) 2023-01-15
|
||||
|
||||
### Bots
|
||||
|
||||
* Add Bot Command Reloading ([#2773](https://github.com/EQEmu/Server/pull/2773)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-01-22
|
||||
* Add Bot-specific Spell Settings. ([#2553](https://github.com/EQEmu/Server/pull/2553)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-11-27
|
||||
* Add Buff support for Bards under AI_IdleCastChecks ([#2590](https://github.com/EQEmu/Server/pull/2590)) ([Aeadoin](https://github.com/Aeadoin)) 2022-11-28
|
||||
* Add Data Bucket support to Bot Spell Entries. ([#2505](https://github.com/EQEmu/Server/pull/2505)) ([Aeadoin](https://github.com/Aeadoin)) 2022-11-06
|
||||
* Add EVENT_TRADE Support to Bots. ([#2560](https://github.com/EQEmu/Server/pull/2560)) ([Aeadoin](https://github.com/Aeadoin)) 2022-11-25
|
||||
* Add Event_Trade Support for ^inventorygive Command ([#2628](https://github.com/EQEmu/Server/pull/2628)) ([Aeadoin](https://github.com/Aeadoin)) 2022-12-11
|
||||
* Add Expansion Bitmask Quest APIs. ([#2523](https://github.com/EQEmu/Server/pull/2523)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-11-16
|
||||
* Add GetBotOwnerByBotID Method ([#2715](https://github.com/EQEmu/Server/pull/2715)) ([Aeadoin](https://github.com/Aeadoin)) 2023-01-11
|
||||
* Add Melee Support for Casting, Cleanup Bot Casting Logic ([#2571](https://github.com/EQEmu/Server/pull/2571)) ([Aeadoin](https://github.com/Aeadoin)) 2022-11-25
|
||||
* Add Quest API Methods ([#2631](https://github.com/EQEmu/Server/pull/2631)) ([Aeadoin](https://github.com/Aeadoin)) 2022-12-12
|
||||
* Add Quest API Support for Limits. ([#2522](https://github.com/EQEmu/Server/pull/2522)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-11-17
|
||||
* Add Rule Allowing Bots to Equip Any Race Items ([#2578](https://github.com/EQEmu/Server/pull/2578)) ([Aeadoin](https://github.com/Aeadoin)) 2022-11-26
|
||||
* Add Support for AA bonuses that were missing. ([#2764](https://github.com/EQEmu/Server/pull/2764)) ([Aeadoin](https://github.com/Aeadoin)) 2023-01-20
|
||||
* Add Support for Bots to receive Auras, and other AoE Buffs. ([#2586](https://github.com/EQEmu/Server/pull/2586)) ([Aeadoin](https://github.com/Aeadoin)) 2022-11-27
|
||||
* Add Virtual Override for Bot::Attack ([#2771](https://github.com/EQEmu/Server/pull/2771)) ([Aeadoin](https://github.com/Aeadoin)) 2023-01-20
|
||||
* Add give/remove saylinks to ^itemuse. ([#2503](https://github.com/EQEmu/Server/pull/2503)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-10-30
|
||||
* Add support for Bot scripting. ([#2515](https://github.com/EQEmu/Server/pull/2515)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-11-17
|
||||
* Apply Spells:IgnoreSpellDmgLvlRestriction to bots ([#2024](https://github.com/EQEmu/Server/pull/2024)) ([catapultam-habeo](https://github.com/catapultam-habeo)) 2022-03-07
|
||||
* Bot::PerformTradeWithClient Cleanup. ([#2084](https://github.com/EQEmu/Server/pull/2084)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-01
|
||||
* Cleanup Bot Spell Functions, reduce reliance on NPC Functions/Attributes ([#2495](https://github.com/EQEmu/Server/pull/2495)) ([Aeadoin](https://github.com/Aeadoin)) 2022-10-29
|
||||
* Cleanup Fast Rest Regen ([#2626](https://github.com/EQEmu/Server/pull/2626)) ([Aeadoin](https://github.com/Aeadoin)) 2022-12-07
|
||||
* Cleanup Say Event Parse. ([#2557](https://github.com/EQEmu/Server/pull/2557)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-11-20
|
||||
* Cleanup Spell Settings Commands ([#2607](https://github.com/EQEmu/Server/pull/2607)) ([Aeadoin](https://github.com/Aeadoin)) 2022-12-04
|
||||
* Cleanup ^inventoryremove, ^inventorylist, and ^list Commands and bot groups. ([#2273](https://github.com/EQEmu/Server/pull/2273)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-07-03
|
||||
* Cleanup and remove preprocessors. ([#2757](https://github.com/EQEmu/Server/pull/2757)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-01-20
|
||||
* Cleanup various Bot Spell Focus methods ([#2649](https://github.com/EQEmu/Server/pull/2649)) ([Aeadoin](https://github.com/Aeadoin)) 2022-12-16
|
||||
* Convert Load, Save, SaveNew, and Delete to Repositories. ([#2614](https://github.com/EQEmu/Server/pull/2614)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-12-04
|
||||
* Expanded Bot Spell Settings List. ([#2606](https://github.com/EQEmu/Server/pull/2606)) ([Aeadoin](https://github.com/Aeadoin)) 2022-12-03
|
||||
* Fix Bot Spell Type "In Combat Buffs" ([#2711](https://github.com/EQEmu/Server/pull/2711)) ([Aeadoin](https://github.com/Aeadoin)) 2023-01-08
|
||||
* Fix Gender not saving as GetBaseGender on BotSave ([#2639](https://github.com/EQEmu/Server/pull/2639)) ([nytmyr](https://github.com/nytmyr)) 2022-12-13
|
||||
* Fix Slow Query in QueryNameAvailablity ([#2781](https://github.com/EQEmu/Server/pull/2781)) ([Aeadoin](https://github.com/Aeadoin)) 2023-01-22
|
||||
* Fix ^dyearmor command math. ([#2081](https://github.com/EQEmu/Server/pull/2081)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-04-30
|
||||
* Fix bot spawn when bot id = char_id ([#1984](https://github.com/EQEmu/Server/pull/1984)) ([neckkola](https://github.com/neckkola)) 2022-03-07
|
||||
* Hotfix for possible crash. ([#2539](https://github.com/EQEmu/Server/pull/2539)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-11-14
|
||||
* Melee Bot Support for Spell Settings Commands ([#2599](https://github.com/EQEmu/Server/pull/2599)) ([Aeadoin](https://github.com/Aeadoin)) 2022-12-01
|
||||
* Move Bot Spell Loading process to constructor from calcbotstats() ([#2583](https://github.com/EQEmu/Server/pull/2583)) ([Aeadoin](https://github.com/Aeadoin)) 2022-11-27
|
||||
* Optimize inventory loading. ([#2588](https://github.com/EQEmu/Server/pull/2588)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-11-28
|
||||
* Post pre-processor fixes ([#2770](https://github.com/EQEmu/Server/pull/2770)) ([Akkadius](https://github.com/Akkadius)) 2023-01-20
|
||||
* Resolve incorrect values on Bot Creation ([#2644](https://github.com/EQEmu/Server/pull/2644)) ([Aeadoin](https://github.com/Aeadoin)) 2022-12-14
|
||||
* Restrict Bot Groups from spawning while Feigned. ([#2761](https://github.com/EQEmu/Server/pull/2761)) ([Aeadoin](https://github.com/Aeadoin)) 2023-01-19
|
||||
* Save Bot Toggle Archer Setting between Loads. ([#2612](https://github.com/EQEmu/Server/pull/2612)) ([Aeadoin](https://github.com/Aeadoin)) 2022-12-04
|
||||
* Update Bot Heal & Damage methods to more closely match Clients + Bugfixes ([#2045](https://github.com/EQEmu/Server/pull/2045)) ([catapultam-habeo](https://github.com/catapultam-habeo)) 2022-03-11
|
||||
* Update Bot Logic to ignore ST_TargetsTarget when buffing ([#2584](https://github.com/EQEmu/Server/pull/2584)) ([Aeadoin](https://github.com/Aeadoin)) 2022-11-27
|
||||
|
||||
### Bug
|
||||
|
||||
* Fixed trade items record log ([#2003](https://github.com/EQEmu/Server/pull/2003)) ([cybernine186](https://github.com/cybernine186)) 2022-02-17
|
||||
* Loot Drop Randomization adjustment ([#2368](https://github.com/EQEmu/Server/pull/2368)) ([fryguy503](https://github.com/fryguy503)) 2022-08-31
|
||||
* UINT32 EmoteID ([#2369](https://github.com/EQEmu/Server/pull/2369)) ([fryguy503](https://github.com/fryguy503)) 2022-08-13
|
||||
|
||||
### Bug Fix
|
||||
|
||||
* Boats should never get FixZ'd ([#2246](https://github.com/EQEmu/Server/pull/2246)) ([noudess](https://github.com/noudess)) 2022-07-02
|
||||
* Clamp Item Ldon Sell Back Rates. ([#2592](https://github.com/EQEmu/Server/pull/2592)) ([Aeadoin](https://github.com/Aeadoin)) 2022-11-30
|
||||
* Zone Flags Regression ([#2760](https://github.com/EQEmu/Server/pull/2760)) ([Akkadius](https://github.com/Akkadius)) 2023-01-19
|
||||
|
||||
### C++20
|
||||
|
||||
* Arithmetic on different enums is deprecated ([#2752](https://github.com/EQEmu/Server/pull/2752)) ([mackal](https://github.com/mackal)) 2023-01-17
|
||||
* Enable C++20 + Fixes + FMT 9.1 ([#2664](https://github.com/EQEmu/Server/pull/2664)) ([Akkadius](https://github.com/Akkadius)) 2022-12-21
|
||||
|
||||
### CI
|
||||
|
||||
* Hook tests back up ([#2316](https://github.com/EQEmu/Server/pull/2316)) ([Akkadius](https://github.com/Akkadius)) 2022-07-27
|
||||
|
||||
### CPP
|
||||
|
||||
* Update C++ standard to C++17 ([#2308](https://github.com/EQEmu/Server/pull/2308)) ([mackal](https://github.com/mackal)) 2022-07-27
|
||||
|
||||
### Cereal
|
||||
|
||||
* Bump to v1.3.2 from v1.2.2 ([#2654](https://github.com/EQEmu/Server/pull/2654)) ([Akkadius](https://github.com/Akkadius)) 2022-12-20
|
||||
|
||||
### Client
|
||||
|
||||
* Fix IsMoving for Client ([#2318](https://github.com/EQEmu/Server/pull/2318)) ([Akkadius](https://github.com/Akkadius)) 2022-07-27
|
||||
* Remove unimplemented Client Insight Method. ([#2663](https://github.com/EQEmu/Server/pull/2663)) ([Aeadoin](https://github.com/Aeadoin)) 2022-12-21
|
||||
|
||||
### Code
|
||||
|
||||
* Removed vscode setting ([#2753](https://github.com/EQEmu/Server/pull/2753)) ([xackery](https://github.com/xackery)) 2023-01-17
|
||||
|
||||
### Code Cleanup
|
||||
|
||||
* Add Validation to varchar number item fields. ([#2241](https://github.com/EQEmu/Server/pull/2241)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-06-04
|
||||
* Cleanup #kick message. ([#2164](https://github.com/EQEmu/Server/pull/2164)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-10
|
||||
* Cleanup Haste references and Lua API calls for unsigned to signed. ([#2240](https://github.com/EQEmu/Server/pull/2240)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-06-04
|
||||
* Cleanup code smells and compiler warnings in common/shareddb ([#2270](https://github.com/EQEmu/Server/pull/2270)) ([Quintinon](https://github.com/Quintinon)) 2022-07-03
|
||||
* Cleanup magic numbers ([#2662](https://github.com/EQEmu/Server/pull/2662)) ([Aeadoin](https://github.com/Aeadoin)) 2022-12-20
|
||||
* Cleanup spell and max level bucket logic. ([#2181](https://github.com/EQEmu/Server/pull/2181)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-28
|
||||
* Extra Space in NPC::AISpellsList(). ([#2555](https://github.com/EQEmu/Server/pull/2555)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-11-20
|
||||
* Fix unintended copies in zone/zonedb.cpp by changing auto to auto& ([#2271](https://github.com/EQEmu/Server/pull/2271)) ([Quintinon](https://github.com/Quintinon)) 2022-07-03
|
||||
* Make use of std::abs where possible. ([#2739](https://github.com/EQEmu/Server/pull/2739)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-01-15
|
||||
* Merge Client::Attack and Bot::Attack into Mob::Attack ([#2756](https://github.com/EQEmu/Server/pull/2756)) ([Aeadoin](https://github.com/Aeadoin)) 2023-01-20
|
||||
* Move Client::Undye() to client.cpp from #path Command. ([#2188](https://github.com/EQEmu/Server/pull/2188)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-21
|
||||
* Possible issues with variable/parameter name equality. ([#2161](https://github.com/EQEmu/Server/pull/2161)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-10
|
||||
* Quest API push methods using invalid types. ([#2172](https://github.com/EQEmu/Server/pull/2172)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-16
|
||||
* Remove unused basic_functions.h ([#2729](https://github.com/EQEmu/Server/pull/2729)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-01-13
|
||||
* Remove unused maxskill.h. ([#2728](https://github.com/EQEmu/Server/pull/2728)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-01-13
|
||||
* Remove unused methods. ([#2171](https://github.com/EQEmu/Server/pull/2171)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-15
|
||||
* Remove unusued Max Item ID Constant ([#2528](https://github.com/EQEmu/Server/pull/2528)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-11-08
|
||||
* Rework Lua QuestReward to not use try/catch blocks ([#2417](https://github.com/EQEmu/Server/pull/2417)) ([mackal](https://github.com/mackal)) 2022-09-03
|
||||
* Send eqstr message in AddAAPoints ([#2507](https://github.com/EQEmu/Server/pull/2507)) ([hgtw](https://github.com/hgtw)) 2022-10-29
|
||||
* Update to EQEmu #2253 to clean up message strings ([#2279](https://github.com/EQEmu/Server/pull/2279)) ([fryguy503](https://github.com/fryguy503)) 2022-07-03
|
||||
|
||||
### Combat
|
||||
|
||||
* /shield command "too far away message" ([#1999](https://github.com/EQEmu/Server/pull/1999)) ([KayenEQ](https://github.com/KayenEQ)) 2022-02-14
|
||||
* Basic Combat Recording ([#2090](https://github.com/EQEmu/Server/pull/2090)) ([Akkadius](https://github.com/Akkadius)) 2022-05-01
|
||||
* Fix Frenzy vs opponents immune to non-magic ([#2095](https://github.com/EQEmu/Server/pull/2095)) ([noudess](https://github.com/noudess)) 2022-05-03
|
||||
* Fix shield calculation ([#2234](https://github.com/EQEmu/Server/pull/2234)) ([Quintinon](https://github.com/Quintinon)) 2022-06-01
|
||||
* Legacy Combat Middleware Affected by PR #1858 ([#1939](https://github.com/EQEmu/Server/pull/1939)) ([Akkadius](https://github.com/Akkadius)) 2022-01-30
|
||||
|
||||
### Commands
|
||||
|
||||
* #bind Typo. ([#2196](https://github.com/EQEmu/Server/pull/2196)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-23
|
||||
* #ginfo Cleanup. ([#1955](https://github.com/EQEmu/Server/pull/1955)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-02-03
|
||||
* #reload Command Overhaul. ([#2162](https://github.com/EQEmu/Server/pull/2162)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-10
|
||||
* #reload level_mods could cause Non-Booted zones to crash. ([#2670](https://github.com/EQEmu/Server/pull/2670)) ([Aeadoin](https://github.com/Aeadoin)) 2022-12-24
|
||||
* Add #bugs Command. ([#2559](https://github.com/EQEmu/Server/pull/2559)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-11-22
|
||||
* Add #feature Command. ([#2142](https://github.com/EQEmu/Server/pull/2142)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-06
|
||||
* Add #findcharacter Command. ([#2692](https://github.com/EQEmu/Server/pull/2692)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-01-03
|
||||
* Add #findrecipe and #viewrecipe Commands. ([#2401](https://github.com/EQEmu/Server/pull/2401)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-08-31
|
||||
* Add #setanon Command ([#2690](https://github.com/EQEmu/Server/pull/2690)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-01-03
|
||||
* Add #suspendmulti Command. ([#2619](https://github.com/EQEmu/Server/pull/2619)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-12-11
|
||||
* Add BestZ and Region Data to #loc ([#2245](https://github.com/EQEmu/Server/pull/2245)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-06-05
|
||||
* Add additional #peqzone functionality. ([#2085](https://github.com/EQEmu/Server/pull/2085)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-01
|
||||
* Add max_hp back to #modifynpcstat command. ([#2638](https://github.com/EQEmu/Server/pull/2638)) ([nytmyr](https://github.com/nytmyr)) 2022-12-13
|
||||
* Adding movespeed to #showstats output ([#2596](https://github.com/EQEmu/Server/pull/2596)) ([fryguy503](https://github.com/fryguy503)) 2022-11-30
|
||||
* Bug fix for #logs command. ([#2008](https://github.com/EQEmu/Server/pull/2008)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-02-17
|
||||
* Cleanup #ai Command. ([#1980](https://github.com/EQEmu/Server/pull/1980)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-02-11
|
||||
* Cleanup #appearanceeffects Command. ([#2777](https://github.com/EQEmu/Server/pull/2777)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-01-22
|
||||
* Cleanup #attack Command. ([#2103](https://github.com/EQEmu/Server/pull/2103)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-04
|
||||
* Cleanup #ban, #ipban, #flag, #kick, #setlsinfo, and #setpass Commands. ([#2104](https://github.com/EQEmu/Server/pull/2104)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-08
|
||||
* Cleanup #chat Command. ([#2581](https://github.com/EQEmu/Server/pull/2581)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-11-27
|
||||
* Cleanup #corpsefix Command. ([#2197](https://github.com/EQEmu/Server/pull/2197)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-27
|
||||
* Cleanup #cvs Command. ([#2153](https://github.com/EQEmu/Server/pull/2153)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-08
|
||||
* Cleanup #date Command. ([#2228](https://github.com/EQEmu/Server/pull/2228)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-06-01
|
||||
* Cleanup #dbspawn2 Command. ([#2493](https://github.com/EQEmu/Server/pull/2493)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-10-30
|
||||
* Cleanup #delacct Command. ([#2567](https://github.com/EQEmu/Server/pull/2567)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-11-22
|
||||
* Cleanup #depop Command. ([#2536](https://github.com/EQEmu/Server/pull/2536)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-11-14
|
||||
* Cleanup #depopzone Command. ([#2537](https://github.com/EQEmu/Server/pull/2537)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-11-14
|
||||
* Cleanup #devtools Command. ([#2538](https://github.com/EQEmu/Server/pull/2538)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-11-14
|
||||
* Cleanup #doanim Command. ([#2540](https://github.com/EQEmu/Server/pull/2540)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-11-14
|
||||
* Cleanup #emote Command. ([#2535](https://github.com/EQEmu/Server/pull/2535)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-11-14
|
||||
* Cleanup #emotesearch and #emoteview Command. ([#2494](https://github.com/EQEmu/Server/pull/2494)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-10-30
|
||||
* Cleanup #emptyinventory Command. ([#2219](https://github.com/EQEmu/Server/pull/2219)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-29
|
||||
* Cleanup #findaliases and #help Commands. ([#2204](https://github.com/EQEmu/Server/pull/2204)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-27
|
||||
* Cleanup #findclass and #findrace Commands. ([#2211](https://github.com/EQEmu/Server/pull/2211)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-27
|
||||
* Cleanup #flagedit Command. ([#1968](https://github.com/EQEmu/Server/pull/1968)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-02-10
|
||||
* Cleanup #freeze and #unfreeze Commands. ([#2102](https://github.com/EQEmu/Server/pull/2102)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-04
|
||||
* Cleanup #gassign Command. ([#2101](https://github.com/EQEmu/Server/pull/2101)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-06
|
||||
* Cleanup #gearup Command. ([#2589](https://github.com/EQEmu/Server/pull/2589)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-11-27
|
||||
* Cleanup #getvariable Command. ([#2100](https://github.com/EQEmu/Server/pull/2100)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-04
|
||||
* Cleanup #guild Command ([#2693](https://github.com/EQEmu/Server/pull/2693)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-01-04
|
||||
* Cleanup #hatelist Command. ([#1976](https://github.com/EQEmu/Server/pull/1976)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-02-10
|
||||
* Cleanup #heromodel Command. ([#2566](https://github.com/EQEmu/Server/pull/2566)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-11-22
|
||||
* Cleanup #kill Command. ([#2195](https://github.com/EQEmu/Server/pull/2195)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-23
|
||||
* Cleanup #level Command. ([#2203](https://github.com/EQEmu/Server/pull/2203)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-27
|
||||
* Cleanup #logs Command. ([#1969](https://github.com/EQEmu/Server/pull/1969)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-02-10
|
||||
* Cleanup #makepet Command. ([#2105](https://github.com/EQEmu/Server/pull/2105)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-07
|
||||
* Cleanup #modifynpcstat Command. ([#2499](https://github.com/EQEmu/Server/pull/2499)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-10-30
|
||||
* Cleanup #motd Command. ([#2190](https://github.com/EQEmu/Server/pull/2190)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-23
|
||||
* Cleanup #name Command. ([#1977](https://github.com/EQEmu/Server/pull/1977)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-02-10
|
||||
* Cleanup #netstats Command. ([#1970](https://github.com/EQEmu/Server/pull/1970)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-02-10
|
||||
* Cleanup #npcedit Command. ([#2582](https://github.com/EQEmu/Server/pull/2582)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-11-27
|
||||
* Cleanup #npcedit, #lastname, #title, and #titlesuffix Commands. ([#2215](https://github.com/EQEmu/Server/pull/2215)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-28
|
||||
* Cleanup #npceditmass command. ([#1957](https://github.com/EQEmu/Server/pull/1957)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-02-03
|
||||
* Cleanup #npcemote Command. ([#2106](https://github.com/EQEmu/Server/pull/2106)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-07
|
||||
* Cleanup #npcloot Command. ([#1974](https://github.com/EQEmu/Server/pull/1974)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-02-11
|
||||
* Cleanup #npcsay and #npcshout Commands. ([#2107](https://github.com/EQEmu/Server/pull/2107)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-07
|
||||
* Cleanup #npcspecialattk Command. ([#2108](https://github.com/EQEmu/Server/pull/2108)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-07
|
||||
* Cleanup #npctype_cache Command. ([#2109](https://github.com/EQEmu/Server/pull/2109)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-07
|
||||
* Cleanup #npctypespawn Command. ([#2110](https://github.com/EQEmu/Server/pull/2110)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-07
|
||||
* Cleanup #nudge Command. ([#2220](https://github.com/EQEmu/Server/pull/2220)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-29
|
||||
* Cleanup #oocmute Command. ([#2191](https://github.com/EQEmu/Server/pull/2191)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-27
|
||||
* Cleanup #opcode Command. ([#2547](https://github.com/EQEmu/Server/pull/2547)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-11-16
|
||||
* Cleanup #profanity Command. ([#2113](https://github.com/EQEmu/Server/pull/2113)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-07
|
||||
* Cleanup #push Command. ([#2114](https://github.com/EQEmu/Server/pull/2114)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-07
|
||||
* Cleanup #qglobal Command. ([#2115](https://github.com/EQEmu/Server/pull/2115)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-07
|
||||
* Cleanup #randomizefeatures Command. ([#2118](https://github.com/EQEmu/Server/pull/2118)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-07
|
||||
* Cleanup #refreshgroup Command. ([#2119](https://github.com/EQEmu/Server/pull/2119)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-07
|
||||
* Cleanup #reloadaa Command. ([#2120](https://github.com/EQEmu/Server/pull/2120)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-07
|
||||
* Cleanup #reloadallrules Command. ([#2121](https://github.com/EQEmu/Server/pull/2121)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-07
|
||||
* Cleanup #reloadlevelmods Command. ([#2122](https://github.com/EQEmu/Server/pull/2122)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-07
|
||||
* Cleanup #reloadmerchants Command. ([#2123](https://github.com/EQEmu/Server/pull/2123)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-07
|
||||
* Cleanup #reloadperlexportsettings Command. ([#2124](https://github.com/EQEmu/Server/pull/2124)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-07
|
||||
* Cleanup #reloadrulesworld Command. ([#2128](https://github.com/EQEmu/Server/pull/2128)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-07
|
||||
* Cleanup #reloadstatic Command. ([#2130](https://github.com/EQEmu/Server/pull/2130)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-07
|
||||
* Cleanup #reloadtitles Command. ([#2125](https://github.com/EQEmu/Server/pull/2125)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-07
|
||||
* Cleanup #reloadtraps Command. ([#2126](https://github.com/EQEmu/Server/pull/2126)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-07
|
||||
* Cleanup #reloadworld and #repop Command. ([#2127](https://github.com/EQEmu/Server/pull/2127)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-07
|
||||
* Cleanup #reloadzps Command. ([#2129](https://github.com/EQEmu/Server/pull/2129)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-07
|
||||
* Cleanup #resetaa Command. ([#2132](https://github.com/EQEmu/Server/pull/2132)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-07
|
||||
* Cleanup #resetaa_timer Command. ([#2131](https://github.com/EQEmu/Server/pull/2131)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-07
|
||||
* Cleanup #resetdisc_timer Command. ([#2133](https://github.com/EQEmu/Server/pull/2133)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-06
|
||||
* Cleanup #revoke Command. ([#2134](https://github.com/EQEmu/Server/pull/2134)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-07
|
||||
* Cleanup #roambox Command. ([#2135](https://github.com/EQEmu/Server/pull/2135)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-06
|
||||
* Cleanup #rules Command. ([#2593](https://github.com/EQEmu/Server/pull/2593)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-12-10
|
||||
* Cleanup #save Command. ([#2136](https://github.com/EQEmu/Server/pull/2136)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-06
|
||||
* Cleanup #scale Command. ([#2591](https://github.com/EQEmu/Server/pull/2591)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-12-05
|
||||
* Cleanup #scribespell and #scribespells Commands. ([#2534](https://github.com/EQEmu/Server/pull/2534)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-11-14
|
||||
* Cleanup #sensetrap Command. ([#2137](https://github.com/EQEmu/Server/pull/2137)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-07
|
||||
* Cleanup #serverinfo Command. ([#2568](https://github.com/EQEmu/Server/pull/2568)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-11-22
|
||||
* Cleanup #serverrules Command. ([#2139](https://github.com/EQEmu/Server/pull/2139)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-06
|
||||
* Cleanup #setlanguage Command. ([#2464](https://github.com/EQEmu/Server/pull/2464)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-10-13
|
||||
* Cleanup #setskillall Command. ([#1992](https://github.com/EQEmu/Server/pull/1992)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-02-15
|
||||
* Cleanup #shownpcgloballoot and #showzonegloballoot Command. ([#2141](https://github.com/EQEmu/Server/pull/2141)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-06
|
||||
* Cleanup #showskills Command. ([#1994](https://github.com/EQEmu/Server/pull/1994)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-02-15
|
||||
* Cleanup #spawneditmass Command. ([#2229](https://github.com/EQEmu/Server/pull/2229)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-06-04
|
||||
* Cleanup #spawnfix Command. ([#2143](https://github.com/EQEmu/Server/pull/2143)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-06
|
||||
* Cleanup #spawnstatus Command. ([#2144](https://github.com/EQEmu/Server/pull/2144)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-06
|
||||
* Cleanup #summon Command. ([#2145](https://github.com/EQEmu/Server/pull/2145)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-06
|
||||
* Cleanup #summonburiedplayercorpse Command. ([#2146](https://github.com/EQEmu/Server/pull/2146)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-07
|
||||
* Cleanup #suspend Command. ([#2564](https://github.com/EQEmu/Server/pull/2564)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-11-22
|
||||
* Cleanup #task Command. ([#2071](https://github.com/EQEmu/Server/pull/2071)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-04-14
|
||||
* Cleanup #time and #timezone Command. ([#2147](https://github.com/EQEmu/Server/pull/2147)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-07
|
||||
* Cleanup #timers Command. ([#2562](https://github.com/EQEmu/Server/pull/2562)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-11-22
|
||||
* Cleanup #trapinfo Command. ([#2148](https://github.com/EQEmu/Server/pull/2148)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-07
|
||||
* Cleanup #ucs Command. ([#2149](https://github.com/EQEmu/Server/pull/2149)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-07
|
||||
* Cleanup #undye and #undyeme Commands. ([#1966](https://github.com/EQEmu/Server/pull/1966)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-02-10
|
||||
* Cleanup #unscribespell Command. ([#1998](https://github.com/EQEmu/Server/pull/1998)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-02-16
|
||||
* Cleanup #untraindisc Command. ([#1996](https://github.com/EQEmu/Server/pull/1996)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-02-16
|
||||
* Cleanup #version Command. ([#1967](https://github.com/EQEmu/Server/pull/1967)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-02-10
|
||||
* Cleanup #worldwide command. ([#2021](https://github.com/EQEmu/Server/pull/2021)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-03-01
|
||||
* Cleanup #xtargets Command. ([#2545](https://github.com/EQEmu/Server/pull/2545)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-11-17
|
||||
* Cleanup #zone and #zoneinstance Commands. ([#2202](https://github.com/EQEmu/Server/pull/2202)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-27
|
||||
* Command Status Reload and Helper Method ([#2377](https://github.com/EQEmu/Server/pull/2377)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-08-20
|
||||
* Consolidate #lock and #unlock Commands into #serverlock. ([#2193](https://github.com/EQEmu/Server/pull/2193)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-23
|
||||
* Fix #copycharacter command crash ([#2446](https://github.com/EQEmu/Server/pull/2446)) ([Akkadius](https://github.com/Akkadius)) 2022-09-25
|
||||
* Fix #killallnpcs from crashing ([#2037](https://github.com/EQEmu/Server/pull/2037)) ([Akkadius](https://github.com/Akkadius)) 2022-03-07
|
||||
* Fix Flymode Command Help Prompt ([#2669](https://github.com/EQEmu/Server/pull/2669)) ([Aeadoin](https://github.com/Aeadoin)) 2022-12-23
|
||||
* Fix typos in #ban and #ipban Commands. ([#2209](https://github.com/EQEmu/Server/pull/2209)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-26
|
||||
* Make #damage require a target ([#2426](https://github.com/EQEmu/Server/pull/2426)) ([hgtw](https://github.com/hgtw)) 2022-09-05
|
||||
* Nested Command Aliases ([#2636](https://github.com/EQEmu/Server/pull/2636)) ([Akkadius](https://github.com/Akkadius)) 2022-12-15
|
||||
* Remove #guildapprove, #guildcreate, and #guildlist Commands ([#2775](https://github.com/EQEmu/Server/pull/2775)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-01-22
|
||||
* Remove #iteminfo Command. ([#2565](https://github.com/EQEmu/Server/pull/2565)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-11-22
|
||||
* Remove #profiledump and #profilereset Commands. ([#2546](https://github.com/EQEmu/Server/pull/2546)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-11-16
|
||||
* Remove #undyeme Command. ([#2776](https://github.com/EQEmu/Server/pull/2776)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-01-22
|
||||
* Remove unused #bestz and #pf Commands. ([#2112](https://github.com/EQEmu/Server/pull/2112)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-07
|
||||
* Remove unused/broken #deletegraveyard and #setgraveyard Commands. ([#2198](https://github.com/EQEmu/Server/pull/2198)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-23
|
||||
|
||||
### Compile
|
||||
|
||||
* Decrease build times using unity build strategy ([#2089](https://github.com/EQEmu/Server/pull/2089)) ([Akkadius](https://github.com/Akkadius)) 2022-05-01
|
||||
|
||||
### Crash
|
||||
|
||||
* Fix reload crashes ([#2462](https://github.com/EQEmu/Server/pull/2462)) ([Akkadius](https://github.com/Akkadius)) 2022-09-30
|
||||
* Fix spawn race condition shown by #repop ([#2455](https://github.com/EQEmu/Server/pull/2455)) ([Akkadius](https://github.com/Akkadius)) 2022-09-29
|
||||
* Linux Crash Dump Improvements ([#2296](https://github.com/EQEmu/Server/pull/2296)) ([Akkadius](https://github.com/Akkadius)) 2022-07-14
|
||||
* Pointer validation in mob iteration loops ([#2490](https://github.com/EQEmu/Server/pull/2490)) ([Akkadius](https://github.com/Akkadius)) 2022-10-15
|
||||
* Stability Fixes ([#2489](https://github.com/EQEmu/Server/pull/2489)) ([Akkadius](https://github.com/Akkadius)) 2022-10-15
|
||||
* Websocket Crash fix race when fetching log categories ([#2456](https://github.com/EQEmu/Server/pull/2456)) ([Akkadius](https://github.com/Akkadius)) 2022-09-29
|
||||
|
||||
### Database
|
||||
|
||||
* Add Primary ID Keys to Tables ([#2036](https://github.com/EQEmu/Server/pull/2036)) ([Akkadius](https://github.com/Akkadius)) 2022-03-07
|
||||
* Add fallback migration for logsys columns ([#2457](https://github.com/EQEmu/Server/pull/2457)) ([Akkadius](https://github.com/Akkadius)) 2022-09-29
|
||||
* Update 2022_01_10_checksum_verification.sql ([#2041](https://github.com/EQEmu/Server/pull/2041)) ([joligario](https://github.com/joligario)) 2022-03-07
|
||||
|
||||
### Diawind
|
||||
|
||||
* Plus sign markdown fix ([#2727](https://github.com/EQEmu/Server/pull/2727)) ([Akkadius](https://github.com/Akkadius)) 2023-01-12
|
||||
|
||||
### Doors
|
||||
|
||||
* Fix Misty PoK Stone ([#2482](https://github.com/EQEmu/Server/pull/2482)) ([Akkadius](https://github.com/Akkadius)) 2022-10-14
|
||||
* Fix Neriak PoK Stone ([#2486](https://github.com/EQEmu/Server/pull/2486)) ([Coreidan](https://github.com/Coreidan)) 2022-10-15
|
||||
* Fix door target zone heading data ([#2414](https://github.com/EQEmu/Server/pull/2414)) ([Akkadius](https://github.com/Akkadius)) 2022-09-05
|
||||
* Improvements to door manipulation ([#2370](https://github.com/EQEmu/Server/pull/2370)) ([Akkadius](https://github.com/Akkadius)) 2022-08-13
|
||||
|
||||
### Drone
|
||||
|
||||
* Speed up drone builds ([#2092](https://github.com/EQEmu/Server/pull/2092)) ([Akkadius](https://github.com/Akkadius)) 2022-05-02
|
||||
|
||||
### Expansions
|
||||
|
||||
* Expansion Deprecation Revert ([#2312](https://github.com/EQEmu/Server/pull/2312)) ([Akkadius](https://github.com/Akkadius)) 2022-07-15
|
||||
* Zone expansion consistency changes ([#2380](https://github.com/EQEmu/Server/pull/2380)) ([Akkadius](https://github.com/Akkadius)) 2022-08-22
|
||||
|
||||
### Experience
|
||||
|
||||
* Change Exp Calculations to be 64 bit where needed. ([#2677](https://github.com/EQEmu/Server/pull/2677)) ([Aeadoin](https://github.com/Aeadoin)) 2022-12-31
|
||||
|
||||
### Feature
|
||||
|
||||
* AA Cap Limit ([#2423](https://github.com/EQEmu/Server/pull/2423)) ([fryguy503](https://github.com/fryguy503)) 2022-10-13
|
||||
* Add "Keeps Sold Items" Flag to NPCs ([#2671](https://github.com/EQEmu/Server/pull/2671)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-12-25
|
||||
* Add Experience Gain Toggle. ([#2676](https://github.com/EQEmu/Server/pull/2676)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-12-30
|
||||
* Add Guild Chat to Console. ([#2387](https://github.com/EQEmu/Server/pull/2387)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-08-22
|
||||
* Add Hate Override for Heals ([#2485](https://github.com/EQEmu/Server/pull/2485)) ([Aeadoin](https://github.com/Aeadoin)) 2022-10-14
|
||||
* Add Rule to Disable Group EXP Modifier. ([#2741](https://github.com/EQEmu/Server/pull/2741)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-01-15
|
||||
* Add Support for "Show Mine Only" Filters ([#2484](https://github.com/EQEmu/Server/pull/2484)) ([Aeadoin](https://github.com/Aeadoin)) 2022-10-13
|
||||
* Add Type 49545 to Spell Resistrictions ([#2436](https://github.com/EQEmu/Server/pull/2436)) ([Aeadoin](https://github.com/Aeadoin)) 2022-09-20
|
||||
* Add humanoid and non-wielded restrictions to pick pocket ([#2276](https://github.com/EQEmu/Server/pull/2276)) ([noudess](https://github.com/noudess)) 2022-07-03
|
||||
* Add player /inspect quest event ([#2508](https://github.com/EQEmu/Server/pull/2508)) ([hgtw](https://github.com/hgtw)) 2022-10-29
|
||||
* Add special ability to block /open ([#2506](https://github.com/EQEmu/Server/pull/2506)) ([hgtw](https://github.com/hgtw)) 2022-10-29
|
||||
* Allow Focus Effects to be Filtered out. ([#2447](https://github.com/EQEmu/Server/pull/2447)) ([Aeadoin](https://github.com/Aeadoin)) 2022-09-25
|
||||
* Allow pets to zone with permanent (buffdurationformula 50) buffs to maintain them through zone transitions ([#2035](https://github.com/EQEmu/Server/pull/2035)) ([catapultam-habeo](https://github.com/catapultam-habeo)) 2022-03-07
|
||||
* Bind Wound and Forage while mounted. ([#2257](https://github.com/EQEmu/Server/pull/2257)) ([fryguy503](https://github.com/fryguy503)) 2022-07-03
|
||||
* Change #scribespells to be aware of spellgroups & ranks ([#2501](https://github.com/EQEmu/Server/pull/2501)) ([Aeadoin](https://github.com/Aeadoin)) 2022-11-06
|
||||
* Change GetSkillDmgAmt to int32 ([#2364](https://github.com/EQEmu/Server/pull/2364)) ([Aeadoin](https://github.com/Aeadoin)) 2022-08-10
|
||||
* Change Lifetap Emotes to be filterable. ([#2454](https://github.com/EQEmu/Server/pull/2454)) ([Aeadoin](https://github.com/Aeadoin)) 2022-09-29
|
||||
* Change Mana Costs to use Signed Int ([#2384](https://github.com/EQEmu/Server/pull/2384)) ([Aeadoin](https://github.com/Aeadoin)) 2022-08-21
|
||||
* Change mana_used to int32 ([#2321](https://github.com/EQEmu/Server/pull/2321)) ([Aeadoin](https://github.com/Aeadoin)) 2022-07-30
|
||||
* Client Checksum Verification (Resubmit old 1678) ([#1922](https://github.com/EQEmu/Server/pull/1922)) ([noudess](https://github.com/noudess)) 2022-03-07
|
||||
* EQ2-style implied targeting for spells. ([#2032](https://github.com/EQEmu/Server/pull/2032)) ([catapultam-habeo](https://github.com/catapultam-habeo)) 2022-03-07
|
||||
* Faction Association ([#2408](https://github.com/EQEmu/Server/pull/2408)) ([mackal](https://github.com/mackal)) 2022-09-03
|
||||
* GM State Change Persistance ([#2328](https://github.com/EQEmu/Server/pull/2328)) ([fryguy503](https://github.com/fryguy503)) 2022-07-31
|
||||
* Implement Heroic Strikethrough to NPCs ([#2395](https://github.com/EQEmu/Server/pull/2395)) ([Aeadoin](https://github.com/Aeadoin)) 2022-08-31
|
||||
* Implement OP_CashReward ([#2307](https://github.com/EQEmu/Server/pull/2307)) ([mackal](https://github.com/mackal)) 2022-07-15
|
||||
* Instance Version Specific Experience Modifiers ([#2376](https://github.com/EQEmu/Server/pull/2376)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-08-20
|
||||
* NPCs with bows and arrows do ranged attacks ([#2322](https://github.com/EQEmu/Server/pull/2322)) ([mackal](https://github.com/mackal)) 2022-07-30
|
||||
* Soft Delete Bots on Character Soft Delete ([#2467](https://github.com/EQEmu/Server/pull/2467)) ([Aeadoin](https://github.com/Aeadoin)) 2022-10-13
|
||||
* Spell Ranks will now work with AllowSpellMemorizeFromItem Rule ([#2475](https://github.com/EQEmu/Server/pull/2475)) ([Aeadoin](https://github.com/Aeadoin)) 2022-10-13
|
||||
* Update HateMod used by SPA 114 to Int32. ([#2428](https://github.com/EQEmu/Server/pull/2428)) ([Aeadoin](https://github.com/Aeadoin)) 2022-09-08
|
||||
|
||||
### Git
|
||||
|
||||
* Add Clangd Generated Files to .gitignore ([#2684](https://github.com/EQEmu/Server/pull/2684)) ([Aeadoin](https://github.com/Aeadoin)) 2022-12-31
|
||||
|
||||
### Hotfix
|
||||
|
||||
* Add Bazaar portal discs to SQL ([Akkadius](https://github.com/Akkadius)) 2022-09-05
|
||||
* Add discord_webhooks to server tables ([Akkadius](https://github.com/Akkadius)) 2022-07-03
|
||||
* Blocks are nested too deeply. ([#2689](https://github.com/EQEmu/Server/pull/2689)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-01-01
|
||||
* Cleanup #questerrors Command. ([#2116](https://github.com/EQEmu/Server/pull/2116)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-07
|
||||
* Compiling fails on FMT 9.1 with Bots ([#2665](https://github.com/EQEmu/Server/pull/2665)) ([Aeadoin](https://github.com/Aeadoin)) 2022-12-21
|
||||
* Correct database call to point to the content_db connection ([Akkadius](https://github.com/Akkadius)) 2022-06-12
|
||||
* Corrected misnamed Database Query file for Experience Toggle ([#2683](https://github.com/EQEmu/Server/pull/2683)) ([Aeadoin](https://github.com/Aeadoin)) 2022-12-31
|
||||
* Faction associations file naming / lock consistency ([Akkadius](https://github.com/Akkadius)) 2022-09-05
|
||||
* Fix DB version merge ([Akkadius](https://github.com/Akkadius)) 2022-05-08
|
||||
* Fix door click crash issue if destination zone doesn't exist ([Akkadius](https://github.com/Akkadius)) 2023-01-20
|
||||
* Fix issue with Bot Loading with 0 Health causing buffs to be lost. ([#2552](https://github.com/EQEmu/Server/pull/2552)) ([Aeadoin](https://github.com/Aeadoin)) 2022-11-18
|
||||
* Fix lua mod load path ([Akkadius](https://github.com/Akkadius)) 2022-09-29
|
||||
* Fix merge issue ([Akkadius](https://github.com/Akkadius)) 2022-07-14
|
||||
* Fix path load ordering for CLI commands ([Akkadius](https://github.com/Akkadius)) 2022-10-16
|
||||
* Fix potential race for crash dumps (Linux) ([Akkadius](https://github.com/Akkadius)) 2022-07-31
|
||||
* Fix regression caused by #2129 ([Akkadius](https://github.com/Akkadius)) 2022-05-09
|
||||
* Flipped positive / negative values for legacy_combat.lua ([Akkadius](https://github.com/Akkadius)) 2022-06-09
|
||||
* Force collation on conversion script ([Akkadius](https://github.com/Akkadius)) 2022-09-28
|
||||
* Instances Repository Fix ([#2576](https://github.com/EQEmu/Server/pull/2576)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-11-26
|
||||
* Login Server failing to compile on Windows. ([#2758](https://github.com/EQEmu/Server/pull/2758)) ([Aeadoin](https://github.com/Aeadoin)) 2023-01-19
|
||||
* Lua Parser Needs Lua_ItemInst ([#2696](https://github.com/EQEmu/Server/pull/2696)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-01-01
|
||||
* Make sure we have a proper split size before assuming we can split it ([Akkadius](https://github.com/Akkadius)) 2023-01-20
|
||||
* Move discord_webhooks to state tables because we don't want webhooks being exported ([Akkadius](https://github.com/Akkadius)) 2022-07-03
|
||||
* Possible windows compile fix ([Akkadius](https://github.com/Akkadius)) 2022-07-07
|
||||
* Possible windows compile fix take 2 ([Akkadius](https://github.com/Akkadius)) 2022-07-07
|
||||
* Remove appveyor fetch bots ([Akkadius](https://github.com/Akkadius)) 2023-01-21
|
||||
* Remove expansion field from account for those who have it ([#2357](https://github.com/EQEmu/Server/pull/2357)) ([Akkadius](https://github.com/Akkadius)) 2022-08-01
|
||||
* Resolve Zone Crashing when grouped with Bots. ([#2747](https://github.com/EQEmu/Server/pull/2747)) ([Aeadoin](https://github.com/Aeadoin)) 2023-01-16
|
||||
* Resolve issue with Bot Casting after zoning. ([#2617](https://github.com/EQEmu/Server/pull/2617)) ([Aeadoin](https://github.com/Aeadoin)) 2022-12-04
|
||||
* Return weather_type_map ([Akkadius](https://github.com/Akkadius)) 2022-10-14
|
||||
* SQL Update ([Akkadius](https://github.com/Akkadius)) 2022-07-31
|
||||
* Shared Memory Protection Fixes ([Akkadius](https://github.com/Akkadius)) 2022-07-27
|
||||
* Windows compile fix take 3 (final) ([Akkadius](https://github.com/Akkadius)) 2022-07-07
|
||||
* fix manifest ([Akkadius](https://github.com/Akkadius)) 2022-07-16
|
||||
|
||||
### Library
|
||||
|
||||
* Bump httplib to 0.11.2 ([#2442](https://github.com/EQEmu/Server/pull/2442)) ([Akkadius](https://github.com/Akkadius)) 2022-09-28
|
||||
|
||||
### Loading
|
||||
|
||||
* Zone Version Loading Fixes ([#2233](https://github.com/EQEmu/Server/pull/2233)) ([Akkadius](https://github.com/Akkadius)) 2022-06-01
|
||||
|
||||
### Logging
|
||||
|
||||
* Add stack trace in code paths that shouldn't occur ([#2453](https://github.com/EQEmu/Server/pull/2453)) ([Akkadius](https://github.com/Akkadius)) 2022-09-28
|
||||
* Cleanup AI Logging Events ([#2615](https://github.com/EQEmu/Server/pull/2615)) ([Aeadoin](https://github.com/Aeadoin)) 2022-12-04
|
||||
* Fix log messages to final damage values ([#2056](https://github.com/EQEmu/Server/pull/2056)) ([noudess](https://github.com/noudess)) 2022-03-14
|
||||
* Fix zoning log typo ([#2478](https://github.com/EQEmu/Server/pull/2478)) ([Akkadius](https://github.com/Akkadius)) 2022-10-11
|
||||
* Force crash logs to always be on regardless of setting ([#2762](https://github.com/EQEmu/Server/pull/2762)) ([Akkadius](https://github.com/Akkadius)) 2023-01-20
|
||||
* Improvements to GM Say Logging ([#2765](https://github.com/EQEmu/Server/pull/2765)) ([Akkadius](https://github.com/Akkadius)) 2023-01-20
|
||||
* Logging Improvements ([#2755](https://github.com/EQEmu/Server/pull/2755)) ([Akkadius](https://github.com/Akkadius)) 2023-01-18
|
||||
* More AI Logging Cleanup ([#2616](https://github.com/EQEmu/Server/pull/2616)) ([Aeadoin](https://github.com/Aeadoin)) 2022-12-10
|
||||
* Netcode Logging Unify ([#2443](https://github.com/EQEmu/Server/pull/2443)) ([Akkadius](https://github.com/Akkadius)) 2022-09-28
|
||||
* Remove function prefixes ([#2766](https://github.com/EQEmu/Server/pull/2766)) ([Akkadius](https://github.com/Akkadius)) 2023-01-20
|
||||
* Remove loginserver unhandled error ([#2458](https://github.com/EQEmu/Server/pull/2458)) ([Akkadius](https://github.com/Akkadius)) 2022-09-29
|
||||
* Reset stream so we don't bold the whole line ([Akkadius](https://github.com/Akkadius)) 2023-01-18
|
||||
* Table Injection - Member Variable Cleanup ([#2281](https://github.com/EQEmu/Server/pull/2281)) ([Akkadius](https://github.com/Akkadius)) 2022-07-07
|
||||
* Update BUILD_LOGGING=false Blank Aliases ([#2083](https://github.com/EQEmu/Server/pull/2083)) ([Akkadius](https://github.com/Akkadius)) 2022-05-01
|
||||
|
||||
### Login
|
||||
|
||||
* Added OP_ExpansionPacketData for RoF2 and update payload for Titanium ([#2186](https://github.com/EQEmu/Server/pull/2186)) ([neckkola](https://github.com/neckkola)) 2022-07-14
|
||||
|
||||
### Logs
|
||||
|
||||
* #logs list Improvements ([#2302](https://github.com/EQEmu/Server/pull/2302)) ([Akkadius](https://github.com/Akkadius)) 2022-07-14
|
||||
* Fix GMSay Log Regression ([#2298](https://github.com/EQEmu/Server/pull/2298)) ([Akkadius](https://github.com/Akkadius)) 2022-07-14
|
||||
* Have #reload logs also reload UCS logging ([#2491](https://github.com/EQEmu/Server/pull/2491)) ([Akkadius](https://github.com/Akkadius)) 2022-10-15
|
||||
|
||||
### Loot
|
||||
|
||||
* Add #lootsim (Loot Simulator) command ([#2375](https://github.com/EQEmu/Server/pull/2375)) ([Akkadius](https://github.com/Akkadius)) 2022-08-20
|
||||
* Remove unnecessary loot error messages. ([#2261](https://github.com/EQEmu/Server/pull/2261)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-06-12
|
||||
|
||||
### Luabind
|
||||
|
||||
* Silence deprecation warning ([#2657](https://github.com/EQEmu/Server/pull/2657)) ([Akkadius](https://github.com/Akkadius)) 2022-12-20
|
||||
|
||||
### Luamod
|
||||
|
||||
* Add CalcSpellEffectValue_formula to luamods ([#2721](https://github.com/EQEmu/Server/pull/2721)) ([Natedog2012](https://github.com/Natedog2012)) 2023-01-11
|
||||
|
||||
### Manifest
|
||||
|
||||
* Its not_empty not notempty ([#2394](https://github.com/EQEmu/Server/pull/2394)) ([mackal](https://github.com/mackal)) 2022-08-23
|
||||
|
||||
### Merchant
|
||||
|
||||
* LDoNSellBackRate support for Rule Merchant:EnableAltCurrencySell ([#2570](https://github.com/EQEmu/Server/pull/2570)) ([Aeadoin](https://github.com/Aeadoin)) 2022-11-25
|
||||
|
||||
### Mercs
|
||||
|
||||
* Add Mercenary Support ([#2745](https://github.com/EQEmu/Server/pull/2745)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-01-17
|
||||
|
||||
### Messages
|
||||
|
||||
* Convert messages from Spells to FocusEffect where necessary. ([#2243](https://github.com/EQEmu/Server/pull/2243)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-06-08
|
||||
|
||||
### Netcode
|
||||
|
||||
* Adjust first packet for compress flag ([#2326](https://github.com/EQEmu/Server/pull/2326)) ([hgtw](https://github.com/hgtw)) 2022-07-27
|
||||
|
||||
### Opcode
|
||||
|
||||
* Implement SetFace opcode ([#2167](https://github.com/EQEmu/Server/pull/2167)) ([hgtw](https://github.com/hgtw)) 2022-05-11
|
||||
|
||||
### Optimization
|
||||
|
||||
* Handle channel name filter checks in memory ([#2767](https://github.com/EQEmu/Server/pull/2767)) ([Valorith](https://github.com/Valorith)) 2023-01-20
|
||||
|
||||
### Pathing
|
||||
|
||||
* Fix pathing z-correctness for certain models ([#2430](https://github.com/EQEmu/Server/pull/2430)) ([Akkadius](https://github.com/Akkadius)) 2022-09-11
|
||||
|
||||
### Process
|
||||
|
||||
* Process Execution Refactor ([#2632](https://github.com/EQEmu/Server/pull/2632)) ([Akkadius](https://github.com/Akkadius)) 2022-12-11
|
||||
|
||||
### QS
|
||||
|
||||
* Database class name change ([#2743](https://github.com/EQEmu/Server/pull/2743)) ([Akkadius](https://github.com/Akkadius)) 2023-01-15
|
||||
|
||||
### Quests
|
||||
|
||||
* Improve Quest Error Handling ([#2635](https://github.com/EQEmu/Server/pull/2635)) ([Akkadius](https://github.com/Akkadius)) 2022-12-13
|
||||
* Improve Quest Error Handling - Add back in process based syntax validation ([#2646](https://github.com/EQEmu/Server/pull/2646)) ([Akkadius](https://github.com/Akkadius)) 2022-12-15
|
||||
|
||||
### Refactor
|
||||
|
||||
* Simplify NPC Loading ([#2087](https://github.com/EQEmu/Server/pull/2087)) ([Akkadius](https://github.com/Akkadius)) 2022-05-01
|
||||
|
||||
### Regen
|
||||
|
||||
* Fix possible overflow in CalcHPRegenCap(). ([#2185](https://github.com/EQEmu/Server/pull/2185)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-27
|
||||
* Implement Per Second HP Regen for NPCs ([#2086](https://github.com/EQEmu/Server/pull/2086)) ([Akkadius](https://github.com/Akkadius)) 2022-05-01
|
||||
|
||||
### Repositories
|
||||
|
||||
* Add Bot Repositories. ([#2529](https://github.com/EQEmu/Server/pull/2529)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-11-16
|
||||
* Add Cereal support to repository generator ([#2660](https://github.com/EQEmu/Server/pull/2660)) ([Akkadius](https://github.com/Akkadius)) 2022-12-20
|
||||
* Add GetMaxId, Count ([#2371](https://github.com/EQEmu/Server/pull/2371)) ([Akkadius](https://github.com/Akkadius)) 2022-08-13
|
||||
* Add more precise types to repository generator ([#2391](https://github.com/EQEmu/Server/pull/2391)) ([mackal](https://github.com/mackal)) 2022-08-31
|
||||
* Cast floats to avoid grid repository warnings ([#2094](https://github.com/EQEmu/Server/pull/2094)) ([hgtw](https://github.com/hgtw)) 2022-05-02
|
||||
* Migrate LoadPerlEventExportSettings to use repositories ([#2637](https://github.com/EQEmu/Server/pull/2637)) ([Akkadius](https://github.com/Akkadius)) 2022-12-15
|
||||
* Modernize character recipe list ([#2385](https://github.com/EQEmu/Server/pull/2385)) ([Akkadius](https://github.com/Akkadius)) 2022-08-22
|
||||
* Update Character EXP Modifiers Repository ([#2530](https://github.com/EQEmu/Server/pull/2530)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-11-14
|
||||
* Update repositories ([#2040](https://github.com/EQEmu/Server/pull/2040)) ([Akkadius](https://github.com/Akkadius)) 2022-03-11
|
||||
|
||||
### Roambox
|
||||
|
||||
* Improve Path Finding ([#2324](https://github.com/EQEmu/Server/pull/2324)) ([noudess](https://github.com/noudess)) 2022-07-30
|
||||
|
||||
### Rules
|
||||
|
||||
* Add Backstab Rules ([#2666](https://github.com/EQEmu/Server/pull/2666)) ([Valorith](https://github.com/Valorith)) 2022-12-21
|
||||
* Add Frontal Stun Immunity Rules. ([#2217](https://github.com/EQEmu/Server/pull/2217)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-06-07
|
||||
* Add Keep Level on Death ([#2319](https://github.com/EQEmu/Server/pull/2319)) ([trentdm](https://github.com/trentdm)) 2022-07-30
|
||||
* Add LDoN Loot Count Modifier Rule ([#2694](https://github.com/EQEmu/Server/pull/2694)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-01-03
|
||||
* Add ManaOnDeath and EndurOnDeath ([#2661](https://github.com/EQEmu/Server/pull/2661)) ([fryguy503](https://github.com/fryguy503)) 2022-12-20
|
||||
* Add Rule to Disable NPC Last Names. ([#2227](https://github.com/EQEmu/Server/pull/2227)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-06-04
|
||||
* Add Rule to Enable Tells with #hideme ([#2358](https://github.com/EQEmu/Server/pull/2358)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-08-04
|
||||
* Add Rule to allow Assassinate on non-Humanoid body types. ([#2331](https://github.com/EQEmu/Server/pull/2331)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-07-29
|
||||
* Add Rule to allow Headshots on non-Humanoid body types. ([#2329](https://github.com/EQEmu/Server/pull/2329)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-07-29
|
||||
* Add Rules to disable various item functionalities and cleanup data types. ([#2225](https://github.com/EQEmu/Server/pull/2225)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-06-01
|
||||
* Add Spells:BuffsFadeOnDeath. ([#2200](https://github.com/EQEmu/Server/pull/2200)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-27
|
||||
* Add Spells:IllusionsAlwaysPersist. ([#2199](https://github.com/EQEmu/Server/pull/2199)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-27
|
||||
* Add Toggle for Warrior Shielding ([#2496](https://github.com/EQEmu/Server/pull/2496)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-10-22
|
||||
* Add adjustment for zone forage. ([#2330](https://github.com/EQEmu/Server/pull/2330)) ([fryguy503](https://github.com/fryguy503)) 2022-07-30
|
||||
* Add rule for NPC Level Based Buff Restrictions. ([#2708](https://github.com/EQEmu/Server/pull/2708)) ([noudess](https://github.com/noudess)) 2023-01-15
|
||||
* Add rule to allow players to permanently save chat channels to database, up to a limit. ([#2706](https://github.com/EQEmu/Server/pull/2706)) ([Valorith](https://github.com/Valorith)) 2023-01-19
|
||||
* Change TradeskillUp Rules to be Floats ([#2674](https://github.com/EQEmu/Server/pull/2674)) ([Aeadoin](https://github.com/Aeadoin)) 2022-12-25
|
||||
* Cleanup all unused rules. ([#2184](https://github.com/EQEmu/Server/pull/2184)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-23
|
||||
* Rule Gate Pet Zoning ([#2625](https://github.com/EQEmu/Server/pull/2625)) ([fryguy503](https://github.com/fryguy503)) 2022-12-07
|
||||
* Rule to allow cap on % XP gain per kill ([#2667](https://github.com/EQEmu/Server/pull/2667)) ([Valorith](https://github.com/Valorith)) 2022-12-25
|
||||
* Update logic checks everywhere for FVNoDropFlag. ([#2179](https://github.com/EQEmu/Server/pull/2179)) ([Quintinon](https://github.com/Quintinon)) 2022-07-30
|
||||
|
||||
### SQL
|
||||
|
||||
* Bugs Table Migration (#2602) ([#2559](https://github.com/EQEmu/Server/pull/2559)) ([joligario](https://github.com/joligario)) 2022-12-01
|
||||
* Update 2023_01_15_merc_data.sql ([#2763](https://github.com/EQEmu/Server/pull/2763)) ([joligario](https://github.com/joligario)) 2023-01-20
|
||||
|
||||
### Saylinks
|
||||
|
||||
* Add Silent helper ([#2372](https://github.com/EQEmu/Server/pull/2372)) ([Akkadius](https://github.com/Akkadius)) 2022-08-13
|
||||
* Convert all GM Command Saylinks to Silent Saylinks. ([#2373](https://github.com/EQEmu/Server/pull/2373)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-08-14
|
||||
* Inject Saylinks in MessageClose API ([#2335](https://github.com/EQEmu/Server/pull/2335)) ([hgtw](https://github.com/hgtw)) 2022-07-31
|
||||
* Refactor saylink injection ([#2315](https://github.com/EQEmu/Server/pull/2315)) ([hgtw](https://github.com/hgtw)) 2022-07-27
|
||||
|
||||
### Server
|
||||
|
||||
* Configuration Issues Checker (LAN Detection) ([#2283](https://github.com/EQEmu/Server/pull/2283)) ([Akkadius](https://github.com/Akkadius)) 2022-07-07
|
||||
|
||||
### Skills
|
||||
|
||||
* Configurable Exponential Decay Formula for Skill Up ([#1887](https://github.com/EQEmu/Server/pull/1887)) ([mmcgarvey](https://github.com/mmcgarvey)) 2022-01-30
|
||||
|
||||
### Spells
|
||||
|
||||
* AE Duration effect (Rains) will now work with Target Ring and PBAE spells. ([#2000](https://github.com/EQEmu/Server/pull/2000)) ([KayenEQ](https://github.com/KayenEQ)) 2022-02-16
|
||||
* Allow damage spells to heal if quest based spell mitigation is over 100 pct. ([#1978](https://github.com/EQEmu/Server/pull/1978)) ([KayenEQ](https://github.com/KayenEQ)) 2022-02-08
|
||||
* Bard songs from item clickies should not require components ([#2011](https://github.com/EQEmu/Server/pull/2011)) ([KayenEQ](https://github.com/KayenEQ)) 2022-02-18
|
||||
* Fix for AA and Discipline recast timers being set on spell casting failure. ([#1971](https://github.com/EQEmu/Server/pull/1971)) ([KayenEQ](https://github.com/KayenEQ)) 2022-02-08
|
||||
* Fix for AA recast timers not resetting properly ([#1989](https://github.com/EQEmu/Server/pull/1989)) ([KayenEQ](https://github.com/KayenEQ)) 2022-02-11
|
||||
* Fixes for numhits type 7 counter incrementing incorrectly. ([#2022](https://github.com/EQEmu/Server/pull/2022)) ([KayenEQ](https://github.com/KayenEQ)) 2022-03-02
|
||||
* Illusions will now persist onto the corpse when mob is killed. ([#1960](https://github.com/EQEmu/Server/pull/1960)) ([KayenEQ](https://github.com/KayenEQ)) 2022-02-05
|
||||
* Invisibility updates and rework ([#1991](https://github.com/EQEmu/Server/pull/1991)) ([KayenEQ](https://github.com/KayenEQ)) 2022-02-15
|
||||
* Major update to Bard song pulsing, Bard item clicks while singing, and spell casting restriction logic. ([#1954](https://github.com/EQEmu/Server/pull/1954)) ([KayenEQ](https://github.com/KayenEQ)) 2022-02-07
|
||||
* SPA 311 SE_LimitCombatSkills should prevent focusing of procs even if proc is a 'casted' spell. ([#1961](https://github.com/EQEmu/Server/pull/1961)) ([KayenEQ](https://github.com/KayenEQ)) 2022-02-05
|
||||
* SPA 79 SE_CurrentHPOnce now will check for focus, critical and partial resist checks, except for buffs. ([#2018](https://github.com/EQEmu/Server/pull/2018)) ([KayenEQ](https://github.com/KayenEQ)) 2022-02-24
|
||||
* Support for 'HateAdded' spell field to apply negative values to reduce hate. ([#1953](https://github.com/EQEmu/Server/pull/1953)) ([KayenEQ](https://github.com/KayenEQ)) 2022-02-03
|
||||
* Support for SPA 194 SE_FadingMemories to use max level checks on aggroed mobs ([#1979](https://github.com/EQEmu/Server/pull/1979)) ([KayenEQ](https://github.com/KayenEQ)) 2022-02-09
|
||||
* Swarm pet aggro logic fix ([#1956](https://github.com/EQEmu/Server/pull/1956)) ([KayenEQ](https://github.com/KayenEQ)) 2022-02-04
|
||||
* Target's Target Combat Range Rule ([#2274](https://github.com/EQEmu/Server/pull/2274)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-06-24
|
||||
* Update to target types Beam and Cone to ignore invalid targets. ([#2080](https://github.com/EQEmu/Server/pull/2080)) ([KayenEQ](https://github.com/KayenEQ)) 2022-05-01
|
||||
* Updates to spell field 'cast not stands' to ignore casting restrictions ([#1938](https://github.com/EQEmu/Server/pull/1938)) ([KayenEQ](https://github.com/KayenEQ)) 2022-01-29
|
||||
|
||||
### Strings
|
||||
|
||||
* Refactor Strings Usage ([#2305](https://github.com/EQEmu/Server/pull/2305)) ([Akkadius](https://github.com/Akkadius)) 2022-07-14
|
||||
|
||||
### Tasks
|
||||
|
||||
* Add Task Reward Points Field ([#2317](https://github.com/EQEmu/Server/pull/2317)) ([hgtw](https://github.com/hgtw)) 2022-07-30
|
||||
* Add method to filter shared task offers ([#2497](https://github.com/EQEmu/Server/pull/2497)) ([hgtw](https://github.com/hgtw)) 2022-10-29
|
||||
* Add pre-task update event ([#2512](https://github.com/EQEmu/Server/pull/2512)) ([hgtw](https://github.com/hgtw)) 2022-10-30
|
||||
* Add rule to update multiple task elements ([#2427](https://github.com/EQEmu/Server/pull/2427)) ([hgtw](https://github.com/hgtw)) 2022-09-06
|
||||
* Add task accept packet validation ([#2354](https://github.com/EQEmu/Server/pull/2354)) ([hgtw](https://github.com/hgtw)) 2022-07-31
|
||||
* Apply full duration mission replay timers ([#2299](https://github.com/EQEmu/Server/pull/2299)) ([hgtw](https://github.com/hgtw)) 2022-07-14
|
||||
* Change zone task data container ([#2410](https://github.com/EQEmu/Server/pull/2410)) ([hgtw](https://github.com/hgtw)) 2022-09-03
|
||||
* Crash fix with data input sanitization ([#2629](https://github.com/EQEmu/Server/pull/2629)) ([Akkadius](https://github.com/Akkadius)) 2022-12-10
|
||||
* Data validation for zone_version ([#2381](https://github.com/EQEmu/Server/pull/2381)) ([Akkadius](https://github.com/Akkadius)) 2022-08-21
|
||||
* Fix #task command crash on bad input ([#2301](https://github.com/EQEmu/Server/pull/2301)) ([hgtw](https://github.com/hgtw)) 2022-07-14
|
||||
* Fix validation loading ([#2230](https://github.com/EQEmu/Server/pull/2230)) ([Akkadius](https://github.com/Akkadius)) 2022-06-01
|
||||
* Implement Task Goal Match List ([#2097](https://github.com/EQEmu/Server/pull/2097)) ([Akkadius](https://github.com/Akkadius)) 2022-05-07
|
||||
* Implement task activity prerequisites ([#2374](https://github.com/EQEmu/Server/pull/2374)) ([hgtw](https://github.com/hgtw)) 2022-08-22
|
||||
* Let task completion event block task rewards ([#2511](https://github.com/EQEmu/Server/pull/2511)) ([hgtw](https://github.com/hgtw)) 2022-10-30
|
||||
* Let task reward find free bag slots ([#2431](https://github.com/EQEmu/Server/pull/2431)) ([hgtw](https://github.com/hgtw)) 2022-09-18
|
||||
* Make #task reloadall not quit shared tasks ([#2351](https://github.com/EQEmu/Server/pull/2351)) ([hgtw](https://github.com/hgtw)) 2022-07-31
|
||||
* Make Task Selector Cooldown Optional ([#2420](https://github.com/EQEmu/Server/pull/2420)) ([hgtw](https://github.com/hgtw)) 2022-09-03
|
||||
* Only allow shared task completion once ([#2422](https://github.com/EQEmu/Server/pull/2422)) ([hgtw](https://github.com/hgtw)) 2022-09-03
|
||||
* Only update loot tasks for NPC corpses ([#2513](https://github.com/EQEmu/Server/pull/2513)) ([hgtw](https://github.com/hgtw)) 2022-11-05
|
||||
* Place task item rewards in free slots ([#2300](https://github.com/EQEmu/Server/pull/2300)) ([hgtw](https://github.com/hgtw)) 2022-07-14
|
||||
* Remove delivered task items from trades ([#2405](https://github.com/EQEmu/Server/pull/2405)) ([hgtw](https://github.com/hgtw)) 2022-09-02
|
||||
* Replace task goals with explicit fields ([#2402](https://github.com/EQEmu/Server/pull/2402)) ([hgtw](https://github.com/hgtw)) 2022-09-02
|
||||
* Reward clients on shared task completion sync ([#2306](https://github.com/EQEmu/Server/pull/2306)) ([hgtw](https://github.com/hgtw)) 2022-07-16
|
||||
* Schema simplification ([#2449](https://github.com/EQEmu/Server/pull/2449)) ([hgtw](https://github.com/hgtw)) 2022-09-28
|
||||
* Send Client Message for All Solo Task Updates ([#2336](https://github.com/EQEmu/Server/pull/2336)) ([hgtw](https://github.com/hgtw)) 2022-07-31
|
||||
* Support Raw NPC Names in Task Goal List ([#2333](https://github.com/EQEmu/Server/pull/2333)) ([hgtw](https://github.com/hgtw)) 2022-07-30
|
||||
* Tweak task update messages ([#2406](https://github.com/EQEmu/Server/pull/2406)) ([hgtw](https://github.com/hgtw)) 2022-09-02
|
||||
* Use CashReward for Tasks ([#2332](https://github.com/EQEmu/Server/pull/2332)) ([hgtw](https://github.com/hgtw)) 2022-07-30
|
||||
* Use dz switch id for task touch events ([#2344](https://github.com/EQEmu/Server/pull/2344)) ([hgtw](https://github.com/hgtw)) 2022-07-31
|
||||
* Use zone currencies instead of hard-coded enum. ([#2459](https://github.com/EQEmu/Server/pull/2459)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-09-29
|
||||
* Zone Version Matching ([#2303](https://github.com/EQEmu/Server/pull/2303)) ([Akkadius](https://github.com/Akkadius)) 2022-07-14
|
||||
|
||||
### Telnet
|
||||
|
||||
* Add guildsay to console commands and Guild Channel to QueueMessage. ([#2263](https://github.com/EQEmu/Server/pull/2263)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-07-03
|
||||
|
||||
### Titles
|
||||
|
||||
* Cleanup titles, title suffix, and last name methods. ([#2174](https://github.com/EQEmu/Server/pull/2174)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-20
|
||||
|
||||
### Typo
|
||||
|
||||
* Remove CanTradeFVNoDropItem() Duplicate ([#2352](https://github.com/EQEmu/Server/pull/2352)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-07-31
|
||||
|
||||
### UCS
|
||||
|
||||
* Auto Client Reconnection ([#2154](https://github.com/EQEmu/Server/pull/2154)) ([Akkadius](https://github.com/Akkadius)) 2022-05-08
|
||||
|
||||
### Utility
|
||||
|
||||
* Add std::string_view overloads for std::from_chars ([#2392](https://github.com/EQEmu/Server/pull/2392)) ([mackal](https://github.com/mackal)) 2022-08-31
|
||||
|
||||
### Validation
|
||||
|
||||
* Add Size Validation to #hotfix. ([#2304](https://github.com/EQEmu/Server/pull/2304)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-07-14
|
||||
|
||||
### Websocket
|
||||
|
||||
* Fix cpp20/gcc11 compile failure ([#2737](https://github.com/EQEmu/Server/pull/2737)) ([Akkadius](https://github.com/Akkadius)) 2023-01-15
|
||||
|
||||
### World
|
||||
|
||||
* Add more descriptive LS auth erroring ([#2293](https://github.com/EQEmu/Server/pull/2293)) ([Akkadius](https://github.com/Akkadius)) 2022-07-14
|
||||
* World Bootup Consolidation ([#2294](https://github.com/EQEmu/Server/pull/2294)) ([Akkadius](https://github.com/Akkadius)) 2022-07-14
|
||||
|
||||
### XTarget
|
||||
|
||||
* Revert All XTarget Corpse Changes ([#1944](https://github.com/EQEmu/Server/pull/1944)) ([mmcgarvey](https://github.com/mmcgarvey)) 2022-01-24
|
||||
|
||||
### Zone
|
||||
|
||||
* Add missing safe_heading assignment ([#2407](https://github.com/EQEmu/Server/pull/2407)) ([hgtw](https://github.com/hgtw)) 2022-09-02
|
||||
* Deprecate Zone `expansion` Field ([#2297](https://github.com/EQEmu/Server/pull/2297)) ([Akkadius](https://github.com/Akkadius)) 2022-07-14
|
||||
* Fix and simplify zone shutdown logic ([#2390](https://github.com/EQEmu/Server/pull/2390)) ([Akkadius](https://github.com/Akkadius)) 2022-08-31
|
||||
|
||||
### Zones
|
||||
|
||||
* Add Max Level Check to Zones. ([#2714](https://github.com/EQEmu/Server/pull/2714)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-01-11
|
||||
|
||||
### Zoning
|
||||
|
||||
* Fix zone race condition ([#2479](https://github.com/EQEmu/Server/pull/2479)) ([Akkadius](https://github.com/Akkadius)) 2022-10-12
|
||||
* Fix zoning logic issues ([#2412](https://github.com/EQEmu/Server/pull/2412)) ([Akkadius](https://github.com/Akkadius)) 2022-09-03
|
||||
* Possible zoning under world fix ([#2424](https://github.com/EQEmu/Server/pull/2424)) ([Akkadius](https://github.com/Akkadius)) 2022-10-11
|
||||
* Revert #2424 ([#2492](https://github.com/EQEmu/Server/pull/2492)) ([Akkadius](https://github.com/Akkadius)) 2022-10-16
|
||||
|
||||
### eqemu_server.pl
|
||||
|
||||
* Remove non-working fetch_latest_windows_binaries() ([#2445](https://github.com/EQEmu/Server/pull/2445)) ([Akkadius](https://github.com/Akkadius)) 2022-09-25
|
||||
|
||||
### int64
|
||||
|
||||
* Fix int64 for OOC Regen and GetHP(), GetMaxHP(), GetItemHPBonuses() in Perl/Lua. ([#2218](https://github.com/EQEmu/Server/pull/2218)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-29
|
||||
* Further int64 cleanup in Perl SetHP() and GetSpellHPBonuses() in Perl/Lua. ([#2222](https://github.com/EQEmu/Server/pull/2222)) ([Kinglykrab](https://github.com/Kinglykrab)) 2022-05-29
|
||||
* Hate Fixes ([#2163](https://github.com/EQEmu/Server/pull/2163)) ([Akkadius](https://github.com/Akkadius)) 2022-05-10
|
||||
* Support for HP / Mana / End / Damage / Hate ([#2091](https://github.com/EQEmu/Server/pull/2091)) ([Akkadius](https://github.com/Akkadius)) 2022-05-08
|
||||
* Windows Compile Fixes ([#2155](https://github.com/EQEmu/Server/pull/2155)) ([Akkadius](https://github.com/Akkadius)) 2022-05-08
|
||||
|
||||
### libuv
|
||||
|
||||
* Bump to v1.44.2 from v1.26.0 ([#2658](https://github.com/EQEmu/Server/pull/2658)) ([Akkadius](https://github.com/Akkadius)) 2022-12-20
|
||||
+20
-61
@@ -1,4 +1,4 @@
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 3.12)
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 3.2)
|
||||
|
||||
SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/" ${CMAKE_MODULE_PATH})
|
||||
|
||||
@@ -12,7 +12,7 @@ IF(NOT CMAKE_BUILD_TYPE)
|
||||
SET(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build." FORCE)
|
||||
ENDIF(NOT CMAKE_BUILD_TYPE)
|
||||
|
||||
SET(CMAKE_CXX_STANDARD 20)
|
||||
SET(CMAKE_CXX_STANDARD 14)
|
||||
SET(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
SET(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
@@ -20,10 +20,8 @@ IF(MSVC)
|
||||
ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS)
|
||||
ADD_DEFINITIONS(-DNOMINMAX)
|
||||
ADD_DEFINITIONS(-DCRASH_LOGGING)
|
||||
ADD_DEFINITIONS(-D_HAS_AUTO_PTR_ETC) # for Luabind on C++17
|
||||
|
||||
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
|
||||
ADD_DEFINITIONS( "/W0 /D_CRT_SECURE_NO_WARNINGS /wd4005 /wd4996 /nologo /Os")
|
||||
ELSE(MSVC)
|
||||
ADD_DEFINITIONS(-DHAS_UNION_SEMUN)
|
||||
ENDIF(MSVC)
|
||||
@@ -123,6 +121,8 @@ ENDIF()
|
||||
MESSAGE(STATUS "**************************************************")
|
||||
|
||||
#options
|
||||
OPTION(EQEMU_DEPOP_INVALIDATES_CACHE "#repop invalidates the npc_types cache (will cause a larger database hit on #repop but is more convienent)." ON)
|
||||
OPTION(EQEMU_ENABLE_BOTS "Enable Bots" OFF)
|
||||
OPTION(EQEMU_COMMANDS_LOGGING "Enable GM Command logs" ON)
|
||||
OPTION(EQEMU_BUILD_SERVER "Build the game server." ON)
|
||||
OPTION(EQEMU_BUILD_LOGIN "Build the login server." ON)
|
||||
@@ -131,58 +131,21 @@ OPTION(EQEMU_BUILD_TESTS "Build utility tests." OFF)
|
||||
OPTION(EQEMU_BUILD_CLIENT_FILES "Build Client Import/Export Data Programs." ON)
|
||||
OPTION(EQEMU_PREFER_LUA "Build with normal Lua even if LuaJIT is found." OFF)
|
||||
|
||||
#PRNG options
|
||||
OPTION(EQEMU_ADDITIVE_LFIB_PRNG "Use Additive LFib for PRNG." OFF)
|
||||
MARK_AS_ADVANCED(EQEMU_ADDITIVE_LFIB_PRNG)
|
||||
OPTION(EQEMU_BIASED_INT_DIST "Use biased int dist instead of uniform." OFF)
|
||||
MARK_AS_ADVANCED(EQEMU_BIASED_INT_DIST)
|
||||
SET(EQEMU_CUSTOM_PRNG_ENGINE "" CACHE STRING "Custom random engine. (ex. std::default_random_engine)")
|
||||
MARK_AS_ADVANCED(EQEMU_CUSTOM_PRNG_ENGINE)
|
||||
|
||||
IF(CMAKE_COMPILER_IS_GNUCXX)
|
||||
OPTION(EQEMU_SFMT19937 "Use GCC's extention for SIMD Fast MT19937." OFF)
|
||||
MARK_AS_ADVANCED(EQEMU_SFMT19937)
|
||||
ENDIF()
|
||||
|
||||
IF(EQEMU_ADDITIVE_LFIB_PRNG)
|
||||
ADD_DEFINITIONS(-DUSE_ADDITIVE_LFIB_PRNG)
|
||||
IF(EQEMU_SFMT19937)
|
||||
MESSAGE(STATUS "SFMT19937 and ADDITITVE_LFIB_PRNG both set, SFMT19937 ignored.")
|
||||
SET(EQEMU_SFMT19937 OFF)
|
||||
ENDIF()
|
||||
IF(NOT EQEMU_CUSTOM_PRNG_ENGINE STREQUAL "")
|
||||
MESSAGE(STATUS "CUSTOM_PRNG_ENGINE and ADDITITVE_LFIB_PRNG both set, CUSTOM_PRNG_ENGINE ignored.")
|
||||
SET(EQEMU_CUSTOM_PRNG_ENGINE "")
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
IF(EQEMU_SFMT19937)
|
||||
ADD_DEFINITIONS(-DUSE_SFMT19937)
|
||||
IF(NOT EQEMU_CUSTOM_PRNG_ENGINE STREQUAL "")
|
||||
MESSAGE(STATUS "CUSTOM_PRNG_ENGINE and SFMT19937 both set, CUSTOM_PRNG_ENGINE ignored.")
|
||||
SET(EQEMU_CUSTOM_PRNG_ENGINE "")
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
IF(NOT EQEMU_CUSTOM_PRNG_ENGINE STREQUAL "")
|
||||
ADD_DEFINITIONS(-DUSE_CUSTOM_PRNG_ENGINE=${EQEMU_CUSTOM_PRNG_ENGINE})
|
||||
ENDIF()
|
||||
|
||||
IF(EQEMU_BIASED_INT_DIST)
|
||||
ADD_DEFINITIONS(-DBIASED_INT_DIST)
|
||||
ENDIF()
|
||||
|
||||
IF(EQEMU_COMMANDS_LOGGING)
|
||||
ADD_DEFINITIONS(-DCOMMANDS_LOGGING)
|
||||
ENDIF(EQEMU_COMMANDS_LOGGING)
|
||||
|
||||
IF(EQEMU_ENABLE_BOTS)
|
||||
ADD_DEFINITIONS(-DBOTS)
|
||||
ENDIF(EQEMU_ENABLE_BOTS)
|
||||
|
||||
#database
|
||||
IF(MySQL_FOUND AND MariaDB_FOUND)
|
||||
SET(DATABASE_LIBRARY_SELECTION MariaDB CACHE STRING "Database library to use:
|
||||
MySQL
|
||||
MariaDB"
|
||||
)
|
||||
|
||||
|
||||
IF(DATABASE_LIBRARY_SELECTION STREQUAL "MySQL")
|
||||
SET(DATABASE_LIBRARY_TYPE " MySQL")
|
||||
SET(DATABASE_LIBRARY_LIBS ${MySQL_LIBRARIES})
|
||||
@@ -213,16 +176,13 @@ IF(OpenSSL_FOUND AND MBEDTLS_FOUND)
|
||||
OpenSSL
|
||||
mbedTLS"
|
||||
)
|
||||
|
||||
|
||||
IF(TLS_LIBRARY_SELECTION STREQUAL "OpenSSL")
|
||||
SET(TLS_LIBRARY_TYPE " OpenSSL")
|
||||
SET(TLS_LIBRARY_ENABLED ON)
|
||||
SET(TLS_LIBRARY_LIBS ${OPENSSL_LIBRARIES})
|
||||
SET(TLS_LIBRARY_INCLUDE ${OPENSSL_INCLUDE_DIR})
|
||||
ADD_DEFINITIONS(-DEQEMU_USE_OPENSSL)
|
||||
IF(${OPENSSL_VERSION} VERSION_GREATER_EQUAL "1.1.1")
|
||||
ADD_DEFINITIONS(-DCPPHTTPLIB_OPENSSL_SUPPORT)
|
||||
ENDIF()
|
||||
ELSEIF(TLS_LIBRARY_SELECTION STREQUAL "mbedTLS")
|
||||
SET(TLS_LIBRARY_TYPE " mbedTLS")
|
||||
SET(TLS_LIBRARY_ENABLED ON)
|
||||
@@ -238,9 +198,6 @@ ELSEIF(OpenSSL_FOUND)
|
||||
SET(TLS_LIBRARY_LIBS ${OPENSSL_LIBRARIES})
|
||||
SET(TLS_LIBRARY_INCLUDE ${OPENSSL_INCLUDE_DIR})
|
||||
ADD_DEFINITIONS(-DEQEMU_USE_OPENSSL)
|
||||
IF(${OPENSSL_VERSION} VERSION_GREATER_EQUAL "1.1.1")
|
||||
ADD_DEFINITIONS(-DCPPHTTPLIB_OPENSSL_SUPPORT)
|
||||
ENDIF()
|
||||
ELSEIF(MBEDTLS_FOUND)
|
||||
SET(TLS_LIBRARY_TYPE " mbedTLS")
|
||||
SET(TLS_LIBRARY_ENABLED ON)
|
||||
@@ -336,8 +293,10 @@ INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/submodules/recastnavigat
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/submodules/recastnavigation/Recast/Include")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/submodules/websocketpp")
|
||||
|
||||
# silence obnoxious deprecation message
|
||||
ADD_DEFINITIONS(-DBOOST_BIND_GLOBAL_PLACEHOLDERS)
|
||||
OPTION(EQEMU_BUILD_LOGGING "Build Logging (To speed up compilation)" ON)
|
||||
IF(EQEMU_BUILD_LOGGING)
|
||||
ADD_DEFINITIONS(-DBUILD_LOGGING)
|
||||
ENDIF()
|
||||
|
||||
IF(TLS_LIBRARY_ENABLED)
|
||||
SET(SERVER_LIBS ${SERVER_LIBS} ${TLS_LIBRARY_LIBS})
|
||||
@@ -351,12 +310,12 @@ ENDIF()
|
||||
|
||||
IF(LUA_LIBRARY_ENABLED)
|
||||
OPTION(EQEMU_BUILD_LUA "Build Lua parser." ON)
|
||||
|
||||
|
||||
IF(EQEMU_BUILD_LUA)
|
||||
ADD_DEFINITIONS(-DLUA_EQEMU)
|
||||
SET(ZONE_LIBS ${LUA_LIBRARY_LIBS})
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${LUA_LIBRARY_INCLUDE}")
|
||||
|
||||
|
||||
OPTION(EQEMU_SANITIZE_LUA_LIBS "Sanitize Lua Libraries (Remove OS and IO standard libraries from being able to run)." ON)
|
||||
IF(EQEMU_SANITIZE_LUA_LIBS)
|
||||
ADD_DEFINITIONS(-DSANITIZE_LUA_LIBS)
|
||||
@@ -367,7 +326,7 @@ ENDIF()
|
||||
IF(PERL_LIBRARY_ENABLED)
|
||||
OPTION(EQEMU_BUILD_PERL "Build Perl parser." ON)
|
||||
IF(EQEMU_BUILD_PERL)
|
||||
SET(SERVER_LIBS ${SERVER_LIBS} ${PERL_LIBRARY_LIBS} perlbind)
|
||||
SET(SERVER_LIBS ${SERVER_LIBS} ${PERL_LIBRARY_LIBS})
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${PERL_LIBRARY_INCLUDE}")
|
||||
ADD_DEFINITIONS(-DEMBPERL)
|
||||
ADD_DEFINITIONS(-DEMBPERL_PLUGIN)
|
||||
@@ -404,13 +363,13 @@ IF(EQEMU_BUILD_SERVER OR EQEMU_BUILD_LOGIN OR EQEMU_BUILD_TESTS OR EQEMU_BUILD_H
|
||||
ADD_SUBDIRECTORY(libs)
|
||||
ADD_SUBDIRECTORY(submodules/fmt)
|
||||
ADD_SUBDIRECTORY(submodules/libuv)
|
||||
|
||||
|
||||
IF(EQEMU_BUILD_ZLIB)
|
||||
SET(ZLIB_COMPAT ON CACHE BOOL "Compile with zlib compatible API")
|
||||
SET(ZLIB_ENABLE_TESTS OFF CACHE BOOL "Build test binaries")
|
||||
ADD_SUBDIRECTORY(libs/zlibng)
|
||||
ENDIF()
|
||||
|
||||
|
||||
SET(RECASTNAVIGATION_DEMO OFF CACHE BOOL "Build demo")
|
||||
SET(RECASTNAVIGATION_TESTS OFF CACHE BOOL "Build tests")
|
||||
SET(RECASTNAVIGATION_EXAMPLES OFF CACHE BOOL "Build examples")
|
||||
|
||||
@@ -18,16 +18,16 @@
|
||||
|**Install Count**|||
|
||||
### > Windows
|
||||
|
||||
* [Install Guide](https://docs.eqemu.io/server/installation/server-installation-windows/)
|
||||
* [Install Guide](https://eqemu.gitbook.io/server/categories/installation/server-installation-windows)
|
||||
|
||||
### > Debian/Ubuntu/CentOS/Fedora
|
||||
|
||||
* [Install Guide](https://docs.eqemu.io/server/installation/server-installation-linux/)
|
||||
* [Install Guide](https://eqemu.gitbook.io/server/categories/installation/server-installation-linux)
|
||||
|
||||
* You can use curl or wget to kick off the installer (whichever your OS has)
|
||||
> curl -O https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/linux_installer/install.sh install.sh && chmod 755 install.sh && ./install.sh
|
||||
|
||||
> wget --no-check-certificate https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/linux_installer/install.sh -O install.sh && chmod 755 install.sh && ./install.sh
|
||||
> wget --no-check-certificate https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/linux_installer/install.sh -O install.sh && chmod 755 install.sh && ./install.sh
|
||||
|
||||
## Supported Clients
|
||||
|
||||
@@ -56,7 +56,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://docs.eqemu.io/)
|
||||
- [EQEmulator Wiki](https://eqemu.gitbook.io/)
|
||||
|
||||
## Related Repositories
|
||||
* [ProjectEQ Quests](https://github.com/ProjectEQ/projecteqquests)
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
version: 1.0.{build}
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
image: Visual Studio 2017
|
||||
configuration: RelWithDebInfo
|
||||
clone_folder: c:\projects\eqemu
|
||||
init:
|
||||
- ps: git config --global core.autocrlf input
|
||||
cache: c:\tools\vcpkg\installed\
|
||||
before_build:
|
||||
- ps: "$wc = New-Object System.Net.WebClient\n$wc.DownloadFile(\"http://strawberryperl.com/download/5.26.2.1/strawberry-perl-5.26.2.1-64bit-portable.zip\", \"c:\\projects\\eqemu\\strawberry-perl-5.26.2.1-64bit-portable.zip\")\ncd c:\\projects\\eqemu\n7z x c:/projects/eqemu/strawberry-perl-5.26.2.1-64bit-portable.zip -oc:/projects/eqemu/strawberry-perl-portable -y\n(Get-Content C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE/config.h).replace('#define PERL_STATIC_INLINE static __inline__', '#define PERL_STATIC_INLINE static __inline') | Set-Content C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE/config.h\nvcpkg install boost-geometry:x64-windows boost-dynamic-bitset:x64-windows luajit:x64-windows libsodium:x64-windows libmysql:x64-windows openssl:x64-windows zlib:x64-windows \nmkdir build\ncd build\ncmake -G \"Visual Studio 15 2017 Win64\" -DEQEMU_BUILD_TESTS=ON -DEQEMU_BUILD_LOGIN=ON -EQEMU_ENABLE_BOTS=ON -DPERL_EXECUTABLE=\"C:/projects/eqemu/strawberry-perl-portable/perl/bin/perl.exe\" -DPERL_INCLUDE_PATH=\"C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE\" -DPERL_LIBRARY=\"C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE/libperl526.a\" -DCMAKE_TOOLCHAIN_FILE=\"c:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake\" .."
|
||||
build:
|
||||
project: C:\projects\eqemu\build\EQEmu.sln
|
||||
parallel: true
|
||||
verbosity: minimal
|
||||
after_build:
|
||||
- cmd: >-
|
||||
7z a build_x64-bots.zip C:\projects\eqemu\build\bin\RelWithDebInfo\*.exe C:\projects\eqemu\build\bin\RelWithDebInfo\*.dll C:\projects\eqemu\build\bin\RelWithDebInfo\*.pdb C:\projects\eqemu\build\libs\zlibng\RelWithDebInfo\*.dll
|
||||
|
||||
appveyor PushArtifact build_x64-bots.zip
|
||||
@@ -0,0 +1,21 @@
|
||||
version: 1.0.{build}
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
image: Visual Studio 2017
|
||||
configuration: RelWithDebInfo
|
||||
clone_folder: c:\projects\eqemu
|
||||
init:
|
||||
- ps: git config --global core.autocrlf input
|
||||
cache: c:\tools\vcpkg\installed\
|
||||
before_build:
|
||||
- ps: "$wc = New-Object System.Net.WebClient\n$wc.DownloadFile(\"http://strawberryperl.com/download/5.26.2.1/strawberry-perl-5.26.2.1-64bit-portable.zip\", \"c:\\projects\\eqemu\\strawberry-perl-5.26.2.1-64bit-portable.zip\")\ncd c:\\projects\\eqemu\n7z x c:/projects/eqemu/strawberry-perl-5.26.2.1-64bit-portable.zip -oc:/projects/eqemu/strawberry-perl-portable -y\n(Get-Content C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE/config.h).replace('#define PERL_STATIC_INLINE static __inline__', '#define PERL_STATIC_INLINE static __inline') | Set-Content C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE/config.h\nvcpkg install boost-geometry:x64-windows boost-dynamic-bitset:x64-windows luajit:x64-windows libsodium:x64-windows libmysql:x64-windows openssl:x64-windows zlib:x64-windows \nmkdir build\ncd build\ncmake -G \"Visual Studio 15 2017 Win64\" -DEQEMU_BUILD_TESTS=ON -DEQEMU_BUILD_LOGIN=ON -EQEMU_ENABLE_BOTS=OFF -DPERL_EXECUTABLE=\"C:/projects/eqemu/strawberry-perl-portable/perl/bin/perl.exe\" -DPERL_INCLUDE_PATH=\"C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE\" -DPERL_LIBRARY=\"C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE/libperl526.a\" -DCMAKE_TOOLCHAIN_FILE=\"c:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake\" .."
|
||||
build:
|
||||
project: C:\projects\eqemu\build\EQEmu.sln
|
||||
parallel: true
|
||||
verbosity: minimal
|
||||
after_build:
|
||||
- cmd: >-
|
||||
7z a build_x64-no-bots.zip C:\projects\eqemu\build\bin\RelWithDebInfo\*.exe C:\projects\eqemu\build\bin\RelWithDebInfo\*.dll C:\projects\eqemu\build\bin\RelWithDebInfo\*.pdb C:\projects\eqemu\build\libs\zlibng\RelWithDebInfo\*.dll
|
||||
|
||||
appveyor PushArtifact build_x64-no-bots.zip
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
############################################
|
||||
#
|
||||
# New changelog can be found here
|
||||
# https://docs.eqemu.io/server/changelog/server
|
||||
# https://eqemu.gitbook.io/changelog/
|
||||
#
|
||||
############################################
|
||||
# Deprecated
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 3.12)
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 3.2)
|
||||
|
||||
SET(export_sources
|
||||
main.cpp
|
||||
|
||||
@@ -25,15 +25,11 @@
|
||||
#include "../../common/platform.h"
|
||||
#include "../../common/crash.h"
|
||||
#include "../../common/rulesys.h"
|
||||
#include "../../common/strings.h"
|
||||
#include "../../common/string_util.h"
|
||||
#include "../../common/content/world_content_service.h"
|
||||
#include "../../common/zone_store.h"
|
||||
#include "../../common/path_manager.h"
|
||||
|
||||
EQEmuLogSys LogSys;
|
||||
WorldContentService content_service;
|
||||
ZoneStore zone_store;
|
||||
PathManager path;
|
||||
|
||||
void ExportSpells(SharedDatabase *db);
|
||||
void ExportSkillCaps(SharedDatabase *db);
|
||||
@@ -46,8 +42,6 @@ int main(int argc, char **argv)
|
||||
LogSys.LoadLogSettingsDefaults();
|
||||
set_exception_handler();
|
||||
|
||||
path.LoadPaths();
|
||||
|
||||
LogInfo("Client Files Export Utility");
|
||||
if (!EQEmuConfig::LoadConfig()) {
|
||||
LogError("Unable to load configuration file");
|
||||
@@ -89,10 +83,8 @@ int main(int argc, char **argv)
|
||||
content_db.SetMysql(database.getMySQL());
|
||||
}
|
||||
|
||||
LogSys.SetDatabase(&database)
|
||||
->SetLogPath(path.GetLogPath())
|
||||
->LoadLogDatabaseSettings()
|
||||
->StartFileLogs();
|
||||
database.LoadLogSettings(LogSys.log_settings);
|
||||
LogSys.StartFileLogs();
|
||||
|
||||
std::string arg_1;
|
||||
|
||||
@@ -131,8 +123,7 @@ void ExportSpells(SharedDatabase *db)
|
||||
{
|
||||
LogInfo("Exporting Spells");
|
||||
|
||||
std::string file = fmt::format("{}/export/spells_us.txt", path.GetServerPath());
|
||||
FILE *f = fopen(file.c_str(), "w");
|
||||
FILE *f = fopen("export/spells_us.txt", "w");
|
||||
if (!f) {
|
||||
LogError("Unable to open export/spells_us.txt to write, skipping.");
|
||||
return;
|
||||
@@ -214,8 +205,7 @@ void ExportSkillCaps(SharedDatabase *db)
|
||||
{
|
||||
LogInfo("Exporting Skill Caps");
|
||||
|
||||
std::string file = fmt::format("{}/export/SkillCaps.txt", path.GetServerPath());
|
||||
FILE *f = fopen(file.c_str(), "w");
|
||||
FILE *f = fopen("export/SkillCaps.txt", "w");
|
||||
if (!f) {
|
||||
LogError("Unable to open export/SkillCaps.txt to write, skipping.");
|
||||
return;
|
||||
@@ -245,8 +235,7 @@ void ExportBaseData(SharedDatabase *db)
|
||||
{
|
||||
LogInfo("Exporting Base Data");
|
||||
|
||||
std::string file = fmt::format("{}/export/BaseData.txt", path.GetServerPath());
|
||||
FILE *f = fopen(file.c_str(), "w");
|
||||
FILE *f = fopen("export/BaseData.txt", "w");
|
||||
if (!f) {
|
||||
LogError("Unable to open export/BaseData.txt to write, skipping.");
|
||||
return;
|
||||
@@ -279,8 +268,7 @@ void ExportDBStrings(SharedDatabase *db)
|
||||
{
|
||||
LogInfo("Exporting DB Strings");
|
||||
|
||||
std::string file = fmt::format("{}/export/dbstr_us.txt", path.GetServerPath());
|
||||
FILE *f = fopen(file.c_str(), "w");
|
||||
FILE *f = fopen("export/dbstr_us.txt", "w");
|
||||
if (!f) {
|
||||
LogError("Unable to open export/dbstr_us.txt to write, skipping.");
|
||||
return;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 3.12)
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 3.2)
|
||||
|
||||
SET(import_sources
|
||||
main.cpp
|
||||
|
||||
@@ -23,15 +23,11 @@
|
||||
#include "../../common/platform.h"
|
||||
#include "../../common/crash.h"
|
||||
#include "../../common/rulesys.h"
|
||||
#include "../../common/strings.h"
|
||||
#include "../../common/string_util.h"
|
||||
#include "../../common/content/world_content_service.h"
|
||||
#include "../../common/zone_store.h"
|
||||
#include "../../common/path_manager.h"
|
||||
|
||||
EQEmuLogSys LogSys;
|
||||
WorldContentService content_service;
|
||||
ZoneStore zone_store;
|
||||
PathManager path;
|
||||
|
||||
void ImportSpells(SharedDatabase *db);
|
||||
void ImportSkillCaps(SharedDatabase *db);
|
||||
@@ -43,8 +39,6 @@ int main(int argc, char **argv) {
|
||||
LogSys.LoadLogSettingsDefaults();
|
||||
set_exception_handler();
|
||||
|
||||
path.LoadPaths();
|
||||
|
||||
LogInfo("Client Files Import Utility");
|
||||
if(!EQEmuConfig::LoadConfig()) {
|
||||
LogError("Unable to load configuration file.");
|
||||
@@ -86,10 +80,8 @@ int main(int argc, char **argv) {
|
||||
content_db.SetMysql(database.getMySQL());
|
||||
}
|
||||
|
||||
LogSys.SetDatabase(&database)
|
||||
->SetLogPath(path.GetLogPath())
|
||||
->LoadLogDatabaseSettings()
|
||||
->StartFileLogs();
|
||||
database.LoadLogSettings(LogSys.log_settings);
|
||||
LogSys.StartFileLogs();
|
||||
|
||||
ImportSpells(&content_db);
|
||||
ImportSkillCaps(&content_db);
|
||||
@@ -132,10 +124,9 @@ bool IsStringField(int i) {
|
||||
|
||||
void ImportSpells(SharedDatabase *db) {
|
||||
LogInfo("Importing Spells");
|
||||
std::string file = fmt::format("{}/import/spells_us.txt", path.GetServerPath());
|
||||
FILE *f = fopen(file.c_str(), "r");
|
||||
FILE *f = fopen("import/spells_us.txt", "r");
|
||||
if(!f) {
|
||||
LogError("Unable to open {} to read, skipping.", file);
|
||||
LogError("Unable to open import/spells_us.txt to read, skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -154,8 +145,8 @@ void ImportSpells(SharedDatabase *db) {
|
||||
}
|
||||
}
|
||||
|
||||
std::string escaped = ::Strings::Escape(buffer);
|
||||
auto split = Strings::Split(escaped, '^');
|
||||
std::string escaped = ::EscapeString(buffer);
|
||||
auto split = SplitString(escaped, '^');
|
||||
int line_columns = (int)split.size();
|
||||
|
||||
std::string sql;
|
||||
@@ -222,10 +213,9 @@ void ImportSpells(SharedDatabase *db) {
|
||||
void ImportSkillCaps(SharedDatabase *db) {
|
||||
LogInfo("Importing Skill Caps");
|
||||
|
||||
std::string file = fmt::format("{}/import/SkillCaps.txt", path.GetServerPath());
|
||||
FILE *f = fopen(file.c_str(), "r");
|
||||
FILE *f = fopen("import/SkillCaps.txt", "r");
|
||||
if(!f) {
|
||||
LogError("Unable to open {} to read, skipping.", file);
|
||||
LogError("Unable to open import/SkillCaps.txt to read, skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -234,7 +224,7 @@ void ImportSkillCaps(SharedDatabase *db) {
|
||||
|
||||
char buffer[2048];
|
||||
while(fgets(buffer, 2048, f)) {
|
||||
auto split = Strings::Split(buffer, '^');
|
||||
auto split = SplitString(buffer, '^');
|
||||
|
||||
if(split.size() < 4) {
|
||||
continue;
|
||||
@@ -258,10 +248,9 @@ void ImportSkillCaps(SharedDatabase *db) {
|
||||
void ImportBaseData(SharedDatabase *db) {
|
||||
LogInfo("Importing Base Data");
|
||||
|
||||
std::string file = fmt::format("{}/import/BaseData.txt", path.GetServerPath());
|
||||
FILE *f = fopen(file.c_str(), "r");
|
||||
FILE *f = fopen("import/BaseData.txt", "r");
|
||||
if(!f) {
|
||||
LogError("Unable to open {} to read, skipping.", file);
|
||||
LogError("Unable to open import/BaseData.txt to read, skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -270,7 +259,7 @@ void ImportBaseData(SharedDatabase *db) {
|
||||
|
||||
char buffer[2048];
|
||||
while(fgets(buffer, 2048, f)) {
|
||||
auto split = Strings::Split(buffer, '^');
|
||||
auto split = SplitString(buffer, '^');
|
||||
|
||||
if(split.size() < 10) {
|
||||
continue;
|
||||
@@ -304,10 +293,9 @@ void ImportBaseData(SharedDatabase *db) {
|
||||
void ImportDBStrings(SharedDatabase *db) {
|
||||
LogInfo("Importing DB Strings");
|
||||
|
||||
std::string file = fmt::format("{}/import/dbstr_us.txt", path.GetServerPath());
|
||||
FILE *f = fopen(file.c_str(), "r");
|
||||
FILE *f = fopen("import/dbstr_us.txt", "r");
|
||||
if(!f) {
|
||||
LogError("Unable to open {} to read, skipping.", file);
|
||||
LogError("Unable to open import/dbstr_us.txt to read, skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -329,7 +317,7 @@ void ImportDBStrings(SharedDatabase *db) {
|
||||
}
|
||||
}
|
||||
|
||||
auto split = Strings::Split(buffer, '^');
|
||||
auto split = SplitString(buffer, '^');
|
||||
|
||||
if(split.size() < 2) {
|
||||
continue;
|
||||
@@ -343,7 +331,7 @@ void ImportDBStrings(SharedDatabase *db) {
|
||||
type = atoi(split[1].c_str());
|
||||
|
||||
if(split.size() >= 3) {
|
||||
value = ::Strings::Escape(split[2]);
|
||||
value = ::EscapeString(split[2]);
|
||||
}
|
||||
|
||||
sql = StringFormat("INSERT INTO db_str(id, type, value) VALUES(%u, %u, '%s')",
|
||||
|
||||
+709
-753
File diff suppressed because it is too large
Load Diff
@@ -1,147 +0,0 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2021 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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
/*
|
||||
* This is an additive lagged fibonacci generator as seen in The Art of Computer Programming, Vol. 2
|
||||
* This should roughly match the implementation that EQ's client uses and be compatible with our Random class
|
||||
*
|
||||
* EQ's rand looks like it was from an example implementation that as posted on pscode.com
|
||||
*
|
||||
* You might also want to consider defining BIASED_INT_DIST as well to more closely match EQ
|
||||
*/
|
||||
|
||||
namespace EQ {
|
||||
template<typename UIntType, size_t w, size_t j, size_t k>
|
||||
class additive_lagged_fibonacci_engine {
|
||||
static_assert(std::is_unsigned<UIntType>::value, "result_type must be an unsigned integral type");
|
||||
static_assert(0u < j && j < k, "0 < j < k");
|
||||
static_assert(0u < w && w <= std::numeric_limits<UIntType>::digits,
|
||||
"template argument substituting w out of bounds");
|
||||
|
||||
public:
|
||||
using result_type = UIntType;
|
||||
static constexpr size_t word_size = w;
|
||||
static constexpr size_t short_lag = j;
|
||||
static constexpr size_t long_lag = k;
|
||||
static constexpr result_type default_seed = 19780503u; // default for subtract_with_carry_engine
|
||||
|
||||
additive_lagged_fibonacci_engine() : additive_lagged_fibonacci_engine(default_seed) {}
|
||||
|
||||
explicit additive_lagged_fibonacci_engine(result_type sd) { seed(sd); }
|
||||
|
||||
void seed(result_type seed = default_seed)
|
||||
{
|
||||
state1 = long_lag - long_lag;
|
||||
state2 = long_lag - short_lag;
|
||||
state[0] = static_cast<int>(seed) & ((1u << word_size) - 1);
|
||||
state[1] = 1;
|
||||
for (int i = 2; i < long_lag; ++i)
|
||||
state[i] = (state[i - 1] + state[i - 2]) & ((1u << word_size) - 1);
|
||||
return;
|
||||
}
|
||||
// TODO: seed via seed_seq
|
||||
|
||||
static constexpr result_type min() { return 0; }
|
||||
static constexpr result_type max() { return ((1u << word_size) - 1) >> 6; }
|
||||
|
||||
void discard(unsigned long long z) {
|
||||
for (; z != 0ULL; --z)
|
||||
(*this)();
|
||||
}
|
||||
|
||||
result_type operator()() {
|
||||
result_type rand = (state[state1] + state[state2]) & ((1u << word_size) - 1);
|
||||
state[state1] = rand;
|
||||
if (++state1 == long_lag)
|
||||
state1 = 0;
|
||||
if (++state2 == long_lag)
|
||||
state2 = 0;
|
||||
|
||||
return rand >> 6;
|
||||
}
|
||||
|
||||
private:
|
||||
result_type state1;
|
||||
result_type state2;
|
||||
result_type state[long_lag];
|
||||
|
||||
public:
|
||||
template<typename UInt, size_t W, size_t J, size_t K>
|
||||
friend bool operator==(const additive_lagged_fibonacci_engine<UInt, W, J, K> &x,
|
||||
const additive_lagged_fibonacci_engine<UInt, W, J, K> &y)
|
||||
{
|
||||
return std::equal(x.state, x.state + long_lag, y.state) && x.state1 == y.state1 &&
|
||||
x.state2 == y.state2;
|
||||
}
|
||||
|
||||
template<typename UInt, size_t W, size_t J, size_t K>
|
||||
friend bool operator!=(const additive_lagged_fibonacci_engine<UInt, W, J, K> &x,
|
||||
const additive_lagged_fibonacci_engine<UInt, W, J, K> &y)
|
||||
{ return !(x == y); }
|
||||
|
||||
template<typename UInt, size_t W, size_t J, size_t K, typename CharT, typename Traits>
|
||||
friend std::basic_ostream<CharT, Traits> &
|
||||
operator<<(std::basic_istream<CharT, Traits> &os, additive_lagged_fibonacci_engine<UInt, W, J, K> &x)
|
||||
{
|
||||
using ios_base = typename std::basic_istream<CharT, Traits>::ios_base;
|
||||
|
||||
const typename ios_base::fmtflags flags = os.flags();
|
||||
const CharT fill = os.fill();
|
||||
const CharT space = os.widen(' ');
|
||||
os.flags(ios_base::dec | ios_base::fixed | ios_base::left);
|
||||
os.fill(space);
|
||||
|
||||
for (size_t i = 0; i < long_lag; ++i)
|
||||
os << x.state[i] << space;
|
||||
os << x.state1 << space << x.state2;
|
||||
|
||||
os.flags(flags);
|
||||
os.fill(fill);
|
||||
return os;
|
||||
}
|
||||
|
||||
template<typename UInt, size_t W, size_t J, size_t K, typename CharT, typename Traits>
|
||||
friend std::basic_istream<CharT, Traits> &
|
||||
operator>>(std::basic_istream<CharT, Traits> &is, additive_lagged_fibonacci_engine<UInt, W, J, K> &x)
|
||||
{
|
||||
using ios_base = typename std::basic_istream<CharT, Traits>::ios_base;
|
||||
|
||||
const typename ios_base::fmtflags flags = is.flags();
|
||||
is.flags(ios_base::dec | ios_base::skipws);
|
||||
|
||||
for (size_t i = 0; i < long_lag; ++i)
|
||||
is >> x.state[i];
|
||||
is >> x.state1;
|
||||
is >> x.state2;
|
||||
|
||||
is.flags(flags);
|
||||
return is;
|
||||
}
|
||||
};
|
||||
|
||||
using EQRand = additive_lagged_fibonacci_engine<uint32_t, 30, 24, 55>;
|
||||
};
|
||||
|
||||
+190
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Boost Software License - Version 1.0 - August 17th, 2003
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person or organization
|
||||
* obtaining a copy of the software and accompanying documentation covered by
|
||||
* this license (the "Software") to use, reproduce, display, distribute,
|
||||
* execute, and transmit the Software, and to prepare derivative works of the
|
||||
* Software, and to permit third-parties to whom the Software is furnished to
|
||||
* do so, all subject to the following:
|
||||
*
|
||||
* The copyright notices in the Software and this entire statement, including
|
||||
* the above license grant, this restriction and the following disclaimer,
|
||||
* must be included in all copies of the Software, in whole or in part, and
|
||||
* all derivative works of the Software, unless such copies or derivative
|
||||
* works are solely in the form of machine-executable object code generated by
|
||||
* a source language processor.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
* FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// EQ::Any is a modified version of Boost::Any and as such retains the Boost licensing.
|
||||
|
||||
#ifndef EQEMU_COMMON_ANY_H
|
||||
#define EQEMU_COMMON_ANY_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <typeinfo>
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
class Any
|
||||
{
|
||||
public:
|
||||
Any()
|
||||
: content(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename ValueType>
|
||||
Any(const ValueType &value)
|
||||
: content(new Holder<ValueType>(value))
|
||||
{
|
||||
}
|
||||
|
||||
Any(const Any &other)
|
||||
: content(other.content ? other.content->clone() : 0)
|
||||
{
|
||||
}
|
||||
|
||||
~Any()
|
||||
{
|
||||
if(content)
|
||||
delete content;
|
||||
}
|
||||
|
||||
Any& swap(Any &rhs)
|
||||
{
|
||||
std::swap(content, rhs.content);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename ValueType>
|
||||
Any& operator=(const ValueType &rhs)
|
||||
{
|
||||
Any(rhs).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Any& operator=(Any rhs)
|
||||
{
|
||||
rhs.swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return !content;
|
||||
}
|
||||
|
||||
const std::type_info& type() const
|
||||
{
|
||||
return content ? content->type() : typeid(void);
|
||||
}
|
||||
|
||||
class Placeholder
|
||||
{
|
||||
public:
|
||||
virtual ~Placeholder()
|
||||
{
|
||||
}
|
||||
|
||||
virtual const std::type_info& type() const = 0;
|
||||
virtual Placeholder* clone() const = 0;
|
||||
};
|
||||
|
||||
|
||||
template<typename ValueType>
|
||||
class Holder : public Placeholder
|
||||
{
|
||||
public:
|
||||
Holder(const ValueType &value)
|
||||
: held(value)
|
||||
{
|
||||
}
|
||||
|
||||
virtual const std::type_info& type() const
|
||||
{
|
||||
return typeid(ValueType);
|
||||
}
|
||||
|
||||
virtual Placeholder* clone() const
|
||||
{
|
||||
return new Holder(held);
|
||||
}
|
||||
|
||||
ValueType held;
|
||||
|
||||
private:
|
||||
Holder& operator=(const Holder&);
|
||||
};
|
||||
|
||||
private:
|
||||
template<typename ValueType>
|
||||
friend ValueType* any_cast(Any*);
|
||||
|
||||
template<typename ValueType>
|
||||
friend ValueType* unsafe_any_cast(Any*);
|
||||
|
||||
Placeholder* content;
|
||||
};
|
||||
|
||||
class bad_any_cast : public std::bad_cast
|
||||
{
|
||||
public:
|
||||
virtual const char * what() const throw()
|
||||
{
|
||||
return "DBI::bad_any_cast: failed conversion using DBI::any_cast";
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ValueType>
|
||||
ValueType* any_cast(Any* operand)
|
||||
{
|
||||
return operand &&
|
||||
operand->type() == typeid(ValueType) ? &static_cast<Any::Holder<ValueType>*>(operand->content)->held : nullptr;
|
||||
}
|
||||
|
||||
template<typename ValueType>
|
||||
inline const ValueType* any_cast(const Any* operand)
|
||||
{
|
||||
return any_cast<ValueType>(const_cast<Any*>(operand));
|
||||
}
|
||||
|
||||
template<typename ValueType>
|
||||
ValueType any_cast(Any& operand)
|
||||
{
|
||||
typedef typename std::remove_reference<ValueType>::type nonref;
|
||||
nonref* result = any_cast<nonref>(&operand);
|
||||
if(!result)
|
||||
throw bad_any_cast();
|
||||
return *result;
|
||||
}
|
||||
|
||||
template<typename ValueType>
|
||||
inline ValueType any_cast(const Any& operand)
|
||||
{
|
||||
typedef typename std::remove_reference<ValueType>::type nonref;
|
||||
return any_cast<const nonref&>(const_cast<Any&>(operand));
|
||||
}
|
||||
|
||||
template<typename ValueType>
|
||||
inline ValueType* unsafe_any_cast(Any* operand)
|
||||
{
|
||||
return &static_cast<Any::Holder<ValueType>*>(operand->content)->held;
|
||||
}
|
||||
|
||||
template<typename ValueType>
|
||||
inline const ValueType* unsafe_any_cast(const Any* operand)
|
||||
{
|
||||
return unsafe_any_cast<ValueType>(const_cast<Any*>(operand));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -23,18 +23,18 @@
|
||||
|
||||
BasePacket::BasePacket(const unsigned char *buf, uint32 len)
|
||||
{
|
||||
pBuffer=nullptr;
|
||||
size=0;
|
||||
_wpos = 0;
|
||||
_rpos = 0;
|
||||
timestamp.tv_sec = 0;
|
||||
this->pBuffer=nullptr;
|
||||
this->size=0;
|
||||
this->_wpos = 0;
|
||||
this->_rpos = 0;
|
||||
this->timestamp.tv_sec = 0;
|
||||
if (len>0) {
|
||||
size=len;
|
||||
this->size=len;
|
||||
pBuffer= new unsigned char[len];
|
||||
if (buf) {
|
||||
memcpy(pBuffer,buf,len);
|
||||
memcpy(this->pBuffer,buf,len);
|
||||
} else {
|
||||
memset(pBuffer,0,len);
|
||||
memset(this->pBuffer,0,len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
-10
@@ -27,17 +27,16 @@ typedef enum {
|
||||
BT_Extraplanar = 6,
|
||||
BT_Magical = 7, //this name might be a bit off,
|
||||
BT_SummonedUndead = 8,
|
||||
BT_RaidGiant = 9, //Velious era Raid Giant
|
||||
BT_RaidColdain = 10, //Velious era Raid Coldain
|
||||
BT_RaidGiant = 9,
|
||||
// ...
|
||||
BT_NoTarget = 11, //no name, can't target this bodytype
|
||||
BT_Vampire = 12,
|
||||
BT_Atenha_Ra = 13,
|
||||
BT_Greater_Akheva = 14,
|
||||
BT_Khati_Sha = 15,
|
||||
BT_Seru = 16,
|
||||
BT_Grieg_Veneficus = 17,
|
||||
BT_Seru = 16, //not confirmed....
|
||||
BT_Draz_Nurakk = 18,
|
||||
BT_Zek = 19, //"creatures from the Plane of War."
|
||||
BT_Zek = 19,
|
||||
BT_Luggald = 20,
|
||||
BT_Animal = 21,
|
||||
BT_Insect = 22,
|
||||
@@ -47,18 +46,17 @@ typedef enum {
|
||||
BT_Dragon = 26,
|
||||
BT_Summoned2 = 27,
|
||||
BT_Summoned3 = 28,
|
||||
BT_Dragon2 = 29, //database data indicates this is a dragon type (kunark and DoN?)
|
||||
//29
|
||||
BT_VeliousDragon = 30, //might not be a tight set
|
||||
BT_Familiar = 31,
|
||||
// ...
|
||||
BT_Dragon3 = 32,
|
||||
BT_Boxes = 33,
|
||||
BT_Muramite = 34, //tribal dudes
|
||||
// ...
|
||||
BT_NoTarget2 = 60,
|
||||
// ...
|
||||
BT_SwarmPet = 63, //Looks like weapon proc related temp pets and few misc pets, should not be used for checking swarm pets in general.
|
||||
BT_MonsterSummon = 64,
|
||||
// 65, trap or effect related?
|
||||
BT_SwarmPet = 63, //is this valid, or made up?
|
||||
// ...
|
||||
BT_InvisMan = 66, //no name, seen on 'InvisMan', can be /targeted
|
||||
BT_Special = 67
|
||||
} bodyType;
|
||||
|
||||
+5
-5
@@ -380,12 +380,12 @@ const char *GetClassIDName(uint8 class_id, uint8 level)
|
||||
return "Merchant";
|
||||
case DISCORD_MERCHANT:
|
||||
return "Discord Merchant";
|
||||
case ADVENTURE_RECRUITER:
|
||||
case ADVENTURERECRUITER:
|
||||
return "Adventure Recruiter";
|
||||
case ADVENTURE_MERCHANT:
|
||||
case ADVENTUREMERCHANT:
|
||||
return "Adventure Merchant";
|
||||
case LDON_TREASURE:
|
||||
return "LDoN Treasure";
|
||||
case CORPSE_CLASS:
|
||||
return "Corpse Class";
|
||||
case TRIBUTE_MASTER:
|
||||
return "Tribute Master";
|
||||
case GUILD_TRIBUTE_MASTER:
|
||||
@@ -400,7 +400,7 @@ const char *GetClassIDName(uint8 class_id, uint8 level)
|
||||
return "Fellowship Master";
|
||||
case ALT_CURRENCY_MERCHANT:
|
||||
return "Alternate Currency Merchant";
|
||||
case MERCENARY_MASTER:
|
||||
case MERCERNARY_MASTER:
|
||||
return "Mercenary Liaison";
|
||||
default:
|
||||
return "Unknown";
|
||||
|
||||
+5
-5
@@ -20,7 +20,6 @@
|
||||
|
||||
#include "../common/types.h"
|
||||
|
||||
#define NO_CLASS 0
|
||||
#define WARRIOR 1
|
||||
#define CLERIC 2
|
||||
#define PALADIN 3
|
||||
@@ -56,9 +55,10 @@
|
||||
#define BANKER 40
|
||||
#define MERCHANT 41
|
||||
#define DISCORD_MERCHANT 59
|
||||
#define ADVENTURE_RECRUITER 60
|
||||
#define ADVENTURE_MERCHANT 61
|
||||
#define LDON_TREASURE 62 // objects you can use /open on first seen in LDONs, seen on Danvi's Corpse in Akheva
|
||||
#define ADVENTURERECRUITER 60
|
||||
#define ADVENTUREMERCHANT 61
|
||||
#define LDON_TREASURE 62 // objects you can use /open on first seen in LDONs
|
||||
#define CORPSE_CLASS 62 // only seen on Danvi's Corpse in Akheva so far..
|
||||
#define TRIBUTE_MASTER 63
|
||||
#define GUILD_TRIBUTE_MASTER 64 // not sure
|
||||
#define GUILD_BANKER 66
|
||||
@@ -66,7 +66,7 @@
|
||||
#define DARK_REIGN_MERCHANT 68
|
||||
#define FELLOWSHIP_MASTER 69
|
||||
#define ALT_CURRENCY_MERCHANT 70
|
||||
#define MERCENARY_MASTER 71
|
||||
#define MERCERNARY_MASTER 71
|
||||
|
||||
|
||||
// player class values
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include "../database.h"
|
||||
#include "../rulesys.h"
|
||||
#include "../eqemu_logsys.h"
|
||||
#include "../loottable.h"
|
||||
#include "../repositories/content_flags_repository.h"
|
||||
|
||||
|
||||
@@ -36,12 +35,8 @@ int WorldContentService::GetCurrentExpansion() const
|
||||
return current_expansion;
|
||||
}
|
||||
|
||||
WorldContentService *WorldContentService::SetExpansionContext()
|
||||
void WorldContentService::SetExpansionContext()
|
||||
{
|
||||
// do a rule manager reload until where we store expansion is changed to somewhere else
|
||||
RuleManager::Instance()->LoadRules(GetDatabase(), "default", true);
|
||||
|
||||
// pull expansion from rules
|
||||
int expansion = RuleI(Expansion, CurrentExpansion);
|
||||
if (expansion >= Expansion::Classic && expansion <= Expansion::MaxId) {
|
||||
content_service.SetCurrentExpansion(expansion);
|
||||
@@ -52,8 +47,6 @@ WorldContentService *WorldContentService::SetExpansionContext()
|
||||
GetCurrentExpansion(),
|
||||
GetCurrentExpansionName()
|
||||
);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
std::string WorldContentService::GetCurrentExpansionName()
|
||||
@@ -80,47 +73,15 @@ void WorldContentService::SetCurrentExpansion(int current_expansion)
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
const std::vector<ContentFlagsRepository::ContentFlags> &WorldContentService::GetContentFlags() const
|
||||
const std::vector<std::string> &WorldContentService::GetContentFlags() const
|
||||
{
|
||||
return content_flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
std::vector<std::string> WorldContentService::GetContentFlagsEnabled()
|
||||
{
|
||||
std::vector<std::string> enabled_flags;
|
||||
|
||||
for (auto &f: GetContentFlags()) {
|
||||
if (f.enabled) {
|
||||
enabled_flags.emplace_back(f.flag_name);
|
||||
}
|
||||
}
|
||||
|
||||
return enabled_flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
std::vector<std::string> WorldContentService::GetContentFlagsDisabled()
|
||||
{
|
||||
std::vector<std::string> disabled_flags;
|
||||
|
||||
for (auto &f: GetContentFlags()) {
|
||||
if (!f.enabled) {
|
||||
disabled_flags.emplace_back(f.flag_name);
|
||||
}
|
||||
}
|
||||
|
||||
return disabled_flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param content_flags
|
||||
*/
|
||||
void WorldContentService::SetContentFlags(std::vector<ContentFlagsRepository::ContentFlags> content_flags)
|
||||
void WorldContentService::SetContentFlags(std::vector<std::string> content_flags)
|
||||
{
|
||||
WorldContentService::content_flags = content_flags;
|
||||
}
|
||||
@@ -129,10 +90,10 @@ void WorldContentService::SetContentFlags(std::vector<ContentFlagsRepository::Co
|
||||
* @param content_flag
|
||||
* @return
|
||||
*/
|
||||
bool WorldContentService::IsContentFlagEnabled(const std::string &content_flag)
|
||||
bool WorldContentService::IsContentFlagEnabled(const std::string& content_flag)
|
||||
{
|
||||
for (auto &f: GetContentFlags()) {
|
||||
if (f.flag_name == content_flag && f.enabled == true) {
|
||||
for (auto &flag : GetContentFlags()) {
|
||||
if (flag == content_flag) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -140,102 +101,20 @@ bool WorldContentService::IsContentFlagEnabled(const std::string &content_flag)
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param content_flag
|
||||
* @return
|
||||
*/
|
||||
bool WorldContentService::IsContentFlagDisabled(const std::string &content_flag)
|
||||
void WorldContentService::ReloadContentFlags(Database &db)
|
||||
{
|
||||
for (auto &f: GetContentFlags()) {
|
||||
if (f.flag_name == content_flag && f.enabled == false) {
|
||||
return true;
|
||||
}
|
||||
std::vector<std::string> set_content_flags;
|
||||
auto content_flags = ContentFlagsRepository::GetWhere(db, "enabled = 1");
|
||||
|
||||
set_content_flags.reserve(content_flags.size());
|
||||
for (auto &flags: content_flags) {
|
||||
set_content_flags.push_back(flags.flag_name);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WorldContentService::DoesPassContentFiltering(const ContentFlags &f)
|
||||
{
|
||||
// if we're not set to (-1 All) then fail when we aren't within minimum expansion
|
||||
if (f.min_expansion > Expansion::EXPANSION_ALL && current_expansion < f.min_expansion && current_expansion != -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// if we're not set to (-1 All) then fail when we aren't within max expansion
|
||||
if (f.max_expansion > Expansion::EXPANSION_ALL && current_expansion > f.max_expansion && current_expansion != -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// if we don't have any enabled flag in enabled flags, we fail
|
||||
for (const auto& flag: Strings::Split(f.content_flags)) {
|
||||
if (!Strings::Contains(GetContentFlagsEnabled(), flag)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// if we don't have any disabled flag in disabled flags, we fail
|
||||
for (const auto& flag: Strings::Split(f.content_flags_disabled)) {
|
||||
if (!Strings::Contains(GetContentFlagsDisabled(), flag)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void WorldContentService::ReloadContentFlags()
|
||||
{
|
||||
std::vector<ContentFlagsRepository::ContentFlags> set_content_flags;
|
||||
auto flags = ContentFlagsRepository::All(*GetDatabase());
|
||||
|
||||
set_content_flags.reserve(flags.size());
|
||||
for (auto &f: flags) {
|
||||
set_content_flags.push_back(f);
|
||||
|
||||
LogInfo(
|
||||
"Loaded content flag [{}] [{}]",
|
||||
f.flag_name,
|
||||
(f.enabled ? "Enabled" : "Disabled")
|
||||
);
|
||||
}
|
||||
LogInfo(
|
||||
"Enabled content flags [{}]",
|
||||
implode(", ", set_content_flags)
|
||||
);
|
||||
|
||||
SetContentFlags(set_content_flags);
|
||||
}
|
||||
|
||||
Database *WorldContentService::GetDatabase() const
|
||||
{
|
||||
return m_database;
|
||||
}
|
||||
|
||||
WorldContentService *WorldContentService::SetDatabase(Database *database)
|
||||
{
|
||||
WorldContentService::m_database = database;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
void WorldContentService::SetContentFlag(const std::string &content_flag_name, bool enabled)
|
||||
{
|
||||
auto flags = ContentFlagsRepository::GetWhere(
|
||||
*GetDatabase(),
|
||||
fmt::format("flag_name = '{}'", content_flag_name)
|
||||
);
|
||||
|
||||
auto f = ContentFlagsRepository::NewEntity();
|
||||
if (!flags.empty()) {
|
||||
f = flags.front();
|
||||
}
|
||||
|
||||
f.enabled = enabled ? 1 : 0;
|
||||
f.flag_name = content_flag_name;
|
||||
|
||||
if (!flags.empty()) {
|
||||
ContentFlagsRepository::UpdateOne(*GetDatabase(), f);
|
||||
}
|
||||
else {
|
||||
ContentFlagsRepository::InsertOne(*GetDatabase(), f);
|
||||
}
|
||||
|
||||
ReloadContentFlags();
|
||||
}
|
||||
|
||||
@@ -23,8 +23,6 @@
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "../loottable.h"
|
||||
#include "../repositories/content_flags_repository.h"
|
||||
|
||||
class Database;
|
||||
|
||||
@@ -54,7 +52,7 @@ namespace Expansion {
|
||||
VeilOfAlaris,
|
||||
RainOfFear,
|
||||
CallOfTheForsaken,
|
||||
TheDarkenedSea,
|
||||
TheDarkendSea,
|
||||
TheBrokenMirror,
|
||||
EmpiresOfKunark,
|
||||
RingOfScale,
|
||||
@@ -127,7 +125,7 @@ public:
|
||||
bool IsVeilOfAlarisEnabled() { return GetCurrentExpansion() >= Expansion::ExpansionNumber::VeilOfAlaris || GetCurrentExpansion() == Expansion::EXPANSION_ALL; }
|
||||
bool IsRainOfFearEnabled() { return GetCurrentExpansion() >= Expansion::ExpansionNumber::RainOfFear || GetCurrentExpansion() == Expansion::EXPANSION_ALL; }
|
||||
bool IsCallOfTheForsakenEnabled() { return GetCurrentExpansion() >= Expansion::ExpansionNumber::CallOfTheForsaken || GetCurrentExpansion() == Expansion::EXPANSION_ALL; }
|
||||
bool IsTheDarkenedSeaEnabled() { return GetCurrentExpansion() >= Expansion::ExpansionNumber::TheDarkenedSea || GetCurrentExpansion() == Expansion::EXPANSION_ALL; }
|
||||
bool IsTheDarkendSeaEnabled() { return GetCurrentExpansion() >= Expansion::ExpansionNumber::TheDarkendSea || GetCurrentExpansion() == Expansion::EXPANSION_ALL; }
|
||||
bool IsTheBrokenMirrorEnabled() { return GetCurrentExpansion() >= Expansion::ExpansionNumber::TheBrokenMirror || GetCurrentExpansion() == Expansion::EXPANSION_ALL; }
|
||||
bool IsEmpiresOfKunarkEnabled() { return GetCurrentExpansion() >= Expansion::ExpansionNumber::EmpiresOfKunark || GetCurrentExpansion() == Expansion::EXPANSION_ALL; }
|
||||
bool IsRingOfScaleEnabled() { return GetCurrentExpansion() >= Expansion::ExpansionNumber::RingOfScale || GetCurrentExpansion() == Expansion::EXPANSION_ALL; }
|
||||
@@ -155,35 +153,22 @@ public:
|
||||
bool IsCurrentExpansionVeilOfAlaris() { return current_expansion == Expansion::ExpansionNumber::VeilOfAlaris; }
|
||||
bool IsCurrentExpansionRainOfFear() { return current_expansion == Expansion::ExpansionNumber::RainOfFear; }
|
||||
bool IsCurrentExpansionCallOfTheForsaken() { return current_expansion == Expansion::ExpansionNumber::CallOfTheForsaken; }
|
||||
bool IsCurrentExpansionTheDarkenedSea() { return current_expansion == Expansion::ExpansionNumber::TheDarkenedSea; }
|
||||
bool IsCurrentExpansionTheDarkendSea() { return current_expansion == Expansion::ExpansionNumber::TheDarkendSea; }
|
||||
bool IsCurrentExpansionTheBrokenMirror() { return current_expansion == Expansion::ExpansionNumber::TheBrokenMirror; }
|
||||
bool IsCurrentExpansionEmpiresOfKunark() { return current_expansion == Expansion::ExpansionNumber::EmpiresOfKunark; }
|
||||
bool IsCurrentExpansionRingOfScale() { return current_expansion == Expansion::ExpansionNumber::RingOfScale; }
|
||||
bool IsCurrentExpansionTheBurningLands() { return current_expansion == Expansion::ExpansionNumber::TheBurningLands; }
|
||||
bool IsCurrentExpansionTormentOfVelious() { return current_expansion == Expansion::ExpansionNumber::TormentOfVelious; }
|
||||
|
||||
const std::vector<ContentFlagsRepository::ContentFlags> &GetContentFlags() const;
|
||||
std::vector<std::string> GetContentFlagsEnabled();
|
||||
std::vector<std::string> GetContentFlagsDisabled();
|
||||
bool IsContentFlagEnabled(const std::string& content_flag);
|
||||
bool IsContentFlagDisabled(const std::string& content_flag);
|
||||
void SetContentFlags(std::vector<ContentFlagsRepository::ContentFlags> content_flags);
|
||||
void ReloadContentFlags();
|
||||
WorldContentService * SetExpansionContext();
|
||||
|
||||
bool DoesPassContentFiltering(const ContentFlags& f);
|
||||
|
||||
WorldContentService * SetDatabase(Database *database);
|
||||
Database *GetDatabase() const;
|
||||
|
||||
void SetContentFlag(const std::string &content_flag_name, bool enabled);
|
||||
|
||||
private:
|
||||
int current_expansion{};
|
||||
std::vector<ContentFlagsRepository::ContentFlags> content_flags;
|
||||
|
||||
// reference to database
|
||||
Database *m_database;
|
||||
std::vector<std::string> content_flags;
|
||||
public:
|
||||
const std::vector<std::string> &GetContentFlags() const;
|
||||
bool IsContentFlagEnabled(const std::string& content_flag);
|
||||
void SetContentFlags(std::vector<std::string> content_flags);
|
||||
void ReloadContentFlags(Database &db);
|
||||
void SetExpansionContext();
|
||||
};
|
||||
|
||||
extern WorldContentService content_service;
|
||||
|
||||
+4
-123
@@ -1,97 +1,6 @@
|
||||
#include "global_define.h"
|
||||
#include "eqemu_logsys.h"
|
||||
#include "crash.h"
|
||||
#include "strings.h"
|
||||
#include "process/process.h"
|
||||
#include "http/httplib.h"
|
||||
#include "http/uri.h"
|
||||
#include "json/json.h"
|
||||
#include "version.h"
|
||||
#include "eqemu_config.h"
|
||||
#include "serverinfo.h"
|
||||
#include "rulesys.h"
|
||||
#include "platform.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#if WINDOWS
|
||||
#define popen _popen
|
||||
#endif
|
||||
|
||||
void SendCrashReport(const std::string &crash_report)
|
||||
{
|
||||
// can configure multiple endpoints if need be
|
||||
std::vector<std::string> endpoints = {
|
||||
"http://spire.akkadius.com/api/v1/server-crash-report",
|
||||
// "http://localhost:3010/api/v1/server-crash-report", // development
|
||||
};
|
||||
|
||||
auto config = EQEmuConfig::get();
|
||||
for (auto &e: endpoints) {
|
||||
uri u(e);
|
||||
|
||||
std::string base_url = fmt::format("{}://{}", u.get_scheme(), u.get_host());
|
||||
if (u.get_port()) {
|
||||
base_url += fmt::format(":{}", u.get_port());
|
||||
}
|
||||
|
||||
// client
|
||||
httplib::Client r(base_url);
|
||||
r.set_connection_timeout(1, 0);
|
||||
r.set_read_timeout(1, 0);
|
||||
r.set_write_timeout(1, 0);
|
||||
httplib::Headers headers = {
|
||||
{"Content-Type", "application/json"}
|
||||
};
|
||||
|
||||
// os info
|
||||
auto os = EQ::GetOS();
|
||||
auto cpus = EQ::GetCPUs();
|
||||
auto process_id = EQ::GetPID();
|
||||
auto rss = EQ::GetRSS() / 1048576.0;
|
||||
auto uptime = static_cast<uint32>(EQ::GetUptime());
|
||||
|
||||
// payload
|
||||
Json::Value p;
|
||||
p["platform_name"] = GetPlatformName();
|
||||
p["crash_report"] = crash_report;
|
||||
p["server_version"] = CURRENT_VERSION;
|
||||
p["compile_date"] = COMPILE_DATE;
|
||||
p["compile_time"] = COMPILE_TIME;
|
||||
p["server_name"] = config->LongName;
|
||||
p["server_short_name"] = config->ShortName;
|
||||
p["uptime"] = uptime;
|
||||
p["os_machine"] = os.machine;
|
||||
p["os_release"] = os.release;
|
||||
p["os_version"] = os.version;
|
||||
p["os_sysname"] = os.sysname;
|
||||
p["process_id"] = process_id;
|
||||
p["rss_memory"] = rss;
|
||||
p["cpus"] = cpus.size();
|
||||
p["origination_info"] = "";
|
||||
|
||||
if (!LogSys.origination_info.zone_short_name.empty()) {
|
||||
p["origination_info"] = fmt::format(
|
||||
"{} ({}) instance_id [{}]",
|
||||
LogSys.origination_info.zone_short_name,
|
||||
LogSys.origination_info.zone_long_name,
|
||||
LogSys.origination_info.instance_id
|
||||
);
|
||||
}
|
||||
|
||||
std::stringstream payload;
|
||||
payload << p;
|
||||
|
||||
if (auto res = r.Post(e, payload.str(), "application/json")) {
|
||||
if (res->status == 200) {
|
||||
LogInfo("Sent crash report");
|
||||
}
|
||||
else {
|
||||
LogError("Failed to send crash report to [{}]", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(_WINDOWS) && defined(CRASH_LOGGING)
|
||||
#include "StackWalker.h"
|
||||
@@ -116,11 +25,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
if (RuleB(Analytics, CrashReporting)) {
|
||||
std::string crash_report = buffer;
|
||||
SendCrashReport(crash_report);
|
||||
}
|
||||
|
||||
Log(Logs::General, Logs::Crash, buffer);
|
||||
StackWalker::OnOutput(szText);
|
||||
}
|
||||
@@ -221,27 +125,9 @@ void set_exception_handler() {
|
||||
|
||||
void print_trace()
|
||||
{
|
||||
bool does_gdb_exist = Strings::Contains(Process::execute("gdb -v"), "GNU");
|
||||
if (!does_gdb_exist) {
|
||||
LogCrash(
|
||||
"[Error] GDB is not installed, if you want crash dumps on Linux to work properly you will need GDB installed"
|
||||
);
|
||||
std::exit(1);
|
||||
}
|
||||
auto uid = geteuid();
|
||||
|
||||
auto uid = geteuid();
|
||||
std::string temp_output_file = fmt::format("/tmp/dump-output-{}", Strings::Random(10));
|
||||
|
||||
// check for passwordless sudo if not root
|
||||
if (uid != 0) {
|
||||
bool sudo_password_required = Strings::Contains(Process::execute("sudo -n true"), "a password is required");
|
||||
if (sudo_password_required) {
|
||||
LogCrash(
|
||||
"[Error] Current user does not have passwordless sudo installed. It is required to automatically process crash dumps with GDB as non-root."
|
||||
);
|
||||
std::exit(1);
|
||||
}
|
||||
}
|
||||
std::string temp_output_file = "/tmp/dump-output";
|
||||
|
||||
char pid_buf[30];
|
||||
sprintf(pid_buf, "%d", getpid());
|
||||
@@ -250,6 +136,7 @@ void print_trace()
|
||||
int child_pid = fork();
|
||||
if (!child_pid) {
|
||||
int fd = open(temp_output_file.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
|
||||
|
||||
dup2(fd, 1); // redirect output to stderr
|
||||
fprintf(stdout, "stack trace for %s pid=%s\n", name_buf, pid_buf);
|
||||
if (uid == 0) {
|
||||
@@ -264,22 +151,16 @@ void print_trace()
|
||||
abort(); /* If gdb failed to start */
|
||||
}
|
||||
else {
|
||||
waitpid(child_pid, nullptr, 0);
|
||||
waitpid(child_pid, NULL, 0);
|
||||
}
|
||||
|
||||
std::ifstream input(temp_output_file);
|
||||
std::string crash_report;
|
||||
for (std::string line; getline(input, line);) {
|
||||
LogCrash("{}", line);
|
||||
crash_report += fmt::format("{}\n", line);
|
||||
}
|
||||
|
||||
std::remove(temp_output_file.c_str());
|
||||
|
||||
if (RuleB(Analytics, CrashReporting)) {
|
||||
SendCrashReport(crash_report);
|
||||
}
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
+449
-379
File diff suppressed because it is too large
Load Diff
+35
-35
@@ -78,7 +78,6 @@ class PTimerList;
|
||||
|
||||
#define SQL(...) #__VA_ARGS__
|
||||
|
||||
class LogSettings;
|
||||
class Database : public DBcore {
|
||||
public:
|
||||
Database();
|
||||
@@ -88,6 +87,7 @@ public:
|
||||
|
||||
/* Character Creation */
|
||||
|
||||
bool AddToNameFilter(const char *name);
|
||||
bool CreateCharacter(
|
||||
uint32 account_id,
|
||||
char *name,
|
||||
@@ -113,25 +113,25 @@ public:
|
||||
bool SetMQDetectionFlag(const char *accountname, const char *charactername, const std::string &hacked, const char *zone);
|
||||
bool UpdateName(const char *oldname, const char *newname);
|
||||
bool CopyCharacter(
|
||||
const std::string& source_character_name,
|
||||
const std::string& destination_character_name,
|
||||
const std::string& destination_account_name
|
||||
std::string source_character_name,
|
||||
std::string destination_character_name,
|
||||
std::string destination_account_name
|
||||
);
|
||||
|
||||
/* General Information Queries */
|
||||
|
||||
bool AddBannedIP(std::string banned_ip, std::string notes); //Add IP address to the banned_ips table.
|
||||
bool AddToNameFilter(std::string name);
|
||||
bool CheckBannedIPs(std::string login_ip); //Check incoming connection against banned IP table.
|
||||
bool CheckGMIPs(std::string login_ip, uint32 account_id);
|
||||
bool CheckNameFilter(std::string name, bool surname = false);
|
||||
bool CheckUsedName(std::string name);
|
||||
bool AddBannedIP(char* bannedIP, const char* notes); //Add IP address to the banned_ips table.
|
||||
bool AddGMIP(char* ip_address, char* name);
|
||||
bool CheckBannedIPs(const char* loginIP); //Check incoming connection against banned IP table.
|
||||
bool CheckGMIPs(const char* loginIP, uint32 account_id);
|
||||
bool CheckNameFilter(const char* name, bool surname = false);
|
||||
bool CheckUsedName(const char* name);
|
||||
|
||||
uint32 GetAccountIDByChar(const char* charname, uint32* oCharID = 0);
|
||||
uint32 GetAccountIDByChar(uint32 char_id);
|
||||
uint32 GetAccountIDByName(std::string account_name, std::string loginserver, int16* status = 0, uint32* lsid = 0);
|
||||
uint32 GetAccountIDByName(const char* accname, const char *loginserver, int16* status = 0, uint32* lsid = 0);
|
||||
uint32 GetCharacterID(const char *name);
|
||||
uint32 GetCharacterInfo(std::string character_name, uint32 *account_id, uint32 *zone_id, uint32 *instance_id);
|
||||
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);
|
||||
@@ -140,41 +140,41 @@ public:
|
||||
void GetCharName(uint32 char_id, char* name);
|
||||
std::string GetCharNameByID(uint32 char_id);
|
||||
std::string GetNPCNameByID(uint32 npc_id);
|
||||
std::string GetCleanNPCNameByID(uint32 npc_id);
|
||||
void LoginIP(uint32 account_id, std::string login_ip);
|
||||
void LoginIP(uint32 AccountID, const char* LoginIP);
|
||||
|
||||
/* Instancing */
|
||||
|
||||
bool AddClientToInstance(uint16 instance_id, uint32 character_id);
|
||||
bool CheckInstanceByCharID(uint16 instance_id, uint32 character_id);
|
||||
bool AddClientToInstance(uint16 instance_id, uint32 char_id);
|
||||
bool CharacterInInstanceGroup(uint16 instance_id, uint32 char_id);
|
||||
bool CheckInstanceExists(uint16 instance_id);
|
||||
bool CheckInstanceExpired(uint16 instance_id);
|
||||
bool CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version, uint32 duration);
|
||||
bool GetUnusedInstanceID(uint16 &instance_id);
|
||||
bool IsGlobalInstance(uint16 instance_id);
|
||||
bool GlobalInstance(uint16 instance_id);
|
||||
bool RemoveClientFromInstance(uint16 instance_id, uint32 char_id);
|
||||
bool RemoveClientsFromInstance(uint16 instance_id);
|
||||
bool VerifyInstanceAlive(uint16 instance_id, uint32 character_id);
|
||||
bool VerifyInstanceAlive(uint16 instance_id, uint32 char_id);
|
||||
bool VerifyZoneInstance(uint32 zone_id, uint16 instance_id);
|
||||
|
||||
uint16 GetInstanceID(uint32 zone, uint32 charid, int16 version);
|
||||
std::vector<uint16> GetInstanceIDs(uint32 zone_id, uint32 character_id);
|
||||
uint8_t GetInstanceVersion(uint16 instance_id);
|
||||
uint16 GetInstanceVersion(uint16 instance_id);
|
||||
uint32 GetTimeRemainingInstance(uint16 instance_id, bool &is_perma);
|
||||
uint32 GetInstanceZoneID(uint16 instance_id);
|
||||
uint32 VersionFromInstanceID(uint16 instance_id);
|
||||
uint32 ZoneIDFromInstanceID(uint16 instance_id);
|
||||
|
||||
void AssignGroupToInstance(uint32 gid, uint32 instance_id);
|
||||
void AssignRaidToInstance(uint32 rid, uint32 instance_id);
|
||||
void BuryCorpsesInInstance(uint16 instance_id);
|
||||
void DeleteInstance(uint16 instance_id);
|
||||
void FlagInstanceByGroupLeader(uint32 zone_id, int16 version, uint32 charid, uint32 group_id);
|
||||
void FlagInstanceByRaidLeader(uint32 zone_id, int16 version, uint32 charid, uint32 raid_id);
|
||||
void GetCharactersInInstance(uint16 instance_id, std::list<uint32> &character_ids);
|
||||
void FlagInstanceByGroupLeader(uint32 zone, int16 version, uint32 charid, uint32 gid);
|
||||
void FlagInstanceByRaidLeader(uint32 zone, int16 version, uint32 charid, uint32 rid);
|
||||
void GetCharactersInInstance(uint16 instance_id, std::list<uint32> &charid_list);
|
||||
void PurgeExpiredInstances();
|
||||
void SetInstanceDuration(uint16 instance_id, uint32 new_duration);
|
||||
|
||||
/* Adventure related. */
|
||||
|
||||
void UpdateAdventureStatsEntry(uint32 char_id, uint8 theme, bool win = false, bool remove = false);
|
||||
void UpdateAdventureStatsEntry(uint32 char_id, uint8 theme, bool win, bool remove = false);
|
||||
bool GetAdventureStats(uint32 char_id, AdventureStats_Struct *as);
|
||||
|
||||
/* Account Related */
|
||||
@@ -188,8 +188,6 @@ public:
|
||||
|
||||
int16 CheckStatus(uint32 account_id);
|
||||
|
||||
void SetAccountCRCField(uint32 account_id, std::string field_name, uint64 checksum);
|
||||
|
||||
uint32 CheckLogin(const char* name, const char* password, const char *loginserver, int16* oStatus = 0);
|
||||
uint32 CreateAccount(const char* name, const char* password, int16 status, const char* loginserver, uint32 lsaccount_id);
|
||||
uint32 GetAccountIDFromLSID(const std::string& in_loginserver_id, uint32 in_loginserver_account_id, char* in_account_name = 0, int16* in_status = 0);
|
||||
@@ -198,16 +196,15 @@ public:
|
||||
void GetAccountFromID(uint32 id, char* oAccountName, int16* oStatus);
|
||||
void SetAgreementFlag(uint32 acctid);
|
||||
|
||||
int GetIPExemption(std::string account_ip);
|
||||
void SetIPExemption(std::string account_ip, int exemption_amount);
|
||||
int GetIPExemption(std::string account_ip);
|
||||
|
||||
int GetInstanceID(uint32 char_id, uint32 zone_id);
|
||||
|
||||
|
||||
/* Groups */
|
||||
|
||||
std::string GetGroupLeaderForLogin(std::string character_name);
|
||||
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);
|
||||
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);
|
||||
|
||||
@@ -245,11 +242,14 @@ public:
|
||||
|
||||
/* General Queries */
|
||||
|
||||
bool GetSafePoints(const char* zone_short_name, uint32 instance_version, float* safe_x = 0, float* safe_y = 0, float* safe_z = 0, float* safe_heading = 0, int16* minstatus = 0, uint8* minlevel = 0, char *flag_needed = nullptr);
|
||||
bool GetZoneGraveyard(const uint32 graveyard_id, uint32* graveyard_zoneid = 0, float* graveyard_x = 0, float* graveyard_y = 0, float* graveyard_z = 0, float* graveyard_heading = 0);
|
||||
bool GetZoneLongName(const char* short_name, char** long_name, char* file_name = 0, float* safe_x = 0, float* safe_y = 0, float* safe_z = 0, uint32* graveyard_id = 0, uint32* maxclients = 0);
|
||||
bool LoadPTimers(uint32 charid, PTimerList &into);
|
||||
|
||||
uint8 GetPEQZone(uint32 zone_id, uint32 version);
|
||||
uint8 GetMinStatus(uint32 zone_id, uint32 instance_version);
|
||||
uint32 GetZoneGraveyardID(uint32 zone_id, uint32 version);
|
||||
|
||||
uint8 GetPEQZone(uint32 zoneID, uint32 version);
|
||||
uint8 GetRaceSkill(uint8 skillid, uint8 in_race);
|
||||
uint8 GetServerType();
|
||||
uint8 GetSkillCap(uint8 skillid, uint8 in_race, uint8 in_class, uint16 in_level);
|
||||
@@ -267,8 +267,8 @@ public:
|
||||
int CountInvSnapshots();
|
||||
void ClearInvSnapshots(bool from_now = false);
|
||||
|
||||
void SourceDatabaseTableFromUrl(std::string table_name, std::string url);
|
||||
|
||||
/* EQEmuLogSys */
|
||||
void LoadLogSettings(EQEmuLogSys::LogSettings* log_settings);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
@@ -23,11 +23,10 @@
|
||||
#include <iterator>
|
||||
#include "database_dump_service.h"
|
||||
#include "../eqemu_logsys.h"
|
||||
#include "../strings.h"
|
||||
#include "../string_util.h"
|
||||
#include "../eqemu_config.h"
|
||||
#include "../database_schema.h"
|
||||
#include "../file.h"
|
||||
#include "../process/process.h"
|
||||
#include "../file_util.h"
|
||||
|
||||
#include <ctime>
|
||||
|
||||
@@ -41,6 +40,38 @@
|
||||
|
||||
#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
|
||||
*/
|
||||
@@ -57,7 +88,7 @@ bool DatabaseDumpService::IsMySQLInstalled()
|
||||
*/
|
||||
bool DatabaseDumpService::IsTarAvailable()
|
||||
{
|
||||
std::string version_output = Process::execute("tar --version");
|
||||
std::string version_output = execute("tar --version");
|
||||
|
||||
return version_output.find("GNU tar") != std::string::npos;
|
||||
}
|
||||
@@ -68,7 +99,7 @@ bool DatabaseDumpService::IsTarAvailable()
|
||||
*/
|
||||
bool DatabaseDumpService::Is7ZipAvailable()
|
||||
{
|
||||
std::string version_output = Process::execute("7z --help");
|
||||
std::string version_output = execute("7z --help");
|
||||
|
||||
return version_output.find("7-Zip") != std::string::npos;
|
||||
}
|
||||
@@ -86,9 +117,9 @@ bool DatabaseDumpService::HasCompressionBinary()
|
||||
*/
|
||||
std::string DatabaseDumpService::GetMySQLVersion()
|
||||
{
|
||||
std::string version_output = Process::execute("mysql --version");
|
||||
std::string version_output = execute("mysql --version");
|
||||
|
||||
return Strings::Trim(version_output);
|
||||
return trim(version_output);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,53 +149,95 @@ std::string DatabaseDumpService::GetBaseMySQLDumpCommand()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
std::string DatabaseDumpService::GetPlayerTablesList()
|
||||
{
|
||||
return Strings::Join(DatabaseSchema::GetPlayerTables(), " ");
|
||||
}
|
||||
|
||||
std::string DatabaseDumpService::GetBotTablesList()
|
||||
{
|
||||
return Strings::Join(DatabaseSchema::GetBotTables(), " ");
|
||||
}
|
||||
|
||||
std::string DatabaseDumpService::GetMercTablesList()
|
||||
{
|
||||
return Strings::Join(DatabaseSchema::GetMercTables(), " ");
|
||||
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()
|
||||
{
|
||||
return Strings::Join(DatabaseSchema::GetLoginTables(), " ");
|
||||
std::string tables_list;
|
||||
std::vector<std::string> tables = DatabaseSchema::GetLoginTables();
|
||||
for (const auto &table : tables) {
|
||||
tables_list += table + " ";
|
||||
}
|
||||
|
||||
return trim(tables_list);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
std::string DatabaseDumpService::GetQueryServTables()
|
||||
{
|
||||
return Strings::Join(DatabaseSchema::GetQueryServerTables(), " ");
|
||||
std::string tables_list;
|
||||
std::vector<std::string> tables = DatabaseSchema::GetQueryServerTables();
|
||||
for (const auto &table : tables) {
|
||||
tables_list += table + " ";
|
||||
}
|
||||
|
||||
return trim(tables_list);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
std::string DatabaseDumpService::GetSystemTablesList()
|
||||
{
|
||||
auto system_tables = DatabaseSchema::GetServerTables();
|
||||
auto version_tables = DatabaseSchema::GetVersionTables();
|
||||
std::string tables_list;
|
||||
|
||||
system_tables.insert(
|
||||
std::end(system_tables),
|
||||
std::begin(version_tables),
|
||||
std::end(version_tables)
|
||||
);
|
||||
std::vector<std::string> tables = DatabaseSchema::GetServerTables();
|
||||
for (const auto &table : tables) {
|
||||
tables_list += table + " ";
|
||||
}
|
||||
|
||||
return Strings::Join(system_tables, " ");
|
||||
tables = DatabaseSchema::GetVersionTables();
|
||||
for (const auto &table : tables) {
|
||||
tables_list += table + " ";
|
||||
}
|
||||
|
||||
return trim(tables_list);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
std::string DatabaseDumpService::GetStateTablesList()
|
||||
{
|
||||
return Strings::Join(DatabaseSchema::GetStateTables(), " ");
|
||||
std::string tables_list;
|
||||
|
||||
std::vector<std::string> tables = DatabaseSchema::GetStateTables();
|
||||
for (const auto &table : tables) {
|
||||
tables_list += table + " ";
|
||||
}
|
||||
|
||||
return trim(tables_list);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
std::string DatabaseDumpService::GetContentTablesList()
|
||||
{
|
||||
return Strings::Join(DatabaseSchema::GetContentTables(), " ");
|
||||
std::string tables_list;
|
||||
|
||||
std::vector<std::string> tables = DatabaseSchema::GetContentTables();
|
||||
for (const auto &table : tables) {
|
||||
tables_list += table + " ";
|
||||
}
|
||||
|
||||
return trim(tables_list);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -245,16 +318,6 @@ void DatabaseDumpService::Dump()
|
||||
dump_descriptor += "-player";
|
||||
}
|
||||
|
||||
if (IsDumpBotTables()) {
|
||||
tables_to_dump += GetBotTablesList() + " ";
|
||||
dump_descriptor += "-bots";
|
||||
}
|
||||
|
||||
if (IsDumpMercTables()) {
|
||||
tables_to_dump += GetMercTablesList() + " ";
|
||||
dump_descriptor += "-mercs";
|
||||
}
|
||||
|
||||
if (IsDumpSystemTables()) {
|
||||
tables_to_dump += GetSystemTablesList() + " ";
|
||||
dump_descriptor += "-system";
|
||||
@@ -301,12 +364,12 @@ void DatabaseDumpService::Dump()
|
||||
pipe_file
|
||||
);
|
||||
|
||||
if (!File::Exists(GetSetDumpPath()) && !IsDumpOutputToConsole()) {
|
||||
File::Makedir(GetSetDumpPath());
|
||||
if (!FileUtil::exists(GetSetDumpPath()) && !IsDumpOutputToConsole()) {
|
||||
FileUtil::mkdir(GetSetDumpPath());
|
||||
}
|
||||
|
||||
if (IsDumpDropTableSyntaxOnly()) {
|
||||
std::vector<std::string> tables = Strings::Split(tables_to_dump, ' ');
|
||||
std::vector<std::string> tables = SplitString(tables_to_dump, ' ');
|
||||
|
||||
for (auto &table : tables) {
|
||||
std::cout << "DROP TABLE IF EXISTS `" << table << "`;" << std::endl;
|
||||
@@ -317,14 +380,14 @@ void DatabaseDumpService::Dump()
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::string execution_result = Process::execute(execute_command);
|
||||
if (!execution_result.empty() && IsDumpOutputToConsole()) {
|
||||
std::string execution_result = execute(execute_command, IsDumpOutputToConsole());
|
||||
if (!execution_result.empty()) {
|
||||
std::cout << execution_result;
|
||||
}
|
||||
}
|
||||
|
||||
if (!tables_to_dump.empty()) {
|
||||
LogInfo("Dumping Tables [{}]", Strings::Trim(tables_to_dump));
|
||||
LogInfo("Dumping Tables [{}]", tables_to_dump);
|
||||
}
|
||||
|
||||
LogInfo("Database dump created at [{}.sql]", GetDumpFileNameWithPath());
|
||||
@@ -334,7 +397,7 @@ void DatabaseDumpService::Dump()
|
||||
LogInfo("Compression requested... Compressing dump [{}.sql]", GetDumpFileNameWithPath());
|
||||
|
||||
if (IsTarAvailable()) {
|
||||
Process::execute(
|
||||
execute(
|
||||
fmt::format(
|
||||
"tar -zcvf {}.tar.gz -C {} {}.sql",
|
||||
GetDumpFileNameWithPath(),
|
||||
@@ -345,7 +408,7 @@ void DatabaseDumpService::Dump()
|
||||
LogInfo("Compressed dump created at [{}.tar.gz]", GetDumpFileNameWithPath());
|
||||
}
|
||||
else if (Is7ZipAvailable()) {
|
||||
Process::execute(
|
||||
execute(
|
||||
fmt::format(
|
||||
"7z a -t7z {}.zip {}.sql",
|
||||
GetDumpFileNameWithPath(),
|
||||
@@ -373,7 +436,6 @@ void DatabaseDumpService::Dump()
|
||||
// LogDebug("[{}] login", (IsDumpLoginServerTables() ? "true" : "false"));
|
||||
// LogDebug("[{}] player", (IsDumpPlayerTables() ? "true" : "false"));
|
||||
// LogDebug("[{}] system", (IsDumpSystemTables() ? "true" : "false"));
|
||||
// LogDebug("[{}] bot", (IsDumpBotTables() ? "true" : "false"));
|
||||
}
|
||||
|
||||
bool DatabaseDumpService::IsDumpSystemTables() const
|
||||
@@ -515,23 +577,3 @@ void DatabaseDumpService::SetDumpStateTables(bool dump_state_tables)
|
||||
{
|
||||
DatabaseDumpService::dump_state_tables = dump_state_tables;
|
||||
}
|
||||
|
||||
bool DatabaseDumpService::IsDumpBotTables() const
|
||||
{
|
||||
return dump_bot_tables;
|
||||
}
|
||||
|
||||
void DatabaseDumpService::SetDumpBotTables(bool dump_bot_tables)
|
||||
{
|
||||
DatabaseDumpService::dump_bot_tables = dump_bot_tables;
|
||||
}
|
||||
|
||||
bool DatabaseDumpService::IsDumpMercTables() const
|
||||
{
|
||||
return dump_merc_tables;
|
||||
}
|
||||
|
||||
void DatabaseDumpService::SetDumpMercTables(bool dump_merc_tables)
|
||||
{
|
||||
DatabaseDumpService::dump_merc_tables = dump_merc_tables;
|
||||
}
|
||||
|
||||
@@ -53,10 +53,6 @@ public:
|
||||
void SetDumpDropTableSyntaxOnly(bool dump_drop_table_syntax_only);
|
||||
bool IsDumpStateTables() const;
|
||||
void SetDumpStateTables(bool dump_state_tables);
|
||||
bool IsDumpBotTables() const;
|
||||
void SetDumpBotTables(bool dump_bot_tables);
|
||||
bool IsDumpMercTables() const;
|
||||
void SetDumpMercTables(bool dump_bot_tables);
|
||||
|
||||
private:
|
||||
bool dump_all_tables = false;
|
||||
@@ -71,17 +67,14 @@ private:
|
||||
bool dump_with_compression = false;
|
||||
bool dump_output_to_console = false;
|
||||
bool dump_drop_table_syntax_only = false;
|
||||
bool dump_bot_tables = false;
|
||||
bool dump_merc_tables = 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 GetBotTablesList();
|
||||
std::string GetMercTablesList();
|
||||
std::string GetSystemTablesList();
|
||||
std::string GetStateTablesList();
|
||||
std::string GetContentTablesList();
|
||||
|
||||
+97
-106
@@ -18,12 +18,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
#include "../common/global_define.h"
|
||||
#include "../common/rulesys.h"
|
||||
#include "../common/strings.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/timer.h"
|
||||
|
||||
#include "database.h"
|
||||
#include "extprofile.h"
|
||||
#include "path_manager.h"
|
||||
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
@@ -476,16 +475,8 @@ bool Database::CheckDatabaseConversions() {
|
||||
CheckDatabaseConvertPPDeblob();
|
||||
CheckDatabaseConvertCorpseDeblob();
|
||||
|
||||
RuleManager::Instance()->LoadRules(this, "default", false);
|
||||
if (!RuleB(Bots, Enabled) && DoesTableExist("bot_data")) {
|
||||
LogInfo("Bot tables found but rule not enabled, enabling");
|
||||
RuleManager::Instance()->SetRule("Bots:Enabled", "true", this, true, true);
|
||||
}
|
||||
|
||||
/* Run EQEmu Server script (Checks for database updates) */
|
||||
|
||||
const std::string file = fmt::format("{}/eqemu_server.pl", path.GetServerPath());
|
||||
system(fmt::format("perl {} ran_from_world", file).c_str());
|
||||
if(system("perl eqemu_server.pl ran_from_world"));
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -970,7 +961,7 @@ bool Database::CheckDatabaseConvertPPDeblob(){
|
||||
std::string rquery = StringFormat("REPLACE INTO `character_inspect_messages` (id, inspect_message)"
|
||||
"VALUES (%u, '%s')",
|
||||
character_id,
|
||||
Strings::Escape(inspectmessage).c_str()
|
||||
EscapeString(inspectmessage).c_str()
|
||||
);
|
||||
auto results = QueryDatabase(rquery);
|
||||
}
|
||||
@@ -1106,95 +1097,95 @@ bool Database::CheckDatabaseConvertPPDeblob(){
|
||||
"e_expended_aa_spent"
|
||||
")"
|
||||
"VALUES ("
|
||||
"%u," // id
|
||||
"%u," // account_id
|
||||
"'%s'," // `name`
|
||||
"'%s'," // last_name
|
||||
"%u," // gender
|
||||
"%u," // race
|
||||
"%u," // class
|
||||
"%u," // `level`
|
||||
"%u," // deity
|
||||
"%u," // birthday
|
||||
"%u," // last_login
|
||||
"%u," // time_played
|
||||
"%u," // pvp_status
|
||||
"%u," // level2
|
||||
"%u," // anon
|
||||
"%u," // gm
|
||||
"%u," // intoxication
|
||||
"%u," // hair_color
|
||||
"%u," // beard_color
|
||||
"%u," // eye_color_1
|
||||
"%u," // eye_color_2
|
||||
"%u," // hair_style
|
||||
"%u," // beard
|
||||
"%u," // ability_time_seconds
|
||||
"%u," // ability_number
|
||||
"%u," // ability_time_minutes
|
||||
"%u," // ability_time_hours
|
||||
"'%s'," // title
|
||||
"'%s'," // suffix
|
||||
"%u," // exp
|
||||
"%u," // points
|
||||
"%u," // mana
|
||||
"%u," // cur_hp
|
||||
"%u," // str
|
||||
"%u," // sta
|
||||
"%u," // cha
|
||||
"%u," // dex
|
||||
"%u," // `int`
|
||||
"%u," // agi
|
||||
"%u," // wis
|
||||
"%u," // face
|
||||
"%f," // y
|
||||
"%f," // x
|
||||
"%f," // z
|
||||
"%f," // heading
|
||||
"%u," // pvp2
|
||||
"%u," // pvp_type
|
||||
"%u," // autosplit_enabled
|
||||
"%u," // zone_change_count
|
||||
"%u," // drakkin_heritage
|
||||
"%u," // drakkin_tattoo
|
||||
"%u," // drakkin_details
|
||||
"%i," // toxicity
|
||||
"%u," // hunger_level
|
||||
"%u," // thirst_level
|
||||
"%u," // ability_up
|
||||
"%u," // zone_id
|
||||
"%u," // zone_instance
|
||||
"%u," // leadership_exp_on
|
||||
"%u," // ldon_points_guk
|
||||
"%u," // ldon_points_mir
|
||||
"%u," // ldon_points_mmc
|
||||
"%u," // ldon_points_ruj
|
||||
"%u," // ldon_points_tak
|
||||
"%u," // ldon_points_available
|
||||
"%u," // tribute_time_remaining
|
||||
"%u," // show_helm
|
||||
"%u," // career_tribute_points
|
||||
"%u," // tribute_points
|
||||
"%u," // tribute_active
|
||||
"%u," // endurance
|
||||
"%u," // group_leadership_exp
|
||||
"%u," // raid_leadership_exp
|
||||
"%u," // group_leadership_points
|
||||
"%u," // raid_leadership_points
|
||||
"%u," // air_remaining
|
||||
"%u," // pvp_kills
|
||||
"%u," // pvp_deaths
|
||||
"%u," // pvp_current_points
|
||||
"%u," // pvp_career_points
|
||||
"%u," // pvp_best_kill_streak
|
||||
"%u," // pvp_worst_death_streak
|
||||
"%u," // pvp_current_kill_streak
|
||||
"%u," // aa_points_spent
|
||||
"%u," // aa_exp
|
||||
"%u," // aa_points
|
||||
"%u," // group_auto_consent
|
||||
"%u," // raid_auto_consent
|
||||
"%u," // guild_auto_consent
|
||||
"%u," // id
|
||||
"%u," // account_id
|
||||
"'%s'," // `name`
|
||||
"'%s'," // last_name
|
||||
"%u," // gender
|
||||
"%u," // race
|
||||
"%u," // class
|
||||
"%u," // `level`
|
||||
"%u," // deity
|
||||
"%u," // birthday
|
||||
"%u," // last_login
|
||||
"%u," // time_played
|
||||
"%u," // pvp_status
|
||||
"%u," // level2
|
||||
"%u," // anon
|
||||
"%u," // gm
|
||||
"%u," // intoxication
|
||||
"%u," // hair_color
|
||||
"%u," // beard_color
|
||||
"%u," // eye_color_1
|
||||
"%u," // eye_color_2
|
||||
"%u," // hair_style
|
||||
"%u," // beard
|
||||
"%u," // ability_time_seconds
|
||||
"%u," // ability_number
|
||||
"%u," // ability_time_minutes
|
||||
"%u," // ability_time_hours
|
||||
"'%s'," // title
|
||||
"'%s'," // suffix
|
||||
"%u," // exp
|
||||
"%u," // points
|
||||
"%u," // mana
|
||||
"%u," // cur_hp
|
||||
"%u," // str
|
||||
"%u," // sta
|
||||
"%u," // cha
|
||||
"%u," // dex
|
||||
"%u," // `int`
|
||||
"%u," // agi
|
||||
"%u," // wis
|
||||
"%u," // face
|
||||
"%f," // y
|
||||
"%f," // x
|
||||
"%f," // z
|
||||
"%f," // heading
|
||||
"%u," // pvp2
|
||||
"%u," // pvp_type
|
||||
"%u," // autosplit_enabled
|
||||
"%u," // zone_change_count
|
||||
"%u," // drakkin_heritage
|
||||
"%u," // drakkin_tattoo
|
||||
"%u," // drakkin_details
|
||||
"%i," // toxicity
|
||||
"%u," // hunger_level
|
||||
"%u," // thirst_level
|
||||
"%u," // ability_up
|
||||
"%u," // zone_id
|
||||
"%u," // zone_instance
|
||||
"%u," // leadership_exp_on
|
||||
"%u," // ldon_points_guk
|
||||
"%u," // ldon_points_mir
|
||||
"%u," // ldon_points_mmc
|
||||
"%u," // ldon_points_ruj
|
||||
"%u," // ldon_points_tak
|
||||
"%u," // ldon_points_available
|
||||
"%u," // tribute_time_remaining
|
||||
"%u," // show_helm
|
||||
"%u," // career_tribute_points
|
||||
"%u," // tribute_points
|
||||
"%u," // tribute_active
|
||||
"%u," // endurance
|
||||
"%u," // group_leadership_exp
|
||||
"%u," // raid_leadership_exp
|
||||
"%u," // group_leadership_points
|
||||
"%u," // raid_leadership_points
|
||||
"%u," // air_remaining
|
||||
"%u," // pvp_kills
|
||||
"%u," // pvp_deaths
|
||||
"%u," // pvp_current_points
|
||||
"%u," // pvp_career_points
|
||||
"%u," // pvp_best_kill_streak
|
||||
"%u," // pvp_worst_death_streak
|
||||
"%u," // pvp_current_kill_streak
|
||||
"%u," // aa_points_spent
|
||||
"%u," // aa_exp
|
||||
"%u," // aa_points
|
||||
"%u," // group_auto_consent
|
||||
"%u," // raid_auto_consent
|
||||
"%u," // guild_auto_consent
|
||||
"%u," // RestTimer
|
||||
"%u," // First Logon - References online status for EVENT_CONNECT/EVENT_DISCONNECt
|
||||
"%u," // Looking for Group
|
||||
@@ -1207,8 +1198,8 @@ bool Database::CheckDatabaseConvertPPDeblob(){
|
||||
")",
|
||||
character_id,
|
||||
account_id,
|
||||
Strings::Escape(pp->name).c_str(),
|
||||
Strings::Escape(pp->last_name).c_str(),
|
||||
EscapeString(pp->name).c_str(),
|
||||
EscapeString(pp->last_name).c_str(),
|
||||
pp->gender,
|
||||
pp->race,
|
||||
pp->class_,
|
||||
@@ -1232,8 +1223,8 @@ bool Database::CheckDatabaseConvertPPDeblob(){
|
||||
pp->ability_number,
|
||||
pp->ability_time_minutes,
|
||||
pp->ability_time_hours,
|
||||
Strings::Escape(pp->title).c_str(),
|
||||
Strings::Escape(pp->suffix).c_str(),
|
||||
EscapeString(pp->title).c_str(),
|
||||
EscapeString(pp->suffix).c_str(),
|
||||
pp->exp,
|
||||
pp->points,
|
||||
pp->mana,
|
||||
@@ -1461,7 +1452,7 @@ bool Database::CheckDatabaseConvertPPDeblob(){
|
||||
for (i = 0; i < MAX_LEADERSHIP_AA_ARRAY; i++){
|
||||
if (pp->leader_abilities.ranks[i] > 0 && pp->leader_abilities.ranks[i] < 6){
|
||||
if (first_entry != 1){
|
||||
rquery = StringFormat("REPLACE INTO `character_leadership_abilities` (id, slot, `rank`) VALUES (%i, %u, %u)", character_id, i, pp->leader_abilities.ranks[i]);
|
||||
rquery = StringFormat("REPLACE INTO `character_leadership_abilities` (id, slot, rank) VALUES (%i, %u, %u)", character_id, i, pp->leader_abilities.ranks[i]);
|
||||
first_entry = 1;
|
||||
}
|
||||
rquery = rquery + StringFormat(", (%i, %u, %u)", character_id, i, pp->leader_abilities.ranks[i]);
|
||||
|
||||
+313
-252
@@ -18,18 +18,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
#include "../common/global_define.h"
|
||||
#include "../common/rulesys.h"
|
||||
#include "../common/strings.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/timer.h"
|
||||
#include "../common/repositories/character_corpses_repository.h"
|
||||
#include "../common/repositories/dynamic_zone_members_repository.h"
|
||||
#include "../common/repositories/dynamic_zones_repository.h"
|
||||
#include "../common/repositories/group_id_repository.h"
|
||||
#include "../common/repositories/instance_list_repository.h"
|
||||
#include "../common/repositories/instance_list_player_repository.h"
|
||||
#include "../common/repositories/raid_members_repository.h"
|
||||
#include "../common/repositories/respawn_times_repository.h"
|
||||
#include "../common/repositories/spawn_condition_values_repository.h"
|
||||
|
||||
|
||||
#include "database.h"
|
||||
|
||||
@@ -49,83 +41,115 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
bool Database::AddClientToInstance(uint16 instance_id, uint32 character_id)
|
||||
/**
|
||||
* @param instance_id
|
||||
* @param char_id
|
||||
* @return
|
||||
*/
|
||||
bool Database::AddClientToInstance(uint16 instance_id, uint32 char_id)
|
||||
{
|
||||
auto e = InstanceListPlayerRepository::NewEntity();
|
||||
std::string query = StringFormat(
|
||||
"REPLACE INTO `instance_list_player` (id, charid) "
|
||||
"VALUES "
|
||||
"(%lu, %lu)",
|
||||
(unsigned long) instance_id,
|
||||
(unsigned long) char_id
|
||||
);
|
||||
|
||||
e.id = instance_id;
|
||||
e.charid = character_id;
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
return InstanceListPlayerRepository::ReplaceOne(*this, e);
|
||||
return results.Success();
|
||||
}
|
||||
|
||||
bool Database::CheckInstanceByCharID(uint16 instance_id, uint32 character_id)
|
||||
bool Database::CharacterInInstanceGroup(uint16 instance_id, uint32 char_id)
|
||||
{
|
||||
if (!instance_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto l = InstanceListPlayerRepository::GetWhere(
|
||||
*this,
|
||||
fmt::format(
|
||||
"id = {} AND charid = {}",
|
||||
instance_id,
|
||||
character_id
|
||||
)
|
||||
);
|
||||
if (l.empty()) {
|
||||
std::string query = StringFormat("SELECT charid FROM instance_list_player where id=%u AND charid=%u", instance_id, char_id);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
return false;
|
||||
|
||||
if (results.RowCount() != 1)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Database::CheckInstanceExists(uint16 instance_id)
|
||||
{
|
||||
if (!instance_id) {
|
||||
return false;
|
||||
}
|
||||
bool Database::CheckInstanceExists(uint16 instance_id) {
|
||||
std::string query = StringFormat(
|
||||
"SELECT "
|
||||
"`id` "
|
||||
"FROM "
|
||||
"`instance_list` "
|
||||
"WHERE "
|
||||
"`id` = %u",
|
||||
instance_id
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
auto i = InstanceListRepository::FindOne(*this, instance_id);
|
||||
if (!i.id) {
|
||||
if (!results.Success())
|
||||
return false;
|
||||
|
||||
if (results.RowCount() == 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Database::CheckInstanceExpired(uint16 instance_id)
|
||||
{
|
||||
if (!instance_id) {
|
||||
|
||||
int32 start_time = 0;
|
||||
int32 duration = 0;
|
||||
uint32 never_expires = 0;
|
||||
|
||||
std::string query = StringFormat(
|
||||
"SELECT start_time, duration, never_expires FROM instance_list WHERE id=%u",
|
||||
instance_id
|
||||
);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto i = InstanceListRepository::FindOne(*this, instance_id);
|
||||
if (!i.id) {
|
||||
if (results.RowCount() == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (i.never_expires) {
|
||||
auto row = results.begin();
|
||||
|
||||
start_time = atoi(row[0]);
|
||||
duration = atoi(row[1]);
|
||||
never_expires = atoi(row[2]);
|
||||
|
||||
if (never_expires == 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
timeval tv{};
|
||||
gettimeofday(&tv, nullptr);
|
||||
|
||||
return (i.start_time + i.duration) <= tv.tv_sec;
|
||||
return (start_time + duration) <= tv.tv_sec;
|
||||
|
||||
}
|
||||
|
||||
bool Database::CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version, uint32 duration)
|
||||
{
|
||||
auto e = InstanceListRepository::NewEntity();
|
||||
std::string query = StringFormat(
|
||||
"INSERT INTO instance_list (id, zone, version, start_time, duration)"
|
||||
" values (%u, %u, %u, UNIX_TIMESTAMP(), %u)",
|
||||
instance_id,
|
||||
zone_id,
|
||||
version,
|
||||
duration
|
||||
);
|
||||
|
||||
e.id = instance_id;
|
||||
e.zone = zone_id;
|
||||
e.version = version;
|
||||
e.start_time = std::time(nullptr);
|
||||
e.duration = duration;
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
return InstanceListRepository::InsertOne(*this, e).id;
|
||||
return results.Success();
|
||||
}
|
||||
|
||||
bool Database::GetUnusedInstanceID(uint16 &instance_id)
|
||||
@@ -133,8 +157,8 @@ bool Database::GetUnusedInstanceID(uint16 &instance_id)
|
||||
uint32 max_reserved_instance_id = RuleI(Instances, ReservedInstances);
|
||||
uint32 max = 32000;
|
||||
|
||||
auto query = fmt::format(
|
||||
"SELECT IFNULL(MAX(id), {}) + 1 FROM instance_list WHERE id > {}",
|
||||
std::string query = StringFormat(
|
||||
"SELECT IFNULL(MAX(id),%u)+1 FROM instance_list WHERE id > %u",
|
||||
max_reserved_instance_id,
|
||||
max_reserved_instance_id
|
||||
);
|
||||
@@ -178,7 +202,7 @@ bool Database::GetUnusedInstanceID(uint16 &instance_id)
|
||||
return true;
|
||||
}
|
||||
|
||||
query = fmt::format("SELECT id FROM instance_list where id > {} ORDER BY id", max_reserved_instance_id);
|
||||
query = StringFormat("SELECT id FROM instance_list where id > %u ORDER BY id", max_reserved_instance_id);
|
||||
results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success()) {
|
||||
@@ -192,9 +216,8 @@ bool Database::GetUnusedInstanceID(uint16 &instance_id)
|
||||
}
|
||||
|
||||
max_reserved_instance_id++;
|
||||
|
||||
for (auto row : results) {
|
||||
if (max_reserved_instance_id < std::stoul(row[0])) {
|
||||
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;
|
||||
}
|
||||
@@ -212,45 +235,57 @@ bool Database::GetUnusedInstanceID(uint16 &instance_id)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Database::IsGlobalInstance(uint16 instance_id)
|
||||
bool Database::GlobalInstance(uint16 instance_id)
|
||||
{
|
||||
if (!instance_id) {
|
||||
return false;
|
||||
}
|
||||
std::string query = StringFormat(
|
||||
"SELECT "
|
||||
"is_global "
|
||||
"FROM "
|
||||
"instance_list "
|
||||
"WHERE "
|
||||
"id = %u "
|
||||
"LIMIT 1 ",
|
||||
instance_id
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
auto i = InstanceListRepository::FindOne(*this, instance_id);
|
||||
if (!i.id) {
|
||||
if (!results.Success())
|
||||
return false;
|
||||
}
|
||||
|
||||
return i.is_global;
|
||||
if (results.RowCount() == 0)
|
||||
return false;
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
return (atoi(row[0]) == 1) ? true : false;
|
||||
}
|
||||
|
||||
bool Database::RemoveClientFromInstance(uint16 instance_id, uint32 char_id)
|
||||
{
|
||||
return InstanceListPlayerRepository::DeleteWhere(
|
||||
*this,
|
||||
fmt::format(
|
||||
"id = {} AND charid = {}",
|
||||
instance_id,
|
||||
char_id
|
||||
)
|
||||
);
|
||||
std::string query = StringFormat("DELETE FROM instance_list_player WHERE id=%lu AND charid=%lu",
|
||||
(unsigned long)instance_id, (unsigned long)char_id);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
return results.Success();
|
||||
}
|
||||
|
||||
|
||||
bool Database::RemoveClientsFromInstance(uint16 instance_id)
|
||||
{
|
||||
return InstanceListPlayerRepository::DeleteOne(*this, instance_id);
|
||||
std::string query = StringFormat("DELETE FROM instance_list_player WHERE id=%lu", (unsigned long)instance_id);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
return results.Success();
|
||||
}
|
||||
|
||||
bool Database::VerifyInstanceAlive(uint16 instance_id, uint32 character_id)
|
||||
bool Database::VerifyInstanceAlive(uint16 instance_id, uint32 char_id)
|
||||
{
|
||||
//we are not saved to this instance so set our instance to 0
|
||||
if (!IsGlobalInstance(instance_id) && !CheckInstanceByCharID(instance_id, character_id)) {
|
||||
if (!GlobalInstance(instance_id) && !CharacterInInstanceGroup(instance_id, char_id))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CheckInstanceExpired(instance_id)) {
|
||||
if (CheckInstanceExpired(instance_id))
|
||||
{
|
||||
DeleteInstance(instance_id);
|
||||
return false;
|
||||
}
|
||||
@@ -260,102 +295,99 @@ bool Database::VerifyInstanceAlive(uint16 instance_id, uint32 character_id)
|
||||
|
||||
bool Database::VerifyZoneInstance(uint32 zone_id, uint16 instance_id)
|
||||
{
|
||||
auto l = InstanceListRepository::GetWhere(
|
||||
*this,
|
||||
fmt::format(
|
||||
"id = {} AND zone = {}",
|
||||
instance_id,
|
||||
zone_id
|
||||
)
|
||||
);
|
||||
if (l.empty()) {
|
||||
|
||||
std::string query = StringFormat("SELECT id FROM instance_list where id=%u AND zone=%u", instance_id, zone_id);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
return false;
|
||||
|
||||
if (results.RowCount() == 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16 Database::GetInstanceID(uint32 zone_id, uint32 character_id, int16 version)
|
||||
uint16 Database::GetInstanceID(uint32 zone, uint32 character_id, int16 version)
|
||||
{
|
||||
if (!zone_id) {
|
||||
if (!zone)
|
||||
return 0;
|
||||
|
||||
std::string query = StringFormat(
|
||||
"SELECT "
|
||||
"instance_list.id "
|
||||
"FROM "
|
||||
"instance_list, "
|
||||
"instance_list_player "
|
||||
"WHERE "
|
||||
"instance_list.zone = %u "
|
||||
"AND instance_list.version = %u "
|
||||
"AND instance_list.id = instance_list_player.id "
|
||||
"AND instance_list_player.charid = %u "
|
||||
"LIMIT 1; ",
|
||||
zone,
|
||||
version,
|
||||
character_id
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
return 0;
|
||||
|
||||
if (results.RowCount() == 0)
|
||||
return 0;
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
return atoi(row[0]);
|
||||
}
|
||||
|
||||
uint16 Database::GetInstanceVersion(uint16 instance_id) {
|
||||
if (instance_id == 0)
|
||||
return 0;
|
||||
|
||||
std::string query = StringFormat("SELECT version FROM instance_list where id=%u", instance_id);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
return 0;
|
||||
|
||||
if (results.RowCount() == 0)
|
||||
return 0;
|
||||
|
||||
auto row = results.begin();
|
||||
return atoi(row[0]);
|
||||
}
|
||||
|
||||
uint32 Database::GetTimeRemainingInstance(uint16 instance_id, bool &is_perma)
|
||||
{
|
||||
uint32 start_time = 0;
|
||||
uint32 duration = 0;
|
||||
uint32 never_expires = 0;
|
||||
|
||||
std::string query = StringFormat("SELECT start_time, duration, never_expires FROM instance_list WHERE id=%u", instance_id);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
{
|
||||
is_perma = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto query = fmt::format(
|
||||
"SELECT instance_list.id FROM "
|
||||
"instance_list, instance_list_player WHERE "
|
||||
"instance_list.zone = {} AND "
|
||||
"instance_list.version = {} AND "
|
||||
"instance_list.id = instance_list_player.id AND "
|
||||
"instance_list_player.charid = {} "
|
||||
"LIMIT 1;",
|
||||
zone_id,
|
||||
version,
|
||||
character_id
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success() || !results.RowCount()) {
|
||||
if (results.RowCount() == 0)
|
||||
{
|
||||
is_perma = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
return static_cast<uint16>(std::stoul(row[0]));
|
||||
}
|
||||
start_time = atoi(row[0]);
|
||||
duration = atoi(row[1]);
|
||||
never_expires = atoi(row[2]);
|
||||
|
||||
std::vector<uint16> Database::GetInstanceIDs(uint32 zone_id, uint32 character_id)
|
||||
{
|
||||
std::vector<uint16> l;
|
||||
|
||||
if (!zone_id) {
|
||||
return l;
|
||||
}
|
||||
|
||||
const auto query = fmt::format(
|
||||
"SELECT instance_list.id FROM "
|
||||
"instance_list, instance_list_player WHERE "
|
||||
"instance_list.zone = {} AND "
|
||||
"instance_list.id = instance_list_player.id AND "
|
||||
"instance_list_player.charid = {}",
|
||||
zone_id,
|
||||
character_id
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success() || !results.RowCount()) {
|
||||
return l;
|
||||
}
|
||||
|
||||
for (auto row : results) {
|
||||
l.push_back(static_cast<uint16>(std::stoul(row[0])));
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
uint8_t Database::GetInstanceVersion(uint16 instance_id) {
|
||||
if (!instance_id) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto i = InstanceListRepository::FindOne(*this, instance_id);
|
||||
if (!i.id) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return i.version;
|
||||
}
|
||||
|
||||
uint32 Database::GetTimeRemainingInstance(uint16 instance_id, bool &is_perma)
|
||||
{
|
||||
auto i = InstanceListRepository::FindOne(*this, instance_id);
|
||||
if (!i.id) {
|
||||
is_perma = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (i.never_expires) {
|
||||
if (never_expires == 1)
|
||||
{
|
||||
is_perma = true;
|
||||
return 0;
|
||||
}
|
||||
@@ -364,175 +396,204 @@ uint32 Database::GetTimeRemainingInstance(uint16 instance_id, bool &is_perma)
|
||||
|
||||
timeval tv;
|
||||
gettimeofday(&tv, nullptr);
|
||||
return ((i.start_time + i.duration) - tv.tv_sec);
|
||||
return ((start_time + duration) - tv.tv_sec);
|
||||
}
|
||||
|
||||
uint32 Database::GetInstanceZoneID(uint16 instance_id)
|
||||
uint32 Database::VersionFromInstanceID(uint16 instance_id)
|
||||
{
|
||||
if (!instance_id) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto i = InstanceListRepository::FindOne(*this, instance_id);
|
||||
if (!i.id) {
|
||||
return 0;
|
||||
}
|
||||
std::string query = StringFormat("SELECT version FROM instance_list where id=%u", instance_id);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
return i.zone;
|
||||
if (!results.Success())
|
||||
return 0;
|
||||
|
||||
if (results.RowCount() == 0)
|
||||
return 0;
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
return atoi(row[0]);
|
||||
}
|
||||
|
||||
uint32 Database::ZoneIDFromInstanceID(uint16 instance_id)
|
||||
{
|
||||
|
||||
std::string query = StringFormat("SELECT zone FROM instance_list where id=%u", instance_id);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
return 0;
|
||||
|
||||
if (results.RowCount() == 0)
|
||||
return 0;
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
return atoi(row[0]);
|
||||
}
|
||||
|
||||
void Database::AssignGroupToInstance(uint32 group_id, uint32 instance_id)
|
||||
{
|
||||
auto zone_id = GetInstanceZoneID(instance_id);
|
||||
auto version = GetInstanceVersion(instance_id);
|
||||
|
||||
auto l = GroupIdRepository::GetWhere(
|
||||
*this,
|
||||
fmt::format(
|
||||
"groupid = {}",
|
||||
group_id
|
||||
)
|
||||
);
|
||||
if (l.empty()) {
|
||||
uint32 zone_id = ZoneIDFromInstanceID(instance_id);
|
||||
uint16 version = VersionFromInstanceID(instance_id);
|
||||
|
||||
std::string query = StringFormat("SELECT `charid` FROM `group_id` WHERE `groupid` = %u", group_id);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& e : l) {
|
||||
if (!GetInstanceID(zone_id, e.charid, version)) {
|
||||
AddClientToInstance(instance_id, e.charid);
|
||||
}
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
{
|
||||
uint32 charid = atoi(row[0]);
|
||||
if (GetInstanceID(zone_id, charid, version) == 0)
|
||||
AddClientToInstance(instance_id, charid);
|
||||
}
|
||||
}
|
||||
|
||||
void Database::AssignRaidToInstance(uint32 raid_id, uint32 instance_id)
|
||||
{
|
||||
auto zone_id = GetInstanceZoneID(instance_id);
|
||||
auto version = GetInstanceVersion(instance_id);
|
||||
|
||||
auto l = GroupIdRepository::GetWhere(
|
||||
*this,
|
||||
uint32 zone_id = ZoneIDFromInstanceID(instance_id);
|
||||
uint16 version = VersionFromInstanceID(instance_id);
|
||||
|
||||
std::string query = StringFormat("SELECT `charid` FROM `raid_members` WHERE `raidid` = %u", raid_id);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
return;
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
{
|
||||
uint32 charid = atoi(row[0]);
|
||||
if (GetInstanceID(zone_id, charid, version) == 0)
|
||||
AddClientToInstance(instance_id, charid);
|
||||
}
|
||||
}
|
||||
|
||||
void Database::BuryCorpsesInInstance(uint16 instance_id) {
|
||||
QueryDatabase(
|
||||
fmt::format(
|
||||
"raidid = {}",
|
||||
raid_id
|
||||
"UPDATE character_corpses SET is_buried = 1, instance_id = 0 WHERE instance_id = {}",
|
||||
instance_id
|
||||
)
|
||||
);
|
||||
if (l.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& e : l) {
|
||||
if (!GetInstanceID(zone_id, e.charid, version)) {
|
||||
AddClientToInstance(instance_id, e.charid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Database::DeleteInstance(uint16 instance_id)
|
||||
{
|
||||
std::string query;
|
||||
|
||||
query = StringFormat("DELETE FROM instance_list_player WHERE id=%u", instance_id);
|
||||
QueryDatabase(query);
|
||||
|
||||
InstanceListPlayerRepository::DeleteWhere(*this, fmt::format("id = {}", instance_id));
|
||||
query = StringFormat("DELETE FROM respawn_times WHERE instance_id=%u", instance_id);
|
||||
QueryDatabase(query);
|
||||
|
||||
RespawnTimesRepository::DeleteWhere(*this, fmt::format("instance_id = {}", instance_id));
|
||||
|
||||
SpawnConditionValuesRepository::DeleteWhere(*this, fmt::format("instance_id = {}", instance_id));
|
||||
query = StringFormat("DELETE FROM spawn_condition_values WHERE instance_id=%u", instance_id);
|
||||
QueryDatabase(query);
|
||||
|
||||
DynamicZoneMembersRepository::DeleteByInstance(*this, instance_id);
|
||||
DynamicZonesRepository::DeleteWhere(*this, fmt::format("instance_id = {}", instance_id));
|
||||
|
||||
CharacterCorpsesRepository::BuryInstance(*this, instance_id);
|
||||
BuryCorpsesInInstance(instance_id);
|
||||
}
|
||||
|
||||
void Database::FlagInstanceByGroupLeader(uint32 zone_id, int16 version, uint32 character_id, uint32 group_id)
|
||||
void Database::FlagInstanceByGroupLeader(uint32 zone, int16 version, uint32 charid, uint32 gid)
|
||||
{
|
||||
auto instance_id = GetInstanceID(zone_id, character_id, version);
|
||||
if (instance_id) {
|
||||
uint16 id = GetInstanceID(zone, charid, version);
|
||||
if (id != 0)
|
||||
return;
|
||||
}
|
||||
|
||||
char ln[128];
|
||||
memset(ln, 0, 128);
|
||||
GetGroupLeadershipInfo(group_id, ln);
|
||||
GetGroupLeadershipInfo(gid, ln);
|
||||
uint32 l_charid = GetCharacterID((const char*)ln);
|
||||
uint16 l_id = GetInstanceID(zone, l_charid, version);
|
||||
|
||||
auto group_leader_id = GetCharacterID((const char*)ln);
|
||||
auto group_leader_instance_id = GetInstanceID(zone_id, group_leader_id, version);
|
||||
|
||||
if (!group_leader_instance_id) {
|
||||
if (l_id == 0)
|
||||
return;
|
||||
}
|
||||
|
||||
AddClientToInstance(group_leader_instance_id, character_id);
|
||||
AddClientToInstance(l_id, charid);
|
||||
}
|
||||
|
||||
void Database::FlagInstanceByRaidLeader(uint32 zone_id, int16 version, uint32 character_id, uint32 raid_id)
|
||||
void Database::FlagInstanceByRaidLeader(uint32 zone, int16 version, uint32 charid, uint32 rid)
|
||||
{
|
||||
uint16 instance_id = GetInstanceID(zone_id, character_id, version);
|
||||
if (instance_id) {
|
||||
uint16 id = GetInstanceID(zone, charid, version);
|
||||
if (id != 0)
|
||||
return;
|
||||
}
|
||||
|
||||
auto raid_leader_id = GetCharacterID(GetRaidLeaderName(raid_id));
|
||||
auto raid_leader_instance_id = GetInstanceID(zone_id, raid_leader_id, version);
|
||||
uint32 l_charid = GetCharacterID(GetRaidLeaderName(rid));
|
||||
uint16 l_id = GetInstanceID(zone, l_charid, version);
|
||||
|
||||
if (!raid_leader_instance_id) {
|
||||
if (l_id == 0)
|
||||
return;
|
||||
}
|
||||
|
||||
AddClientToInstance(raid_leader_instance_id, character_id);
|
||||
AddClientToInstance(l_id, charid);
|
||||
}
|
||||
|
||||
void Database::GetCharactersInInstance(uint16 instance_id, std::list<uint32> &character_ids)
|
||||
{
|
||||
auto l = InstanceListPlayerRepository::GetWhere(*this, fmt::format("id = {}", instance_id));
|
||||
if (l.empty()) {
|
||||
return;
|
||||
}
|
||||
void Database::GetCharactersInInstance(uint16 instance_id, std::list<uint32> &charid_list) {
|
||||
|
||||
for (const auto& e : l) {
|
||||
character_ids.push_back(e.charid);
|
||||
}
|
||||
std::string query = StringFormat("SELECT `charid` FROM `instance_list_player` WHERE `id` = %u", instance_id);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
return;
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
charid_list.push_back(atoi(row[0]));
|
||||
}
|
||||
|
||||
void Database::PurgeExpiredInstances()
|
||||
{
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
auto l = InstanceListRepository::GetWhere(
|
||||
*this,
|
||||
"(start_time + duration) <= (UNIX_TIMESTAMP() - 86400) AND never_expires = 0"
|
||||
);
|
||||
if (l.empty()) {
|
||||
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()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (results.RowCount() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::string> instance_ids;
|
||||
for (const auto& e : l) {
|
||||
instance_ids.emplace_back(std::to_string(e.id));
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
instance_ids.emplace_back(row[0]);
|
||||
}
|
||||
|
||||
const auto imploded_instance_ids = Strings::Implode(",", instance_ids);
|
||||
std::string imploded_instance_ids = implode(",", instance_ids);
|
||||
|
||||
InstanceListRepository::DeleteWhere(*this, fmt::format("id IN ({})", imploded_instance_ids));
|
||||
InstanceListPlayerRepository::DeleteWhere(*this, fmt::format("id IN ({})", imploded_instance_ids));
|
||||
RespawnTimesRepository::DeleteWhere(*this, fmt::format("instance_id IN ({})", imploded_instance_ids));
|
||||
SpawnConditionValuesRepository::DeleteWhere(*this, fmt::format("instance_id IN ({})", imploded_instance_ids));
|
||||
CharacterCorpsesRepository::BuryInstances(*this, imploded_instance_ids);
|
||||
QueryDatabase(fmt::format("DELETE FROM instance_list WHERE id IN ({})", imploded_instance_ids));
|
||||
QueryDatabase(fmt::format("DELETE FROM instance_list_player WHERE id IN ({})", imploded_instance_ids));
|
||||
QueryDatabase(fmt::format("DELETE FROM respawn_times WHERE instance_id IN ({})", imploded_instance_ids));
|
||||
QueryDatabase(fmt::format("DELETE FROM spawn_condition_values WHERE instance_id IN ({})", imploded_instance_ids));
|
||||
QueryDatabase(fmt::format("UPDATE character_corpses SET is_buried = 1, instance_id = 0 WHERE instance_id IN ({})", imploded_instance_ids));
|
||||
DynamicZoneMembersRepository::DeleteByManyInstances(*this, imploded_instance_ids);
|
||||
DynamicZonesRepository::DeleteWhere(*this, fmt::format("instance_id IN ({})", imploded_instance_ids));
|
||||
}
|
||||
|
||||
void Database::SetInstanceDuration(uint16 instance_id, uint32 new_duration)
|
||||
{
|
||||
auto i = InstanceListRepository::FindOne(*this, instance_id);
|
||||
if (!i.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
i.start_time = std::time(nullptr);
|
||||
i.duration = new_duration;
|
||||
|
||||
InstanceListRepository::UpdateOne(*this, i);
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -53,7 +53,6 @@ namespace DatabaseSchema {
|
||||
{"character_expedition_lockouts", "character_id"},
|
||||
{"character_exp_modifiers", "character_id"},
|
||||
{"character_inspect_messages", "id"},
|
||||
{"character_instance_safereturns", "character_id"},
|
||||
{"character_item_recast", "id"},
|
||||
{"character_languages", "id"},
|
||||
{"character_leadership_abilities", "id"},
|
||||
@@ -62,11 +61,9 @@ namespace DatabaseSchema {
|
||||
{"character_pet_buffs", "char_id"},
|
||||
{"character_pet_info", "char_id"},
|
||||
{"character_pet_inventory", "char_id"},
|
||||
{"character_peqzone_flags", "id"},
|
||||
{"character_potionbelt", "id"},
|
||||
{"character_skills", "id"},
|
||||
{"character_spells", "id"},
|
||||
{"character_task_timers", "character_id"},
|
||||
{"character_tasks", "charid"},
|
||||
{"character_tribute", "id"},
|
||||
{"completed_tasks", "charid"},
|
||||
@@ -83,6 +80,7 @@ namespace DatabaseSchema {
|
||||
{"player_titlesets", "char_id"},
|
||||
{"quest_globals", "charid"},
|
||||
{"timers", "char_id"},
|
||||
{"titles", "char_id"},
|
||||
{"trader", "char_id"},
|
||||
{"zone_flags", "charID"}
|
||||
};
|
||||
@@ -121,7 +119,6 @@ namespace DatabaseSchema {
|
||||
"character_expedition_lockouts",
|
||||
"character_exp_modifiers",
|
||||
"character_inspect_messages",
|
||||
"character_instance_safereturns",
|
||||
"character_item_recast",
|
||||
"character_languages",
|
||||
"character_leadership_abilities",
|
||||
@@ -130,11 +127,9 @@ namespace DatabaseSchema {
|
||||
"character_pet_buffs",
|
||||
"character_pet_info",
|
||||
"character_pet_inventory",
|
||||
"character_peqzone_flags",
|
||||
"character_potionbelt",
|
||||
"character_skills",
|
||||
"character_spells",
|
||||
"character_task_timers",
|
||||
"character_tasks",
|
||||
"character_tribute",
|
||||
"completed_tasks",
|
||||
@@ -159,6 +154,7 @@ namespace DatabaseSchema {
|
||||
"spell_buckets",
|
||||
"spell_globals",
|
||||
"timers",
|
||||
"titles",
|
||||
"trader",
|
||||
"trader_audit",
|
||||
"zone_flags"
|
||||
@@ -189,14 +185,13 @@ namespace DatabaseSchema {
|
||||
"char_create_point_allocations",
|
||||
"damageshieldtypes",
|
||||
"doors",
|
||||
"dynamic_zone_templates",
|
||||
"faction_association",
|
||||
"faction_base_data",
|
||||
"faction_list",
|
||||
"faction_list_mod",
|
||||
"fishing",
|
||||
"forage",
|
||||
"global_loot",
|
||||
"goallists",
|
||||
"graveyard",
|
||||
"grid",
|
||||
"grid_entries",
|
||||
@@ -222,9 +217,9 @@ namespace DatabaseSchema {
|
||||
"npc_types_tint",
|
||||
"object",
|
||||
"pets",
|
||||
"pets_beastlord_data",
|
||||
"pets_equipmentset",
|
||||
"pets_equipmentset_entries",
|
||||
"proximities",
|
||||
"skill_caps",
|
||||
"spawn2",
|
||||
"spawn_conditions",
|
||||
@@ -270,7 +265,6 @@ namespace DatabaseSchema {
|
||||
"perl_event_export_settings",
|
||||
"profanity_list",
|
||||
"rule_sets",
|
||||
"titles",
|
||||
"rule_values",
|
||||
"variables",
|
||||
};
|
||||
@@ -315,10 +309,6 @@ namespace DatabaseSchema {
|
||||
"banned_ips",
|
||||
"bug_reports",
|
||||
"bugs",
|
||||
"completed_shared_task_activity_state",
|
||||
"completed_shared_task_members",
|
||||
"completed_shared_tasks",
|
||||
"discord_webhooks",
|
||||
"dynamic_zone_members",
|
||||
"dynamic_zones",
|
||||
"eventlog",
|
||||
@@ -328,13 +318,11 @@ namespace DatabaseSchema {
|
||||
"group_id",
|
||||
"group_leaders",
|
||||
"hackers",
|
||||
"instance_list",
|
||||
"ip_exemptions",
|
||||
"instance_list",
|
||||
"item_tick",
|
||||
"lfguild",
|
||||
"merc_buffs",
|
||||
"merchantlist_temp",
|
||||
"mercs",
|
||||
"object_contents",
|
||||
"raid_details",
|
||||
"raid_leaders",
|
||||
@@ -343,10 +331,6 @@ namespace DatabaseSchema {
|
||||
"respawn_times",
|
||||
"saylink",
|
||||
"server_scheduled_events",
|
||||
"shared_task_activity_state",
|
||||
"shared_task_dynamic_zones",
|
||||
"shared_task_members",
|
||||
"shared_tasks",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -379,60 +363,6 @@ namespace DatabaseSchema {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Gets all player bot tables
|
||||
* @note These tables have no content in the PEQ daily dump
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
static std::vector<std::string> GetBotTables()
|
||||
{
|
||||
return {
|
||||
"bot_buffs",
|
||||
"bot_command_settings",
|
||||
"bot_create_combinations",
|
||||
"bot_data",
|
||||
"bot_group_members",
|
||||
"bot_groups",
|
||||
"bot_guild_members",
|
||||
"bot_heal_rotation_members",
|
||||
"bot_heal_rotation_targets",
|
||||
"bot_heal_rotations",
|
||||
"bot_inspect_messages",
|
||||
"bot_inventories",
|
||||
"bot_owner_options",
|
||||
"bot_pet_buffs",
|
||||
"bot_pet_inventories",
|
||||
"bot_pets",
|
||||
"bot_spell_casting_chances",
|
||||
"bot_spell_settings",
|
||||
"bot_spells_entries",
|
||||
"bot_stances",
|
||||
"bot_timers"
|
||||
};
|
||||
}
|
||||
|
||||
static std::vector<std::string> GetMercTables()
|
||||
{
|
||||
return {
|
||||
"merc_armorinfo",
|
||||
"merc_inventory",
|
||||
"merc_merchant_entries",
|
||||
"merc_merchant_template_entries",
|
||||
"merc_merchant_templates",
|
||||
"merc_name_types",
|
||||
"merc_npc_types",
|
||||
"merc_spell_list_entries",
|
||||
"merc_spell_lists",
|
||||
"merc_stance_entries",
|
||||
"merc_stats",
|
||||
"merc_subtypes",
|
||||
"merc_templates",
|
||||
"merc_types",
|
||||
"merc_weaponinfo"
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif //EQEMU_DATABASE_SCHEMA_H
|
||||
|
||||
+2
-2
@@ -167,7 +167,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)) {
|
||||
LogMySQLQuery(
|
||||
"{0} -- ({1} row{2} returned) ({3}s)",
|
||||
"{0} ({1} row{2} returned) ({3}s)",
|
||||
query,
|
||||
requestResult.RowCount(),
|
||||
requestResult.RowCount() == 1 ? "" : "s",
|
||||
@@ -176,7 +176,7 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo
|
||||
}
|
||||
else {
|
||||
LogMySQLQuery(
|
||||
"{0} -- ({1} row{2} affected) ({3}s)",
|
||||
"{0} ({1} row{2} affected) ({3}s)",
|
||||
query,
|
||||
requestResult.RowsAffected(),
|
||||
requestResult.RowsAffected() == 1 ? "" : "s",
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
#include "discord.h"
|
||||
#include "../http/httplib.h"
|
||||
#include "../json/json.h"
|
||||
#include "../strings.h"
|
||||
#include "../eqemu_logsys.h"
|
||||
|
||||
constexpr int MAX_RETRIES = 10;
|
||||
|
||||
void Discord::SendWebhookMessage(const std::string &message, const std::string &webhook_url)
|
||||
{
|
||||
// validate
|
||||
if (webhook_url.empty()) {
|
||||
LogDiscord("[webhook_url] is empty");
|
||||
return;
|
||||
}
|
||||
|
||||
// validate
|
||||
if (webhook_url.find("http://") == std::string::npos && webhook_url.find("https://") == std::string::npos) {
|
||||
LogDiscord("[webhook_url] [{}] does not contain a valid http/s prefix.", webhook_url);
|
||||
return;
|
||||
}
|
||||
|
||||
// split
|
||||
auto s = Strings::Split(webhook_url, '/');
|
||||
|
||||
// url
|
||||
std::string base_url = fmt::format("{}//{}", s[0], s[2]);
|
||||
std::string endpoint = Strings::Replace(webhook_url, base_url, "");
|
||||
|
||||
// client
|
||||
httplib::Client cli(base_url.c_str());
|
||||
cli.set_connection_timeout(0, 15000000); // 15 sec
|
||||
cli.set_read_timeout(15, 0); // 15 seconds
|
||||
cli.set_write_timeout(15, 0); // 15 seconds
|
||||
httplib::Headers headers = {
|
||||
{"Content-Type", "application/json"}
|
||||
};
|
||||
|
||||
// payload
|
||||
Json::Value p;
|
||||
p["content"] = message;
|
||||
std::stringstream payload;
|
||||
payload << p;
|
||||
|
||||
bool retry = true;
|
||||
int retries = 0;
|
||||
int retry_timer = 1000;
|
||||
while (retry) {
|
||||
if (auto res = cli.Post(endpoint.c_str(), payload.str(), "application/json")) {
|
||||
if (res->status != 200 && res->status != 204) {
|
||||
LogError("Code [{}] Error [{}]", res->status, res->body);
|
||||
}
|
||||
if (res->status == 429) {
|
||||
if (!res->body.empty()) {
|
||||
std::stringstream ss(res->body);
|
||||
Json::Value response;
|
||||
|
||||
try {
|
||||
ss >> response;
|
||||
}
|
||||
catch (std::exception const &ex) {
|
||||
LogDiscord("JSON serialization failure [{}] via [{}]", ex.what(), res->body);
|
||||
}
|
||||
|
||||
retry_timer = std::stoi(response["retry_after"].asString()) + 500;
|
||||
}
|
||||
|
||||
LogDiscord("Rate limited... retrying message in [{}ms]", retry_timer);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(retry_timer + 500));
|
||||
}
|
||||
if (res->status == 204) {
|
||||
retry = false;
|
||||
}
|
||||
if (retries > MAX_RETRIES) {
|
||||
LogDiscord("Retries exceeded for message [{}]", message);
|
||||
retry = false;
|
||||
}
|
||||
|
||||
retries++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string Discord::FormatDiscordMessage(uint16 category_id, const std::string &message)
|
||||
{
|
||||
if (category_id == Logs::LogCategory::MySQLQuery) {
|
||||
return fmt::format("```sql\n{}\n```", message);
|
||||
}
|
||||
|
||||
return message + "\n";
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
#ifndef EQEMU_DISCORD_H
|
||||
#define EQEMU_DISCORD_H
|
||||
|
||||
|
||||
#include <string>
|
||||
#include "../types.h"
|
||||
|
||||
class Discord {
|
||||
public:
|
||||
static void SendWebhookMessage(const std::string& message, const std::string& webhook_url);
|
||||
static std::string FormatDiscordMessage(uint16 category_id, const std::string& message);
|
||||
};
|
||||
|
||||
|
||||
#endif //EQEMU_DISCORD_H
|
||||
@@ -1,69 +0,0 @@
|
||||
#include "discord_manager.h"
|
||||
#include "../common/discord/discord.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
#include "../common/strings.h"
|
||||
|
||||
void DiscordManager::QueueWebhookMessage(uint32 webhook_id, const std::string &message)
|
||||
{
|
||||
webhook_queue_lock.lock();
|
||||
webhook_message_queue[webhook_id].emplace_back(message);
|
||||
webhook_queue_lock.unlock();
|
||||
}
|
||||
|
||||
constexpr int MAX_MESSAGE_LENGTH = 1900;
|
||||
|
||||
void DiscordManager::ProcessMessageQueue()
|
||||
{
|
||||
if (webhook_message_queue.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
webhook_queue_lock.lock();
|
||||
for (auto &q: webhook_message_queue) {
|
||||
LogDiscord("Processing [{}] messages in queue for webhook ID [{}]...", q.second.size(), q.first);
|
||||
|
||||
if (q.first >= MAX_DISCORD_WEBHOOK_ID) {
|
||||
LogDiscord("Out of bounds webhook ID [{}] max [{}]", q.first, MAX_DISCORD_WEBHOOK_ID);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto webhook = LogSys.GetDiscordWebhooks()[q.first];
|
||||
std::string message;
|
||||
|
||||
for (auto &m: q.second) {
|
||||
// next message would become too large
|
||||
bool next_message_too_large = ((int) m.length() + (int) message.length()) > MAX_MESSAGE_LENGTH;
|
||||
if (next_message_too_large) {
|
||||
Discord::SendWebhookMessage(
|
||||
message,
|
||||
webhook.webhook_url
|
||||
);
|
||||
message = "";
|
||||
}
|
||||
|
||||
message += m;
|
||||
|
||||
// one single message was too large
|
||||
// this should rarely happen but the message will need to be split
|
||||
if ((int) message.length() > MAX_MESSAGE_LENGTH) {
|
||||
for (unsigned mi = 0; mi < message.length(); mi += MAX_MESSAGE_LENGTH) {
|
||||
Discord::SendWebhookMessage(
|
||||
message.substr(mi, MAX_MESSAGE_LENGTH),
|
||||
webhook.webhook_url
|
||||
);
|
||||
}
|
||||
message = "";
|
||||
}
|
||||
}
|
||||
|
||||
// final flush
|
||||
if (!message.empty()) {
|
||||
Discord::SendWebhookMessage(
|
||||
message,
|
||||
webhook.webhook_url
|
||||
);
|
||||
}
|
||||
}
|
||||
webhook_message_queue.clear();
|
||||
webhook_queue_lock.unlock();
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
#ifndef EQEMU_DISCORD_MANAGER_H
|
||||
#define EQEMU_DISCORD_MANAGER_H
|
||||
|
||||
#include <mutex>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "../common/types.h"
|
||||
|
||||
class DiscordManager {
|
||||
public:
|
||||
void QueueWebhookMessage(uint32 webhook_id, const std::string& message);
|
||||
void ProcessMessageQueue();
|
||||
private:
|
||||
std::mutex webhook_queue_lock{};
|
||||
std::map<uint32, std::vector<std::string>> webhook_message_queue{};
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
+48
-267
@@ -5,7 +5,6 @@
|
||||
#include "repositories/instance_list_player_repository.h"
|
||||
#include "rulesys.h"
|
||||
#include "servertalk.h"
|
||||
#include "util/uuid.h"
|
||||
|
||||
DynamicZoneBase::DynamicZoneBase(DynamicZonesRepository::DynamicZoneInstance&& entry)
|
||||
{
|
||||
@@ -14,12 +13,16 @@ DynamicZoneBase::DynamicZoneBase(DynamicZonesRepository::DynamicZoneInstance&& e
|
||||
|
||||
uint32_t DynamicZoneBase::Create()
|
||||
{
|
||||
if (m_id != 0)
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
if (GetInstanceID() == 0)
|
||||
{
|
||||
CreateInstance();
|
||||
}
|
||||
|
||||
m_uuid = EQ::Util::UUID::Generate().ToString();
|
||||
m_id = SaveToDatabase();
|
||||
|
||||
return m_id;
|
||||
@@ -72,14 +75,8 @@ uint32_t DynamicZoneBase::CreateInstance()
|
||||
void DynamicZoneBase::LoadRepositoryResult(DynamicZonesRepository::DynamicZoneInstance&& dz_entry)
|
||||
{
|
||||
m_id = dz_entry.id;
|
||||
m_uuid = std::move(dz_entry.uuid);
|
||||
m_name = std::move(dz_entry.name);
|
||||
m_leader.id = dz_entry.leader_id;
|
||||
m_min_players = dz_entry.min_players;
|
||||
m_max_players = dz_entry.max_players;
|
||||
m_instance_id = dz_entry.instance_id;
|
||||
m_type = static_cast<DynamicZoneType>(dz_entry.type);
|
||||
m_dz_switch_id = dz_entry.dz_switch_id;
|
||||
m_compass.zone_id = dz_entry.compass_zone_id;
|
||||
m_compass.x = dz_entry.compass_x;
|
||||
m_compass.y = dz_entry.compass_y;
|
||||
@@ -107,12 +104,6 @@ void DynamicZoneBase::AddMemberFromRepositoryResult(
|
||||
DynamicZoneMembersRepository::MemberWithName&& entry)
|
||||
{
|
||||
auto status = DynamicZoneMemberStatus::Unknown;
|
||||
|
||||
if (m_leader.id == entry.character_id)
|
||||
{
|
||||
m_leader.name = entry.character_name;
|
||||
}
|
||||
|
||||
AddInternalMember({ entry.character_id, std::move(entry.character_name), status });
|
||||
}
|
||||
|
||||
@@ -123,14 +114,8 @@ uint32_t DynamicZoneBase::SaveToDatabase()
|
||||
if (m_instance_id != 0)
|
||||
{
|
||||
auto insert_dz = DynamicZonesRepository::NewEntity();
|
||||
insert_dz.uuid = m_uuid;
|
||||
insert_dz.name = m_name;
|
||||
insert_dz.leader_id = m_leader.id;
|
||||
insert_dz.min_players = m_min_players;
|
||||
insert_dz.max_players = m_max_players;
|
||||
insert_dz.instance_id = m_instance_id,
|
||||
insert_dz.type = static_cast<int>(m_type);
|
||||
insert_dz.dz_switch_id = m_dz_switch_id;
|
||||
insert_dz.compass_zone_id = m_compass.zone_id;
|
||||
insert_dz.compass_x = m_compass.x;
|
||||
insert_dz.compass_y = m_compass.y;
|
||||
@@ -152,80 +137,34 @@ uint32_t DynamicZoneBase::SaveToDatabase()
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool DynamicZoneBase::AddMember(const DynamicZoneMember& add_member)
|
||||
void DynamicZoneBase::AddCharacter(uint32_t character_id)
|
||||
{
|
||||
if (HasMember(add_member.id))
|
||||
DynamicZoneMembersRepository::AddMember(GetDatabase(), m_id, character_id);
|
||||
GetDatabase().AddClientToInstance(m_instance_id, character_id);
|
||||
SendInstanceAddRemoveCharacter(character_id, false); // stops client kick timer
|
||||
}
|
||||
|
||||
void DynamicZoneBase::RemoveCharacter(uint32_t character_id)
|
||||
{
|
||||
DynamicZoneMembersRepository::RemoveMember(GetDatabase(), m_id, character_id);
|
||||
GetDatabase().RemoveClientFromInstance(m_instance_id, character_id);
|
||||
SendInstanceAddRemoveCharacter(character_id, true); // start client kick timer
|
||||
}
|
||||
|
||||
void DynamicZoneBase::RemoveAllCharacters(bool enable_removal_timers)
|
||||
{
|
||||
if (GetInstanceID() == 0)
|
||||
{
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
DynamicZoneMembersRepository::AddMember(GetDatabase(), m_id, add_member.id);
|
||||
GetDatabase().AddClientToInstance(m_instance_id, add_member.id);
|
||||
|
||||
ProcessMemberAddRemove(add_member, false);
|
||||
SendServerPacket(CreateServerMemberAddRemovePacket(add_member, false).get());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DynamicZoneBase::RemoveMember(uint32_t character_id)
|
||||
{
|
||||
auto remove_member = GetMemberData(character_id);
|
||||
return RemoveMember(remove_member);
|
||||
}
|
||||
|
||||
bool DynamicZoneBase::RemoveMember(const std::string& character_name)
|
||||
{
|
||||
auto remove_member = GetMemberData(character_name);
|
||||
return RemoveMember(remove_member);
|
||||
}
|
||||
|
||||
bool DynamicZoneBase::RemoveMember(const DynamicZoneMember& remove_member)
|
||||
{
|
||||
if (remove_member.id == 0)
|
||||
if (enable_removal_timers)
|
||||
{
|
||||
return false;
|
||||
SendInstanceRemoveAllCharacters();
|
||||
}
|
||||
|
||||
DynamicZoneMembersRepository::RemoveMember(GetDatabase(), m_id, remove_member.id);
|
||||
GetDatabase().RemoveClientFromInstance(m_instance_id, remove_member.id);
|
||||
|
||||
ProcessMemberAddRemove(remove_member, true);
|
||||
SendServerPacket(CreateServerMemberAddRemovePacket(remove_member, true).get());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DynamicZoneBase::SwapMember(
|
||||
const DynamicZoneMember& add_member, const std::string& remove_char_name)
|
||||
{
|
||||
auto remove_member = GetMemberData(remove_char_name);
|
||||
if (!add_member.IsValid() || !remove_member.IsValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// make remove and add atomic to avoid racing with separate world messages
|
||||
DynamicZoneMembersRepository::RemoveMember(GetDatabase(), m_id, remove_member.id);
|
||||
GetDatabase().RemoveClientFromInstance(m_instance_id, remove_member.id);
|
||||
|
||||
DynamicZoneMembersRepository::AddMember(GetDatabase(), m_id, add_member.id);
|
||||
GetDatabase().AddClientToInstance(m_instance_id, add_member.id);
|
||||
|
||||
ProcessMemberAddRemove(remove_member, true);
|
||||
ProcessMemberAddRemove(add_member, false);
|
||||
SendServerPacket(CreateServerMemberSwapPacket(remove_member, add_member).get());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DynamicZoneBase::RemoveAllMembers()
|
||||
{
|
||||
DynamicZoneMembersRepository::RemoveAllMembers(GetDatabase(), m_id);
|
||||
GetDatabase().RemoveClientsFromInstance(GetInstanceID());
|
||||
|
||||
ProcessRemoveAllMembers();
|
||||
SendServerPacket(CreateServerRemoveAllMembersPacket().get());
|
||||
}
|
||||
|
||||
void DynamicZoneBase::SaveMembers(const std::vector<DynamicZoneMember>& members)
|
||||
@@ -242,6 +181,7 @@ void DynamicZoneBase::SaveMembers(const std::vector<DynamicZoneMember>& members)
|
||||
DynamicZoneMembersRepository::DynamicZoneMembers member_entry{};
|
||||
member_entry.dynamic_zone_id = m_id;
|
||||
member_entry.character_id = member.id;
|
||||
member_entry.is_current_member = true;
|
||||
insert_members.emplace_back(member_entry);
|
||||
|
||||
InstanceListPlayerRepository::InstanceListPlayer player_entry;
|
||||
@@ -266,7 +206,7 @@ void DynamicZoneBase::SetCompass(const DynamicZoneLocation& location, bool updat
|
||||
DynamicZonesRepository::UpdateCompass(GetDatabase(),
|
||||
m_id, m_compass.zone_id, m_compass.x, m_compass.y, m_compass.z);
|
||||
|
||||
SendServerPacket(CreateServerDzLocationPacket(ServerOP_DzSetCompass, location).get());
|
||||
SendGlobalLocationChange(ServerOP_DzSetCompass, location);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,7 +227,7 @@ void DynamicZoneBase::SetSafeReturn(const DynamicZoneLocation& location, bool up
|
||||
DynamicZonesRepository::UpdateSafeReturn(GetDatabase(), m_id, m_safereturn.zone_id,
|
||||
m_safereturn.x, m_safereturn.y, m_safereturn.z, m_safereturn.heading);
|
||||
|
||||
SendServerPacket(CreateServerDzLocationPacket(ServerOP_DzSetSafeReturn, location).get());
|
||||
SendGlobalLocationChange(ServerOP_DzSetSafeReturn, location);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,7 +249,7 @@ void DynamicZoneBase::SetZoneInLocation(const DynamicZoneLocation& location, boo
|
||||
DynamicZonesRepository::UpdateZoneIn(GetDatabase(), m_id, m_zone_id,
|
||||
m_zonein.x, m_zonein.y, m_zonein.z, m_zonein.heading, m_has_zonein);
|
||||
|
||||
SendServerPacket(CreateServerDzLocationPacket(ServerOP_DzSetZoneIn, location).get());
|
||||
SendGlobalLocationChange(ServerOP_DzSetZoneIn, location);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,82 +258,35 @@ void DynamicZoneBase::SetZoneInLocation(float x, float y, float z, float heading
|
||||
SetZoneInLocation({ 0, x, y, z, heading }, update_db);
|
||||
}
|
||||
|
||||
void DynamicZoneBase::SetSwitchID(int dz_switch_id, bool update_db)
|
||||
{
|
||||
m_dz_switch_id = dz_switch_id;
|
||||
|
||||
if (update_db)
|
||||
{
|
||||
DynamicZonesRepository::UpdateSwitchID(GetDatabase(), m_id, dz_switch_id);
|
||||
SendServerPacket(CreateServerDzSwitchIDPacket().get());
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicZoneBase::SetLeader(const DynamicZoneMember& new_leader, bool update_db)
|
||||
{
|
||||
m_leader = new_leader;
|
||||
|
||||
if (update_db)
|
||||
{
|
||||
DynamicZonesRepository::UpdateLeaderID(GetDatabase(), m_id, new_leader.id);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t DynamicZoneBase::GetSecondsRemaining() const
|
||||
{
|
||||
auto remaining = std::chrono::duration_cast<std::chrono::seconds>(GetDurationRemaining()).count();
|
||||
return std::max(0, static_cast<int>(remaining));
|
||||
}
|
||||
|
||||
std::unique_ptr<ServerPacket> DynamicZoneBase::CreateServerMemberAddRemovePacket(
|
||||
const DynamicZoneMember& member, bool removed)
|
||||
std::unique_ptr<ServerPacket> DynamicZoneBase::CreateServerAddRemoveCharacterPacket(
|
||||
uint32_t character_id, bool removed)
|
||||
{
|
||||
constexpr uint32_t pack_size = sizeof(ServerDzMember_Struct);
|
||||
auto pack = std::make_unique<ServerPacket>(ServerOP_DzAddRemoveMember, pack_size);
|
||||
auto buf = reinterpret_cast<ServerDzMember_Struct*>(pack->pBuffer);
|
||||
buf->dz_id = GetID();
|
||||
buf->dz_zone_id = GetZoneID();
|
||||
buf->dz_instance_id = GetInstanceID();
|
||||
buf->sender_zone_id = GetCurrentZoneID();
|
||||
buf->sender_instance_id = GetCurrentInstanceID();
|
||||
buf->removed = removed;
|
||||
buf->character_id = member.id;
|
||||
buf->character_status = static_cast<uint8_t>(member.status);
|
||||
strn0cpy(buf->character_name, member.name.c_str(), sizeof(buf->character_name));
|
||||
constexpr uint32_t pack_size = sizeof(ServerDzCharacter_Struct);
|
||||
auto pack = std::make_unique<ServerPacket>(ServerOP_DzAddRemoveCharacter, pack_size);
|
||||
auto buf = reinterpret_cast<ServerDzCharacter_Struct*>(pack->pBuffer);
|
||||
buf->zone_id = GetZoneID();
|
||||
buf->instance_id = GetInstanceID();
|
||||
buf->remove = removed;
|
||||
buf->character_id = character_id;
|
||||
|
||||
return pack;
|
||||
}
|
||||
|
||||
std::unique_ptr<ServerPacket> DynamicZoneBase::CreateServerMemberSwapPacket(
|
||||
const DynamicZoneMember& remove_member, const DynamicZoneMember& add_member)
|
||||
std::unique_ptr<ServerPacket> DynamicZoneBase::CreateServerRemoveAllCharactersPacket()
|
||||
{
|
||||
constexpr uint32_t pack_size = sizeof(ServerDzMemberSwap_Struct);
|
||||
auto pack = std::make_unique<ServerPacket>(ServerOP_DzSwapMembers, pack_size);
|
||||
auto buf = reinterpret_cast<ServerDzMemberSwap_Struct*>(pack->pBuffer);
|
||||
buf->dz_id = GetID();
|
||||
buf->dz_zone_id = GetZoneID();
|
||||
buf->dz_instance_id = GetInstanceID();
|
||||
buf->sender_zone_id = GetCurrentZoneID();
|
||||
buf->sender_instance_id = GetCurrentInstanceID();
|
||||
buf->add_character_status = static_cast<uint8_t>(add_member.status);
|
||||
buf->add_character_id = add_member.id;
|
||||
buf->remove_character_id = remove_member.id;
|
||||
strn0cpy(buf->add_character_name, add_member.name.c_str(), sizeof(buf->add_character_name));
|
||||
strn0cpy(buf->remove_character_name, remove_member.name.c_str(), sizeof(buf->remove_character_name));
|
||||
|
||||
return pack;
|
||||
}
|
||||
|
||||
std::unique_ptr<ServerPacket> DynamicZoneBase::CreateServerRemoveAllMembersPacket()
|
||||
{
|
||||
constexpr uint32_t pack_size = sizeof(ServerDzID_Struct);
|
||||
auto pack = std::make_unique<ServerPacket>(ServerOP_DzRemoveAllMembers, pack_size);
|
||||
auto buf = reinterpret_cast<ServerDzID_Struct*>(pack->pBuffer);
|
||||
buf->dz_id = GetID();
|
||||
buf->dz_zone_id = GetZoneID();
|
||||
buf->dz_instance_id = GetInstanceID();
|
||||
buf->sender_zone_id = GetCurrentZoneID();
|
||||
buf->sender_instance_id = GetCurrentInstanceID();
|
||||
constexpr uint32_t pack_size = sizeof(ServerDzCharacter_Struct);
|
||||
auto pack = std::make_unique<ServerPacket>(ServerOP_DzRemoveAllCharacters, pack_size);
|
||||
auto buf = reinterpret_cast<ServerDzCharacter_Struct*>(pack->pBuffer);
|
||||
buf->zone_id = GetZoneID();
|
||||
buf->instance_id = GetInstanceID();
|
||||
buf->remove = true;
|
||||
buf->character_id = 0;
|
||||
|
||||
return pack;
|
||||
}
|
||||
@@ -416,36 +309,10 @@ std::unique_ptr<ServerPacket> DynamicZoneBase::CreateServerDzLocationPacket(
|
||||
return pack;
|
||||
}
|
||||
|
||||
std::unique_ptr<ServerPacket> DynamicZoneBase::CreateServerDzSwitchIDPacket()
|
||||
{
|
||||
constexpr uint32_t pack_size = sizeof(ServerDzSwitchID_Struct);
|
||||
auto pack = std::make_unique<ServerPacket>(ServerOP_DzSetSwitchID, pack_size);
|
||||
auto buf = reinterpret_cast<ServerDzSwitchID_Struct*>(pack->pBuffer);
|
||||
buf->dz_id = GetID();
|
||||
buf->dz_switch_id = GetSwitchID();
|
||||
|
||||
return pack;
|
||||
}
|
||||
|
||||
std::unique_ptr<ServerPacket> DynamicZoneBase::CreateServerMemberStatusPacket(
|
||||
uint32_t character_id, DynamicZoneMemberStatus status)
|
||||
{
|
||||
constexpr uint32_t pack_size = sizeof(ServerDzMemberStatus_Struct);
|
||||
auto pack = std::make_unique<ServerPacket>(ServerOP_DzUpdateMemberStatus, pack_size);
|
||||
auto buf = reinterpret_cast<ServerDzMemberStatus_Struct*>(pack->pBuffer);
|
||||
buf->dz_id = GetID();
|
||||
buf->sender_zone_id = GetCurrentZoneID();
|
||||
buf->sender_instance_id = GetCurrentInstanceID();
|
||||
buf->status = static_cast<uint8_t>(status);
|
||||
buf->character_id = character_id;
|
||||
|
||||
return pack;
|
||||
}
|
||||
|
||||
uint32_t DynamicZoneBase::GetDatabaseMemberCount()
|
||||
{
|
||||
return DynamicZoneMembersRepository::GetCountWhere(GetDatabase(),
|
||||
fmt::format("dynamic_zone_id = {}", m_id));
|
||||
fmt::format("dynamic_zone_id = {} AND is_current_member = TRUE", m_id));
|
||||
}
|
||||
|
||||
bool DynamicZoneBase::HasDatabaseMember(uint32_t character_id)
|
||||
@@ -456,7 +323,7 @@ bool DynamicZoneBase::HasDatabaseMember(uint32_t character_id)
|
||||
}
|
||||
|
||||
auto entries = DynamicZoneMembersRepository::GetWhere(GetDatabase(), fmt::format(
|
||||
"dynamic_zone_id = {} AND character_id = {}",
|
||||
"dynamic_zone_id = {} AND character_id = {} AND is_current_member = TRUE",
|
||||
m_id, character_id
|
||||
));
|
||||
|
||||
@@ -544,33 +411,6 @@ bool DynamicZoneBase::SetInternalMemberStatus(uint32_t character_id, DynamicZone
|
||||
return false;
|
||||
}
|
||||
|
||||
void DynamicZoneBase::SetMemberStatus(uint32_t character_id, DynamicZoneMemberStatus status)
|
||||
{
|
||||
auto update_member = GetMemberData(character_id);
|
||||
if (update_member.IsValid())
|
||||
{
|
||||
ProcessMemberStatusChange(character_id, status);
|
||||
SendServerPacket(CreateServerMemberStatusPacket(character_id, status).get());
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicZoneBase::ProcessMemberAddRemove(const DynamicZoneMember& member, bool removed)
|
||||
{
|
||||
if (!removed)
|
||||
{
|
||||
AddInternalMember(member);
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveInternalMember(member.id);
|
||||
}
|
||||
}
|
||||
|
||||
bool DynamicZoneBase::ProcessMemberStatusChange(uint32_t character_id, DynamicZoneMemberStatus status)
|
||||
{
|
||||
return SetInternalMemberStatus(character_id, status);
|
||||
}
|
||||
|
||||
std::string DynamicZoneBase::GetDynamicZoneTypeName(DynamicZoneType dz_type)
|
||||
{
|
||||
switch (dz_type)
|
||||
@@ -585,65 +425,6 @@ std::string DynamicZoneBase::GetDynamicZoneTypeName(DynamicZoneType dz_type)
|
||||
return "Mission";
|
||||
case DynamicZoneType::Quest:
|
||||
return "Quest";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
EQ::Net::DynamicPacket DynamicZoneBase::GetSerializedDzPacket()
|
||||
{
|
||||
EQ::Net::DynamicPacket dyn_pack;
|
||||
dyn_pack.PutSerialize(0, *this);
|
||||
|
||||
LogDynamicZonesDetail("Serialized server dz size [{}]", dyn_pack.Length());
|
||||
return dyn_pack;
|
||||
}
|
||||
|
||||
std::unique_ptr<ServerPacket> DynamicZoneBase::CreateServerDzCreatePacket(
|
||||
uint16_t origin_zone_id, uint16_t origin_instance_id)
|
||||
{
|
||||
EQ::Net::DynamicPacket dyn_pack = GetSerializedDzPacket();
|
||||
|
||||
auto pack_size = sizeof(ServerDzCreateSerialized_Struct) + dyn_pack.Length();
|
||||
auto pack = std::make_unique<ServerPacket>(ServerOP_DzCreated, static_cast<uint32_t>(pack_size));
|
||||
auto buf = reinterpret_cast<ServerDzCreateSerialized_Struct*>(pack->pBuffer);
|
||||
buf->origin_zone_id = origin_zone_id;
|
||||
buf->origin_instance_id = origin_instance_id;
|
||||
buf->cereal_size = static_cast<uint32_t>(dyn_pack.Length());
|
||||
memcpy(buf->cereal_data, dyn_pack.Data(), dyn_pack.Length());
|
||||
|
||||
return pack;
|
||||
}
|
||||
|
||||
void DynamicZoneBase::LoadSerializedDzPacket(char* cereal_data, uint32_t cereal_size)
|
||||
{
|
||||
LogDynamicZonesDetail("Deserializing server dz size [{}]", cereal_size);
|
||||
EQ::Util::MemoryStreamReader ss(cereal_data, cereal_size);
|
||||
cereal::BinaryInputArchive archive(ss);
|
||||
archive(*this);
|
||||
}
|
||||
|
||||
void DynamicZoneBase::LoadTemplate(const DynamicZoneTemplatesRepository::DynamicZoneTemplates& dz_template)
|
||||
{
|
||||
m_zone_id = dz_template.zone_id;
|
||||
m_zone_version = dz_template.zone_version;
|
||||
m_name = dz_template.name;
|
||||
m_min_players = dz_template.min_players;
|
||||
m_max_players = dz_template.max_players;
|
||||
m_duration = std::chrono::seconds(dz_template.duration_seconds);
|
||||
m_dz_switch_id = dz_template.dz_switch_id;
|
||||
m_compass.zone_id = dz_template.compass_zone_id;
|
||||
m_compass.x = dz_template.compass_x;
|
||||
m_compass.y = dz_template.compass_y;
|
||||
m_compass.z = dz_template.compass_z;
|
||||
m_safereturn.zone_id = dz_template.return_zone_id;
|
||||
m_safereturn.x = dz_template.return_x;
|
||||
m_safereturn.y = dz_template.return_y;
|
||||
m_safereturn.z = dz_template.return_z;
|
||||
m_safereturn.heading = dz_template.return_h;
|
||||
m_has_zonein = dz_template.override_zone_in;
|
||||
m_zonein.x = dz_template.zone_in_x;
|
||||
m_zonein.y = dz_template.zone_in_y;
|
||||
m_zonein.z = dz_template.zone_in_z;
|
||||
m_zonein.heading = dz_template.zone_in_h;
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
+15
-81
@@ -2,10 +2,8 @@
|
||||
#define COMMON_DYNAMIC_ZONE_BASE_H
|
||||
|
||||
#include "eq_constants.h"
|
||||
#include "net/packet.h"
|
||||
#include "repositories/dynamic_zones_repository.h"
|
||||
#include "repositories/dynamic_zone_members_repository.h"
|
||||
#include "repositories/dynamic_zone_templates_repository.h"
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
@@ -20,7 +18,7 @@ struct DynamicZoneMember
|
||||
{
|
||||
uint32_t id = 0;
|
||||
std::string name;
|
||||
DynamicZoneMemberStatus status = DynamicZoneMemberStatus::Unknown;
|
||||
DynamicZoneMemberStatus status = DynamicZoneMemberStatus::Online;
|
||||
|
||||
DynamicZoneMember() = default;
|
||||
DynamicZoneMember(uint32_t id, std::string name_)
|
||||
@@ -31,12 +29,6 @@ struct DynamicZoneMember
|
||||
bool IsOnline() const { return status == DynamicZoneMemberStatus::Online ||
|
||||
status == DynamicZoneMemberStatus::InDynamicZone; }
|
||||
bool IsValid() const { return id != 0 && !name.empty(); }
|
||||
|
||||
template<class Archive>
|
||||
void serialize(Archive& archive)
|
||||
{
|
||||
archive(id, name, status);
|
||||
}
|
||||
};
|
||||
|
||||
struct DynamicZoneLocation
|
||||
@@ -50,12 +42,6 @@ struct DynamicZoneLocation
|
||||
DynamicZoneLocation() = default;
|
||||
DynamicZoneLocation(uint32_t zone_id_, float x_, float y_, float z_, float heading_)
|
||||
: zone_id(zone_id_), x(x_), y(y_), z(z_), heading(heading_) {}
|
||||
|
||||
template<class Archive>
|
||||
void serialize(Archive& archive)
|
||||
{
|
||||
archive(zone_id, x, y, z, heading);
|
||||
}
|
||||
};
|
||||
|
||||
class DynamicZoneBase
|
||||
@@ -75,11 +61,9 @@ public:
|
||||
|
||||
virtual void SetSecondsRemaining(uint32_t seconds_remaining) = 0;
|
||||
|
||||
int GetDuration() const { return static_cast<int>(m_duration.count()); }
|
||||
uint64_t GetExpireTime() const { return std::chrono::system_clock::to_time_t(m_expire_time); }
|
||||
uint32_t GetID() const { return m_id; }
|
||||
uint16_t GetInstanceID() const { return static_cast<uint16_t>(m_instance_id); }
|
||||
uint32_t GetLeaderID() const { return m_leader.id; }
|
||||
uint32_t GetMaxPlayers() const { return m_max_players; }
|
||||
uint32_t GetMemberCount() const { return static_cast<uint32_t>(m_members.size()); }
|
||||
uint32_t GetMinPlayers() const { return m_min_players; }
|
||||
@@ -87,11 +71,9 @@ public:
|
||||
uint16_t GetZoneID() const { return static_cast<uint16_t>(m_zone_id); }
|
||||
uint32_t GetZoneIndex() const { return (m_instance_id << 16) | (m_zone_id & 0xffff); }
|
||||
uint32_t GetZoneVersion() const { return m_zone_version; }
|
||||
int GetSwitchID() const { return m_dz_switch_id; }
|
||||
DynamicZoneType GetType() const { return m_type; }
|
||||
const std::string& GetLeaderName() const { return m_leader.name; }
|
||||
const std::string& GetName() const { return m_name; }
|
||||
const std::string& GetUUID() const { return m_uuid; }
|
||||
const DynamicZoneMember& GetLeader() const { return m_leader; }
|
||||
const std::vector<DynamicZoneMember>& GetMembers() const { return m_members; }
|
||||
const DynamicZoneLocation& GetCompassLocation() const { return m_compass; }
|
||||
@@ -99,12 +81,14 @@ public:
|
||||
const DynamicZoneLocation& GetZoneInLocation() const { return m_zonein; }
|
||||
std::chrono::system_clock::duration GetDurationRemaining() const { return m_expire_time - std::chrono::system_clock::now(); }
|
||||
|
||||
bool AddMember(const DynamicZoneMember& add_member);
|
||||
void AddCharacter(uint32_t character_id);
|
||||
void AddInternalMember(const DynamicZoneMember& member);
|
||||
void AddMemberFromRepositoryResult(DynamicZoneMembersRepository::MemberWithName&& entry);
|
||||
void ClearInternalMembers() { m_members.clear(); }
|
||||
uint32_t Create();
|
||||
uint32_t GetDatabaseMemberCount();
|
||||
DynamicZoneMember GetMemberData(uint32_t character_id);
|
||||
DynamicZoneMember GetMemberData(const std::string& character_name);
|
||||
EQ::Net::DynamicPacket GetSerializedDzPacket();
|
||||
bool HasDatabaseMember(uint32_t character_id);
|
||||
bool HasMember(uint32_t character_id);
|
||||
bool HasMember(const std::string& character_name);
|
||||
@@ -114,56 +98,38 @@ public:
|
||||
bool IsInstanceID(uint32_t instance_id) const { return (m_instance_id != 0 && m_instance_id == instance_id); }
|
||||
bool IsValid() const { return m_instance_id != 0; }
|
||||
bool IsSameDz(uint32_t zone_id, uint32_t instance_id) const { return zone_id == m_zone_id && instance_id == m_instance_id; }
|
||||
void LoadSerializedDzPacket(char* cereal_data, uint32_t cereal_size);
|
||||
void LoadTemplate(const DynamicZoneTemplatesRepository::DynamicZoneTemplates& dz_template);
|
||||
void RemoveAllMembers();
|
||||
bool RemoveMember(uint32_t character_id);
|
||||
bool RemoveMember(const std::string& character_name);
|
||||
bool RemoveMember(const DynamicZoneMember& remove_member);
|
||||
void RemoveAllCharacters(bool enable_removal_timers = true);
|
||||
void RemoveCharacter(uint32_t character_id);
|
||||
void RemoveInternalMember(uint32_t character_id);
|
||||
void SaveMembers(const std::vector<DynamicZoneMember>& members);
|
||||
void SetCompass(const DynamicZoneLocation& location, bool update_db = false);
|
||||
void SetCompass(uint32_t zone_id, float x, float y, float z, bool update_db = false);
|
||||
void SetDuration(uint32_t seconds) { m_duration = std::chrono::seconds(seconds); }
|
||||
void SetLeader(const DynamicZoneMember& leader, bool update_db = false);
|
||||
bool SetInternalMemberStatus(uint32_t character_id, DynamicZoneMemberStatus status);
|
||||
void SetLeader(const DynamicZoneMember& leader) { m_leader = leader; }
|
||||
void SetMaxPlayers(uint32_t max_players) { m_max_players = max_players; }
|
||||
void SetMemberStatus(uint32_t character_id, DynamicZoneMemberStatus status);
|
||||
void SetMinPlayers(uint32_t min_players) { m_min_players = min_players; }
|
||||
void SetName(const std::string& name) { m_name = name; }
|
||||
void SetSafeReturn(const DynamicZoneLocation& location, bool update_db = false);
|
||||
void SetSafeReturn(uint32_t zone_id, float x, float y, float z, float heading, bool update_db = false);
|
||||
void SetSwitchID(int dz_switch_id, bool update_db = false);
|
||||
void SetType(DynamicZoneType type) { m_type = type; }
|
||||
void SetUUID(std::string uuid) { m_uuid = std::move(uuid); }
|
||||
void SetZoneInLocation(const DynamicZoneLocation& location, bool update_db = false);
|
||||
void SetZoneInLocation(float x, float y, float z, float heading, bool update_db = false);
|
||||
bool SwapMember(const DynamicZoneMember& add_member, const std::string& remove_char_name);
|
||||
|
||||
protected:
|
||||
virtual uint16_t GetCurrentInstanceID() { return 0; }
|
||||
virtual uint16_t GetCurrentZoneID() { return 0; }
|
||||
virtual Database& GetDatabase() = 0;
|
||||
virtual void ProcessCompassChange(const DynamicZoneLocation& location) { m_compass = location; }
|
||||
virtual void ProcessMemberAddRemove(const DynamicZoneMember& member, bool removed);
|
||||
virtual bool ProcessMemberStatusChange(uint32_t member_id, DynamicZoneMemberStatus status);
|
||||
virtual void ProcessRemoveAllMembers(bool silent = false) { m_members.clear(); }
|
||||
virtual void ProcessSetSwitchID(int dz_switch_id) { m_dz_switch_id = dz_switch_id; }
|
||||
virtual bool SendServerPacket(ServerPacket* packet) = 0;
|
||||
virtual void SendInstanceAddRemoveCharacter(uint32_t character_id, bool remove) = 0;
|
||||
virtual void SendInstanceRemoveAllCharacters() = 0;
|
||||
virtual void SendGlobalLocationChange(uint16_t server_opcode, const DynamicZoneLocation& location) = 0;
|
||||
|
||||
void AddInternalMember(const DynamicZoneMember& member);
|
||||
uint32_t Create();
|
||||
uint32_t CreateInstance();
|
||||
void LoadRepositoryResult(DynamicZonesRepository::DynamicZoneInstance&& dz_entry);
|
||||
void RemoveInternalMember(uint32_t character_id);
|
||||
uint32_t SaveToDatabase();
|
||||
bool SetInternalMemberStatus(uint32_t character_id, DynamicZoneMemberStatus status);
|
||||
|
||||
std::unique_ptr<ServerPacket> CreateServerDzCreatePacket(uint16_t origin_zone_id, uint16_t origin_instance_id);
|
||||
std::unique_ptr<ServerPacket> CreateServerAddRemoveCharacterPacket(uint32_t character_id, bool removed);
|
||||
std::unique_ptr<ServerPacket> CreateServerRemoveAllCharactersPacket();
|
||||
std::unique_ptr<ServerPacket> CreateServerDzLocationPacket(uint16_t server_opcode, const DynamicZoneLocation& location);
|
||||
std::unique_ptr<ServerPacket> CreateServerDzSwitchIDPacket();
|
||||
std::unique_ptr<ServerPacket> CreateServerMemberAddRemovePacket(const DynamicZoneMember& member, bool removed);
|
||||
std::unique_ptr<ServerPacket> CreateServerMemberStatusPacket(uint32_t character_id, DynamicZoneMemberStatus status);
|
||||
std::unique_ptr<ServerPacket> CreateServerMemberSwapPacket(const DynamicZoneMember& remove_member, const DynamicZoneMember& add_member);
|
||||
std::unique_ptr<ServerPacket> CreateServerRemoveAllMembersPacket();
|
||||
|
||||
uint32_t m_id = 0;
|
||||
uint32_t m_zone_id = 0;
|
||||
@@ -171,12 +137,9 @@ protected:
|
||||
uint32_t m_zone_version = 0;
|
||||
uint32_t m_min_players = 0;
|
||||
uint32_t m_max_players = 0;
|
||||
int m_dz_switch_id = 0;
|
||||
bool m_never_expires = false;
|
||||
bool m_has_zonein = false;
|
||||
bool m_has_member_statuses = false;
|
||||
std::string m_name;
|
||||
std::string m_uuid;
|
||||
DynamicZoneMember m_leader;
|
||||
DynamicZoneType m_type{ DynamicZoneType::None };
|
||||
DynamicZoneLocation m_compass;
|
||||
@@ -186,35 +149,6 @@ protected:
|
||||
std::chrono::time_point<std::chrono::system_clock> m_start_time;
|
||||
std::chrono::time_point<std::chrono::system_clock> m_expire_time;
|
||||
std::vector<DynamicZoneMember> m_members;
|
||||
|
||||
public:
|
||||
template<class Archive>
|
||||
void serialize(Archive& archive)
|
||||
{
|
||||
archive(
|
||||
m_id,
|
||||
m_zone_id,
|
||||
m_instance_id,
|
||||
m_zone_version,
|
||||
m_min_players,
|
||||
m_max_players,
|
||||
m_dz_switch_id,
|
||||
m_never_expires,
|
||||
m_has_zonein,
|
||||
m_has_member_statuses,
|
||||
m_name,
|
||||
m_uuid,
|
||||
m_leader,
|
||||
m_type,
|
||||
m_compass,
|
||||
m_safereturn,
|
||||
m_zonein,
|
||||
m_duration,
|
||||
m_start_time,
|
||||
m_expire_time,
|
||||
m_members
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+4
-431
@@ -1,5 +1,5 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
|
||||
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
@@ -18,12 +18,7 @@
|
||||
*/
|
||||
|
||||
#include "emu_constants.h"
|
||||
#include "bodytypes.h"
|
||||
#include "data_verification.h"
|
||||
#include "eqemu_logsys.h"
|
||||
#include "eqemu_logsys_log_aliases.h"
|
||||
#include "languages.h"
|
||||
#include "rulesys.h"
|
||||
|
||||
|
||||
int16 EQ::invtype::GetInvTypeSize(int16 inv_type) {
|
||||
static const int16 local_array[] = {
|
||||
@@ -120,7 +115,7 @@ EQ::bug::CategoryID EQ::bug::CategoryNameToCategoryID(const char* category_name)
|
||||
return catLoNTCG;
|
||||
if (!strcmp(category_name, "Mercenaries"))
|
||||
return catMercenaries;
|
||||
|
||||
|
||||
return catOther;
|
||||
}
|
||||
|
||||
@@ -152,430 +147,8 @@ const char *EQ::constants::GetStanceName(StanceType stance_type) {
|
||||
}
|
||||
|
||||
int EQ::constants::ConvertStanceTypeToIndex(StanceType stance_type) {
|
||||
if (EQ::ValueWithin(stance_type, EQ::constants::stancePassive, EQ::constants::stanceBurnAE)) {
|
||||
if (stance_type >= EQ::constants::stancePassive && stance_type <= EQ::constants::stanceBurnAE)
|
||||
return (stance_type - EQ::constants::stancePassive);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const std::map<int, std::string>& EQ::constants::GetLanguageMap()
|
||||
{
|
||||
static const std::map<int, std::string> language_map = {
|
||||
{ LANG_COMMON_TONGUE, "Common Tongue" },
|
||||
{ LANG_BARBARIAN, "Barbarian" },
|
||||
{ LANG_ERUDIAN, "Erudian" },
|
||||
{ LANG_ELVISH, "Elvish" },
|
||||
{ LANG_DARK_ELVISH, "Dark Elvish" },
|
||||
{ LANG_DWARVISH, "Dwarvish" },
|
||||
{ LANG_TROLL, "Troll" },
|
||||
{ LANG_OGRE, "Ogre" },
|
||||
{ LANG_GNOMISH, "Gnomish" },
|
||||
{ LANG_HALFLING, "Halfling" },
|
||||
{ LANG_THIEVES_CANT, "Thieves Cant" },
|
||||
{ LANG_OLD_ERUDIAN, "Old Erudian" },
|
||||
{ LANG_ELDER_ELVISH, "Elder Elvish" },
|
||||
{ LANG_FROGLOK, "Froglok" },
|
||||
{ LANG_GOBLIN, "Goblin" },
|
||||
{ LANG_GNOLL, "Gnoll" },
|
||||
{ LANG_COMBINE_TONGUE, "Combine Tongue" },
|
||||
{ LANG_ELDER_TEIRDAL, "Elder Teirdal" },
|
||||
{ LANG_LIZARDMAN, "Lizardman" },
|
||||
{ LANG_ORCISH, "Orcish" },
|
||||
{ LANG_FAERIE, "Faerie" },
|
||||
{ LANG_DRAGON, "Dragon" },
|
||||
{ LANG_ELDER_DRAGON, "Elder Dragon" },
|
||||
{ LANG_DARK_SPEECH, "Dark Speech" },
|
||||
{ LANG_VAH_SHIR, "Vah Shir" },
|
||||
{ LANG_ALARAN, "Alaran" },
|
||||
{ LANG_HADAL, "Hadal" },
|
||||
{ LANG_UNKNOWN, "Unknown" }
|
||||
};
|
||||
|
||||
return language_map;
|
||||
}
|
||||
|
||||
std::string EQ::constants::GetLanguageName(int language_id)
|
||||
{
|
||||
if (EQ::ValueWithin(language_id, LANG_COMMON_TONGUE, LANG_UNKNOWN)) {
|
||||
return EQ::constants::GetLanguageMap().find(language_id)->second;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
const std::map<uint32, std::string>& EQ::constants::GetLDoNThemeMap()
|
||||
{
|
||||
static const std::map<uint32, std::string> ldon_theme_map = {
|
||||
{ LDoNThemes::Unused, "Unused" },
|
||||
{ LDoNThemes::GUK, "Deepest Guk" },
|
||||
{ LDoNThemes::MIR, "Miragul's Menagerie" },
|
||||
{ LDoNThemes::MMC, "Mistmoore Catacombs" },
|
||||
{ LDoNThemes::RUJ, "Rujarkian Hills" },
|
||||
{ LDoNThemes::TAK, "Takish-Hiz" },
|
||||
};
|
||||
|
||||
return ldon_theme_map;
|
||||
}
|
||||
|
||||
std::string EQ::constants::GetLDoNThemeName(uint32 theme_id)
|
||||
{
|
||||
if (EQ::ValueWithin(theme_id, LDoNThemes::Unused, LDoNThemes::TAK)) {
|
||||
return EQ::constants::GetLDoNThemeMap().find(theme_id)->second;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
const std::map<int8, std::string>& EQ::constants::GetFlyModeMap()
|
||||
{
|
||||
static const std::map<int8, std::string> flymode_map = {
|
||||
{ GravityBehavior::Ground, "Ground" },
|
||||
{ GravityBehavior::Flying, "Flying" },
|
||||
{ GravityBehavior::Levitating, "Levitating" },
|
||||
{ GravityBehavior::Water, "Water" },
|
||||
{ GravityBehavior::Floating, "Floating" },
|
||||
{ GravityBehavior::LevitateWhileRunning, "Levitating While Running" },
|
||||
};
|
||||
|
||||
return flymode_map;
|
||||
}
|
||||
|
||||
std::string EQ::constants::GetFlyModeName(int8 flymode_id)
|
||||
{
|
||||
if (EQ::ValueWithin(flymode_id, GravityBehavior::Ground, GravityBehavior::LevitateWhileRunning)) {
|
||||
return EQ::constants::GetFlyModeMap().find(flymode_id)->second;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
const std::map<bodyType, std::string>& EQ::constants::GetBodyTypeMap()
|
||||
{
|
||||
static const std::map<bodyType, std::string> bodytype_map = {
|
||||
{ BT_Humanoid, "Humanoid" },
|
||||
{ BT_Lycanthrope, "Lycanthrope" },
|
||||
{ BT_Undead, "Undead" },
|
||||
{ BT_Giant, "Giant" },
|
||||
{ BT_Construct, "Construct" },
|
||||
{ BT_Extraplanar, "Extraplanar" },
|
||||
{ BT_Magical, "Magical" },
|
||||
{ BT_SummonedUndead, "Summoned Undead" },
|
||||
{ BT_RaidGiant, "Raid Giant" },
|
||||
{ BT_RaidColdain, "Raid Coldain" },
|
||||
{ BT_NoTarget, "Untargetable" },
|
||||
{ BT_Vampire, "Vampire" },
|
||||
{ BT_Atenha_Ra, "Aten Ha Ra" },
|
||||
{ BT_Greater_Akheva, "Greater Akheva" },
|
||||
{ BT_Khati_Sha, "Khati Sha" },
|
||||
{ BT_Seru, "Seru" },
|
||||
{ BT_Grieg_Veneficus, "Grieg Veneficus" },
|
||||
{ BT_Draz_Nurakk, "Draz Nurakk" },
|
||||
{ BT_Zek, "Zek" },
|
||||
{ BT_Luggald, "Luggald" },
|
||||
{ BT_Animal, "Animal" },
|
||||
{ BT_Insect, "Insect" },
|
||||
{ BT_Monster, "Monster" },
|
||||
{ BT_Summoned, "Summoned" },
|
||||
{ BT_Plant, "Plant" },
|
||||
{ BT_Dragon, "Dragon" },
|
||||
{ BT_Summoned2, "Summoned 2" },
|
||||
{ BT_Summoned3, "Summoned 3" },
|
||||
{ BT_Dragon2, "Dragon 2" },
|
||||
{ BT_VeliousDragon, "Velious Dragon" },
|
||||
{ BT_Familiar, "Familiar" },
|
||||
{ BT_Dragon3, "Dragon 3" },
|
||||
{ BT_Boxes, "Boxes" },
|
||||
{ BT_Muramite, "Muramite" },
|
||||
{ BT_NoTarget2, "Untargetable 2" },
|
||||
{ BT_SwarmPet, "Swarm Pet" },
|
||||
{ BT_MonsterSummon, "Monster Summon" },
|
||||
{ BT_InvisMan, "Invisible Man" },
|
||||
{ BT_Special, "Special" },
|
||||
};
|
||||
|
||||
return bodytype_map;
|
||||
}
|
||||
|
||||
std::string EQ::constants::GetBodyTypeName(bodyType bodytype_id)
|
||||
{
|
||||
if (EQ::constants::GetBodyTypeMap().find(bodytype_id) != EQ::constants::GetBodyTypeMap().end()) {
|
||||
return EQ::constants::GetBodyTypeMap().find(bodytype_id)->second;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
const std::map<uint8, std::string>& EQ::constants::GetAccountStatusMap()
|
||||
{
|
||||
static const std::map<uint8, std::string> account_status_map = {
|
||||
{ AccountStatus::Player, "Player" },
|
||||
{ AccountStatus::Steward, "Steward" },
|
||||
{ AccountStatus::ApprenticeGuide, "Apprentice Guide" },
|
||||
{ AccountStatus::Guide, "Guide" },
|
||||
{ AccountStatus::QuestTroupe, "Quest Troupe" },
|
||||
{ AccountStatus::SeniorGuide, "Senior Guide" },
|
||||
{ AccountStatus::GMTester, "GM Tester" },
|
||||
{ AccountStatus::EQSupport, "EQ Support" },
|
||||
{ AccountStatus::GMStaff, "GM Staff" },
|
||||
{ AccountStatus::GMAdmin, "GM Admin" },
|
||||
{ AccountStatus::GMLeadAdmin, "GM Lead Admin" },
|
||||
{ AccountStatus::QuestMaster, "Quest Master" },
|
||||
{ AccountStatus::GMAreas, "GM Areas" },
|
||||
{ AccountStatus::GMCoder, "GM Coder" },
|
||||
{ AccountStatus::GMMgmt, "GM Mgmt" },
|
||||
{ AccountStatus::GMImpossible, "GM Impossible" },
|
||||
{ AccountStatus::Max, "GM Max" }
|
||||
};
|
||||
|
||||
return account_status_map;
|
||||
}
|
||||
|
||||
std::string EQ::constants::GetAccountStatusName(uint8 account_status)
|
||||
{
|
||||
for (
|
||||
auto status_level = EQ::constants::GetAccountStatusMap().rbegin();
|
||||
status_level != EQ::constants::GetAccountStatusMap().rend();
|
||||
++status_level
|
||||
) {
|
||||
if (account_status >= status_level->first) {
|
||||
return status_level->second;
|
||||
}
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
const std::map<uint8, std::string>& EQ::constants::GetConsiderLevelMap()
|
||||
{
|
||||
static const std::map<uint8, std::string> consider_level_map = {
|
||||
{ ConsiderLevel::Ally, "Ally" },
|
||||
{ ConsiderLevel::Warmly, "Warmly" },
|
||||
{ ConsiderLevel::Kindly, "Kindly" },
|
||||
{ ConsiderLevel::Amiably, "Amiably" },
|
||||
{ ConsiderLevel::Indifferently, "Indifferently" },
|
||||
{ ConsiderLevel::Apprehensively, "Apprehensively" },
|
||||
{ ConsiderLevel::Dubiously, "Dubiously" },
|
||||
{ ConsiderLevel::Threateningly, "Threateningly" },
|
||||
{ ConsiderLevel::Scowls, "Scowls" }
|
||||
};
|
||||
|
||||
return consider_level_map;
|
||||
}
|
||||
|
||||
std::string EQ::constants::GetConsiderLevelName(uint8 faction_consider_level)
|
||||
{
|
||||
if (EQ::constants::GetConsiderLevelMap().find(faction_consider_level) != EQ::constants::GetConsiderLevelMap().end()) {
|
||||
return EQ::constants::GetConsiderLevelMap().find(faction_consider_level)->second;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
const std::map<uint8, std::string>& EQ::constants::GetEnvironmentalDamageMap()
|
||||
{
|
||||
static const std::map<uint8, std::string> damage_type_map = {
|
||||
{ EnvironmentalDamage::Lava, "Lava" },
|
||||
{ EnvironmentalDamage::Drowning, "Drowning" },
|
||||
{ EnvironmentalDamage::Falling, "Falling" },
|
||||
{ EnvironmentalDamage::Trap, "Trap" }
|
||||
};
|
||||
|
||||
return damage_type_map;
|
||||
}
|
||||
|
||||
std::string EQ::constants::GetEnvironmentalDamageName(uint8 damage_type)
|
||||
{
|
||||
if (EQ::ValueWithin(damage_type, EnvironmentalDamage::Lava, EnvironmentalDamage::Trap)) {
|
||||
return EQ::constants::GetEnvironmentalDamageMap().find(damage_type)->second;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
const std::map<uint8, std::string>& EQ::constants::GetStuckBehaviorMap()
|
||||
{
|
||||
static const std::map<uint8, std::string> stuck_behavior_map = {
|
||||
{ StuckBehavior::RunToTarget, "Run To Target" },
|
||||
{ StuckBehavior::WarpToTarget, "Warp To Target" },
|
||||
{ StuckBehavior::TakeNoAction, "Take No Action" },
|
||||
{ StuckBehavior::EvadeCombat, "Evade Combat" }
|
||||
};
|
||||
|
||||
return stuck_behavior_map;
|
||||
}
|
||||
|
||||
std::string EQ::constants::GetStuckBehaviorName(uint8 behavior_id)
|
||||
{
|
||||
if (EQ::ValueWithin(behavior_id, StuckBehavior::RunToTarget, StuckBehavior::EvadeCombat)) {
|
||||
return EQ::constants::GetStuckBehaviorMap().find(behavior_id)->second;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
const std::map<uint8, std::string>& EQ::constants::GetSpawnAnimationMap()
|
||||
{
|
||||
static const std::map<uint8, std::string> spawn_animation_map = {
|
||||
{ SpawnAnimations::Standing, "Standing" },
|
||||
{ SpawnAnimations::Sitting, "Sitting" },
|
||||
{ SpawnAnimations::Crouching, "Crouching" },
|
||||
{ SpawnAnimations::Laying, "Laying" },
|
||||
{ SpawnAnimations::Looting, "Looting" }
|
||||
};
|
||||
|
||||
return spawn_animation_map;
|
||||
}
|
||||
|
||||
std::string EQ::constants::GetSpawnAnimationName(uint8 animation_id)
|
||||
{
|
||||
if (EQ::ValueWithin(animation_id, SpawnAnimations::Standing, SpawnAnimations::Looting)) {
|
||||
return EQ::constants::GetSpawnAnimationMap().find(animation_id)->second;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
const std::map<int, std::string>& EQ::constants::GetObjectTypeMap()
|
||||
{
|
||||
static const std::map<int, std::string> object_type_map = {
|
||||
{ ObjectTypes::SmallBag, "Small Bag" },
|
||||
{ ObjectTypes::LargeBag, "Large Bag" },
|
||||
{ ObjectTypes::Quiver, "Quiver" },
|
||||
{ ObjectTypes::BeltPouch, "Belt Pouch" },
|
||||
{ ObjectTypes::WristPouch, "Wrist Pouch" },
|
||||
{ ObjectTypes::Backpack, "Backpack" },
|
||||
{ ObjectTypes::SmallChest, "Small Chest" },
|
||||
{ ObjectTypes::LargeChest, "Large Chest" },
|
||||
{ ObjectTypes::Bandolier, "Bandolier" },
|
||||
{ ObjectTypes::Medicine, "Medicine" },
|
||||
{ ObjectTypes::Tinkering, "Tinkering" },
|
||||
{ ObjectTypes::Lexicon, "Lexicon" },
|
||||
{ ObjectTypes::PoisonMaking, "Mortar and Pestle" },
|
||||
{ ObjectTypes::Quest, "Quest" },
|
||||
{ ObjectTypes::MixingBowl, "Mixing Bowl" },
|
||||
{ ObjectTypes::Baking, "Baking" },
|
||||
{ ObjectTypes::Tailoring, "Tailoring" },
|
||||
{ ObjectTypes::Blacksmithing, "Blacksmithing" },
|
||||
{ ObjectTypes::Fletching, "Fletching" },
|
||||
{ ObjectTypes::Brewing, "Brewing" },
|
||||
{ ObjectTypes::JewelryMaking, "Jewelry Making" },
|
||||
{ ObjectTypes::Pottery, "Pottery" },
|
||||
{ ObjectTypes::Kiln, "Kiln" },
|
||||
{ ObjectTypes::KeyMaker, "Key Maker" },
|
||||
{ ObjectTypes::ResearchWIZ, "Lexicon" },
|
||||
{ ObjectTypes::ResearchMAG, "Lexicon" },
|
||||
{ ObjectTypes::ResearchNEC, "Lexicon" },
|
||||
{ ObjectTypes::ResearchENC, "Lexicon" },
|
||||
{ ObjectTypes::Unknown, "Unknown" },
|
||||
{ ObjectTypes::ResearchPractice, "Lexicon" },
|
||||
{ ObjectTypes::Alchemy, "Alchemy" },
|
||||
{ ObjectTypes::HighElfForge, "High Elf Forge" },
|
||||
{ ObjectTypes::DarkElfForge, "Dark Elf Forge" },
|
||||
{ ObjectTypes::OgreForge, "Ogre Forge" },
|
||||
{ ObjectTypes::DwarfForge, "Dwarf Forge" },
|
||||
{ ObjectTypes::GnomeForge, "Gnome Forge" },
|
||||
{ ObjectTypes::BarbarianForge, "Barbarian Forge" },
|
||||
{ ObjectTypes::IksarForge, "Iksar Forge" },
|
||||
{ ObjectTypes::HumanForgeOne, "Human Forge" },
|
||||
{ ObjectTypes::HumanForgeTwo, "Human Forge" },
|
||||
{ ObjectTypes::HalflingTailoringOne, "Halfling Tailoring" },
|
||||
{ ObjectTypes::HalflingTailoringTwo, "Halfling Tailoring" },
|
||||
{ ObjectTypes::EruditeTailoring, "Erudite Tailoring" },
|
||||
{ ObjectTypes::WoodElfTailoring, "Wood Elf Tailoring" },
|
||||
{ ObjectTypes::WoodElfFletching, "Wood Elf Fletching" },
|
||||
{ ObjectTypes::IksarPottery, "Iksar Pottery" },
|
||||
{ ObjectTypes::Fishing, "Fishing" },
|
||||
{ ObjectTypes::TrollForge, "Troll Forge" },
|
||||
{ ObjectTypes::WoodElfForge, "Wood Elf Forge" },
|
||||
{ ObjectTypes::HalflingForge, "Halfling Forge" },
|
||||
{ ObjectTypes::EruditeForge, "Erudite Forge" },
|
||||
{ ObjectTypes::Merchant, "Merchant" },
|
||||
{ ObjectTypes::FroglokForge, "Froglok Forge" },
|
||||
{ ObjectTypes::Augmenter, "Augmenter" },
|
||||
{ ObjectTypes::Churn, "Churn" },
|
||||
{ ObjectTypes::TransformationMold, "Transformation Mold" },
|
||||
{ ObjectTypes::DetransformationMold, "Detransformation Mold" },
|
||||
{ ObjectTypes::Unattuner, "Unattuner" },
|
||||
{ ObjectTypes::TradeskillBag, "Tradeskill Bag" },
|
||||
{ ObjectTypes::CollectibleBag, "Collectible Bag" },
|
||||
{ ObjectTypes::NoDeposit, "No Deposit" }
|
||||
};
|
||||
|
||||
return object_type_map;
|
||||
}
|
||||
|
||||
std::string EQ::constants::GetObjectTypeName(int object_type)
|
||||
{
|
||||
if (EQ::ValueWithin(object_type, ObjectTypes::SmallBag, ObjectTypes::NoDeposit)) {
|
||||
return EQ::constants::GetObjectTypeMap().find(object_type)->second;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
const std::map<uint8, std::string> &EQ::constants::GetWeatherTypeMap()
|
||||
{
|
||||
static const std::map<uint8, std::string> weather_type_map = {
|
||||
{WeatherTypes::None, "None"},
|
||||
{WeatherTypes::Raining, "Raining"},
|
||||
{WeatherTypes::Snowing, "Snowing"}
|
||||
};
|
||||
|
||||
return weather_type_map;
|
||||
}
|
||||
|
||||
std::string EQ::constants::GetWeatherTypeName(uint8 weather_type)
|
||||
{
|
||||
if (EQ::ValueWithin(weather_type, WeatherTypes::None, WeatherTypes::Snowing)) {
|
||||
return EQ::constants::GetWeatherTypeMap().find(weather_type)->second;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
const std::map<uint8, std::string> &EQ::constants::GetEmoteEventTypeMap()
|
||||
{
|
||||
static const std::map<uint8, std::string> emote_event_type_map = {
|
||||
{ EmoteEventTypes::LeaveCombat, "Leave Combat" },
|
||||
{ EmoteEventTypes::EnterCombat, "Enter Combat" },
|
||||
{ EmoteEventTypes::OnDeath, "On Death" },
|
||||
{ EmoteEventTypes::AfterDeath, "After Death" },
|
||||
{ EmoteEventTypes::Hailed, "Hailed" },
|
||||
{ EmoteEventTypes::KilledPC, "Killed PC" },
|
||||
{ EmoteEventTypes::KilledNPC, "Killed NPC" },
|
||||
{ EmoteEventTypes::OnSpawn, "On Spawn" },
|
||||
{ EmoteEventTypes::OnDespawn, "On Despawn" }
|
||||
};
|
||||
|
||||
return emote_event_type_map;
|
||||
}
|
||||
|
||||
std::string EQ::constants::GetEmoteEventTypeName(uint8 emote_event_type)
|
||||
{
|
||||
if (EQ::ValueWithin(emote_event_type, EmoteEventTypes::LeaveCombat, EmoteEventTypes::OnDespawn)) {
|
||||
return EQ::constants::GetEmoteEventTypeMap().find(emote_event_type)->second;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
const std::map<uint8, std::string> &EQ::constants::GetEmoteTypeMap()
|
||||
{
|
||||
static const std::map<uint8, std::string> emote_type_map = {
|
||||
{ EmoteTypes::Emote, "Emote" },
|
||||
{ EmoteTypes::Shout, "Shout" },
|
||||
{ EmoteTypes::Proximity, "Proximity" }
|
||||
};
|
||||
|
||||
return emote_type_map;
|
||||
}
|
||||
|
||||
std::string EQ::constants::GetEmoteTypeName(uint8 emote_type)
|
||||
{
|
||||
if (EQ::ValueWithin(emote_type, EmoteTypes::Emote, EmoteTypes::Proximity)) {
|
||||
return EQ::constants::GetEmoteTypeMap().find(emote_type)->second;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
+14
-273
@@ -1,5 +1,5 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
|
||||
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
@@ -22,7 +22,6 @@
|
||||
|
||||
#include "eq_limits.h"
|
||||
#include "emu_versions.h"
|
||||
#include "bodytypes.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@@ -32,6 +31,10 @@ namespace EQ
|
||||
{
|
||||
using RoF2::IINVALID;
|
||||
using RoF2::INULL;
|
||||
|
||||
namespace inventory {
|
||||
|
||||
} /*inventory*/
|
||||
|
||||
namespace invtype {
|
||||
using namespace RoF2::invtype::enum_;
|
||||
@@ -197,7 +200,7 @@ namespace EQ
|
||||
using RoF2::constants::EXPANSIONS_MASK;
|
||||
|
||||
using RoF2::constants::CHARACTER_CREATION_LIMIT;
|
||||
|
||||
|
||||
const size_t SAY_LINK_OPENER_SIZE = 1;
|
||||
using RoF2::constants::SAY_LINK_BODY_SIZE;
|
||||
const size_t SAY_LINK_TEXT_SIZE = 256; // this may be varied until it breaks something (tested:374) - the others are constant
|
||||
@@ -217,186 +220,9 @@ namespace EQ
|
||||
stanceBurnAE
|
||||
};
|
||||
|
||||
enum BotSpellIDs : int {
|
||||
Warrior = 3001,
|
||||
Cleric,
|
||||
Paladin,
|
||||
Ranger,
|
||||
Shadowknight,
|
||||
Druid,
|
||||
Monk,
|
||||
Bard,
|
||||
Rogue,
|
||||
Shaman,
|
||||
Necromancer,
|
||||
Wizard,
|
||||
Magician,
|
||||
Enchanter,
|
||||
Beastlord,
|
||||
Berserker
|
||||
};
|
||||
|
||||
enum GravityBehavior : int8 {
|
||||
Ground,
|
||||
Flying,
|
||||
Levitating,
|
||||
Water,
|
||||
Floating,
|
||||
LevitateWhileRunning
|
||||
};
|
||||
|
||||
enum EnvironmentalDamage : uint8 {
|
||||
Lava = 250,
|
||||
Drowning,
|
||||
Falling,
|
||||
Trap
|
||||
};
|
||||
|
||||
enum StuckBehavior : uint8 {
|
||||
RunToTarget,
|
||||
WarpToTarget,
|
||||
TakeNoAction,
|
||||
EvadeCombat
|
||||
};
|
||||
|
||||
enum SpawnAnimations : uint8 {
|
||||
Standing,
|
||||
Sitting,
|
||||
Crouching,
|
||||
Laying,
|
||||
Looting
|
||||
};
|
||||
|
||||
enum ObjectTypes : int {
|
||||
SmallBag,
|
||||
LargeBag,
|
||||
Quiver,
|
||||
BeltPouch,
|
||||
WristPouch,
|
||||
Backpack,
|
||||
SmallChest,
|
||||
LargeChest,
|
||||
Bandolier,
|
||||
Medicine,
|
||||
Tinkering,
|
||||
Lexicon,
|
||||
PoisonMaking,
|
||||
Quest,
|
||||
MixingBowl,
|
||||
Baking,
|
||||
Tailoring,
|
||||
Blacksmithing,
|
||||
Fletching,
|
||||
Brewing,
|
||||
JewelryMaking,
|
||||
Pottery,
|
||||
Kiln,
|
||||
KeyMaker,
|
||||
ResearchWIZ,
|
||||
ResearchMAG,
|
||||
ResearchNEC,
|
||||
ResearchENC,
|
||||
Unknown,
|
||||
ResearchPractice,
|
||||
Alchemy,
|
||||
HighElfForge,
|
||||
DarkElfForge,
|
||||
OgreForge,
|
||||
DwarfForge,
|
||||
GnomeForge,
|
||||
BarbarianForge,
|
||||
IksarForge,
|
||||
HumanForgeOne,
|
||||
HumanForgeTwo,
|
||||
HalflingTailoringOne,
|
||||
HalflingTailoringTwo,
|
||||
EruditeTailoring,
|
||||
WoodElfTailoring,
|
||||
WoodElfFletching,
|
||||
IksarPottery,
|
||||
Fishing,
|
||||
TrollForge,
|
||||
WoodElfForge,
|
||||
HalflingForge,
|
||||
EruditeForge,
|
||||
Merchant,
|
||||
FroglokForge,
|
||||
Augmenter,
|
||||
Churn,
|
||||
TransformationMold,
|
||||
DetransformationMold,
|
||||
Unattuner,
|
||||
TradeskillBag,
|
||||
CollectibleBag,
|
||||
NoDeposit
|
||||
};
|
||||
|
||||
enum WeatherTypes : uint8 {
|
||||
None,
|
||||
Raining,
|
||||
Snowing
|
||||
};
|
||||
|
||||
enum EmoteEventTypes : uint8 {
|
||||
LeaveCombat,
|
||||
EnterCombat,
|
||||
OnDeath,
|
||||
AfterDeath,
|
||||
Hailed,
|
||||
KilledPC,
|
||||
KilledNPC,
|
||||
OnSpawn,
|
||||
OnDespawn
|
||||
};
|
||||
|
||||
enum EmoteTypes : uint8 {
|
||||
Emote,
|
||||
Shout,
|
||||
Proximity
|
||||
};
|
||||
|
||||
const char *GetStanceName(StanceType stance_type);
|
||||
int ConvertStanceTypeToIndex(StanceType stance_type);
|
||||
|
||||
extern const std::map<int, std::string>& GetLanguageMap();
|
||||
std::string GetLanguageName(int language_id);
|
||||
|
||||
extern const std::map<uint32, std::string>& GetLDoNThemeMap();
|
||||
std::string GetLDoNThemeName(uint32 theme_id);
|
||||
|
||||
extern const std::map<int8, std::string>& GetFlyModeMap();
|
||||
std::string GetFlyModeName(int8 flymode_id);
|
||||
|
||||
extern const std::map<bodyType, std::string>& GetBodyTypeMap();
|
||||
std::string GetBodyTypeName(bodyType bodytype_id);
|
||||
|
||||
extern const std::map<uint8, std::string>& GetAccountStatusMap();
|
||||
std::string GetAccountStatusName(uint8 account_status);
|
||||
|
||||
extern const std::map<uint8, std::string>& GetConsiderLevelMap();
|
||||
std::string GetConsiderLevelName(uint8 consider_level);
|
||||
|
||||
extern const std::map<uint8, std::string>& GetEnvironmentalDamageMap();
|
||||
std::string GetEnvironmentalDamageName(uint8 damage_type);
|
||||
|
||||
extern const std::map<uint8, std::string>& GetStuckBehaviorMap();
|
||||
std::string GetStuckBehaviorName(uint8 behavior_id);
|
||||
|
||||
extern const std::map<uint8, std::string>& GetSpawnAnimationMap();
|
||||
std::string GetSpawnAnimationName(uint8 animation_id);
|
||||
|
||||
extern const std::map<int, std::string>& GetObjectTypeMap();
|
||||
std::string GetObjectTypeName(int object_type);
|
||||
|
||||
extern const std::map<uint8, std::string>& GetWeatherTypeMap();
|
||||
std::string GetWeatherTypeName(uint8 weather_type);
|
||||
|
||||
extern const std::map<uint8, std::string>& GetEmoteEventTypeMap();
|
||||
std::string GetEmoteEventTypeName(uint8 emote_event_type);
|
||||
|
||||
extern const std::map<uint8, std::string>& GetEmoteTypeMap();
|
||||
std::string GetEmoteTypeName(uint8 emote_type);
|
||||
|
||||
const int STANCE_TYPE_FIRST = stancePassive;
|
||||
const int STANCE_TYPE_LAST = stanceBurnAE;
|
||||
const int STANCE_TYPE_COUNT = stanceBurnAE;
|
||||
@@ -406,7 +232,7 @@ namespace EQ
|
||||
namespace profile {
|
||||
using RoF2::profile::BANDOLIERS_SIZE;
|
||||
using RoF2::profile::BANDOLIER_ITEM_COUNT;
|
||||
|
||||
|
||||
using RoF2::profile::POTION_BELT_SIZE;
|
||||
|
||||
using RoF2::profile::SKILL_ARRAY_SIZE;
|
||||
@@ -499,98 +325,13 @@ namespace EQ
|
||||
Guild
|
||||
};
|
||||
}; // namespace consent
|
||||
|
||||
} /*EQEmu*/
|
||||
|
||||
enum ServerLockType : int {
|
||||
List,
|
||||
Lock,
|
||||
Unlock
|
||||
};
|
||||
|
||||
enum AccountStatus : uint8 {
|
||||
Player = 0,
|
||||
Steward = 10,
|
||||
ApprenticeGuide = 20,
|
||||
Guide = 50,
|
||||
QuestTroupe = 80,
|
||||
SeniorGuide = 81,
|
||||
GMTester = 85,
|
||||
EQSupport = 90,
|
||||
GMStaff = 95,
|
||||
GMAdmin = 100,
|
||||
GMLeadAdmin = 150,
|
||||
QuestMaster = 160,
|
||||
GMAreas = 170,
|
||||
GMCoder = 180,
|
||||
GMMgmt = 200,
|
||||
GMImpossible = 250,
|
||||
Max = 255
|
||||
};
|
||||
|
||||
enum Invisibility : uint8 {
|
||||
Visible,
|
||||
Invisible,
|
||||
Special = 255
|
||||
};
|
||||
|
||||
enum AugmentActions : int {
|
||||
Insert,
|
||||
Remove,
|
||||
Swap,
|
||||
Destroy
|
||||
};
|
||||
|
||||
enum ConsiderLevel : uint8 {
|
||||
Ally = 1,
|
||||
Warmly,
|
||||
Kindly,
|
||||
Amiably,
|
||||
Indifferently,
|
||||
Apprehensively,
|
||||
Dubiously,
|
||||
Threateningly,
|
||||
Scowls
|
||||
};
|
||||
|
||||
enum TargetDescriptionType : uint8 {
|
||||
LCSelf,
|
||||
UCSelf,
|
||||
LCYou,
|
||||
UCYou,
|
||||
LCYour,
|
||||
UCYour
|
||||
};
|
||||
|
||||
enum ReloadWorld : uint8 {
|
||||
NoRepop = 0,
|
||||
Repop,
|
||||
ForceRepop
|
||||
};
|
||||
|
||||
enum BucketComparison : uint8 {
|
||||
BucketEqualTo = 0,
|
||||
BucketNotEqualTo,
|
||||
BucketGreaterThanOrEqualTo,
|
||||
BucketLesserThanOrEqualTo,
|
||||
BucketGreaterThan,
|
||||
BucketLesserThan,
|
||||
BucketIsAny,
|
||||
BucketIsNotAny,
|
||||
BucketIsBetween,
|
||||
BucketIsNotBetween
|
||||
};
|
||||
|
||||
enum class EntityFilterType {
|
||||
All,
|
||||
Bots,
|
||||
Clients,
|
||||
NPCs
|
||||
};
|
||||
|
||||
enum class ApplySpellType {
|
||||
Solo,
|
||||
Group,
|
||||
Raid
|
||||
};
|
||||
|
||||
#endif /*COMMON_EMU_CONSTANTS_H*/
|
||||
|
||||
/* hack list to prevent circular references
|
||||
|
||||
eq_limits.h:EQ::inventory::LookupEntry::InventoryTypeSize[n];
|
||||
|
||||
*/
|
||||
|
||||
+5
-23
@@ -35,7 +35,7 @@ N(OP_AltCurrencyMerchantRequest),
|
||||
N(OP_AltCurrencyPurchase),
|
||||
N(OP_AltCurrencyReclaim),
|
||||
N(OP_AltCurrencySell),
|
||||
N(OP_AltCurrencySellSelection), // Used by eqstr_us.txt 8066, 8068, 8069
|
||||
N(OP_AltCurrencySellSelection),
|
||||
N(OP_Animation),
|
||||
N(OP_AnnoyingZoneUnknown),
|
||||
N(OP_ApplyPoison),
|
||||
@@ -71,7 +71,6 @@ N(OP_Camp),
|
||||
N(OP_CancelSneakHide),
|
||||
N(OP_CancelTask),
|
||||
N(OP_CancelTrade),
|
||||
N(OP_CashReward),
|
||||
N(OP_CastSpell),
|
||||
N(OP_ChangeSize),
|
||||
N(OP_ChannelMessage),
|
||||
@@ -130,8 +129,8 @@ N(OP_DisciplineTimer),
|
||||
N(OP_DisciplineUpdate),
|
||||
N(OP_DiscordMerchantInventory),
|
||||
N(OP_DoGroupLeadershipAbility),
|
||||
N(OP_DuelDecline),
|
||||
N(OP_DuelAccept),
|
||||
N(OP_DuelResponse),
|
||||
N(OP_DuelResponse2),
|
||||
N(OP_DumpName),
|
||||
N(OP_Dye),
|
||||
N(OP_DynamicWall),
|
||||
@@ -304,7 +303,6 @@ N(OP_LockoutTimerInfo),
|
||||
N(OP_Login),
|
||||
N(OP_LoginAccepted),
|
||||
N(OP_LoginComplete),
|
||||
N(OP_LoginExpansionPacketData), //added for Rof2 client to send expansion data packet. Requires login_opcodes_sod.conf to be updated.
|
||||
N(OP_LoginUnknown1),
|
||||
N(OP_LoginUnknown2),
|
||||
N(OP_Logout),
|
||||
@@ -357,6 +355,7 @@ N(OP_OpenContainer),
|
||||
N(OP_OpenDiscordMerchant),
|
||||
N(OP_OpenGuildTributeMaster),
|
||||
N(OP_OpenInventory),
|
||||
N(OP_OpenNewTasksWindow),
|
||||
N(OP_OpenTributeMaster),
|
||||
N(OP_PDeletePetition),
|
||||
N(OP_PetBuffWindow),
|
||||
@@ -457,7 +456,6 @@ N(OP_ServerListResponse),
|
||||
N(OP_SessionReady),
|
||||
N(OP_SetChatServer),
|
||||
N(OP_SetChatServer2),
|
||||
N(OP_SetFace),
|
||||
N(OP_SetGroupTarget),
|
||||
N(OP_SetGuildMOTD),
|
||||
N(OP_SetGuildRank),
|
||||
@@ -466,19 +464,6 @@ N(OP_SetServerFilter),
|
||||
N(OP_SetStartCity),
|
||||
N(OP_SetTitle),
|
||||
N(OP_SetTitleReply),
|
||||
N(OP_SharedTaskMemberList),
|
||||
N(OP_SharedTaskAddPlayer),
|
||||
N(OP_SharedTaskRemovePlayer),
|
||||
N(OP_SharedTaskMakeLeader),
|
||||
N(OP_SharedTaskMemberInvite),
|
||||
N(OP_SharedTaskInvite),
|
||||
N(OP_SharedTaskInviteResponse),
|
||||
N(OP_SharedTaskAcceptNew),
|
||||
N(OP_SharedTaskMemberChange),
|
||||
N(OP_SharedTaskPlayerList),
|
||||
N(OP_SharedTaskSelectWindow),
|
||||
N(OP_SharedTaskQuit),
|
||||
N(OP_TaskTimers),
|
||||
N(OP_Shielding),
|
||||
N(OP_ShopDelItem),
|
||||
N(OP_ShopEnd),
|
||||
@@ -514,8 +499,7 @@ N(OP_TaskActivityComplete),
|
||||
N(OP_TaskDescription),
|
||||
N(OP_TaskHistoryReply),
|
||||
N(OP_TaskHistoryRequest),
|
||||
N(OP_TaskRequestTimer),
|
||||
N(OP_TaskSelectWindow),
|
||||
N(OP_TaskMemberList),
|
||||
N(OP_Taunt),
|
||||
N(OP_TestBuff),
|
||||
N(OP_TGB),
|
||||
@@ -561,7 +545,6 @@ N(OP_WhoAllRequest),
|
||||
N(OP_WhoAllResponse),
|
||||
N(OP_World_Client_CRC1),
|
||||
N(OP_World_Client_CRC2),
|
||||
N(OP_World_Client_CRC3),
|
||||
N(OP_WorldClientReady),
|
||||
N(OP_WorldComplete),
|
||||
N(OP_WorldLogout),
|
||||
@@ -584,5 +567,4 @@ N(OP_ZoneServerReady),
|
||||
N(OP_ZoneSpawns),
|
||||
N(OP_ZoneUnavail),
|
||||
N(OP_ResetAA),
|
||||
N(OP_UnderWorld),
|
||||
// mail and chat opcodes located in ../mail_oplist.h
|
||||
|
||||
+14
-550
@@ -65,7 +65,6 @@
|
||||
#define AT_FindBits 46 // set FindBits, whatever those are!
|
||||
#define AT_TextureType 48 // TextureType
|
||||
#define AT_FacePick 49 // Turns off face pick window? maybe ...
|
||||
#define AT_AntiCheat 51 // sent by the client randomly telling the server how long since last action has occured
|
||||
#define AT_GuildShow 52 // this is what MQ2 call sit, not sure
|
||||
#define AT_Offline 53 // Offline mode
|
||||
|
||||
@@ -198,491 +197,13 @@ namespace Chat {
|
||||
const uint16 Stun = 340;
|
||||
};
|
||||
|
||||
// generation SQL:
|
||||
// SELECT CONCAT(' constexpr uint16 ', UPPER(short_name), ' = ' , zoneidnumber, '; // ', long_name) from zone group by zoneidnumber ORDER BY zoneidnumber;
|
||||
namespace Zones {
|
||||
constexpr uint16 QEYNOS = 1; // South Qeynos
|
||||
constexpr uint16 QEYNOS2 = 2; // North Qeynos
|
||||
constexpr uint16 QRG = 3; // The Surefall Glade
|
||||
constexpr uint16 QEYTOQRG = 4; // The Qeynos Hills
|
||||
constexpr uint16 HIGHPASS = 5; // Highpass Hold
|
||||
constexpr uint16 HIGHKEEP = 6; // High Keep
|
||||
constexpr uint16 FREPORTN = 8; // North Freeport
|
||||
constexpr uint16 FREPORTW = 9; // West Freeport
|
||||
constexpr uint16 FREPORTE = 10; // East Freeport
|
||||
constexpr uint16 RUNNYEYE = 11; // The Liberated Citadel of Runnyeye
|
||||
constexpr uint16 QEY2HH1 = 12; // The Western Plains of Karana
|
||||
constexpr uint16 NORTHKARANA = 13; // The Northern Plains of Karana
|
||||
constexpr uint16 SOUTHKARANA = 14; // The Southern Plains of Karana
|
||||
constexpr uint16 EASTKARANA = 15; // Eastern Plains of Karana
|
||||
constexpr uint16 BEHOLDER = 16; // Gorge of King Xorbb
|
||||
constexpr uint16 BLACKBURROW = 17; // Blackburrow
|
||||
constexpr uint16 PAW = 18; // The Lair of the Splitpaw
|
||||
constexpr uint16 RIVERVALE = 19; // Rivervale
|
||||
constexpr uint16 KITHICOR = 20; // Kithicor Forest
|
||||
constexpr uint16 COMMONS = 21; // West Commonlands
|
||||
constexpr uint16 ECOMMONS = 22; // East Commonlands
|
||||
constexpr uint16 ERUDNINT = 23; // The Erudin Palace
|
||||
constexpr uint16 ERUDNEXT = 24; // Erudin
|
||||
constexpr uint16 NEKTULOS = 25; // The Nektulos Forest
|
||||
constexpr uint16 CSHOME = 26; // Sunset Home
|
||||
constexpr uint16 LAVASTORM = 27; // The Lavastorm Mountains
|
||||
constexpr uint16 NEKTROPOS = 28; // Nektropos
|
||||
constexpr uint16 HALAS = 29; // Halas
|
||||
constexpr uint16 EVERFROST = 30; // Everfrost Peaks
|
||||
constexpr uint16 SOLDUNGA = 31; // Solusek's Eye
|
||||
constexpr uint16 SOLDUNGB = 32; // Nagafen's Lair
|
||||
constexpr uint16 MISTY = 33; // Misty Thicket
|
||||
constexpr uint16 NRO = 34; // Northern Desert of Ro
|
||||
constexpr uint16 SRO = 35; // Southern Desert of Ro
|
||||
constexpr uint16 BEFALLEN = 36; // Befallen
|
||||
constexpr uint16 OASIS = 37; // Oasis of Marr
|
||||
constexpr uint16 TOX = 38; // Toxxulia Forest
|
||||
constexpr uint16 HOLE = 39; // The Hole
|
||||
constexpr uint16 NERIAKA = 40; // Neriak - Foreign Quarter
|
||||
constexpr uint16 NERIAKB = 41; // Neriak - Commons
|
||||
constexpr uint16 NERIAKC = 42; // Neriak - 3rd Gate
|
||||
constexpr uint16 NERIAKD = 43; // Neriak Palace
|
||||
constexpr uint16 NAJENA = 44; // Najena
|
||||
constexpr uint16 QCAT = 45; // The Qeynos Aqueduct System
|
||||
constexpr uint16 INNOTHULE = 46; // Innothule Swamp
|
||||
constexpr uint16 FEERROTT = 47; // The Feerrott
|
||||
constexpr uint16 CAZICTHULE = 48; // Accursed Temple of CazicThule
|
||||
constexpr uint16 OGGOK = 49; // Oggok
|
||||
constexpr uint16 RATHEMTN = 50; // The Rathe Mountains
|
||||
constexpr uint16 LAKERATHE = 51; // Lake Rathetear
|
||||
constexpr uint16 GROBB = 52; // Grobb
|
||||
constexpr uint16 AVIAK = 53; // Aviak Village
|
||||
constexpr uint16 GFAYDARK = 54; // The Greater Faydark
|
||||
constexpr uint16 AKANON = 55; // Ak'Anon
|
||||
constexpr uint16 STEAMFONT = 56; // Steamfont Mountains
|
||||
constexpr uint16 LFAYDARK = 57; // The Lesser Faydark
|
||||
constexpr uint16 CRUSHBONE = 58; // Crushbone
|
||||
constexpr uint16 MISTMOORE = 59; // The Castle of Mistmoore
|
||||
constexpr uint16 KALADIMA = 60; // South Kaladim
|
||||
constexpr uint16 FELWITHEA = 61; // Northern Felwithe
|
||||
constexpr uint16 FELWITHEB = 62; // Southern Felwithe
|
||||
constexpr uint16 UNREST = 63; // The Estate of Unrest
|
||||
constexpr uint16 KEDGE = 64; // Kedge Keep
|
||||
constexpr uint16 GUKTOP = 65; // The City of Guk
|
||||
constexpr uint16 GUKBOTTOM = 66; // The Ruins of Old Guk
|
||||
constexpr uint16 KALADIMB = 67; // North Kaladim
|
||||
constexpr uint16 BUTCHER = 68; // Butcherblock Mountains
|
||||
constexpr uint16 OOT = 69; // Ocean of Tears
|
||||
constexpr uint16 CAULDRON = 70; // Dagnor's Cauldron
|
||||
constexpr uint16 AIRPLANE = 71; // The Plane of Sky
|
||||
constexpr uint16 FEARPLANE = 72; // The Plane of Fear
|
||||
constexpr uint16 PERMAFROST = 73; // The Permafrost Caverns
|
||||
constexpr uint16 KERRARIDGE = 74; // Kerra Isle
|
||||
constexpr uint16 PAINEEL = 75; // Paineel
|
||||
constexpr uint16 HATEPLANE = 76; // Plane of Hate
|
||||
constexpr uint16 ARENA = 77; // The Arena
|
||||
constexpr uint16 FIELDOFBONE = 78; // The Field of Bone
|
||||
constexpr uint16 WARSLIKSWOOD = 79; // The Warsliks Woods
|
||||
constexpr uint16 SOLTEMPLE = 80; // The Temple of Solusek Ro
|
||||
constexpr uint16 DROGA = 81; // The Temple of Droga
|
||||
constexpr uint16 CABWEST = 82; // Cabilis West
|
||||
constexpr uint16 SWAMPOFNOHOPE = 83; // The Swamp of No Hope
|
||||
constexpr uint16 FIRIONA = 84; // Firiona Vie
|
||||
constexpr uint16 LAKEOFILLOMEN = 85; // Lake of Ill Omen
|
||||
constexpr uint16 DREADLANDS = 86; // The Dreadlands
|
||||
constexpr uint16 BURNINGWOOD = 87; // The Burning Wood
|
||||
constexpr uint16 KAESORA = 88; // Kaesora
|
||||
constexpr uint16 SEBILIS = 89; // The Ruins of Sebilis
|
||||
constexpr uint16 CITYMIST = 90; // The City of Mist
|
||||
constexpr uint16 SKYFIRE = 91; // The Skyfire Mountains
|
||||
constexpr uint16 FRONTIERMTNS = 92; // Frontier Mountains
|
||||
constexpr uint16 OVERTHERE = 93; // The Overthere
|
||||
constexpr uint16 EMERALDJUNGLE = 94; // The Emerald Jungle
|
||||
constexpr uint16 TRAKANON = 95; // Trakanon's Teeth
|
||||
constexpr uint16 TIMOROUS = 96; // Timorous Deep
|
||||
constexpr uint16 KURN = 97; // Kurn's Tower
|
||||
constexpr uint16 ERUDSXING = 98; // Erud's Crossing
|
||||
constexpr uint16 STONEBRUNT = 100; // The Stonebrunt Mountains
|
||||
constexpr uint16 WARRENS = 101; // The Warrens
|
||||
constexpr uint16 KARNOR = 102; // Karnor's Castle
|
||||
constexpr uint16 CHARDOK = 103; // Chardok
|
||||
constexpr uint16 DALNIR = 104; // The Crypt of Dalnir
|
||||
constexpr uint16 CHARASIS = 105; // The Howling Stones
|
||||
constexpr uint16 CABEAST = 106; // Cabilis East
|
||||
constexpr uint16 NURGA = 107; // The Mines of Nurga
|
||||
constexpr uint16 VEESHAN = 108; // Veeshan's Peak
|
||||
constexpr uint16 VEKSAR = 109; // Veksar
|
||||
constexpr uint16 ICECLAD = 110; // The Iceclad Ocean
|
||||
constexpr uint16 FROZENSHADOW = 111; // The Tower of Frozen Shadow
|
||||
constexpr uint16 VELKETOR = 112; // Velketor's Labyrinth
|
||||
constexpr uint16 KAEL = 113; // Kael Drakkel
|
||||
constexpr uint16 SKYSHRINE = 114; // Skyshrine
|
||||
constexpr uint16 THURGADINA = 115; // The City of Thurgadin
|
||||
constexpr uint16 EASTWASTES = 116; // Eastern Wastes
|
||||
constexpr uint16 COBALTSCAR = 117; // Cobaltscar
|
||||
constexpr uint16 GREATDIVIDE = 118; // The Great Divide
|
||||
constexpr uint16 WAKENING = 119; // The Wakening Land
|
||||
constexpr uint16 WESTWASTES = 120; // The Western Wastes
|
||||
constexpr uint16 CRYSTAL = 121; // The Crystal Caverns
|
||||
constexpr uint16 NECROPOLIS = 123; // Dragon Necropolis
|
||||
constexpr uint16 TEMPLEVEESHAN = 124; // The Temple of Veeshan
|
||||
constexpr uint16 SIRENS = 125; // Siren's Grotto
|
||||
constexpr uint16 MISCHIEFPLANE = 126; // The Plane of Mischief
|
||||
constexpr uint16 GROWTHPLANE = 127; // The Plane of Growth
|
||||
constexpr uint16 SLEEPER = 128; // The Sleeper's Tomb
|
||||
constexpr uint16 THURGADINB = 129; // Icewell Keep
|
||||
constexpr uint16 ERUDSXING2 = 130; // Marauders Mire
|
||||
constexpr uint16 SHADOWHAVEN = 150; // Shadow Haven
|
||||
constexpr uint16 BAZAAR = 151; // The Bazaar
|
||||
constexpr uint16 NEXUS = 152; // Nexus
|
||||
constexpr uint16 ECHO_ = 153; // The Echo Caverns
|
||||
constexpr uint16 ACRYLIA = 154; // The Acrylia Caverns
|
||||
constexpr uint16 SHARVAHL = 155; // The City of Shar Vahl
|
||||
constexpr uint16 PALUDAL = 156; // The Paludal Caverns
|
||||
constexpr uint16 FUNGUSGROVE = 157; // The Fungus Grove
|
||||
constexpr uint16 VEXTHAL = 158; // Vex Thal
|
||||
constexpr uint16 SSERU = 159; // Sanctus Seru
|
||||
constexpr uint16 KATTA = 160; // Katta Castellum
|
||||
constexpr uint16 NETHERBIAN = 161; // Netherbian Lair
|
||||
constexpr uint16 SSRATEMPLE = 162; // Ssraeshza Temple
|
||||
constexpr uint16 GRIEGSEND = 163; // Grieg's End
|
||||
constexpr uint16 THEDEEP = 164; // The Deep
|
||||
constexpr uint16 SHADEWEAVER = 165; // Shadeweaver's Thicket
|
||||
constexpr uint16 HOLLOWSHADE = 166; // Hollowshade Moor
|
||||
constexpr uint16 GRIMLING = 167; // Grimling Forest
|
||||
constexpr uint16 MSERU = 168; // Marus Seru
|
||||
constexpr uint16 LETALIS = 169; // Mons Letalis
|
||||
constexpr uint16 TWILIGHT = 170; // The Twilight Sea
|
||||
constexpr uint16 THEGREY = 171; // The Grey
|
||||
constexpr uint16 TENEBROUS = 172; // The Tenebrous Mountains
|
||||
constexpr uint16 MAIDEN = 173; // The Maiden's Eye
|
||||
constexpr uint16 DAWNSHROUD = 174; // The Dawnshroud Peaks
|
||||
constexpr uint16 SCARLET = 175; // The Scarlet Desert
|
||||
constexpr uint16 UMBRAL = 176; // The Umbral Plains
|
||||
constexpr uint16 AKHEVA = 179; // The Akheva Ruins
|
||||
constexpr uint16 ARENA2 = 180; // The Arena Two
|
||||
constexpr uint16 JAGGEDPINE = 181; // The Jaggedpine Forest
|
||||
constexpr uint16 NEDARIA = 182; // Nedaria's Landing
|
||||
constexpr uint16 TUTORIAL = 183; // EverQuest Tutorial
|
||||
constexpr uint16 LOAD = 184; // Loading Zone
|
||||
constexpr uint16 LOAD2 = 185; // New Loading Zone
|
||||
constexpr uint16 HATEPLANEB = 186; // The Plane of Hate
|
||||
constexpr uint16 SHADOWREST = 187; // Shadowrest
|
||||
constexpr uint16 TUTORIALA = 188; // The Mines of Gloomingdeep
|
||||
constexpr uint16 TUTORIALB = 189; // The Mines of Gloomingdeep
|
||||
constexpr uint16 CLZ = 190; // Loading
|
||||
constexpr uint16 CODECAY = 200; // The Crypt of Decay
|
||||
constexpr uint16 POJUSTICE = 201; // The Plane of Justice
|
||||
constexpr uint16 POKNOWLEDGE = 202; // The Plane of Knowledge
|
||||
constexpr uint16 POTRANQUILITY = 203; // The Plane of Tranquility
|
||||
constexpr uint16 PONIGHTMARE = 204; // The Plane of Nightmares
|
||||
constexpr uint16 PODISEASE = 205; // The Plane of Disease
|
||||
constexpr uint16 POINNOVATION = 206; // The Plane of Innovation
|
||||
constexpr uint16 POTORMENT = 207; // Torment, the Plane of Pain
|
||||
constexpr uint16 POVALOR = 208; // The Plane of Valor
|
||||
constexpr uint16 BOTHUNDER = 209; // Bastion of Thunder
|
||||
constexpr uint16 POSTORMS = 210; // The Plane of Storms
|
||||
constexpr uint16 HOHONORA = 211; // The Halls of Honor
|
||||
constexpr uint16 SOLROTOWER = 212; // The Tower of Solusek Ro
|
||||
constexpr uint16 POWAR = 213; // Plane of War
|
||||
constexpr uint16 POTACTICS = 214; // Drunder, the Fortress of Zek
|
||||
constexpr uint16 POAIR = 215; // The Plane of Air
|
||||
constexpr uint16 POWATER = 216; // The Plane of Water
|
||||
constexpr uint16 POFIRE = 217; // The Plane of Fire
|
||||
constexpr uint16 POEARTHA = 218; // The Plane of Earth
|
||||
constexpr uint16 POTIMEA = 219; // The Plane of Time
|
||||
constexpr uint16 HOHONORB = 220; // The Temple of Marr
|
||||
constexpr uint16 NIGHTMAREB = 221; // The Lair of Terris Thule
|
||||
constexpr uint16 POEARTHB = 222; // The Plane of Earth
|
||||
constexpr uint16 POTIMEB = 223; // The Plane of Time
|
||||
constexpr uint16 GUNTHAK = 224; // The Gulf of Gunthak
|
||||
constexpr uint16 DULAK = 225; // Dulak's Harbor
|
||||
constexpr uint16 TORGIRAN = 226; // The Torgiran Mines
|
||||
constexpr uint16 NADOX = 227; // The Crypt of Nadox
|
||||
constexpr uint16 HATESFURY = 228; // Hate's Fury
|
||||
constexpr uint16 GUKA = 229; // Deepest Guk: Cauldron of Lost Souls
|
||||
constexpr uint16 RUJA = 230; // The Rujarkian Hills: Bloodied Quarries
|
||||
constexpr uint16 TAKA = 231; // Takish-Hiz: Sunken Library
|
||||
constexpr uint16 MIRA = 232; // Miragul's Menagerie: Silent Gallery
|
||||
constexpr uint16 MMCA = 233; // Mistmoore's Catacombs: Forlorn Caverns
|
||||
constexpr uint16 GUKB = 234; // The Drowning Crypt
|
||||
constexpr uint16 RUJB = 235; // The Rujarkian Hills: Halls of War
|
||||
constexpr uint16 TAKB = 236; // Takish-Hiz: Shifting Tower
|
||||
constexpr uint16 MIRB = 237; // Miragul's Menagerie: Frozen Nightmare
|
||||
constexpr uint16 MMCB = 238; // Mistmoore's Catacombs: Dreary Grotto
|
||||
constexpr uint16 GUKC = 239; // Deepest Guk: Ancient Aqueducts
|
||||
constexpr uint16 RUJC = 240; // The Rujarkian Hills: Wind Bridges
|
||||
constexpr uint16 TAKC = 241; // Takish-Hiz: Within the Compact
|
||||
constexpr uint16 MIRC = 242; // The Spider Den
|
||||
constexpr uint16 MMCC = 243; // Mistmoore's Catacombs: Struggles within the Progeny
|
||||
constexpr uint16 GUKD = 244; // The Mushroom Grove
|
||||
constexpr uint16 RUJD = 245; // The Rujarkian Hills: Prison Break
|
||||
constexpr uint16 TAKD = 246; // Takish-Hiz: Royal Observatory
|
||||
constexpr uint16 MIRD = 247; // Miragul's Menagerie: Hushed Banquet
|
||||
constexpr uint16 MMCD = 248; // Mistmoore's Catacombs: Chambers of Eternal Affliction
|
||||
constexpr uint16 GUKE = 249; // Deepest Guk: The Curse Reborn
|
||||
constexpr uint16 RUJE = 250; // The Rujarkian Hills: Drudge Hollows
|
||||
constexpr uint16 TAKE = 251; // Takish-Hiz: River of Recollection
|
||||
constexpr uint16 MIRE = 252; // The Frosted Halls
|
||||
constexpr uint16 MMCE = 253; // Mistmoore's Catacombs: Sepulcher of the Damned
|
||||
constexpr uint16 GUKF = 254; // Deepest Guk: Chapel of the Witnesses
|
||||
constexpr uint16 RUJF = 255; // The Rujarkian Hills: Fortified Lair of the Taskmasters
|
||||
constexpr uint16 TAKF = 256; // Takish-Hiz: Sandfall Corridors
|
||||
constexpr uint16 MIRF = 257; // The Forgotten Wastes
|
||||
constexpr uint16 MMCF = 258; // Mistmoore's Catacombs: Scion Lair of Fury
|
||||
constexpr uint16 GUKG = 259; // The Root Garden
|
||||
constexpr uint16 RUJG = 260; // The Rujarkian Hills: Hidden Vale of Deceit
|
||||
constexpr uint16 TAKG = 261; // Takish-Hiz: Balancing Chamber
|
||||
constexpr uint16 MIRG = 262; // Miragul's Menagerie: Heart of the Menagerie
|
||||
constexpr uint16 MMCG = 263; // Mistmoore's Catacombs: Cesspits of Putrescence
|
||||
constexpr uint16 GUKH = 264; // Deepest Guk: Accursed Sanctuary
|
||||
constexpr uint16 RUJH = 265; // The Rujarkian Hills: Blazing Forge
|
||||
constexpr uint16 TAKH = 266; // Takish-Hiz: Sweeping Tides
|
||||
constexpr uint16 MIRH = 267; // The Morbid Laboratory
|
||||
constexpr uint16 MMCH = 268; // Mistmoore's Catacombs: Aisles of Blood
|
||||
constexpr uint16 RUJI = 269; // The Rujarkian Hills: Arena of Chance
|
||||
constexpr uint16 TAKI = 270; // Takish-Hiz: Antiquated Palace
|
||||
constexpr uint16 MIRI = 271; // The Theater of Imprisoned Horror
|
||||
constexpr uint16 MMCI = 272; // Mistmoore's Catacombs: Halls of Sanguinary Rites
|
||||
constexpr uint16 RUJJ = 273; // The Rujarkian Hills: Barracks of War
|
||||
constexpr uint16 TAKJ = 274; // Takish-Hiz: Prismatic Corridors
|
||||
constexpr uint16 MIRJ = 275; // Miragul's Menagerie: Grand Library
|
||||
constexpr uint16 MMCJ = 276; // Mistmoore's Catacombs: Infernal Sanctuary
|
||||
constexpr uint16 CHARDOKB = 277; // Chardok: The Halls of Betrayal
|
||||
constexpr uint16 SOLDUNGC = 278; // The Caverns of Exile
|
||||
constexpr uint16 ABYSMAL = 279; // The Abysmal Sea
|
||||
constexpr uint16 NATIMBI = 280; // Natimbi, the Broken Shores
|
||||
constexpr uint16 QINIMI = 281; // Qinimi, Court of Nihilia
|
||||
constexpr uint16 RIWWI = 282; // Riwwi, Coliseum of Games
|
||||
constexpr uint16 BARINDU = 283; // Barindu, Hanging Gardens
|
||||
constexpr uint16 FERUBI = 284; // Ferubi, Forgotten Temple of Taelosia
|
||||
constexpr uint16 SNPOOL = 285; // Sewers of Nihilia, Pool of Sludg
|
||||
constexpr uint16 SNLAIR = 286; // Sewers of Nihilia, Lair of Trapp
|
||||
constexpr uint16 SNPLANT = 287; // Sewers of Nihilia, Purifying Pla
|
||||
constexpr uint16 SNCREMATORY = 288; // Sewers of Nihilia, Emanating Cre
|
||||
constexpr uint16 TIPT = 289; // Tipt, Treacherous Crags
|
||||
constexpr uint16 VXED = 290; // Vxed, the Crumbling Caverns
|
||||
constexpr uint16 YXTTA = 291; // Yxtta, Pulpit of Exiles
|
||||
constexpr uint16 UQUA = 292; // Uqua, the Ocean God Chantry
|
||||
constexpr uint16 KODTAZ = 293; // Kod'Taz, Broken Trial Grounds
|
||||
constexpr uint16 IKKINZ = 294; // Ikkinz, Chambers of Transcendence
|
||||
constexpr uint16 QVIC = 295; // Qvic, Prayer Grounds of Calling
|
||||
constexpr uint16 INKTUTA = 296; // Inktu'Ta, the Unmasked Chapel
|
||||
constexpr uint16 TXEVU = 297; // Txevu, Lair of the Elite
|
||||
constexpr uint16 TACVI = 298; // Tacvi, The Broken Temple
|
||||
constexpr uint16 QVICB = 299; // Qvic, the Hidden Vault
|
||||
constexpr uint16 WALLOFSLAUGHTER = 300; // Wall of Slaughter
|
||||
constexpr uint16 BLOODFIELDS = 301; // The Bloodfields
|
||||
constexpr uint16 DRANIKSSCAR = 302; // Dranik's Scar
|
||||
constexpr uint16 CAUSEWAY = 303; // Nobles' Causeway
|
||||
constexpr uint16 CHAMBERSA = 304; // Muramite Proving Grounds
|
||||
constexpr uint16 CHAMBERSB = 305; // Muramite Proving Grounds
|
||||
constexpr uint16 CHAMBERSC = 306; // Muramite Proving Grounds
|
||||
constexpr uint16 CHAMBERSD = 307; // Muramite Proving Grounds
|
||||
constexpr uint16 CHAMBERSE = 308; // Muramite Proving Grounds
|
||||
constexpr uint16 CHAMBERSF = 309; // Muramite Proving Grounds
|
||||
constexpr uint16 PROVINGGROUNDS = 316; // Muramite Proving Grounds
|
||||
constexpr uint16 ANGUISH = 317; // Anguish, the Fallen Palace
|
||||
constexpr uint16 DRANIKHOLLOWSA = 318; // Dranik's Hollows
|
||||
constexpr uint16 DRANIKHOLLOWSB = 319; // Dranik's Hollows
|
||||
constexpr uint16 DRANIKHOLLOWSC = 320; // Dranik's Hollows
|
||||
constexpr uint16 DRANIKCATACOMBSA = 328; // Catacombs of Dranik
|
||||
constexpr uint16 DRANIKCATACOMBSB = 329; // Catacombs of Dranik
|
||||
constexpr uint16 DRANIKCATACOMBSC = 330; // Catacombs of Dranik
|
||||
constexpr uint16 DRANIKSEWERSA = 331; // Sewers of Dranik
|
||||
constexpr uint16 DRANIKSEWERSB = 332; // Sewers of Dranik
|
||||
constexpr uint16 DRANIKSEWERSC = 333; // Sewers of Dranik
|
||||
constexpr uint16 RIFTSEEKERS = 334; // Riftseekers' Sanctum
|
||||
constexpr uint16 HARBINGERS = 335; // Harbinger's Spire
|
||||
constexpr uint16 DRANIK = 336; // The Ruined City of Dranik
|
||||
constexpr uint16 BROODLANDS = 337; // The Broodlands
|
||||
constexpr uint16 STILLMOONA = 338; // Stillmoon Temple
|
||||
constexpr uint16 STILLMOONB = 339; // The Ascent
|
||||
constexpr uint16 THUNDERCREST = 340; // Thundercrest Isles
|
||||
constexpr uint16 DELVEA = 341; // Lavaspinner's Lair
|
||||
constexpr uint16 DELVEB = 342; // Tirranun's Delve
|
||||
constexpr uint16 THENEST = 343; // The Nest
|
||||
constexpr uint16 GUILDLOBBY = 344; // Guild Lobby
|
||||
constexpr uint16 GUILDHALL = 345; // Guild Hall
|
||||
constexpr uint16 BARTER = 346; // The Barter Hall
|
||||
constexpr uint16 ILLSALIN = 347; // Ruins of Illsalin
|
||||
constexpr uint16 ILLSALINA = 348; // Illsalin Marketplace
|
||||
constexpr uint16 ILLSALINB = 349; // Temple of Korlach
|
||||
constexpr uint16 ILLSALINC = 350; // The Nargil Pits
|
||||
constexpr uint16 DREADSPIRE = 351; // Dreadspire Keep
|
||||
constexpr uint16 DRACHNIDHIVE = 354; // The Hive
|
||||
constexpr uint16 DRACHNIDHIVEA = 355; // The Hatchery
|
||||
constexpr uint16 DRACHNIDHIVEB = 356; // The Cocoons
|
||||
constexpr uint16 DRACHNIDHIVEC = 357; // Queen Sendaii`s Lair
|
||||
constexpr uint16 WESTKORLACH = 358; // Stoneroot Falls
|
||||
constexpr uint16 WESTKORLACHA = 359; // Prince's Manor
|
||||
constexpr uint16 WESTKORLACHB = 360; // Caverns of the Lost
|
||||
constexpr uint16 WESTKORLACHC = 361; // Lair of the Korlach
|
||||
constexpr uint16 EASTKORLACH = 362; // The Undershore
|
||||
constexpr uint16 EASTKORLACHA = 363; // Snarlstone Dens
|
||||
constexpr uint16 SHADOWSPINE = 364; // Shadow Spine
|
||||
constexpr uint16 CORATHUS = 365; // Corathus Creep
|
||||
constexpr uint16 CORATHUSA = 366; // Sporali Caverns
|
||||
constexpr uint16 CORATHUSB = 367; // The Corathus Mines
|
||||
constexpr uint16 NEKTULOSA = 368; // Shadowed Grove
|
||||
constexpr uint16 ARCSTONE = 369; // Arcstone, Isle of Spirits
|
||||
constexpr uint16 RELIC = 370; // Relic, the Artifact City
|
||||
constexpr uint16 SKYLANCE = 371; // Skylance
|
||||
constexpr uint16 DEVASTATION = 372; // The Devastation
|
||||
constexpr uint16 DEVASTATIONA = 373; // The Seething Wall
|
||||
constexpr uint16 RAGE = 374; // Sverag, Stronghold of Rage
|
||||
constexpr uint16 RAGEA = 375; // Razorthorn, Tower of Sullon Zek
|
||||
constexpr uint16 TAKISHRUINS = 376; // Ruins of Takish-Hiz
|
||||
constexpr uint16 TAKISHRUINSA = 377; // The Root of Ro
|
||||
constexpr uint16 ELDDAR = 378; // The Elddar Forest
|
||||
constexpr uint16 ELDDARA = 379; // Tunare's Shrine
|
||||
constexpr uint16 THEATER = 380; // Theater of Blood
|
||||
constexpr uint16 THEATERA = 381; // Deathknell, Tower of Dissonance
|
||||
constexpr uint16 FREEPORTEAST = 382; // East Freeport
|
||||
constexpr uint16 FREEPORTWEST = 383; // West Freeport
|
||||
constexpr uint16 FREEPORTSEWERS = 384; // Freeport Sewers
|
||||
constexpr uint16 FREEPORTACADEMY = 385; // Academy of Arcane Sciences
|
||||
constexpr uint16 FREEPORTTEMPLE = 386; // Temple of Marr
|
||||
constexpr uint16 FREEPORTMILITIA = 387; // Freeport Militia House: My Precious
|
||||
constexpr uint16 FREEPORTARENA = 388; // Arena
|
||||
constexpr uint16 FREEPORTCITYHALL = 389; // City Hall
|
||||
constexpr uint16 FREEPORTTHEATER = 390; // Theater of the Tranquil
|
||||
constexpr uint16 FREEPORTHALL = 391; // Hall of Truth: Bounty
|
||||
constexpr uint16 NORTHRO = 392; // North Desert of Ro
|
||||
constexpr uint16 SOUTHRO = 393; // South Desert of Ro
|
||||
constexpr uint16 CRESCENT = 394; // Crescent Reach
|
||||
constexpr uint16 MOORS = 395; // Blightfire Moors
|
||||
constexpr uint16 STONEHIVE = 396; // Stone Hive
|
||||
constexpr uint16 MESA = 397; // Goru`kar Mesa
|
||||
constexpr uint16 ROOST = 398; // Blackfeather Roost
|
||||
constexpr uint16 STEPPES = 399; // The Steppes
|
||||
constexpr uint16 ICEFALL = 400; // Icefall Glacier
|
||||
constexpr uint16 VALDEHOLM = 401; // Valdeholm
|
||||
constexpr uint16 FROSTCRYPT = 402; // Frostcrypt, Throne of the Shade King
|
||||
constexpr uint16 SUNDEROCK = 403; // Sunderock Springs
|
||||
constexpr uint16 VERGALID = 404; // Vergalid Mines
|
||||
constexpr uint16 DIREWIND = 405; // Direwind Cliffs
|
||||
constexpr uint16 ASHENGATE = 406; // Ashengate, Reliquary of the Scale
|
||||
constexpr uint16 HIGHPASSHOLD = 407; // Highpass Hold
|
||||
constexpr uint16 COMMONLANDS = 408; // The Commonlands
|
||||
constexpr uint16 OCEANOFTEARS = 409; // The Ocean of Tears
|
||||
constexpr uint16 KITHFOREST = 410; // Kithicor Forest
|
||||
constexpr uint16 BEFALLENB = 411; // Befallen
|
||||
constexpr uint16 HIGHPASSKEEP = 412; // HighKeep
|
||||
constexpr uint16 INNOTHULEB = 413; // The Innothule Swamp
|
||||
constexpr uint16 TOXXULIA = 414; // Toxxulia Forest
|
||||
constexpr uint16 MISTYTHICKET = 415; // The Misty Thicket
|
||||
constexpr uint16 KATTACASTRUM = 416; // Katta Castrum
|
||||
constexpr uint16 THALASSIUS = 417; // Thalassius, the Coral Keep
|
||||
constexpr uint16 ATIIKI = 418; // Jewel of Atiiki
|
||||
constexpr uint16 ZHISZA = 419; // Zhisza, the Shissar Sanctuary
|
||||
constexpr uint16 SILYSSAR = 420; // Silyssar, New Chelsith
|
||||
constexpr uint16 SOLTERIS = 421; // Solteris, the Throne of Ro
|
||||
constexpr uint16 BARREN = 422; // Barren Coast
|
||||
constexpr uint16 BURIEDSEA = 423; // The Buried Sea
|
||||
constexpr uint16 JARDELSHOOK = 424; // Jardel's Hook
|
||||
constexpr uint16 MONKEYROCK = 425; // Monkey Rock
|
||||
constexpr uint16 SUNCREST = 426; // Suncrest Isle
|
||||
constexpr uint16 DEADBONE = 427; // Deadbone Reef
|
||||
constexpr uint16 BLACKSAIL = 428; // Blacksail Folly
|
||||
constexpr uint16 MAIDENSGRAVE = 429; // Maiden's Grave
|
||||
constexpr uint16 REDFEATHER = 430; // Redfeather Isle
|
||||
constexpr uint16 SHIPMVP = 431; // The Open Sea
|
||||
constexpr uint16 SHIPMVU = 432; // The Open Sea
|
||||
constexpr uint16 SHIPPVU = 433; // The Open Sea
|
||||
constexpr uint16 SHIPUVU = 434; // The Open Sea
|
||||
constexpr uint16 SHIPMVM = 435; // The Open Sea
|
||||
constexpr uint16 MECHANOTUS = 436; // Fortress Mechanotus
|
||||
constexpr uint16 MANSION = 437; // Meldrath's Majestic Mansion
|
||||
constexpr uint16 STEAMFACTORY = 438; // The Steam Factory
|
||||
constexpr uint16 SHIPWORKSHOP = 439; // S.H.I.P. Workshop
|
||||
constexpr uint16 GYROSPIREB = 440; // Gyrospire Beza
|
||||
constexpr uint16 GYROSPIREZ = 441; // Gyrospire Zeka
|
||||
constexpr uint16 DRAGONSCALE = 442; // Dragonscale Hills
|
||||
constexpr uint16 LOPINGPLAINS = 443; // Loping Plains
|
||||
constexpr uint16 HILLSOFSHADE = 444; // Hills of Shade
|
||||
constexpr uint16 BLOODMOON = 445; // Bloodmoon Keep
|
||||
constexpr uint16 CRYSTALLOS = 446; // Crystallos, Lair of the Awakened
|
||||
constexpr uint16 GUARDIAN = 447; // The Mechamatic Guardian
|
||||
constexpr uint16 STEAMFONTMTS = 448; // The Steamfont Mountains
|
||||
constexpr uint16 CRYPTOFSHADE = 449; // Crypt of Shade
|
||||
constexpr uint16 DRAGONSCALEB = 451; // Deepscar's Den
|
||||
constexpr uint16 OLDFIELDOFBONE = 452; // Field of Scale
|
||||
constexpr uint16 OLDKAESORAA = 453; // Kaesora Library
|
||||
constexpr uint16 OLDKAESORAB = 454; // Kaesora Hatchery
|
||||
constexpr uint16 OLDKURN = 455; // Kurn's Tower
|
||||
constexpr uint16 OLDKITHICOR = 456; // Bloody Kithicor
|
||||
constexpr uint16 OLDCOMMONS = 457; // Old Commonlands
|
||||
constexpr uint16 OLDHIGHPASS = 458; // Highpass Hold
|
||||
constexpr uint16 THEVOIDA = 459; // The Void
|
||||
constexpr uint16 THEVOIDB = 460; // The Void
|
||||
constexpr uint16 THEVOIDC = 461; // The Void
|
||||
constexpr uint16 THEVOIDD = 462; // The Void
|
||||
constexpr uint16 THEVOIDE = 463; // The Void
|
||||
constexpr uint16 THEVOIDF = 464; // The Void
|
||||
constexpr uint16 THEVOIDG = 465; // The Void
|
||||
constexpr uint16 OCEANGREENHILLS = 466; // Oceangreen Hills
|
||||
constexpr uint16 OCEANGREENVILLAGE = 467; // Oceangreen Village
|
||||
constexpr uint16 OLDBLACKBURROW = 468; // BlackBurrow
|
||||
constexpr uint16 BERTOXTEMPLE = 469; // Temple of Bertoxxulous
|
||||
constexpr uint16 DISCORD = 470; // Korafax, Home of the Riders
|
||||
constexpr uint16 DISCORDTOWER = 471; // Citadel of the Worldslayer
|
||||
constexpr uint16 OLDBLOODFIELD = 472; // Old Bloodfields
|
||||
constexpr uint16 PRECIPICEOFWAR = 473; // The Precipice of War
|
||||
constexpr uint16 OLDDRANIK = 474; // City of Dranik
|
||||
constexpr uint16 TOSKIRAKK = 475; // Toskirakk
|
||||
constexpr uint16 KORASCIAN = 476; // Korascian Warrens
|
||||
constexpr uint16 RATHECHAMBER = 477; // Rathe Council Chamber
|
||||
constexpr uint16 BRELLSREST = 480; // Brell's Rest
|
||||
constexpr uint16 FUNGALFOREST = 481; // Fungal Forest
|
||||
constexpr uint16 UNDERQUARRY = 482; // The Underquarry
|
||||
constexpr uint16 COOLINGCHAMBER = 483; // The Cooling Chamber
|
||||
constexpr uint16 SHININGCITY = 484; // Kernagir, the Shining City
|
||||
constexpr uint16 ARTHICREX = 485; // Arthicrex
|
||||
constexpr uint16 FOUNDATION = 486; // The Foundation
|
||||
constexpr uint16 LICHENCREEP = 487; // Lichen Creep
|
||||
constexpr uint16 PELLUCID = 488; // Pellucid Grotto
|
||||
constexpr uint16 STONESNAKE = 489; // Volska's Husk
|
||||
constexpr uint16 BRELLSTEMPLE = 490; // Brell's Temple
|
||||
constexpr uint16 CONVORTEUM = 491; // The Convorteum
|
||||
constexpr uint16 BRELLSARENA = 492; // Brell's Arena
|
||||
constexpr uint16 WEDDINGCHAPEL = 493; // Wedding Chapel
|
||||
constexpr uint16 WEDDINGCHAPELDARK = 494; // Wedding Chapel
|
||||
constexpr uint16 DRAGONCRYPT = 495; // Lair of the Risen
|
||||
constexpr uint16 FEERROTT2 = 700; // The Feerrott
|
||||
constexpr uint16 THULEHOUSE1 = 701; // House of Thule
|
||||
constexpr uint16 THULEHOUSE2 = 702; // House of Thule, Upper Floors
|
||||
constexpr uint16 HOUSEGARDEN = 703; // The Grounds
|
||||
constexpr uint16 THULELIBRARY = 704; // The Library
|
||||
constexpr uint16 WELL = 705; // The Well
|
||||
constexpr uint16 FALLEN = 706; // Erudin Burning
|
||||
constexpr uint16 MORELLCASTLE = 707; // Morell's Castle
|
||||
constexpr uint16 SOMNIUM = 708; // Sanctum Somnium
|
||||
constexpr uint16 ALKABORMARE = 709; // Al'Kabor's Nightmare
|
||||
constexpr uint16 MIRAGULMARE = 710; // Miragul's Nightmare
|
||||
constexpr uint16 THULEDREAM = 711; // Fear Itself
|
||||
constexpr uint16 NEIGHBORHOOD = 712; // Sunrise Hills
|
||||
constexpr uint16 ARGATH = 724; // Argath, Bastion of Illdaera
|
||||
constexpr uint16 ARELIS = 725; // Valley of Lunanyn
|
||||
constexpr uint16 SARITHCITY = 726; // Sarith, City of Tides
|
||||
constexpr uint16 RUBAK = 727; // Rubak Oseka, Temple of the Sea
|
||||
constexpr uint16 BEASTDOMAIN = 728; // Beasts' Domain
|
||||
constexpr uint16 RESPLENDENT = 729; // The Resplendent Temple
|
||||
constexpr uint16 PILLARSALRA = 730; // Pillars of Alra
|
||||
constexpr uint16 WINDSONG = 731; // Windsong Sanctuary
|
||||
constexpr uint16 CITYOFBRONZE = 732; // Erillion, City of Bronze
|
||||
constexpr uint16 SEPULCHER = 733; // Sepulcher of Order
|
||||
constexpr uint16 EASTSEPULCHER = 734; // Sepulcher East
|
||||
constexpr uint16 WESTSEPULCHER = 735; // Sepulcher West
|
||||
constexpr uint16 SHARDSLANDING = 752; // Shard's Landing
|
||||
constexpr uint16 XORBB = 753; // Valley of King Xorbb
|
||||
constexpr uint16 KAELSHARD = 754; // Kael Drakkel: The King's Madness
|
||||
constexpr uint16 EASTWASTESSHARD = 755; // East Wastes: Zeixshi-Kar's Awakening
|
||||
constexpr uint16 CRYSTALSHARD = 756; // The Crystal Caverns: Fragment of Fear
|
||||
constexpr uint16 BREEDINGGROUNDS = 757; // The Breeding Grounds
|
||||
constexpr uint16 EVILTREE = 758; // Evantil, the Vile Oak
|
||||
constexpr uint16 GRELLETH = 759; // Grelleth's Palace, the Chateau of Filth
|
||||
constexpr uint16 CHAPTERHOUSE = 760; // Chapterhouse of the Fallen
|
||||
constexpr uint16 ARTTEST = 996; // Art Testing Domain
|
||||
constexpr uint16 FHALLS = 998; // The Forgotten Halls
|
||||
constexpr uint16 APPRENTICE = 999; // Designer Apprentice
|
||||
}
|
||||
//ZoneChange_Struct->success values
|
||||
#define ZONE_ERROR_NOMSG 0
|
||||
#define ZONE_ERROR_NOTREADY -1
|
||||
#define ZONE_ERROR_VALIDPC -2
|
||||
#define ZONE_ERROR_STORYZONE -3
|
||||
#define ZONE_ERROR_NOEXPANSION -6
|
||||
#define ZONE_ERROR_NOEXPERIENCE -7
|
||||
|
||||
|
||||
typedef enum {
|
||||
@@ -710,7 +231,7 @@ typedef enum {
|
||||
FilterPetMisses = 21, //0=show, 1=hide
|
||||
FilterFocusEffects = 22, //0=show, 1=hide
|
||||
FilterPetSpells = 23, //0=show, 1=hide
|
||||
FilterHealOverTime = 24, //0=show, 1=mine only, 2=hide
|
||||
FilterHealOverTime = 24, //0=show, 1=hide
|
||||
FilterUnknown25 = 25,
|
||||
FilterUnknown26 = 26,
|
||||
FilterUnknown27 = 27,
|
||||
@@ -917,9 +438,12 @@ static const uint8 SkillDamageTypes[EQ::skills::HIGHEST_SKILL + 1] = // change t
|
||||
|
||||
static const uint32 MAX_SPELL_DB_ID_VAL = 65535;
|
||||
|
||||
static const uint32 DB_FACTION_GEM_CHOPPERS = 255;
|
||||
static const uint32 DB_FACTION_HERETICS = 265;
|
||||
static const uint32 DB_FACTION_KING_AKANON = 333;
|
||||
static const uint32 DB_SPELL_CAZIC_TOUCH = 982;
|
||||
static const uint32 DB_SPELL_TOUCH_OF_VINITRAS = 2859;
|
||||
|
||||
static const uint32 DB_FACTION_GEM_CHOPPERS = 255;
|
||||
static const uint32 DB_FACTION_HERETICS = 265;
|
||||
static const uint32 DB_FACTION_KING_AKANON = 333;
|
||||
|
||||
enum ChatChannelNames : uint16
|
||||
{
|
||||
@@ -966,64 +490,4 @@ enum class DynamicZoneMemberStatus : uint8_t
|
||||
LinkDead
|
||||
};
|
||||
|
||||
enum LDoNThemes {
|
||||
Unused = 0,
|
||||
GUK,
|
||||
MIR,
|
||||
MMC,
|
||||
RUJ,
|
||||
TAK
|
||||
};
|
||||
|
||||
enum LDoNThemeBits {
|
||||
UnusedBit = 0,
|
||||
GUKBit = 1,
|
||||
MIRBit = 2,
|
||||
MMCBit = 4,
|
||||
RUJBit = 8,
|
||||
TAKBit = 16
|
||||
};
|
||||
|
||||
enum StartZoneIndex {
|
||||
Odus = 0,
|
||||
Qeynos,
|
||||
Halas,
|
||||
Rivervale,
|
||||
Freeport,
|
||||
Neriak,
|
||||
Grobb,
|
||||
Oggok,
|
||||
Kaladim,
|
||||
GreaterFaydark,
|
||||
Felwithe,
|
||||
Akanon,
|
||||
Cabilis,
|
||||
SharVahl
|
||||
};
|
||||
|
||||
enum FVNoDropFlagRule
|
||||
{
|
||||
Disabled = 0,
|
||||
Enabled = 1,
|
||||
AdminOnly = 2
|
||||
};
|
||||
|
||||
enum Anonymity : uint8
|
||||
{
|
||||
NotAnonymous,
|
||||
Anonymous,
|
||||
Roleplaying
|
||||
};
|
||||
|
||||
enum ZoningMessage : int8
|
||||
{
|
||||
ZoneNoMessage = 0,
|
||||
ZoneSuccess = 1,
|
||||
ZoneNotReady = -1,
|
||||
ZoneValidPC = -2,
|
||||
ZoneStoryZone = -3,
|
||||
ZoneNoExpansion = -6,
|
||||
ZoneNoExperience = -7
|
||||
};
|
||||
|
||||
#endif /*COMMON_EQ_CONSTANTS_H*/
|
||||
|
||||
+16
-16
@@ -1,5 +1,5 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
|
||||
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
@@ -11,7 +11,7 @@
|
||||
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
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
static bool global_dictionary_init = false;
|
||||
void EQ::InitializeDynamicLookups() {
|
||||
if (global_dictionary_init)
|
||||
if (global_dictionary_init == true)
|
||||
return;
|
||||
|
||||
constants::InitializeDynamicLookups();
|
||||
@@ -167,7 +167,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers
|
||||
ClientUnknown::INULL, ClientUnknown::INULL, ClientUnknown::INULL,
|
||||
ClientUnknown::INULL
|
||||
),
|
||||
|
||||
|
||||
ClientUnknown::INULL,
|
||||
ClientUnknown::INULL,
|
||||
ClientUnknown::INULL,
|
||||
@@ -175,7 +175,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers
|
||||
ClientUnknown::INULL,
|
||||
ClientUnknown::INULL,
|
||||
ClientUnknown::INULL,
|
||||
|
||||
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
@@ -194,7 +194,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers
|
||||
Client62::INULL, Client62::INULL, Client62::INULL,
|
||||
Client62::INULL
|
||||
),
|
||||
|
||||
|
||||
Client62::INULL,
|
||||
Client62::INULL,
|
||||
Client62::INULL,
|
||||
@@ -202,7 +202,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers
|
||||
Client62::INULL,
|
||||
Client62::INULL,
|
||||
Client62::INULL,
|
||||
|
||||
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
@@ -221,7 +221,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers
|
||||
Titanium::INULL, Titanium::INULL, Titanium::INULL,
|
||||
Titanium::invtype::OTHER_SIZE
|
||||
),
|
||||
|
||||
|
||||
Titanium::invslot::EQUIPMENT_BITMASK,
|
||||
Titanium::invslot::GENERAL_BITMASK,
|
||||
Titanium::invslot::CURSOR_BITMASK,
|
||||
@@ -229,7 +229,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers
|
||||
Titanium::invslot::CORPSE_BITMASK,
|
||||
Titanium::invbag::SLOT_COUNT,
|
||||
Titanium::invaug::SOCKET_COUNT,
|
||||
|
||||
|
||||
Titanium::inventory::AllowEmptyBagInBag,
|
||||
Titanium::inventory::AllowClickCastFromBag,
|
||||
Titanium::inventory::ConcatenateInvTypeLimbo,
|
||||
@@ -248,7 +248,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers
|
||||
SoF::INULL, SoF::INULL, SoF::INULL,
|
||||
SoF::invtype::OTHER_SIZE
|
||||
),
|
||||
|
||||
|
||||
SoF::invslot::EQUIPMENT_BITMASK,
|
||||
SoF::invslot::GENERAL_BITMASK,
|
||||
SoF::invslot::CURSOR_BITMASK,
|
||||
@@ -256,7 +256,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers
|
||||
SoF::invslot::CORPSE_BITMASK,
|
||||
SoF::invbag::SLOT_COUNT,
|
||||
SoF::invaug::SOCKET_COUNT,
|
||||
|
||||
|
||||
SoF::inventory::AllowEmptyBagInBag,
|
||||
SoF::inventory::AllowClickCastFromBag,
|
||||
SoF::inventory::ConcatenateInvTypeLimbo,
|
||||
@@ -763,7 +763,7 @@ void EQ::inventory::InitializeDynamicLookups() {
|
||||
// Notes:
|
||||
// - Currently, there are only 3 known expansions that affect inventory-related settings in the clients..
|
||||
// -- Expansion::PoR "Prophecy of Ro" - toggles between 24 (set) and 16 (clear) bank slots
|
||||
// -- Expansion::TBS "The Buried Sea" - toggles slotPowerSource activated (set) and deactivated (clear)
|
||||
// -- Expansion::TBS "The Buried Sea" - toggles slotPowerSource activated (set) and deactivated (clear)
|
||||
// -- Expansion::HoT "House of Thule" - toggles slotGeneral9/slotGeneral10 activated (set) and deactivated (clear)
|
||||
// - Corspe size does not appear to reflect loss of active possessions slots
|
||||
// - Inspect size does not appear to reflect loss of active equipment slots
|
||||
@@ -772,7 +772,7 @@ void EQ::inventory::InitializeDynamicLookups() {
|
||||
// - General9 and General10 slots are activated by GM flag when expansion bit is (clear)
|
||||
// - Obviously, the client must support the expansion to allow any (set) or override condition
|
||||
|
||||
const uint32 dynamic_check_mask =
|
||||
const uint32 dynamic_check_mask =
|
||||
(
|
||||
EQ::expansions::bitPoR |
|
||||
EQ::expansions::bitTBS |
|
||||
@@ -1210,10 +1210,10 @@ void EQ::spells::InitializeDynamicLookups() {
|
||||
if (spells_dictionary_init == true)
|
||||
return;
|
||||
spells_dictionary_init = true;
|
||||
|
||||
|
||||
if (RuleB(World, UseClientBasedExpansionSettings))
|
||||
return;
|
||||
|
||||
|
||||
// use static references for now
|
||||
}
|
||||
|
||||
@@ -1239,7 +1239,7 @@ const EQ::spells::LookupEntry* EQ::spells::DynamicGMLookup(versions::ClientVersi
|
||||
client_version = versions::ValidateClientVersion(client_version);
|
||||
if (spells_dynamic_gm_lookup_entries[static_cast<int>(client_version)])
|
||||
return spells_dynamic_gm_lookup_entries[static_cast<int>(client_version)].get();
|
||||
|
||||
|
||||
return &spells_static_lookup_entries[static_cast<int>(client_version)];
|
||||
}
|
||||
|
||||
|
||||
+63
-151
@@ -374,19 +374,17 @@ struct NewZone_Struct {
|
||||
/*0684*/ uint16 zone_id;
|
||||
/*0686*/ uint16 zone_instance;
|
||||
/*0688*/ uint32 unknown688;
|
||||
/*0692*/ uint8 unknown692[8];
|
||||
/*0692*/ uint8 unknown692[8];
|
||||
// Titanium doesn't have a translator, but we can still safely add stuff under here without issues since client memcpy's only what it knows
|
||||
// Just wastes some bandwidth sending to tit clients /shrug
|
||||
/*0700*/ float fog_density;
|
||||
/*0704*/ uint32 suspend_buffs;
|
||||
/*0708*/ uint32 fast_regen_hp;
|
||||
/*0712*/ uint32 fast_regen_mana;
|
||||
/*0716*/ uint32 fast_regen_endurance;
|
||||
/*0720*/ uint32 npc_aggro_max_dist;
|
||||
/*0724*/ uint32 underworld_teleport_index; // > 0 teleports w/ zone point index, invalid succors, if this value is 0, it prevents you from running off edges that would end up underworld
|
||||
/*0728*/ uint32 lava_damage; // Seen 50
|
||||
/*0732*/ uint32 min_lava_damage; // Seen 10
|
||||
/*0736*/
|
||||
/*0700*/ float fog_density;
|
||||
/*0704*/ uint32 SuspendBuffs;
|
||||
/*0708*/ uint32 FastRegenHP;
|
||||
/*0712*/ uint32 FastRegenMana;
|
||||
/*0716*/ uint32 FastRegenEndurance;
|
||||
/*0720*/ uint32 NPCAggroMaxDist;
|
||||
/*0724*/ uint32 underworld_teleport_index; // > 0 teleports w/ zone point index, invalid succors, if this value is 0, it prevents you from running off edges that would end up underworld
|
||||
/*0728*/
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -448,7 +446,6 @@ struct ManaChange_Struct
|
||||
/*08*/ uint32 spell_id;
|
||||
/*12*/ uint8 keepcasting; // won't stop the cast. Change mana while casting?
|
||||
/*13*/ uint8 padding[3]; // client doesn't read it, garbage data seems like
|
||||
/*16*/ int32 slot; // -1 normal, otherwise clear ETA and GCD
|
||||
};
|
||||
|
||||
struct SwapSpell_Struct
|
||||
@@ -2134,31 +2131,31 @@ struct AdventureLeaderboard_Struct
|
||||
};*/
|
||||
|
||||
struct Illusion_Struct { //size: 256 - SoF
|
||||
/*000*/ uint32 spawnid;
|
||||
/*004*/ char charname[64]; //
|
||||
/*068*/ uint16 race; //
|
||||
/*070*/ char unknown006[2];
|
||||
/*072*/ uint8 gender;
|
||||
/*073*/ uint8 texture;
|
||||
/*074*/ uint8 unknown008; //
|
||||
/*075*/ uint8 unknown009; //
|
||||
/*076*/ uint8 helmtexture; //
|
||||
/*077*/ uint8 unknown010; //
|
||||
/*078*/ uint8 unknown011; //
|
||||
/*079*/ uint8 unknown012; //
|
||||
/*080*/ uint32 face; //
|
||||
/*084*/ uint8 hairstyle; //
|
||||
/*085*/ uint8 haircolor; //
|
||||
/*086*/ uint8 beard; //
|
||||
/*087*/ uint8 beardcolor; //
|
||||
/*088*/ float size; //
|
||||
/*092*/ uint32 drakkin_heritage; //
|
||||
/*096*/ uint32 drakkin_tattoo; //
|
||||
/*100*/ uint32 drakkin_details; //
|
||||
/*104*/ EQ::TintProfile armor_tint; //
|
||||
/*140*/ uint8 eyecolor1; // Field Not Identified in any Illusion Struct
|
||||
/*141*/ uint8 eyecolor2; // Field Not Identified in any Illusion Struct
|
||||
/*142*/ uint8 unknown138[114]; //
|
||||
/*000*/ uint32 spawnid;
|
||||
/*004*/ char charname[64]; //
|
||||
/*068*/ uint16 race; //
|
||||
/*070*/ char unknown006[2];
|
||||
/*072*/ uint8 gender;
|
||||
/*073*/ uint8 texture;
|
||||
/*074*/ uint8 unknown008; //
|
||||
/*075*/ uint8 unknown009; //
|
||||
/*076*/ uint8 helmtexture; //
|
||||
/*077*/ uint8 unknown010; //
|
||||
/*078*/ uint8 unknown011; //
|
||||
/*079*/ uint8 unknown012; //
|
||||
/*080*/ uint32 face; //
|
||||
/*084*/ uint8 hairstyle; //
|
||||
/*085*/ uint8 haircolor; //
|
||||
/*086*/ uint8 beard; //
|
||||
/*087*/ uint8 beardcolor; //
|
||||
/*088*/ float size; //
|
||||
/*092*/ uint32 drakkin_heritage; //
|
||||
/*096*/ uint32 drakkin_tattoo; //
|
||||
/*100*/ uint32 drakkin_details; //
|
||||
/*104*/ EQ::TintProfile armor_tint; //
|
||||
/*140*/ uint8 eyecolor1; // Field Not Identified in any Illusion Struct
|
||||
/*141*/ uint8 eyecolor2; // Field Not Identified in any Illusion Struct
|
||||
/*142*/ uint8 unknown138[114]; //
|
||||
/*256*/
|
||||
};
|
||||
|
||||
@@ -2192,19 +2189,11 @@ struct QuestReward_Struct
|
||||
/*068*/
|
||||
};
|
||||
|
||||
struct CashReward_Struct
|
||||
{
|
||||
/*000*/ uint32 copper;
|
||||
/*004*/ uint32 silver;
|
||||
/*008*/ uint32 gold;
|
||||
/*012*/ uint32 platinum;
|
||||
};
|
||||
|
||||
// Size: 8
|
||||
struct Camera_Struct
|
||||
{
|
||||
uint32 duration; // Duration in ms
|
||||
float intensity;
|
||||
uint32 intensity; // Between 1023410176 and 1090519040
|
||||
};
|
||||
|
||||
struct ZonePoint_Entry {
|
||||
@@ -2324,12 +2313,9 @@ struct FaceChange_Struct {
|
||||
/*004*/ uint8 hairstyle;
|
||||
/*005*/ uint8 beard;
|
||||
/*006*/ uint8 face;
|
||||
/*007*/ uint8 unused_padding;
|
||||
/*008*/ uint32 drakkin_heritage;
|
||||
/*012*/ uint32 drakkin_tattoo;
|
||||
/*016*/ uint32 drakkin_details;
|
||||
/*020*/ uint32 entity_id;
|
||||
/*024*/
|
||||
/*007*/ uint32 drakkin_heritage;
|
||||
/*011*/ uint32 drakkin_tattoo;
|
||||
/*015*/ uint32 drakkin_details;
|
||||
//there are only 10 faces for barbs changing woad just
|
||||
//increase the face value by ten so if there were 8 woad
|
||||
//designs then there would be 80 barb faces
|
||||
@@ -2773,7 +2759,7 @@ struct EnvDamage2_Struct {
|
||||
/*0004*/ uint16 unknown4;
|
||||
/*0006*/ uint32 damage;
|
||||
/*0010*/ uint8 unknown10[12];
|
||||
/*0022*/ uint8 dmgtype; // FA = Lava, FB = Drowning, FC = Falling, FD = Trap
|
||||
/*0022*/ uint8 dmgtype; //FA = Lava; FC = Falling
|
||||
/*0023*/ uint8 unknown2[4];
|
||||
/*0027*/ uint16 constant; //Always FFFF
|
||||
/*0029*/ uint16 unknown29;
|
||||
@@ -3632,17 +3618,14 @@ struct LevelAppearance_Struct { //Sends a little graphic on level up
|
||||
};
|
||||
|
||||
struct MerchantList {
|
||||
uint32 id;
|
||||
uint32 slot;
|
||||
uint32 item;
|
||||
int16 faction_required;
|
||||
int8 level_required;
|
||||
uint16 alt_currency_cost;
|
||||
uint32 classes_required;
|
||||
uint8 probability;
|
||||
std::string bucket_name;
|
||||
std::string bucket_value;
|
||||
uint8 bucket_comparison;
|
||||
uint32 id;
|
||||
uint32 slot;
|
||||
uint32 item;
|
||||
int16 faction_required;
|
||||
int8 level_required;
|
||||
uint16 alt_currency_cost;
|
||||
uint32 classes_required;
|
||||
uint8 probability;
|
||||
};
|
||||
|
||||
struct TempMerchantList {
|
||||
@@ -3731,66 +3714,17 @@ struct SetTitleReply_Struct {
|
||||
uint32 entity_id;
|
||||
};
|
||||
|
||||
struct SharedTaskMemberList_Struct {
|
||||
/*00*/ uint32 gopher_id;
|
||||
/*04*/ uint32 unknown04;
|
||||
/*08*/ uint32 member_count; //1 less than the number of members
|
||||
///*12*/ char list_pointer[0];
|
||||
char member_name[1]; //null terminated string
|
||||
uint32 monster_mission; // class chosen
|
||||
uint8 task_leader; //boolean flag
|
||||
|
||||
struct TaskMemberList_Struct {
|
||||
/*00*/ uint32 gopher_id;
|
||||
/*04*/ uint32 unknown04;
|
||||
/*08*/ uint32 member_count; //1 less than the number of members
|
||||
/*12*/ char list_pointer[0];
|
||||
/* list is of the form:
|
||||
char member_name[1] //null terminated string
|
||||
uint8 task_leader //boolean flag
|
||||
*/
|
||||
};
|
||||
|
||||
struct SharedTaskQuit_Struct {
|
||||
int32 field1;
|
||||
int32 field2;
|
||||
int32 field3;
|
||||
};
|
||||
|
||||
struct SharedTaskAddPlayer_Struct {
|
||||
int32 field1;
|
||||
int32 field2;
|
||||
char player_name[64];
|
||||
};
|
||||
|
||||
struct SharedTaskMakeLeader_Struct {
|
||||
int32 field1;
|
||||
int32 field2;
|
||||
char player_name[64];
|
||||
};
|
||||
|
||||
struct SharedTaskRemovePlayer_Struct {
|
||||
int32 field1;
|
||||
int32 field2;
|
||||
char player_name[64];
|
||||
};
|
||||
|
||||
struct SharedTaskInvite_Struct {
|
||||
int32_t unknown00; // probably the unique character id sent in some packets
|
||||
int32_t invite_id; // invite id sent back in response
|
||||
char task_name[64];
|
||||
char inviter_name[64];
|
||||
};
|
||||
|
||||
struct SharedTaskInviteResponse_Struct {
|
||||
int32_t unknown00; // 0
|
||||
int32_t invite_id; // same id sent in the invite, probably for server verification
|
||||
int8_t accepted; // 0: declined 1: accepted
|
||||
int8_t padding[3]; // padding garbage probably
|
||||
};
|
||||
|
||||
struct SharedTaskAccept_Struct {
|
||||
int32_t unknown00;
|
||||
int32_t unknown04;
|
||||
uint32_t npc_entity_id; // npc task giver entity id (sent in selection window)
|
||||
uint32_t task_id;
|
||||
float reward_multiplier; // added after titanium (sent in selection window)
|
||||
};
|
||||
|
||||
#if 0
|
||||
|
||||
// Old struct not used by Task System implementation but left for reference
|
||||
@@ -3883,7 +3817,7 @@ struct TaskHistory_Struct {
|
||||
#endif
|
||||
|
||||
struct AcceptNewTask_Struct {
|
||||
uint32 task_type; // type sent in selection window
|
||||
uint32 unknown00;
|
||||
uint32 task_id; //set to 0 for 'decline'
|
||||
uint32 task_master_id; //entity ID
|
||||
};
|
||||
@@ -4357,8 +4291,8 @@ struct AARankPrereq_Struct
|
||||
struct AARankEffect_Struct
|
||||
{
|
||||
int32 effect_id;
|
||||
int32 base_value;
|
||||
int32 limit_value;
|
||||
int32 base1;
|
||||
int32 base2;
|
||||
int32 slot;
|
||||
};
|
||||
|
||||
@@ -4366,8 +4300,8 @@ struct AARankEffect_Struct
|
||||
|
||||
struct AA_Ability {
|
||||
/*00*/ uint32 skill_id;
|
||||
/*04*/ uint32 base_value;
|
||||
/*08*/ uint32 limit_value;
|
||||
/*04*/ uint32 base1;
|
||||
/*08*/ uint32 base2;
|
||||
/*12*/ uint32 slot;
|
||||
};
|
||||
|
||||
@@ -5006,7 +4940,7 @@ struct DynamicZoneCompassEntry_Struct
|
||||
/*000*/ uint16 dz_zone_id; // target dz id pair
|
||||
/*002*/ uint16 dz_instance_id;
|
||||
/*004*/ uint32 dz_type; // 1: Expedition, 2: Tutorial (purple), 3: Task, 4: Mission, 5: Quest (green)
|
||||
/*008*/ uint32 dz_switch_id;
|
||||
/*008*/ uint32 unknown008;
|
||||
/*012*/ float y;
|
||||
/*016*/ float x;
|
||||
/*020*/ float z;
|
||||
@@ -5163,10 +5097,10 @@ struct AltCurrencySelectItemReply_Struct {
|
||||
/*000*/ uint32 unknown000;
|
||||
/*004*/ uint8 unknown004; //0xff
|
||||
/*005*/ uint8 unknown005; //0xff
|
||||
/*006*/ uint16 unknown006; //0xffff
|
||||
/*008*/ uint16 unknown008; //0xffff
|
||||
/*010*/ char item_name[64];
|
||||
/*074*/ uint16 unknown074;
|
||||
/*006*/ uint8 unknown006; //0xff
|
||||
/*007*/ uint8 unknown007; //0xff
|
||||
/*008*/ char item_name[64];
|
||||
/*072*/ uint32 unknown074;
|
||||
/*076*/ uint32 cost;
|
||||
/*080*/ uint32 unknown080;
|
||||
/*084*/ uint32 unknown084;
|
||||
@@ -5596,28 +5530,6 @@ struct SayLinkBodyFrame_Struct {
|
||||
/*056*/
|
||||
};
|
||||
|
||||
struct Checksum_Struct {
|
||||
uint64 checksum;
|
||||
uint8 data[2048];
|
||||
};
|
||||
|
||||
struct UpdateMovementEntry {
|
||||
/* 00 */ float Y;
|
||||
/* 04 */ float X;
|
||||
/* 08 */ float Z;
|
||||
/* 12 */ uint8 type;
|
||||
/* 13 */ unsigned int timestamp;
|
||||
/* 17 */
|
||||
};
|
||||
|
||||
struct UnderWorld {
|
||||
/* 00 */ int spawn_id;
|
||||
/* 04 */ float y;
|
||||
/* 08 */ float x;
|
||||
/* 12 */ float z;
|
||||
/* 16 */
|
||||
};
|
||||
|
||||
// Restore structure packing to default
|
||||
#pragma pack()
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "op_codes.h"
|
||||
#include "crc16.h"
|
||||
#include "platform.h"
|
||||
#include "strings.h"
|
||||
#include "string_util.h"
|
||||
|
||||
#include <string>
|
||||
#include <iomanip>
|
||||
@@ -406,7 +406,7 @@ void EQStream::ProcessPacket(EQProtocolPacket *p)
|
||||
if(uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) {
|
||||
LogNetcode(_L "Pre-OOA Invalid Sequenced queue: BS [{}] + SQ [{}] != NOS [{}]" __L, SequencedBase, SequencedQueue.size(), NextOutSeq);
|
||||
}
|
||||
|
||||
|
||||
//if the packet they got out of order is between our last acked packet and the last sent packet, then its valid.
|
||||
if (CompareSequence(SequencedBase,seq) != SeqPast && CompareSequence(NextOutSeq,seq) == SeqPast) {
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Received OP_OutOfOrderAck for sequence %d, starting retransmit at the start of our unacked buffer (seq %d, was %d)." __L,
|
||||
@@ -453,7 +453,7 @@ void EQStream::ProcessPacket(EQProtocolPacket *p)
|
||||
(unsigned long)ntohl(ClientStats->packets_received), (unsigned long)ntohl(ClientStats->packets_sent), (unsigned long)ntohl(ClientStats->last_local_delta),
|
||||
(unsigned long)ntohl(ClientStats->low_delta), (unsigned long)ntohl(ClientStats->average_delta),
|
||||
(unsigned long)ntohl(ClientStats->high_delta), (unsigned long)ntohl(ClientStats->last_remote_delta));
|
||||
|
||||
|
||||
AdjustRates(ntohl(ClientStats->average_delta));
|
||||
|
||||
if(GetExecutablePlatform() == ExePlatformWorld || GetExecutablePlatform() == ExePlatformZone) {
|
||||
@@ -951,7 +951,7 @@ EQRawApplicationPacket *p=nullptr;
|
||||
EmuOpcode emu_op = (*OpMgr)->EQToEmu(p->opcode);
|
||||
if (emu_op == OP_Unknown) {
|
||||
// Log(Logs::General, Logs::Client_Server_Packet_Unhandled, "Unknown :: [%s - 0x%04x] [Size: %u] %s", OpcodeManager::EmuToName(p->GetOpcode()), p->opcode, p->Size(), DumpPacketToString(p).c_str());
|
||||
}
|
||||
}
|
||||
p->SetOpcode(emu_op);
|
||||
}
|
||||
}
|
||||
@@ -1359,11 +1359,11 @@ void EQStream::AdjustRates(uint32 average_delta)
|
||||
DecayRate=DECAYBASE/average_delta;
|
||||
if (BytesWritten > RateThreshold)
|
||||
BytesWritten = RateThreshold + DecayRate;
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Adjusting data rate to thresh %d, decay %d based on avg delta %d" __L,
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Adjusting data rate to thresh %d, decay %d based on avg delta %d" __L,
|
||||
RateThreshold, DecayRate, average_delta);
|
||||
MRate.unlock();
|
||||
} else {
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Not adjusting data rate because avg delta over max (%d > %d)" __L,
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Not adjusting data rate because avg delta over max (%d > %d)" __L,
|
||||
average_delta, AVERAGE_DELTA_MAX);
|
||||
AverageDelta = AVERAGE_DELTA_MAX;
|
||||
}
|
||||
@@ -1374,7 +1374,7 @@ void EQStream::AdjustRates(uint32 average_delta)
|
||||
BytesWritten = 0;
|
||||
RateThreshold=RATEBASE/average_delta;
|
||||
DecayRate=DECAYBASE/average_delta;
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Adjusting data rate to thresh %d, decay %d based on avg delta %d" __L,
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Adjusting data rate to thresh %d, decay %d based on avg delta %d" __L,
|
||||
RateThreshold, DecayRate, average_delta);
|
||||
MRate.unlock();
|
||||
}
|
||||
|
||||
+6
-11
@@ -218,13 +218,13 @@ class EQStream : public EQStreamInterface {
|
||||
|
||||
void init(bool resetSession=true);
|
||||
public:
|
||||
EQStream() { init(); remote_ip = 0; remote_port = 0; State = UNESTABLISHED;
|
||||
StreamType = UnknownStream; compressed = true; encoded = false; app_opcode_size = 2;
|
||||
bytes_sent = 0; bytes_recv = 0; create_time = Timer::GetTimeSeconds(); sessionAttempts = 0;
|
||||
EQStream() { init(); remote_ip = 0; remote_port = 0; State = UNESTABLISHED;
|
||||
StreamType = UnknownStream; compressed = true; encoded = false; app_opcode_size = 2;
|
||||
bytes_sent = 0; bytes_recv = 0; create_time = Timer::GetTimeSeconds(); sessionAttempts = 0;
|
||||
streamactive = false; }
|
||||
EQStream(sockaddr_in addr) { init(); remote_ip = addr.sin_addr.s_addr;
|
||||
remote_port = addr.sin_port; State = UNESTABLISHED; StreamType = UnknownStream;
|
||||
compressed = true; encoded = false; app_opcode_size = 2; bytes_sent = 0; bytes_recv = 0;
|
||||
EQStream(sockaddr_in addr) { init(); remote_ip = addr.sin_addr.s_addr;
|
||||
remote_port = addr.sin_port; State = UNESTABLISHED; StreamType = UnknownStream;
|
||||
compressed = true; encoded = false; app_opcode_size = 2; bytes_sent = 0; bytes_recv = 0;
|
||||
create_time = Timer::GetTimeSeconds(); }
|
||||
virtual ~EQStream() { RemoveData(); SetState(CLOSED); }
|
||||
void SetMaxLen(uint32 length) { MaxLen=length; }
|
||||
@@ -243,11 +243,6 @@ class EQStream : public EQStreamInterface {
|
||||
|
||||
virtual void SetOpcodeManager(OpcodeManager **opm) { OpMgr = opm; }
|
||||
|
||||
virtual OpcodeManager* GetOpcodeManager() const
|
||||
{
|
||||
return (*OpMgr);
|
||||
};
|
||||
|
||||
void CheckTimeout(uint32 now, uint32 timeout=30);
|
||||
bool HasOutgoingData();
|
||||
void Process(const unsigned char *data, const uint32 length);
|
||||
|
||||
@@ -30,7 +30,7 @@ struct EQStreamManagerInterfaceOptions
|
||||
|
||||
//World seems to support both compression and xor zone supports one or the others.
|
||||
//Enforce one or the other in the convienence construct
|
||||
//Login I had trouble getting to recognize compression at all
|
||||
//Login I had trouble getting to recognize compression at all
|
||||
//but that might be because it was still a bit buggy when i was testing that.
|
||||
if (compressed) {
|
||||
daybreak_options.encode_passes[0] = EQ::Net::EncodeCompression;
|
||||
@@ -100,7 +100,6 @@ public:
|
||||
virtual MatchState CheckSignature(const Signature *sig) { return MatchFailed; }
|
||||
virtual EQStreamState GetState() = 0;
|
||||
virtual void SetOpcodeManager(OpcodeManager **opm) = 0;
|
||||
virtual OpcodeManager* GetOpcodeManager() const = 0;
|
||||
virtual const EQ::versions::ClientVersion ClientVersion() const { return EQ::versions::ClientVersion::Unknown; }
|
||||
virtual Stats GetStats() const = 0;
|
||||
virtual void ResetStats() = 0;
|
||||
|
||||
@@ -38,8 +38,12 @@ void EQStreamProxy::SetOpcodeManager(OpcodeManager **opm)
|
||||
}
|
||||
|
||||
void EQStreamProxy::QueuePacket(const EQApplicationPacket *p, bool ack_req) {
|
||||
if (p == nullptr) {
|
||||
if(p == nullptr)
|
||||
return;
|
||||
|
||||
if (p->GetOpcode() != OP_SpecialMesg) {
|
||||
Log(Logs::General, Logs::PacketServerClient, "[%s - 0x%04x] [Size: %u]", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size());
|
||||
Log(Logs::General, Logs::PacketServerClientWithDump, "[%s - 0x%04x] [Size: %u] %s", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size(), DumpPacketToString(p).c_str());
|
||||
}
|
||||
|
||||
EQApplicationPacket *newp = p->Copy();
|
||||
@@ -108,8 +112,3 @@ bool EQStreamProxy::CheckState(EQStreamState state) {
|
||||
return false;
|
||||
}
|
||||
|
||||
OpcodeManager *EQStreamProxy::GetOpcodeManager() const
|
||||
{
|
||||
return (*m_opcodes);
|
||||
}
|
||||
|
||||
|
||||
@@ -34,15 +34,13 @@ public:
|
||||
virtual Stats GetStats() const;
|
||||
virtual void ResetStats();
|
||||
virtual EQStreamManagerInterface* GetManager() const;
|
||||
virtual OpcodeManager* GetOpcodeManager() const;
|
||||
|
||||
protected:
|
||||
std::shared_ptr<EQStreamInterface> const m_stream; //we own this stream object.
|
||||
const StructStrategy *const m_structs; //we do not own this object.
|
||||
//this is a pointer to a pointer to make it less likely that a packet will
|
||||
//reference an invalid opcode manager when they are being reloaded.
|
||||
OpcodeManager **const m_opcodes;
|
||||
//we do not own this object.
|
||||
OpcodeManager **const m_opcodes; //we do not own this object.
|
||||
};
|
||||
|
||||
#endif /*EQSTREAMPROXY_H_*/
|
||||
|
||||
+1
-18
@@ -44,12 +44,6 @@ void EQEmuConfig::parse_config()
|
||||
if (_root["server"]["world"]["loginserver"].get("legacy", "0").asString() == "1") { LoginLegacy = true; }
|
||||
LoginAccount = _root["server"]["world"]["loginserver"].get("account", "").asString();
|
||||
LoginPassword = _root["server"]["world"]["loginserver"].get("password", "").asString();
|
||||
|
||||
// at least today, this is wrong a majority of the time
|
||||
// remove this if eqemulator ever upgrades its loginserver
|
||||
if (LoginHost.find("login.eqemulator.net") != std::string::npos) {
|
||||
LoginLegacy = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
char str[32];
|
||||
@@ -68,19 +62,12 @@ void EQEmuConfig::parse_config()
|
||||
|
||||
loginconfig->LoginLegacy = false;
|
||||
if (_root["server"]["world"][str].get("legacy", "0").asString() == "1") { loginconfig->LoginLegacy = true; }
|
||||
|
||||
// at least today, this is wrong a majority of the time
|
||||
// remove this if eqemulator ever upgrades its loginserver
|
||||
if (loginconfig->LoginHost.find("login.eqemulator.net") != std::string::npos) {
|
||||
loginconfig->LoginLegacy = true;
|
||||
}
|
||||
|
||||
loginlist.Insert(loginconfig);
|
||||
} while (LoginCount < 100);
|
||||
}
|
||||
|
||||
|
||||
//<locked> from xml converts to json as locked: "", so i default to "false".
|
||||
//<locked> from xml converts to json as locked: "", so i default to "false".
|
||||
//The only way to enable locked is by switching to true, meaning this value is always false until manually set true
|
||||
Locked = false;
|
||||
if (_root["server"]["world"].get("locked", "false").asString() == "true") { Locked = true; }
|
||||
@@ -100,10 +87,6 @@ void EQEmuConfig::parse_config()
|
||||
WorldHTTPEnabled = true;
|
||||
}
|
||||
|
||||
if (_root["server"].get("disable_config_checks", "false").asString() == "true") {
|
||||
DisableConfigChecks = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* UCS
|
||||
*/
|
||||
|
||||
+7
-18
@@ -20,9 +20,7 @@
|
||||
|
||||
#include "json/json.h"
|
||||
#include "linked_list.h"
|
||||
#include "path_manager.h"
|
||||
#include <fstream>
|
||||
#include <fmt/format.h>
|
||||
|
||||
struct LoginConfig {
|
||||
std::string LoginHost;
|
||||
@@ -60,7 +58,6 @@ class EQEmuConfig
|
||||
uint16 WorldHTTPPort;
|
||||
std::string WorldHTTPMimeFile;
|
||||
std::string SharedKey;
|
||||
bool DisableConfigChecks;
|
||||
|
||||
// From <chatserver/>
|
||||
std::string ChatHost;
|
||||
@@ -133,7 +130,7 @@ class EQEmuConfig
|
||||
void parse_config();
|
||||
|
||||
EQEmuConfig()
|
||||
{
|
||||
{
|
||||
|
||||
}
|
||||
virtual ~EQEmuConfig() {}
|
||||
@@ -154,38 +151,30 @@ class EQEmuConfig
|
||||
}
|
||||
|
||||
// Load the config
|
||||
static bool LoadConfig(const std::string& path = "")
|
||||
static bool LoadConfig()
|
||||
{
|
||||
if (_config != nullptr) {
|
||||
return true;
|
||||
}
|
||||
_config = new EQEmuConfig;
|
||||
|
||||
return parseFile(path);
|
||||
return parseFile();
|
||||
}
|
||||
|
||||
// Load config file and parse data
|
||||
static bool parseFile(const std::string& file_path = ".")
|
||||
{
|
||||
static bool parseFile() {
|
||||
if (_config == nullptr) {
|
||||
return LoadConfig(file_path);
|
||||
return LoadConfig();
|
||||
}
|
||||
|
||||
std::string file = fmt::format(
|
||||
"{}/{}",
|
||||
(file_path.empty() ? path.GetServerPath() : file_path),
|
||||
EQEmuConfig::ConfigFile
|
||||
);
|
||||
|
||||
std::ifstream fconfig(file, std::ifstream::binary);
|
||||
|
||||
std::ifstream fconfig(EQEmuConfig::ConfigFile, std::ifstream::binary);
|
||||
try {
|
||||
fconfig >> _config->_root;
|
||||
_config->parse_config();
|
||||
}
|
||||
catch (std::exception &) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+296
-437
@@ -21,20 +21,19 @@
|
||||
#include "eqemu_logsys.h"
|
||||
#include "rulesys.h"
|
||||
#include "platform.h"
|
||||
#include "strings.h"
|
||||
#include "repositories/discord_webhooks_repository.h"
|
||||
#include "repositories/logsys_categories_repository.h"
|
||||
#include "termcolor/rang.hpp"
|
||||
#include "string_util.h"
|
||||
#include "database.h"
|
||||
#include "misc.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <iomanip>
|
||||
#include <time.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
std::ofstream process_log;
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#include <direct.h>
|
||||
#include <conio.h>
|
||||
@@ -46,17 +45,50 @@ std::ofstream process_log;
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <thread>
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Linux ANSI console color defines
|
||||
*/
|
||||
#define LC_RESET "\033[0m"
|
||||
#define LC_BLACK "\033[30m" /* Black */
|
||||
#define LC_RED "\033[31m" /* Red */
|
||||
#define LC_GREEN "\033[32m" /* Green */
|
||||
#define LC_YELLOW "\033[33m" /* Yellow */
|
||||
#define LC_BLUE "\033[34m" /* Blue */
|
||||
#define LC_MAGENTA "\033[35m" /* Magenta */
|
||||
#define LC_CYAN "\033[36m" /* Cyan */
|
||||
#define LC_WHITE "\033[37m" /* White */
|
||||
|
||||
namespace Console {
|
||||
enum Color {
|
||||
Black = 0,
|
||||
Blue = 1,
|
||||
Green = 2,
|
||||
Cyan = 3,
|
||||
Red = 4,
|
||||
Magenta = 5,
|
||||
Brown = 6,
|
||||
LightGray = 7,
|
||||
DarkGray = 8,
|
||||
LightBlue = 9,
|
||||
LightGreen = 10,
|
||||
LightCyan = 11,
|
||||
LightRed = 12,
|
||||
LightMagenta = 13,
|
||||
Yellow = 14,
|
||||
White = 15
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* EQEmuLogSys Constructor
|
||||
*/
|
||||
EQEmuLogSys::EQEmuLogSys()
|
||||
{
|
||||
m_on_log_gmsay_hook = [](uint16 log_type, const char *func, const std::string &) {};
|
||||
m_on_log_console_hook = [](uint16 log_type, const std::string &) {};
|
||||
on_log_gmsay_hook = [](uint16 log_type, const std::string &) {};
|
||||
on_log_console_hook = [](uint16 debug_level, uint16 log_type, const std::string &) {};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,48 +96,48 @@ EQEmuLogSys::EQEmuLogSys()
|
||||
*/
|
||||
EQEmuLogSys::~EQEmuLogSys() = default;
|
||||
|
||||
EQEmuLogSys *EQEmuLogSys::LoadLogSettingsDefaults()
|
||||
void EQEmuLogSys::LoadLogSettingsDefaults()
|
||||
{
|
||||
/**
|
||||
* Get Executable platform currently running this code (Zone/World/etc)
|
||||
*/
|
||||
m_log_platform = GetExecutablePlatformInt();
|
||||
log_platform = GetExecutablePlatformInt();
|
||||
|
||||
for (int log_category_id = Logs::AA; log_category_id != Logs::MaxCategoryID; log_category_id++) {
|
||||
log_settings[log_category_id].log_to_console = 0;
|
||||
log_settings[log_category_id].log_to_file = 0;
|
||||
log_settings[log_category_id].log_to_gmsay = 0;
|
||||
log_settings[log_category_id].log_to_discord = 0;
|
||||
log_settings[log_category_id].is_category_enabled = 0;
|
||||
}
|
||||
|
||||
m_file_logs_enabled = false;
|
||||
file_logs_enabled = false;
|
||||
|
||||
/**
|
||||
* Set Defaults
|
||||
*/
|
||||
log_settings[Logs::Crash].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::MySQLError].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::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);
|
||||
log_settings[Logs::Loot].log_to_gmsay = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Scheduler].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Cheat].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::HTTP].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::HTTP].log_to_gmsay = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::ChecksumVerification].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::ChecksumVerification].log_to_gmsay = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::CombatRecord].log_to_gmsay = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Discord].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::QuestErrors].log_to_gmsay = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::QuestErrors].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::WorldServer].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::ZoneServer].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::QSServer].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::UCSServer].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Crash].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::MySQLError].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Loginserver].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::HeadlessClient].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::NPCScaling].log_to_gmsay = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::HotReload].log_to_gmsay = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::HotReload].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Loot].log_to_gmsay = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Scheduler].log_to_console = static_cast<uint8>(Logs::General);
|
||||
|
||||
/**
|
||||
* RFC 5424
|
||||
*/
|
||||
log_settings[Logs::Emergency].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Alert].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Critical].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Error].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Warning].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Notice].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Info].log_to_console = static_cast<uint8>(Logs::General);
|
||||
|
||||
/**
|
||||
@@ -115,8 +147,7 @@ EQEmuLogSys *EQEmuLogSys::LoadLogSettingsDefaults()
|
||||
const bool log_to_console = log_settings[log_category_id].log_to_console > 0;
|
||||
const bool log_to_file = log_settings[log_category_id].log_to_file > 0;
|
||||
const bool log_to_gmsay = log_settings[log_category_id].log_to_gmsay > 0;
|
||||
const bool log_to_discord = log_settings[log_category_id].log_to_discord > 0;
|
||||
const bool is_category_enabled = log_to_console || log_to_file || log_to_gmsay || log_to_discord;
|
||||
const bool is_category_enabled = log_to_console || log_to_file || log_to_gmsay;
|
||||
if (is_category_enabled) {
|
||||
log_settings[log_category_id].is_category_enabled = 1;
|
||||
}
|
||||
@@ -125,29 +156,86 @@ EQEmuLogSys *EQEmuLogSys::LoadLogSettingsDefaults()
|
||||
/**
|
||||
* Declare process file names for log writing=
|
||||
*/
|
||||
if (EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformWorld) {
|
||||
m_platform_file_name = "world";
|
||||
if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformWorld) {
|
||||
platform_file_name = "world";
|
||||
}
|
||||
else if (EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformQueryServ) {
|
||||
m_platform_file_name = "query_server";
|
||||
else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformQueryServ) {
|
||||
platform_file_name = "query_server";
|
||||
}
|
||||
else if (EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformZone) {
|
||||
m_platform_file_name = "zone";
|
||||
else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformZone) {
|
||||
platform_file_name = "zone";
|
||||
}
|
||||
else if (EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformUCS) {
|
||||
m_platform_file_name = "ucs";
|
||||
else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformUCS) {
|
||||
platform_file_name = "ucs";
|
||||
}
|
||||
else if (EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformLogin) {
|
||||
m_platform_file_name = "login";
|
||||
else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformLogin) {
|
||||
platform_file_name = "login";
|
||||
}
|
||||
else if (EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformLaunch) {
|
||||
m_platform_file_name = "launcher";
|
||||
else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformLaunch) {
|
||||
platform_file_name = "launcher";
|
||||
}
|
||||
else if (EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformHC) {
|
||||
m_platform_file_name = "hc";
|
||||
else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformHC) {
|
||||
platform_file_name = "hc";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param log_category
|
||||
* @return
|
||||
*/
|
||||
bool EQEmuLogSys::IsRfc5424LogCategory(uint16 log_category)
|
||||
{
|
||||
return (
|
||||
log_category == Logs::Emergency ||
|
||||
log_category == Logs::Alert ||
|
||||
log_category == Logs::Critical ||
|
||||
log_category == Logs::Error ||
|
||||
log_category == Logs::Warning ||
|
||||
log_category == Logs::Notice ||
|
||||
log_category == Logs::Info ||
|
||||
log_category == Logs::Debug
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param log_category
|
||||
* @param in_message
|
||||
* @return
|
||||
*/
|
||||
std::string EQEmuLogSys::FormatOutMessageString(
|
||||
uint16 log_category,
|
||||
const std::string &in_message
|
||||
)
|
||||
{
|
||||
std::string return_string = "[" + GetPlatformName() + "] ";
|
||||
|
||||
return return_string + "[" + Logs::LogCategoryName[log_category] + "] " + in_message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param debug_level
|
||||
* @param log_category
|
||||
* @param message
|
||||
*/
|
||||
void EQEmuLogSys::ProcessGMSay(
|
||||
uint16 debug_level,
|
||||
uint16 log_category,
|
||||
const std::string &message
|
||||
)
|
||||
{
|
||||
/**
|
||||
* Enabling Netcode based GMSay output creates a feedback loop that ultimately ends in a crash
|
||||
*/
|
||||
if (log_category == Logs::LogCategory::Netcode) {
|
||||
return;
|
||||
}
|
||||
|
||||
return this;
|
||||
/**
|
||||
* Check to see if the process that actually ran this is zone
|
||||
*/
|
||||
if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformZone) {
|
||||
on_log_gmsay_hook(log_category, message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -156,6 +244,7 @@ EQEmuLogSys *EQEmuLogSys::LoadLogSettingsDefaults()
|
||||
* @param message
|
||||
*/
|
||||
void EQEmuLogSys::ProcessLogWrite(
|
||||
uint16 debug_level,
|
||||
uint16 log_category,
|
||||
const std::string &message
|
||||
)
|
||||
@@ -166,20 +255,79 @@ void EQEmuLogSys::ProcessLogWrite(
|
||||
std::ofstream crash_log;
|
||||
EQEmuLogSys::MakeDirectory("logs/crashes");
|
||||
crash_log.open(
|
||||
StringFormat("logs/crashes/crash_%s_%i.log", m_platform_file_name.c_str(), getpid()),
|
||||
StringFormat("logs/crashes/crash_%s_%i.log", platform_file_name.c_str(), getpid()),
|
||||
std::ios_base::app | std::ios_base::out
|
||||
);
|
||||
crash_log << time_stamp << " " << message << "\n";
|
||||
crash_log.close();
|
||||
}
|
||||
|
||||
char time_stamp[80];
|
||||
EQEmuLogSys::SetCurrentTimeStamp(time_stamp);
|
||||
|
||||
if (process_log) {
|
||||
char time_stamp[80];
|
||||
EQEmuLogSys::SetCurrentTimeStamp(time_stamp);
|
||||
process_log << time_stamp << " " << message << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param log_category
|
||||
* @return
|
||||
*/
|
||||
uint16 EQEmuLogSys::GetWindowsConsoleColorFromCategory(uint16 log_category)
|
||||
{
|
||||
switch (log_category) {
|
||||
case Logs::Status:
|
||||
case Logs::Normal:
|
||||
return Console::Color::Yellow;
|
||||
case Logs::MySQLError:
|
||||
case Logs::Error:
|
||||
return Console::Color::LightRed;
|
||||
case Logs::MySQLQuery:
|
||||
case Logs::Debug:
|
||||
return Console::Color::LightGreen;
|
||||
case Logs::Quests:
|
||||
return Console::Color::LightCyan;
|
||||
case Logs::Commands:
|
||||
case Logs::Mercenaries:
|
||||
return Console::Color::LightMagenta;
|
||||
case Logs::Crash:
|
||||
return Console::Color::LightRed;
|
||||
default:
|
||||
return Console::Color::Yellow;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param log_category
|
||||
* @return
|
||||
*/
|
||||
std::string EQEmuLogSys::GetLinuxConsoleColorFromCategory(uint16 log_category)
|
||||
{
|
||||
switch (log_category) {
|
||||
case Logs::Status:
|
||||
case Logs::Normal:
|
||||
return LC_YELLOW;
|
||||
case Logs::MySQLError:
|
||||
case Logs::Warning:
|
||||
case Logs::Critical:
|
||||
case Logs::Error:
|
||||
return LC_RED;
|
||||
case Logs::MySQLQuery:
|
||||
case Logs::Debug:
|
||||
return LC_GREEN;
|
||||
case Logs::Quests:
|
||||
return LC_CYAN;
|
||||
case Logs::Commands:
|
||||
case Logs::Mercenaries:
|
||||
return LC_MAGENTA;
|
||||
case Logs::Crash:
|
||||
return LC_RED;
|
||||
default:
|
||||
return LC_YELLOW;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param log_category
|
||||
* @return
|
||||
@@ -187,8 +335,10 @@ void EQEmuLogSys::ProcessLogWrite(
|
||||
uint16 EQEmuLogSys::GetGMSayColorFromCategory(uint16 log_category)
|
||||
{
|
||||
switch (log_category) {
|
||||
case Logs::Status:
|
||||
case Logs::Normal:
|
||||
return Chat::Yellow;
|
||||
case Logs::MySQLError:
|
||||
case Logs::QuestErrors:
|
||||
case Logs::Error:
|
||||
return Chat::Red;
|
||||
case Logs::MySQLQuery:
|
||||
@@ -206,146 +356,30 @@ uint16 EQEmuLogSys::GetGMSayColorFromCategory(uint16 log_category)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param debug_level
|
||||
* @param log_category
|
||||
* @param message
|
||||
*/
|
||||
void EQEmuLogSys::ProcessConsoleMessage(
|
||||
uint16 log_category,
|
||||
const std::string &message,
|
||||
const char *file,
|
||||
const char *func,
|
||||
int line
|
||||
)
|
||||
void EQEmuLogSys::ProcessConsoleMessage(uint16 debug_level, uint16 log_category, const std::string &message)
|
||||
{
|
||||
bool is_error = (
|
||||
log_category == Logs::LogCategory::Error ||
|
||||
log_category == Logs::LogCategory::MySQLError ||
|
||||
log_category == Logs::LogCategory::Crash ||
|
||||
log_category == Logs::LogCategory::QuestErrors
|
||||
);
|
||||
bool is_warning = (
|
||||
log_category == Logs::LogCategory::Warning
|
||||
);
|
||||
#ifdef _WINDOWS
|
||||
HANDLE console_handle;
|
||||
console_handle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
CONSOLE_FONT_INFOEX info = { 0 };
|
||||
info.cbSize = sizeof(info);
|
||||
info.dwFontSize.Y = 12; // leave X as zero
|
||||
info.FontWeight = FW_NORMAL;
|
||||
wcscpy(info.FaceName, L"Lucida Console");
|
||||
SetCurrentConsoleFontEx(console_handle, NULL, &info);
|
||||
SetConsoleTextAttribute(console_handle, EQEmuLogSys::GetWindowsConsoleColorFromCategory(log_category));
|
||||
std::cout << message << "\n";
|
||||
SetConsoleTextAttribute(console_handle, Console::Color::White);
|
||||
#else
|
||||
std::cout << EQEmuLogSys::GetLinuxConsoleColorFromCategory(log_category) << message << LC_RESET << std::endl;
|
||||
#endif
|
||||
|
||||
(!is_error ? std::cout : std::cerr)
|
||||
<< ""
|
||||
<< rang::fgB::black
|
||||
<< rang::style::bold
|
||||
<< fmt::format("{:>6}", GetPlatformName().substr(0, 6))
|
||||
<< rang::style::reset
|
||||
<< rang::fgB::gray
|
||||
<< " | "
|
||||
<< ((is_error || is_warning) ? rang::fgB::red : rang::fgB::gray)
|
||||
<< rang::style::bold
|
||||
<< fmt::format("{:^10}", fmt::format("{}", Logs::LogCategoryName[log_category]).substr(0, 10))
|
||||
<< rang::style::reset
|
||||
<< rang::fgB::gray
|
||||
<< " | "
|
||||
<< rang::fgB::gray
|
||||
<< rang::style::bold
|
||||
<< fmt::format("{}", func)
|
||||
<< rang::style::reset
|
||||
<< rang::fgB::gray
|
||||
<< " ";
|
||||
|
||||
if (RuleB(Logging, PrintFileFunctionAndLine)) {
|
||||
(!is_error ? std::cout : std::cerr)
|
||||
<< ""
|
||||
<< rang::fgB::green
|
||||
<< rang::style::bold
|
||||
<< fmt::format("{:}", fmt::format("{}:{}:{}", std::filesystem::path(file).filename().string(), func, line))
|
||||
<< rang::style::reset
|
||||
<< " | ";
|
||||
}
|
||||
|
||||
if (log_category == Logs::LogCategory::MySQLQuery) {
|
||||
auto s = Strings::Split(message, "--");
|
||||
if (s.size() > 1) {
|
||||
std::string query = Strings::Trim(s[0]);
|
||||
std::string meta = Strings::Trim(s[1]);
|
||||
|
||||
std::cout <<
|
||||
rang::fgB::green
|
||||
<<
|
||||
query
|
||||
<<
|
||||
rang::style::reset;
|
||||
|
||||
std::cout <<
|
||||
rang::fgB::black
|
||||
<<
|
||||
" -- "
|
||||
<<
|
||||
meta
|
||||
<<
|
||||
rang::style::reset;
|
||||
}
|
||||
}
|
||||
else if (Strings::Contains(message, "[")) {
|
||||
for (auto &e: Strings::Split(message, " ")) {
|
||||
if (Strings::Contains(e, "[") && Strings::Contains(e, "]")) {
|
||||
e = Strings::Replace(e, "[", "");
|
||||
e = Strings::Replace(e, "]", "");
|
||||
|
||||
bool is_upper = false;
|
||||
|
||||
for (int i = 0; i < strlen(e.c_str()); i++) {
|
||||
if (isupper(e[i])) {
|
||||
is_upper = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_upper) {
|
||||
(!is_error ? std::cout : std::cerr)
|
||||
<< rang::fgB::gray
|
||||
<< "["
|
||||
<< rang::style::bold
|
||||
<< rang::fgB::yellow
|
||||
<< e
|
||||
<< rang::fgB::gray
|
||||
<< "] "
|
||||
;
|
||||
}
|
||||
else {
|
||||
(!is_error ? std::cout : std::cerr) << rang::fgB::gray << "[" << e << "] ";
|
||||
}
|
||||
}
|
||||
else {
|
||||
(!is_error ? std::cout : std::cerr)
|
||||
<< (is_error ? rang::fgB::red : rang::fgB::gray)
|
||||
<< e
|
||||
<< " ";
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
(!is_error ? std::cout : std::cerr)
|
||||
<< (is_error ? rang::fgB::red : rang::fgB::gray)
|
||||
<< message
|
||||
<< " ";
|
||||
}
|
||||
|
||||
if (!origination_info.zone_short_name.empty()) {
|
||||
(!is_error ? std::cout : std::cerr)
|
||||
<<
|
||||
rang::fgB::black
|
||||
<<
|
||||
"-- "
|
||||
<<
|
||||
fmt::format(
|
||||
"[{}] ({}) inst_id [{}]",
|
||||
origination_info.zone_short_name,
|
||||
origination_info.zone_long_name,
|
||||
origination_info.instance_id
|
||||
);
|
||||
}
|
||||
|
||||
(!is_error ? std::cout : std::cerr) << rang::style::reset << std::endl;
|
||||
|
||||
m_on_log_console_hook(log_category, message);
|
||||
on_log_console_hook(debug_level, log_category, message);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -357,6 +391,33 @@ constexpr const char *str_end(const char *str)
|
||||
return *str ? str_end(str + 1) : str;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param str
|
||||
* @return
|
||||
*/
|
||||
constexpr bool str_slant(const char *str)
|
||||
{
|
||||
return *str == '/' ? true : (*str ? str_slant(str + 1) : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param str
|
||||
* @return
|
||||
*/
|
||||
constexpr const char *r_slant(const char *str)
|
||||
{
|
||||
return *str == '/' ? (str + 1) : r_slant(str - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param str
|
||||
* @return
|
||||
*/
|
||||
constexpr const char *base_file_name(const char *str)
|
||||
{
|
||||
return str_slant(str) ? r_slant(str_end(str)) : str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Core logging function
|
||||
*
|
||||
@@ -375,55 +436,47 @@ void EQEmuLogSys::Out(
|
||||
...
|
||||
)
|
||||
{
|
||||
auto l = GetLogsEnabled(debug_level, log_category);
|
||||
bool log_to_console = true;
|
||||
if (log_settings[log_category].log_to_console < debug_level) {
|
||||
log_to_console = false;
|
||||
}
|
||||
|
||||
// bail out if nothing to log
|
||||
if (!l.log_enabled) {
|
||||
bool log_to_file = true;
|
||||
if (log_settings[log_category].log_to_file < debug_level) {
|
||||
log_to_file = false;
|
||||
}
|
||||
|
||||
bool log_to_gmsay = true;
|
||||
if (log_settings[log_category].log_to_gmsay < debug_level) {
|
||||
log_to_gmsay = false;
|
||||
}
|
||||
|
||||
const bool nothing_to_log = !log_to_console && !log_to_file && !log_to_gmsay;
|
||||
if (nothing_to_log) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string prefix;
|
||||
|
||||
if (RuleB(Logging, PrintFileFunctionAndLine)) {
|
||||
prefix = fmt::format("[{0}::{1}:{2}] ", std::filesystem::path(file).filename().string(), func, line);
|
||||
prefix = fmt::format("[{0}::{1}:{2}] ", base_file_name(file), func, line);
|
||||
}
|
||||
|
||||
// remove this when we remove all legacy logs
|
||||
bool ignore_log_legacy_format = (
|
||||
log_category == Logs::Netcode ||
|
||||
log_category == Logs::PacketServerClient ||
|
||||
log_category == Logs::PacketClientServer ||
|
||||
log_category == Logs::PacketServerToServer
|
||||
);
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
std::string output_message = vStringFormat(message, args);
|
||||
va_end(args);
|
||||
|
||||
// remove this when we remove all legacy logs
|
||||
std::string output_message = message;
|
||||
if (!ignore_log_legacy_format) {
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
output_message = vStringFormat(message, args);
|
||||
va_end(args);
|
||||
}
|
||||
std::string output_debug_message = EQEmuLogSys::FormatOutMessageString(log_category, prefix + output_message);
|
||||
|
||||
if (l.log_to_console_enabled) {
|
||||
EQEmuLogSys::ProcessConsoleMessage(
|
||||
log_category,
|
||||
output_message,
|
||||
file,
|
||||
func,
|
||||
line
|
||||
);
|
||||
if (log_to_console) {
|
||||
EQEmuLogSys::ProcessConsoleMessage(debug_level, log_category, output_debug_message);
|
||||
}
|
||||
if (l.log_to_gmsay_enabled) {
|
||||
m_on_log_gmsay_hook(log_category, func, output_message);
|
||||
if (log_to_gmsay) {
|
||||
EQEmuLogSys::ProcessGMSay(debug_level, log_category, output_debug_message);
|
||||
}
|
||||
if (l.log_to_file_enabled) {
|
||||
EQEmuLogSys::ProcessLogWrite(
|
||||
log_category,
|
||||
fmt::format("[{}] [{}] {}", GetPlatformName(), Logs::LogCategoryName[log_category], prefix + output_message)
|
||||
);
|
||||
}
|
||||
if (l.log_to_discord_enabled && m_on_log_discord_hook) {
|
||||
m_on_log_discord_hook(log_category, log_settings[log_category].discord_webhook_id, output_message);
|
||||
if (log_to_file) {
|
||||
EQEmuLogSys::ProcessLogWrite(debug_level, log_category, output_debug_message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -436,7 +489,7 @@ void EQEmuLogSys::SetCurrentTimeStamp(char *time_stamp)
|
||||
struct tm *time_info;
|
||||
time(&raw_time);
|
||||
time_info = localtime(&raw_time);
|
||||
strftime(time_stamp, 80, "[%m-%d-%Y %H:%M:%S]", time_info);
|
||||
strftime(time_stamp, 80, "[%m-%d-%Y :: %H:%M:%S]", time_info);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -475,45 +528,53 @@ void EQEmuLogSys::StartFileLogs(const std::string &log_name)
|
||||
/**
|
||||
* When loading settings, we must have been given a reason in category based logging to output to a file in order to even create or open one...
|
||||
*/
|
||||
if (!m_file_logs_enabled) {
|
||||
if (!file_logs_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Zone
|
||||
*/
|
||||
if (EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformZone) {
|
||||
if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformZone) {
|
||||
if (!log_name.empty()) {
|
||||
m_platform_file_name = log_name;
|
||||
platform_file_name = log_name;
|
||||
}
|
||||
|
||||
if (m_platform_file_name.empty()) {
|
||||
if (platform_file_name.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
LogInfo("Starting File Log [{}/zone/{}_{}.log]", GetLogPath(), m_platform_file_name.c_str(), getpid());
|
||||
LogInfo("Starting File Log [logs/{}_{}.log]", platform_file_name.c_str(), getpid());
|
||||
|
||||
// Make directory if not exists
|
||||
EQEmuLogSys::MakeDirectory(fmt::format("{}/zone", GetLogPath()));
|
||||
/**
|
||||
* Make directory if not exists
|
||||
*/
|
||||
EQEmuLogSys::MakeDirectory("logs/zone");
|
||||
|
||||
// Open file pointer
|
||||
/**
|
||||
* Open file pointer
|
||||
*/
|
||||
process_log.open(
|
||||
fmt::format("{}/zone/{}_{}.log", GetLogPath(), m_platform_file_name, getpid()),
|
||||
StringFormat("logs/zone/%s_%i.log", platform_file_name.c_str(), getpid()),
|
||||
std::ios_base::app | std::ios_base::out
|
||||
);
|
||||
}
|
||||
else {
|
||||
|
||||
// All other processes
|
||||
if (m_platform_file_name.empty()) {
|
||||
/**
|
||||
* All other processes
|
||||
*/
|
||||
if (platform_file_name.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
LogInfo("Starting File Log [{}/{}_{}.log]", GetLogPath(), m_platform_file_name.c_str(), getpid());
|
||||
LogInfo("Starting File Log [logs/{}_{}.log]", platform_file_name.c_str(), getpid());
|
||||
|
||||
// Open file pointer
|
||||
/**
|
||||
* Open file pointer
|
||||
*/
|
||||
process_log.open(
|
||||
fmt::format("{}/{}_{}.log", GetLogPath(), m_platform_file_name.c_str(), getpid()),
|
||||
StringFormat("logs/%s_%i.log", platform_file_name.c_str(), getpid()),
|
||||
std::ios_base::app | std::ios_base::out
|
||||
);
|
||||
}
|
||||
@@ -528,8 +589,6 @@ void EQEmuLogSys::SilenceConsoleLogging()
|
||||
log_settings[log_index].log_to_console = 0;
|
||||
log_settings[log_index].is_category_enabled = 0;
|
||||
}
|
||||
|
||||
log_settings[Logs::Crash].log_to_console = static_cast<uint8>(Logs::General);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -542,203 +601,3 @@ void EQEmuLogSys::EnableConsoleLogging()
|
||||
log_settings[log_index].is_category_enabled = 1;
|
||||
}
|
||||
}
|
||||
|
||||
EQEmuLogSys *EQEmuLogSys::LoadLogDatabaseSettings()
|
||||
{
|
||||
InjectTablesIfNotExist();
|
||||
|
||||
auto categories = LogsysCategoriesRepository::GetWhere(
|
||||
*m_database,
|
||||
"TRUE ORDER BY log_category_id"
|
||||
);
|
||||
|
||||
// keep track of categories
|
||||
std::vector<int> db_categories{};
|
||||
db_categories.reserve(categories.size());
|
||||
|
||||
// loop through database categories
|
||||
for (auto &c: categories) {
|
||||
if (c.log_category_id <= Logs::None || c.log_category_id >= Logs::MaxCategoryID) {
|
||||
continue;
|
||||
}
|
||||
|
||||
log_settings[c.log_category_id].log_to_console = static_cast<uint8>(c.log_to_console);
|
||||
log_settings[c.log_category_id].log_to_file = static_cast<uint8>(c.log_to_file);
|
||||
log_settings[c.log_category_id].log_to_gmsay = static_cast<uint8>(c.log_to_gmsay);
|
||||
log_settings[c.log_category_id].log_to_discord = static_cast<uint8>(c.log_to_discord);
|
||||
log_settings[c.log_category_id].discord_webhook_id = c.discord_webhook_id;
|
||||
|
||||
// Determine if any output method is enabled for the category
|
||||
// and set it to 1 so it can used to check if category is enabled
|
||||
const bool log_to_console = log_settings[c.log_category_id].log_to_console > 0;
|
||||
const bool log_to_file = log_settings[c.log_category_id].log_to_file > 0;
|
||||
const bool log_to_gmsay = log_settings[c.log_category_id].log_to_gmsay > 0;
|
||||
const bool log_to_discord = log_settings[c.log_category_id].log_to_discord > 0 &&
|
||||
log_settings[c.log_category_id].discord_webhook_id > 0;
|
||||
const bool is_category_enabled = log_to_console || log_to_file || log_to_gmsay || log_to_discord;
|
||||
|
||||
if (is_category_enabled) {
|
||||
log_settings[c.log_category_id].is_category_enabled = 1;
|
||||
}
|
||||
|
||||
// This determines whether or not the process needs to actually file log anything.
|
||||
// If we go through this whole loop and nothing is set to any debug level, there
|
||||
// is no point to create a file or keep anything open
|
||||
if (log_settings[c.log_category_id].log_to_file > 0) {
|
||||
LogSys.m_file_logs_enabled = true;
|
||||
}
|
||||
|
||||
db_categories.emplace_back(c.log_category_id);
|
||||
}
|
||||
|
||||
// Auto inject categories that don't exist in the database...
|
||||
for (int i = Logs::AA; i != Logs::MaxCategoryID; i++) {
|
||||
|
||||
bool is_missing_in_database = std::find(db_categories.begin(), db_categories.end(), i) == db_categories.end();
|
||||
bool is_deprecated_category = Strings::Contains(fmt::format("{}", Logs::LogCategoryName[i]), "Deprecated");
|
||||
if (!is_missing_in_database && is_deprecated_category) {
|
||||
LogInfo(
|
||||
"Logging category [{}] ({}) is now deprecated, deleting from database",
|
||||
Logs::LogCategoryName[i],
|
||||
i
|
||||
);
|
||||
LogsysCategoriesRepository::DeleteOne(*m_database, i);
|
||||
}
|
||||
|
||||
if (is_missing_in_database && !is_deprecated_category) {
|
||||
LogInfo(
|
||||
"Automatically adding new log category [{}] ({})",
|
||||
Logs::LogCategoryName[i],
|
||||
i
|
||||
);
|
||||
|
||||
auto new_category = LogsysCategoriesRepository::NewEntity();
|
||||
new_category.log_category_id = i;
|
||||
new_category.log_category_description = Strings::Escape(Logs::LogCategoryName[i]);
|
||||
new_category.log_to_console = log_settings[i].log_to_console;
|
||||
new_category.log_to_gmsay = log_settings[i].log_to_gmsay;
|
||||
new_category.log_to_file = log_settings[i].log_to_file;
|
||||
new_category.log_to_discord = log_settings[i].log_to_discord;
|
||||
|
||||
LogsysCategoriesRepository::InsertOne(*m_database, new_category);
|
||||
}
|
||||
}
|
||||
|
||||
LogInfo("Loaded [{}] log categories", categories.size());
|
||||
|
||||
auto webhooks = DiscordWebhooksRepository::GetWhere(*m_database, fmt::format("id < {}", MAX_DISCORD_WEBHOOK_ID));
|
||||
if (!webhooks.empty()) {
|
||||
for (auto &w: webhooks) {
|
||||
m_discord_webhooks[w.id] = {w.id, w.webhook_name, w.webhook_url};
|
||||
}
|
||||
LogInfo("Loaded [{}] Discord webhooks", webhooks.size());
|
||||
}
|
||||
|
||||
// force override this setting
|
||||
log_settings[Logs::Crash].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Crash].log_to_gmsay = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Crash].log_to_file = static_cast<uint8>(Logs::General);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
EQEmuLogSys *EQEmuLogSys::SetDatabase(Database *db)
|
||||
{
|
||||
m_database = db;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
void EQEmuLogSys::InjectTablesIfNotExist()
|
||||
{
|
||||
// do not run injections for zone as its unnecessary hits every time a zone boots
|
||||
// other processes less frequently ran can pick up injection
|
||||
if (m_log_platform == EQEmuExePlatform::ExePlatformZone) {
|
||||
return;
|
||||
}
|
||||
|
||||
// inject discord_webhooks
|
||||
if (!m_database->DoesTableExist("discord_webhooks")) {
|
||||
LogInfo("Creating table [discord_webhooks]");
|
||||
m_database->QueryDatabase(
|
||||
SQL(
|
||||
CREATE TABLE discord_webhooks
|
||||
(
|
||||
id INT auto_increment primary key NULL,
|
||||
webhook_name varchar(100) NULL,
|
||||
webhook_url varchar(255) NULL,
|
||||
created_at DATETIME NULL,
|
||||
deleted_at DATETIME NULL
|
||||
) ENGINE=InnoDB
|
||||
DEFAULT CHARSET=utf8mb4
|
||||
COLLATE=utf8mb4_general_ci;
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// inject logsys_categories
|
||||
if (!m_database->DoesTableExist("logsys_categories")) {
|
||||
LogInfo("Creating table [logsys_categories]");
|
||||
m_database->QueryDatabase(
|
||||
SQL(
|
||||
CREATE TABLE `logsys_categories` (
|
||||
`log_category_id` int(11) NOT NULL,
|
||||
`log_category_description` varchar(150) DEFAULT NULL,
|
||||
`log_to_console` smallint(11) DEFAULT 0,
|
||||
`log_to_file` smallint(11) DEFAULT 0,
|
||||
`log_to_gmsay` smallint(11) DEFAULT 0,
|
||||
`log_to_discord` smallint(11) DEFAULT 0,
|
||||
`discord_webhook_id` int(11) DEFAULT 0,
|
||||
PRIMARY KEY (`log_category_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const EQEmuLogSys::DiscordWebhooks *EQEmuLogSys::GetDiscordWebhooks() const
|
||||
{
|
||||
return m_discord_webhooks;
|
||||
}
|
||||
|
||||
EQEmuLogSys::LogEnabled EQEmuLogSys::GetLogsEnabled(const Logs::DebugLevel &debug_level, const uint16 &log_category)
|
||||
{
|
||||
auto e = LogEnabled{};
|
||||
|
||||
e.log_to_console_enabled = log_settings[log_category].log_to_console > 0 &&
|
||||
log_settings[log_category].log_to_console >= debug_level;
|
||||
e.log_to_file_enabled = log_settings[log_category].log_to_file > 0 &&
|
||||
log_settings[log_category].log_to_file >= debug_level;
|
||||
e.log_to_gmsay_enabled = log_settings[log_category].log_to_gmsay > 0 &&
|
||||
log_settings[log_category].log_to_gmsay >= debug_level &&
|
||||
log_category != Logs::LogCategory::Netcode &&
|
||||
(EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformZone ||
|
||||
EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformWorld);
|
||||
e.log_to_discord_enabled = EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformZone &&
|
||||
log_settings[log_category].log_to_discord > 0 &&
|
||||
log_settings[log_category].log_to_discord >= debug_level &&
|
||||
log_settings[log_category].discord_webhook_id > 0 &&
|
||||
log_settings[log_category].discord_webhook_id < MAX_DISCORD_WEBHOOK_ID;
|
||||
e.log_enabled =
|
||||
e.log_to_console_enabled || e.log_to_file_enabled || e.log_to_gmsay_enabled || e.log_to_discord_enabled;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
bool EQEmuLogSys::IsLogEnabled(const Logs::DebugLevel &debug_level, const uint16 &log_category)
|
||||
{
|
||||
return GetLogsEnabled(debug_level, log_category).log_enabled;
|
||||
}
|
||||
|
||||
const std::string &EQEmuLogSys::GetLogPath() const
|
||||
{
|
||||
return m_log_path;
|
||||
}
|
||||
|
||||
EQEmuLogSys *EQEmuLogSys::SetLogPath(const std::string &log_path)
|
||||
{
|
||||
EQEmuLogSys::m_log_path = log_path;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
+129
-154
@@ -23,9 +23,8 @@
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <cstdio>
|
||||
#include <stdio.h>
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef utf16_to_utf8
|
||||
@@ -38,8 +37,9 @@
|
||||
|
||||
namespace Logs {
|
||||
enum DebugLevel {
|
||||
General = 1, // 1 - Low-Level general debugging, useful info on single line
|
||||
Detail // 2 - Use this for very chatty logging you want to leave in but don't want on by default
|
||||
General = 1, /* 1 - Low-Level general debugging, useful info on single line */
|
||||
Moderate, /* 2 - Informational based, used in functions, when particular things load */
|
||||
Detail /* 3 - Use this for extreme detail in logging, usually in extreme debugging in the stack or interprocess communication */
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -53,7 +53,7 @@ namespace Logs {
|
||||
AI,
|
||||
Aggro,
|
||||
Attack,
|
||||
DeprecatedCS, // deprecated
|
||||
PacketClientServer,
|
||||
Combat,
|
||||
Commands,
|
||||
Crash,
|
||||
@@ -64,36 +64,36 @@ namespace Logs {
|
||||
Inventory,
|
||||
Launcher,
|
||||
Netcode,
|
||||
Normal, // deprecated
|
||||
Normal,
|
||||
Object,
|
||||
Pathing,
|
||||
QSServer, // deprecated
|
||||
QSServer,
|
||||
Quests,
|
||||
Rules,
|
||||
Skills,
|
||||
Spawns,
|
||||
Spells,
|
||||
Status, // deprecated
|
||||
Status,
|
||||
TCPConnection,
|
||||
Tasks,
|
||||
Tradeskills,
|
||||
Trading,
|
||||
Tribute,
|
||||
UCSServer, // deprecated
|
||||
WebInterfaceServer, // deprecated
|
||||
WorldServer, // deprecated
|
||||
ZoneServer, // deprecated
|
||||
UCSServer,
|
||||
WebInterfaceServer,
|
||||
WorldServer,
|
||||
ZoneServer,
|
||||
MySQLError,
|
||||
MySQLQuery,
|
||||
Mercenaries,
|
||||
QuestDebug,
|
||||
DeprecatedSC, // deprecated
|
||||
DeprecatedCSU, // deprecated
|
||||
DeprecatedSCD, // deprecated
|
||||
DeprecatedCSD, // deprecated
|
||||
Loginserver, // deprecated
|
||||
PacketServerClient,
|
||||
PacketClientServerUnhandled,
|
||||
PacketServerClientWithDump,
|
||||
PacketClientServerWithDump,
|
||||
Loginserver,
|
||||
ClientLogin,
|
||||
HeadlessClient, // deprecated
|
||||
HeadlessClient,
|
||||
HPUpdate,
|
||||
FixZ,
|
||||
Food,
|
||||
@@ -103,10 +103,10 @@ namespace Logs {
|
||||
MobAppearance,
|
||||
Info,
|
||||
Warning,
|
||||
Critical, // deprecated
|
||||
Emergency, // deprecated
|
||||
Alert, // deprecated
|
||||
Notice, // deprecated
|
||||
Critical,
|
||||
Emergency,
|
||||
Alert,
|
||||
Notice,
|
||||
AIScanClose,
|
||||
AIYellForHelp,
|
||||
AICastBeneficialClose,
|
||||
@@ -121,34 +121,19 @@ namespace Logs {
|
||||
Expeditions,
|
||||
DynamicZones,
|
||||
Scheduler,
|
||||
Cheat,
|
||||
ClientList,
|
||||
DiaWind,
|
||||
HTTP,
|
||||
Saylink,
|
||||
ChecksumVerification,
|
||||
CombatRecord,
|
||||
Hate,
|
||||
Discord,
|
||||
Faction,
|
||||
PacketServerClient,
|
||||
PacketClientServer,
|
||||
PacketServerToServer,
|
||||
Bugs,
|
||||
QuestErrors,
|
||||
MaxCategoryID /* Don't Remove this */
|
||||
};
|
||||
|
||||
/**
|
||||
* If you add to this, make sure you update LogCategory
|
||||
*/
|
||||
static const char *LogCategoryName[LogCategory::MaxCategoryID] = {
|
||||
static const char* LogCategoryName[LogCategory::MaxCategoryID] = {
|
||||
"",
|
||||
"AA",
|
||||
"AI",
|
||||
"Aggro",
|
||||
"Attack",
|
||||
"Deprecated",
|
||||
"Packet :: Client -> Server",
|
||||
"Combat",
|
||||
"Commands",
|
||||
"Crash",
|
||||
@@ -159,52 +144,52 @@ namespace Logs {
|
||||
"Inventory",
|
||||
"Launcher",
|
||||
"Netcode",
|
||||
"Normal (Deprecated)",
|
||||
"Normal",
|
||||
"Object",
|
||||
"Pathing",
|
||||
"QS Server (Deprecated)",
|
||||
"QS Server",
|
||||
"Quests",
|
||||
"Rules",
|
||||
"Skills",
|
||||
"Spawns",
|
||||
"Spells",
|
||||
"Status (Deprecated)",
|
||||
"Status",
|
||||
"TCP Connection",
|
||||
"Tasks",
|
||||
"Tradeskills",
|
||||
"Trading",
|
||||
"Tribute",
|
||||
"UCS Server (Deprecated)",
|
||||
"Web Interface (Deprecated)",
|
||||
"World Server (Deprecated)",
|
||||
"Zone Server (Deprecated)",
|
||||
"QueryErr",
|
||||
"Query",
|
||||
"UCS Server",
|
||||
"WebInterface Server",
|
||||
"World Server",
|
||||
"Zone Server",
|
||||
"MySQL Error",
|
||||
"MySQL Query",
|
||||
"Mercenaries",
|
||||
"Quest Debug",
|
||||
"Legacy Packet Logging (Deprecated)",
|
||||
"Legacy Packet Logging (Deprecated)",
|
||||
"Legacy Packet Logging (Deprecated)",
|
||||
"Legacy Packet Logging (Deprecated)",
|
||||
"Login Server (Deprecated)",
|
||||
"Packet :: Server -> Client",
|
||||
"Packet :: Client -> Server Unhandled",
|
||||
"Packet :: Server -> Client (Dump)",
|
||||
"Packet :: Client -> Server (Dump)",
|
||||
"Login Server",
|
||||
"Client Login",
|
||||
"Headless Client (Deprecated)",
|
||||
"Headless Client",
|
||||
"HP Update",
|
||||
"FixZ",
|
||||
"Food",
|
||||
"Traps",
|
||||
"NPC Roam Box",
|
||||
"NPC Scaling",
|
||||
"MobAppearance",
|
||||
"Mob Appearance",
|
||||
"Info",
|
||||
"Warning",
|
||||
"Critical (Deprecated)",
|
||||
"Emergency (Deprecated)",
|
||||
"Alert (Deprecated)",
|
||||
"Notice (Deprecated)",
|
||||
"AI Scan",
|
||||
"AI Yell",
|
||||
"AI CastBeneficial",
|
||||
"Critical",
|
||||
"Emergency",
|
||||
"Alert",
|
||||
"Notice",
|
||||
"AI Scan Close",
|
||||
"AI Yell For Help",
|
||||
"AI Cast Beneficial Close",
|
||||
"AOE Cast",
|
||||
"Entity Management",
|
||||
"Flee",
|
||||
@@ -216,30 +201,11 @@ namespace Logs {
|
||||
"Expeditions",
|
||||
"DynamicZones",
|
||||
"Scheduler",
|
||||
"Cheat",
|
||||
"ClientList",
|
||||
"DialogueWindow",
|
||||
"HTTP",
|
||||
"Saylink",
|
||||
"ChecksumVer",
|
||||
"CombatRecord",
|
||||
"Hate",
|
||||
"Discord",
|
||||
"Faction",
|
||||
"Packet S->C",
|
||||
"Packet C->S",
|
||||
"Packet S->S",
|
||||
"Bugs",
|
||||
"QuestErrors"
|
||||
};
|
||||
}
|
||||
|
||||
#include "eqemu_logsys_log_aliases.h"
|
||||
|
||||
class Database;
|
||||
|
||||
constexpr uint16 MAX_DISCORD_WEBHOOK_ID = 300;
|
||||
|
||||
class EQEmuLogSys {
|
||||
public:
|
||||
EQEmuLogSys();
|
||||
@@ -250,8 +216,7 @@ public:
|
||||
* This should be handled on deconstructor but to be safe we use it anyways.
|
||||
*/
|
||||
void CloseFileLogs();
|
||||
EQEmuLogSys *LoadLogSettingsDefaults();
|
||||
EQEmuLogSys *LoadLogDatabaseSettings();
|
||||
void LoadLogSettingsDefaults();
|
||||
|
||||
/**
|
||||
* @param directory_name
|
||||
@@ -281,7 +246,7 @@ public:
|
||||
* Used in file logs to prepend a timestamp entry for logs
|
||||
* @param time_stamp
|
||||
*/
|
||||
void SetCurrentTimeStamp(char *time_stamp);
|
||||
void SetCurrentTimeStamp(char* time_stamp);
|
||||
|
||||
/**
|
||||
* @param log_name
|
||||
@@ -302,98 +267,108 @@ public:
|
||||
uint8 log_to_file;
|
||||
uint8 log_to_console;
|
||||
uint8 log_to_gmsay;
|
||||
uint8 log_to_discord;
|
||||
int discord_webhook_id;
|
||||
uint8 is_category_enabled; /* When any log output in a category > 0, set this to 1 as (Enabled) */
|
||||
};
|
||||
|
||||
struct OriginationInfo {
|
||||
std::string zone_short_name;
|
||||
std::string zone_long_name;
|
||||
int instance_id;
|
||||
};
|
||||
|
||||
OriginationInfo origination_info{};
|
||||
|
||||
/**
|
||||
* Internally used memory reference for all log settings per category
|
||||
* These are loaded via DB and have defaults loaded in LoadLogSettingsDefaults
|
||||
* Database loaded via LogSys.SetDatabase(&database)->LoadLogDatabaseSettings();
|
||||
* Database loaded via Database::LoadLogSettings(log_settings)
|
||||
*/
|
||||
LogSettings log_settings[Logs::LogCategory::MaxCategoryID]{};
|
||||
|
||||
struct LogEnabled {
|
||||
bool log_to_file_enabled;
|
||||
bool log_to_console_enabled;
|
||||
bool log_to_gmsay_enabled;
|
||||
bool log_to_discord_enabled;
|
||||
bool log_enabled;
|
||||
};
|
||||
bool file_logs_enabled = false;
|
||||
|
||||
LogEnabled GetLogsEnabled(const Logs::DebugLevel &debug_level, const uint16 &log_category);
|
||||
bool IsLogEnabled(const Logs::DebugLevel &debug_level, const uint16 &log_category);
|
||||
/**
|
||||
* Sets Executable platform (Zone/World/UCS) etc.
|
||||
*/
|
||||
int log_platform = 0;
|
||||
|
||||
struct DiscordWebhooks {
|
||||
int id;
|
||||
std::string webhook_name;
|
||||
std::string webhook_url;
|
||||
};
|
||||
/**
|
||||
* File name used in writing logs
|
||||
*/
|
||||
std::string platform_file_name;
|
||||
|
||||
const DiscordWebhooks *GetDiscordWebhooks() const;
|
||||
|
||||
// gmsay
|
||||
/**
|
||||
* GMSay Client Message colors mapped by category
|
||||
*
|
||||
* @param log_category
|
||||
* @return
|
||||
*/
|
||||
uint16 GetGMSayColorFromCategory(uint16 log_category);
|
||||
|
||||
EQEmuLogSys *SetGMSayHandler(const std::function<void(uint16 log_type, const char *func, const std::string &)>& f)
|
||||
{
|
||||
m_on_log_gmsay_hook = f;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* @param f
|
||||
*/
|
||||
void SetGMSayHandler(std::function<void(uint16 log_type, const std::string&)> f) { on_log_gmsay_hook = f; }
|
||||
|
||||
EQEmuLogSys *SetDiscordHandler(std::function<void(uint16 log_category, int webhook_id, const std::string &)> f)
|
||||
{
|
||||
m_on_log_discord_hook = f;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* @param f
|
||||
*/
|
||||
void SetConsoleHandler(std::function<void(uint16 debug_level, uint16 log_type, const std::string&)> f) { on_log_console_hook = f; }
|
||||
|
||||
// console
|
||||
void SetConsoleHandler(
|
||||
std::function<void(
|
||||
uint16 log_type,
|
||||
const std::string &
|
||||
)> f
|
||||
) { m_on_log_console_hook = f; }
|
||||
/**
|
||||
* Silence console logging
|
||||
*/
|
||||
void SilenceConsoleLogging();
|
||||
|
||||
/**
|
||||
* Turn on all console logging
|
||||
*/
|
||||
void EnableConsoleLogging();
|
||||
|
||||
// database
|
||||
EQEmuLogSys *SetDatabase(Database *db);
|
||||
|
||||
[[nodiscard]] const std::string &GetLogPath() const;
|
||||
EQEmuLogSys * SetLogPath(const std::string &log_path);
|
||||
|
||||
private:
|
||||
|
||||
// reference to database
|
||||
Database *m_database;
|
||||
std::function<void(uint16 log_category, const char *func, const std::string &)> m_on_log_gmsay_hook;
|
||||
std::function<void(uint16 log_category, int webhook_id, const std::string &)> m_on_log_discord_hook;
|
||||
std::function<void(uint16 log_category, const std::string &)> m_on_log_console_hook;
|
||||
DiscordWebhooks m_discord_webhooks[MAX_DISCORD_WEBHOOK_ID]{};
|
||||
bool m_file_logs_enabled = false;
|
||||
int m_log_platform = 0;
|
||||
std::string m_platform_file_name;
|
||||
std::string m_log_path;
|
||||
/**
|
||||
* Callback pointer to zone process for hooking logs to zone using GMSay
|
||||
*/
|
||||
std::function<void(uint16 log_category, const std::string&)> on_log_gmsay_hook;
|
||||
std::function<void(uint16 debug_level, uint16 log_category, const std::string&)> on_log_console_hook;
|
||||
|
||||
void ProcessConsoleMessage(
|
||||
uint16 log_category,
|
||||
const std::string &message,
|
||||
const char *file,
|
||||
const char *func,
|
||||
int line
|
||||
);
|
||||
void ProcessLogWrite(uint16 log_category, const std::string &message);
|
||||
void InjectTablesIfNotExist();
|
||||
/**
|
||||
* Formats log messages like '[Category] This is a log message'
|
||||
*/
|
||||
std::string FormatOutMessageString(uint16 log_category, const std::string &in_message);
|
||||
|
||||
/**
|
||||
* Linux console color messages mapped by category
|
||||
*
|
||||
* @param log_category
|
||||
* @return
|
||||
*/
|
||||
std::string GetLinuxConsoleColorFromCategory(uint16 log_category);
|
||||
|
||||
/**
|
||||
* Windows console color messages mapped by category
|
||||
*/
|
||||
uint16 GetWindowsConsoleColorFromCategory(uint16 log_category);
|
||||
|
||||
/**
|
||||
* @param debug_level
|
||||
* @param log_category
|
||||
* @param message
|
||||
*/
|
||||
void ProcessConsoleMessage(uint16 debug_level, uint16 log_category, const std::string &message);
|
||||
|
||||
/**
|
||||
* @param debug_level
|
||||
* @param log_category
|
||||
* @param message
|
||||
*/
|
||||
void ProcessGMSay(uint16 debug_level, uint16 log_category, const std::string &message);
|
||||
|
||||
/**
|
||||
* @param debug_level
|
||||
* @param log_category
|
||||
* @param message
|
||||
*/
|
||||
void ProcessLogWrite(uint16 debug_level, uint16 log_category, const std::string &message);
|
||||
|
||||
/**
|
||||
* @param log_category
|
||||
* @return
|
||||
*/
|
||||
bool IsRfc5424LogCategory(uint16 log_category);
|
||||
};
|
||||
|
||||
extern EQEmuLogSys LogSys;
|
||||
|
||||
+563
-333
File diff suppressed because it is too large
Load Diff
+4
-4
@@ -1,14 +1,14 @@
|
||||
#pragma once
|
||||
#include <any>
|
||||
#include <functional>
|
||||
#include <exception>
|
||||
#include "event_loop.h"
|
||||
#include "../any.h"
|
||||
|
||||
namespace EQ {
|
||||
class Task
|
||||
{
|
||||
public:
|
||||
typedef std::function<void(const std::any&)> ResolveFn;
|
||||
typedef std::function<void(const EQ::Any&)> ResolveFn;
|
||||
typedef std::function<void(const std::exception&)> RejectFn;
|
||||
typedef std::function<void()> FinallyFn;
|
||||
typedef std::function<void(ResolveFn, RejectFn)> TaskFn;
|
||||
@@ -19,7 +19,7 @@ namespace EQ {
|
||||
RejectFn on_catch;
|
||||
FinallyFn on_finally;
|
||||
bool has_result;
|
||||
std::any result;
|
||||
EQ::Any result;
|
||||
bool has_error;
|
||||
std::exception error;
|
||||
};
|
||||
@@ -63,7 +63,7 @@ namespace EQ {
|
||||
uv_queue_work(EventLoop::Get().Handle(), m_work, [](uv_work_t* req) {
|
||||
TaskBaton *baton = (TaskBaton*)req->data;
|
||||
|
||||
baton->fn([baton](const std::any& result) {
|
||||
baton->fn([baton](const EQ::Any& result) {
|
||||
baton->has_error = false;
|
||||
baton->has_result = true;
|
||||
baton->result = result;
|
||||
|
||||
@@ -60,8 +60,8 @@ namespace EQ
|
||||
}
|
||||
|
||||
template<typename Fn, typename... Args>
|
||||
auto Enqueue(Fn&& fn, Args&&... args) -> std::future<typename std::invoke_result<Fn, Args...>::type> {
|
||||
using return_type = typename std::invoke_result<Fn, Args...>::type;
|
||||
auto Enqueue(Fn&& fn, Args&&... args) -> std::future<typename std::result_of<Fn(Args...)>::type> {
|
||||
using return_type = typename std::result_of<Fn(Args...)>::type;
|
||||
|
||||
auto task = std::make_shared<std::packaged_task<return_type()>>(
|
||||
std::bind(std::forward<Fn>(fn), std::forward<Args>(args)...)
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
#include "expedition_base.h"
|
||||
#include "repositories/expeditions_repository.h"
|
||||
|
||||
ExpeditionBase::ExpeditionBase(uint32_t id, const std::string& uuid,
|
||||
const std::string& expedition_name, const DynamicZoneMember& leader
|
||||
) :
|
||||
m_id(id),
|
||||
m_uuid(uuid),
|
||||
m_expedition_name(expedition_name),
|
||||
m_leader(leader)
|
||||
{
|
||||
}
|
||||
|
||||
void ExpeditionBase::LoadRepositoryResult(ExpeditionsRepository::ExpeditionWithLeader&& entry)
|
||||
{
|
||||
m_id = entry.id;
|
||||
m_uuid = std::move(entry.uuid);
|
||||
m_expedition_name = std::move(entry.expedition_name);
|
||||
m_add_replay_on_join = entry.add_replay_on_join;
|
||||
m_is_locked = entry.is_locked;
|
||||
m_leader.id = entry.leader_id;
|
||||
m_leader.name = std::move(entry.leader_name);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
#ifndef COMMON_EXPEDITION_BASE_H
|
||||
#define COMMON_EXPEDITION_BASE_H
|
||||
|
||||
#include "dynamic_zone_base.h"
|
||||
#include "repositories/expeditions_repository.h"
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
class ExpeditionBase
|
||||
{
|
||||
public:
|
||||
virtual ~ExpeditionBase() = default;
|
||||
ExpeditionBase(const ExpeditionBase&) = default;
|
||||
ExpeditionBase(ExpeditionBase&&) = default;
|
||||
ExpeditionBase& operator=(const ExpeditionBase&) = default;
|
||||
ExpeditionBase& operator=(ExpeditionBase&&) = default;
|
||||
|
||||
uint32_t GetID() const { return m_id; }
|
||||
uint32_t GetLeaderID() const { return m_leader.id; }
|
||||
const std::string& GetName() const { return m_expedition_name; }
|
||||
const std::string& GetLeaderName() const { return m_leader.name; }
|
||||
const std::string& GetUUID() const { return m_uuid; }
|
||||
const DynamicZoneMember& GetLeader() const { return m_leader; }
|
||||
|
||||
void LoadRepositoryResult(ExpeditionsRepository::ExpeditionWithLeader&& entry);
|
||||
|
||||
protected:
|
||||
ExpeditionBase() = default;
|
||||
ExpeditionBase(uint32_t id, const std::string& uuid, const std::string& expedition_name,
|
||||
const DynamicZoneMember& leader);
|
||||
|
||||
uint32_t m_id = 0;
|
||||
bool m_is_locked = false;
|
||||
bool m_add_replay_on_join = true;
|
||||
std::string m_uuid;
|
||||
std::string m_expedition_name;
|
||||
DynamicZoneMember m_leader;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -19,7 +19,7 @@
|
||||
*/
|
||||
|
||||
#include "expedition_lockout_timer.h"
|
||||
#include "../common/strings.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/rulesys.h"
|
||||
#include "../common/util/uuid.h"
|
||||
#include <fmt/format.h>
|
||||
|
||||
+24
-24
@@ -20,31 +20,31 @@
|
||||
#include "races.h"
|
||||
#include "rulesys.h"
|
||||
|
||||
const char *FactionValueToString(FACTION_VALUE faction_value)
|
||||
const char *FactionValueToString(FACTION_VALUE fv)
|
||||
{
|
||||
switch (faction_value) {
|
||||
switch (fv) {
|
||||
case FACTION_ALLY:
|
||||
return "Ally";
|
||||
return ("Ally");
|
||||
case FACTION_WARMLY:
|
||||
return "Warmly";
|
||||
return ("Warmly");
|
||||
case FACTION_KINDLY:
|
||||
return "Kindly";
|
||||
case FACTION_AMIABLY:
|
||||
return "Amiably";
|
||||
case FACTION_INDIFFERENTLY:
|
||||
return "Indifferently";
|
||||
case FACTION_APPREHENSIVELY:
|
||||
return "Apprehensively";
|
||||
case FACTION_DUBIOUSLY:
|
||||
return "Dubiously";
|
||||
case FACTION_THREATENINGLY:
|
||||
return "Threateningly";
|
||||
return ("Kindly");
|
||||
case FACTION_AMIABLE:
|
||||
return ("Amiable");
|
||||
case FACTION_INDIFFERENT:
|
||||
return ("Indifferent");
|
||||
case FACTION_APPREHENSIVE:
|
||||
return ("Apprehensive");
|
||||
case FACTION_DUBIOUS:
|
||||
return ("Dubious");
|
||||
case FACTION_THREATENLY:
|
||||
return ("Threatenly");
|
||||
case FACTION_SCOWLS:
|
||||
return "Scowls";
|
||||
return ("Scowls, ready to attack.");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return "Unknown";
|
||||
return ("Unknown Faction Con");
|
||||
}
|
||||
|
||||
|
||||
@@ -70,19 +70,19 @@ FACTION_VALUE CalculateFaction(FactionMods* fm, int32 tmpCharacter_value)
|
||||
return FACTION_KINDLY;
|
||||
}
|
||||
if (character_value >= RuleI(Faction, AmiablyFactionMinimum)) {
|
||||
return FACTION_AMIABLY;
|
||||
return FACTION_AMIABLE;
|
||||
}
|
||||
if (character_value >= RuleI(Faction, IndifferentlyFactionMinimum)) {
|
||||
return FACTION_INDIFFERENTLY;
|
||||
return FACTION_INDIFFERENT;
|
||||
}
|
||||
if (character_value >= RuleI(Faction, ApprehensivelyFactionMinimum)) {
|
||||
return FACTION_APPREHENSIVELY;
|
||||
return FACTION_APPREHENSIVE;
|
||||
}
|
||||
if (character_value >= RuleI(Faction, DubiouslyFactionMinimum)) {
|
||||
return FACTION_DUBIOUSLY;
|
||||
return FACTION_DUBIOUS;
|
||||
}
|
||||
if (character_value >= RuleI(Faction, ThreateninglyFactionMinimum)) {
|
||||
return FACTION_THREATENINGLY;
|
||||
return FACTION_THREATENLY;
|
||||
}
|
||||
return FACTION_SCOWLS;
|
||||
}
|
||||
@@ -96,12 +96,12 @@ bool IsOfEqualRace(int r1, int r2)
|
||||
// TODO: add more values
|
||||
switch (r1) {
|
||||
case DARK_ELF:
|
||||
if (r2 == RACE_NERIAK_CITIZEN_77) {
|
||||
if (r2 == 77) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case BARBARIAN:
|
||||
if (r2 == RACE_HALAS_CITIZEN_90) {
|
||||
if (r2 == 90) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
+10
-27
@@ -27,13 +27,13 @@ enum FACTION_VALUE {
|
||||
FACTION_ALLY = 1,
|
||||
FACTION_WARMLY = 2,
|
||||
FACTION_KINDLY = 3,
|
||||
FACTION_AMIABLY = 4,
|
||||
FACTION_AMIABLE = 4,
|
||||
|
||||
FACTION_INDIFFERENTLY = 5,
|
||||
FACTION_INDIFFERENT = 5,
|
||||
|
||||
FACTION_APPREHENSIVELY = 6,
|
||||
FACTION_DUBIOUSLY = 7,
|
||||
FACTION_THREATENINGLY = 8,
|
||||
FACTION_APPREHENSIVE = 6,
|
||||
FACTION_DUBIOUS = 7,
|
||||
FACTION_THREATENLY = 8,
|
||||
FACTION_SCOWLS = 9
|
||||
};
|
||||
|
||||
@@ -50,8 +50,8 @@ struct NPCFactionList {
|
||||
struct FactionMods
|
||||
{
|
||||
int32 base;
|
||||
int16 min; // The lowest your personal earned faction can go - before race/class/deity adjustments.
|
||||
int16 max; // The highest your personal earned faction can go - before race/class/deity adjustments.
|
||||
int16 min; // The lowest your personal earned faction can go - before race/class/diety adjustments.
|
||||
int16 max; // The highest your personal earned faction can go - before race/class/diety adjustments.
|
||||
int32 class_mod;
|
||||
int32 race_mod;
|
||||
int32 deity_mod;
|
||||
@@ -61,8 +61,8 @@ struct Faction {
|
||||
int32 id;
|
||||
std::map<std::string, int16> mods;
|
||||
int16 base;
|
||||
int16 min; // The lowest your personal earned faction can go - before race/class/deity adjustments.
|
||||
int16 max; // The highest your personal earned faction can go - before race/class/deity adjustments.
|
||||
int16 min; // The lowest your personal earned faction can go - before race/class/diety adjustments.
|
||||
int16 max; // The highest your personal earned faction can go - before race/class/diety adjustments.
|
||||
char name[50];
|
||||
};
|
||||
|
||||
@@ -75,23 +75,6 @@ struct NPCFaction
|
||||
uint8 temp;
|
||||
};
|
||||
|
||||
// Faction Associations give a much more live like faction system
|
||||
// Basically the primary faction and magnitude of a faction hit will generate the rest of them
|
||||
|
||||
// Largest faction I could find quickly was Lord Inquisitor Seru with 9 total hits (8 associations) so 8 + 2 for max for now
|
||||
#define MAX_FACTION_ASSOC 10
|
||||
|
||||
// this is the ID of a faction association and it's multiplier
|
||||
struct FactionAssociationHit {
|
||||
int id;
|
||||
float multiplier;
|
||||
};
|
||||
|
||||
struct FactionAssociations {
|
||||
// maybe there should be more data here, fine for now
|
||||
FactionAssociationHit hits[MAX_FACTION_ASSOC];
|
||||
};
|
||||
|
||||
const char *FactionValueToString(FACTION_VALUE faction_value);
|
||||
const char *FactionValueToString(FACTION_VALUE fv);
|
||||
FACTION_VALUE CalculateFaction(FactionMods* fm, int32 tmpCharacter_value);
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -204,7 +204,7 @@ enum { //some random constants
|
||||
#define MIN_LEVEL_ALCHEMY 25
|
||||
|
||||
//chance ratio that a
|
||||
#define THREATENINGLY_AGGRO_CHANCE 32 // 32/128 (25%) chance that a mob will arrgo on con Threatenly
|
||||
#define THREATENLY_ARRGO_CHANCE 32 // 32/128 (25%) chance that a mob will arrgo on con Threatenly
|
||||
|
||||
//max factions per npc faction list
|
||||
#define MAX_NPC_FACTIONS 20
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
*/
|
||||
|
||||
#include <fstream>
|
||||
#include "file.h"
|
||||
#include "file_util.h"
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#include <direct.h>
|
||||
@@ -35,48 +35,33 @@
|
||||
|
||||
#endif
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <filesystem>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
bool File::Exists(const std::string &name)
|
||||
bool FileUtil::exists(const std::string &name)
|
||||
{
|
||||
return fs::exists(fs::path{name});
|
||||
std::ifstream f(name.c_str());
|
||||
|
||||
return f.good();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param directory_name
|
||||
*/
|
||||
void File::Makedir(const std::string &directory_name)
|
||||
void FileUtil::mkdir(const std::string& directory_name)
|
||||
{
|
||||
fs::create_directory(directory_name);
|
||||
fs::permissions(directory_name, fs::perms::owner_all);
|
||||
}
|
||||
|
||||
std::string File::FindEqemuConfigPath()
|
||||
{
|
||||
if (File::Exists(fs::path{File::GetCwd() + "/eqemu_config.json"}.string())) {
|
||||
return File::GetCwd();
|
||||
#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;
|
||||
}
|
||||
else if (File::Exists(fs::path{File::GetCwd() + "/../eqemu_config.json"}.string())) {
|
||||
return canonical(fs::path{File::GetCwd() + "/../"}).string();
|
||||
}
|
||||
else if (File::Exists(fs::path{File::GetCwd() + "/login.json"}.string())) {
|
||||
return File::GetCwd();
|
||||
}
|
||||
else if (File::Exists(fs::path{File::GetCwd() + "/../login.json"}.string())) {
|
||||
return canonical(fs::path{File::GetCwd() + "/../"}).string();
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string File::GetCwd()
|
||||
{
|
||||
return fs::current_path().string();
|
||||
}
|
||||
::mkdir(directory_name.c_str(), 0755);
|
||||
#endif
|
||||
}
|
||||
@@ -18,21 +18,15 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_FILE_H
|
||||
#define EQEMU_FILE_H
|
||||
#ifndef EQEMU_FILE_UTIL_H
|
||||
#define EQEMU_FILE_UTIL_H
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
class File {
|
||||
class FileUtil {
|
||||
public:
|
||||
static bool Exists(const std::string &name);
|
||||
static void Makedir(const std::string& directory_name);
|
||||
static std::string FindEqemuConfigPath();
|
||||
static std::string GetCwd();
|
||||
static bool exists(const std::string &name);
|
||||
static void mkdir(const std::string& directory_name);
|
||||
};
|
||||
|
||||
bool Exists(const std::string& name);
|
||||
|
||||
#endif //EQEMU_FILE_H
|
||||
#endif //EQEMU_FILE_UTIL_H
|
||||
+23
-71
@@ -20,7 +20,7 @@
|
||||
#include "database.h"
|
||||
|
||||
//#include "misc_functions.h"
|
||||
#include "strings.h"
|
||||
#include "string_util.h"
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
@@ -63,9 +63,7 @@ bool BaseGuildManager::LoadGuilds() {
|
||||
for (auto row=results.begin();row!=results.end();++row)
|
||||
_CreateGuild(atoi(row[0]), row[1], atoi(row[2]), atoi(row[3]), row[4], row[5], row[6], row[7]);
|
||||
|
||||
LogInfo("Loaded [{}] Guilds", Strings::Commify(std::to_string(results.RowCount())));
|
||||
|
||||
query = "SELECT guild_id,`rank`,title,can_hear,can_speak,can_invite,can_remove,can_promote,can_demote,can_motd,can_warpeace FROM guild_ranks";
|
||||
query = "SELECT guild_id,rank,title,can_hear,can_speak,can_invite,can_remove,can_promote,can_demote,can_motd,can_warpeace FROM guild_ranks";
|
||||
results = m_db->QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
@@ -133,7 +131,7 @@ bool BaseGuildManager::RefreshGuild(uint32 guild_id) {
|
||||
|
||||
info = _CreateGuild(guild_id, row[0], atoi(row[1]), atoi(row[2]), row[3], row[4], row[5], row[6]);
|
||||
|
||||
query = StringFormat("SELECT guild_id, `rank`, title, can_hear, can_speak, can_invite, can_remove, can_promote, can_demote, can_motd, can_warpeace "
|
||||
query = StringFormat("SELECT guild_id, rank, title, can_hear, can_speak, can_invite, can_remove, can_promote, can_demote, can_motd, can_warpeace "
|
||||
"FROM guild_ranks WHERE guild_id=%lu", (unsigned long)guild_id);
|
||||
results = m_db->QueryDatabase(query);
|
||||
|
||||
@@ -270,7 +268,7 @@ bool BaseGuildManager::_StoreGuildDB(uint32 guild_id) {
|
||||
m_db->DoEscapeString(title_esc, rankInfo.name.c_str(), rankInfo.name.length());
|
||||
|
||||
query = StringFormat("INSERT INTO guild_ranks "
|
||||
"(guild_id,`rank`,title,can_hear,can_speak,can_invite,can_remove,can_promote,can_demote,can_motd,can_warpeace)"
|
||||
"(guild_id,rank,title,can_hear,can_speak,can_invite,can_remove,can_promote,can_demote,can_motd,can_warpeace)"
|
||||
" VALUES(%d,%d,'%s',%d,%d,%d,%d,%d,%d,%d,%d)",
|
||||
guild_id, rank, title_esc,
|
||||
rankInfo.permissions[GUILD_HEAR],
|
||||
@@ -740,7 +738,7 @@ bool BaseGuildManager::DBSetGuild(uint32 charid, uint32 guild_id, uint8 rank) {
|
||||
std::string query;
|
||||
|
||||
if(guild_id != GUILD_NONE) {
|
||||
query = StringFormat("REPLACE INTO guild_members (char_id,guild_id,`rank`,public_note) VALUES(%d,%d,%d,'')", charid, guild_id, rank);
|
||||
query = StringFormat("REPLACE INTO guild_members (char_id,guild_id,rank,public_note) VALUES(%d,%d,%d,'')", charid, guild_id, rank);
|
||||
auto results = m_db->QueryDatabase(query);
|
||||
|
||||
if (!results.Success()) {
|
||||
@@ -760,7 +758,7 @@ bool BaseGuildManager::DBSetGuild(uint32 charid, uint32 guild_id, uint8 rank) {
|
||||
}
|
||||
|
||||
bool BaseGuildManager::DBSetGuildRank(uint32 charid, uint8 rank) {
|
||||
std::string query = StringFormat("UPDATE guild_members SET `rank`=%d WHERE char_id=%d", rank, charid);
|
||||
std::string query = StringFormat("UPDATE guild_members SET rank=%d WHERE char_id=%d", rank, charid);
|
||||
return(QueryWithLogging(query, "setting a guild member's rank"));
|
||||
}
|
||||
|
||||
@@ -866,11 +864,20 @@ bool BaseGuildManager::QueryWithLogging(std::string query, const char *errmsg) {
|
||||
return(true);
|
||||
}
|
||||
|
||||
//factored out so I dont have to copy this crap.
|
||||
#ifdef BOTS
|
||||
#define GuildMemberBaseQuery \
|
||||
"SELECT c.`id`, c.`name`, c.`class`, c.`level`, c.`last_login`, c.`zone_id`," \
|
||||
" g.`guild_id`, g.`rank`, g.`tribute_enable`, g.`total_tribute`, g.`last_tribute`," \
|
||||
" g.`banker`, g.`public_note`, g.`alt`" \
|
||||
" FROM `vw_bot_character_mobs` AS c LEFT JOIN `vw_guild_members` AS g ON c.`id` = g.`char_id` AND c.`mob_type` = g.`mob_type` "
|
||||
#else
|
||||
#define GuildMemberBaseQuery \
|
||||
"SELECT c.`id`, c.`name`, c.`class`, c.`level`, c.`last_login`, c.`zone_id`," \
|
||||
" g.`guild_id`, g.`rank`, g.`tribute_enable`, g.`total_tribute`, g.`last_tribute`," \
|
||||
" g.`banker`, g.`public_note`, g.`alt` " \
|
||||
" FROM `character_data` AS c LEFT JOIN `guild_members` AS g ON c.`id` = g.`char_id` "
|
||||
#endif
|
||||
static void ProcessGuildMember(MySQLRequestRow row, CharGuildInfo &into) {
|
||||
//fields from `characer_`
|
||||
into.char_id = atoi(row[0]);
|
||||
@@ -960,8 +967,13 @@ bool BaseGuildManager::GetCharInfo(uint32 char_id, CharGuildInfo &into) {
|
||||
}
|
||||
|
||||
//load up the rank info for each guild.
|
||||
std::string query = StringFormat(GuildMemberBaseQuery " WHERE c.id=%d AND c.deleted_at IS NULL", char_id);
|
||||
auto results = m_db->QueryDatabase(query);
|
||||
std::string query;
|
||||
#ifdef BOTS
|
||||
query = StringFormat(GuildMemberBaseQuery " WHERE c.id=%d AND c.mob_type = 'C' AND c.deleted_at IS NULL", char_id);
|
||||
#else
|
||||
query = StringFormat(GuildMemberBaseQuery " WHERE c.id=%d AND c.deleted_at IS NULL", char_id);
|
||||
#endif
|
||||
auto results = m_db->QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
@@ -1196,7 +1208,7 @@ BaseGuildManager::RankInfo::RankInfo() {
|
||||
|
||||
BaseGuildManager::GuildInfo::GuildInfo() {
|
||||
leader_char_id = 0;
|
||||
minstatus = AccountStatus::Player;
|
||||
minstatus = 0;
|
||||
}
|
||||
|
||||
uint32 BaseGuildManager::DoesAccountContainAGuildLeader(uint32 AccountID)
|
||||
@@ -1213,66 +1225,6 @@ uint32 BaseGuildManager::DoesAccountContainAGuildLeader(uint32 AccountID)
|
||||
return results.RowCount();
|
||||
}
|
||||
|
||||
std::string BaseGuildManager::GetGuildNameByID(uint32 guild_id) const {
|
||||
if(guild_id == GUILD_NONE) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::map<uint32, GuildInfo *>::const_iterator res;
|
||||
res = m_guilds.find(guild_id);
|
||||
if(res == m_guilds.end()) {
|
||||
return "Invalid Guild";
|
||||
}
|
||||
|
||||
return res->second->name;
|
||||
}
|
||||
|
||||
std::string BaseGuildManager::GetGuildRankName(uint32 guild_id, uint8 rank) const
|
||||
{
|
||||
if(rank > GUILD_MAX_RANK) {
|
||||
return "Invalid Rank";
|
||||
}
|
||||
|
||||
std::map<uint32, GuildInfo *>::const_iterator res;
|
||||
res = m_guilds.find(guild_id);
|
||||
if(res == m_guilds.end()) {
|
||||
return "Invalid Guild Rank";
|
||||
}
|
||||
|
||||
return res->second->ranks[rank].name;
|
||||
}
|
||||
|
||||
uint32 BaseGuildManager::GetGuildIDByCharacterID(uint32 character_id)
|
||||
{
|
||||
if(!m_db) {
|
||||
return GUILD_NONE;
|
||||
}
|
||||
|
||||
std::string query = fmt::format(
|
||||
"SELECT `guild_id` FROM `guild_members` WHERE char_id = {} LIMIT 1",
|
||||
character_id
|
||||
);
|
||||
auto results = m_db->QueryDatabase(query);
|
||||
if(!results.Success() || !results.RowCount()) {
|
||||
return GUILD_NONE;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
auto guild_id = std::stoul(row[0]);
|
||||
return guild_id;
|
||||
}
|
||||
|
||||
bool BaseGuildManager::IsCharacterInGuild(uint32 character_id, uint32 guild_id)
|
||||
{
|
||||
auto current_guild_id = GetGuildIDByCharacterID(character_id);
|
||||
|
||||
if (current_guild_id == GUILD_NONE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (guild_id && current_guild_id != guild_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -76,12 +76,8 @@ class BaseGuildManager
|
||||
bool GetGuildChannel(uint32 GuildID, char *ChannelBuffer) const;
|
||||
const char *GetRankName(uint32 guild_id, uint8 rank) const;
|
||||
const char *GetGuildName(uint32 guild_id) const;
|
||||
std::string GetGuildNameByID(uint32 guild_id) const;
|
||||
std::string GetGuildRankName(uint32 guild_id, uint8 rank) const;
|
||||
bool IsCharacterInGuild(uint32 character_id, uint32 guild_id = 0);
|
||||
bool GetGuildNameByID(uint32 guild_id, std::string &into) const;
|
||||
uint32 GetGuildIDByName(const char *GuildName);
|
||||
uint32 GetGuildIDByCharacterID(uint32 character_id);
|
||||
bool IsGuildLeader(uint32 guild_id, uint32 char_id) const;
|
||||
uint8 GetDisplayedRank(uint32 guild_id, uint8 rank, uint32 char_id) const;
|
||||
bool CheckGMStatus(uint32 guild_id, uint8 status) const;
|
||||
|
||||
+1747
-7439
File diff suppressed because it is too large
Load Diff
@@ -1,633 +0,0 @@
|
||||
// Copyright (C) 2015 Ben Lewis <benjf5+github@gmail.com>
|
||||
// Licensed under the MIT license.
|
||||
// https://github.com/ben-zen/uri-library
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cctype>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
class uri {
|
||||
/* URIs are broadly divided into two categories: hierarchical and
|
||||
* non-hierarchical. Both hierarchical URIs and non-hierarchical URIs have a
|
||||
* few elements in common; all URIs have a scheme of one or more alphanumeric
|
||||
* characters followed by a colon, and they all may optionally have a query
|
||||
* component preceded by a question mark, and a fragment component preceded by
|
||||
* an octothorpe (hash mark: '#'). The query consists of stanzas separated by
|
||||
* either ampersands ('&') or semicolons (';') (but only one or the other),
|
||||
* and each stanza consists of a key and an optional value; if the value
|
||||
* exists, the key and value must be divided by an equals sign.
|
||||
*
|
||||
* The following is an example from Wikipedia of a hierarchical URI:
|
||||
* scheme:[//[user:password@]domain[:port]][/]path[?query][#fragment]
|
||||
*/
|
||||
|
||||
public:
|
||||
|
||||
enum class scheme_category {
|
||||
Hierarchical,
|
||||
NonHierarchical
|
||||
};
|
||||
|
||||
enum class component {
|
||||
Scheme,
|
||||
Content,
|
||||
Username,
|
||||
Password,
|
||||
Host,
|
||||
Port,
|
||||
Path,
|
||||
Query,
|
||||
Fragment
|
||||
};
|
||||
|
||||
enum class query_argument_separator {
|
||||
ampersand,
|
||||
semicolon
|
||||
};
|
||||
|
||||
uri(
|
||||
char const *uri_text, scheme_category category = scheme_category::Hierarchical,
|
||||
query_argument_separator separator = query_argument_separator::ampersand
|
||||
) :
|
||||
m_category(category),
|
||||
m_path_is_rooted(false),
|
||||
m_port(0),
|
||||
m_separator(separator)
|
||||
{
|
||||
setup(std::string(uri_text), category);
|
||||
};
|
||||
|
||||
uri(
|
||||
std::string const &uri_text, scheme_category category = scheme_category::Hierarchical,
|
||||
query_argument_separator separator = query_argument_separator::ampersand
|
||||
) :
|
||||
m_category(category),
|
||||
m_path_is_rooted(false),
|
||||
m_port(0),
|
||||
m_separator(separator)
|
||||
{
|
||||
setup(uri_text, category);
|
||||
};
|
||||
|
||||
uri(
|
||||
std::map<component, std::string> const &components,
|
||||
scheme_category category,
|
||||
bool rooted_path,
|
||||
query_argument_separator separator = query_argument_separator::ampersand
|
||||
) :
|
||||
m_category(category),
|
||||
m_path_is_rooted(rooted_path),
|
||||
m_separator(separator)
|
||||
{
|
||||
if (components.count(component::Scheme)) {
|
||||
if (components.at(component::Scheme).length() == 0) {
|
||||
throw std::invalid_argument("Scheme cannot be empty.");
|
||||
}
|
||||
m_scheme = components.at(component::Scheme);
|
||||
}
|
||||
else {
|
||||
throw std::invalid_argument("A URI must have a scheme.");
|
||||
}
|
||||
|
||||
if (category == scheme_category::Hierarchical) {
|
||||
if (components.count(component::Content)) {
|
||||
throw std::invalid_argument("The content component is only for use in non-hierarchical URIs.");
|
||||
}
|
||||
|
||||
bool has_username = components.count(component::Username);
|
||||
bool has_password = components.count(component::Password);
|
||||
if (has_username && has_password) {
|
||||
m_username = components.at(component::Username);
|
||||
m_password = components.at(component::Password);
|
||||
}
|
||||
else if ((has_username && !has_password) || (!has_username && has_password)) {
|
||||
throw std::invalid_argument("If a username or password is supplied, both must be provided.");
|
||||
}
|
||||
|
||||
if (components.count(component::Host)) {
|
||||
m_host = components.at(component::Host);
|
||||
}
|
||||
|
||||
if (components.count(component::Port)) {
|
||||
m_port = std::stoul(components.at(component::Port));
|
||||
}
|
||||
|
||||
if (components.count(component::Path)) {
|
||||
m_path = components.at(component::Path);
|
||||
}
|
||||
else {
|
||||
throw std::invalid_argument("A path is required on a hierarchical URI, even an empty path.");
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (components.count(component::Username)
|
||||
|| components.count(component::Password)
|
||||
|| components.count(component::Host)
|
||||
|| components.count(component::Port)
|
||||
|| components.count(component::Path)) {
|
||||
throw std::invalid_argument("None of the hierarchical components are allowed in a non-hierarchical URI.");
|
||||
}
|
||||
|
||||
if (components.count(component::Content)) {
|
||||
m_content = components.at(component::Content);
|
||||
}
|
||||
else {
|
||||
throw std::invalid_argument(
|
||||
"Content is a required component for a non-hierarchical URI, even an empty string."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (components.count(component::Query)) {
|
||||
m_query = components.at(component::Query);
|
||||
}
|
||||
|
||||
if (components.count(component::Fragment)) {
|
||||
m_fragment = components.at(component::Fragment);
|
||||
}
|
||||
}
|
||||
|
||||
uri(uri const &other, std::map<component, std::string> const &replacements) :
|
||||
m_category(other.m_category),
|
||||
m_path_is_rooted(other.m_path_is_rooted),
|
||||
m_separator(other.m_separator)
|
||||
{
|
||||
m_scheme = (replacements.count(component::Scheme))
|
||||
? replacements.at(component::Scheme) : other.m_scheme;
|
||||
|
||||
if (m_category == scheme_category::Hierarchical) {
|
||||
m_username = (replacements.count(component::Username))
|
||||
? replacements.at(component::Username) : other.m_username;
|
||||
|
||||
m_password = (replacements.count(component::Password))
|
||||
? replacements.at(component::Password) : other.m_password;
|
||||
|
||||
m_host = (replacements.count(component::Host))
|
||||
? replacements.at(component::Host) : other.m_host;
|
||||
|
||||
m_port = (replacements.count(component::Port))
|
||||
? std::stoul(replacements.at(component::Port)) : other.m_port;
|
||||
|
||||
m_path = (replacements.count(component::Path))
|
||||
? replacements.at(component::Path) : other.m_path;
|
||||
}
|
||||
else {
|
||||
m_content = (replacements.count(component::Content))
|
||||
? replacements.at(component::Content) : other.m_content;
|
||||
}
|
||||
|
||||
m_query = (replacements.count(component::Query))
|
||||
? replacements.at(component::Query) : other.m_query;
|
||||
|
||||
m_fragment = (replacements.count(component::Fragment))
|
||||
? replacements.at(component::Fragment) : other.m_fragment;
|
||||
}
|
||||
|
||||
// Copy constructor; just use the copy assignment operator internally.
|
||||
uri(uri const &other)
|
||||
{
|
||||
*this = other;
|
||||
};
|
||||
|
||||
// Copy assignment operator
|
||||
uri &operator=(uri const &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
m_scheme = other.m_scheme;
|
||||
m_content = other.m_content;
|
||||
m_username = other.m_username;
|
||||
m_password = other.m_password;
|
||||
m_host = other.m_host;
|
||||
m_path = other.m_path;
|
||||
m_query = other.m_query;
|
||||
m_fragment = other.m_fragment;
|
||||
m_query_dict = other.m_query_dict;
|
||||
m_category = other.m_category;
|
||||
m_port = other.m_port;
|
||||
m_path_is_rooted = other.m_path_is_rooted;
|
||||
m_separator = other.m_separator;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
~uri() {};
|
||||
|
||||
std::string const &get_scheme() const
|
||||
{
|
||||
return m_scheme;
|
||||
};
|
||||
|
||||
scheme_category get_scheme_category() const
|
||||
{
|
||||
return m_category;
|
||||
};
|
||||
|
||||
std::string const &get_content() const
|
||||
{
|
||||
if (m_category != scheme_category::NonHierarchical) {
|
||||
throw std::domain_error("The content component is only valid for non-hierarchical URIs.");
|
||||
}
|
||||
return m_content;
|
||||
};
|
||||
|
||||
std::string const &get_username() const
|
||||
{
|
||||
if (m_category != scheme_category::Hierarchical) {
|
||||
throw std::domain_error("The username component is only valid for hierarchical URIs.");
|
||||
}
|
||||
return m_username;
|
||||
};
|
||||
|
||||
std::string const &get_password() const
|
||||
{
|
||||
if (m_category != scheme_category::Hierarchical) {
|
||||
throw std::domain_error("The password component is only valid for hierarchical URIs.");
|
||||
}
|
||||
return m_password;
|
||||
};
|
||||
|
||||
std::string const &get_host() const
|
||||
{
|
||||
if (m_category != scheme_category::Hierarchical) {
|
||||
throw std::domain_error("The host component is only valid for hierarchical URIs.");
|
||||
}
|
||||
return m_host;
|
||||
};
|
||||
|
||||
unsigned long get_port() const
|
||||
{
|
||||
if (m_category != scheme_category::Hierarchical) {
|
||||
throw std::domain_error("The port component is only valid for hierarchical URIs.");
|
||||
}
|
||||
return m_port;
|
||||
};
|
||||
|
||||
std::string const &get_path() const
|
||||
{
|
||||
if (m_category != scheme_category::Hierarchical) {
|
||||
throw std::domain_error("The path component is only valid for hierarchical URIs.");
|
||||
}
|
||||
return m_path;
|
||||
};
|
||||
|
||||
std::string const &get_query() const
|
||||
{
|
||||
return m_query;
|
||||
};
|
||||
|
||||
std::map<std::string, std::string> const &get_query_dictionary() const
|
||||
{
|
||||
return m_query_dict;
|
||||
};
|
||||
|
||||
std::string const &get_fragment() const
|
||||
{
|
||||
return m_fragment;
|
||||
};
|
||||
|
||||
std::string to_string() const
|
||||
{
|
||||
std::string full_uri;
|
||||
full_uri.append(m_scheme);
|
||||
full_uri.append(":");
|
||||
|
||||
if (m_content.length() > m_path.length()) {
|
||||
full_uri.append("//");
|
||||
if (!(m_username.empty() || m_password.empty())) {
|
||||
full_uri.append(m_username);
|
||||
full_uri.append(":");
|
||||
full_uri.append(m_password);
|
||||
full_uri.append("@");
|
||||
}
|
||||
|
||||
full_uri.append(m_host);
|
||||
|
||||
if (m_port != 0) {
|
||||
full_uri.append(":");
|
||||
full_uri.append(std::to_string(m_port));
|
||||
}
|
||||
}
|
||||
|
||||
if (m_path_is_rooted) {
|
||||
full_uri.append("/");
|
||||
}
|
||||
full_uri.append(m_path);
|
||||
|
||||
if (!m_query.empty()) {
|
||||
full_uri.append("?");
|
||||
full_uri.append(m_query);
|
||||
}
|
||||
|
||||
if (!m_fragment.empty()) {
|
||||
full_uri.append("#");
|
||||
full_uri.append(m_fragment);
|
||||
}
|
||||
|
||||
return full_uri;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
void setup(std::string const &uri_text, scheme_category category)
|
||||
{
|
||||
size_t const uri_length = uri_text.length();
|
||||
|
||||
if (uri_length == 0) {
|
||||
throw std::invalid_argument("URIs cannot be of zero length.");
|
||||
}
|
||||
|
||||
std::string::const_iterator cursor = parse_scheme(
|
||||
uri_text,
|
||||
uri_text.begin());
|
||||
// After calling parse_scheme, *cursor == ':'; none of the following parsers
|
||||
// expect a separator character, so we advance the cursor upon calling them.
|
||||
cursor = parse_content(uri_text, (cursor + 1));
|
||||
|
||||
if ((cursor != uri_text.end()) && (*cursor == '?')) {
|
||||
cursor = parse_query(uri_text, (cursor + 1));
|
||||
}
|
||||
|
||||
if ((cursor != uri_text.end()) && (*cursor == '#')) {
|
||||
cursor = parse_fragment(uri_text, (cursor + 1));
|
||||
}
|
||||
|
||||
init_query_dictionary(); // If the query string is empty, this will be empty too.
|
||||
|
||||
};
|
||||
|
||||
std::string::const_iterator parse_scheme(
|
||||
std::string const &uri_text,
|
||||
std::string::const_iterator scheme_start
|
||||
)
|
||||
{
|
||||
std::string::const_iterator scheme_end = scheme_start;
|
||||
while ((scheme_end != uri_text.end()) && (*scheme_end != ':')) {
|
||||
if (!(std::isalnum(*scheme_end) || (*scheme_end == '-')
|
||||
|| (*scheme_end == '+') || (*scheme_end == '.'))) {
|
||||
throw std::invalid_argument(
|
||||
"Invalid character found in the scheme component. Supplied URI was: \""
|
||||
+ uri_text + "\"."
|
||||
);
|
||||
}
|
||||
++scheme_end;
|
||||
}
|
||||
|
||||
if (scheme_end == uri_text.end()) {
|
||||
throw std::invalid_argument(
|
||||
"End of URI found while parsing the scheme. Supplied URI was: \""
|
||||
+ uri_text + "\"."
|
||||
);
|
||||
}
|
||||
|
||||
if (scheme_start == scheme_end) {
|
||||
throw std::invalid_argument(
|
||||
"Scheme component cannot be zero-length. Supplied URI was: \""
|
||||
+ uri_text + "\"."
|
||||
);
|
||||
}
|
||||
|
||||
m_scheme = std::move(std::string(scheme_start, scheme_end));
|
||||
return scheme_end;
|
||||
};
|
||||
|
||||
std::string::const_iterator parse_content(
|
||||
std::string const &uri_text,
|
||||
std::string::const_iterator content_start
|
||||
)
|
||||
{
|
||||
std::string::const_iterator content_end = content_start;
|
||||
while ((content_end != uri_text.end()) && (*content_end != '?') && (*content_end != '#')) {
|
||||
++content_end;
|
||||
}
|
||||
|
||||
m_content = std::move(std::string(content_start, content_end));
|
||||
|
||||
if ((m_category == scheme_category::Hierarchical) && (m_content.length() > 0)) {
|
||||
// If it's a hierarchical URI, the content should be parsed for the hierarchical components.
|
||||
std::string::const_iterator path_start = m_content.begin();
|
||||
std::string::const_iterator path_end = m_content.end();
|
||||
if (!m_content.compare(0, 2, "//")) {
|
||||
// In this case an authority component is present.
|
||||
std::string::const_iterator authority_cursor = (m_content.begin() + 2);
|
||||
if (m_content.find_first_of('@') != std::string::npos) {
|
||||
std::string::const_iterator userpass_divider = parse_username(
|
||||
uri_text,
|
||||
m_content,
|
||||
authority_cursor
|
||||
);
|
||||
authority_cursor = parse_password(uri_text, m_content, (userpass_divider + 1));
|
||||
// After this call, *authority_cursor == '@', so we skip over it.
|
||||
++authority_cursor;
|
||||
}
|
||||
|
||||
authority_cursor = parse_host(uri_text, m_content, authority_cursor);
|
||||
|
||||
if ((authority_cursor != m_content.end()) && (*authority_cursor == ':')) {
|
||||
authority_cursor = parse_port(uri_text, m_content, (authority_cursor + 1));
|
||||
}
|
||||
|
||||
if ((authority_cursor != m_content.end()) && (*authority_cursor == '/')) {
|
||||
// Then the path is rooted, and we should note this.
|
||||
m_path_is_rooted = true;
|
||||
path_start = authority_cursor + 1;
|
||||
}
|
||||
|
||||
// If we've reached the end and no path is present then set path_start
|
||||
// to the end.
|
||||
if (authority_cursor == m_content.end()) {
|
||||
path_start = m_content.end();
|
||||
}
|
||||
}
|
||||
else if (!m_content.compare(0, 1, "/")) {
|
||||
m_path_is_rooted = true;
|
||||
++path_start;
|
||||
}
|
||||
|
||||
// We can now build the path based on what remains in the content string,
|
||||
// since that's all that exists after the host and optional port component.
|
||||
m_path = std::move(std::string(path_start, path_end));
|
||||
}
|
||||
return content_end;
|
||||
};
|
||||
|
||||
std::string::const_iterator parse_username(
|
||||
std::string const &uri_text,
|
||||
std::string const &content,
|
||||
std::string::const_iterator username_start
|
||||
)
|
||||
{
|
||||
std::string::const_iterator username_end = username_start;
|
||||
// Since this is only reachable when '@' was in the content string, we can
|
||||
// ignore the end-of-string case.
|
||||
while (*username_end != ':') {
|
||||
if (*username_end == '@') {
|
||||
throw std::invalid_argument(
|
||||
"Username must be followed by a password. Supplied URI was: \""
|
||||
+ uri_text + "\"."
|
||||
);
|
||||
}
|
||||
++username_end;
|
||||
}
|
||||
m_username = std::move(std::string(username_start, username_end));
|
||||
return username_end;
|
||||
};
|
||||
|
||||
std::string::const_iterator parse_password(
|
||||
std::string const &uri_text,
|
||||
std::string const &content,
|
||||
std::string::const_iterator password_start
|
||||
)
|
||||
{
|
||||
std::string::const_iterator password_end = password_start;
|
||||
while (*password_end != '@') {
|
||||
++password_end;
|
||||
}
|
||||
|
||||
m_password = std::move(std::string(password_start, password_end));
|
||||
return password_end;
|
||||
};
|
||||
|
||||
std::string::const_iterator parse_host(
|
||||
std::string const &uri_text,
|
||||
std::string const &content,
|
||||
std::string::const_iterator host_start
|
||||
)
|
||||
{
|
||||
std::string::const_iterator host_end = host_start;
|
||||
// So, the host can contain a few things. It can be a domain, it can be an
|
||||
// IPv4 address, it can be an IPv6 address, or an IPvFuture literal. In the
|
||||
// case of those last two, it's of the form [...] where what's between the
|
||||
// brackets is a matter of which IPv?? version it is.
|
||||
while (host_end != content.end()) {
|
||||
if (*host_end == '[') {
|
||||
// We're parsing an IPv6 or IPvFuture address, so we should handle that
|
||||
// instead of the normal procedure.
|
||||
while ((host_end != content.end()) && (*host_end != ']')) {
|
||||
++host_end;
|
||||
}
|
||||
|
||||
if (host_end == content.end()) {
|
||||
throw std::invalid_argument(
|
||||
"End of content component encountered "
|
||||
"while parsing the host component. "
|
||||
"Supplied URI was: \""
|
||||
+ uri_text + "\"."
|
||||
);
|
||||
}
|
||||
|
||||
++host_end;
|
||||
break;
|
||||
// We can stop looping, we found the end of the IP literal, which is the
|
||||
// whole of the host component when one's in use.
|
||||
}
|
||||
else if ((*host_end == ':') || (*host_end == '/')) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
++host_end;
|
||||
}
|
||||
}
|
||||
|
||||
m_host = std::move(std::string(host_start, host_end));
|
||||
return host_end;
|
||||
};
|
||||
|
||||
std::string::const_iterator parse_port(
|
||||
std::string const &uri_text,
|
||||
std::string const &content,
|
||||
std::string::const_iterator port_start
|
||||
)
|
||||
{
|
||||
std::string::const_iterator port_end = port_start;
|
||||
while ((port_end != content.end()) && (*port_end != '/')) {
|
||||
if (!std::isdigit(*port_end)) {
|
||||
throw std::invalid_argument(
|
||||
"Invalid character while parsing the port. "
|
||||
"Supplied URI was: \"" + uri_text + "\"."
|
||||
);
|
||||
}
|
||||
|
||||
++port_end;
|
||||
}
|
||||
|
||||
m_port = std::stoul(std::string(port_start, port_end));
|
||||
return port_end;
|
||||
};
|
||||
|
||||
std::string::const_iterator parse_query(
|
||||
std::string const &uri_text,
|
||||
std::string::const_iterator query_start
|
||||
)
|
||||
{
|
||||
std::string::const_iterator query_end = query_start;
|
||||
while ((query_end != uri_text.end()) && (*query_end != '#')) {
|
||||
// Queries can contain almost any character except hash, which is reserved
|
||||
// for the start of the fragment.
|
||||
++query_end;
|
||||
}
|
||||
m_query = std::move(std::string(query_start, query_end));
|
||||
return query_end;
|
||||
};
|
||||
|
||||
std::string::const_iterator parse_fragment(
|
||||
std::string const &uri_text,
|
||||
std::string::const_iterator fragment_start
|
||||
)
|
||||
{
|
||||
m_fragment = std::move(std::string(fragment_start, uri_text.end()));
|
||||
return uri_text.end();
|
||||
};
|
||||
|
||||
void init_query_dictionary()
|
||||
{
|
||||
if (!m_query.empty()) {
|
||||
// Loop over the query string looking for '&'s, then check each one for
|
||||
// an '=' to find keys and values; if there's not an '=' then the key
|
||||
// will have an empty value in the map.
|
||||
char separator = (m_separator == query_argument_separator::ampersand) ? '&' : ';';
|
||||
size_t carat = 0;
|
||||
size_t stanza_end = m_query.find_first_of(separator);
|
||||
do {
|
||||
std::string stanza = m_query.substr(
|
||||
carat,
|
||||
((stanza_end != std::string::npos) ? (stanza_end - carat) : std::string::npos));
|
||||
size_t key_value_divider = stanza.find_first_of('=');
|
||||
std::string key = stanza.substr(0, key_value_divider);
|
||||
std::string value;
|
||||
if (key_value_divider != std::string::npos) {
|
||||
value = stanza.substr((key_value_divider + 1));
|
||||
}
|
||||
|
||||
if (m_query_dict.count(key) != 0) {
|
||||
throw std::invalid_argument("Bad key in the query string!");
|
||||
}
|
||||
|
||||
m_query_dict.emplace(key, value);
|
||||
carat = ((stanza_end != std::string::npos) ? (stanza_end + 1)
|
||||
: std::string::npos);
|
||||
stanza_end = m_query.find_first_of(separator, carat);
|
||||
} while ((stanza_end != std::string::npos)
|
||||
|| (carat != std::string::npos));
|
||||
}
|
||||
}
|
||||
|
||||
std::string m_scheme;
|
||||
std::string m_content;
|
||||
std::string m_username;
|
||||
std::string m_password;
|
||||
std::string m_host;
|
||||
std::string m_path;
|
||||
std::string m_query;
|
||||
std::string m_fragment;
|
||||
|
||||
std::map<std::string, std::string> m_query_dict;
|
||||
|
||||
scheme_category m_category;
|
||||
unsigned long m_port;
|
||||
bool m_path_is_rooted;
|
||||
query_argument_separator m_separator;
|
||||
};
|
||||
@@ -25,7 +25,7 @@
|
||||
//#include "races.h"
|
||||
//#include "rulesys.h"
|
||||
//#include "shareddb.h"
|
||||
#include "strings.h"
|
||||
#include "string_util.h"
|
||||
|
||||
#include "../common/light_source.h"
|
||||
|
||||
@@ -224,7 +224,7 @@ EQ::ItemInstance* EQ::InventoryProfile::GetItem(int16 slot_id, uint8 bagidx) con
|
||||
return GetItem(InventoryProfile::CalcSlotId(slot_id, bagidx));
|
||||
}
|
||||
|
||||
// Put an item into specified slot
|
||||
// Put an item snto specified slot
|
||||
int16 EQ::InventoryProfile::PutItem(int16 slot_id, const ItemInstance& inst)
|
||||
{
|
||||
if (slot_id <= EQ::invslot::POSSESSIONS_END && slot_id >= EQ::invslot::POSSESSIONS_BEGIN) {
|
||||
@@ -245,7 +245,7 @@ int16 EQ::InventoryProfile::PutItem(int16 slot_id, const ItemInstance& inst)
|
||||
if (temp_slot >= m_lookup->InventoryTypeSize.Bank)
|
||||
return EQ::invslot::SLOT_INVALID;
|
||||
}
|
||||
|
||||
|
||||
// Clean up item already in slot (if exists)
|
||||
DeleteItem(slot_id);
|
||||
|
||||
@@ -399,7 +399,7 @@ bool EQ::InventoryProfile::SwapItem(
|
||||
}
|
||||
|
||||
// Remove item from inventory (with memory delete)
|
||||
bool EQ::InventoryProfile::DeleteItem(int16 slot_id, int16 quantity) {
|
||||
bool EQ::InventoryProfile::DeleteItem(int16 slot_id, uint8 quantity) {
|
||||
// Pop item out of inventory map (or queue)
|
||||
ItemInstance *item_to_delete = PopItem(slot_id);
|
||||
|
||||
@@ -590,68 +590,6 @@ bool EQ::InventoryProfile::HasSpaceForItem(const ItemData *ItemToTry, int16 Quan
|
||||
// Checks that user has at least 'quantity' number of items in a given inventory slot
|
||||
// Returns first slot it was found in, or SLOT_INVALID if not found
|
||||
|
||||
bool EQ::InventoryProfile::HasAugmentEquippedByID(uint32 item_id)
|
||||
{
|
||||
bool has_equipped = false;
|
||||
ItemInstance* item = nullptr;
|
||||
|
||||
for (int slot_id = EQ::invslot::EQUIPMENT_BEGIN; slot_id <= EQ::invslot::EQUIPMENT_END; ++slot_id) {
|
||||
item = GetItem(slot_id);
|
||||
if (item && item->ContainsAugmentByID(item_id)) {
|
||||
has_equipped = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return has_equipped;
|
||||
}
|
||||
|
||||
int EQ::InventoryProfile::CountAugmentEquippedByID(uint32 item_id)
|
||||
{
|
||||
int quantity = 0;
|
||||
ItemInstance* item = nullptr;
|
||||
|
||||
for (int slot_id = EQ::invslot::EQUIPMENT_BEGIN; slot_id <= EQ::invslot::EQUIPMENT_END; ++slot_id) {
|
||||
item = GetItem(slot_id);
|
||||
if (item && item->ContainsAugmentByID(item_id)) {
|
||||
quantity += item->CountAugmentByID(item_id);
|
||||
}
|
||||
}
|
||||
|
||||
return quantity;
|
||||
}
|
||||
|
||||
bool EQ::InventoryProfile::HasItemEquippedByID(uint32 item_id)
|
||||
{
|
||||
bool has_equipped = false;
|
||||
ItemInstance* item = nullptr;
|
||||
|
||||
for (int slot_id = EQ::invslot::EQUIPMENT_BEGIN; slot_id <= EQ::invslot::EQUIPMENT_END; ++slot_id) {
|
||||
item = GetItem(slot_id);
|
||||
if (item && item->GetID() == item_id) {
|
||||
has_equipped = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return has_equipped;
|
||||
}
|
||||
|
||||
int EQ::InventoryProfile::CountItemEquippedByID(uint32 item_id)
|
||||
{
|
||||
int quantity = 0;
|
||||
ItemInstance* item = nullptr;
|
||||
|
||||
for (int slot_id = EQ::invslot::EQUIPMENT_BEGIN; slot_id <= EQ::invslot::EQUIPMENT_END; ++slot_id) {
|
||||
item = GetItem(slot_id);
|
||||
if (item && item->GetID() == item_id) {
|
||||
quantity += item->IsStackable() ? item->GetCharges() : 1;
|
||||
}
|
||||
}
|
||||
|
||||
return quantity;
|
||||
}
|
||||
|
||||
//This function has a flaw in that it only returns the last stack that it looked at
|
||||
//when quantity is greater than 1 and not all of quantity can be found in 1 stack.
|
||||
int16 EQ::InventoryProfile::HasItem(uint32 item_id, uint8 quantity, uint8 where)
|
||||
@@ -993,7 +931,7 @@ int16 EQ::InventoryProfile::CalcSlotId(int16 slot_id) {
|
||||
//else if (slot_id >= EmuConstants::BANK_BEGIN && slot_id <= EmuConstants::BANK_END)
|
||||
// parent_slot_id = EmuConstants::BANK_BEGIN + (slot_id - EmuConstants::BANK_BEGIN) / EmuConstants::ITEM_CONTAINER_SIZE;
|
||||
//else if (slot_id >= 3100 && slot_id <= 3179) should be {3031..3110}..where did this range come from!!? (verified db save range)
|
||||
|
||||
|
||||
if (slot_id >= invbag::GENERAL_BAGS_BEGIN && slot_id <= invbag::GENERAL_BAGS_END) {
|
||||
parent_slot_id = invslot::GENERAL_BEGIN + (slot_id - invbag::GENERAL_BAGS_BEGIN) / invbag::SLOT_COUNT;
|
||||
}
|
||||
@@ -1231,7 +1169,7 @@ uint8 EQ::InventoryProfile::FindBrightestLightType()
|
||||
for (auto iter = m_worn.begin(); iter != m_worn.end(); ++iter) {
|
||||
if ((iter->first < invslot::EQUIPMENT_BEGIN || iter->first > invslot::EQUIPMENT_END))
|
||||
continue;
|
||||
|
||||
|
||||
if (iter->first == invslot::slotAmmo)
|
||||
continue;
|
||||
|
||||
@@ -1369,7 +1307,7 @@ EQ::ItemInstance* EQ::InventoryProfile::_GetItem(const std::map<int16, ItemInsta
|
||||
if (slot_id - EQ::invslot::BANK_BEGIN >= m_lookup->InventoryTypeSize.Bank)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
auto it = bucket.find(slot_id);
|
||||
if (it != bucket.end()) {
|
||||
return it->second;
|
||||
@@ -1441,7 +1379,7 @@ int16 EQ::InventoryProfile::_PutItem(int16 slot_id, ItemInstance* inst)
|
||||
result = slot_id;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (result == INVALID_INDEX) {
|
||||
LogError("InventoryProfile::_PutItem: Invalid slot_id specified ({}) with parent slot id ({})", slot_id, parentSlot);
|
||||
InventoryProfile::MarkDirty(inst); // Slot not found, clean up
|
||||
@@ -1478,7 +1416,7 @@ int16 EQ::InventoryProfile::_HasItem(std::map<int16, ItemInstance*>& bucket, uin
|
||||
if (inst->GetAugmentItemID(index) == item_id && quantity <= 1)
|
||||
return invslot::SLOT_AUGMENT_GENERIC_RETURN;
|
||||
}
|
||||
|
||||
|
||||
if (!inst->IsClassBag()) { continue; }
|
||||
|
||||
for (auto bag_iter = inst->_cbegin(); bag_iter != inst->_cend(); ++bag_iter) {
|
||||
@@ -1509,7 +1447,7 @@ int16 EQ::InventoryProfile::_HasItem(ItemInstQueue& iqueue, uint32 item_id, uint
|
||||
// is sufficient. However, in cases where referential criteria is considered, this can lead
|
||||
// to unintended results. Funtionality should be observed when referencing the return value
|
||||
// of this query
|
||||
|
||||
|
||||
uint32 quantity_found = 0;
|
||||
|
||||
for (auto iter = iqueue.cbegin(); iter != iqueue.cend(); ++iter) {
|
||||
@@ -1715,20 +1653,6 @@ int16 EQ::InventoryProfile::_HasItemByLoreGroup(ItemInstQueue& iqueue, uint32 lo
|
||||
// We only check the visible cursor due to lack of queue processing ability (client allows duplicate in limbo)
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return EQ::invslot::SLOT_INVALID;
|
||||
}
|
||||
|
||||
std::vector<uint32> EQ::InventoryProfile::GetAugmentIDsBySlotID(int16 slot_id)
|
||||
{
|
||||
std::vector<uint32> augments;
|
||||
const auto* item = GetItem(slot_id);
|
||||
|
||||
if (item) {
|
||||
for (uint8 i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; i++) {
|
||||
augments.push_back(item->GetAugment(i) ? item->GetAugmentItemID(i) : 0);
|
||||
}
|
||||
}
|
||||
|
||||
return augments;
|
||||
}
|
||||
|
||||
@@ -26,11 +26,8 @@
|
||||
|
||||
|
||||
#include "item_instance.h"
|
||||
#include "classes.h"
|
||||
#include "races.h"
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
|
||||
//FatherNitwit: location bits for searching specific
|
||||
@@ -132,10 +129,10 @@ namespace EQ
|
||||
|
||||
// Swap items in inventory
|
||||
enum SwapItemFailState : int8 { swapInvalid = -1, swapPass = 0, swapNotAllowed, swapNullData, swapRaceClass, swapDeity, swapLevel };
|
||||
bool SwapItem(int16 source_slot, int16 destination_slot, SwapItemFailState& fail_state, uint16 race_id = RACE_DOUG_0, uint8 class_id = NO_CLASS, uint16 deity_id = deity::DeityType::DeityUnknown, uint8 level = 0);
|
||||
bool SwapItem(int16 source_slot, int16 destination_slot, SwapItemFailState& fail_state, uint16 race_id = 0, uint8 class_id = 0, uint16 deity_id = 0, uint8 level = 0);
|
||||
|
||||
// Remove item from inventory
|
||||
bool DeleteItem(int16 slot_id, int16 quantity = 0);
|
||||
bool DeleteItem(int16 slot_id, uint8 quantity = 0);
|
||||
|
||||
// Checks All items in a bag for No Drop
|
||||
bool CheckNoDrop(int16 slot_id, bool recurse = true);
|
||||
@@ -143,21 +140,6 @@ namespace EQ
|
||||
// Remove item from inventory (and take control of memory)
|
||||
ItemInstance* PopItem(int16 slot_id);
|
||||
|
||||
// Check if player has a specific item equipped by Item ID
|
||||
bool HasItemEquippedByID(uint32 item_id);
|
||||
|
||||
// Check how many of a specific item the player has equipped by Item ID
|
||||
int CountItemEquippedByID(uint32 item_id);
|
||||
|
||||
// Check if player has a specific augment equipped by Item ID
|
||||
bool HasAugmentEquippedByID(uint32 item_id);
|
||||
|
||||
// Check how many of a specific augment the player has equipped by Item ID
|
||||
int CountAugmentEquippedByID(uint32 item_id);
|
||||
|
||||
// Get a list of augments from a specific slot ID
|
||||
std::vector<uint32> GetAugmentIDsBySlotID(int16 slot_id);
|
||||
|
||||
// Check whether there is space for the specified number of the specified item.
|
||||
bool HasSpaceForItem(const ItemData *ItemToTry, int16 Quantity);
|
||||
|
||||
@@ -208,7 +190,6 @@ namespace EQ
|
||||
void SetCustomItemData(uint32 character_id, int16 slot_id, std::string identifier, float value);
|
||||
void SetCustomItemData(uint32 character_id, int16 slot_id, std::string identifier, bool value);
|
||||
std::string GetCustomItemData(int16 slot_id, std::string identifier);
|
||||
static const int GetItemStatValue(uint32 item_id, std::string identifier);
|
||||
protected:
|
||||
///////////////////////////////
|
||||
// Protected Methods
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#include "inventory_slot.h"
|
||||
#include "textures.h"
|
||||
#include "strings.h"
|
||||
#include "string_util.h"
|
||||
|
||||
|
||||
int8 EQ::inventory::ConvertEquipmentIndexToTextureIndex(int16 slot_index)
|
||||
@@ -86,7 +86,7 @@ bool EQ::InventorySlot::IsValidSlot() const
|
||||
{
|
||||
if (_typeless)
|
||||
return false;
|
||||
|
||||
|
||||
int16 slot_count = invtype::GetInvTypeSize(_type_index);
|
||||
if (!slot_count || _slot_index < invslot::SLOT_BEGIN || _slot_index >= slot_count)
|
||||
return false;
|
||||
@@ -136,7 +136,7 @@ bool EQ::InventorySlot::IsWeaponIndex(int16 slot_index)
|
||||
{
|
||||
if (slot_index == invslot::slotPrimary || slot_index == invslot::slotSecondary || slot_index == invslot::slotRange)
|
||||
return true;
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -364,7 +364,7 @@ bool EQ::InventorySlot::operator<(const InventorySlot& rhs) const
|
||||
{
|
||||
if (Typeless() || rhs.Typeless())
|
||||
return inventory_slot_typeless_lessthan(*this, rhs);
|
||||
|
||||
|
||||
if (TypeIndex() < rhs.TypeIndex())
|
||||
return true;
|
||||
|
||||
@@ -384,6 +384,6 @@ bool EQ::operator==(const InventorySlot& lhs, const InventorySlot& rhs)
|
||||
{
|
||||
if (lhs.Typeless() || rhs.Typeless())
|
||||
return ((lhs.SlotIndex() == rhs.SlotIndex()) && (lhs.ContainerIndex() == rhs.ContainerIndex()) && (lhs.SocketIndex() == rhs.SocketIndex()));
|
||||
|
||||
|
||||
return ((lhs.TypeIndex() == rhs.TypeIndex()) && (lhs.SlotIndex() == rhs.SlotIndex()) && (lhs.ContainerIndex() == rhs.ContainerIndex()) && (lhs.SocketIndex() == rhs.SocketIndex()));
|
||||
}
|
||||
|
||||
@@ -18,17 +18,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include <fmt/format.h>
|
||||
#include <csignal>
|
||||
#include <vector>
|
||||
#include "ip_util.h"
|
||||
#include "http/httplib.h"
|
||||
#include "http/uri.h"
|
||||
#include "eqemu_logsys.h"
|
||||
#include "event/event_loop.h"
|
||||
#include "net/dns.h"
|
||||
#include "event/task_scheduler.h"
|
||||
|
||||
/**
|
||||
* @param ip
|
||||
@@ -80,148 +70,3 @@ bool IpUtil::IsIpInPrivateRfc1918(const std::string &ip)
|
||||
IpUtil::IsIpInRange(ip, "192.168.0.0", "255.255.0.0")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets local address - pings google to inspect what interface was used locally
|
||||
* @return
|
||||
*/
|
||||
std::string IpUtil::GetLocalIPAddress()
|
||||
{
|
||||
char my_ip_address[16];
|
||||
unsigned int my_port;
|
||||
struct sockaddr_in server_address{};
|
||||
struct sockaddr_in my_address{};
|
||||
int sockfd;
|
||||
|
||||
// Connect to server
|
||||
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// Set server_addr
|
||||
memset(&server_address, 0, sizeof(server_address));
|
||||
server_address.sin_family = AF_INET;
|
||||
server_address.sin_addr.s_addr = inet_addr("172.217.160.99");
|
||||
server_address.sin_port = htons(80);
|
||||
|
||||
// Connect to server
|
||||
if (connect(sockfd, (struct sockaddr *) &server_address, sizeof(server_address)) < 0) {
|
||||
close(sockfd);
|
||||
return "";
|
||||
}
|
||||
|
||||
// Get my ip address and port
|
||||
memset(&my_address, 0, sizeof(my_address));
|
||||
socklen_t len = sizeof(my_address);
|
||||
getsockname(sockfd, (struct sockaddr *) &my_address, &len);
|
||||
inet_ntop(AF_INET, &my_address.sin_addr, my_ip_address, sizeof(my_ip_address));
|
||||
my_port = ntohs(my_address.sin_port);
|
||||
|
||||
return fmt::format("{}", my_ip_address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets public address
|
||||
* Uses various websites as options to return raw public IP back to the client
|
||||
* @return
|
||||
*/
|
||||
std::string IpUtil::GetPublicIPAddress()
|
||||
{
|
||||
std::vector<std::string> endpoints = {
|
||||
"http://ifconfig.me",
|
||||
"http://api.ipify.org",
|
||||
"http://ipinfo.io/ip",
|
||||
"http://ipecho.net/plain",
|
||||
};
|
||||
|
||||
for (auto &s: endpoints) {
|
||||
// http get request
|
||||
uri u(s);
|
||||
|
||||
httplib::Client r(
|
||||
fmt::format(
|
||||
"{}://{}",
|
||||
u.get_scheme(),
|
||||
u.get_host()
|
||||
).c_str()
|
||||
);
|
||||
|
||||
httplib::Headers headers = {
|
||||
{"Content-type", "text/plain; charset=utf-8"},
|
||||
{"User-Agent", "curl/7.81.0"}
|
||||
};
|
||||
|
||||
r.set_connection_timeout(1, 0);
|
||||
r.set_read_timeout(1, 0);
|
||||
r.set_write_timeout(1, 0);
|
||||
|
||||
if (auto res = r.Get(fmt::format("/{}", u.get_path()).c_str(), headers)) {
|
||||
if (res->status == 200) {
|
||||
if (res->body.find('.') != std::string::npos) {
|
||||
return res->body;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string IpUtil::DNSLookupSync(const std::string &addr, int port)
|
||||
{
|
||||
auto task_runner = new EQ::Event::TaskScheduler();
|
||||
auto res = task_runner->Enqueue(
|
||||
[&]() -> std::string {
|
||||
bool running = true;
|
||||
std::string ret;
|
||||
|
||||
EQ::Net::DNSLookup(
|
||||
addr, port, false, [&](const std::string &addr) {
|
||||
ret = addr;
|
||||
if (addr.empty()) {
|
||||
ret = "";
|
||||
running = false;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
);
|
||||
|
||||
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
|
||||
|
||||
auto &loop = EQ::EventLoop::Get();
|
||||
while (running) {
|
||||
if (!ret.empty()) {
|
||||
running = false;
|
||||
}
|
||||
|
||||
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
|
||||
if (std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count() > 1500) {
|
||||
LogInfo(
|
||||
"Deadline exceeded [{}]",
|
||||
1500
|
||||
);
|
||||
running = false;
|
||||
}
|
||||
|
||||
loop.Process();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
);
|
||||
|
||||
std::string result = res.get();
|
||||
safe_delete(task_runner);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool IpUtil::IsIPAddress(const std::string &ip_address)
|
||||
{
|
||||
struct sockaddr_in sa{};
|
||||
int result = inet_pton(AF_INET, ip_address.c_str(), &(sa.sin_addr));
|
||||
return result != 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+1
-8
@@ -30,14 +30,7 @@ public:
|
||||
static uint32_t IPToUInt(const std::string &ip);
|
||||
static bool IsIpInRange(const std::string &ip, const std::string &network, const std::string &mask);
|
||||
static bool IsIpInPrivateRfc1918(const std::string &ip);
|
||||
static std::string GetLocalIPAddress();
|
||||
static std::string GetPublicIPAddress();
|
||||
static std::string DNSLookupSync(
|
||||
const std::string &addr,
|
||||
int port
|
||||
);
|
||||
static bool IsIPAddress(const std::string &ip_address);
|
||||
|
||||
};
|
||||
|
||||
#endif //EQEMU_IP_UTIL_H
|
||||
#endif //EQEMU_IP_UTIL_H
|
||||
@@ -30,7 +30,6 @@
|
||||
#include "types.h"
|
||||
#include "eqemu_exception.h"
|
||||
#include "eqemu_config.h"
|
||||
#include "path_manager.h"
|
||||
|
||||
namespace EQ {
|
||||
struct IPCMutex::Implementation {
|
||||
@@ -41,11 +40,12 @@ namespace EQ {
|
||||
#endif
|
||||
};
|
||||
|
||||
IPCMutex::IPCMutex(const std::string& name) : locked_(false) {
|
||||
IPCMutex::IPCMutex(std::string name) : locked_(false) {
|
||||
imp_ = new Implementation;
|
||||
#ifdef _WINDOWS
|
||||
auto Config = EQEmuConfig::get();
|
||||
std::string final_name = fmt::format("{}/EQEmuMutex_{}", Config->SharedMemDir, name);
|
||||
std::string final_name = Config->SharedMemDir + "EQEmuMutex_";
|
||||
final_name += name;
|
||||
|
||||
imp_->mut_ = CreateMutex(nullptr,
|
||||
FALSE,
|
||||
@@ -55,7 +55,9 @@ namespace EQ {
|
||||
EQ_EXCEPT("IPC Mutex", "Could not create mutex.");
|
||||
}
|
||||
#else
|
||||
std::string final_name = fmt::format("{}/{}.lock", path.GetSharedMemoryPath(), name);
|
||||
auto Config = EQEmuConfig::get();
|
||||
std::string final_name = Config->SharedMemDir + name;
|
||||
final_name += ".lock";
|
||||
|
||||
#ifdef __DARWIN
|
||||
#if __DARWIN_C_LEVEL < 200809L
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ namespace EQ {
|
||||
Creates a named binary semaphore, basically a semaphore that is init S <- 1
|
||||
\param name The name of this mutex.
|
||||
*/
|
||||
IPCMutex(const std::string& name);
|
||||
IPCMutex(std::string name);
|
||||
|
||||
//! Destructor
|
||||
~IPCMutex();
|
||||
|
||||
+2
-24
@@ -169,33 +169,11 @@ uint8 EQ::item::ConvertAugTypeBitToAugType(uint32 aug_type_bit)
|
||||
|
||||
bool EQ::ItemData::IsEquipable(uint16 race_id, uint16 class_id) const
|
||||
{
|
||||
if (!(Races & GetPlayerRaceBit(race_id))) {
|
||||
if (!(Races & GetPlayerRaceBit(race_id)))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(Classes & GetPlayerClassBit(GetPlayerClassValue(class_id)))) {
|
||||
if (!(Classes & GetPlayerClassBit(GetPlayerClassValue(class_id))))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EQ::ItemData::IsClassEquipable(uint16 class_id) const
|
||||
{
|
||||
|
||||
if (!(Classes & GetPlayerClassBit(GetPlayerClassValue(class_id)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EQ::ItemData::IsRaceEquipable(uint16 race_id) const
|
||||
{
|
||||
|
||||
if (!(Races & GetPlayerRaceBit(race_id))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
+10
-12
@@ -370,7 +370,7 @@ namespace EQ
|
||||
uint32 Slots; // Bitfield for which slots this item can be used in
|
||||
uint32 Price; // Item cost (?)
|
||||
uint32 Icon; // Icon Number
|
||||
int32 LoreGroup; // Later items use LoreGroup instead of LoreFlag. we might want to see about changing this to int32 since it is commonly -1 and is constantly being cast from signed (-1) to unsigned (4294967295)
|
||||
uint32 LoreGroup; // Later items use LoreGroup instead of LoreFlag. we might want to see about changing this to int32 since it is commonly -1 and is constantly being cast from signed (-1) to unsigned (4294967295)
|
||||
bool LoreFlag; // This will be true if LoreGroup is non-zero
|
||||
bool PendingLoreFlag;
|
||||
bool ArtifactFlag;
|
||||
@@ -473,16 +473,16 @@ namespace EQ
|
||||
uint32 LDoNSold;
|
||||
uint32 BaneDmgRaceAmt;
|
||||
uint32 AugRestrict;
|
||||
int32 Endur;
|
||||
int32 DotShielding;
|
||||
int32 Attack;
|
||||
int32 Regen;
|
||||
int32 ManaRegen;
|
||||
int32 EnduranceRegen;
|
||||
int32 Haste;
|
||||
int32 DamageShield;
|
||||
uint32 Endur;
|
||||
uint32 DotShielding;
|
||||
uint32 Attack;
|
||||
uint32 Regen;
|
||||
uint32 ManaRegen;
|
||||
uint32 EnduranceRegen;
|
||||
uint32 Haste;
|
||||
uint32 DamageShield;
|
||||
uint32 RecastDelay;
|
||||
int RecastType;
|
||||
uint32 RecastType;
|
||||
uint32 AugDistiller;
|
||||
bool Attuneable;
|
||||
bool NoPet;
|
||||
@@ -533,8 +533,6 @@ namespace EQ
|
||||
//BardName
|
||||
|
||||
bool IsEquipable(uint16 Race, uint16 Class) const;
|
||||
bool IsClassEquipable(uint16 Class) const;
|
||||
bool IsRaceEquipable(uint16 Race) const;
|
||||
bool IsClassCommon() const;
|
||||
bool IsClassBag() const;
|
||||
bool IsClassBook() const;
|
||||
|
||||
+36
-123
@@ -23,7 +23,7 @@
|
||||
//#include "races.h"
|
||||
#include "rulesys.h"
|
||||
#include "shareddb.h"
|
||||
#include "strings.h"
|
||||
#include "string_util.h"
|
||||
|
||||
//#include "../common/light_source.h"
|
||||
|
||||
@@ -214,7 +214,7 @@ EQ::ItemInstance::~ItemInstance()
|
||||
bool EQ::ItemInstance::IsType(item::ItemClass item_class) const
|
||||
{
|
||||
// IsType(<ItemClassTypes>) does not protect against 'm_item = nullptr'
|
||||
|
||||
|
||||
// Check usage type
|
||||
if ((m_use_type == ItemInstWorldContainer) && (item_class == item::ItemClassBag))
|
||||
return true;
|
||||
@@ -245,7 +245,7 @@ bool EQ::ItemInstance::IsStackable() const
|
||||
{
|
||||
if (!m_item)
|
||||
return false;
|
||||
|
||||
|
||||
return m_item->Stackable;
|
||||
}
|
||||
|
||||
@@ -253,7 +253,7 @@ bool EQ::ItemInstance::IsCharged() const
|
||||
{
|
||||
if (!m_item)
|
||||
return false;
|
||||
|
||||
|
||||
if (m_item->MaxCharges > 1)
|
||||
return true;
|
||||
else
|
||||
@@ -263,43 +263,20 @@ bool EQ::ItemInstance::IsCharged() const
|
||||
// Can item be equipped?
|
||||
bool EQ::ItemInstance::IsEquipable(uint16 race, uint16 class_) const
|
||||
{
|
||||
if (!m_item || !m_item->Slots) {
|
||||
if (!m_item || (m_item->Slots == 0))
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_item->IsEquipable(race, class_);
|
||||
}
|
||||
|
||||
// Can item be equipped by Class?
|
||||
bool EQ::ItemInstance::IsClassEquipable(uint16 class_) const
|
||||
{
|
||||
if (!m_item || !m_item->Slots) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_item->IsClassEquipable(class_);
|
||||
}
|
||||
|
||||
// Can item be equipped by Race?
|
||||
bool EQ::ItemInstance::IsRaceEquipable(uint16 race) const
|
||||
{
|
||||
if (!m_item || !m_item->Slots) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_item->IsRaceEquipable(race);
|
||||
}
|
||||
|
||||
// Can equip at this slot?
|
||||
bool EQ::ItemInstance::IsEquipable(int16 slot_id) const
|
||||
{
|
||||
if (!m_item || !m_item->Slots) {
|
||||
if (!m_item)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (slot_id < EQ::invslot::EQUIPMENT_BEGIN || slot_id > EQ::invslot::EQUIPMENT_END) {
|
||||
if (slot_id < EQ::invslot::EQUIPMENT_BEGIN || slot_id > EQ::invslot::EQUIPMENT_END)
|
||||
return false;
|
||||
}
|
||||
|
||||
return ((m_item->Slots & (1 << slot_id)) != 0);
|
||||
}
|
||||
@@ -332,30 +309,19 @@ bool EQ::ItemInstance::AvailableWearSlot(uint32 aug_wear_slots) const {
|
||||
return (index <= EQ::invslot::EQUIPMENT_END);
|
||||
}
|
||||
|
||||
int8 EQ::ItemInstance::AvailableAugmentSlot(int32 augment_type) const
|
||||
int8 EQ::ItemInstance::AvailableAugmentSlot(int32 augtype) const
|
||||
{
|
||||
if (!m_item || !m_item->IsClassCommon()) {
|
||||
if (!m_item || !m_item->IsClassCommon())
|
||||
return INVALID_INDEX;
|
||||
}
|
||||
|
||||
auto i = invaug::SOCKET_BEGIN;
|
||||
for (; i <= invaug::SOCKET_END; ++i) {
|
||||
if (GetItem(i)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
augment_type == -1 ||
|
||||
(
|
||||
m_item->AugSlotType[i] &&
|
||||
((1 << (m_item->AugSlotType[i] - 1)) & augment_type)
|
||||
)
|
||||
) {
|
||||
int index = invaug::SOCKET_BEGIN;
|
||||
for (; index <= invaug::SOCKET_END; ++index) {
|
||||
if (GetItem(index)) { continue; }
|
||||
if (augtype == -1 || (m_item->AugSlotType[index] && ((1 << (m_item->AugSlotType[index] - 1)) & augtype)))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (i <= invaug::SOCKET_END) ? i : INVALID_INDEX;
|
||||
return (index <= invaug::SOCKET_END) ? index : INVALID_INDEX;
|
||||
}
|
||||
|
||||
bool EQ::ItemInstance::IsAugmentSlotAvailable(int32 augtype, uint8 slot) const
|
||||
@@ -415,7 +381,7 @@ EQ::ItemInstance* EQ::ItemInstance::PopItem(uint8 index)
|
||||
m_contents.erase(index);
|
||||
return inst; // Return pointer that needs to be deleted (or otherwise managed)
|
||||
}
|
||||
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -510,7 +476,7 @@ uint8 EQ::ItemInstance::GetTotalItemCount() const
|
||||
{
|
||||
if (!m_item)
|
||||
return 0;
|
||||
|
||||
|
||||
uint8 item_count = 1;
|
||||
|
||||
if (m_item && !m_item->IsClassBag()) { return item_count; }
|
||||
@@ -534,11 +500,10 @@ bool EQ::ItemInstance::IsNoneEmptyContainer()
|
||||
}
|
||||
|
||||
// Retrieve augment inside item
|
||||
EQ::ItemInstance* EQ::ItemInstance::GetAugment(uint8 augment_index) const
|
||||
EQ::ItemInstance* EQ::ItemInstance::GetAugment(uint8 slot) const
|
||||
{
|
||||
if (m_item && m_item->IsClassCommon()) {
|
||||
return GetItem(augment_index);
|
||||
}
|
||||
if (m_item && m_item->IsClassCommon())
|
||||
return GetItem(slot);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
@@ -561,7 +526,7 @@ EQ::ItemInstance* EQ::ItemInstance::GetOrnamentationAug(int32 ornamentationAugty
|
||||
{
|
||||
continue;
|
||||
}
|
||||
return GetAugment(i);
|
||||
return this->GetAugment(i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -584,7 +549,7 @@ uint32 EQ::ItemInstance::GetOrnamentHeroModel(int32 material_slot) const {
|
||||
bool EQ::ItemInstance::UpdateOrnamentationInfo() {
|
||||
if (!m_item || !m_item->IsClassCommon())
|
||||
return false;
|
||||
|
||||
|
||||
bool ornamentSet = false;
|
||||
|
||||
int32 ornamentationAugtype = RuleI(Character, OrnamentationAugmentType);
|
||||
@@ -664,13 +629,12 @@ bool EQ::ItemInstance::CanTransform(const ItemData *ItemToTry, const ItemData *C
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 EQ::ItemInstance::GetAugmentItemID(uint8 augment_index) const
|
||||
uint32 EQ::ItemInstance::GetAugmentItemID(uint8 slot) const
|
||||
{
|
||||
if (!m_item || !m_item->IsClassCommon()) {
|
||||
if (!m_item || !m_item->IsClassCommon())
|
||||
return 0;
|
||||
}
|
||||
|
||||
return GetItemID(augment_index);
|
||||
return GetItemID(slot);
|
||||
}
|
||||
|
||||
// Add an augment to the item
|
||||
@@ -678,7 +642,7 @@ void EQ::ItemInstance::PutAugment(uint8 slot, const ItemInstance& augment)
|
||||
{
|
||||
if (!m_item || !m_item->IsClassCommon())
|
||||
return;
|
||||
|
||||
|
||||
PutItem(slot, augment);
|
||||
}
|
||||
|
||||
@@ -691,7 +655,7 @@ void EQ::ItemInstance::PutAugment(SharedDatabase *db, uint8 slot, uint32 item_id
|
||||
if (aug) {
|
||||
PutAugment(slot, *aug);
|
||||
safe_delete(aug);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove augment from item and destroy it
|
||||
@@ -699,7 +663,7 @@ void EQ::ItemInstance::DeleteAugment(uint8 index)
|
||||
{
|
||||
if (!m_item || !m_item->IsClassCommon())
|
||||
return;
|
||||
|
||||
|
||||
DeleteItem(index);
|
||||
}
|
||||
|
||||
@@ -708,7 +672,7 @@ EQ::ItemInstance* EQ::ItemInstance::RemoveAugment(uint8 index)
|
||||
{
|
||||
if (!m_item || !m_item->IsClassCommon())
|
||||
return nullptr;
|
||||
|
||||
|
||||
return PopItem(index);
|
||||
}
|
||||
|
||||
@@ -716,7 +680,7 @@ bool EQ::ItemInstance::IsAugmented()
|
||||
{
|
||||
if (!m_item || !m_item->IsClassCommon())
|
||||
return false;
|
||||
|
||||
|
||||
for (int index = invaug::SOCKET_BEGIN; index <= invaug::SOCKET_END; ++index) {
|
||||
if (GetAugmentItemID(index))
|
||||
return true;
|
||||
@@ -725,45 +689,6 @@ bool EQ::ItemInstance::IsAugmented()
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EQ::ItemInstance::ContainsAugmentByID(uint32 item_id)
|
||||
{
|
||||
if (!m_item || !m_item->IsClassCommon()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!item_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint8 augment_slot = invaug::SOCKET_BEGIN; augment_slot <= invaug::SOCKET_END; ++augment_slot) {
|
||||
if (GetAugmentItemID(augment_slot) == item_id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int EQ::ItemInstance::CountAugmentByID(uint32 item_id)
|
||||
{
|
||||
int quantity = 0;
|
||||
if (!m_item || !m_item->IsClassCommon()) {
|
||||
return quantity;
|
||||
}
|
||||
|
||||
if (!item_id) {
|
||||
return quantity;
|
||||
}
|
||||
|
||||
for (uint8 augment_slot = invaug::SOCKET_BEGIN; augment_slot <= invaug::SOCKET_END; ++augment_slot) {
|
||||
if (GetAugmentItemID(augment_slot) == item_id) {
|
||||
quantity++;
|
||||
}
|
||||
}
|
||||
|
||||
return quantity;
|
||||
}
|
||||
|
||||
// Has attack/delay?
|
||||
bool EQ::ItemInstance::IsWeapon() const
|
||||
{
|
||||
@@ -909,7 +834,7 @@ bool EQ::ItemInstance::IsDroppable(bool recurse) const
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1133,7 +1058,7 @@ int EQ::ItemInstance::GetItemElementalFlag(bool augments) const
|
||||
|
||||
int EQ::ItemInstance::GetItemElementalDamage(bool augments) const
|
||||
{
|
||||
int64 damage = 0;
|
||||
int damage = 0;
|
||||
const auto item = GetItem();
|
||||
if (item) {
|
||||
damage = item->ElemDmgAmt;
|
||||
@@ -1198,7 +1123,7 @@ int EQ::ItemInstance::GetItemRequiredLevel(bool augments) const
|
||||
|
||||
int EQ::ItemInstance::GetItemWeaponDamage(bool augments) const
|
||||
{
|
||||
int64 damage = 0;
|
||||
int damage = 0;
|
||||
const auto item = GetItem();
|
||||
if (item) {
|
||||
damage = item->Damage;
|
||||
@@ -1214,7 +1139,7 @@ int EQ::ItemInstance::GetItemWeaponDamage(bool augments) const
|
||||
|
||||
int EQ::ItemInstance::GetItemBackstabDamage(bool augments) const
|
||||
{
|
||||
int64 damage = 0;
|
||||
int damage = 0;
|
||||
const auto item = GetItem();
|
||||
if (item) {
|
||||
damage = item->BackstabDmg;
|
||||
@@ -1251,7 +1176,7 @@ int EQ::ItemInstance::GetItemBaneDamageBody(bool augments) const
|
||||
|
||||
int EQ::ItemInstance::GetItemBaneDamageRace(bool augments) const
|
||||
{
|
||||
int race = RACE_DOUG_0;
|
||||
int race = 0;
|
||||
const auto item = GetItem();
|
||||
if (item) {
|
||||
race = item->BaneDmgRace;
|
||||
@@ -1272,7 +1197,7 @@ int EQ::ItemInstance::GetItemBaneDamageRace(bool augments) const
|
||||
|
||||
int EQ::ItemInstance::GetItemBaneDamageBody(bodyType against, bool augments) const
|
||||
{
|
||||
int64 damage = 0;
|
||||
int damage = 0;
|
||||
const auto item = GetItem();
|
||||
if (item) {
|
||||
if (item->BaneDmgBody == against)
|
||||
@@ -1289,7 +1214,7 @@ int EQ::ItemInstance::GetItemBaneDamageBody(bodyType against, bool augments) con
|
||||
|
||||
int EQ::ItemInstance::GetItemBaneDamageRace(uint16 against, bool augments) const
|
||||
{
|
||||
int64 damage = 0;
|
||||
int damage = 0;
|
||||
const auto item = GetItem();
|
||||
if (item) {
|
||||
if (item->BaneDmgRace == against)
|
||||
@@ -1757,18 +1682,6 @@ int EQ::ItemInstance::GetItemHaste(bool augments) const
|
||||
return total;
|
||||
}
|
||||
|
||||
int EQ::ItemInstance::RemoveTaskDeliveredItems()
|
||||
{
|
||||
int count = IsStackable() ? GetCharges() : 1;
|
||||
count -= GetTaskDeliveredCount();
|
||||
if (IsStackable())
|
||||
{
|
||||
SetCharges(count);
|
||||
}
|
||||
SetTaskDeliveredCount(0);
|
||||
return count;
|
||||
}
|
||||
|
||||
//
|
||||
// class EvolveInfo
|
||||
//
|
||||
|
||||
+2
-16
@@ -92,8 +92,6 @@ namespace EQ
|
||||
|
||||
// Can item be equipped by/at?
|
||||
bool IsEquipable(uint16 race, uint16 class_) const;
|
||||
bool IsClassEquipable(uint16 class_) const;
|
||||
bool IsRaceEquipable(uint16 race) const;
|
||||
bool IsEquipable(int16 slot_id) const;
|
||||
|
||||
//
|
||||
@@ -127,15 +125,13 @@ namespace EQ
|
||||
//
|
||||
// Augments
|
||||
//
|
||||
ItemInstance* GetAugment(uint8 augment_index) const;
|
||||
uint32 GetAugmentItemID(uint8 augment_index) const;
|
||||
ItemInstance* GetAugment(uint8 slot) const;
|
||||
uint32 GetAugmentItemID(uint8 slot) const;
|
||||
void PutAugment(uint8 slot, const ItemInstance& inst);
|
||||
void PutAugment(SharedDatabase *db, uint8 slot, uint32 item_id);
|
||||
void DeleteAugment(uint8 slot);
|
||||
ItemInstance* RemoveAugment(uint8 index);
|
||||
bool IsAugmented();
|
||||
bool ContainsAugmentByID(uint32 item_id);
|
||||
int CountAugmentByID(uint32 item_id);
|
||||
ItemInstance* GetOrnamentationAug(int32 ornamentationAugtype) const;
|
||||
bool UpdateOrnamentationInfo();
|
||||
static bool CanTransform(const ItemData *ItemToTry, const ItemData *Container, bool AllowAll = false);
|
||||
@@ -150,8 +146,6 @@ namespace EQ
|
||||
const ItemData* GetItem() const;
|
||||
const ItemData* GetUnscaledItem() const;
|
||||
|
||||
const uint8 GetItemType() const { return m_item ? m_item->ItemType : 255; } // Return 255 so you know there's no valid item
|
||||
|
||||
int16 GetCharges() const { return m_charges; }
|
||||
void SetCharges(int16 charges) { m_charges = charges; }
|
||||
|
||||
@@ -233,13 +227,6 @@ namespace EQ
|
||||
void StopTimer(std::string name);
|
||||
void ClearTimers();
|
||||
|
||||
int GetTaskDeliveredCount() const { return m_task_delivered_count; }
|
||||
void SetTaskDeliveredCount(int count) { m_task_delivered_count = count; }
|
||||
// This function should only be used by trade return apis
|
||||
// Removes delivered task items from stack count and returns remaining count
|
||||
// Return value should be used to determine if an item still exists (for stackable and non-stackable)
|
||||
int RemoveTaskDeliveredItems();
|
||||
|
||||
// Get a total of a stat, including augs
|
||||
// These functions should be used in place of other code manually totaling
|
||||
// to centralize where it is done to make future changes easier (ex. whenever powersources come around)
|
||||
@@ -324,7 +311,6 @@ namespace EQ
|
||||
uint32 m_new_id_file;
|
||||
uint32 m_ornament_hero_model;
|
||||
uint32 m_recast_timestamp;
|
||||
int m_task_delivered_count = 0;
|
||||
|
||||
//
|
||||
// Items inside of this item (augs or contents);
|
||||
|
||||
+5
-14
@@ -30,19 +30,11 @@ struct LootTableEntries_Struct {
|
||||
float probability;
|
||||
};
|
||||
|
||||
struct ContentFlags {
|
||||
int16 min_expansion;
|
||||
int16 max_expansion;
|
||||
char content_flags[100];
|
||||
char content_flags_disabled[100];
|
||||
};
|
||||
|
||||
struct LootTable_Struct {
|
||||
uint32 mincash;
|
||||
uint32 maxcash;
|
||||
uint32 avgcoin;
|
||||
uint32 NumEntries;
|
||||
ContentFlags content_flags;
|
||||
uint32 mincash;
|
||||
uint32 maxcash;
|
||||
uint32 avgcoin;
|
||||
uint32 NumEntries;
|
||||
LootTableEntries_Struct Entries[0];
|
||||
};
|
||||
|
||||
@@ -59,8 +51,7 @@ struct LootDropEntries_Struct {
|
||||
};
|
||||
|
||||
struct LootDrop_Struct {
|
||||
uint32 NumEntries;
|
||||
ContentFlags content_flags;
|
||||
uint32 NumEntries;
|
||||
LootDropEntries_Struct Entries[0];
|
||||
};
|
||||
#pragma pack()
|
||||
|
||||
+2
-2
@@ -9,7 +9,7 @@
|
||||
*/
|
||||
#include <string.h> /* for memcpy() */
|
||||
#include "../common/md5.h"
|
||||
#include "../common/strings.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/seperator.h"
|
||||
|
||||
MD5::MD5() {
|
||||
@@ -194,7 +194,7 @@ void MD5::Final(uint8 digest[16], MD5Context *ctx) {
|
||||
|
||||
/* The heart of the MD5 algorithm. */
|
||||
void MD5::Transform(uint32 hash[4], const uint32 input[16]) {
|
||||
uint32 a = hash[0], b = hash[1], c = hash[2], d = hash[3];
|
||||
register uint32 a = hash[0], b = hash[1], c = hash[2], d = hash[3];
|
||||
|
||||
MD5STEP(F1, a, b, c, d, input[ 0]+0xd76aa478, 7);
|
||||
MD5STEP(F1, d, a, b, c, input[ 1]+0xe8c7b756, 12);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
|
||||
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
@@ -41,7 +41,7 @@ namespace EQ
|
||||
MemoryBuffer& operator+=(const MemoryBuffer &rhs);
|
||||
friend MemoryBuffer operator+(MemoryBuffer lhs, const MemoryBuffer& rhs) { return lhs += rhs; }
|
||||
~MemoryBuffer();
|
||||
|
||||
|
||||
uchar& operator[](size_t pos);
|
||||
const uchar& operator[](size_t pos) const;
|
||||
|
||||
@@ -64,20 +64,20 @@ namespace EQ
|
||||
size_t Size() const;
|
||||
size_t Capacity();
|
||||
size_t Capacity() const;
|
||||
|
||||
|
||||
void Resize(size_t sz);
|
||||
void Clear();
|
||||
void Zero();
|
||||
|
||||
template<typename T>
|
||||
void Write(T val) {
|
||||
static_assert(std::is_standard_layout<T>::value, "MemoryBuffer::Write<T>(T val) only works on pod and string types.");
|
||||
static_assert(std::is_pod<T>::value, "MemoryBuffer::Write<T>(T val) only works on pod and string types.");
|
||||
Write((const char*)&val, sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T Read() {
|
||||
static_assert(std::is_standard_layout<T>::value, "MemoryBuffer::Read<T>() only works on pod and string types.");
|
||||
static_assert(std::is_pod<T>::value, "MemoryBuffer::Read<T>() only works on pod and string types.");
|
||||
T temp;
|
||||
Read((uchar*)&temp, sizeof(T));
|
||||
return temp;
|
||||
@@ -102,7 +102,7 @@ namespace EQ
|
||||
read_pos_ += len + 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void Write(const char *val, size_t len);
|
||||
void Read(uchar *buf, size_t len);
|
||||
void Read(char *str);
|
||||
@@ -113,7 +113,7 @@ namespace EQ
|
||||
inline size_t GetReadPosition() { return read_pos_; }
|
||||
inline void SetReadPosition(size_t rp) { read_pos_ = rp; }
|
||||
inline void ReadSkipBytes(size_t skip) { read_pos_ += skip; }
|
||||
|
||||
|
||||
private:
|
||||
uchar *buffer_;
|
||||
size_t size_;
|
||||
|
||||
@@ -33,9 +33,6 @@
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#include <filesystem>
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace EQ {
|
||||
|
||||
struct MemoryMappedFile::Implementation {
|
||||
|
||||
@@ -10,14 +10,8 @@
|
||||
#include <iterator>
|
||||
#include "types.h"
|
||||
|
||||
class MySQLRequestRow
|
||||
class MySQLRequestRow : public std::iterator<std::input_iterator_tag, MYSQL_ROW>
|
||||
{
|
||||
public:
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using value_type = MYSQL_ROW;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = MYSQL_ROW*;
|
||||
using reference = MYSQL_ROW&;
|
||||
|
||||
private:
|
||||
MYSQL_RES* m_Result;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "console_server.h"
|
||||
#include "../strings.h"
|
||||
#include "../string_util.h"
|
||||
#include <fmt/format.h>
|
||||
|
||||
EQ::Net::ConsoleServer::ConsoleServer(const std::string &addr, int port)
|
||||
@@ -52,11 +52,11 @@ void EQ::Net::ConsoleServer::ConnectionDisconnected(ConsoleServerConnection *c)
|
||||
|
||||
void EQ::Net::ConsoleServer::ProcessCommand(ConsoleServerConnection *c, const std::string &cmd)
|
||||
{
|
||||
auto split = Strings::Split(cmd, ' ');
|
||||
|
||||
auto split = SplitString(cmd, ' ');
|
||||
|
||||
if (split.size() > 0) {
|
||||
auto command = split[0];
|
||||
command = Strings::ToLower(command);
|
||||
ToLowerString(command);
|
||||
|
||||
if (command == "help" || command == "?") {
|
||||
c->SendLine("Commands:");
|
||||
@@ -70,9 +70,9 @@ void EQ::Net::ConsoleServer::ProcessCommand(ConsoleServerConnection *c, const st
|
||||
c->SendPrompt();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
split.erase(split.begin(), split.begin() + 1);
|
||||
|
||||
|
||||
auto cmd_def = m_commands.find(command);
|
||||
if (cmd_def != m_commands.end()) {
|
||||
if (c->Admin() >= cmd_def->second.status_required) {
|
||||
|
||||
@@ -15,7 +15,7 @@ EQ::Net::ConsoleServerConnection::ConsoleServerConnection(ConsoleServer *parent,
|
||||
memset(m_line, 0, MaxConsoleLineLength);
|
||||
m_accept_messages = false;
|
||||
m_user_id = 0;
|
||||
m_admin = AccountStatus::Player;
|
||||
m_admin = 0;
|
||||
|
||||
m_connection->OnRead(std::bind(&ConsoleServerConnection::OnRead, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
m_connection->OnDisconnect(std::bind(&ConsoleServerConnection::OnDisconnect, this, std::placeholders::_1));
|
||||
@@ -29,7 +29,7 @@ EQ::Net::ConsoleServerConnection::ConsoleServerConnection(ConsoleServer *parent,
|
||||
if (addr.find("127.0.0.1") != std::string::npos || addr.find("::0") != std::string::npos) {
|
||||
SendLine("Connection established from localhost, assuming admin");
|
||||
m_status = ConsoleStatusLoggedIn;
|
||||
m_admin = AccountStatus::Max;
|
||||
m_admin = 255;
|
||||
SendPrompt();
|
||||
}
|
||||
else {
|
||||
@@ -116,42 +116,43 @@ bool EQ::Net::ConsoleServerConnection::SendChannelMessage(const ServerChannelMes
|
||||
}
|
||||
|
||||
switch (scm->chan_num) {
|
||||
case ChatChannel_Guild: {
|
||||
QueueMessage(fmt::format("{} tells the guild [{}], '{}'", scm->from, scm->guilddbid, scm->message));
|
||||
break;
|
||||
}
|
||||
case ChatChannel_Auction: {
|
||||
case 4: {
|
||||
if (RuleB(Chat, ServerWideAuction)) {
|
||||
QueueMessage(fmt::format("{} auctions, '{}'", scm->from, scm->message));
|
||||
QueueMessage(fmt::format("{0} auctions, '{1}'", scm->from, scm->message));
|
||||
break;
|
||||
} else { // I think we want default action in this case?
|
||||
return false;
|
||||
}
|
||||
}
|
||||
case ChatChannel_OOC: {
|
||||
|
||||
case 5: {
|
||||
if (RuleB(Chat, ServerWideOOC)) {
|
||||
QueueMessage(fmt::format("{} says ooc, '{}'", scm->from, scm->message));
|
||||
QueueMessage(fmt::format("{0} says ooc, '{1}'", scm->from, scm->message));
|
||||
break;
|
||||
} else { // I think we want default action in this case?
|
||||
return false;
|
||||
}
|
||||
}
|
||||
case ChatChannel_Broadcast: {
|
||||
QueueMessage(fmt::format("{} BROADCASTS, '{}'", scm->from, scm->message));
|
||||
|
||||
case 6: {
|
||||
QueueMessage(fmt::format("{0} BROADCASTS, '{1}'", scm->from, scm->message));
|
||||
break;
|
||||
}
|
||||
case ChatChannel_Tell: {
|
||||
QueueMessage(fmt::format("[{}] tells {}, '{}'", scm->from, scm->to, scm->message));
|
||||
|
||||
case 7: {
|
||||
QueueMessage(fmt::format("[{0}] tells you, '{1}'", scm->from, scm->message));
|
||||
if (onTell) {
|
||||
onTell();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case ChatChannel_GMSAY: {
|
||||
QueueMessage(fmt::format("{} GMSAYS, '{}'", scm->from, scm->message));
|
||||
|
||||
case 11: {
|
||||
QueueMessage(fmt::format("{0} GMSAYS, '{1}'", scm->from, scm->message));
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include "../event/task.h"
|
||||
#include "../data_verification.h"
|
||||
#include "crc32.h"
|
||||
#include "../eqemu_logsys.h"
|
||||
#include <zlib.h>
|
||||
#include <fmt/format.h>
|
||||
#include <sstream>
|
||||
@@ -309,8 +308,6 @@ EQ::Net::DaybreakConnection::DaybreakConnection(DaybreakConnectionManager *owner
|
||||
m_combined[1] = OP_Combined;
|
||||
m_last_session_stats = Clock::now();
|
||||
m_outgoing_budget = owner->m_options.outgoing_data_rate;
|
||||
|
||||
LogNetcode("New session [{}] with encode key [{}]", m_connect_code, HostToNetwork(m_encode_key));
|
||||
}
|
||||
|
||||
//new connection made as client
|
||||
@@ -469,7 +466,7 @@ void EQ::Net::DaybreakConnection::ProcessPacket(Packet &p)
|
||||
for (int i = 1; i >= 0; --i) {
|
||||
switch (m_encode_passes[i]) {
|
||||
case EncodeXOR:
|
||||
if (temp.GetInt8(0) == 0)
|
||||
if (temp.GetInt8(0) == 0)
|
||||
Decode(temp, DaybreakHeader::size(), temp.Length() - DaybreakHeader::size());
|
||||
else
|
||||
Decode(temp, 1, temp.Length() - 1);
|
||||
@@ -633,8 +630,6 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p)
|
||||
DynamicPacket p;
|
||||
p.PutSerialize(0, reply);
|
||||
InternalSend(p);
|
||||
|
||||
LogNetcode("[OP_SessionRequest] Session [{}] started with encode key [{}]", m_connect_code, HostToNetwork(m_encode_key));
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -652,12 +647,6 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p)
|
||||
m_encode_passes[1] = (DaybreakEncodeType)reply.encode_pass2;
|
||||
m_max_packet_size = reply.max_packet_size;
|
||||
ChangeStatus(StatusConnected);
|
||||
|
||||
LogNetcode(
|
||||
"[OP_SessionResponse] Session [{}] refresh with encode key [{}]",
|
||||
m_connect_code,
|
||||
HostToNetwork(m_encode_key)
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -782,12 +771,6 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p)
|
||||
SendDisconnect();
|
||||
}
|
||||
|
||||
LogNetcode(
|
||||
"[OP_SessionDisconnect] Session [{}] disconnect with encode key [{}]",
|
||||
m_connect_code,
|
||||
HostToNetwork(m_encode_key)
|
||||
);
|
||||
|
||||
ChangeStatus(StatusDisconnecting);
|
||||
break;
|
||||
}
|
||||
@@ -852,7 +835,6 @@ bool EQ::Net::DaybreakConnection::ValidateCRC(Packet &p)
|
||||
}
|
||||
|
||||
if (p.Length() < (size_t)m_crc_bytes) {
|
||||
LogNetcode("Session [{}] ignored packet (crc bytes invalid on session)", m_connect_code);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1096,7 +1078,7 @@ void EQ::Net::DaybreakConnection::ProcessResend(int stream)
|
||||
if (m_status == DbProtocolStatus::StatusDisconnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
auto resends = 0;
|
||||
auto now = Clock::now();
|
||||
auto s = &m_streams[stream];
|
||||
@@ -1131,7 +1113,7 @@ void EQ::Net::DaybreakConnection::ProcessResend(int stream)
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if ((size_t)time_since_last_send.count() > entry.second.resend_delay) {
|
||||
auto &p = entry.second.packet;
|
||||
if (p.Length() >= DaybreakHeader::size()) {
|
||||
@@ -1412,7 +1394,7 @@ void EQ::Net::DaybreakConnection::InternalQueuePacket(Packet &p, int stream_id,
|
||||
first_header.total_size = (uint32_t)HostToNetwork((uint32_t)length);
|
||||
|
||||
size_t used = 0;
|
||||
size_t sublen = m_max_packet_size - m_crc_bytes - DaybreakReliableFragmentHeader::size() - 1; // -1 for compress flag
|
||||
size_t sublen = m_max_packet_size - m_crc_bytes - DaybreakReliableFragmentHeader::size();
|
||||
DynamicPacket first_packet;
|
||||
first_packet.PutSerialize(0, first_header);
|
||||
first_packet.PutData(DaybreakReliableFragmentHeader::size(), (char*)p.Data() + used, sublen);
|
||||
@@ -1424,8 +1406,8 @@ void EQ::Net::DaybreakConnection::InternalQueuePacket(Packet &p, int stream_id,
|
||||
sent.first_sent = Clock::now();
|
||||
sent.times_resent = 0;
|
||||
sent.resend_delay = EQ::Clamp(
|
||||
static_cast<size_t>((m_rolling_ping * m_owner->m_options.resend_delay_factor) + m_owner->m_options.resend_delay_ms),
|
||||
m_owner->m_options.resend_delay_min,
|
||||
static_cast<size_t>((m_rolling_ping * m_owner->m_options.resend_delay_factor) + m_owner->m_options.resend_delay_ms),
|
||||
m_owner->m_options.resend_delay_min,
|
||||
m_owner->m_options.resend_delay_max);
|
||||
stream->sent_packets.insert(std::make_pair(stream->sequence_out, sent));
|
||||
stream->sequence_out++;
|
||||
|
||||
@@ -65,15 +65,6 @@ EQ::Net::EQStream::~EQStream()
|
||||
}
|
||||
|
||||
void EQ::Net::EQStream::QueuePacket(const EQApplicationPacket *p, bool ack_req) {
|
||||
|
||||
LogPacketServerClient(
|
||||
"[{}] [{:#06x}] Size [{}] {}",
|
||||
OpcodeManager::EmuToName(p->GetOpcode()),
|
||||
(*m_opcode_manager)->EmuToEQ(p->GetOpcode()),
|
||||
p->Size(),
|
||||
(LogSys.IsLogEnabled(Logs::Detail, Logs::PacketServerClient) ? DumpPacketToString(p) : "")
|
||||
);
|
||||
|
||||
if (m_opcode_manager && *m_opcode_manager) {
|
||||
uint16 opcode = 0;
|
||||
if (p->GetOpcodeBypass() != 0) {
|
||||
|
||||
@@ -57,10 +57,6 @@ namespace EQ
|
||||
virtual void SetOpcodeManager(OpcodeManager **opm) {
|
||||
m_opcode_manager = opm;
|
||||
}
|
||||
virtual OpcodeManager * GetOpcodeManager() const
|
||||
{
|
||||
return (*m_opcode_manager);
|
||||
};
|
||||
|
||||
virtual Stats GetStats() const;
|
||||
virtual void ResetStats();
|
||||
|
||||
@@ -21,16 +21,32 @@ EQ::Net::ServertalkClient::~ServertalkClient()
|
||||
|
||||
void EQ::Net::ServertalkClient::Send(uint16_t opcode, EQ::Net::Packet &p)
|
||||
{
|
||||
// pad zero size packets
|
||||
if (p.Length() == 0) {
|
||||
p.PutUInt8(0, 0);
|
||||
}
|
||||
|
||||
EQ::Net::DynamicPacket out;
|
||||
#ifdef ENABLE_SECURITY
|
||||
if (m_encrypted) {
|
||||
if (p.Length() == 0) {
|
||||
p.PutUInt8(0, 0);
|
||||
}
|
||||
|
||||
out.PutUInt32(0, p.Length() + crypto_secretbox_MACBYTES);
|
||||
out.PutUInt16(4, opcode);
|
||||
|
||||
std::unique_ptr<unsigned char[]> cipher(new unsigned char[p.Length() + crypto_secretbox_MACBYTES]);
|
||||
|
||||
crypto_box_easy_afternm(&cipher[0], (unsigned char*)p.Data(), p.Length(), m_nonce_ours, m_shared_key);
|
||||
(*(uint64_t*)&m_nonce_ours[0])++;
|
||||
out.PutData(6, &cipher[0], p.Length() + crypto_secretbox_MACBYTES);
|
||||
}
|
||||
else {
|
||||
out.PutUInt32(0, p.Length());
|
||||
out.PutUInt16(4, opcode);
|
||||
out.PutPacket(6, p);
|
||||
}
|
||||
#else
|
||||
out.PutUInt32(0, p.Length());
|
||||
out.PutUInt16(4, opcode);
|
||||
out.PutPacket(6, p);
|
||||
|
||||
#endif
|
||||
InternalSend(ServertalkMessage, out);
|
||||
}
|
||||
|
||||
@@ -71,18 +87,14 @@ void EQ::Net::ServertalkClient::Connect()
|
||||
m_connection = connection;
|
||||
m_connection->OnDisconnect([this](EQ::Net::TCPConnection *c) {
|
||||
LogF(Logs::General, Logs::TCPConnection, "Connection lost to {0}:{1}, attempting to reconnect...", m_addr, m_port);
|
||||
m_encrypted = false;
|
||||
m_connection.reset();
|
||||
});
|
||||
|
||||
m_connection->OnRead(std::bind(&EQ::Net::ServertalkClient::ProcessData, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
m_connection->Start();
|
||||
|
||||
SendHandshake();
|
||||
|
||||
if (m_on_connect_cb) {
|
||||
m_on_connect_cb(this);
|
||||
}
|
||||
|
||||
SendHello();
|
||||
m_connecting = false;
|
||||
});
|
||||
}
|
||||
@@ -176,11 +188,67 @@ void EQ::Net::ServertalkClient::ProcessReadBuffer()
|
||||
|
||||
void EQ::Net::ServertalkClient::ProcessHello(EQ::Net::Packet &p)
|
||||
{
|
||||
#ifdef ENABLE_SECURITY
|
||||
memset(m_public_key_ours, 0, crypto_box_PUBLICKEYBYTES);
|
||||
memset(m_public_key_theirs, 0, crypto_box_PUBLICKEYBYTES);
|
||||
memset(m_private_key_ours, 0, crypto_box_SECRETKEYBYTES);
|
||||
memset(m_nonce_ours, 0, crypto_box_NONCEBYTES);
|
||||
memset(m_nonce_theirs, 0, crypto_box_NONCEBYTES);
|
||||
memset(m_shared_key, 0, crypto_box_BEFORENMBYTES);
|
||||
m_encrypted = false;
|
||||
|
||||
try {
|
||||
SendHandshake();
|
||||
bool enc = p.GetInt8(0) == 1 ? true : false;
|
||||
|
||||
if (enc) {
|
||||
if (p.Length() == (1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES)) {
|
||||
memcpy(m_public_key_theirs, (char*)p.Data() + 1, crypto_box_PUBLICKEYBYTES);
|
||||
memcpy(m_nonce_theirs, (char*)p.Data() + 1 + crypto_box_PUBLICKEYBYTES, crypto_box_NONCEBYTES);
|
||||
m_encrypted = true;
|
||||
|
||||
SendHandshake();
|
||||
|
||||
if (m_on_connect_cb) {
|
||||
m_on_connect_cb(this);
|
||||
}
|
||||
}
|
||||
else {
|
||||
LogError("Could not process hello, size != {0}", 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES);
|
||||
}
|
||||
}
|
||||
else {
|
||||
SendHandshake();
|
||||
|
||||
if (m_on_connect_cb) {
|
||||
m_on_connect_cb(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (std::exception &ex) {
|
||||
LogError("Error parsing hello from server: {0}", ex.what());
|
||||
m_connection->Disconnect();
|
||||
|
||||
if (m_on_connect_cb) {
|
||||
m_on_connect_cb(this);
|
||||
m_on_connect_cb(nullptr);
|
||||
}
|
||||
}
|
||||
#else
|
||||
try {
|
||||
bool enc = p.GetInt8(0) == 1 ? true : false;
|
||||
|
||||
if (enc) {
|
||||
SendHandshake(true);
|
||||
|
||||
if (m_on_connect_cb) {
|
||||
m_on_connect_cb(this);
|
||||
}
|
||||
}
|
||||
else {
|
||||
SendHandshake();
|
||||
|
||||
if (m_on_connect_cb) {
|
||||
m_on_connect_cb(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (std::exception &ex) {
|
||||
@@ -191,6 +259,7 @@ void EQ::Net::ServertalkClient::ProcessHello(EQ::Net::Packet &p)
|
||||
m_on_connect_cb(nullptr);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkClient::ProcessMessage(EQ::Net::Packet &p)
|
||||
@@ -200,7 +269,45 @@ void EQ::Net::ServertalkClient::ProcessMessage(EQ::Net::Packet &p)
|
||||
auto opcode = p.GetUInt16(4);
|
||||
if (length > 0) {
|
||||
auto data = p.GetString(6, length);
|
||||
#ifdef ENABLE_SECURITY
|
||||
if (m_encrypted) {
|
||||
size_t message_len = length - crypto_secretbox_MACBYTES;
|
||||
std::unique_ptr<unsigned char[]> decrypted_text(new unsigned char[message_len]);
|
||||
if (crypto_box_open_easy_afternm(&decrypted_text[0], (unsigned char*)&data[0], length, m_nonce_theirs, m_shared_key))
|
||||
{
|
||||
LogError("Error decrypting message from server");
|
||||
(*(uint64_t*)&m_nonce_theirs[0])++;
|
||||
return;
|
||||
}
|
||||
|
||||
EQ::Net::StaticPacket decrypted_packet(&decrypted_text[0], message_len);
|
||||
|
||||
(*(uint64_t*)&m_nonce_theirs[0])++;
|
||||
|
||||
auto cb = m_message_callbacks.find(opcode);
|
||||
if (cb != m_message_callbacks.end()) {
|
||||
cb->second(opcode, decrypted_packet);
|
||||
}
|
||||
|
||||
if (m_message_callback) {
|
||||
m_message_callback(opcode, decrypted_packet);
|
||||
}
|
||||
}
|
||||
else {
|
||||
size_t message_len = length;
|
||||
EQ::Net::StaticPacket packet(&data[0], message_len);
|
||||
|
||||
auto cb = m_message_callbacks.find(opcode);
|
||||
if (cb != m_message_callbacks.end()) {
|
||||
cb->second(opcode, packet);
|
||||
}
|
||||
|
||||
if (m_message_callback) {
|
||||
m_message_callback(opcode, packet);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
size_t message_len = length;
|
||||
EQ::Net::StaticPacket packet(&data[0], message_len);
|
||||
|
||||
@@ -212,6 +319,7 @@ void EQ::Net::ServertalkClient::ProcessMessage(EQ::Net::Packet &p)
|
||||
if (m_message_callback) {
|
||||
m_message_callback(opcode, packet);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
catch (std::exception &ex) {
|
||||
@@ -219,11 +327,54 @@ void EQ::Net::ServertalkClient::ProcessMessage(EQ::Net::Packet &p)
|
||||
}
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkClient::SendHandshake()
|
||||
void EQ::Net::ServertalkClient::SendHandshake(bool downgrade)
|
||||
{
|
||||
EQ::Net::DynamicPacket handshake;
|
||||
#ifdef ENABLE_SECURITY
|
||||
if (m_encrypted) {
|
||||
crypto_box_keypair(m_public_key_ours, m_private_key_ours);
|
||||
randombytes_buf(m_nonce_ours, crypto_box_NONCEBYTES);
|
||||
|
||||
crypto_box_beforenm(m_shared_key, m_public_key_theirs, m_private_key_ours);
|
||||
|
||||
handshake.PutData(0, m_public_key_ours, crypto_box_PUBLICKEYBYTES);
|
||||
handshake.PutData(crypto_box_PUBLICKEYBYTES, m_nonce_ours, crypto_box_NONCEBYTES);
|
||||
|
||||
memset(m_public_key_ours, 0, crypto_box_PUBLICKEYBYTES);
|
||||
memset(m_public_key_theirs, 0, crypto_box_PUBLICKEYBYTES);
|
||||
memset(m_private_key_ours, 0, crypto_box_SECRETKEYBYTES);
|
||||
|
||||
size_t cipher_length = m_identifier.length() + 1 + m_credentials.length() + 1 + crypto_secretbox_MACBYTES;
|
||||
size_t data_length = m_identifier.length() + 1 + m_credentials.length() + 1;
|
||||
|
||||
std::unique_ptr<unsigned char[]> signed_buffer(new unsigned char[cipher_length]);
|
||||
std::unique_ptr<unsigned char[]> data_buffer(new unsigned char[data_length]);
|
||||
|
||||
memset(&data_buffer[0], 0, data_length);
|
||||
memcpy(&data_buffer[0], m_identifier.c_str(), m_identifier.length());
|
||||
memcpy(&data_buffer[1 + m_identifier.length()], m_credentials.c_str(), m_credentials.length());
|
||||
|
||||
crypto_box_easy_afternm(&signed_buffer[0], &data_buffer[0], data_length, m_nonce_ours, m_shared_key);
|
||||
|
||||
(*(uint64_t*)&m_nonce_ours[0])++;
|
||||
|
||||
handshake.PutData(crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, &signed_buffer[0], cipher_length);
|
||||
}
|
||||
else {
|
||||
handshake.PutString(0, m_identifier);
|
||||
handshake.PutString(m_identifier.length() + 1, m_credentials);
|
||||
handshake.PutUInt8(m_identifier.length() + 1 + m_credentials.length(), 0);
|
||||
}
|
||||
#else
|
||||
handshake.PutString(0, m_identifier);
|
||||
handshake.PutString(m_identifier.length() + 1, m_credentials);
|
||||
handshake.PutUInt8(m_identifier.length() + 1 + m_credentials.length(), 0);
|
||||
InternalSend(ServertalkClientDowngradeSecurityHandshake, handshake);
|
||||
#endif
|
||||
|
||||
if (downgrade) {
|
||||
InternalSend(ServertalkClientDowngradeSecurityHandshake, handshake);
|
||||
}
|
||||
else {
|
||||
InternalSend(ServertalkClientHandshake, handshake);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
#include "../event/timer.h"
|
||||
#include "servertalk_common.h"
|
||||
#include "packet.h"
|
||||
#ifdef ENABLE_SECURITY
|
||||
#include <sodium.h>
|
||||
#endif
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
@@ -31,7 +34,8 @@ namespace EQ
|
||||
void ProcessReadBuffer();
|
||||
void ProcessHello(EQ::Net::Packet &p);
|
||||
void ProcessMessage(EQ::Net::Packet &p);
|
||||
void SendHandshake();
|
||||
void SendHandshake() { SendHandshake(false); }
|
||||
void SendHandshake(bool downgrade);
|
||||
|
||||
std::unique_ptr<EQ::Timer> m_timer;
|
||||
|
||||
@@ -41,11 +45,23 @@ namespace EQ
|
||||
bool m_connecting;
|
||||
int m_port;
|
||||
bool m_ipv6;
|
||||
bool m_encrypted;
|
||||
std::shared_ptr<EQ::Net::TCPConnection> m_connection;
|
||||
std::vector<char> m_buffer;
|
||||
std::unordered_map<uint16_t, std::function<void(uint16_t, EQ::Net::Packet&)>> m_message_callbacks;
|
||||
std::function<void(uint16_t, EQ::Net::Packet&)> m_message_callback;
|
||||
std::function<void(ServertalkClient*)> m_on_connect_cb;
|
||||
|
||||
#ifdef ENABLE_SECURITY
|
||||
unsigned char m_public_key_ours[crypto_box_PUBLICKEYBYTES];
|
||||
unsigned char m_private_key_ours[crypto_box_SECRETKEYBYTES];
|
||||
unsigned char m_nonce_ours[crypto_box_NONCEBYTES];
|
||||
|
||||
unsigned char m_public_key_theirs[crypto_box_PUBLICKEYBYTES];
|
||||
unsigned char m_nonce_theirs[crypto_box_NONCEBYTES];
|
||||
|
||||
unsigned char m_shared_key[crypto_box_BEFORENMBYTES];
|
||||
#endif
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,4 +15,4 @@ namespace EQ
|
||||
ServertalkMessage,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,10 +10,12 @@ EQ::Net::ServertalkServer::~ServertalkServer()
|
||||
|
||||
void EQ::Net::ServertalkServer::Listen(const ServertalkServerOptions& opts)
|
||||
{
|
||||
m_encrypted = opts.encrypted;
|
||||
m_credentials = opts.credentials;
|
||||
m_allow_downgrade = opts.allow_downgrade;
|
||||
m_server = std::make_unique<EQ::Net::TCPServer>();
|
||||
m_server->Listen(opts.port, opts.ipv6, [this](std::shared_ptr<EQ::Net::TCPConnection> connection) {
|
||||
m_unident_connections.push_back(std::make_shared<ServertalkServerConnection>(connection, this));
|
||||
m_unident_connections.push_back(std::make_shared<ServertalkServerConnection>(connection, this, m_encrypted, m_allow_downgrade));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#ifdef ENABLE_SECURITY
|
||||
#include <sodium.h>
|
||||
#endif
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
namespace Net
|
||||
@@ -13,9 +17,18 @@ namespace EQ
|
||||
{
|
||||
int port;
|
||||
bool ipv6;
|
||||
bool encrypted;
|
||||
bool allow_downgrade;
|
||||
std::string credentials;
|
||||
|
||||
ServertalkServerOptions() {
|
||||
#ifdef ENABLE_SECURITY
|
||||
encrypted = true;
|
||||
allow_downgrade = true;
|
||||
#else
|
||||
encrypted = false;
|
||||
allow_downgrade = true;
|
||||
#endif
|
||||
ipv6 = false;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -3,15 +3,16 @@
|
||||
#include "../eqemu_logsys.h"
|
||||
#include "../util/uuid.h"
|
||||
|
||||
EQ::Net::ServertalkServerConnection::ServertalkServerConnection(std::shared_ptr<EQ::Net::TCPConnection> c, EQ::Net::ServertalkServer *parent)
|
||||
EQ::Net::ServertalkServerConnection::ServertalkServerConnection(std::shared_ptr<EQ::Net::TCPConnection> c, EQ::Net::ServertalkServer *parent, bool encrypted, bool allow_downgrade)
|
||||
{
|
||||
m_connection = c;
|
||||
m_parent = parent;
|
||||
m_encrypted = encrypted;
|
||||
m_allow_downgrade = allow_downgrade;
|
||||
m_uuid = EQ::Util::UUID::Generate().ToString();
|
||||
m_connection->OnRead(std::bind(&ServertalkServerConnection::OnRead, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
m_connection->OnDisconnect(std::bind(&ServertalkServerConnection::OnDisconnect, this, std::placeholders::_1));
|
||||
m_connection->Start();
|
||||
m_legacy_mode = false;
|
||||
}
|
||||
|
||||
EQ::Net::ServertalkServerConnection::~ServertalkServerConnection()
|
||||
@@ -20,73 +21,32 @@ EQ::Net::ServertalkServerConnection::~ServertalkServerConnection()
|
||||
|
||||
void EQ::Net::ServertalkServerConnection::Send(uint16_t opcode, EQ::Net::Packet & p)
|
||||
{
|
||||
if (m_legacy_mode) {
|
||||
if (!m_connection)
|
||||
return;
|
||||
|
||||
if (opcode == ServerOP_UsertoWorldReq) {
|
||||
auto req_in = (UsertoWorldRequest_Struct*)p.Data();
|
||||
|
||||
EQ::Net::DynamicPacket req;
|
||||
size_t i = 0;
|
||||
req.PutUInt32(i, req_in->lsaccountid); i += 4;
|
||||
req.PutUInt32(i, req_in->worldid); i += 4;
|
||||
req.PutUInt32(i, req_in->FromID); i += 4;
|
||||
req.PutUInt32(i, req_in->ToID); i += 4;
|
||||
req.PutData(i, req_in->IPAddr, 64); i += 64;
|
||||
|
||||
EQ::Net::DynamicPacket out;
|
||||
out.PutUInt16(0, ServerOP_UsertoWorldReqLeg);
|
||||
out.PutUInt16(2, req.Length() + 4);
|
||||
out.PutPacket(4, req);
|
||||
|
||||
m_connection->Write((const char*)out.Data(), out.Length());
|
||||
return;
|
||||
}
|
||||
|
||||
if (opcode == ServerOP_LSClientAuth) {
|
||||
auto req_in = (ClientAuth_Struct*)p.Data();
|
||||
|
||||
EQ::Net::DynamicPacket req;
|
||||
size_t i = 0;
|
||||
req.PutUInt32(i, req_in->loginserver_account_id); i += 4;
|
||||
req.PutData(i, req_in->account_name, 30); i += 30;
|
||||
req.PutData(i, req_in->key, 30); i += 30;
|
||||
req.PutUInt8(i, req_in->lsadmin); i += 1;
|
||||
req.PutUInt16(i, req_in->is_world_admin); i += 2;
|
||||
req.PutUInt32(i, req_in->ip); i += 4;
|
||||
req.PutUInt8(i, req_in->is_client_from_local_network); i += 1;
|
||||
|
||||
EQ::Net::DynamicPacket out;
|
||||
out.PutUInt16(0, ServerOP_LSClientAuthLeg);
|
||||
out.PutUInt16(2, req.Length() + 4);
|
||||
out.PutPacket(4, req);
|
||||
|
||||
m_connection->Write((const char*)out.Data(), out.Length());
|
||||
return;
|
||||
}
|
||||
|
||||
EQ::Net::DynamicPacket out;
|
||||
out.PutUInt16(0, opcode);
|
||||
out.PutUInt16(2, p.Length() + 4);
|
||||
out.PutPacket(4, p);
|
||||
|
||||
m_connection->Write((const char*)out.Data(), out.Length());
|
||||
} else {
|
||||
// pad zero size packets
|
||||
// pad packets that would cause a collision with legacy identification code
|
||||
// It's unlikely we'd send a 4MB msg for any reason but just incase.
|
||||
if (p.Length() == 0 || p.Length() == 43061256) {
|
||||
EQ::Net::DynamicPacket out;
|
||||
#ifdef ENABLE_SECURITY
|
||||
if (m_encrypted) {
|
||||
if (p.Length() == 0) {
|
||||
p.PutUInt8(0, 0);
|
||||
}
|
||||
|
||||
EQ::Net::DynamicPacket out;
|
||||
out.PutUInt32(0, p.Length() + crypto_secretbox_MACBYTES);
|
||||
out.PutUInt16(4, opcode);
|
||||
|
||||
std::unique_ptr<unsigned char[]> cipher(new unsigned char[p.Length() + crypto_secretbox_MACBYTES]);
|
||||
crypto_box_easy_afternm(&cipher[0], (unsigned char*)p.Data(), p.Length(), m_nonce_ours, m_shared_key);
|
||||
(*(uint64_t*)&m_nonce_ours[0])++;
|
||||
out.PutData(6, &cipher[0], p.Length() + crypto_secretbox_MACBYTES);
|
||||
}
|
||||
else {
|
||||
out.PutUInt32(0, p.Length());
|
||||
out.PutUInt16(4, opcode);
|
||||
out.PutPacket(6, p);
|
||||
|
||||
InternalSend(ServertalkMessage, out);
|
||||
}
|
||||
#else
|
||||
out.PutUInt32(0, p.Length());
|
||||
out.PutUInt16(4, opcode);
|
||||
out.PutPacket(6, p);
|
||||
#endif
|
||||
InternalSend(ServertalkMessage, out);
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkServerConnection::SendPacket(ServerPacket *p)
|
||||
@@ -111,41 +71,17 @@ void EQ::Net::ServertalkServerConnection::OnMessage(std::function<void(uint16_t,
|
||||
void EQ::Net::ServertalkServerConnection::OnRead(TCPConnection *c, const unsigned char *data, size_t sz)
|
||||
{
|
||||
m_buffer.insert(m_buffer.end(), (const char*)data, (const char*)data + sz);
|
||||
|
||||
if (m_legacy_mode) {
|
||||
ProcessOldReadBuffer();
|
||||
} else {
|
||||
ProcessReadBuffer();
|
||||
}
|
||||
ProcessReadBuffer();
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkServerConnection::ProcessReadBuffer()
|
||||
{
|
||||
size_t current = 0;
|
||||
size_t total = m_buffer.size();
|
||||
constexpr size_t ls_info_size = sizeof(ServerNewLSInfo_Struct);
|
||||
|
||||
while (current < total) {
|
||||
auto left = total - current;
|
||||
|
||||
if (left < 4) {
|
||||
break;
|
||||
}
|
||||
|
||||
auto leg_opcode = *(uint16_t*)&m_buffer[current];
|
||||
auto leg_size = *(uint16_t*)&m_buffer[current + 2] - 4;
|
||||
|
||||
//this creates a small edge case where the exact size of a
|
||||
//packet from the modern protocol can't be "43061256"
|
||||
//so in send we pad it one byte if that's the case
|
||||
if (leg_opcode == ServerOP_NewLSInfo && leg_size == sizeof(ServerNewLSInfo_Struct)) {
|
||||
m_legacy_mode = true;
|
||||
m_identifier = "World";
|
||||
m_parent->ConnectionIdentified(this);
|
||||
ProcessOldReadBuffer();
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
//header:
|
||||
//uint32 length;
|
||||
@@ -173,7 +109,6 @@ void EQ::Net::ServertalkServerConnection::ProcessReadBuffer()
|
||||
}
|
||||
break;
|
||||
case ServertalkClientHandshake:
|
||||
case ServertalkClientDowngradeSecurityHandshake:
|
||||
ProcessHandshake(p);
|
||||
break;
|
||||
case ServertalkMessage:
|
||||
@@ -190,9 +125,11 @@ void EQ::Net::ServertalkServerConnection::ProcessReadBuffer()
|
||||
}
|
||||
break;
|
||||
case ServertalkClientHandshake:
|
||||
case ServertalkClientDowngradeSecurityHandshake:
|
||||
ProcessHandshake(p);
|
||||
break;
|
||||
case ServertalkClientDowngradeSecurityHandshake:
|
||||
ProcessHandshake(p, true);
|
||||
break;
|
||||
case ServertalkMessage:
|
||||
ProcessMessage(p);
|
||||
break;
|
||||
@@ -210,57 +147,6 @@ void EQ::Net::ServertalkServerConnection::ProcessReadBuffer()
|
||||
}
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkServerConnection::ProcessOldReadBuffer()
|
||||
{
|
||||
size_t current = 0;
|
||||
size_t total = m_buffer.size();
|
||||
|
||||
while (current < total) {
|
||||
auto left = total - current;
|
||||
|
||||
/*
|
||||
//header:
|
||||
//uint32 length;
|
||||
//uint8 type;
|
||||
*/
|
||||
uint16_t length = 0;
|
||||
uint16_t opcode = 0;
|
||||
if (left < 4) {
|
||||
break;
|
||||
}
|
||||
|
||||
opcode = *(uint16_t*)&m_buffer[current];
|
||||
length = *(uint16_t*)&m_buffer[current + 2];
|
||||
if (length < 4) {
|
||||
break;
|
||||
}
|
||||
|
||||
length -= 4;
|
||||
|
||||
if (current + 4 + length > total) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (length == 0) {
|
||||
EQ::Net::DynamicPacket p;
|
||||
ProcessMessageOld(opcode, p);
|
||||
}
|
||||
else {
|
||||
EQ::Net::StaticPacket p(&m_buffer[current + 4], length);
|
||||
ProcessMessageOld(opcode, p);
|
||||
}
|
||||
|
||||
current += length + 4;
|
||||
}
|
||||
|
||||
if (current == total) {
|
||||
m_buffer.clear();
|
||||
}
|
||||
else {
|
||||
m_buffer.erase(m_buffer.begin(), m_buffer.begin() + current);
|
||||
}
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkServerConnection::OnDisconnect(TCPConnection *c)
|
||||
{
|
||||
m_parent->ConnectionDisconnected(this);
|
||||
@@ -269,14 +155,36 @@ void EQ::Net::ServertalkServerConnection::OnDisconnect(TCPConnection *c)
|
||||
void EQ::Net::ServertalkServerConnection::SendHello()
|
||||
{
|
||||
EQ::Net::DynamicPacket hello;
|
||||
|
||||
#ifdef ENABLE_SECURITY
|
||||
memset(m_public_key_ours, 0, crypto_box_PUBLICKEYBYTES);
|
||||
memset(m_public_key_theirs, 0, crypto_box_PUBLICKEYBYTES);
|
||||
memset(m_private_key_ours, 0, crypto_box_SECRETKEYBYTES);
|
||||
memset(m_nonce_ours, 0, crypto_box_NONCEBYTES);
|
||||
memset(m_nonce_theirs, 0, crypto_box_NONCEBYTES);
|
||||
|
||||
if (m_encrypted) {
|
||||
hello.PutInt8(0, 1);
|
||||
|
||||
crypto_box_keypair(m_public_key_ours, m_private_key_ours);
|
||||
randombytes_buf(m_nonce_ours, crypto_box_NONCEBYTES);
|
||||
|
||||
hello.PutData(1, m_public_key_ours, crypto_box_PUBLICKEYBYTES);
|
||||
hello.PutData(1 + crypto_box_PUBLICKEYBYTES, m_nonce_ours, crypto_box_NONCEBYTES);
|
||||
}
|
||||
else {
|
||||
hello.PutInt8(0, 0);
|
||||
}
|
||||
#else
|
||||
hello.PutInt8(0, 0);
|
||||
#endif
|
||||
|
||||
InternalSend(ServertalkServerHello, hello);
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkServerConnection::InternalSend(ServertalkPacketType type, EQ::Net::Packet &p)
|
||||
{
|
||||
if (!m_connection || m_legacy_mode)
|
||||
if (!m_connection)
|
||||
return;
|
||||
|
||||
EQ::Net::DynamicPacket out;
|
||||
@@ -289,8 +197,71 @@ void EQ::Net::ServertalkServerConnection::InternalSend(ServertalkPacketType type
|
||||
m_connection->Write((const char*)out.Data(), out.Length());
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkServerConnection::ProcessHandshake(EQ::Net::Packet &p)
|
||||
void EQ::Net::ServertalkServerConnection::ProcessHandshake(EQ::Net::Packet &p, bool downgrade_security)
|
||||
{
|
||||
#ifdef ENABLE_SECURITY
|
||||
if (downgrade_security && m_allow_downgrade && m_encrypted) {
|
||||
LogF(Logs::General, Logs::TCPConnection, "Downgraded encrypted connection to plaintext because otherside didn't support encryption {0}:{1}",
|
||||
m_connection->RemoteIP(), m_connection->RemotePort());
|
||||
m_encrypted = false;
|
||||
}
|
||||
|
||||
if (m_encrypted) {
|
||||
try {
|
||||
if (p.Length() > (crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES)) {
|
||||
memcpy(m_public_key_theirs, (char*)p.Data(), crypto_box_PUBLICKEYBYTES);
|
||||
memcpy(m_nonce_theirs, (char*)p.Data() + crypto_box_PUBLICKEYBYTES, crypto_box_NONCEBYTES);
|
||||
|
||||
crypto_box_beforenm(m_shared_key, m_public_key_theirs, m_private_key_ours);
|
||||
|
||||
size_t cipher_len = p.Length() - crypto_box_PUBLICKEYBYTES - crypto_box_NONCEBYTES;
|
||||
size_t message_len = cipher_len - crypto_secretbox_MACBYTES;
|
||||
std::unique_ptr<unsigned char[]> decrypted_text(new unsigned char[message_len]);
|
||||
|
||||
if (crypto_box_open_easy_afternm(&decrypted_text[0], (unsigned char*)p.Data() + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, cipher_len, m_nonce_theirs, m_shared_key))
|
||||
{
|
||||
LogError("Error decrypting handshake from client, dropping connection.");
|
||||
m_connection->Disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
m_identifier = (const char*)&decrypted_text[0];
|
||||
std::string credentials = (const char*)&decrypted_text[0] + (m_identifier.length() + 1);
|
||||
|
||||
if (!m_parent->CheckCredentials(credentials)) {
|
||||
LogError("Got incoming connection with invalid credentials during handshake, dropping connection.");
|
||||
m_connection->Disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
m_parent->ConnectionIdentified(this);
|
||||
(*(uint64_t*)&m_nonce_theirs[0])++;
|
||||
}
|
||||
}
|
||||
catch (std::exception &ex) {
|
||||
LogError("Error parsing handshake from client: {0}", ex.what());
|
||||
m_connection->Disconnect();
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
m_identifier = p.GetCString(0);
|
||||
auto credentials = p.GetCString(m_identifier.length() + 1);
|
||||
|
||||
if (!m_parent->CheckCredentials(credentials)) {
|
||||
LogError("Got incoming connection with invalid credentials during handshake, dropping connection.");
|
||||
m_connection->Disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
m_parent->ConnectionIdentified(this);
|
||||
}
|
||||
catch (std::exception &ex) {
|
||||
LogError("Error parsing handshake from client: {0}", ex.what());
|
||||
m_connection->Disconnect();
|
||||
}
|
||||
}
|
||||
#else
|
||||
try {
|
||||
m_identifier = p.GetCString(0);
|
||||
auto credentials = p.GetCString(m_identifier.length() + 1);
|
||||
@@ -307,6 +278,7 @@ void EQ::Net::ServertalkServerConnection::ProcessHandshake(EQ::Net::Packet &p)
|
||||
LogError("Error parsing handshake from client: {0}", ex.what());
|
||||
m_connection->Disconnect();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkServerConnection::ProcessMessage(EQ::Net::Packet &p)
|
||||
@@ -316,19 +288,49 @@ void EQ::Net::ServertalkServerConnection::ProcessMessage(EQ::Net::Packet &p)
|
||||
auto opcode = p.GetUInt16(4);
|
||||
if (length > 0) {
|
||||
auto data = p.GetString(6, length);
|
||||
#ifdef ENABLE_SECURITY
|
||||
if (m_encrypted) {
|
||||
size_t message_len = length - crypto_secretbox_MACBYTES;
|
||||
std::unique_ptr<unsigned char[]> decrypted_text(new unsigned char[message_len]);
|
||||
|
||||
if (crypto_box_open_easy_afternm(&decrypted_text[0], (unsigned char*)&data[0], length, m_nonce_theirs, m_shared_key))
|
||||
{
|
||||
LogError("Error decrypting message from client");
|
||||
(*(uint64_t*)&m_nonce_theirs[0])++;
|
||||
return;
|
||||
}
|
||||
|
||||
EQ::Net::StaticPacket decrypted_packet(&decrypted_text[0], message_len);
|
||||
|
||||
(*(uint64_t*)&m_nonce_theirs[0])++;
|
||||
|
||||
auto cb = m_message_callbacks.find(opcode);
|
||||
if (cb != m_message_callbacks.end()) {
|
||||
cb->second(opcode, decrypted_packet);
|
||||
}
|
||||
|
||||
if (m_message_callback) {
|
||||
m_message_callback(opcode, decrypted_packet);
|
||||
}
|
||||
}
|
||||
else {
|
||||
size_t message_len = length;
|
||||
EQ::Net::StaticPacket packet(&data[0], message_len);
|
||||
|
||||
auto cb = m_message_callbacks.find(opcode);
|
||||
if (cb != m_message_callbacks.end()) {
|
||||
cb->second(opcode, packet);
|
||||
}
|
||||
|
||||
if (m_message_callback) {
|
||||
m_message_callback(opcode, packet);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
size_t message_len = length;
|
||||
EQ::Net::StaticPacket packet(&data[0], message_len);
|
||||
|
||||
const auto is_detail_enabled = LogSys.IsLogEnabled(Logs::Detail, Logs::PacketServerToServer);
|
||||
if (opcode != ServerOP_KeepAlive || is_detail_enabled) {
|
||||
LogPacketServerToServer(
|
||||
"[{:#06x}] Size [{}] {}",
|
||||
opcode,
|
||||
packet.Length(),
|
||||
(is_detail_enabled ? "\n" + packet.ToString() : "")
|
||||
);
|
||||
}
|
||||
|
||||
auto cb = m_message_callbacks.find(opcode);
|
||||
if (cb != m_message_callbacks.end()) {
|
||||
cb->second(opcode, packet);
|
||||
@@ -337,26 +339,10 @@ void EQ::Net::ServertalkServerConnection::ProcessMessage(EQ::Net::Packet &p)
|
||||
if (m_message_callback) {
|
||||
m_message_callback(opcode, packet);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
catch (std::exception &ex) {
|
||||
LogError("Error parsing message from client: {0}", ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
void EQ::Net::ServertalkServerConnection::ProcessMessageOld(uint16_t opcode, EQ::Net::Packet &p)
|
||||
{
|
||||
try {
|
||||
auto cb = m_message_callbacks.find(opcode);
|
||||
if (cb != m_message_callbacks.end()) {
|
||||
cb->second(opcode, p);
|
||||
}
|
||||
|
||||
if (m_message_callback) {
|
||||
m_message_callback(opcode, p);
|
||||
}
|
||||
}
|
||||
catch (std::exception &ex) {
|
||||
LogError("Error parsing legacy message from client: {0}", ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
#include "servertalk_common.h"
|
||||
#include "packet.h"
|
||||
#include <vector>
|
||||
#ifdef ENABLE_SECURITY
|
||||
#include <sodium.h>
|
||||
#endif
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
@@ -13,7 +16,7 @@ namespace EQ
|
||||
class ServertalkServerConnection
|
||||
{
|
||||
public:
|
||||
ServertalkServerConnection(std::shared_ptr<EQ::Net::TCPConnection> c, ServertalkServer *parent);
|
||||
ServertalkServerConnection(std::shared_ptr<EQ::Net::TCPConnection> c, ServertalkServer *parent, bool encrypted, bool allow_downgrade);
|
||||
~ServertalkServerConnection();
|
||||
|
||||
void Send(uint16_t opcode, EQ::Net::Packet &p);
|
||||
@@ -27,13 +30,12 @@ namespace EQ
|
||||
private:
|
||||
void OnRead(TCPConnection* c, const unsigned char* data, size_t sz);
|
||||
void ProcessReadBuffer();
|
||||
void ProcessOldReadBuffer();
|
||||
void OnDisconnect(TCPConnection* c);
|
||||
void SendHello();
|
||||
void InternalSend(ServertalkPacketType type, EQ::Net::Packet &p);
|
||||
void ProcessHandshake(EQ::Net::Packet &p);
|
||||
void ProcessHandshake(EQ::Net::Packet &p) { ProcessHandshake(p, false); }
|
||||
void ProcessHandshake(EQ::Net::Packet &p, bool security_downgrade);
|
||||
void ProcessMessage(EQ::Net::Packet &p);
|
||||
void ProcessMessageOld(uint16_t opcode, EQ::Net::Packet &p);
|
||||
|
||||
std::shared_ptr<EQ::Net::TCPConnection> m_connection;
|
||||
ServertalkServer *m_parent;
|
||||
@@ -43,7 +45,19 @@ namespace EQ
|
||||
std::function<void(uint16_t, EQ::Net::Packet&)> m_message_callback;
|
||||
std::string m_identifier;
|
||||
std::string m_uuid;
|
||||
bool m_legacy_mode;
|
||||
|
||||
bool m_encrypted;
|
||||
bool m_allow_downgrade;
|
||||
#ifdef ENABLE_SECURITY
|
||||
unsigned char m_public_key_ours[crypto_box_PUBLICKEYBYTES];
|
||||
unsigned char m_private_key_ours[crypto_box_SECRETKEYBYTES];
|
||||
unsigned char m_nonce_ours[crypto_box_NONCEBYTES];
|
||||
|
||||
unsigned char m_public_key_theirs[crypto_box_PUBLICKEYBYTES];
|
||||
unsigned char m_nonce_theirs[crypto_box_NONCEBYTES];
|
||||
|
||||
unsigned char m_shared_key[crypto_box_BEFORENMBYTES];
|
||||
#endif
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <map>
|
||||
#include <unordered_set>
|
||||
#include <array>
|
||||
#include "../emu_constants.h"
|
||||
|
||||
struct MethodHandlerEntry
|
||||
{
|
||||
@@ -175,13 +174,13 @@ Json::Value EQ::Net::WebsocketServer::Login(WebsocketServerConnection *connectio
|
||||
auto r = _impl->login_handler(connection, user, pass);
|
||||
|
||||
if (r.logged_in) {
|
||||
connection->SetAuthorized(true, r.account_name, r.account_id, AccountStatus::Max);
|
||||
connection->SetAuthorized(true, r.account_name, r.account_id, 255);
|
||||
ret["status"] = "Ok";
|
||||
}
|
||||
else if (user == "admin" && (connection->RemoteIP() == "127.0.0.1" || connection->RemoteIP() == "::")) {
|
||||
r.logged_in = true;
|
||||
r.account_id = 0;
|
||||
connection->SetAuthorized(true, r.account_name, r.account_id, AccountStatus::Max);
|
||||
connection->SetAuthorized(true, r.account_name, r.account_id, 255);
|
||||
ret["status"] = "Ok";
|
||||
}
|
||||
else {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user