Compare commits

..

1 Commits

Author SHA1 Message Date
Xiphoseer
166a283c70 feat(k8s): mvp 2024-01-02 12:31:39 +01:00
657 changed files with 10840 additions and 10735 deletions

View File

@@ -3,8 +3,8 @@ Dockerfile
*.md *.md
logo.png logo.png
versions.txt versions.txt
build.sh
docker-compose.yml docker-compose.yml
.env .env
docker/__pycache__ docker/__pycache__
.env.example .env.example
build

View File

@@ -1,7 +1,9 @@
# Full path to the LEGO Universe client # Full path to the LEGO Universe client
CLIENT_PATH=./client CLIENT_PATH=/Users/someuser/LEGO Universe
# Can improve build time
BUILD_THREADS=1
# Updates NET_VERSION in CMakeVariables.txt # Updates NET_VERSION in CMakeVariables.txt
NET_VERSION=171022 BUILD_VERSION=171022
# make sure this is a long random string # make sure this is a long random string
# grab a "SHA 256-bit Key" from here: https://keygen.io/ # grab a "SHA 256-bit Key" from here: https://keygen.io/
ACCOUNT_MANAGER_SECRET= ACCOUNT_MANAGER_SECRET=
@@ -10,5 +12,6 @@ EXTERNAL_IP=localhost
# Database values # Database values
# Be careful with special characters here. It is more safe to use normal characters and/or numbers. # Be careful with special characters here. It is more safe to use normal characters and/or numbers.
MARIADB_USER=darkflame MARIADB_USER=darkflame
MARIADB_PASSWORD= MARIADB_PASSWORD=SECRET_VALUE_CHANGE_ME
MARIADB_ROOT_PASSWORD=SECRET_VALUE_CHANGE_ME
MARIADB_DATABASE=darkflame MARIADB_DATABASE=darkflame

View File

@@ -1,56 +0,0 @@
name: CI
on:
push:
branches:
- "main"
tags:
- "v*.*.*"
pull_request:
branches:
- "main"
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push-image:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: recursive
- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
# generate Docker tags based on the following events/attributes
tags: |
type=ref,event=pr
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'main') }}
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

View File

@@ -13,7 +13,7 @@ jobs:
continue-on-error: true continue-on-error: true
strategy: strategy:
matrix: matrix:
os: [ windows-2022, ubuntu-22.04, macos-13 ] os: [ windows-2022, ubuntu-20.04, macos-11 ]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
@@ -25,11 +25,9 @@ jobs:
with: with:
vs-version: '[17,18)' vs-version: '[17,18)'
msbuild-architecture: x64 msbuild-architecture: x64
- name: Install libssl and switch to XCode 15.2 (Mac Only) - name: Install libssl (Mac Only)
if: ${{ matrix.os == 'macos-13' }} if: ${{ matrix.os == 'macos-11' }}
run: | run: brew install openssl@3
brew install openssl@3
sudo xcode-select -s /Applications/Xcode_15.2.app/Contents/Developer
- name: cmake - name: cmake
uses: lukka/run-cmake@v10 uses: lukka/run-cmake@v10
with: with:

1
.gitignore vendored
View File

@@ -122,4 +122,3 @@ docker/__pycache__
docker-compose.override.yml docker-compose.override.yml
!*Test.bin !*Test.bin
!cmake/*

6
.gitmodules vendored
View File

@@ -14,6 +14,12 @@
path = thirdparty/mariadb-connector-cpp path = thirdparty/mariadb-connector-cpp
url = https://github.com/mariadb-corporation/mariadb-connector-cpp.git url = https://github.com/mariadb-corporation/mariadb-connector-cpp.git
ignore = dirty ignore = dirty
[submodule "thirdparty/AccountManager"]
path = thirdparty/AccountManager
url = https://github.com/DarkflameUniverse/AccountManager
[submodule "thirdparty/magic_enum"] [submodule "thirdparty/magic_enum"]
path = thirdparty/magic_enum path = thirdparty/magic_enum
url = https://github.com/Neargye/magic_enum.git url = https://github.com/Neargye/magic_enum.git
[submodule "thirdparty/kubernetes-client-c"]
path = thirdparty/kubernetes-client-c
url = https://github.com/kubernetes-client/c

View File

@@ -3,8 +3,6 @@ project(Darkflame)
include(CTest) include(CTest)
set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD 20)
set(CXX_STANDARD_REQUIRED ON)
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
# Read variables from file # Read variables from file
FILE(READ "${CMAKE_SOURCE_DIR}/CMakeVariables.txt" variables) FILE(READ "${CMAKE_SOURCE_DIR}/CMakeVariables.txt" variables)
@@ -16,13 +14,14 @@ string(REPLACE "\n" ";" variables ${variables})
foreach(variable ${variables}) foreach(variable ${variables})
# If the string contains a #, skip it # If the string contains a #, skip it
if(NOT "${variable}" MATCHES "#") if(NOT "${variable}" MATCHES "#")
# Split the variable into name and value # Split the variable into name and value
string(REPLACE "=" ";" variable ${variable}) string(REPLACE "=" ";" variable ${variable})
# Check that the length of the variable is 2 (name and value) # Check that the length of the variable is 2 (name and value)
list(LENGTH variable length) list(LENGTH variable length)
if(${length} EQUAL 2) if(${length} EQUAL 2)
list(GET variable 0 variable_name) list(GET variable 0 variable_name)
list(GET variable 1 variable_value) list(GET variable 1 variable_value)
@@ -52,18 +51,17 @@ set(RECASTNAVIGATION_EXAMPLES OFF CACHE BOOL "" FORCE)
# Disabled no-register # Disabled no-register
# Disabled unknown pragmas because Linux doesn't understand Windows pragmas. # Disabled unknown pragmas because Linux doesn't understand Windows pragmas.
if(UNIX) if(UNIX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -Wuninitialized -fPIC") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17 -O2 -Wuninitialized -fPIC")
add_compile_definitions(_GLIBCXX_USE_CXX11_ABI=0 _GLIBCXX_USE_CXX17_ABI=0) add_compile_definitions(_GLIBCXX_USE_CXX11_ABI=0 _GLIBCXX_USE_CXX17_ABI=0)
if(NOT APPLE) if(NOT APPLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -lstdc++fs") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -lstdc++fs")
endif() endif()
if(${DYNAMIC} AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") if (${DYNAMIC} AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -rdynamic") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -rdynamic")
endif() endif()
if(${GGDB}) if (${GGDB})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb")
endif() endif()
@@ -77,7 +75,6 @@ endif()
# Our output dir # Our output dir
set(CMAKE_BINARY_DIR ${PROJECT_BINARY_DIR}) set(CMAKE_BINARY_DIR ${PROJECT_BINARY_DIR})
#set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON) # unfortunately, forces all libraries to be built in series, which will slow down the build process
# TODO make this not have to override the build type directories # TODO make this not have to override the build type directories
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_BINARY_DIR}) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_BINARY_DIR})
@@ -91,8 +88,6 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
find_package(MariaDB)
# Create a /resServer directory # Create a /resServer directory
make_directory(${CMAKE_BINARY_DIR}/resServer) make_directory(${CMAKE_BINARY_DIR}/resServer)
@@ -102,64 +97,47 @@ make_directory(${CMAKE_BINARY_DIR}/logs)
# Copy resource files on first build # Copy resource files on first build
set(RESOURCE_FILES "sharedconfig.ini" "authconfig.ini" "chatconfig.ini" "worldconfig.ini" "masterconfig.ini" "blacklist.dcf") set(RESOURCE_FILES "sharedconfig.ini" "authconfig.ini" "chatconfig.ini" "worldconfig.ini" "masterconfig.ini" "blacklist.dcf")
message(STATUS "Checking resource file integrity") message(STATUS "Checking resource file integrity")
foreach (resource_file ${RESOURCE_FILES})
include(Utils)
UpdateConfigOption(${PROJECT_BINARY_DIR}/authconfig.ini "port" "auth_server_port")
UpdateConfigOption(${PROJECT_BINARY_DIR}/chatconfig.ini "port" "chat_server_port")
UpdateConfigOption(${PROJECT_BINARY_DIR}/masterconfig.ini "port" "master_server_port")
foreach(resource_file ${RESOURCE_FILES})
set(file_size 0) set(file_size 0)
if (EXISTS ${PROJECT_BINARY_DIR}/${resource_file})
if(EXISTS ${PROJECT_BINARY_DIR}/${resource_file})
file(SIZE ${PROJECT_BINARY_DIR}/${resource_file} file_size) file(SIZE ${PROJECT_BINARY_DIR}/${resource_file} file_size)
endif() endif()
if (${file_size} EQUAL 0)
if(${file_size} EQUAL 0)
configure_file( configure_file(
${CMAKE_SOURCE_DIR}/resources/${resource_file} ${PROJECT_BINARY_DIR}/${resource_file} ${CMAKE_SOURCE_DIR}/resources/${resource_file} ${PROJECT_BINARY_DIR}/${resource_file}
COPYONLY COPYONLY
) )
message(STATUS "Moved " ${resource_file} " to project binary directory") message(STATUS "Moved " ${resource_file} " to project binary directory")
elseif(resource_file MATCHES ".ini") elseif (resource_file MATCHES ".ini")
message(STATUS "Checking " ${resource_file} " for missing config options") message(STATUS "Checking " ${resource_file} " for missing config options")
file(READ ${PROJECT_BINARY_DIR}/${resource_file} current_file_contents) file(READ ${PROJECT_BINARY_DIR}/${resource_file} current_file_contents)
string(REPLACE "\\\n" "" current_file_contents ${current_file_contents}) string(REPLACE "\\\n" "" current_file_contents ${current_file_contents})
string(REPLACE "\n" ";" current_file_contents ${current_file_contents}) string(REPLACE "\n" ";" current_file_contents ${current_file_contents})
set(parsed_current_file_contents "") set(parsed_current_file_contents "")
# Remove comment lines so they do not interfere with the variable parsing # Remove comment lines so they do not interfere with the variable parsing
foreach(line ${current_file_contents}) foreach (line ${current_file_contents})
string(FIND ${line} "#" is_comment) string(FIND ${line} "#" is_comment)
if (NOT ${is_comment} EQUAL 0)
if(NOT ${is_comment} EQUAL 0)
string(APPEND parsed_current_file_contents ${line}) string(APPEND parsed_current_file_contents ${line})
endif() endif()
endforeach() endforeach()
file(READ ${CMAKE_SOURCE_DIR}/resources/${resource_file} depot_file_contents) file(READ ${CMAKE_SOURCE_DIR}/resources/${resource_file} depot_file_contents)
string(REPLACE "\\\n" "" depot_file_contents ${depot_file_contents}) string(REPLACE "\\\n" "" depot_file_contents ${depot_file_contents})
string(REPLACE "\n" ";" depot_file_contents ${depot_file_contents}) string(REPLACE "\n" ";" depot_file_contents ${depot_file_contents})
set(line_to_add "") set(line_to_add "")
foreach (line ${depot_file_contents})
foreach(line ${depot_file_contents})
string(FIND ${line} "#" is_comment) string(FIND ${line} "#" is_comment)
if (NOT ${is_comment} EQUAL 0)
if(NOT ${is_comment} EQUAL 0)
string(REPLACE "=" ";" line_split ${line}) string(REPLACE "=" ";" line_split ${line})
list(GET line_split 0 variable_name) list(GET line_split 0 variable_name)
if (NOT ${parsed_current_file_contents} MATCHES ${variable_name})
if(NOT ${parsed_current_file_contents} MATCHES ${variable_name})
message(STATUS "Adding missing config option " ${variable_name} " to " ${resource_file}) message(STATUS "Adding missing config option " ${variable_name} " to " ${resource_file})
set(line_to_add ${line_to_add} ${line}) set(line_to_add ${line_to_add} ${line})
foreach (line_to_append ${line_to_add})
foreach(line_to_append ${line_to_add})
file(APPEND ${PROJECT_BINARY_DIR}/${resource_file} "\n" ${line_to_append}) file(APPEND ${PROJECT_BINARY_DIR}/${resource_file} "\n" ${line_to_append})
endforeach() endforeach()
file(APPEND ${PROJECT_BINARY_DIR}/${resource_file} "\n") file(APPEND ${PROJECT_BINARY_DIR}/${resource_file} "\n")
endif() endif()
set(line_to_add "") set(line_to_add "")
else() else()
set(line_to_add ${line_to_add} ${line}) set(line_to_add ${line_to_add} ${line})
@@ -167,11 +145,10 @@ foreach(resource_file ${RESOURCE_FILES})
endforeach() endforeach()
endif() endif()
endforeach() endforeach()
message(STATUS "Resource file integrity check complete") message(STATUS "Resource file integrity check complete")
# if navmeshes directory does not exist, create it # if navmeshes directory does not exist, create it
if(NOT EXISTS ${PROJECT_BINARY_DIR}/navmeshes) if (NOT EXISTS ${PROJECT_BINARY_DIR}/navmeshes)
file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/navmeshes) file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/navmeshes)
endif() endif()
@@ -182,8 +159,7 @@ file(ARCHIVE_EXTRACT INPUT ${PROJECT_BINARY_DIR}/navmeshes.zip DESTINATION ${PRO
file(REMOVE ${PROJECT_BINARY_DIR}/navmeshes.zip) file(REMOVE ${PROJECT_BINARY_DIR}/navmeshes.zip)
# Copy vanity files on first build # Copy vanity files on first build
set(VANITY_FILES "CREDITS.md" "INFO.md" "TESTAMENT.md" "root.xml" "dev-tribute.xml" "atm.xml" "demo.xml") set(VANITY_FILES "CREDITS.md" "INFO.md" "TESTAMENT.md" "NPC.xml")
foreach(file ${VANITY_FILES}) foreach(file ${VANITY_FILES})
configure_file("${CMAKE_SOURCE_DIR}/vanity/${file}" "${CMAKE_BINARY_DIR}/vanity/${file}" COPYONLY) configure_file("${CMAKE_SOURCE_DIR}/vanity/${file}" "${CMAKE_BINARY_DIR}/vanity/${file}" COPYONLY)
endforeach() endforeach()
@@ -191,7 +167,6 @@ endforeach()
# Move our migrations for MasterServer to run # Move our migrations for MasterServer to run
file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/migrations/dlu/) file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/migrations/dlu/)
file(GLOB SQL_FILES ${CMAKE_SOURCE_DIR}/migrations/dlu/*.sql) file(GLOB SQL_FILES ${CMAKE_SOURCE_DIR}/migrations/dlu/*.sql)
foreach(file ${SQL_FILES}) foreach(file ${SQL_FILES})
get_filename_component(file ${file} NAME) get_filename_component(file ${file} NAME)
configure_file(${CMAKE_SOURCE_DIR}/migrations/dlu/${file} ${PROJECT_BINARY_DIR}/migrations/dlu/${file}) configure_file(${CMAKE_SOURCE_DIR}/migrations/dlu/${file} ${PROJECT_BINARY_DIR}/migrations/dlu/${file})
@@ -199,36 +174,125 @@ endforeach()
file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/migrations/cdserver/) file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/migrations/cdserver/)
file(GLOB SQL_FILES ${CMAKE_SOURCE_DIR}/migrations/cdserver/*.sql) file(GLOB SQL_FILES ${CMAKE_SOURCE_DIR}/migrations/cdserver/*.sql)
foreach(file ${SQL_FILES}) foreach(file ${SQL_FILES})
get_filename_component(file ${file} NAME) get_filename_component(file ${file} NAME)
configure_file(${CMAKE_SOURCE_DIR}/migrations/cdserver/${file} ${PROJECT_BINARY_DIR}/migrations/cdserver/${file}) configure_file(${CMAKE_SOURCE_DIR}/migrations/cdserver/${file} ${PROJECT_BINARY_DIR}/migrations/cdserver/${file})
endforeach() endforeach()
# Add system specfic includes for Apple, Windows and Other Unix OS' (including Linux)
if (APPLE)
include_directories("/usr/local/include/")
endif()
# Load all of our third party directories
add_subdirectory(thirdparty)
# Create our list of include directories # Create our list of include directories
set(INCLUDED_DIRECTORIES set(INCLUDED_DIRECTORIES
"dCommon"
"dCommon/dClient"
"dCommon/dEnums"
"dChatFilter"
"dGame"
"dGame/dBehaviors"
"dGame/dComponents"
"dGame/dGameMessages"
"dGame/dInventory"
"dGame/dMission"
"dGame/dEntity"
"dGame/dPropertyBehaviors"
"dGame/dPropertyBehaviors/ControlBehaviorMessages"
"dGame/dUtilities"
"dPhysics" "dPhysics"
"dNavigation" "dNavigation"
"dNavigation/dTerrain"
"dZoneManager"
"dDatabase"
"dDatabase/CDClientDatabase"
"dDatabase/CDClientDatabase/CDClientTables"
"dDatabase/GameDatabase"
"dDatabase/GameDatabase/ITables"
"dDatabase/GameDatabase/MySQL"
"dDatabase/GameDatabase/MySQL/Tables"
"dNet" "dNet"
"dScripts"
"dScripts/02_server"
"dScripts/ai"
"dScripts/client"
"dScripts/EquipmentScripts"
"dScripts/EquipmentTriggers"
"dScripts/zone"
"dScripts/02_server/DLU"
"dScripts/02_server/Enemy"
"dScripts/02_server/Equipment"
"dScripts/02_server/Map"
"dScripts/02_server/Minigame"
"dScripts/02_server/Objects"
"dScripts/02_server/Pets"
"dScripts/02_server/Enemy/AG"
"dScripts/02_server/Enemy/AM"
"dScripts/02_server/Enemy/FV"
"dScripts/02_server/Enemy/General"
"dScripts/02_server/Enemy/Survival"
"dScripts/02_server/Enemy/VE"
"dScripts/02_server/Enemy/Waves"
"dScripts/02_server/Map/AG"
"dScripts/02_server/Map/AG_Spider_Queen"
"dScripts/02_server/Map/AM"
"dScripts/02_server/Map/FV"
"dScripts/02_server/Map/General"
"dScripts/02_server/Map/GF"
"dScripts/02_server/Map/njhub"
"dScripts/02_server/Map/NS"
"dScripts/02_server/Map/NT"
"dScripts/02_server/Map/PR"
"dScripts/02_server/Map/Property"
"dScripts/02_server/Map/SS"
"dScripts/02_server/Map/VE"
"dScripts/02_server/Map/FV/Racing"
"dScripts/02_server/Map/General/Ninjago"
"dScripts/02_server/Map/njhub/boss_instance"
"dScripts/02_server/Map/NS/Waves"
"dScripts/02_server/Map/Property/AG_Med"
"dScripts/02_server/Map/Property/AG_Small"
"dScripts/02_server/Map/Property/NS_Med"
"dScripts/02_server/Minigame/General"
"dScripts/ai/ACT"
"dScripts/ai/AG"
"dScripts/ai/FV"
"dScripts/ai/GENERAL"
"dScripts/ai/GF"
"dScripts/ai/MINIGAME"
"dScripts/ai/MINIGAME/Objects"
"dScripts/ai/NP"
"dScripts/ai/NS"
"dScripts/ai/PETS"
"dScripts/ai/PROPERTY"
"dScripts/ai/RACING"
"dScripts/ai/SPEC"
"dScripts/ai/WILD"
"dScripts/ai/ACT/FootRace"
"dScripts/ai/MINIGAME/SG_GF"
"dScripts/ai/MINIGAME/SG_GF/SERVER"
"dScripts/ai/NS/NS_PP_01"
"dScripts/ai/NS/WH"
"dScripts/ai/PROPERTY/AG"
"dScripts/ai/RACING/OBJECTS"
"dScripts/client/ai"
"dScripts/client/ai/PR"
"dScripts/zone/AG"
"dScripts/zone/LUPs"
"dScripts/zone/PROPERTY"
"dScripts/zone/PROPERTY/FV"
"dScripts/zone/PROPERTY/GF"
"dScripts/zone/PROPERTY/NS"
"thirdparty/magic_enum/include/magic_enum" "thirdparty/magic_enum/include/magic_enum"
"thirdparty/raknet/Source" "thirdparty/raknet/Source"
"thirdparty/tinyxml2" "thirdparty/tinyxml2"
"thirdparty/recastnavigation" "thirdparty/recastnavigation"
"thirdparty/SQLite" "thirdparty/SQLite"
"thirdparty/cpplinq" "thirdparty/cpplinq"
"thirdparty/cpp-httplib"
"thirdparty/MD5"
"tests" "tests"
"tests/dCommonTests" "tests/dCommonTests"
@@ -237,20 +301,37 @@ set(INCLUDED_DIRECTORIES
) )
# Add system specfic includes for Apple, Windows and Other Unix OS' (including Linux) # Add system specfic includes for Apple, Windows and Other Unix OS' (including Linux)
# TODO: Should probably not do this. if (APPLE)
if(APPLE)
include_directories("/usr/local/include/") include_directories("/usr/local/include/")
endif() endif()
# Actually include the directories from our list # Actually include the directories from our list
foreach(dir ${INCLUDED_DIRECTORIES}) foreach (dir ${INCLUDED_DIRECTORIES})
include_directories(${PROJECT_SOURCE_DIR}/${dir}) include_directories(${PROJECT_SOURCE_DIR}/${dir})
endforeach() endforeach()
# Add linking directories: if (NOT WIN32)
if (UNIX) include_directories("${PROJECT_SOURCE_DIR}/thirdparty/libbcrypt/include/bcrypt")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
endif() endif()
include_directories("${PROJECT_SOURCE_DIR}/thirdparty/libbcrypt/include")
# Add linking directories:
link_directories(${PROJECT_BINARY_DIR})
# Load all of our third party directories
add_subdirectory(thirdparty)
# Glob together all headers that need to be precompiled
file(
GLOB HEADERS_DDATABASE
LIST_DIRECTORIES false
${PROJECT_SOURCE_DIR}/dDatabase/CDClientDatabase/*.h
${PROJECT_SOURCE_DIR}/dDatabase/CDClientDatabase/CDClientTables/*.h
${PROJECT_SOURCE_DIR}/dDatabase/GameDatabase/ITables/*.h
${PROJECT_SOURCE_DIR}/thirdparty/SQLite/*.h
)
file( file(
GLOB HEADERS_DZONEMANAGER GLOB HEADERS_DZONEMANAGER
LIST_DIRECTORIES false LIST_DIRECTORIES false
@@ -282,16 +363,15 @@ add_subdirectory(dGame)
add_subdirectory(dZoneManager) add_subdirectory(dZoneManager)
add_subdirectory(dNavigation) add_subdirectory(dNavigation)
add_subdirectory(dPhysics) add_subdirectory(dPhysics)
add_subdirectory(dServer)
# Create a list of common libraries shared between all binaries # Create a list of common libraries shared between all binaries
set(COMMON_LIBRARIES "dCommon" "dDatabase" "dNet" "raknet" "MariaDB::ConnCpp" "magic_enum") set(COMMON_LIBRARIES "dCommon" "dDatabase" "dNet" "raknet" "mariadbConnCpp" "magic_enum")
# Add platform specific common libraries # Add platform specific common libraries
if(UNIX) if (UNIX)
set(COMMON_LIBRARIES ${COMMON_LIBRARIES} "dl" "pthread") set(COMMON_LIBRARIES ${COMMON_LIBRARIES} "dl" "pthread")
if(NOT APPLE AND ${INCLUDE_BACKTRACE}) if (NOT APPLE AND ${INCLUDE_BACKTRACE})
set(COMMON_LIBRARIES ${COMMON_LIBRARIES} "backtrace") set(COMMON_LIBRARIES ${COMMON_LIBRARIES} "backtrace")
endif() endif()
endif() endif()
@@ -302,11 +382,23 @@ add_subdirectory(dAuthServer)
add_subdirectory(dChatServer) add_subdirectory(dChatServer)
add_subdirectory(dMasterServer) # Add MasterServer last so it can rely on the other binaries add_subdirectory(dMasterServer) # Add MasterServer last so it can rely on the other binaries
# Add our precompiled headers
target_precompile_headers(
dGame PRIVATE
${HEADERS_DGAME}
)
target_precompile_headers( target_precompile_headers(
dZoneManager PRIVATE dZoneManager PRIVATE
${HEADERS_DZONEMANAGER} ${HEADERS_DZONEMANAGER}
) )
# Need to specify to use the CXX compiler language here or else we get errors including <string>.
target_precompile_headers(
dDatabase PRIVATE
"$<$<COMPILE_LANGUAGE:CXX>:${HEADERS_DDATABASE}>"
)
target_precompile_headers( target_precompile_headers(
dCommon PRIVATE dCommon PRIVATE
${HEADERS_DCOMMON} ${HEADERS_DCOMMON}
@@ -317,6 +409,6 @@ target_precompile_headers(
"$<$<COMPILE_LANGUAGE:CXX>:${PROJECT_SOURCE_DIR}/thirdparty/tinyxml2/tinyxml2.h>" "$<$<COMPILE_LANGUAGE:CXX>:${PROJECT_SOURCE_DIR}/thirdparty/tinyxml2/tinyxml2.h>"
) )
if(${ENABLE_TESTING}) if (${ENABLE_TESTING})
add_subdirectory(tests) add_subdirectory(tests)
endif() endif()

View File

@@ -14,13 +14,13 @@
"generator": "Unix Makefiles" "generator": "Unix Makefiles"
}, },
{ {
"name": "ci-ubuntu-22.04", "name": "ci-ubuntu-20.04",
"displayName": "CI configure step for Ubuntu", "displayName": "CI configure step for Ubuntu",
"description": "Same as default, Used in GitHub actions workflow", "description": "Same as default, Used in GitHub actions workflow",
"inherits": "default" "inherits": "default"
}, },
{ {
"name": "ci-macos-13", "name": "ci-macos-11",
"displayName": "CI configure step for MacOS", "displayName": "CI configure step for MacOS",
"description": "Same as default, Used in GitHub actions workflow", "description": "Same as default, Used in GitHub actions workflow",
"inherits": "default" "inherits": "default"
@@ -67,15 +67,15 @@
"jobs": 2 "jobs": 2
}, },
{ {
"name": "ci-ubuntu-22.04", "name": "ci-ubuntu-20.04",
"configurePreset": "ci-ubuntu-22.04", "configurePreset": "ci-ubuntu-20.04",
"displayName": "Linux CI Build", "displayName": "Linux CI Build",
"description": "This preset is used by the CI build on linux", "description": "This preset is used by the CI build on linux",
"jobs": 2 "jobs": 2
}, },
{ {
"name": "ci-macos-13", "name": "ci-macos-11",
"configurePreset": "ci-macos-13", "configurePreset": "ci-macos-11",
"displayName": "MacOS CI Build", "displayName": "MacOS CI Build",
"description": "This preset is used by the CI build on MacOS", "description": "This preset is used by the CI build on MacOS",
"jobs": 2 "jobs": 2
@@ -83,8 +83,8 @@
], ],
"testPresets": [ "testPresets": [
{ {
"name": "ci-ubuntu-22.04", "name": "ci-ubuntu-20.04",
"configurePreset": "ci-ubuntu-22.04", "configurePreset": "ci-ubuntu-20.04",
"displayName": "CI Tests on Linux", "displayName": "CI Tests on Linux",
"description": "Runs all tests on a linux configuration", "description": "Runs all tests on a linux configuration",
"execution": { "execution": {
@@ -95,8 +95,8 @@
} }
}, },
{ {
"name": "ci-macos-13", "name": "ci-macos-11",
"configurePreset": "ci-macos-13", "configurePreset": "ci-macos-11",
"displayName": "CI Tests on MacOS", "displayName": "CI Tests on MacOS",
"description": "Runs all tests on a Mac configuration", "description": "Runs all tests on a Mac configuration",
"execution": { "execution": {

46
Docker.md Normal file
View File

@@ -0,0 +1,46 @@
# Run the Darkflame Server inside Docker
## What you need
- [Docker](https://docs.docker.com/get-docker/) (Docker Desktop or on Linux normal Docker)
- [Docker Compose](https://docs.docker.com/compose/install/) (Included in Docker Desktop)
- LEGO® Universe Client. Check the main [README](./README.md) for details on this.
## Run server inside Docker
1. Copy `.env.example` and save it as `.env` inside the root directory of this repository
2. Edit the `.env` file and add your path to the root directory of your LEGO® Universe Client after `CLIENT_PATH=`
3. Update other values in the `.env` file as needed (be sure to update passwords!)
4. Run `docker compose up -d --build`
5. Run `docker compose exec darkflame /app/MasterServer -a` and setup your admin account
6. Follow the directions [here](https://github.com/DarkflameUniverse/AccountManager) to setup regular user accounts. The server will be accessible at: `http://<EXTERNAL_IP>:5000`
7. Now you can see the output of the server with `docker compose logs -f --tail 100` or `docker compose logs -f --tail 100`. This can help you understand issues and there you can also see when the server finishes it's startup.
8. You're ready to connect your client!
**NOTE #1**: If you're running an older version of Docker, you may need to use the command `docker-compose` instead of `docker compose`.
**NOTE #2**: To stop the server simply run `docker compose down` and to restart it just run `docker compose up -d` again. No need to run all the steps above every time.
**NOTE #3**: Docker buildkit needs to be enabled. https://docs.docker.com/develop/develop-images/build_enhancements/#to-enable-buildkit-builds
**NOTE #4**: Make sure to run the following in the repo root directory after cloning so submodules are also downloaded.
```
git submodule update --init --recursive
```
**NOTE #5**: If DarkflameSetup fails due to not having cdclient.fdb, rename CDClient.fdb (in the same folder) to cdclient.fdb
## Disable brickbuildfix
If you don't need the http server running on port 80 do this:
1. Create a file with the name `docker-compose.override.yml` in the root of the repository
2. Paste this content:
```yml
services:
brickbuildfix:
profiles:
- donotstart
```
3. Now run `docker compose up -d`

58
Docker_Windows.md Normal file
View File

@@ -0,0 +1,58 @@
# Installation under Windows
## First Run
1. Navigate to the [Docker download page](https://www.docker.com/products/docker-desktop) and download docker.
![Docker Download Page](docker/images/Docker_Download_Page.png)
2. Once the file has finished downloading, run it and proceed through the installation. Make sure, "Install required Windows components for WSL 2" is checked.
![Docker Desktop Installer Configuration](docker/images/Docker_Desktop_Installer_Configuration.png)
3. If necessary, restart your computer.
4. After the restart, Docker Desktop will automatically open. If it does not, simply start it like any other program.
5. If a window "WSL 2 Installation is incomplete." pops up, follow the link and click "WSL2 Linux kernel update package for x64 machines". Run the downloaded file and once that finishes, click "Restart" in the Docker Desktop window.
![WSL 2 download](docker/images/WSL_2_download.png)
6. Wait until Docker Desktop has started. You may skip the tutorial.
7. You may want to disable "Open Docker Dashboard at startup" in _Settings_ -> _General_
![Disable Dashboard Autostart](docker/images/DD_General_Settings.png)
8. Install [Git for Windows](https://git-scm.com/download/win). During the installation, simply confirming the defaults is sufficient.
9. In the folder you wish to save the Server, right click and select "Git Bash Here".
10. Type `git clone --recursive https://github.com/DarkflameUniverse/DarkflameServer`
11. Once the command has completed (you can see you path again and can enter commands), close the window.
12. Inside the downloaded folder, copy `.env.example` and name the copy `.env`
13. Open `.env` with Notepad by right-clicking it and selecting _Open With_ -> _More apps_ -> _Notepad_.
14. Change the text after `CLIENT_PATH=` to the location of your client. This folder must contain either a folder `client` or `legouniverse.exe`.
> If you need the extra performance, place the client files in `\\wsl$\<your linux OS>\...` to avoid working across file systems, see [Docker Best Practices](https://docs.docker.com/desktop/windows/wsl/#best-practices) and [WSL documentation](https://docs.microsoft.com/en-us/windows/wsl/filesystems#file-storage-and-performance-across-file-systems).
15. Optionally, you can change the number after `BUILD_THREADS=` to the number of cores / threads your processor has. If your computer crashes while building, you can try to reduce this value.
16. After `ACCOUNT_MANAGER_SECRET=` paste a "SHA 256-bit Key" from https://keygen.io/
17. If you are not only hosting a local server, change the value after `EXTERNAL_IP=` to the external IP address of your computer.
18. Change the two values `SECRET_VALUE_CHANGE_ME` to passwords only you know. Save and close the file.
19. In the extracted folder hit Shift+Right Click and select "Open PowerShell window here".
![Open PowerShell](docker/images/Open_Powershell.png)
17. In the new window, paste (with right click) or type `docker compose up -d --build` and confirm with enter.
18. Once you see the blinking cursor and the path again, setup has finished and the server is already running.
![setup done](docker/images/setup_finished.png)
19. Create an admin account by pasting `docker compose exec darkflame /app/MasterServer -a` and following the prompts.
![admin account creation](docker/images/Account_Creation.png)
20. You can now login with these credentials at `http://your_ip:5000` (replace your_ip with your external IP). There you can create your account for playing as well as generate keys for other people to join; use these at `http://your_ip:5000/activate`
## Normal Use
1. In Docker Desktop you should now see an entry `darkflameserver-main` and when you click on it all containers but `DarkflameSetup` should eventually be green. That means the server is running.
![server running](docker/images/Docker_Compose_Finished.png)
2. For troubleshooting, you can check the logs of the various parts by clicking their entry.
3. You can start and stop the server with the corresponding buttons. Once all containers are grey, the server has shut down, and when all containers but `DarkflameSetup` are green, the server is running. Note that starting and stopping takes some time, please be patient.
![start stop buttons](docker/images/DD_Server_Startstop.png)

View File

@@ -1,50 +0,0 @@
FROM gcc:12 as build
WORKDIR /app
RUN set -ex; \
apt-get update; \
apt-get install -y cmake
COPY . /app/
COPY --chmod=0500 ./build.sh /app/
RUN sed -i 's/MARIADB_CONNECTOR_COMPILE_JOBS__=.*/MARIADB_CONNECTOR_COMPILE_JOBS__=2/' /app/CMakeVariables.txt
RUN ./build.sh
FROM debian:12 as runtime
WORKDIR /app
RUN --mount=type=cache,id=build-apt-cache,target=/var/cache/apt \
apt update && \
apt install -y libssl3 libcurl4 && \
rm -rf /var/lib/apt/lists/*
# Grab libraries and load them
COPY --from=build /app/build/mariadbcpp/libmariadbcpp.so /usr/local/lib/
RUN ldconfig
# Server bins
COPY --from=build /app/build/*Server /app/
# Necessary suplimentary files
COPY --from=build /app/build/*.ini /app/configs/
COPY --from=build /app/build/vanity/*.* /app/vanity/*
COPY --from=build /app/build/navmeshes /app/navmeshes
COPY --from=build /app/build/migrations /app/migrations
COPY --from=build /app/build/*.dcf /app/
# backup of config and vanity files to copy to the host incase
# of a mount clobbering the copy from above
COPY --from=build /app/build/*.ini /app/default-configs/
COPY --from=build /app/build/vanity/*.* /app/default-vanity/*
# needed as the container runs with the root user
# and therefore sudo doesn't exist
ENV USE_SUDO_AUTH=0
ENV DLU_CONFIG_DIR=/app/configs/
COPY --chmod=0500 ./entrypoint.sh /app/
ENTRYPOINT [ "/app/entrypoint.sh" ]

View File

@@ -37,7 +37,6 @@ If you would like a setup for a single player server only on a Windows machine,
* [Verify your setup](#verify-your-setup) * [Verify your setup](#verify-your-setup)
* [Running the server](#running-the-server) * [Running the server](#running-the-server)
* [User Guide](#user-guide) * [User Guide](#user-guide)
* [Docker](#docker)
## Clone the repository ## Clone the repository
If you are on Windows, you will need to download and install git from [here](https://git-scm.com/download/win) If you are on Windows, you will need to download and install git from [here](https://git-scm.com/download/win)
@@ -348,66 +347,6 @@ certutil -hashfile <file> SHA1
Known good *SHA1* checksum of the Darkflame Universe client: Known good *SHA1* checksum of the Darkflame Universe client:
- `91498e09b83ce69f46baf9e521d48f23fe502985` (packed client, zip compressed) - `91498e09b83ce69f46baf9e521d48f23fe502985` (packed client, zip compressed)
# Docker
The Darkflame Server is automatically built and published as a Docker Container / [OCI](https://opencontainers.org/) Image to the GitHub Container Registry at:
[`ghcr.io/darkflameuniverse/darkflameserver`](https://github.com/DarkflameUniverse/DarkflameServer/pkgs/container/darkflameserver).
## Compose
> [!WARNING]
> It seems that Docker Desktop on Windows with the WSL 2 backend has some issues with MariaDB (c.f. [mariadb-docker#331](https://github.com/MariaDB/mariadb-docker/issues/331)) triggered by NexusDashboard
> migrations, so this setup may not work for you. If that is the case, please tell us about your setup in [NexusDashboard#92](https://github.com/DarkflameUniverse/NexusDashboard/issues/92).
You can use the `docker-compose` tool to [setup a MariaDB database](#database-setup), run the Darkflame Server and manage it with [Nexus Dashboard](https://github.com/DarkflameUniverse/NexusDashboard) all
at once. For that:
- [Install Docker Desktop](https://docs.docker.com/get-docker/)
- Open the directory that contains your LU Client
- If the `legouniverse.exe` is in a subfolder called `client`, you're good to go. There may also be a folder `versions`.
- Otherwise, create a new `client` folder and move the exe and everything else (e.g. `res` and `locale`) in there. This is necessary to work around a bug in the client that will prevent that you to log back in after getting disconnected.
- Download the [docker-compose.yml](docker-compose.yml) file and place it next to `client`.
- Download the [.env.example](.env.example) file and place it next to `client` with the file name `.env`
- You may get warnings that this name starts with a dot, acknowledge those, this is intentional. Depending on your operating system, you may need to activate showing hidden files (e.g. Ctrl-H in Gnome on Linux) and/or file extensions ("File name extensions" in the "View" tab on Windows).
- Update the `ACCOUNT_MANAGER_SECRET` and `MARIADB_PASSWORD` with strong random passwords.
- Use a password generator like <https://keygen.io>
- Avoid `:` and `@` characters
- Once the database user is created, changing the password will not update it, so the server will just fail to connect.
- Set `EXTERNAL_IP` to your LAN IP or public IP if you want to host the game for friends & family
- Open a terminal in the folder with the `docker-compose.yml` and `client`
- Run `docker compose up -d`
- This might require `sudo` on Linux, and a recent version of [docker compose](https://docs.docker.com/compose/install/)
- Run `docker exec -it dlu-darkflameserver-1 /app/MasterServer -a` and follow the instructions to create the initial admin account
- Open <http://localhost:8000> to access Nexus Dashboard with the admin account to create normal users
- Set `AUTHSERVERIP=0:localhost` in `client/boot.cfg`
- Replace `localhost` with the value of `EXTERNAL_IP` if you changed that earlier.
- Also make sure `UGCUSE3DSERVICES=7:` is set to `0`
- Launch `legouniverse.exe`
## Standalone
This assumes that you have a database deployed to your host or in another docker container.
A basic deployment of this contianer would look like:
```sh
# example docker contianer deployment
docker run -it \
-v /path/to/configs/:/app/configs \
-v /path/to/logs/:/app/logs \
-v /path/to/dumps/:/app/dumps \
-v /path/to/res:/app/res:ro \
-v /path/to/resServer:/app/resServer \
-e DUMP_FOLDER=/app/dumps \
-p 1001:1001/udp \
-p 2005:2005/udp \
-p 3000-3300:3000-3300/udp \
ghcr.io/darkflameuniverse/darkflameserver:latest
```
You will need to replace the `/path/to/`'s to reflect the paths on your host.
Any config option in the `.ini`'s can be overridden with environmental variables: Ex: `log_to_console=1` from `shared_config.ini` would be overidden like `-e LOG_TO_CONSOLE=0`
# Development Documentation # Development Documentation
This is a Work in Progress, but below are some quick links to documentaion for systems and structs in the server This is a Work in Progress, but below are some quick links to documentaion for systems and structs in the server
[Networked message structs](https://lcdruniverse.org/lu_packets/lu_packets/index.html) [Networked message structs](https://lcdruniverse.org/lu_packets/lu_packets/index.html)

View File

@@ -1,17 +0,0 @@
include(FetchContent)
message(STATUS "Fetching gtest...")
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG release-1.12.1
)
# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(GoogleTest)
message(STATUS "gtest fetched and is now ready.")
set(GoogleTest_FOUND TRUE)

View File

@@ -1,51 +0,0 @@
# Parses a config file for a specific option and appends the new option if it does not exist
# If the new option does exist, this function will do nothing.
# file_name: The name of the file to parse
# old_option_name: The name of the option to find
# new_option_name: The name of the option to add
function(UpdateConfigOption file_name old_option_name new_option_name)
string(APPEND old_option_name "=")
string(APPEND new_option_name "=")
message(STATUS "Checking " ${file_name} " for " ${old_option_name} " and adding " ${new_option_name} " if it does not exist")
if(NOT EXISTS ${file_name})
message(STATUS ${file_name} " does not exist. Doing nothing")
return()
endif()
file(READ ${file_name} current_file_contents)
string(REPLACE "\\\n" "" current_file_contents ${current_file_contents})
string(REPLACE "\n" ";" current_file_contents ${current_file_contents})
set(parsed_current_file_contents "")
# Remove comment lines so they do not interfere with the variable parsing
foreach(line ${current_file_contents})
string(FIND ${line} "#" is_comment)
if(NOT ${is_comment} EQUAL 0)
string(APPEND parsed_current_file_contents ${line})
endif()
endforeach()
set(found_new_option -1)
set(found_old_option -1)
set(current_value -1)
foreach(line ${current_file_contents})
string(FIND ${line} ${old_option_name} old_option_in_file)
if(${old_option_in_file} EQUAL 0)
set(found_old_option 1)
set(current_value ${line})
endif()
string(FIND ${line} ${new_option_name} found_new_option_in_file)
if(${found_new_option_in_file} EQUAL 0)
set(found_new_option 1)
endif()
endforeach(line ${current_file_contents})
if(${found_old_option} EQUAL 1 AND NOT ${found_new_option} EQUAL 1)
string(REPLACE ${old_option_name} ${new_option_name} current_value ${current_value})
file(APPEND ${file_name} "\n" ${current_value})
endif()
endfunction()

View File

@@ -16,7 +16,7 @@
//RakNet includes: //RakNet includes:
#include "RakNetDefines.h" #include "RakNetDefines.h"
#include "MessageIdentifiers.h" #include <MessageIdentifiers.h>
//Auth includes: //Auth includes:
#include "AuthPackets.h" #include "AuthPackets.h"
@@ -25,9 +25,6 @@
#include "eAuthMessageType.h" #include "eAuthMessageType.h"
#include "Game.h" #include "Game.h"
#include "Server.h"
namespace Game { namespace Game {
Logger* logger = nullptr; Logger* logger = nullptr;
dServer* server = nullptr; dServer* server = nullptr;
@@ -36,6 +33,7 @@ namespace Game {
std::mt19937 randomEngine; std::mt19937 randomEngine;
} }
Logger* SetupLogger();
void HandlePacket(Packet* packet); void HandlePacket(Packet* packet);
int main(int argc, char** argv) { int main(int argc, char** argv) {
@@ -48,12 +46,15 @@ int main(int argc, char** argv) {
std::signal(SIGINT, Game::OnSignal); std::signal(SIGINT, Game::OnSignal);
std::signal(SIGTERM, Game::OnSignal); std::signal(SIGTERM, Game::OnSignal);
Game::config = new dConfig("authconfig.ini");
//Create all the objects we need to run our service: //Create all the objects we need to run our service:
Server::SetupLogger("AuthServer"); Game::logger = SetupLogger();
if (!Game::logger) return EXIT_FAILURE; if (!Game::logger) return EXIT_FAILURE;
//Read our config:
Game::config = new dConfig("authconfig.ini");
Game::logger->SetLogToConsole(Game::config->GetValue("log_to_console") != "0");
Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1");
LOG("Starting Auth server..."); LOG("Starting Auth server...");
LOG("Version: %s", PROJECT_VERSION); LOG("Version: %s", PROJECT_VERSION);
LOG("Compiled on: %s", __TIMESTAMP__); LOG("Compiled on: %s", __TIMESTAMP__);
@@ -82,15 +83,12 @@ int main(int argc, char** argv) {
Game::randomEngine = std::mt19937(time(0)); Game::randomEngine = std::mt19937(time(0));
//It's safe to pass 'localhost' here, as the IP is only used as the external IP. //It's safe to pass 'localhost' here, as the IP is only used as the external IP.
std::string ourIP = "localhost"; uint32_t maxClients = 50;
const uint32_t maxClients = GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("max_clients")).value_or(999); uint32_t ourPort = 1001; //LU client is hardcoded to use this for auth port, so I'm making it the default.
if (Game::config->GetValue("max_clients") != "") maxClients = std::stoi(Game::config->GetValue("max_clients"));
if (Game::config->GetValue("port") != "") ourPort = std::atoi(Game::config->GetValue("port").c_str());
//LU client is hardcoded to use this for auth port, so I'm making it the default. Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Auth, Game::config, &Game::lastSignal);
const uint32_t ourPort = GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("auth_server_port")).value_or(1001);
const auto externalIPString = Game::config->GetValue("external_ip");
if (!externalIPString.empty()) ourIP = externalIPString;
Game::server = new dServer(ourIP, ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Auth, Game::config, &Game::lastSignal);
//Run it until server gets a kill message from Master: //Run it until server gets a kill message from Master:
auto t = std::chrono::high_resolution_clock::now(); auto t = std::chrono::high_resolution_clock::now();
@@ -161,6 +159,18 @@ int main(int argc, char** argv) {
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
Logger* SetupLogger() {
std::string logPath = (BinaryPathFinder::GetBinaryDir() / ("logs/AuthServer_" + std::to_string(time(nullptr)) + ".log")).string();
bool logToConsole = false;
bool logDebugStatements = false;
#ifdef _DEBUG
logToConsole = true;
logDebugStatements = true;
#endif
return new Logger(logPath, logToConsole, logDebugStatements);
}
void HandlePacket(Packet* packet) { void HandlePacket(Packet* packet) {
if (packet->length < 4) return; if (packet->length < 4) return;

View File

@@ -1,7 +1,3 @@
add_executable(AuthServer "AuthServer.cpp") add_executable(AuthServer "AuthServer.cpp")
target_link_libraries(AuthServer ${COMMON_LIBRARIES})
target_link_libraries(AuthServer ${COMMON_LIBRARIES} dServer)
target_include_directories(AuthServer PRIVATE ${PROJECT_SOURCE_DIR}/dServer)
add_compile_definitions(AuthServer PRIVATE PROJECT_VERSION="\"${PROJECT_VERSION}\"") add_compile_definitions(AuthServer PRIVATE PROJECT_VERSION="\"${PROJECT_VERSION}\"")

View File

@@ -5,12 +5,8 @@ set(DCHATSERVER_SOURCES
) )
add_executable(ChatServer "ChatServer.cpp") add_executable(ChatServer "ChatServer.cpp")
target_include_directories(ChatServer PRIVATE "${PROJECT_SOURCE_DIR}/dChatFilter") add_library(dChatServer ${DCHATSERVER_SOURCES})
add_compile_definitions(ChatServer PRIVATE PROJECT_VERSION="\"${PROJECT_VERSION}\"") add_compile_definitions(ChatServer PRIVATE PROJECT_VERSION="\"${PROJECT_VERSION}\"")
add_library(dChatServer ${DCHATSERVER_SOURCES})
target_include_directories(dChatServer PRIVATE "${PROJECT_SOURCE_DIR}/dServer")
target_link_libraries(dChatServer ${COMMON_LIBRARIES} dChatFilter) target_link_libraries(dChatServer ${COMMON_LIBRARIES} dChatFilter)
target_link_libraries(ChatServer ${COMMON_LIBRARIES} dChatFilter dChatServer dServer) target_link_libraries(ChatServer ${COMMON_LIBRARIES} dChatFilter dChatServer)

View File

@@ -2,6 +2,7 @@
#include "PlayerContainer.h" #include "PlayerContainer.h"
#include "eChatInternalMessageType.h" #include "eChatInternalMessageType.h"
#include "BitStreamUtils.h" #include "BitStreamUtils.h"
#include "PacketUtils.h"
#include "Game.h" #include "Game.h"
#include "Logger.h" #include "Logger.h"
#include "eObjectBits.h" #include "eObjectBits.h"
@@ -25,41 +26,42 @@ void ChatIgnoreList::GetIgnoreList(Packet* packet) {
LWOOBJID playerId; LWOOBJID playerId;
inStream.Read(playerId); inStream.Read(playerId);
auto& receiver = Game::playerContainer.GetPlayerDataMutable(playerId); auto* receiver = Game::playerContainer.GetPlayerData(playerId);
if (!receiver) { if (!receiver) {
LOG("Tried to get ignore list, but player %llu not found in container", playerId); LOG("Tried to get ignore list, but player %llu not found in container", playerId);
return; return;
} }
if (!receiver.ignoredPlayers.empty()) { if (!receiver->ignoredPlayers.empty()) {
LOG_DEBUG("Player %llu already has an ignore list, but is requesting it again.", playerId); LOG_DEBUG("Player %llu already has an ignore list", playerId);
} else { return;
auto ignoreList = Database::Get()->GetIgnoreList(static_cast<uint32_t>(playerId)); }
if (ignoreList.empty()) {
LOG_DEBUG("Player %llu has no ignores", playerId);
return;
}
for (auto& ignoredPlayer : ignoreList) { auto ignoreList = Database::Get()->GetIgnoreList(static_cast<uint32_t>(playerId));
receiver.ignoredPlayers.emplace_back(ignoredPlayer.name, ignoredPlayer.id); if (ignoreList.empty()) {
GeneralUtils::SetBit(receiver.ignoredPlayers.back().playerId, eObjectBits::CHARACTER); LOG_DEBUG("Player %llu has no ignores", playerId);
GeneralUtils::SetBit(receiver.ignoredPlayers.back().playerId, eObjectBits::PERSISTENT); return;
} }
for (auto& ignoredPlayer : ignoreList) {
receiver->ignoredPlayers.push_back(IgnoreData{ ignoredPlayer.id, ignoredPlayer.name });
GeneralUtils::SetBit(receiver->ignoredPlayers.back().playerId, eObjectBits::CHARACTER);
GeneralUtils::SetBit(receiver->ignoredPlayers.back().playerId, eObjectBits::PERSISTENT);
} }
CBITSTREAM; CBITSTREAM;
WriteOutgoingReplyHeader(bitStream, receiver.playerID, ChatIgnoreList::Response::GET_IGNORE); WriteOutgoingReplyHeader(bitStream, receiver->playerID, ChatIgnoreList::Response::GET_IGNORE);
bitStream.Write<uint8_t>(false); // Probably is Is Free Trial, but we don't care about that bitStream.Write<uint8_t>(false); // Probably is Is Free Trial, but we don't care about that
bitStream.Write<uint16_t>(0); // literally spacing due to struct alignment bitStream.Write<uint16_t>(0); // literally spacing due to struct alignment
bitStream.Write<uint16_t>(receiver.ignoredPlayers.size()); bitStream.Write<uint16_t>(receiver->ignoredPlayers.size());
for (const auto& ignoredPlayer : receiver.ignoredPlayers) { for (const auto& ignoredPlayer : receiver->ignoredPlayers) {
bitStream.Write(ignoredPlayer.playerId); bitStream.Write(ignoredPlayer.playerId);
bitStream.Write(LUWString(ignoredPlayer.playerName, 36)); bitStream.Write(LUWString(ignoredPlayer.playerName, 36));
} }
Game::server->Send(bitStream, packet->systemAddress, false); Game::server->Send(&bitStream, packet->systemAddress, false);
} }
void ChatIgnoreList::AddIgnore(Packet* packet) { void ChatIgnoreList::AddIgnore(Packet* packet) {
@@ -67,40 +69,40 @@ void ChatIgnoreList::AddIgnore(Packet* packet) {
LWOOBJID playerId; LWOOBJID playerId;
inStream.Read(playerId); inStream.Read(playerId);
auto& receiver = Game::playerContainer.GetPlayerDataMutable(playerId); auto* receiver = Game::playerContainer.GetPlayerData(playerId);
if (!receiver) { if (!receiver) {
LOG("Tried to get ignore list, but player %llu not found in container", playerId); LOG("Tried to get ignore list, but player %llu not found in container", playerId);
return; return;
} }
constexpr int32_t MAX_IGNORES = 32; constexpr int32_t MAX_IGNORES = 32;
if (receiver.ignoredPlayers.size() > MAX_IGNORES) { if (receiver->ignoredPlayers.size() > MAX_IGNORES) {
LOG_DEBUG("Player %llu has too many ignores", playerId); LOG_DEBUG("Player %llu has too many ignores", playerId);
return; return;
} }
inStream.IgnoreBytes(4); // ignore some garbage zeros idk inStream.IgnoreBytes(4); // ignore some garbage zeros idk
LUWString toIgnoreName; LUWString toIgnoreName(33);
inStream.Read(toIgnoreName); inStream.Read(toIgnoreName);
std::string toIgnoreStr = toIgnoreName.GetAsString(); std::string toIgnoreStr = toIgnoreName.GetAsString();
CBITSTREAM; CBITSTREAM;
WriteOutgoingReplyHeader(bitStream, receiver.playerID, ChatIgnoreList::Response::ADD_IGNORE); WriteOutgoingReplyHeader(bitStream, receiver->playerID, ChatIgnoreList::Response::ADD_IGNORE);
// Check if the player exists // Check if the player exists
LWOOBJID ignoredPlayerId = LWOOBJID_EMPTY; LWOOBJID ignoredPlayerId = LWOOBJID_EMPTY;
if (toIgnoreStr == receiver.playerName || toIgnoreStr.find("[GM]") == 0) { if (toIgnoreStr == receiver->playerName || toIgnoreStr.find("[GM]") == 0) {
LOG_DEBUG("Player %llu tried to ignore themselves", playerId); LOG_DEBUG("Player %llu tried to ignore themselves", playerId);
bitStream.Write(ChatIgnoreList::AddResponse::GENERAL_ERROR); bitStream.Write(ChatIgnoreList::AddResponse::GENERAL_ERROR);
} else if (std::count(receiver.ignoredPlayers.begin(), receiver.ignoredPlayers.end(), toIgnoreStr) > 0) { } else if (std::count(receiver->ignoredPlayers.begin(), receiver->ignoredPlayers.end(), toIgnoreStr) > 0) {
LOG_DEBUG("Player %llu is already ignoring %s", playerId, toIgnoreStr.c_str()); LOG_DEBUG("Player %llu is already ignoring %s", playerId, toIgnoreStr.c_str());
bitStream.Write(ChatIgnoreList::AddResponse::ALREADY_IGNORED); bitStream.Write(ChatIgnoreList::AddResponse::ALREADY_IGNORED);
} else { } else {
// Get the playerId falling back to query if not online // Get the playerId falling back to query if not online
const auto& playerData = Game::playerContainer.GetPlayerData(toIgnoreStr); auto* playerData = Game::playerContainer.GetPlayerData(toIgnoreStr);
if (!playerData) { if (!playerData) {
// Fall back to query // Fall back to query
auto player = Database::Get()->GetCharacterInfo(toIgnoreStr); auto player = Database::Get()->GetCharacterInfo(toIgnoreStr);
@@ -110,7 +112,7 @@ void ChatIgnoreList::AddIgnore(Packet* packet) {
ignoredPlayerId = player->id; ignoredPlayerId = player->id;
} }
} else { } else {
ignoredPlayerId = playerData.playerID; ignoredPlayerId = playerData->playerID;
} }
if (ignoredPlayerId != LWOOBJID_EMPTY) { if (ignoredPlayerId != LWOOBJID_EMPTY) {
@@ -118,7 +120,7 @@ void ChatIgnoreList::AddIgnore(Packet* packet) {
GeneralUtils::SetBit(ignoredPlayerId, eObjectBits::CHARACTER); GeneralUtils::SetBit(ignoredPlayerId, eObjectBits::CHARACTER);
GeneralUtils::SetBit(ignoredPlayerId, eObjectBits::PERSISTENT); GeneralUtils::SetBit(ignoredPlayerId, eObjectBits::PERSISTENT);
receiver.ignoredPlayers.emplace_back(toIgnoreStr, ignoredPlayerId); receiver->ignoredPlayers.push_back(IgnoreData{ ignoredPlayerId, toIgnoreStr });
LOG_DEBUG("Player %llu is ignoring %s", playerId, toIgnoreStr.c_str()); LOG_DEBUG("Player %llu is ignoring %s", playerId, toIgnoreStr.c_str());
bitStream.Write(ChatIgnoreList::AddResponse::SUCCESS); bitStream.Write(ChatIgnoreList::AddResponse::SUCCESS);
@@ -131,7 +133,7 @@ void ChatIgnoreList::AddIgnore(Packet* packet) {
bitStream.Write(playerNameSend); bitStream.Write(playerNameSend);
bitStream.Write(ignoredPlayerId); bitStream.Write(ignoredPlayerId);
Game::server->Send(bitStream, packet->systemAddress, false); Game::server->Send(&bitStream, packet->systemAddress, false);
} }
void ChatIgnoreList::RemoveIgnore(Packet* packet) { void ChatIgnoreList::RemoveIgnore(Packet* packet) {
@@ -139,7 +141,7 @@ void ChatIgnoreList::RemoveIgnore(Packet* packet) {
LWOOBJID playerId; LWOOBJID playerId;
inStream.Read(playerId); inStream.Read(playerId);
auto& receiver = Game::playerContainer.GetPlayerDataMutable(playerId); auto* receiver = Game::playerContainer.GetPlayerData(playerId);
if (!receiver) { if (!receiver) {
LOG("Tried to get ignore list, but player %llu not found in container", playerId); LOG("Tried to get ignore list, but player %llu not found in container", playerId);
return; return;
@@ -147,25 +149,25 @@ void ChatIgnoreList::RemoveIgnore(Packet* packet) {
inStream.IgnoreBytes(4); // ignore some garbage zeros idk inStream.IgnoreBytes(4); // ignore some garbage zeros idk
LUWString removedIgnoreName; LUWString removedIgnoreName(33);
inStream.Read(removedIgnoreName); inStream.Read(removedIgnoreName);
std::string removedIgnoreStr = removedIgnoreName.GetAsString(); std::string removedIgnoreStr = removedIgnoreName.GetAsString();
auto toRemove = std::remove(receiver.ignoredPlayers.begin(), receiver.ignoredPlayers.end(), removedIgnoreStr); auto toRemove = std::remove(receiver->ignoredPlayers.begin(), receiver->ignoredPlayers.end(), removedIgnoreStr);
if (toRemove == receiver.ignoredPlayers.end()) { if (toRemove == receiver->ignoredPlayers.end()) {
LOG_DEBUG("Player %llu is not ignoring %s", playerId, removedIgnoreStr.c_str()); LOG_DEBUG("Player %llu is not ignoring %s", playerId, removedIgnoreStr.c_str());
return; return;
} }
Database::Get()->RemoveIgnore(static_cast<uint32_t>(playerId), static_cast<uint32_t>(toRemove->playerId)); Database::Get()->RemoveIgnore(static_cast<uint32_t>(playerId), static_cast<uint32_t>(toRemove->playerId));
receiver.ignoredPlayers.erase(toRemove, receiver.ignoredPlayers.end()); receiver->ignoredPlayers.erase(toRemove, receiver->ignoredPlayers.end());
CBITSTREAM; CBITSTREAM;
WriteOutgoingReplyHeader(bitStream, receiver.playerID, ChatIgnoreList::Response::REMOVE_IGNORE); WriteOutgoingReplyHeader(bitStream, receiver->playerID, ChatIgnoreList::Response::REMOVE_IGNORE);
bitStream.Write<int8_t>(0); bitStream.Write<int8_t>(0);
LUWString playerNameSend(removedIgnoreStr, 33); LUWString playerNameSend(removedIgnoreStr, 33);
bitStream.Write(playerNameSend); bitStream.Write(playerNameSend);
Game::server->Send(bitStream, packet->systemAddress, false); Game::server->Send(&bitStream, packet->systemAddress, false);
} }

File diff suppressed because it is too large Load Diff

View File

@@ -4,56 +4,16 @@
#include "BitStream.h" #include "BitStream.h"
struct PlayerData; struct PlayerData;
enum class eAddFriendResponseType : uint8_t; enum class eAddFriendResponseType : uint8_t;
enum class eChatChannel : uint8_t {
SYSTEMNOTIFY = 0,
SYSTEMWARNING,
SYSTEMERROR,
BROADCAST,
LOCAL,
LOCALNOANIM,
EMOTE,
PRIVATE_CHAT,
TEAM,
TEAMLOCAL,
GUILD,
GUILDNOTIFY,
PROPERTY,
ADMIN,
COMBATDAMAGE,
COMBATHEALING,
COMBATLOOT,
COMBATEXP,
COMBATDEATH,
GENERAL,
TRADE,
LFG,
USER
};
enum class eChatMessageResponseCode : uint8_t {
SENT = 0,
NOTONLINE,
GENERALERROR,
RECEIVEDNEWWHISPER,
NOTFRIENDS,
SENDERFREETRIAL,
RECEIVERFREETRIAL,
};
namespace ChatPacketHandler { namespace ChatPacketHandler {
void HandleFriendlistRequest(Packet* packet); void HandleFriendlistRequest(Packet* packet);
void HandleFriendRequest(Packet* packet); void HandleFriendRequest(Packet* packet);
void HandleFriendResponse(Packet* packet); void HandleFriendResponse(Packet* packet);
void HandleRemoveFriend(Packet* packet); void HandleRemoveFriend(Packet* packet);
void HandleGMLevelUpdate(Packet* packet);
void HandleChatMessage(Packet* packet); void HandleChatMessage(Packet* packet);
void HandlePrivateChatMessage(Packet* packet); void HandlePrivateChatMessage(Packet* packet);
void SendPrivateChatMessage(const PlayerData& sender, const PlayerData& receiver, const PlayerData& routeTo, const LUWString& message, const eChatChannel channel, const eChatMessageResponseCode responseCode);
void HandleTeamInvite(Packet* packet); void HandleTeamInvite(Packet* packet);
void HandleTeamInviteResponse(Packet* packet); void HandleTeamInviteResponse(Packet* packet);
@@ -63,18 +23,18 @@ namespace ChatPacketHandler {
void HandleTeamLootOption(Packet* packet); void HandleTeamLootOption(Packet* packet);
void HandleTeamStatusRequest(Packet* packet); void HandleTeamStatusRequest(Packet* packet);
void SendTeamInvite(const PlayerData& receiver, const PlayerData& sender); void SendTeamInvite(PlayerData* receiver, PlayerData* sender);
void SendTeamInviteConfirm(const PlayerData& receiver, bool bLeaderIsFreeTrial, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, uint8_t ucResponseCode, std::u16string wsLeaderName); void SendTeamInviteConfirm(PlayerData* receiver, bool bLeaderIsFreeTrial, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, uint8_t ucResponseCode, std::u16string wsLeaderName);
void SendTeamStatus(const PlayerData& receiver, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, std::u16string wsLeaderName); void SendTeamStatus(PlayerData* receiver, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, std::u16string wsLeaderName);
void SendTeamSetLeader(const PlayerData& receiver, LWOOBJID i64PlayerID); void SendTeamSetLeader(PlayerData* receiver, LWOOBJID i64PlayerID);
void SendTeamAddPlayer(const PlayerData& receiver, bool bIsFreeTrial, bool bLocal, bool bNoLootOnDeath, LWOOBJID i64PlayerID, std::u16string wsPlayerName, LWOZONEID zoneID); void SendTeamAddPlayer(PlayerData* receiver, bool bIsFreeTrial, bool bLocal, bool bNoLootOnDeath, LWOOBJID i64PlayerID, std::u16string wsPlayerName, LWOZONEID zoneID);
void SendTeamRemovePlayer(const PlayerData& receiver, bool bDisband, bool bIsKicked, bool bIsLeaving, bool bLocal, LWOOBJID i64LeaderID, LWOOBJID i64PlayerID, std::u16string wsPlayerName); void SendTeamRemovePlayer(PlayerData* receiver, bool bDisband, bool bIsKicked, bool bIsLeaving, bool bLocal, LWOOBJID i64LeaderID, LWOOBJID i64PlayerID, std::u16string wsPlayerName);
void SendTeamSetOffWorldFlag(const PlayerData& receiver, LWOOBJID i64PlayerID, LWOZONEID zoneID); void SendTeamSetOffWorldFlag(PlayerData* receiver, LWOOBJID i64PlayerID, LWOZONEID zoneID);
//FriendData is the player we're SENDING this stuff to. Player is the friend that changed state. //FriendData is the player we're SENDING this stuff to. Player is the friend that changed state.
void SendFriendUpdate(const PlayerData& friendData, const PlayerData& playerData, uint8_t notifyType, uint8_t isBestFriend); void SendFriendUpdate(PlayerData* friendData, PlayerData* playerData, uint8_t notifyType, uint8_t isBestFriend);
void SendFriendRequest(const PlayerData& receiver, const PlayerData& sender); void SendFriendRequest(PlayerData* receiver, PlayerData* sender);
void SendFriendResponse(const PlayerData& receiver, const PlayerData& sender, eAddFriendResponseType responseCode, uint8_t isBestFriendsAlready = 0U, uint8_t isBestFriendRequest = 0U); void SendFriendResponse(PlayerData* receiver, PlayerData* sender, eAddFriendResponseType responseCode, uint8_t isBestFriendsAlready = 0U, uint8_t isBestFriendRequest = 0U);
void SendRemoveFriend(const PlayerData& receiver, std::string& personToRemove, bool isSuccessful); void SendRemoveFriend(PlayerData* receiver, std::string& personToRemove, bool isSuccessful);
}; };

View File

@@ -20,14 +20,12 @@
#include "eChatInternalMessageType.h" #include "eChatInternalMessageType.h"
#include "eWorldMessageType.h" #include "eWorldMessageType.h"
#include "ChatIgnoreList.h" #include "ChatIgnoreList.h"
#include "StringifiedEnum.h"
#include "Game.h" #include "Game.h"
#include "Server.h"
//RakNet includes: //RakNet includes:
#include "RakNetDefines.h" #include "RakNetDefines.h"
#include "MessageIdentifiers.h" #include <MessageIdentifiers.h>
namespace Game { namespace Game {
Logger* logger = nullptr; Logger* logger = nullptr;
@@ -40,6 +38,7 @@ namespace Game {
PlayerContainer playerContainer; PlayerContainer playerContainer;
} }
Logger* SetupLogger();
void HandlePacket(Packet* packet); void HandlePacket(Packet* packet);
int main(int argc, char** argv) { int main(int argc, char** argv) {
@@ -52,13 +51,14 @@ int main(int argc, char** argv) {
std::signal(SIGINT, Game::OnSignal); std::signal(SIGINT, Game::OnSignal);
std::signal(SIGTERM, Game::OnSignal); std::signal(SIGTERM, Game::OnSignal);
Game::config = new dConfig("chatconfig.ini");
//Create all the objects we need to run our service: //Create all the objects we need to run our service:
Server::SetupLogger("ChatServer"); Game::logger = SetupLogger();
if (!Game::logger) return EXIT_FAILURE; if (!Game::logger) return EXIT_FAILURE;
//Read our config: //Read our config:
Game::config = new dConfig("chatconfig.ini");
Game::logger->SetLogToConsole(Game::config->GetValue("log_to_console") != "0");
Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1");
LOG("Starting Chat server..."); LOG("Starting Chat server...");
LOG("Version: %s", PROJECT_VERSION); LOG("Version: %s", PROJECT_VERSION);
@@ -99,16 +99,14 @@ int main(int argc, char** argv) {
masterPort = masterInfo->port; masterPort = masterInfo->port;
} }
//It's safe to pass 'localhost' here, as the IP is only used as the external IP. //It's safe to pass 'localhost' here, as the IP is only used as the external IP.
std::string ourIP = "localhost"; uint32_t maxClients = 50;
const uint32_t maxClients = GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("max_clients")).value_or(999); uint32_t ourPort = 1501;
const uint32_t ourPort = GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("chat_server_port")).value_or(2005); if (Game::config->GetValue("max_clients") != "") maxClients = std::stoi(Game::config->GetValue("max_clients"));
const auto externalIPString = Game::config->GetValue("external_ip"); if (Game::config->GetValue("port") != "") ourPort = std::atoi(Game::config->GetValue("port").c_str());
if (!externalIPString.empty()) ourIP = externalIPString;
Game::server = new dServer(ourIP, ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config, &Game::lastSignal); Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config, &Game::lastSignal);
const bool dontGenerateDCF = GeneralUtils::TryParse<bool>(Game::config->GetValue("dont_generate_dcf")).value_or(false); Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(Game::config->GetValue("dont_generate_dcf"))));
Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", dontGenerateDCF);
Game::randomEngine = std::mt19937(time(0)); Game::randomEngine = std::mt19937(time(0));
@@ -179,6 +177,18 @@ int main(int argc, char** argv) {
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
Logger* SetupLogger() {
std::string logPath = (BinaryPathFinder::GetBinaryDir() / ("logs/ChatServer_" + std::to_string(time(nullptr)) + ".log")).string();
bool logToConsole = false;
bool logDebugStatements = false;
#ifdef _DEBUG
logToConsole = true;
logDebugStatements = true;
#endif
return new Logger(logPath, logToConsole, logDebugStatements);
}
void HandlePacket(Packet* packet) { void HandlePacket(Packet* packet) {
if (packet->data[0] == ID_DISCONNECTION_NOTIFICATION || packet->data[0] == ID_CONNECTION_LOST) { if (packet->data[0] == ID_DISCONNECTION_NOTIFICATION || packet->data[0] == ID_CONNECTION_LOST) {
LOG("A server has disconnected, erasing their connected players from the list."); LOG("A server has disconnected, erasing their connected players from the list.");
@@ -211,7 +221,7 @@ void HandlePacket(Packet* packet) {
case eChatInternalMessageType::ANNOUNCEMENT: { case eChatInternalMessageType::ANNOUNCEMENT: {
//we just forward this packet to every connected server //we just forward this packet to every connected server
CINSTREAM; CINSTREAM;
Game::server->Send(inStream, packet->systemAddress, true); //send to everyone except origin Game::server->Send(&inStream, packet->systemAddress, true); //send to everyone except origin
break; break;
} }
@@ -221,8 +231,7 @@ void HandlePacket(Packet* packet) {
} }
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::CHAT) { if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::CHAT) {
eChatMessageType chat_message_type = static_cast<eChatMessageType>(packet->data[3]); switch (static_cast<eChatMessageType>(packet->data[3])) {
switch (chat_message_type) {
case eChatMessageType::GET_FRIENDS_LIST: case eChatMessageType::GET_FRIENDS_LIST:
ChatPacketHandler::HandleFriendlistRequest(packet); ChatPacketHandler::HandleFriendlistRequest(packet);
break; break;
@@ -292,61 +301,9 @@ void HandlePacket(Packet* packet) {
case eChatMessageType::TEAM_SET_LOOT: case eChatMessageType::TEAM_SET_LOOT:
ChatPacketHandler::HandleTeamLootOption(packet); ChatPacketHandler::HandleTeamLootOption(packet);
break; break;
case eChatMessageType::GMLEVEL_UPDATE:
ChatPacketHandler::HandleGMLevelUpdate(packet);
break;
case eChatMessageType::LOGIN_SESSION_NOTIFY:
case eChatMessageType::USER_CHANNEL_CHAT_MESSAGE:
case eChatMessageType::WORLD_DISCONNECT_REQUEST:
case eChatMessageType::WORLD_PROXIMITY_RESPONSE:
case eChatMessageType::WORLD_PARCEL_RESPONSE:
case eChatMessageType::TEAM_MISSED_INVITE_CHECK:
case eChatMessageType::GUILD_CREATE:
case eChatMessageType::GUILD_INVITE:
case eChatMessageType::GUILD_INVITE_RESPONSE:
case eChatMessageType::GUILD_LEAVE:
case eChatMessageType::GUILD_KICK:
case eChatMessageType::GUILD_GET_STATUS:
case eChatMessageType::GUILD_GET_ALL:
case eChatMessageType::SHOW_ALL:
case eChatMessageType::BLUEPRINT_MODERATED:
case eChatMessageType::BLUEPRINT_MODEL_READY:
case eChatMessageType::PROPERTY_READY_FOR_APPROVAL:
case eChatMessageType::PROPERTY_MODERATION_CHANGED:
case eChatMessageType::PROPERTY_BUILDMODE_CHANGED:
case eChatMessageType::PROPERTY_BUILDMODE_CHANGED_REPORT:
case eChatMessageType::MAIL:
case eChatMessageType::WORLD_INSTANCE_LOCATION_REQUEST:
case eChatMessageType::REPUTATION_UPDATE:
case eChatMessageType::SEND_CANNED_TEXT:
case eChatMessageType::CHARACTER_NAME_CHANGE_REQUEST:
case eChatMessageType::CSR_REQUEST:
case eChatMessageType::CSR_REPLY:
case eChatMessageType::GM_KICK:
case eChatMessageType::GM_ANNOUNCE:
case eChatMessageType::WORLD_ROUTE_PACKET:
case eChatMessageType::GET_ZONE_POPULATIONS:
case eChatMessageType::REQUEST_MINIMUM_CHAT_MODE:
case eChatMessageType::MATCH_REQUEST:
case eChatMessageType::UGCMANIFEST_REPORT_MISSING_FILE:
case eChatMessageType::UGCMANIFEST_REPORT_DONE_FILE:
case eChatMessageType::UGCMANIFEST_REPORT_DONE_BLUEPRINT:
case eChatMessageType::UGCC_REQUEST:
case eChatMessageType::WHO:
case eChatMessageType::WORLD_PLAYERS_PET_MODERATED_ACKNOWLEDGE:
case eChatMessageType::ACHIEVEMENT_NOTIFY:
case eChatMessageType::GM_CLOSE_PRIVATE_CHAT_WINDOW:
case eChatMessageType::UNEXPECTED_DISCONNECT:
case eChatMessageType::PLAYER_READY:
case eChatMessageType::GET_DONATION_TOTAL:
case eChatMessageType::UPDATE_DONATION:
case eChatMessageType::PRG_CSR_COMMAND:
case eChatMessageType::HEARTBEAT_REQUEST_FROM_WORLD:
case eChatMessageType::UPDATE_FREE_TRIAL_STATUS:
LOG("Unhandled CHAT Message id: %s (%i)", StringifiedEnum::ToString(chat_message_type).data(), chat_message_type);
break;
default: default:
LOG("Unknown CHAT Message id: %i", chat_message_type); LOG("Unknown CHAT id: %i", int(packet->data[3]));
} }
} }

View File

@@ -14,10 +14,12 @@
#include "dConfig.h" #include "dConfig.h"
void PlayerContainer::Initialize() { void PlayerContainer::Initialize() {
m_MaxNumberOfBestFriends = GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("max_number_of_best_friends"), m_MaxNumberOfBestFriends);
GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("max_number_of_best_friends")).value_or(m_MaxNumberOfBestFriends); GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("max_number_of_friends"), m_MaxNumberOfFriends);
m_MaxNumberOfFriends = }
GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("max_number_of_friends")).value_or(m_MaxNumberOfFriends);
PlayerContainer::~PlayerContainer() {
m_Players.clear();
} }
TeamData::TeamData() { TeamData::TeamData() {
@@ -26,33 +28,27 @@ TeamData::TeamData() {
void PlayerContainer::InsertPlayer(Packet* packet) { void PlayerContainer::InsertPlayer(Packet* packet) {
CINSTREAM_SKIP_HEADER; CINSTREAM_SKIP_HEADER;
LWOOBJID playerId; PlayerData* data = new PlayerData();
if (!inStream.Read(playerId)) { inStream.Read(data->playerID);
LOG("Failed to read player ID");
return;
}
auto& data = m_Players[playerId];
data.playerID = playerId;
uint32_t len; uint32_t len;
inStream.Read<uint32_t>(len); inStream.Read<uint32_t>(len);
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
char character; inStream.Read<char>(character); char character; inStream.Read<char>(character);
data.playerName += character; data->playerName += character;
} }
inStream.Read(data.zoneID); inStream.Read(data->zoneID);
inStream.Read(data.muteExpire); inStream.Read(data->muteExpire);
inStream.Read(data.gmLevel); data->sysAddr = packet->systemAddress;
data.sysAddr = packet->systemAddress;
m_Names[data.playerID] = GeneralUtils::UTF8ToUTF16(data.playerName); m_Names[data->playerID] = GeneralUtils::UTF8ToUTF16(data->playerName);
LOG("Added user: %s (%llu), zone: %i", data.playerName.c_str(), data.playerID, data.zoneID.GetMapID()); m_Players.insert(std::make_pair(data->playerID, data));
LOG("Added user: %s (%llu), zone: %i", data->playerName.c_str(), data->playerID, data->zoneID.GetMapID());
Database::Get()->UpdateActivityLog(data.playerID, eActivityType::PlayerLoggedIn, data.zoneID.GetMapID()); Database::Get()->UpdateActivityLog(data->playerID, eActivityType::PlayerLoggedIn, data->zoneID.GetMapID());
} }
void PlayerContainer::RemovePlayer(Packet* packet) { void PlayerContainer::RemovePlayer(Packet* packet) {
@@ -61,27 +57,26 @@ void PlayerContainer::RemovePlayer(Packet* packet) {
inStream.Read(playerID); inStream.Read(playerID);
//Before they get kicked, we need to also send a message to their friends saying that they disconnected. //Before they get kicked, we need to also send a message to their friends saying that they disconnected.
const auto& player = GetPlayerData(playerID); std::unique_ptr<PlayerData> player(this->GetPlayerData(playerID));
if (!player) { if (player == nullptr) {
LOG("Failed to find user: %llu", playerID);
return; return;
} }
for (const auto& fr : player.friends) { for (auto& fr : player->friends) {
const auto& fd = this->GetPlayerData(fr.friendID); auto fd = this->GetPlayerData(fr.friendID);
if (fd) ChatPacketHandler::SendFriendUpdate(fd, player, 0, fr.isBestFriend); if (fd) ChatPacketHandler::SendFriendUpdate(fd, player.get(), 0, fr.isBestFriend);
} }
auto* team = GetTeam(playerID); auto* team = GetTeam(playerID);
if (team != nullptr) { if (team != nullptr) {
const auto memberName = GeneralUtils::UTF8ToUTF16(player.playerName); const auto memberName = GeneralUtils::UTF8ToUTF16(std::string(player->playerName.c_str()));
for (const auto memberId : team->memberIDs) { for (const auto memberId : team->memberIDs) {
const auto& otherMember = GetPlayerData(memberId); auto* otherMember = GetPlayerData(memberId);
if (!otherMember) continue; if (otherMember == nullptr) continue;
ChatPacketHandler::SendTeamSetOffWorldFlag(otherMember, playerID, { 0, 0, 0 }); ChatPacketHandler::SendTeamSetOffWorldFlag(otherMember, playerID, { 0, 0, 0 });
} }
@@ -90,7 +85,7 @@ void PlayerContainer::RemovePlayer(Packet* packet) {
LOG("Removed user: %llu", playerID); LOG("Removed user: %llu", playerID);
m_Players.erase(playerID); m_Players.erase(playerID);
Database::Get()->UpdateActivityLog(playerID, eActivityType::PlayerLoggedOut, player.zoneID.GetMapID()); Database::Get()->UpdateActivityLog(playerID, eActivityType::PlayerLoggedOut, player->zoneID.GetMapID());
} }
void PlayerContainer::MuteUpdate(Packet* packet) { void PlayerContainer::MuteUpdate(Packet* packet) {
@@ -100,15 +95,15 @@ void PlayerContainer::MuteUpdate(Packet* packet) {
time_t expire = 0; time_t expire = 0;
inStream.Read(expire); inStream.Read(expire);
auto& player = this->GetPlayerDataMutable(playerID); auto* player = this->GetPlayerData(playerID);
if (!player) { if (player == nullptr) {
LOG("Failed to find user: %llu", playerID); LOG("Failed to find user: %llu", playerID);
return; return;
} }
player.muteExpire = expire; player->muteExpire = expire;
BroadcastMuteUpdate(playerID, expire); BroadcastMuteUpdate(playerID, expire);
} }
@@ -150,7 +145,7 @@ void PlayerContainer::BroadcastMuteUpdate(LWOOBJID player, time_t time) {
bitStream.Write(player); bitStream.Write(player);
bitStream.Write(time); bitStream.Write(time);
Game::server->Send(bitStream, UNASSIGNED_SYSTEM_ADDRESS, true); Game::server->Send(&bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);
} }
TeamData* PlayerContainer::CreateLocalTeam(std::vector<LWOOBJID> members) { TeamData* PlayerContainer::CreateLocalTeam(std::vector<LWOOBJID> members) {
@@ -206,11 +201,11 @@ TeamData* PlayerContainer::GetTeam(LWOOBJID playerID) {
} }
void PlayerContainer::AddMember(TeamData* team, LWOOBJID playerID) { void PlayerContainer::AddMember(TeamData* team, LWOOBJID playerID) {
if (team->memberIDs.size() >= 4) { if (team->memberIDs.size() >= 4){
LOG("Tried to add player to team that already had 4 players"); LOG("Tried to add player to team that already had 4 players");
const auto& player = GetPlayerData(playerID); auto* player = GetPlayerData(playerID);
if (!player) return; if (!player) return;
ChatPackets::SendSystemMessage(player.sysAddr, u"The teams is full! You have not been added to a team!"); ChatPackets::SendSystemMessage(player->sysAddr, u"The teams is full! You have not been added to a team!");
return; return;
} }
@@ -220,18 +215,18 @@ void PlayerContainer::AddMember(TeamData* team, LWOOBJID playerID) {
team->memberIDs.push_back(playerID); team->memberIDs.push_back(playerID);
const auto& leader = GetPlayerData(team->leaderID); auto* leader = GetPlayerData(team->leaderID);
const auto& member = GetPlayerData(playerID); auto* member = GetPlayerData(playerID);
if (!leader || !member) return; if (leader == nullptr || member == nullptr) return;
const auto leaderName = GeneralUtils::UTF8ToUTF16(leader.playerName); const auto leaderName = GeneralUtils::UTF8ToUTF16(leader->playerName);
const auto memberName = GeneralUtils::UTF8ToUTF16(member.playerName); const auto memberName = GeneralUtils::UTF8ToUTF16(member->playerName);
ChatPacketHandler::SendTeamInviteConfirm(member, false, leader.playerID, leader.zoneID, team->lootFlag, 0, 0, leaderName); ChatPacketHandler::SendTeamInviteConfirm(member, false, leader->playerID, leader->zoneID, team->lootFlag, 0, 0, leaderName);
if (!team->local) { if (!team->local) {
ChatPacketHandler::SendTeamSetLeader(member, leader.playerID); ChatPacketHandler::SendTeamSetLeader(member, leader->playerID);
} else { } else {
ChatPacketHandler::SendTeamSetLeader(member, LWOOBJID_EMPTY); ChatPacketHandler::SendTeamSetLeader(member, LWOOBJID_EMPTY);
} }
@@ -239,16 +234,16 @@ void PlayerContainer::AddMember(TeamData* team, LWOOBJID playerID) {
UpdateTeamsOnWorld(team, false); UpdateTeamsOnWorld(team, false);
for (const auto memberId : team->memberIDs) { for (const auto memberId : team->memberIDs) {
const auto& otherMember = GetPlayerData(memberId); auto* otherMember = GetPlayerData(memberId);
if (otherMember == member) continue; if (otherMember == member) continue;
const auto otherMemberName = GetName(memberId); const auto otherMemberName = GetName(memberId);
ChatPacketHandler::SendTeamAddPlayer(member, false, team->local, false, memberId, otherMemberName, otherMember ? otherMember.zoneID : LWOZONEID(0, 0, 0)); ChatPacketHandler::SendTeamAddPlayer(member, false, team->local, false, memberId, otherMemberName, otherMember != nullptr ? otherMember->zoneID : LWOZONEID(0, 0, 0));
if (otherMember) { if (otherMember != nullptr) {
ChatPacketHandler::SendTeamAddPlayer(otherMember, false, team->local, false, member.playerID, memberName, member.zoneID); ChatPacketHandler::SendTeamAddPlayer(otherMember, false, team->local, false, member->playerID, memberName, member->zoneID);
} }
} }
} }
@@ -258,9 +253,9 @@ void PlayerContainer::RemoveMember(TeamData* team, LWOOBJID playerID, bool disba
if (index == team->memberIDs.end()) return; if (index == team->memberIDs.end()) return;
const auto& member = GetPlayerData(playerID); auto* member = GetPlayerData(playerID);
if (member && !silent) { if (member != nullptr && !silent) {
ChatPacketHandler::SendTeamSetLeader(member, LWOOBJID_EMPTY); ChatPacketHandler::SendTeamSetLeader(member, LWOOBJID_EMPTY);
} }
@@ -271,9 +266,9 @@ void PlayerContainer::RemoveMember(TeamData* team, LWOOBJID playerID, bool disba
continue; continue;
} }
const auto& otherMember = GetPlayerData(memberId); auto* otherMember = GetPlayerData(memberId);
if (!otherMember) continue; if (otherMember == nullptr) continue;
ChatPacketHandler::SendTeamRemovePlayer(otherMember, disband, kicked, leaving, false, team->leaderID, playerID, memberName); ChatPacketHandler::SendTeamRemovePlayer(otherMember, disband, kicked, leaving, false, team->leaderID, playerID, memberName);
} }
@@ -295,9 +290,9 @@ void PlayerContainer::PromoteMember(TeamData* team, LWOOBJID newLeader) {
team->leaderID = newLeader; team->leaderID = newLeader;
for (const auto memberId : team->memberIDs) { for (const auto memberId : team->memberIDs) {
const auto& otherMember = GetPlayerData(memberId); auto* otherMember = GetPlayerData(memberId);
if (!otherMember) continue; if (otherMember == nullptr) continue;
ChatPacketHandler::SendTeamSetLeader(otherMember, newLeader); ChatPacketHandler::SendTeamSetLeader(otherMember, newLeader);
} }
@@ -309,14 +304,14 @@ void PlayerContainer::DisbandTeam(TeamData* team) {
if (index == mTeams.end()) return; if (index == mTeams.end()) return;
for (const auto memberId : team->memberIDs) { for (const auto memberId : team->memberIDs) {
const auto& otherMember = GetPlayerData(memberId); auto* otherMember = GetPlayerData(memberId);
if (!otherMember) continue; if (otherMember == nullptr) continue;
const auto memberName = GeneralUtils::UTF8ToUTF16(otherMember.playerName); const auto memberName = GeneralUtils::UTF8ToUTF16(otherMember->playerName);
ChatPacketHandler::SendTeamSetLeader(otherMember, LWOOBJID_EMPTY); ChatPacketHandler::SendTeamSetLeader(otherMember, LWOOBJID_EMPTY);
ChatPacketHandler::SendTeamRemovePlayer(otherMember, true, false, false, team->local, team->leaderID, otherMember.playerID, memberName); ChatPacketHandler::SendTeamRemovePlayer(otherMember, true, false, false, team->local, team->leaderID, otherMember->playerID, memberName);
} }
UpdateTeamsOnWorld(team, true); UpdateTeamsOnWorld(team, true);
@@ -331,19 +326,19 @@ void PlayerContainer::TeamStatusUpdate(TeamData* team) {
if (index == mTeams.end()) return; if (index == mTeams.end()) return;
const auto& leader = GetPlayerData(team->leaderID); auto* leader = GetPlayerData(team->leaderID);
if (!leader) return; if (leader == nullptr) return;
const auto leaderName = GeneralUtils::UTF8ToUTF16(leader.playerName); const auto leaderName = GeneralUtils::UTF8ToUTF16(leader->playerName);
for (const auto memberId : team->memberIDs) { for (const auto memberId : team->memberIDs) {
const auto& otherMember = GetPlayerData(memberId); auto* otherMember = GetPlayerData(memberId);
if (!otherMember) continue; if (otherMember == nullptr) continue;
if (!team->local) { if (!team->local) {
ChatPacketHandler::SendTeamStatus(otherMember, team->leaderID, leader.zoneID, team->lootFlag, 0, leaderName); ChatPacketHandler::SendTeamStatus(otherMember, team->leaderID, leader->zoneID, team->lootFlag, 0, leaderName);
} }
} }
@@ -365,46 +360,27 @@ void PlayerContainer::UpdateTeamsOnWorld(TeamData* team, bool deleteTeam) {
} }
} }
Game::server->Send(bitStream, UNASSIGNED_SYSTEM_ADDRESS, true); Game::server->Send(&bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);
} }
std::u16string PlayerContainer::GetName(LWOOBJID playerID) { std::u16string PlayerContainer::GetName(LWOOBJID playerID) {
const auto iter = m_Names.find(playerID); const auto& pair = m_Names.find(playerID);
if (iter == m_Names.end()) return u""; if (pair == m_Names.end()) return u"";
return iter->second; return pair->second;
} }
LWOOBJID PlayerContainer::GetId(const std::u16string& playerName) { LWOOBJID PlayerContainer::GetId(const std::u16string& playerName) {
LWOOBJID toReturn = LWOOBJID_EMPTY; for (const auto& pair : m_Names) {
if (pair.second == playerName) {
for (const auto& [id, name] : m_Names) { return pair.first;
if (name == playerName) {
toReturn = id;
break;
} }
} }
return toReturn; return LWOOBJID_EMPTY;
} }
PlayerData& PlayerContainer::GetPlayerDataMutable(const LWOOBJID& playerID) { bool PlayerContainer::GetIsMuted(PlayerData* data) {
return m_Players[playerID]; return data->muteExpire == 1 || data->muteExpire > time(NULL);
}
PlayerData& PlayerContainer::GetPlayerDataMutable(const std::string& playerName) {
for (auto& [id, player] : m_Players) {
if (!player) continue;
if (player.playerName == playerName) return player;
}
return m_Players[LWOOBJID_EMPTY];
}
const PlayerData& PlayerContainer::GetPlayerData(const LWOOBJID& playerID) {
return GetPlayerDataMutable(playerID);
}
const PlayerData& PlayerContainer::GetPlayerData(const std::string& playerName) {
return GetPlayerDataMutable(playerName);
} }

View File

@@ -7,10 +7,7 @@
#include "dServer.h" #include "dServer.h"
#include <unordered_map> #include <unordered_map>
enum class eGameMasterLevel : uint8_t;
struct IgnoreData { struct IgnoreData {
IgnoreData(const std::string& name, const LWOOBJID& id) : playerName{ name }, playerId{ id } {}
inline bool operator==(const std::string& other) const noexcept { inline bool operator==(const std::string& other) const noexcept {
return playerName == other; return playerName == other;
} }
@@ -19,33 +16,19 @@ struct IgnoreData {
return playerId == other; return playerId == other;
} }
LWOOBJID playerId = LWOOBJID_EMPTY; LWOOBJID playerId;
std::string playerName; std::string playerName;
}; };
struct PlayerData { struct PlayerData {
operator bool() const noexcept { LWOOBJID playerID;
return playerID != LWOOBJID_EMPTY;
}
bool operator==(const PlayerData& other) const noexcept {
return playerID == other.playerID;
}
bool GetIsMuted() const {
return muteExpire == 1 || muteExpire > time(NULL);
}
SystemAddress sysAddr{};
LWOZONEID zoneID{};
LWOOBJID playerID = LWOOBJID_EMPTY;
time_t muteExpire = 0;
uint8_t countOfBestFriends = 0;
std::string playerName; std::string playerName;
SystemAddress sysAddr;
LWOZONEID zoneID;
std::vector<FriendData> friends; std::vector<FriendData> friends;
std::vector<IgnoreData> ignoredPlayers; std::vector<IgnoreData> ignoredPlayers;
eGameMasterLevel gmLevel = static_cast<eGameMasterLevel>(0); // CIVILLIAN time_t muteExpire;
bool isFTP = false; uint8_t countOfBestFriends = 0;
}; };
struct TeamData { struct TeamData {
@@ -60,6 +43,8 @@ struct TeamData {
class PlayerContainer { class PlayerContainer {
public: public:
~PlayerContainer();
void Initialize(); void Initialize();
void InsertPlayer(Packet* packet); void InsertPlayer(Packet* packet);
void RemovePlayer(Packet* packet); void RemovePlayer(Packet* packet);
@@ -67,10 +52,22 @@ public:
void CreateTeamServer(Packet* packet); void CreateTeamServer(Packet* packet);
void BroadcastMuteUpdate(LWOOBJID player, time_t time); void BroadcastMuteUpdate(LWOOBJID player, time_t time);
const PlayerData& GetPlayerData(const LWOOBJID& playerID); PlayerData* GetPlayerData(const LWOOBJID& playerID) {
const PlayerData& GetPlayerData(const std::string& playerName); auto it = m_Players.find(playerID);
PlayerData& GetPlayerDataMutable(const LWOOBJID& playerID); if (it != m_Players.end()) return it->second;
PlayerData& GetPlayerDataMutable(const std::string& playerName); return nullptr;
}
PlayerData* GetPlayerData(const std::string& playerName) {
for (auto player : m_Players) {
if (player.second) {
std::string pn = player.second->playerName.c_str();
if (pn == playerName) return player.second;
}
}
return nullptr;
}
TeamData* CreateLocalTeam(std::vector<LWOOBJID> members); TeamData* CreateLocalTeam(std::vector<LWOOBJID> members);
TeamData* CreateTeam(LWOOBJID leader, bool local = false); TeamData* CreateTeam(LWOOBJID leader, bool local = false);
@@ -83,12 +80,15 @@ public:
void UpdateTeamsOnWorld(TeamData* team, bool deleteTeam); void UpdateTeamsOnWorld(TeamData* team, bool deleteTeam);
std::u16string GetName(LWOOBJID playerID); std::u16string GetName(LWOOBJID playerID);
LWOOBJID GetId(const std::u16string& playerName); LWOOBJID GetId(const std::u16string& playerName);
bool GetIsMuted(PlayerData* data);
uint32_t GetMaxNumberOfBestFriends() { return m_MaxNumberOfBestFriends; } uint32_t GetMaxNumberOfBestFriends() { return m_MaxNumberOfBestFriends; }
uint32_t GetMaxNumberOfFriends() { return m_MaxNumberOfFriends; } uint32_t GetMaxNumberOfFriends() { return m_MaxNumberOfFriends; }
std::map<LWOOBJID, PlayerData*>& GetAllPlayerData() { return m_Players; }
private: private:
LWOOBJID m_TeamIDCounter = 0; LWOOBJID m_TeamIDCounter = 0;
std::map<LWOOBJID, PlayerData> m_Players; std::map<LWOOBJID, PlayerData*> m_Players;
std::vector<TeamData*> mTeams; std::vector<TeamData*> mTeams;
std::unordered_map<LWOOBJID, std::u16string> m_Names; std::unordered_map<LWOOBJID, std::u16string> m_Names;
uint32_t m_MaxNumberOfBestFriends = 5; uint32_t m_MaxNumberOfBestFriends = 5;

View File

@@ -9,11 +9,12 @@
* AMF3 Deserializer written by EmosewaMC * AMF3 Deserializer written by EmosewaMC
*/ */
AMFBaseValue* AMFDeserialize::Read(RakNet::BitStream& inStream) { AMFBaseValue* AMFDeserialize::Read(RakNet::BitStream* inStream) {
if (!inStream) return nullptr;
AMFBaseValue* returnValue = nullptr; AMFBaseValue* returnValue = nullptr;
// Read in the value type from the bitStream // Read in the value type from the bitStream
eAmf marker; eAmf marker;
inStream.Read(marker); inStream->Read(marker);
// Based on the typing, create the value associated with that and return the base value class // Based on the typing, create the value associated with that and return the base value class
switch (marker) { switch (marker) {
case eAmf::Undefined: { case eAmf::Undefined: {
@@ -78,13 +79,13 @@ AMFBaseValue* AMFDeserialize::Read(RakNet::BitStream& inStream) {
return returnValue; return returnValue;
} }
uint32_t AMFDeserialize::ReadU29(RakNet::BitStream& inStream) { uint32_t AMFDeserialize::ReadU29(RakNet::BitStream* inStream) {
bool byteFlag = true; bool byteFlag = true;
uint32_t actualNumber{}; uint32_t actualNumber{};
uint8_t numberOfBytesRead{}; uint8_t numberOfBytesRead{};
while (byteFlag && numberOfBytesRead < 4) { while (byteFlag && numberOfBytesRead < 4) {
uint8_t byte{}; uint8_t byte{};
inStream.Read(byte); inStream->Read(byte);
// Parse the byte // Parse the byte
if (numberOfBytesRead < 3) { if (numberOfBytesRead < 3) {
byteFlag = byte & static_cast<uint8_t>(1 << 7); byteFlag = byte & static_cast<uint8_t>(1 << 7);
@@ -100,7 +101,7 @@ uint32_t AMFDeserialize::ReadU29(RakNet::BitStream& inStream) {
return actualNumber; return actualNumber;
} }
const std::string AMFDeserialize::ReadString(RakNet::BitStream& inStream) { const std::string AMFDeserialize::ReadString(RakNet::BitStream* inStream) {
auto length = ReadU29(inStream); auto length = ReadU29(inStream);
// Check if this is a reference // Check if this is a reference
bool isReference = length % 2 == 1; bool isReference = length % 2 == 1;
@@ -108,7 +109,7 @@ const std::string AMFDeserialize::ReadString(RakNet::BitStream& inStream) {
length = length >> 1; length = length >> 1;
if (isReference) { if (isReference) {
std::string value(length, 0); std::string value(length, 0);
inStream.Read(&value[0], length); inStream->Read(&value[0], length);
// Empty strings are never sent by reference // Empty strings are never sent by reference
if (!value.empty()) accessedElements.push_back(value); if (!value.empty()) accessedElements.push_back(value);
return value; return value;
@@ -118,20 +119,20 @@ const std::string AMFDeserialize::ReadString(RakNet::BitStream& inStream) {
} }
} }
AMFBaseValue* AMFDeserialize::ReadAmfDouble(RakNet::BitStream& inStream) { AMFBaseValue* AMFDeserialize::ReadAmfDouble(RakNet::BitStream* inStream) {
double value; double value;
inStream.Read<double>(value); inStream->Read<double>(value);
return new AMFDoubleValue(value); return new AMFDoubleValue(value);
} }
AMFBaseValue* AMFDeserialize::ReadAmfArray(RakNet::BitStream& inStream) { AMFBaseValue* AMFDeserialize::ReadAmfArray(RakNet::BitStream* inStream) {
auto arrayValue = new AMFArrayValue(); auto arrayValue = new AMFArrayValue();
// Read size of dense array // Read size of dense array
const auto sizeOfDenseArray = (ReadU29(inStream) >> 1); auto sizeOfDenseArray = (ReadU29(inStream) >> 1);
// Then read associative portion // Then read associative portion
while (true) { while (true) {
const auto key = ReadString(inStream); auto key = ReadString(inStream);
// No more associative values when we encounter an empty string key // No more associative values when we encounter an empty string key
if (key.size() == 0) break; if (key.size() == 0) break;
arrayValue->Insert(key, Read(inStream)); arrayValue->Insert(key, Read(inStream));
@@ -143,10 +144,10 @@ AMFBaseValue* AMFDeserialize::ReadAmfArray(RakNet::BitStream& inStream) {
return arrayValue; return arrayValue;
} }
AMFBaseValue* AMFDeserialize::ReadAmfString(RakNet::BitStream& inStream) { AMFBaseValue* AMFDeserialize::ReadAmfString(RakNet::BitStream* inStream) {
return new AMFStringValue(ReadString(inStream)); return new AMFStringValue(ReadString(inStream));
} }
AMFBaseValue* AMFDeserialize::ReadAmfInteger(RakNet::BitStream& inStream) { AMFBaseValue* AMFDeserialize::ReadAmfInteger(RakNet::BitStream* inStream) {
return new AMFIntValue(ReadU29(inStream)); return new AMFIntValue(ReadU29(inStream));
} }

View File

@@ -15,7 +15,7 @@ public:
* @param inStream inStream to read value from. * @param inStream inStream to read value from.
* @return Returns an AMFValue with all the information from the bitStream in it. * @return Returns an AMFValue with all the information from the bitStream in it.
*/ */
AMFBaseValue* Read(RakNet::BitStream& inStream); AMFBaseValue* Read(RakNet::BitStream* inStream);
private: private:
/** /**
* @brief Private method to read a U29 integer from a bitstream * @brief Private method to read a U29 integer from a bitstream
@@ -23,7 +23,7 @@ private:
* @param inStream bitstream to read data from * @param inStream bitstream to read data from
* @return The number as an unsigned 29 bit integer * @return The number as an unsigned 29 bit integer
*/ */
static uint32_t ReadU29(RakNet::BitStream& inStream); uint32_t ReadU29(RakNet::BitStream* inStream);
/** /**
* @brief Reads a string from a bitstream * @brief Reads a string from a bitstream
@@ -31,7 +31,7 @@ private:
* @param inStream bitStream to read data from * @param inStream bitStream to read data from
* @return The read string * @return The read string
*/ */
const std::string ReadString(RakNet::BitStream& inStream); const std::string ReadString(RakNet::BitStream* inStream);
/** /**
* @brief Read an AMFDouble value from a bitStream * @brief Read an AMFDouble value from a bitStream
@@ -39,7 +39,7 @@ private:
* @param inStream bitStream to read data from * @param inStream bitStream to read data from
* @return Double value represented as an AMFValue * @return Double value represented as an AMFValue
*/ */
AMFBaseValue* ReadAmfDouble(RakNet::BitStream& inStream); AMFBaseValue* ReadAmfDouble(RakNet::BitStream* inStream);
/** /**
* @brief Read an AMFArray from a bitStream * @brief Read an AMFArray from a bitStream
@@ -47,7 +47,7 @@ private:
* @param inStream bitStream to read data from * @param inStream bitStream to read data from
* @return Array value represented as an AMFValue * @return Array value represented as an AMFValue
*/ */
AMFBaseValue* ReadAmfArray(RakNet::BitStream& inStream); AMFBaseValue* ReadAmfArray(RakNet::BitStream* inStream);
/** /**
* @brief Read an AMFString from a bitStream * @brief Read an AMFString from a bitStream
@@ -55,7 +55,7 @@ private:
* @param inStream bitStream to read data from * @param inStream bitStream to read data from
* @return String value represented as an AMFValue * @return String value represented as an AMFValue
*/ */
AMFBaseValue* ReadAmfString(RakNet::BitStream& inStream); AMFBaseValue* ReadAmfString(RakNet::BitStream* inStream);
/** /**
* @brief Read an AMFInteger from a bitStream * @brief Read an AMFInteger from a bitStream
@@ -63,7 +63,7 @@ private:
* @param inStream bitStream to read data from * @param inStream bitStream to read data from
* @return Integer value represented as an AMFValue * @return Integer value represented as an AMFValue
*/ */
AMFBaseValue* ReadAmfInteger(RakNet::BitStream& inStream); AMFBaseValue* ReadAmfInteger(RakNet::BitStream* inStream);
/** /**
* List of strings read so far saved to be read by reference. * List of strings read so far saved to be read by reference.

View File

@@ -31,70 +31,54 @@ enum class eAmf : uint8_t {
class AMFBaseValue { class AMFBaseValue {
public: public:
[[nodiscard]] constexpr virtual eAmf GetValueType() const noexcept { return eAmf::Undefined; } virtual eAmf GetValueType() { return eAmf::Undefined; };
constexpr AMFBaseValue() noexcept = default; AMFBaseValue() {};
constexpr virtual ~AMFBaseValue() noexcept = default; virtual ~AMFBaseValue() {};
}; };
// AMFValue template class instantiations template<typename ValueType>
template <typename ValueType>
class AMFValue : public AMFBaseValue { class AMFValue : public AMFBaseValue {
public: public:
AMFValue() = default; AMFValue() {};
AMFValue(const ValueType value) : m_Data{ value } {} AMFValue(ValueType value) { SetValue(value); };
virtual ~AMFValue() override {};
virtual ~AMFValue() override = default; eAmf GetValueType() override { return eAmf::Undefined; };
[[nodiscard]] constexpr eAmf GetValueType() const noexcept override;
[[nodiscard]] const ValueType& GetValue() const { return m_Data; }
void SetValue(const ValueType value) { m_Data = value; }
const ValueType& GetValue() { return data; };
void SetValue(ValueType value) { data = value; };
protected: protected:
ValueType m_Data; ValueType data;
}; };
// Explicit template class instantiations
template class AMFValue<std::nullptr_t>;
template class AMFValue<bool>;
template class AMFValue<int32_t>;
template class AMFValue<uint32_t>;
template class AMFValue<std::string>;
template class AMFValue<double>;
// AMFValue template class member function instantiations
template <> [[nodiscard]] constexpr eAmf AMFValue<std::nullptr_t>::GetValueType() const noexcept { return eAmf::Null; }
template <> [[nodiscard]] constexpr eAmf AMFValue<bool>::GetValueType() const noexcept { return m_Data ? eAmf::True : eAmf::False; }
template <> [[nodiscard]] constexpr eAmf AMFValue<int32_t>::GetValueType() const noexcept { return eAmf::Integer; }
template <> [[nodiscard]] constexpr eAmf AMFValue<uint32_t>::GetValueType() const noexcept { return eAmf::Integer; }
template <> [[nodiscard]] constexpr eAmf AMFValue<std::string>::GetValueType() const noexcept { return eAmf::String; }
template <> [[nodiscard]] constexpr eAmf AMFValue<double>::GetValueType() const noexcept { return eAmf::Double; }
template <typename ValueType>
[[nodiscard]] constexpr eAmf AMFValue<ValueType>::GetValueType() const noexcept { return eAmf::Undefined; }
// As a string this is much easier to write and read from a BitStream. // As a string this is much easier to write and read from a BitStream.
template <> template<>
class AMFValue<const char*> : public AMFBaseValue { class AMFValue<const char*> : public AMFBaseValue {
public: public:
AMFValue() = default; AMFValue() {};
AMFValue(const char* value) { m_Data = value; } AMFValue(const char* value) { SetValue(std::string(value)); };
virtual ~AMFValue() override = default; virtual ~AMFValue() override {};
[[nodiscard]] constexpr eAmf GetValueType() const noexcept override { return eAmf::String; } eAmf GetValueType() override { return eAmf::String; };
[[nodiscard]] const std::string& GetValue() const { return m_Data; } const std::string& GetValue() { return data; };
void SetValue(const std::string& value) { m_Data = value; } void SetValue(std::string value) { data = value; };
protected: protected:
std::string m_Data; std::string data;
}; };
using AMFNullValue = AMFValue<std::nullptr_t>; typedef AMFValue<std::nullptr_t> AMFNullValue;
using AMFBoolValue = AMFValue<bool>; typedef AMFValue<bool> AMFBoolValue;
using AMFIntValue = AMFValue<int32_t>; typedef AMFValue<int32_t> AMFIntValue;
using AMFStringValue = AMFValue<std::string>; typedef AMFValue<std::string> AMFStringValue;
using AMFDoubleValue = AMFValue<double>; typedef AMFValue<double> AMFDoubleValue;
template<> inline eAmf AMFValue<std::nullptr_t>::GetValueType() { return eAmf::Null; };
template<> inline eAmf AMFValue<bool>::GetValueType() { return this->data ? eAmf::True : eAmf::False; };
template<> inline eAmf AMFValue<int32_t>::GetValueType() { return eAmf::Integer; };
template<> inline eAmf AMFValue<uint32_t>::GetValueType() { return eAmf::Integer; };
template<> inline eAmf AMFValue<std::string>::GetValueType() { return eAmf::String; };
template<> inline eAmf AMFValue<double>::GetValueType() { return eAmf::Double; };
/** /**
* The AMFArrayValue object holds 2 types of lists: * The AMFArrayValue object holds 2 types of lists:
@@ -105,14 +89,15 @@ using AMFDoubleValue = AMFValue<double>;
* and are not to be deleted by a caller. * and are not to be deleted by a caller.
*/ */
class AMFArrayValue : public AMFBaseValue { class AMFArrayValue : public AMFBaseValue {
using AMFAssociative = std::unordered_map<std::string, AMFBaseValue*>;
using AMFDense = std::vector<AMFBaseValue*>; typedef std::unordered_map<std::string, AMFBaseValue*> AMFAssociative;
typedef std::vector<AMFBaseValue*> AMFDense;
public: public:
[[nodiscard]] constexpr eAmf GetValueType() const noexcept override { return eAmf::Array; } eAmf GetValueType() override { return eAmf::Array; };
~AMFArrayValue() override { ~AMFArrayValue() override {
for (const auto* valueToDelete : GetDense()) { for (auto valueToDelete : GetDense()) {
if (valueToDelete) { if (valueToDelete) {
delete valueToDelete; delete valueToDelete;
valueToDelete = nullptr; valueToDelete = nullptr;
@@ -124,17 +109,17 @@ public:
valueToDelete.second = nullptr; valueToDelete.second = nullptr;
} }
} }
} };
/** /**
* Returns the Associative portion of the object * Returns the Associative portion of the object
*/ */
[[nodiscard]] inline const AMFAssociative& GetAssociative() const noexcept { return m_Associative; } inline AMFAssociative& GetAssociative() { return this->associative; };
/** /**
* Returns the dense portion of the object * Returns the dense portion of the object
*/ */
[[nodiscard]] inline const AMFDense& GetDense() const noexcept { return m_Dense; } inline AMFDense& GetDense() { return this->dense; };
/** /**
* Inserts an AMFValue into the associative portion with the given key. * Inserts an AMFValue into the associative portion with the given key.
@@ -150,48 +135,48 @@ public:
* @return The inserted element if the type matched, * @return The inserted element if the type matched,
* or nullptr if a key existed and was not the same type * or nullptr if a key existed and was not the same type
*/ */
template <typename ValueType> template<typename ValueType>
[[maybe_unused]] std::pair<AMFValue<ValueType>*, bool> Insert(const std::string& key, const ValueType value) { std::pair<AMFValue<ValueType>*, bool> Insert(const std::string& key, ValueType value) {
const auto element = m_Associative.find(key); auto element = associative.find(key);
AMFValue<ValueType>* val = nullptr; AMFValue<ValueType>* val = nullptr;
bool found = true; bool found = true;
if (element == m_Associative.cend()) { if (element == associative.end()) {
val = new AMFValue<ValueType>(value); val = new AMFValue<ValueType>(value);
m_Associative.emplace(key, val); associative.insert(std::make_pair(key, val));
} else { } else {
val = dynamic_cast<AMFValue<ValueType>*>(element->second); val = dynamic_cast<AMFValue<ValueType>*>(element->second);
found = false; found = false;
} }
return std::make_pair(val, found); return std::make_pair(val, found);
} };
// Associates an array with a string key // Associates an array with a string key
[[maybe_unused]] std::pair<AMFBaseValue*, bool> Insert(const std::string& key) { std::pair<AMFBaseValue*, bool> Insert(const std::string& key) {
const auto element = m_Associative.find(key); auto element = associative.find(key);
AMFArrayValue* val = nullptr; AMFArrayValue* val = nullptr;
bool found = true; bool found = true;
if (element == m_Associative.cend()) { if (element == associative.end()) {
val = new AMFArrayValue(); val = new AMFArrayValue();
m_Associative.emplace(key, val); associative.insert(std::make_pair(key, val));
} else { } else {
val = dynamic_cast<AMFArrayValue*>(element->second); val = dynamic_cast<AMFArrayValue*>(element->second);
found = false; found = false;
} }
return std::make_pair(val, found); return std::make_pair(val, found);
} };
// Associates an array with an integer key // Associates an array with an integer key
[[maybe_unused]] std::pair<AMFBaseValue*, bool> Insert(const size_t index) { std::pair<AMFBaseValue*, bool> Insert(const uint32_t& index) {
AMFArrayValue* val = nullptr; AMFArrayValue* val = nullptr;
bool inserted = false; bool inserted = false;
if (index >= m_Dense.size()) { if (index >= dense.size()) {
m_Dense.resize(index + 1); dense.resize(index + 1);
val = new AMFArrayValue(); val = new AMFArrayValue();
m_Dense.at(index) = val; dense.at(index) = val;
inserted = true; inserted = true;
} }
return std::make_pair(dynamic_cast<AMFArrayValue*>(m_Dense.at(index)), inserted); return std::make_pair(dynamic_cast<AMFArrayValue*>(dense.at(index)), inserted);
} };
/** /**
* @brief Inserts an AMFValue into the AMFArray key'd by index. * @brief Inserts an AMFValue into the AMFArray key'd by index.
@@ -203,18 +188,18 @@ public:
* @return The inserted element, or nullptr if the type did not match * @return The inserted element, or nullptr if the type did not match
* what was at the index. * what was at the index.
*/ */
template <typename ValueType> template<typename ValueType>
[[maybe_unused]] std::pair<AMFValue<ValueType>*, bool> Insert(const size_t index, const ValueType value) { std::pair<AMFValue<ValueType>*, bool> Insert(const uint32_t& index, ValueType value) {
AMFValue<ValueType>* val = nullptr; AMFValue<ValueType>* val = nullptr;
bool inserted = false; bool inserted = false;
if (index >= m_Dense.size()) { if (index >= this->dense.size()) {
m_Dense.resize(index + 1); this->dense.resize(index + 1);
val = new AMFValue<ValueType>(value); val = new AMFValue<ValueType>(value);
m_Dense.at(index) = val; this->dense.at(index) = val;
inserted = true; inserted = true;
} }
return std::make_pair(dynamic_cast<AMFValue<ValueType>*>(m_Dense.at(index)), inserted); return std::make_pair(dynamic_cast<AMFValue<ValueType>*>(this->dense.at(index)), inserted);
} };
/** /**
* Inserts an AMFValue into the associative portion with the given key. * Inserts an AMFValue into the associative portion with the given key.
@@ -225,15 +210,15 @@ public:
* @param key The key to associate with the value * @param key The key to associate with the value
* @param value The value to insert * @param value The value to insert
*/ */
void Insert(const std::string& key, AMFBaseValue* const value) { void Insert(const std::string& key, AMFBaseValue* value) {
const auto element = m_Associative.find(key); auto element = associative.find(key);
if (element != m_Associative.cend() && element->second) { if (element != associative.end() && element->second) {
delete element->second; delete element->second;
element->second = value; element->second = value;
} else { } else {
m_Associative.emplace(key, value); associative.insert(std::make_pair(key, value));
} }
} };
/** /**
* Inserts an AMFValue into the associative portion with the given index. * Inserts an AMFValue into the associative portion with the given index.
@@ -244,15 +229,15 @@ public:
* @param key The key to associate with the value * @param key The key to associate with the value
* @param value The value to insert * @param value The value to insert
*/ */
void Insert(const size_t index, AMFBaseValue* const value) { void Insert(const uint32_t index, AMFBaseValue* value) {
if (index < m_Dense.size()) { if (index < dense.size()) {
const AMFDense::const_iterator itr = m_Dense.cbegin() + index; AMFDense::iterator itr = dense.begin() + index;
if (*itr) delete m_Dense.at(index); if (*itr) delete dense.at(index);
} else { } else {
m_Dense.resize(index + 1); dense.resize(index + 1);
} }
m_Dense.at(index) = value; dense.at(index) = value;
} };
/** /**
* Pushes an AMFValue into the back of the dense portion. * Pushes an AMFValue into the back of the dense portion.
@@ -264,10 +249,10 @@ public:
* *
* @return The inserted pointer, or nullptr should the key already be in use. * @return The inserted pointer, or nullptr should the key already be in use.
*/ */
template <typename ValueType> template<typename ValueType>
[[maybe_unused]] inline AMFValue<ValueType>* Push(const ValueType value) { inline AMFValue<ValueType>* Push(ValueType value) {
return Insert(m_Dense.size(), value).first; return Insert(this->dense.size(), value).first;
} };
/** /**
* Removes the key from the associative portion * Removes the key from the associative portion
@@ -276,49 +261,52 @@ public:
* *
* @param key The key to remove from the associative portion * @param key The key to remove from the associative portion
*/ */
void Remove(const std::string& key, const bool deleteValue = true) { void Remove(const std::string& key, bool deleteValue = true) {
const AMFAssociative::const_iterator it = m_Associative.find(key); AMFAssociative::iterator it = this->associative.find(key);
if (it != m_Associative.cend()) { if (it != this->associative.end()) {
if (deleteValue) delete it->second; if (deleteValue) delete it->second;
m_Associative.erase(it); this->associative.erase(it);
} }
} }
/** /**
* Pops the last element in the dense portion, deleting it in the process. * Pops the last element in the dense portion, deleting it in the process.
*/ */
void Remove(const size_t index) { void Remove(const uint32_t index) {
if (!m_Dense.empty() && index < m_Dense.size()) { if (!this->dense.empty() && index < this->dense.size()) {
const auto itr = m_Dense.cbegin() + index; auto itr = this->dense.begin() + index;
if (*itr) delete (*itr); if (*itr) delete (*itr);
m_Dense.erase(itr); this->dense.erase(itr);
} }
} }
void Pop() { void Pop() {
if (!m_Dense.empty()) Remove(m_Dense.size() - 1); if (!this->dense.empty()) Remove(this->dense.size() - 1);
} }
[[nodiscard]] AMFArrayValue* GetArray(const std::string& key) const { AMFArrayValue* GetArray(const std::string& key) {
const AMFAssociative::const_iterator it = m_Associative.find(key); AMFAssociative::const_iterator it = this->associative.find(key);
return it != m_Associative.cend() ? dynamic_cast<AMFArrayValue*>(it->second) : nullptr; if (it != this->associative.end()) {
} return dynamic_cast<AMFArrayValue*>(it->second);
}
return nullptr;
};
[[nodiscard]] AMFArrayValue* GetArray(const size_t index) const { AMFArrayValue* GetArray(const uint32_t index) {
return index < m_Dense.size() ? dynamic_cast<AMFArrayValue*>(m_Dense.at(index)) : nullptr; return index >= this->dense.size() ? nullptr : dynamic_cast<AMFArrayValue*>(this->dense.at(index));
} };
[[maybe_unused]] inline AMFArrayValue* InsertArray(const std::string& key) { inline AMFArrayValue* InsertArray(const std::string& key) {
return static_cast<AMFArrayValue*>(Insert(key).first); return static_cast<AMFArrayValue*>(Insert(key).first);
} };
[[maybe_unused]] inline AMFArrayValue* InsertArray(const size_t index) { inline AMFArrayValue* InsertArray(const uint32_t index) {
return static_cast<AMFArrayValue*>(Insert(index).first); return static_cast<AMFArrayValue*>(Insert(index).first);
} };
[[maybe_unused]] inline AMFArrayValue* PushArray() { inline AMFArrayValue* PushArray() {
return static_cast<AMFArrayValue*>(Insert(m_Dense.size()).first); return static_cast<AMFArrayValue*>(Insert(this->dense.size()).first);
} };
/** /**
* Gets an AMFValue by the key from the associative portion and converts it * Gets an AMFValue by the key from the associative portion and converts it
@@ -330,18 +318,18 @@ public:
* @return The AMFValue * @return The AMFValue
*/ */
template <typename AmfType> template <typename AmfType>
[[nodiscard]] AMFValue<AmfType>* Get(const std::string& key) const { AMFValue<AmfType>* Get(const std::string& key) const {
const AMFAssociative::const_iterator it = m_Associative.find(key); AMFAssociative::const_iterator it = this->associative.find(key);
return it != m_Associative.cend() ? return it != this->associative.end() ?
dynamic_cast<AMFValue<AmfType>*>(it->second) : dynamic_cast<AMFValue<AmfType>*>(it->second) :
nullptr; nullptr;
} };
// Get from the array but dont cast it // Get from the array but dont cast it
[[nodiscard]] AMFBaseValue* Get(const std::string& key) const { AMFBaseValue* Get(const std::string& key) const {
const AMFAssociative::const_iterator it = m_Associative.find(key); AMFAssociative::const_iterator it = this->associative.find(key);
return it != m_Associative.cend() ? it->second : nullptr; return it != this->associative.end() ? it->second : nullptr;
} };
/** /**
* @brief Get an AMFValue object at a position in the dense portion. * @brief Get an AMFValue object at a position in the dense portion.
@@ -353,28 +341,27 @@ public:
* @return The casted object, or nullptr. * @return The casted object, or nullptr.
*/ */
template <typename AmfType> template <typename AmfType>
[[nodiscard]] AMFValue<AmfType>* Get(const size_t index) const { AMFValue<AmfType>* Get(uint32_t index) const {
return index < m_Dense.size() ? return index < this->dense.size() ?
dynamic_cast<AMFValue<AmfType>*>(m_Dense.at(index)) : dynamic_cast<AMFValue<AmfType>*>(this->dense.at(index)) :
nullptr; nullptr;
} };
// Get from the dense but dont cast it // Get from the dense but dont cast it
[[nodiscard]] AMFBaseValue* Get(const size_t index) const { AMFBaseValue* Get(const uint32_t index) const {
return index < m_Dense.size() ? m_Dense.at(index) : nullptr; return index < this->dense.size() ? this->dense.at(index) : nullptr;
} };
private: private:
/** /**
* The associative portion. These values are key'd with strings to an AMFValue. * The associative portion. These values are key'd with strings to an AMFValue.
*/ */
AMFAssociative m_Associative; AMFAssociative associative;
/** /**
* The dense portion. These AMFValue's are stored one after * The dense portion. These AMFValue's are stored one after
* another with the most recent addition being at the back. * another with the most recent addition being at the back.
*/ */
AMFDense m_Dense; AMFDense dense;
}; };
#endif //!__AMF3__H__ #endif //!__AMF3__H__

View File

@@ -53,7 +53,7 @@ void RakNet::BitStream::Write<AMFBaseValue&>(AMFBaseValue& value) {
* A private function to write an value to a RakNet::BitStream * A private function to write an value to a RakNet::BitStream
* RakNet writes in the correct byte order - do not reverse this. * RakNet writes in the correct byte order - do not reverse this.
*/ */
void WriteUInt29(RakNet::BitStream& bs, uint32_t v) { void WriteUInt29(RakNet::BitStream* bs, uint32_t v) {
unsigned char b4 = static_cast<unsigned char>(v); unsigned char b4 = static_cast<unsigned char>(v);
if (v < 0x00200000) { if (v < 0x00200000) {
b4 = b4 & 0x7F; b4 = b4 & 0x7F;
@@ -65,10 +65,10 @@ void WriteUInt29(RakNet::BitStream& bs, uint32_t v) {
unsigned char b2; unsigned char b2;
v = v >> 7; v = v >> 7;
b2 = static_cast<unsigned char>(v) | 0x80; b2 = static_cast<unsigned char>(v) | 0x80;
bs.Write(b2); bs->Write(b2);
} }
bs.Write(b3); bs->Write(b3);
} }
} else { } else {
unsigned char b1; unsigned char b1;
@@ -82,19 +82,19 @@ void WriteUInt29(RakNet::BitStream& bs, uint32_t v) {
v = v >> 7; v = v >> 7;
b1 = static_cast<unsigned char>(v) | 0x80; b1 = static_cast<unsigned char>(v) | 0x80;
bs.Write(b1); bs->Write(b1);
bs.Write(b2); bs->Write(b2);
bs.Write(b3); bs->Write(b3);
} }
bs.Write(b4); bs->Write(b4);
} }
/** /**
* Writes a flag number to a RakNet::BitStream * Writes a flag number to a RakNet::BitStream
* RakNet writes in the correct byte order - do not reverse this. * RakNet writes in the correct byte order - do not reverse this.
*/ */
void WriteFlagNumber(RakNet::BitStream& bs, uint32_t v) { void WriteFlagNumber(RakNet::BitStream* bs, uint32_t v) {
v = (v << 1) | 0x01; v = (v << 1) | 0x01;
WriteUInt29(bs, v); WriteUInt29(bs, v);
} }
@@ -104,9 +104,9 @@ void WriteFlagNumber(RakNet::BitStream& bs, uint32_t v) {
* *
* RakNet writes in the correct byte order - do not reverse this. * RakNet writes in the correct byte order - do not reverse this.
*/ */
void WriteAMFString(RakNet::BitStream& bs, const std::string& str) { void WriteAMFString(RakNet::BitStream* bs, const std::string& str) {
WriteFlagNumber(bs, static_cast<uint32_t>(str.size())); WriteFlagNumber(bs, static_cast<uint32_t>(str.size()));
bs.Write(str.c_str(), static_cast<uint32_t>(str.size())); bs->Write(str.c_str(), static_cast<uint32_t>(str.size()));
} }
/** /**
@@ -114,8 +114,8 @@ void WriteAMFString(RakNet::BitStream& bs, const std::string& str) {
* *
* RakNet writes in the correct byte order - do not reverse this. * RakNet writes in the correct byte order - do not reverse this.
*/ */
void WriteAMFU16(RakNet::BitStream& bs, uint16_t value) { void WriteAMFU16(RakNet::BitStream* bs, uint16_t value) {
bs.Write(value); bs->Write(value);
} }
/** /**
@@ -123,8 +123,8 @@ void WriteAMFU16(RakNet::BitStream& bs, uint16_t value) {
* *
* RakNet writes in the correct byte order - do not reverse this. * RakNet writes in the correct byte order - do not reverse this.
*/ */
void WriteAMFU32(RakNet::BitStream& bs, uint32_t value) { void WriteAMFU32(RakNet::BitStream* bs, uint32_t value) {
bs.Write(value); bs->Write(value);
} }
/** /**
@@ -132,40 +132,40 @@ void WriteAMFU32(RakNet::BitStream& bs, uint32_t value) {
* *
* RakNet writes in the correct byte order - do not reverse this. * RakNet writes in the correct byte order - do not reverse this.
*/ */
void WriteAMFU64(RakNet::BitStream& bs, uint64_t value) { void WriteAMFU64(RakNet::BitStream* bs, uint64_t value) {
bs.Write(value); bs->Write(value);
} }
// Writes an AMFIntegerValue to BitStream // Writes an AMFIntegerValue to BitStream
template<> template<>
void RakNet::BitStream::Write<AMFIntValue&>(AMFIntValue& value) { void RakNet::BitStream::Write<AMFIntValue&>(AMFIntValue& value) {
WriteUInt29(*this, value.GetValue()); WriteUInt29(this, value.GetValue());
} }
// Writes an AMFDoubleValue to BitStream // Writes an AMFDoubleValue to BitStream
template<> template<>
void RakNet::BitStream::Write<AMFDoubleValue&>(AMFDoubleValue& value) { void RakNet::BitStream::Write<AMFDoubleValue&>(AMFDoubleValue& value) {
double d = value.GetValue(); double d = value.GetValue();
WriteAMFU64(*this, *reinterpret_cast<uint64_t*>(&d)); WriteAMFU64(this, *reinterpret_cast<uint64_t*>(&d));
} }
// Writes an AMFStringValue to BitStream // Writes an AMFStringValue to BitStream
template<> template<>
void RakNet::BitStream::Write<AMFStringValue&>(AMFStringValue& value) { void RakNet::BitStream::Write<AMFStringValue&>(AMFStringValue& value) {
WriteAMFString(*this, value.GetValue()); WriteAMFString(this, value.GetValue());
} }
// Writes an AMFArrayValue to BitStream // Writes an AMFArrayValue to BitStream
template<> template<>
void RakNet::BitStream::Write<AMFArrayValue&>(AMFArrayValue& value) { void RakNet::BitStream::Write<AMFArrayValue&>(AMFArrayValue& value) {
uint32_t denseSize = value.GetDense().size(); uint32_t denseSize = value.GetDense().size();
WriteFlagNumber(*this, denseSize); WriteFlagNumber(this, denseSize);
auto it = value.GetAssociative().begin(); auto it = value.GetAssociative().begin();
auto end = value.GetAssociative().end(); auto end = value.GetAssociative().end();
while (it != end) { while (it != end) {
WriteAMFString(*this, it->first); WriteAMFString(this, it->first);
this->Write<AMFBaseValue&>(*it->second); this->Write<AMFBaseValue&>(*it->second);
it++; it++;
} }

View File

@@ -4,7 +4,7 @@
#include "Amf3.h" #include "Amf3.h"
// RakNet // RakNet
#include "BitStream.h" #include <BitStream.h>
/*! /*!
\file AmfSerialize.h \file AmfSerialize.h

View File

@@ -8,9 +8,11 @@ set(DCOMMON_SOURCES
"Game.cpp" "Game.cpp"
"GeneralUtils.cpp" "GeneralUtils.cpp"
"LDFFormat.cpp" "LDFFormat.cpp"
"MD5.cpp"
"Metrics.cpp" "Metrics.cpp"
"NiPoint3.cpp" "NiPoint3.cpp"
"NiQuaternion.cpp" "NiQuaternion.cpp"
"SHA512.cpp"
"Demangler.cpp" "Demangler.cpp"
"ZCompression.cpp" "ZCompression.cpp"
"BrickByBrickFix.cpp" "BrickByBrickFix.cpp"
@@ -18,27 +20,17 @@ set(DCOMMON_SOURCES
"FdbToSqlite.cpp" "FdbToSqlite.cpp"
) )
# Workaround for compiler bug where the optimized code could result in a memcpy of 0 bytes, even though that isnt possible.
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97185
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set_source_files_properties("FdbToSqlite.cpp" PROPERTIES COMPILE_FLAGS "-Wno-stringop-overflow")
endif()
add_subdirectory(dClient) add_subdirectory(dClient)
foreach(file ${DCOMMON_DCLIENT_SOURCES}) foreach(file ${DCOMMON_DCLIENT_SOURCES})
set(DCOMMON_SOURCES ${DCOMMON_SOURCES} "dClient/${file}") set(DCOMMON_SOURCES ${DCOMMON_SOURCES} "dClient/${file}")
endforeach() endforeach()
include_directories(${PROJECT_SOURCE_DIR}/dCommon/)
add_library(dCommon STATIC ${DCOMMON_SOURCES}) add_library(dCommon STATIC ${DCOMMON_SOURCES})
target_include_directories(dCommon
PUBLIC "." "dClient" "dEnums" target_link_libraries(dCommon bcrypt dDatabase tinyxml2)
PRIVATE
"${PROJECT_SOURCE_DIR}/dDatabase/GameDatabase"
"${PROJECT_SOURCE_DIR}/dDatabase/GameDatabase/ITables"
"${PROJECT_SOURCE_DIR}/dDatabase/CDClientDatabase"
"${PROJECT_SOURCE_DIR}/thirdparty/mariadb-connector-cpp/include"
)
if (UNIX) if (UNIX)
find_package(ZLIB REQUIRED) find_package(ZLIB REQUIRED)
@@ -69,6 +61,4 @@ else ()
) )
endif () endif ()
target_link_libraries(dCommon target_link_libraries(dCommon ZLIB::ZLIB)
PRIVATE ZLIB::ZLIB bcrypt tinyxml2
INTERFACE dDatabase)

View File

@@ -121,6 +121,7 @@ void CatchUnhandled(int sig) {
} catch(const std::exception& e) { } catch(const std::exception& e) {
LOG("Caught exception: '%s'", e.what()); LOG("Caught exception: '%s'", e.what());
} }
Game::logger->Flush();
#ifndef INCLUDE_BACKTRACE #ifndef INCLUDE_BACKTRACE
@@ -186,7 +187,7 @@ void CatchUnhandled(int sig) {
Bt(state); Bt(state);
#endif // INCLUDE_BACKTRACE #endif // INCLUDE_BACKTRACE
Game::logger->Flush();
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }

View File

@@ -278,14 +278,14 @@ std::vector<std::string> GeneralUtils::SplitString(const std::string& str, char
return vector; return vector;
} }
std::u16string GeneralUtils::ReadWString(RakNet::BitStream& inStream) { std::u16string GeneralUtils::ReadWString(RakNet::BitStream* inStream) {
uint32_t length; uint32_t length;
inStream.Read<uint32_t>(length); inStream->Read<uint32_t>(length);
std::u16string string; std::u16string string;
for (auto i = 0; i < length; i++) { for (auto i = 0; i < length; i++) {
uint16_t c; uint16_t c;
inStream.Read(c); inStream->Read(c);
string.push_back(c); string.push_back(c);
} }
@@ -294,50 +294,32 @@ std::u16string GeneralUtils::ReadWString(RakNet::BitStream& inStream) {
std::vector<std::string> GeneralUtils::GetSqlFileNamesFromFolder(const std::string& folder) { std::vector<std::string> GeneralUtils::GetSqlFileNamesFromFolder(const std::string& folder) {
// Because we dont know how large the initial number before the first _ is we need to make it a map like so. // Because we dont know how large the initial number before the first _ is we need to make it a map like so.
std::map<uint32_t, std::string> filenames{}; std::map<uint32_t, std::string> filenames{};
for (auto& t : std::filesystem::directory_iterator(folder)) { for (auto& t : std::filesystem::directory_iterator(folder)) {
auto filename = t.path().filename().string(); auto filename = t.path().filename().string();
auto index = std::stoi(GeneralUtils::SplitString(filename, '_').at(0)); auto index = std::stoi(GeneralUtils::SplitString(filename, '_').at(0));
filenames.insert(std::make_pair(index, filename)); filenames.insert(std::make_pair(index, filename));
} }
// Now sort the map by the oldest migration. // Now sort the map by the oldest migration.
std::vector<std::string> sortedFiles{}; std::vector<std::string> sortedFiles{};
auto fileIterator = filenames.begin(); auto fileIterator = filenames.begin();
std::map<uint32_t, std::string>::iterator oldest = filenames.begin(); std::map<uint32_t, std::string>::iterator oldest = filenames.begin();
while (!filenames.empty()) { while (!filenames.empty()) {
if (fileIterator == filenames.end()) { if (fileIterator == filenames.end()) {
sortedFiles.push_back(oldest->second); sortedFiles.push_back(oldest->second);
filenames.erase(oldest); filenames.erase(oldest);
fileIterator = filenames.begin(); fileIterator = filenames.begin();
oldest = filenames.begin(); oldest = filenames.begin();
continue; continue;
} }
if (oldest->first > fileIterator->first) oldest = fileIterator; if (oldest->first > fileIterator->first) oldest = fileIterator;
fileIterator++; fileIterator++;
} }
return sortedFiles; return sortedFiles;
} }
#ifdef DARKFLAME_PLATFORM_MACOS bool GeneralUtils::TryParse(const std::string& x, const std::string& y, const std::string& z, NiPoint3& dst) {
return TryParse<float>(x.c_str(), dst.x) && TryParse<float>(y.c_str(), dst.y) && TryParse<float>(z.c_str(), dst.z);
// MacOS floating-point parse function specializations
namespace GeneralUtils::details {
template <>
[[nodiscard]] float _parse<float>(const std::string_view str, size_t& parseNum) {
return std::stof(std::string{ str }, &parseNum);
}
template <>
[[nodiscard]] double _parse<double>(const std::string_view str, size_t& parseNum) {
return std::stod(std::string{ str }, &parseNum);
}
template <>
[[nodiscard]] long double _parse<long double>(const std::string_view str, size_t& parseNum) {
return std::stold(std::string{ str }, &parseNum);
}
} }
#endif

View File

@@ -1,20 +1,17 @@
#pragma once #pragma once
// C++ // C++
#include <charconv> #include <stdint.h>
#include <cstdint>
#include <random> #include <random>
#include <ctime> #include <time.h>
#include <string> #include <string>
#include <string_view> #include <type_traits>
#include <optional>
#include <functional> #include <functional>
#include <type_traits> #include <type_traits>
#include <stdexcept> #include <stdexcept>
#include "BitStream.h" #include <BitStream.h>
#include "NiPoint3.h" #include "NiPoint3.h"
#include "dPlatforms.h"
#include "Game.h" #include "Game.h"
#include "Logger.h" #include "Logger.h"
@@ -116,7 +113,7 @@ namespace GeneralUtils {
bool ReplaceInString(std::string& str, const std::string& from, const std::string& to); bool ReplaceInString(std::string& str, const std::string& from, const std::string& to);
std::u16string ReadWString(RakNet::BitStream& inStream); std::u16string ReadWString(RakNet::BitStream* inStream);
std::vector<std::wstring> SplitString(std::wstring& str, wchar_t delimiter); std::vector<std::wstring> SplitString(std::wstring& str, wchar_t delimiter);
@@ -126,111 +123,90 @@ namespace GeneralUtils {
std::vector<std::string> GetSqlFileNamesFromFolder(const std::string& folder); std::vector<std::string> GetSqlFileNamesFromFolder(const std::string& folder);
// Concept constraining to enum types
template <typename T> template <typename T>
concept Enum = std::is_enum_v<T>; T Parse(const char* value);
// Concept constraining to numeric types template <>
template <typename T> inline bool Parse(const char* value) {
concept Numeric = std::integral<T> || Enum<T> || std::floating_point<T>; return std::stoi(value);
// Concept trickery to enable parsing underlying numeric types
template <Numeric T>
struct numeric_parse { using type = T; };
// If an enum, present an alias to its underlying type for parsing
template <Numeric T> requires Enum<T>
struct numeric_parse<T> { using type = std::underlying_type_t<T>; };
// If a boolean, present an alias to an intermediate integral type for parsing
template <Numeric T> requires std::same_as<T, bool>
struct numeric_parse<T> { using type = uint32_t; };
// Shorthand type alias
template <Numeric T>
using numeric_parse_t = numeric_parse<T>::type;
/**
* For numeric values: Parses a string_view and returns an optional variable depending on the result.
* @param str The string_view to be evaluated
* @returns An std::optional containing the desired value if it is equivalent to the string
*/
template <Numeric T>
[[nodiscard]] std::optional<T> TryParse(const std::string_view str) {
numeric_parse_t<T> result;
const char* const strEnd = str.data() + str.size();
const auto [parseEnd, ec] = std::from_chars(str.data(), strEnd, result);
const bool isParsed = parseEnd == strEnd && ec == std::errc{};
return isParsed ? static_cast<T>(result) : std::optional<T>{};
} }
#ifdef DARKFLAME_PLATFORM_MACOS template <>
inline int32_t Parse(const char* value) {
// MacOS floating-point parse helper function specializations return std::stoi(value);
namespace details {
template <std::floating_point T>
[[nodiscard]] T _parse(const std::string_view str, size_t& parseNum);
} }
/** template <>
* For floating-point values: Parses a string_view and returns an optional variable depending on the result. inline int64_t Parse(const char* value) {
* Note that this function overload is only included for MacOS, as from_chars will fulfill its purpose otherwise. return std::stoll(value);
* @param str The string_view to be evaluated
* @returns An std::optional containing the desired value if it is equivalent to the string
*/
template <std::floating_point T>
[[nodiscard]] std::optional<T> TryParse(const std::string_view str) noexcept
try {
size_t parseNum;
const T result = details::_parse<T>(str, parseNum);
const bool isParsed = str.length() == parseNum;
return isParsed ? result : std::optional<T>{};
} catch (...) {
return std::nullopt;
} }
#endif template <>
inline float Parse(const char* value) {
/** return std::stof(value);
* The TryParse overload for handling NiPoint3 by passing 3 seperate string references
* @param strX The string representing the X coordinate
* @param strY The string representing the Y coordinate
* @param strZ The string representing the Z coordinate
* @returns An std::optional containing the desired NiPoint3 if it can be constructed from the string parameters
*/
template <typename T>
[[nodiscard]] std::optional<NiPoint3> TryParse(const std::string& strX, const std::string& strY, const std::string& strZ) {
const auto x = TryParse<float>(strX);
if (!x) return std::nullopt;
const auto y = TryParse<float>(strY);
if (!y) return std::nullopt;
const auto z = TryParse<float>(strZ);
return z ? std::make_optional<NiPoint3>(x.value(), y.value(), z.value()) : std::nullopt;
} }
/** template <>
* The TryParse overload for handling NiPoint3 by passingn a reference to a vector of three strings inline double Parse(const char* value) {
* @param str The string vector representing the X, Y, and Xcoordinates return std::stod(value);
* @returns An std::optional containing the desired NiPoint3 if it can be constructed from the string parameters }
*/
template <typename T> template <>
[[nodiscard]] std::optional<NiPoint3> TryParse(const std::vector<std::string>& str) { inline uint16_t Parse(const char* value) {
return (str.size() == 3) ? TryParse<NiPoint3>(str[0], str[1], str[2]) : std::nullopt; return std::stoul(value);
}
template <>
inline uint32_t Parse(const char* value) {
return std::stoul(value);
}
template <>
inline uint64_t Parse(const char* value) {
return std::stoull(value);
}
template <>
inline eInventoryType Parse(const char* value) {
return static_cast<eInventoryType>(std::stoul(value));
}
template <>
inline eReplicaComponentType Parse(const char* value) {
return static_cast<eReplicaComponentType>(std::stoul(value));
} }
template <typename T> template <typename T>
bool TryParse(const char* value, T& dst) {
try {
dst = Parse<T>(value);
return true;
} catch (...) {
return false;
}
}
template <typename T>
T Parse(const std::string& value) {
return Parse<T>(value.c_str());
}
template <typename T>
bool TryParse(const std::string& value, T& dst) {
return TryParse<T>(value.c_str(), dst);
}
bool TryParse(const std::string& x, const std::string& y, const std::string& z, NiPoint3& dst);
template<typename T>
std::u16string to_u16string(T value) { std::u16string to_u16string(T value) {
return GeneralUtils::ASCIIToUTF16(std::to_string(value)); return GeneralUtils::ASCIIToUTF16(std::to_string(value));
} }
// From boost::hash_combine // From boost::hash_combine
template <class T> template <class T>
constexpr void hash_combine(std::size_t& s, const T& v) { void hash_combine(std::size_t& s, const T& v) {
std::hash<T> h; std::hash<T> h;
s ^= h(v) + 0x9e3779b9 + (s << 6) + (s >> 2); s ^= h(v) + 0x9e3779b9 + (s << 6) + (s >> 2);
} }
@@ -263,8 +239,10 @@ namespace GeneralUtils {
* @param entry Enum entry to cast * @param entry Enum entry to cast
* @returns The enum entry's value in its underlying type * @returns The enum entry's value in its underlying type
*/ */
template <Enum eType> template <typename eType>
constexpr typename std::underlying_type_t<eType> CastUnderlyingType(const eType entry) noexcept { inline constexpr typename std::underlying_type_t<eType> CastUnderlyingType(const eType entry) {
static_assert(std::is_enum_v<eType>, "Not an enum");
return static_cast<typename std::underlying_type_t<eType>>(entry); return static_cast<typename std::underlying_type_t<eType>>(entry);
} }

View File

@@ -61,33 +61,33 @@ LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
} }
case LDF_TYPE_S32: { case LDF_TYPE_S32: {
const auto data = GeneralUtils::TryParse<int32_t>(ldfTypeAndValue.second); int32_t data;
if (!data) { if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
LOG("Warning: Attempted to process invalid int32 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data()); LOG("Warning: Attempted to process invalid int32 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr; return nullptr;
} }
returnValue = new LDFData<int32_t>(key, data.value()); returnValue = new LDFData<int32_t>(key, data);
break; break;
} }
case LDF_TYPE_FLOAT: { case LDF_TYPE_FLOAT: {
const auto data = GeneralUtils::TryParse<float>(ldfTypeAndValue.second); float data;
if (!data) { if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
LOG("Warning: Attempted to process invalid float value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data()); LOG("Warning: Attempted to process invalid float value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr; return nullptr;
} }
returnValue = new LDFData<float>(key, data.value()); returnValue = new LDFData<float>(key, data);
break; break;
} }
case LDF_TYPE_DOUBLE: { case LDF_TYPE_DOUBLE: {
const auto data = GeneralUtils::TryParse<double>(ldfTypeAndValue.second); double data;
if (!data) { if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
LOG("Warning: Attempted to process invalid double value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data()); LOG("Warning: Attempted to process invalid double value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr; return nullptr;
} }
returnValue = new LDFData<double>(key, data.value()); returnValue = new LDFData<double>(key, data);
break; break;
} }
@@ -100,12 +100,10 @@ LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
} else if (ldfTypeAndValue.second == "false") { } else if (ldfTypeAndValue.second == "false") {
data = 0; data = 0;
} else { } else {
const auto dataOptional = GeneralUtils::TryParse<uint32_t>(ldfTypeAndValue.second); if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
if (!dataOptional) {
LOG("Warning: Attempted to process invalid uint32 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data()); LOG("Warning: Attempted to process invalid uint32 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr; return nullptr;
} }
data = dataOptional.value();
} }
returnValue = new LDFData<uint32_t>(key, data); returnValue = new LDFData<uint32_t>(key, data);
@@ -120,12 +118,10 @@ LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
} else if (ldfTypeAndValue.second == "false") { } else if (ldfTypeAndValue.second == "false") {
data = false; data = false;
} else { } else {
const auto dataOptional = GeneralUtils::TryParse<bool>(ldfTypeAndValue.second); if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
if (!dataOptional) {
LOG("Warning: Attempted to process invalid bool value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data()); LOG("Warning: Attempted to process invalid bool value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr; return nullptr;
} }
data = dataOptional.value();
} }
returnValue = new LDFData<bool>(key, data); returnValue = new LDFData<bool>(key, data);
@@ -133,22 +129,22 @@ LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
} }
case LDF_TYPE_U64: { case LDF_TYPE_U64: {
const auto data = GeneralUtils::TryParse<uint64_t>(ldfTypeAndValue.second); uint64_t data;
if (!data) { if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
LOG("Warning: Attempted to process invalid uint64 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data()); LOG("Warning: Attempted to process invalid uint64 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr; return nullptr;
} }
returnValue = new LDFData<uint64_t>(key, data.value()); returnValue = new LDFData<uint64_t>(key, data);
break; break;
} }
case LDF_TYPE_OBJID: { case LDF_TYPE_OBJID: {
const auto data = GeneralUtils::TryParse<LWOOBJID>(ldfTypeAndValue.second); LWOOBJID data;
if (!data) { if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
LOG("Warning: Attempted to process invalid LWOOBJID value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data()); LOG("Warning: Attempted to process invalid LWOOBJID value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr; return nullptr;
} }
returnValue = new LDFData<LWOOBJID>(key, data.value()); returnValue = new LDFData<LWOOBJID>(key, data);
break; break;
} }

View File

@@ -31,7 +31,7 @@ public:
virtual ~LDFBaseData() {} virtual ~LDFBaseData() {}
virtual void WriteToPacket(RakNet::BitStream& packet) = 0; virtual void WriteToPacket(RakNet::BitStream* packet) = 0;
virtual const std::u16string& GetKey() = 0; virtual const std::u16string& GetKey() = 0;
@@ -62,17 +62,17 @@ private:
T value; T value;
//! Writes the key to the packet //! Writes the key to the packet
void WriteKey(RakNet::BitStream& packet) { void WriteKey(RakNet::BitStream* packet) {
packet.Write<uint8_t>(this->key.length() * sizeof(uint16_t)); packet->Write<uint8_t>(this->key.length() * sizeof(uint16_t));
for (uint32_t i = 0; i < this->key.length(); ++i) { for (uint32_t i = 0; i < this->key.length(); ++i) {
packet.Write<uint16_t>(this->key[i]); packet->Write<uint16_t>(this->key[i]);
} }
} }
//! Writes the value to the packet //! Writes the value to the packet
void WriteValue(RakNet::BitStream& packet) { void WriteValue(RakNet::BitStream* packet) {
packet.Write<uint8_t>(this->GetValueType()); packet->Write<uint8_t>(this->GetValueType());
packet.Write(this->value); packet->Write(this->value);
} }
public: public:
@@ -108,7 +108,7 @@ public:
/*! /*!
\param packet The packet \param packet The packet
*/ */
void WriteToPacket(RakNet::BitStream& packet) override { void WriteToPacket(RakNet::BitStream* packet) override {
this->WriteKey(packet); this->WriteKey(packet);
this->WriteValue(packet); this->WriteValue(packet);
} }
@@ -162,7 +162,7 @@ public:
return new LDFData<T>(key, value); return new LDFData<T>(key, value);
} }
inline static const T Default = {}; inline static T Default = {};
}; };
// LDF Types // LDF Types
@@ -178,31 +178,31 @@ template<> inline eLDFType LDFData<std::string>::GetValueType(void) { return LDF
// The specialized version for std::u16string (UTF-16) // The specialized version for std::u16string (UTF-16)
template<> template<>
inline void LDFData<std::u16string>::WriteValue(RakNet::BitStream& packet) { inline void LDFData<std::u16string>::WriteValue(RakNet::BitStream* packet) {
packet.Write<uint8_t>(this->GetValueType()); packet->Write<uint8_t>(this->GetValueType());
packet.Write<uint32_t>(this->value.length()); packet->Write<uint32_t>(this->value.length());
for (uint32_t i = 0; i < this->value.length(); ++i) { for (uint32_t i = 0; i < this->value.length(); ++i) {
packet.Write<uint16_t>(this->value[i]); packet->Write<uint16_t>(this->value[i]);
} }
} }
// The specialized version for bool // The specialized version for bool
template<> template<>
inline void LDFData<bool>::WriteValue(RakNet::BitStream& packet) { inline void LDFData<bool>::WriteValue(RakNet::BitStream* packet) {
packet.Write<uint8_t>(this->GetValueType()); packet->Write<uint8_t>(this->GetValueType());
packet.Write<uint8_t>(this->value); packet->Write<uint8_t>(this->value);
} }
// The specialized version for std::string (UTF-8) // The specialized version for std::string (UTF-8)
template<> template<>
inline void LDFData<std::string>::WriteValue(RakNet::BitStream& packet) { inline void LDFData<std::string>::WriteValue(RakNet::BitStream* packet) {
packet.Write<uint8_t>(this->GetValueType()); packet->Write<uint8_t>(this->GetValueType());
packet.Write<uint32_t>(this->value.length()); packet->Write<uint32_t>(this->value.length());
for (uint32_t i = 0; i < this->value.length(); ++i) { for (uint32_t i = 0; i < this->value.length(); ++i) {
packet.Write<uint8_t>(this->value[i]); packet->Write<uint8_t>(this->value[i]);
} }
} }

View File

@@ -16,7 +16,7 @@ Writer::~Writer() {
} }
void Writer::Log(const char* time, const char* message) { void Writer::Log(const char* time, const char* message) {
if (!m_Outfile || !m_Enabled) return; if (!m_Outfile) return;
fputs(time, m_Outfile); fputs(time, m_Outfile);
fputs(message, m_Outfile); fputs(message, m_Outfile);

View File

@@ -1,24 +1,210 @@
#include "NiPoint3.h" #include "NiPoint3.h"
#include "NiQuaternion.h"
// C++ // C++
#include <cmath> #include <cmath>
// MARK: Member Functions // Static Variables
const NiPoint3 NiPoint3::ZERO(0.0f, 0.0f, 0.0f);
const NiPoint3 NiPoint3::UNIT_X(1.0f, 0.0f, 0.0f);
const NiPoint3 NiPoint3::UNIT_Y(0.0f, 1.0f, 0.0f);
const NiPoint3 NiPoint3::UNIT_Z(0.0f, 0.0f, 1.0f);
const NiPoint3 NiPoint3::UNIT_ALL(1.0f, 1.0f, 1.0f);
//! Initializer
NiPoint3::NiPoint3(void) {
this->x = 0;
this->y = 0;
this->z = 0;
}
//! Initializer
NiPoint3::NiPoint3(float x, float y, float z) {
this->x = x;
this->y = y;
this->z = z;
}
//! Copy Constructor
NiPoint3::NiPoint3(const NiPoint3& point) {
this->x = point.x;
this->y = point.y;
this->z = point.z;
}
//! Destructor
NiPoint3::~NiPoint3(void) {}
// MARK: Getters / Setters
//! Gets the X coordinate
float NiPoint3::GetX(void) const {
return this->x;
}
//! Sets the X coordinate
void NiPoint3::SetX(float x) {
this->x = x;
}
//! Gets the Y coordinate
float NiPoint3::GetY(void) const {
return this->y;
}
//! Sets the Y coordinate
void NiPoint3::SetY(float y) {
this->y = y;
}
//! Gets the Z coordinate
float NiPoint3::GetZ(void) const {
return this->z;
}
//! Sets the Z coordinate
void NiPoint3::SetZ(float z) {
this->z = z;
}
// MARK: Functions
//! Gets the length of the vector //! Gets the length of the vector
float NiPoint3::Length() const { float NiPoint3::Length(void) const {
return std::sqrt(x * x + y * y + z * z); return sqrt(x * x + y * y + z * z);
}
//! Gets the squared length of a vector
float NiPoint3::SquaredLength(void) const {
return (x * x + y * y + z * z);
}
//! Returns the dot product of the vector dotted with another vector
float NiPoint3::DotProduct(const Vector3& vec) const {
return ((this->x * vec.x) + (this->y * vec.y) + (this->z * vec.z));
}
//! Returns the cross product of the vector crossed with another vector
Vector3 NiPoint3::CrossProduct(const Vector3& vec) const {
return Vector3(((this->y * vec.z) - (this->z * vec.y)),
((this->z * vec.x) - (this->x * vec.z)),
((this->x * vec.y) - (this->y * vec.x)));
} }
//! Unitize the vector //! Unitize the vector
NiPoint3 NiPoint3::Unitize() const { NiPoint3 NiPoint3::Unitize(void) const {
float length = this->Length(); float length = this->Length();
return length != 0 ? *this / length : NiPoint3Constant::ZERO; return length != 0 ? *this / length : NiPoint3::ZERO;
} }
// MARK: Operators
//! Operator to check for equality
bool NiPoint3::operator==(const NiPoint3& point) const {
return point.x == this->x && point.y == this->y && point.z == this->z;
}
//! Operator to check for inequality
bool NiPoint3::operator!=(const NiPoint3& point) const {
return !(*this == point);
}
//! Operator for subscripting
float& NiPoint3::operator[](int i) {
float* base = &x;
return base[i];
}
//! Operator for subscripting
const float& NiPoint3::operator[](int i) const {
const float* base = &x;
return base[i];
}
//! Operator for addition of vectors
NiPoint3 NiPoint3::operator+(const NiPoint3& point) const {
return NiPoint3(this->x + point.x, this->y + point.y, this->z + point.z);
}
//! Operator for addition of vectors
NiPoint3& NiPoint3::operator+=(const NiPoint3& point) {
this->x += point.x;
this->y += point.y;
this->z += point.z;
return *this;
}
NiPoint3& NiPoint3::operator*=(const float scalar) {
this->x *= scalar;
this->y *= scalar;
this->z *= scalar;
return *this;
}
//! Operator for subtraction of vectors
NiPoint3 NiPoint3::operator-(const NiPoint3& point) const {
return NiPoint3(this->x - point.x, this->y - point.y, this->z - point.z);
}
//! Operator for addition of a scalar on all vector components
NiPoint3 NiPoint3::operator+(float fScalar) const {
return NiPoint3(this->x + fScalar, this->y + fScalar, this->z + fScalar);
}
//! Operator for subtraction of a scalar on all vector components
NiPoint3 NiPoint3::operator-(float fScalar) const {
return NiPoint3(this->x - fScalar, this->y - fScalar, this->z - fScalar);
}
//! Operator for scalar multiplication of a vector
NiPoint3 NiPoint3::operator*(float fScalar) const {
return NiPoint3(this->x * fScalar, this->y * fScalar, this->z * fScalar);
}
//! Operator for scalar division of a vector
NiPoint3 NiPoint3::operator/(float fScalar) const {
float retX = this->x != 0 ? this->x / fScalar : 0;
float retY = this->y != 0 ? this->y / fScalar : 0;
float retZ = this->z != 0 ? this->z / fScalar : 0;
return NiPoint3(retX, retY, retZ);
}
// MARK: Helper Functions // MARK: Helper Functions
//! Checks to see if the point (or vector) is with an Axis-Aligned Bounding Box
bool NiPoint3::IsWithinAxisAlignedBox(const NiPoint3& minPoint, const NiPoint3& maxPoint) {
if (this->x < minPoint.x) return false;
if (this->x > maxPoint.x) return false;
if (this->y < minPoint.y) return false;
if (this->y > maxPoint.y) return false;
return (this->z < maxPoint.z && this->z > minPoint.z);
}
//! Checks to see if the point (or vector) is within a sphere
bool NiPoint3::IsWithinSpehere(const NiPoint3& sphereCenter, float radius) {
Vector3 diffVec = Vector3(x - sphereCenter.GetX(), y - sphereCenter.GetY(), z - sphereCenter.GetZ());
return (diffVec.SquaredLength() <= (radius * radius));
}
NiPoint3 NiPoint3::ClosestPointOnLine(const NiPoint3& a, const NiPoint3& b, const NiPoint3& p) {
if (a == b) return a;
const auto pa = p - a;
const auto ab = b - a;
const auto t = pa.DotProduct(ab) / ab.SquaredLength();
if (t <= 0.0f) return a;
if (t >= 1.0f) return b;
return a + ab * t;
}
float NiPoint3::Angle(const NiPoint3& a, const NiPoint3& b) { float NiPoint3::Angle(const NiPoint3& a, const NiPoint3& b) {
const auto dot = a.DotProduct(b); const auto dot = a.DotProduct(b);
const auto lenA = a.SquaredLength(); const auto lenA = a.SquaredLength();
@@ -34,7 +220,15 @@ float NiPoint3::Distance(const NiPoint3& a, const NiPoint3& b) {
return std::sqrt(dx * dx + dy * dy + dz * dz); return std::sqrt(dx * dx + dy * dy + dz * dz);
} }
NiPoint3 NiPoint3::MoveTowards(const NiPoint3& current, const NiPoint3& target, const float maxDistanceDelta) { float NiPoint3::DistanceSquared(const NiPoint3& a, const NiPoint3& b) {
const auto dx = a.x - b.x;
const auto dy = a.y - b.y;
const auto dz = a.z - b.z;
return dx * dx + dy * dy + dz * dz;
}
NiPoint3 NiPoint3::MoveTowards(const NiPoint3& current, const NiPoint3& target, float maxDistanceDelta) {
float dx = target.x - current.x; float dx = target.x - current.x;
float dy = target.y - current.y; float dy = target.y - current.y;
float dz = target.z - current.z; float dz = target.z - current.z;
@@ -55,3 +249,29 @@ NiPoint3 NiPoint3::MoveTowards(const NiPoint3& current, const NiPoint3& target,
float length = std::sqrt(lengthSquared); float length = std::sqrt(lengthSquared);
return NiPoint3(current.x + dx / length * maxDistanceDelta, current.y + dy / length * maxDistanceDelta, current.z + dz / length * maxDistanceDelta); return NiPoint3(current.x + dx / length * maxDistanceDelta, current.y + dy / length * maxDistanceDelta, current.z + dz / length * maxDistanceDelta);
} }
//This code is yoinked from the MS XNA code, so it should be right, even if it's horrible.
NiPoint3 NiPoint3::RotateByQuaternion(const NiQuaternion& rotation) {
Vector3 vector;
float num12 = rotation.x + rotation.x;
float num2 = rotation.y + rotation.y;
float num = rotation.z + rotation.z;
float num11 = rotation.w * num12;
float num10 = rotation.w * num2;
float num9 = rotation.w * num;
float num8 = rotation.x * num12;
float num7 = rotation.x * num2;
float num6 = rotation.x * num;
float num5 = rotation.y * num2;
float num4 = rotation.y * num;
float num3 = rotation.z * num;
NiPoint3 value = *this;
float num15 = ((value.x * ((1.0f - num5) - num3)) + (value.y * (num7 - num9))) + (value.z * (num6 + num10));
float num14 = ((value.x * (num7 + num9)) + (value.y * ((1.0f - num8) - num3))) + (value.z * (num4 - num11));
float num13 = ((value.x * (num6 - num10)) + (value.y * (num4 + num11))) + (value.z * ((1.0f - num8) - num5));
vector.x = num15;
vector.y = num14;
vector.z = num13;
return vector;
}

View File

@@ -1,5 +1,4 @@
#ifndef __NIPOINT3_H__ #pragma once
#define __NIPOINT3_H__
/*! /*!
\file NiPoint3.hpp \file NiPoint3.hpp
@@ -13,13 +12,13 @@ typedef NiPoint3 Vector3; //!< The Vector3 class is technically the NiPoin
//! A custom class the defines a point in space //! A custom class the defines a point in space
class NiPoint3 { class NiPoint3 {
public: public:
float x{ 0 }; //!< The x position float x; //!< The x position
float y{ 0 }; //!< The y position float y; //!< The y position
float z{ 0 }; //!< The z position float z; //!< The z position
//! Initializer //! Initializer
constexpr NiPoint3() = default; NiPoint3(void);
//! Initializer //! Initializer
/*! /*!
@@ -27,21 +26,23 @@ public:
\param y The y coordinate \param y The y coordinate
\param z The z coordinate \param z The z coordinate
*/ */
constexpr NiPoint3(const float x, const float y, const float z) noexcept NiPoint3(float x, float y, float z);
: x{ x }
, y{ y }
, z{ z } {
}
//! Copy Constructor //! Copy Constructor
/*! /*!
\param point The point to copy \param point The point to copy
*/ */
constexpr NiPoint3(const NiPoint3& point) noexcept NiPoint3(const NiPoint3& point);
: x{ point.x }
, y{ point.y } //! Destructor
, z{ point.z } { ~NiPoint3(void);
}
// MARK: Constants
static const NiPoint3 ZERO; //!< Point(0, 0, 0)
static const NiPoint3 UNIT_X; //!< Point(1, 0, 0)
static const NiPoint3 UNIT_Y; //!< Point(0, 1, 0)
static const NiPoint3 UNIT_Z; //!< Point(0, 0, 1)
static const NiPoint3 UNIT_ALL; //!< Point(1, 1, 1)
// MARK: Getters / Setters // MARK: Getters / Setters
@@ -49,37 +50,38 @@ public:
/*! /*!
\return The x coordinate \return The x coordinate
*/ */
[[nodiscard]] constexpr float GetX() const noexcept; float GetX(void) const;
//! Sets the X coordinate //! Sets the X coordinate
/*! /*!
\param x The x coordinate \param x The x coordinate
*/ */
constexpr void SetX(const float x) noexcept; void SetX(float x);
//! Gets the Y coordinate //! Gets the Y coordinate
/*! /*!
\return The y coordinate \return The y coordinate
*/ */
[[nodiscard]] constexpr float GetY() const noexcept; float GetY(void) const;
//! Sets the Y coordinate //! Sets the Y coordinate
/*! /*!
\param y The y coordinate \param y The y coordinate
*/ */
constexpr void SetY(const float y) noexcept; void SetY(float y);
//! Gets the Z coordinate //! Gets the Z coordinate
/*! /*!
\return The z coordinate \return The z coordinate
*/ */
[[nodiscard]] constexpr float GetZ() const noexcept; float GetZ(void) const;
//! Sets the Z coordinate //! Sets the Z coordinate
/*! /*!
\param z The z coordinate \param z The z coordinate
*/ */
constexpr void SetZ(const float z) noexcept; void SetZ(float z);
// MARK: Member Functions // MARK: Member Functions
@@ -87,70 +89,72 @@ public:
/*! /*!
\return The scalar length of the vector \return The scalar length of the vector
*/ */
[[nodiscard]] float Length() const; float Length(void) const;
//! Gets the squared length of a vector //! Gets the squared length of a vector
/*! /*!
\return The squared length of a vector \return The squared length of a vector
*/ */
[[nodiscard]] constexpr float SquaredLength() const noexcept; float SquaredLength(void) const;
//! Returns the dot product of the vector dotted with another vector //! Returns the dot product of the vector dotted with another vector
/*! /*!
\param vec The second vector \param vec The second vector
\return The dot product of the two vectors \return The dot product of the two vectors
*/ */
[[nodiscard]] constexpr float DotProduct(const Vector3& vec) const noexcept; float DotProduct(const Vector3& vec) const;
//! Returns the cross product of the vector crossed with another vector //! Returns the cross product of the vector crossed with another vector
/*! /*!
\param vec The second vector \param vec The second vector
\return The cross product of the two vectors \return The cross product of the two vectors
*/ */
[[nodiscard]] constexpr Vector3 CrossProduct(const Vector3& vec) const noexcept; Vector3 CrossProduct(const Vector3& vec) const;
//! Unitize the vector //! Unitize the vector
/*! /*!
\returns The current vector \returns The current vector
*/ */
[[nodiscard]] NiPoint3 Unitize() const; NiPoint3 Unitize(void) const;
// MARK: Operators // MARK: Operators
//! Operator to check for equality //! Operator to check for equality
constexpr bool operator==(const NiPoint3& point) const noexcept; bool operator==(const NiPoint3& point) const;
//! Operator to check for inequality //! Operator to check for inequality
constexpr bool operator!=(const NiPoint3& point) const noexcept; bool operator!=(const NiPoint3& point) const;
//! Operator for subscripting //! Operator for subscripting
constexpr float& operator[](const int i) noexcept; float& operator[](int i);
//! Operator for subscripting //! Operator for subscripting
constexpr const float& operator[](const int i) const noexcept; const float& operator[](int i) const;
//! Operator for addition of vectors //! Operator for addition of vectors
constexpr NiPoint3 operator+(const NiPoint3& point) const noexcept; NiPoint3 operator+(const NiPoint3& point) const;
//! Operator for addition of vectors //! Operator for addition of vectors
constexpr NiPoint3& operator+=(const NiPoint3& point) noexcept; NiPoint3& operator+=(const NiPoint3& point);
constexpr NiPoint3& operator*=(const float scalar) noexcept; NiPoint3& operator*=(const float scalar);
//! Operator for subtraction of vectors //! Operator for subtraction of vectors
constexpr NiPoint3 operator-(const NiPoint3& point) const noexcept; NiPoint3 operator-(const NiPoint3& point) const;
//! Operator for addition of a scalar on all vector components //! Operator for addition of a scalar on all vector components
constexpr NiPoint3 operator+(const float fScalar) const noexcept; NiPoint3 operator+(float fScalar) const;
//! Operator for subtraction of a scalar on all vector components //! Operator for subtraction of a scalar on all vector components
constexpr NiPoint3 operator-(const float fScalar) const noexcept; NiPoint3 operator-(float fScalar) const;
//! Operator for scalar multiplication of a vector //! Operator for scalar multiplication of a vector
constexpr NiPoint3 operator*(const float fScalar) const noexcept; NiPoint3 operator*(float fScalar) const;
//! Operator for scalar division of a vector //! Operator for scalar division of a vector
constexpr NiPoint3 operator/(const float fScalar) const noexcept; NiPoint3 operator/(float fScalar) const;
// MARK: Helper Functions // MARK: Helper Functions
@@ -160,14 +164,14 @@ public:
\param maxPoint The maximum point of the bounding box \param maxPoint The maximum point of the bounding box
\return Whether or not this point lies within the box \return Whether or not this point lies within the box
*/ */
[[nodiscard]] constexpr bool IsWithinAxisAlignedBox(const NiPoint3& minPoint, const NiPoint3& maxPoint) noexcept; bool IsWithinAxisAlignedBox(const NiPoint3& minPoint, const NiPoint3& maxPoint);
//! Checks to see if the point (or vector) is within a sphere //! Checks to see if the point (or vector) is within a sphere
/*! /*!
\param sphereCenter The sphere center \param sphereCenter The sphere center
\param radius The radius \param radius The radius
*/ */
[[nodiscard]] constexpr bool IsWithinSphere(const NiPoint3& sphereCenter, const float radius) noexcept; bool IsWithinSpehere(const NiPoint3& sphereCenter, float radius);
/*! /*!
\param a Start of line \param a Start of line
@@ -175,30 +179,15 @@ public:
\param p Refrence point \param p Refrence point
\return The point of line AB which is closest to P \return The point of line AB which is closest to P
*/ */
[[nodiscard]] static constexpr NiPoint3 ClosestPointOnLine(const NiPoint3& a, const NiPoint3& b, const NiPoint3& p) noexcept; static NiPoint3 ClosestPointOnLine(const NiPoint3& a, const NiPoint3& b, const NiPoint3& p);
[[nodiscard]] static float Angle(const NiPoint3& a, const NiPoint3& b); static float Angle(const NiPoint3& a, const NiPoint3& b);
[[nodiscard]] static float Distance(const NiPoint3& a, const NiPoint3& b); static float Distance(const NiPoint3& a, const NiPoint3& b);
[[nodiscard]] static constexpr float DistanceSquared(const NiPoint3& a, const NiPoint3& b) noexcept; static float DistanceSquared(const NiPoint3& a, const NiPoint3& b);
[[nodiscard]] static NiPoint3 MoveTowards(const NiPoint3& current, const NiPoint3& target, const float maxDistanceDelta); static NiPoint3 MoveTowards(const NiPoint3& current, const NiPoint3& target, float maxDistanceDelta);
//This code is yoinked from the MS XNA code, so it should be right, even if it's horrible. NiPoint3 RotateByQuaternion(const NiQuaternion& rotation);
[[nodiscard]] constexpr NiPoint3 RotateByQuaternion(const NiQuaternion& rotation) noexcept;
}; };
// Static Variables
namespace NiPoint3Constant {
constexpr NiPoint3 ZERO(0.0f, 0.0f, 0.0f);
constexpr NiPoint3 UNIT_X(1.0f, 0.0f, 0.0f);
constexpr NiPoint3 UNIT_Y(0.0f, 1.0f, 0.0f);
constexpr NiPoint3 UNIT_Z(0.0f, 0.0f, 1.0f);
constexpr NiPoint3 UNIT_ALL(1.0f, 1.0f, 1.0f);
}
// .inl file needed for code organization and to circumvent circular dependency issues
#include "NiPoint3.inl"
#endif // !__NIPOINT3_H__

View File

@@ -1,196 +0,0 @@
#pragma once
#ifndef __NIPOINT3_H__
#error "This should only be included inline in NiPoint3.h: Do not include directly!"
#endif
#include "NiQuaternion.h"
// MARK: Getters / Setters
//! Gets the X coordinate
constexpr float NiPoint3::GetX() const noexcept {
return this->x;
}
//! Sets the X coordinate
constexpr void NiPoint3::SetX(const float x) noexcept {
this->x = x;
}
//! Gets the Y coordinate
constexpr float NiPoint3::GetY() const noexcept {
return this->y;
}
//! Sets the Y coordinate
constexpr void NiPoint3::SetY(const float y) noexcept {
this->y = y;
}
//! Gets the Z coordinate
constexpr float NiPoint3::GetZ() const noexcept {
return this->z;
}
//! Sets the Z coordinate
constexpr void NiPoint3::SetZ(const float z) noexcept {
this->z = z;
}
// MARK: Member Functions
//! Gets the squared length of a vector
constexpr float NiPoint3::SquaredLength() const noexcept {
return (x * x + y * y + z * z);
}
//! Returns the dot product of the vector dotted with another vector
constexpr float NiPoint3::DotProduct(const Vector3& vec) const noexcept {
return ((this->x * vec.x) + (this->y * vec.y) + (this->z * vec.z));
}
//! Returns the cross product of the vector crossed with another vector
constexpr Vector3 NiPoint3::CrossProduct(const Vector3& vec) const noexcept {
return Vector3(((this->y * vec.z) - (this->z * vec.y)),
((this->z * vec.x) - (this->x * vec.z)),
((this->x * vec.y) - (this->y * vec.x)));
}
// MARK: Operators
//! Operator to check for equality
constexpr bool NiPoint3::operator==(const NiPoint3& point) const noexcept {
return point.x == this->x && point.y == this->y && point.z == this->z;
}
//! Operator to check for inequality
constexpr bool NiPoint3::operator!=(const NiPoint3& point) const noexcept {
return !(*this == point);
}
//! Operator for subscripting
constexpr float& NiPoint3::operator[](const int i) noexcept {
float* base = &x;
return base[i];
}
//! Operator for subscripting
constexpr const float& NiPoint3::operator[](const int i) const noexcept {
const float* base = &x;
return base[i];
}
//! Operator for addition of vectors
constexpr NiPoint3 NiPoint3::operator+(const NiPoint3& point) const noexcept {
return NiPoint3(this->x + point.x, this->y + point.y, this->z + point.z);
}
//! Operator for addition of vectors
constexpr NiPoint3& NiPoint3::operator+=(const NiPoint3& point) noexcept {
this->x += point.x;
this->y += point.y;
this->z += point.z;
return *this;
}
constexpr NiPoint3& NiPoint3::operator*=(const float scalar) noexcept {
this->x *= scalar;
this->y *= scalar;
this->z *= scalar;
return *this;
}
//! Operator for subtraction of vectors
constexpr NiPoint3 NiPoint3::operator-(const NiPoint3& point) const noexcept {
return NiPoint3(this->x - point.x, this->y - point.y, this->z - point.z);
}
//! Operator for addition of a scalar on all vector components
constexpr NiPoint3 NiPoint3::operator+(const float fScalar) const noexcept {
return NiPoint3(this->x + fScalar, this->y + fScalar, this->z + fScalar);
}
//! Operator for subtraction of a scalar on all vector components
constexpr NiPoint3 NiPoint3::operator-(const float fScalar) const noexcept {
return NiPoint3(this->x - fScalar, this->y - fScalar, this->z - fScalar);
}
//! Operator for scalar multiplication of a vector
constexpr NiPoint3 NiPoint3::operator*(const float fScalar) const noexcept {
return NiPoint3(this->x * fScalar, this->y * fScalar, this->z * fScalar);
}
//! Operator for scalar division of a vector
constexpr NiPoint3 NiPoint3::operator/(const float fScalar) const noexcept {
float retX = this->x != 0 ? this->x / fScalar : 0;
float retY = this->y != 0 ? this->y / fScalar : 0;
float retZ = this->z != 0 ? this->z / fScalar : 0;
return NiPoint3(retX, retY, retZ);
}
// MARK: Helper Functions
//! Checks to see if the point (or vector) is with an Axis-Aligned Bounding Box
constexpr bool NiPoint3::IsWithinAxisAlignedBox(const NiPoint3& minPoint, const NiPoint3& maxPoint) noexcept {
if (this->x < minPoint.x) return false;
if (this->x > maxPoint.x) return false;
if (this->y < minPoint.y) return false;
if (this->y > maxPoint.y) return false;
return (this->z < maxPoint.z && this->z > minPoint.z);
}
//! Checks to see if the point (or vector) is within a sphere
constexpr bool NiPoint3::IsWithinSphere(const NiPoint3& sphereCenter, const float radius) noexcept {
Vector3 diffVec = Vector3(x - sphereCenter.GetX(), y - sphereCenter.GetY(), z - sphereCenter.GetZ());
return (diffVec.SquaredLength() <= (radius * radius));
}
constexpr NiPoint3 NiPoint3::ClosestPointOnLine(const NiPoint3& a, const NiPoint3& b, const NiPoint3& p) noexcept {
if (a == b) return a;
const auto pa = p - a;
const auto ab = b - a;
const auto t = pa.DotProduct(ab) / ab.SquaredLength();
if (t <= 0.0f) return a;
if (t >= 1.0f) return b;
return a + ab * t;
}
constexpr float NiPoint3::DistanceSquared(const NiPoint3& a, const NiPoint3& b) noexcept {
const auto dx = a.x - b.x;
const auto dy = a.y - b.y;
const auto dz = a.z - b.z;
return dx * dx + dy * dy + dz * dz;
}
//This code is yoinked from the MS XNA code, so it should be right, even if it's horrible.
constexpr NiPoint3 NiPoint3::RotateByQuaternion(const NiQuaternion& rotation) noexcept {
Vector3 vector;
float num12 = rotation.x + rotation.x;
float num2 = rotation.y + rotation.y;
float num = rotation.z + rotation.z;
float num11 = rotation.w * num12;
float num10 = rotation.w * num2;
float num9 = rotation.w * num;
float num8 = rotation.x * num12;
float num7 = rotation.x * num2;
float num6 = rotation.x * num;
float num5 = rotation.y * num2;
float num4 = rotation.y * num;
float num3 = rotation.z * num;
NiPoint3 value = *this;
float num15 = ((value.x * ((1.0f - num5) - num3)) + (value.y * (num7 - num9))) + (value.z * (num6 + num10));
float num14 = ((value.x * (num7 + num9)) + (value.y * ((1.0f - num8) - num3))) + (value.z * (num4 - num11));
float num13 = ((value.x * (num6 - num10)) + (value.y * (num4 + num11))) + (value.z * ((1.0f - num8) - num5));
vector.x = num15;
vector.y = num14;
vector.z = num13;
return vector;
}

View File

@@ -3,8 +3,89 @@
// C++ // C++
#include <cmath> #include <cmath>
// Static Variables
const NiQuaternion NiQuaternion::IDENTITY(1, 0, 0, 0);
//! The initializer
NiQuaternion::NiQuaternion(void) {
this->w = 1;
this->x = 0;
this->y = 0;
this->z = 0;
}
//! The initializer
NiQuaternion::NiQuaternion(float w, float x, float y, float z) {
this->w = w;
this->x = x;
this->y = y;
this->z = z;
}
//! Destructor
NiQuaternion::~NiQuaternion(void) {}
// MARK: Setters / Getters
//! Gets the W coordinate
float NiQuaternion::GetW(void) const {
return this->w;
}
//! Sets the W coordinate
void NiQuaternion::SetW(float w) {
this->w = w;
}
//! Gets the X coordinate
float NiQuaternion::GetX(void) const {
return this->x;
}
//! Sets the X coordinate
void NiQuaternion::SetX(float x) {
this->x = x;
}
//! Gets the Y coordinate
float NiQuaternion::GetY(void) const {
return this->y;
}
//! Sets the Y coordinate
void NiQuaternion::SetY(float y) {
this->y = y;
}
//! Gets the Z coordinate
float NiQuaternion::GetZ(void) const {
return this->z;
}
//! Sets the Z coordinate
void NiQuaternion::SetZ(float z) {
this->z = z;
}
// MARK: Member Functions // MARK: Member Functions
//! Returns the forward vector from the quaternion
Vector3 NiQuaternion::GetForwardVector(void) const {
return Vector3(2 * (x * z + w * y), 2 * (y * z - w * x), 1 - 2 * (x * x + y * y));
}
//! Returns the up vector from the quaternion
Vector3 NiQuaternion::GetUpVector(void) const {
return Vector3(2 * (x * y - w * z), 1 - 2 * (x * x + z * z), 2 * (y * z + w * x));
}
//! Returns the right vector from the quaternion
Vector3 NiQuaternion::GetRightVector(void) const {
return Vector3(1 - 2 * (y * y + z * z), 2 * (x * y + w * z), 2 * (x * z - w * y));
}
Vector3 NiQuaternion::GetEulerAngles() const { Vector3 NiQuaternion::GetEulerAngles() const {
Vector3 angles; Vector3 angles;
@@ -30,9 +111,22 @@ Vector3 NiQuaternion::GetEulerAngles() const {
return angles; return angles;
} }
// MARK: Operators
//! Operator to check for equality
bool NiQuaternion::operator==(const NiQuaternion& rot) const {
return rot.x == this->x && rot.y == this->y && rot.z == this->z && rot.w == this->w;
}
//! Operator to check for inequality
bool NiQuaternion::operator!=(const NiQuaternion& rot) const {
return !(*this == rot);
}
// MARK: Helper Functions // MARK: Helper Functions
//! Look from a specific point in space to another point in space (Y-locked) //! Look from a specific point in space to another point in space
NiQuaternion NiQuaternion::LookAt(const NiPoint3& sourcePoint, const NiPoint3& destPoint) { NiQuaternion NiQuaternion::LookAt(const NiPoint3& sourcePoint, const NiPoint3& destPoint) {
//To make sure we don't orient around the X/Z axis: //To make sure we don't orient around the X/Z axis:
NiPoint3 source = sourcePoint; NiPoint3 source = sourcePoint;
@@ -42,7 +136,7 @@ NiQuaternion NiQuaternion::LookAt(const NiPoint3& sourcePoint, const NiPoint3& d
NiPoint3 forwardVector = NiPoint3(dest - source).Unitize(); NiPoint3 forwardVector = NiPoint3(dest - source).Unitize();
NiPoint3 posZ = NiPoint3Constant::UNIT_Z; NiPoint3 posZ = NiPoint3::UNIT_Z;
NiPoint3 vecA = posZ.CrossProduct(forwardVector).Unitize(); NiPoint3 vecA = posZ.CrossProduct(forwardVector).Unitize();
float dot = posZ.DotProduct(forwardVector); float dot = posZ.DotProduct(forwardVector);
@@ -54,11 +148,10 @@ NiQuaternion NiQuaternion::LookAt(const NiPoint3& sourcePoint, const NiPoint3& d
return NiQuaternion::CreateFromAxisAngle(vecA, rotAngle); return NiQuaternion::CreateFromAxisAngle(vecA, rotAngle);
} }
//! Look from a specific point in space to another point in space
NiQuaternion NiQuaternion::LookAtUnlocked(const NiPoint3& sourcePoint, const NiPoint3& destPoint) { NiQuaternion NiQuaternion::LookAtUnlocked(const NiPoint3& sourcePoint, const NiPoint3& destPoint) {
NiPoint3 forwardVector = NiPoint3(destPoint - sourcePoint).Unitize(); NiPoint3 forwardVector = NiPoint3(destPoint - sourcePoint).Unitize();
NiPoint3 posZ = NiPoint3Constant::UNIT_Z; NiPoint3 posZ = NiPoint3::UNIT_Z;
NiPoint3 vecA = posZ.CrossProduct(forwardVector).Unitize(); NiPoint3 vecA = posZ.CrossProduct(forwardVector).Unitize();
float dot = posZ.DotProduct(forwardVector); float dot = posZ.DotProduct(forwardVector);

View File

@@ -1,5 +1,4 @@
#ifndef __NIQUATERNION_H__ #pragma once
#define __NIQUATERNION_H__
// Custom Classes // Custom Classes
#include "NiPoint3.h" #include "NiPoint3.h"
@@ -15,14 +14,14 @@ typedef NiQuaternion Quaternion; //!< A typedef for a shorthand version o
//! A class that defines a rotation in space //! A class that defines a rotation in space
class NiQuaternion { class NiQuaternion {
public: public:
float w{ 1 }; //!< The w coordinate float w; //!< The w coordinate
float x{ 0 }; //!< The x coordinate float x; //!< The x coordinate
float y{ 0 }; //!< The y coordinate float y; //!< The y coordinate
float z{ 0 }; //!< The z coordinate float z; //!< The z coordinate
//! The initializer //! The initializer
constexpr NiQuaternion() = default; NiQuaternion(void);
//! The initializer //! The initializer
/*! /*!
@@ -31,12 +30,13 @@ public:
\param y The y coordinate \param y The y coordinate
\param z The z coordinate \param z The z coordinate
*/ */
constexpr NiQuaternion(const float w, const float x, const float y, const float z) noexcept NiQuaternion(float w, float x, float y, float z);
: w{ w }
, x{ x } //! Destructor
, y{ y } ~NiQuaternion(void);
, z{ z } {
} // MARK: Constants
static const NiQuaternion IDENTITY; //!< Quaternion(1, 0, 0, 0)
// MARK: Setters / Getters // MARK: Setters / Getters
@@ -44,49 +44,50 @@ public:
/*! /*!
\return The w coordinate \return The w coordinate
*/ */
[[nodiscard]] constexpr float GetW() const noexcept; float GetW(void) const;
//! Sets the W coordinate //! Sets the W coordinate
/*! /*!
\param w The w coordinate \param w The w coordinate
*/ */
constexpr void SetW(const float w) noexcept; void SetW(float w);
//! Gets the X coordinate //! Gets the X coordinate
/*! /*!
\return The x coordinate \return The x coordinate
*/ */
[[nodiscard]] constexpr float GetX() const noexcept; float GetX(void) const;
//! Sets the X coordinate //! Sets the X coordinate
/*! /*!
\param x The x coordinate \param x The x coordinate
*/ */
constexpr void SetX(const float x) noexcept; void SetX(float x);
//! Gets the Y coordinate //! Gets the Y coordinate
/*! /*!
\return The y coordinate \return The y coordinate
*/ */
[[nodiscard]] constexpr float GetY() const noexcept; float GetY(void) const;
//! Sets the Y coordinate //! Sets the Y coordinate
/*! /*!
\param y The y coordinate \param y The y coordinate
*/ */
constexpr void SetY(const float y) noexcept; void SetY(float y);
//! Gets the Z coordinate //! Gets the Z coordinate
/*! /*!
\return The z coordinate \return The z coordinate
*/ */
[[nodiscard]] constexpr float GetZ() const noexcept; float GetZ(void) const;
//! Sets the Z coordinate //! Sets the Z coordinate
/*! /*!
\param z The z coordinate \param z The z coordinate
*/ */
constexpr void SetZ(const float z) noexcept; void SetZ(float z);
// MARK: Member Functions // MARK: Member Functions
@@ -94,29 +95,31 @@ public:
/*! /*!
\return The forward vector of the quaternion \return The forward vector of the quaternion
*/ */
[[nodiscard]] constexpr Vector3 GetForwardVector() const noexcept; Vector3 GetForwardVector(void) const;
//! Returns the up vector from the quaternion //! Returns the up vector from the quaternion
/*! /*!
\return The up vector fo the quaternion \return The up vector fo the quaternion
*/ */
[[nodiscard]] constexpr Vector3 GetUpVector() const noexcept; Vector3 GetUpVector(void) const;
//! Returns the right vector from the quaternion //! Returns the right vector from the quaternion
/*! /*!
\return The right vector of the quaternion \return The right vector of the quaternion
*/ */
[[nodiscard]] constexpr Vector3 GetRightVector() const noexcept; Vector3 GetRightVector(void) const;
Vector3 GetEulerAngles() const;
[[nodiscard]] Vector3 GetEulerAngles() const;
// MARK: Operators // MARK: Operators
//! Operator to check for equality //! Operator to check for equality
constexpr bool operator==(const NiQuaternion& rot) const noexcept; bool operator==(const NiQuaternion& rot) const;
//! Operator to check for inequality //! Operator to check for inequality
constexpr bool operator!=(const NiQuaternion& rot) const noexcept; bool operator!=(const NiQuaternion& rot) const;
// MARK: Helper Functions // MARK: Helper Functions
@@ -126,7 +129,7 @@ public:
\param destPoint The destination location \param destPoint The destination location
\return The Quaternion with the rotation towards the destination \return The Quaternion with the rotation towards the destination
*/ */
[[nodiscard]] static NiQuaternion LookAt(const NiPoint3& sourcePoint, const NiPoint3& destPoint); static NiQuaternion LookAt(const NiPoint3& sourcePoint, const NiPoint3& destPoint);
//! Look from a specific point in space to another point in space //! Look from a specific point in space to another point in space
/*! /*!
@@ -134,7 +137,7 @@ public:
\param destPoint The destination location \param destPoint The destination location
\return The Quaternion with the rotation towards the destination \return The Quaternion with the rotation towards the destination
*/ */
[[nodiscard]] static NiQuaternion LookAtUnlocked(const NiPoint3& sourcePoint, const NiPoint3& destPoint); static NiQuaternion LookAtUnlocked(const NiPoint3& sourcePoint, const NiPoint3& destPoint);
//! Creates a Quaternion from a specific axis and angle relative to that axis //! Creates a Quaternion from a specific axis and angle relative to that axis
/*! /*!
@@ -142,17 +145,7 @@ public:
\param angle The angle relative to this axis \param angle The angle relative to this axis
\return A quaternion created from the axis and angle \return A quaternion created from the axis and angle
*/ */
[[nodiscard]] static NiQuaternion CreateFromAxisAngle(const Vector3& axis, float angle); static NiQuaternion CreateFromAxisAngle(const Vector3& axis, float angle);
[[nodiscard]] static NiQuaternion FromEulerAngles(const NiPoint3& eulerAngles); static NiQuaternion FromEulerAngles(const NiPoint3& eulerAngles);
}; };
// Static Variables
namespace NiQuaternionConstant {
constexpr NiQuaternion IDENTITY(1, 0, 0, 0);
}
// Include constexpr and inline function definitions in a seperate file for readability
#include "NiQuaternion.inl"
#endif // !__NIQUATERNION_H__

View File

@@ -1,75 +0,0 @@
#pragma once
#ifndef __NIQUATERNION_H__
#error "This should only be included inline in NiQuaternion.h: Do not include directly!"
#endif
// MARK: Setters / Getters
//! Gets the W coordinate
constexpr float NiQuaternion::GetW() const noexcept {
return this->w;
}
//! Sets the W coordinate
constexpr void NiQuaternion::SetW(const float w) noexcept {
this->w = w;
}
//! Gets the X coordinate
constexpr float NiQuaternion::GetX() const noexcept {
return this->x;
}
//! Sets the X coordinate
constexpr void NiQuaternion::SetX(const float x) noexcept {
this->x = x;
}
//! Gets the Y coordinate
constexpr float NiQuaternion::GetY() const noexcept {
return this->y;
}
//! Sets the Y coordinate
constexpr void NiQuaternion::SetY(const float y) noexcept {
this->y = y;
}
//! Gets the Z coordinate
constexpr float NiQuaternion::GetZ() const noexcept {
return this->z;
}
//! Sets the Z coordinate
constexpr void NiQuaternion::SetZ(const float z) noexcept {
this->z = z;
}
// MARK: Member Functions
//! Returns the forward vector from the quaternion
constexpr Vector3 NiQuaternion::GetForwardVector() const noexcept {
return Vector3(2 * (x * z + w * y), 2 * (y * z - w * x), 1 - 2 * (x * x + y * y));
}
//! Returns the up vector from the quaternion
constexpr Vector3 NiQuaternion::GetUpVector() const noexcept {
return Vector3(2 * (x * y - w * z), 1 - 2 * (x * x + z * z), 2 * (y * z + w * x));
}
//! Returns the right vector from the quaternion
constexpr Vector3 NiQuaternion::GetRightVector() const noexcept {
return Vector3(1 - 2 * (y * y + z * z), 2 * (x * y + w * z), 2 * (x * z - w * y));
}
// MARK: Operators
//! Operator to check for equality
constexpr bool NiQuaternion::operator==(const NiQuaternion& rot) const noexcept {
return rot.x == this->x && rot.y == this->y && rot.z == this->z && rot.w == this->w;
}
//! Operator to check for inequality
constexpr bool NiQuaternion::operator!=(const NiQuaternion& rot) const noexcept {
return !(*this == rot);
}

View File

@@ -1,36 +0,0 @@
#ifndef __POSITIONUPDATE__H__
#define __POSITIONUPDATE__H__
#include "NiPoint3.h"
#include "NiQuaternion.h"
struct RemoteInputInfo {
bool operator==(const RemoteInputInfo& other) {
return m_RemoteInputX == other.m_RemoteInputX && m_RemoteInputY == other.m_RemoteInputY && m_IsPowersliding == other.m_IsPowersliding && m_IsModified == other.m_IsModified;
}
float m_RemoteInputX = 0;
float m_RemoteInputY = 0;
bool m_IsPowersliding = false;
bool m_IsModified = false;
};
struct LocalSpaceInfo {
LWOOBJID objectId = LWOOBJID_EMPTY;
NiPoint3 position = NiPoint3Constant::ZERO;
NiPoint3 linearVelocity = NiPoint3Constant::ZERO;
};
struct PositionUpdate {
NiPoint3 position = NiPoint3Constant::ZERO;
NiQuaternion rotation = NiQuaternionConstant::IDENTITY;
bool onGround = false;
bool onRail = false;
NiPoint3 velocity = NiPoint3Constant::ZERO;
NiPoint3 angularVelocity = NiPoint3Constant::ZERO;
LocalSpaceInfo localSpaceInfo;
RemoteInputInfo remoteInputInfo;
};
#endif //!__POSITIONUPDATE__H__

154
dCommon/SHA512.cpp Normal file
View File

@@ -0,0 +1,154 @@
// Source: http://www.zedwood.com/article/cpp-sha512-function
#include "SHA512.h"
#include <cstring>
#include <fstream>
const unsigned long long SHA512::sha512_k[80] = //ULL = uint64
{ 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL,
0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
0xd807aa98a3030242ULL, 0x12835b0145706fbeULL,
0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL,
0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL,
0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL,
0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL,
0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL,
0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
0xd192e819d6ef5218ULL, 0xd69906245565a910ULL,
0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL,
0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL,
0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL,
0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL,
0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
0x28db77f523047d84ULL, 0x32caab7b40c72493ULL,
0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL };
void SHA512::transform(const unsigned char* message, unsigned int block_nb) {
uint64 w[80];
uint64 wv[8];
uint64 t1, t2;
const unsigned char* sub_block;
int i, j;
for (i = 0; i < (int)block_nb; i++) {
sub_block = message + (i << 7);
for (j = 0; j < 16; j++) {
SHA2_PACK64(&sub_block[j << 3], &w[j]);
}
for (j = 16; j < 80; j++) {
w[j] = SHA512_F4(w[j - 2]) + w[j - 7] + SHA512_F3(w[j - 15]) + w[j - 16];
}
for (j = 0; j < 8; j++) {
wv[j] = m_h[j];
}
for (j = 0; j < 80; j++) {
t1 = wv[7] + SHA512_F2(wv[4]) + SHA2_CH(wv[4], wv[5], wv[6])
+ sha512_k[j] + w[j];
t2 = SHA512_F1(wv[0]) + SHA2_MAJ(wv[0], wv[1], wv[2]);
wv[7] = wv[6];
wv[6] = wv[5];
wv[5] = wv[4];
wv[4] = wv[3] + t1;
wv[3] = wv[2];
wv[2] = wv[1];
wv[1] = wv[0];
wv[0] = t1 + t2;
}
for (j = 0; j < 8; j++) {
m_h[j] += wv[j];
}
}
}
void SHA512::init() {
m_h[0] = 0x6a09e667f3bcc908ULL;
m_h[1] = 0xbb67ae8584caa73bULL;
m_h[2] = 0x3c6ef372fe94f82bULL;
m_h[3] = 0xa54ff53a5f1d36f1ULL;
m_h[4] = 0x510e527fade682d1ULL;
m_h[5] = 0x9b05688c2b3e6c1fULL;
m_h[6] = 0x1f83d9abfb41bd6bULL;
m_h[7] = 0x5be0cd19137e2179ULL;
m_len = 0;
m_tot_len = 0;
}
void SHA512::update(const unsigned char* message, unsigned int len) {
unsigned int block_nb;
unsigned int new_len, rem_len, tmp_len;
const unsigned char* shifted_message;
tmp_len = SHA384_512_BLOCK_SIZE - m_len;
rem_len = len < tmp_len ? len : tmp_len;
memcpy(&m_block[m_len], message, rem_len);
if (m_len + len < SHA384_512_BLOCK_SIZE) {
m_len += len;
return;
}
new_len = len - rem_len;
block_nb = new_len / SHA384_512_BLOCK_SIZE;
shifted_message = message + rem_len;
transform(m_block, 1);
transform(shifted_message, block_nb);
rem_len = new_len % SHA384_512_BLOCK_SIZE;
memcpy(m_block, &shifted_message[block_nb << 7], rem_len);
m_len = rem_len;
m_tot_len += (block_nb + 1) << 7;
}
void SHA512::final(unsigned char* digest) {
unsigned int block_nb;
unsigned int pm_len;
unsigned int len_b;
int i;
block_nb = 1 + ((SHA384_512_BLOCK_SIZE - 17)
< (m_len % SHA384_512_BLOCK_SIZE));
len_b = (m_tot_len + m_len) << 3;
pm_len = block_nb << 7;
memset(m_block + m_len, 0, pm_len - m_len);
m_block[m_len] = 0x80;
SHA2_UNPACK32(len_b, m_block + pm_len - 4);
transform(m_block, block_nb);
for (i = 0; i < 8; i++) {
SHA2_UNPACK64(m_h[i], &digest[i << 3]);
}
}
std::string sha512(std::string input) {
unsigned char digest[SHA512::DIGEST_SIZE];
memset(digest, 0, SHA512::DIGEST_SIZE);
class SHA512 ctx;
ctx.init();
ctx.update((unsigned char*)input.c_str(), input.length());
ctx.final(digest);
char buf[2 * SHA512::DIGEST_SIZE + 1];
buf[2 * SHA512::DIGEST_SIZE] = 0;
for (int i = 0; i < SHA512::DIGEST_SIZE; i++)
sprintf(buf + i * 2, "%02x", digest[i]);
return std::string(buf);
}

68
dCommon/SHA512.h Normal file
View File

@@ -0,0 +1,68 @@
#pragma once
// C++
#include <string>
class SHA512 {
protected:
typedef unsigned char uint8;
typedef unsigned int uint32;
typedef unsigned long long uint64;
const static uint64 sha512_k[];
static const unsigned int SHA384_512_BLOCK_SIZE = (1024 / 8);
public:
void init();
void update(const unsigned char* message, unsigned int len);
void final(unsigned char* digest);
static const unsigned int DIGEST_SIZE = (512 / 8);
protected:
void transform(const unsigned char* message, unsigned int block_nb);
unsigned int m_tot_len;
unsigned int m_len;
unsigned char m_block[2 * SHA384_512_BLOCK_SIZE];
uint64 m_h[8];
};
std::string sha512(std::string input);
#define SHA2_SHFR(x, n) (x >> n)
#define SHA2_ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n)))
#define SHA2_ROTL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n)))
#define SHA2_CH(x, y, z) ((x & y) ^ (~x & z))
#define SHA2_MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
#define SHA512_F1(x) (SHA2_ROTR(x, 28) ^ SHA2_ROTR(x, 34) ^ SHA2_ROTR(x, 39))
#define SHA512_F2(x) (SHA2_ROTR(x, 14) ^ SHA2_ROTR(x, 18) ^ SHA2_ROTR(x, 41))
#define SHA512_F3(x) (SHA2_ROTR(x, 1) ^ SHA2_ROTR(x, 8) ^ SHA2_SHFR(x, 7))
#define SHA512_F4(x) (SHA2_ROTR(x, 19) ^ SHA2_ROTR(x, 61) ^ SHA2_SHFR(x, 6))
#define SHA2_UNPACK32(x, str) \
{ \
*((str) + 3) = (uint8) ((x) ); \
*((str) + 2) = (uint8) ((x) >> 8); \
*((str) + 1) = (uint8) ((x) >> 16); \
*((str) + 0) = (uint8) ((x) >> 24); \
}
#define SHA2_UNPACK64(x, str) \
{ \
*((str) + 7) = (uint8) ((x) ); \
*((str) + 6) = (uint8) ((x) >> 8); \
*((str) + 5) = (uint8) ((x) >> 16); \
*((str) + 4) = (uint8) ((x) >> 24); \
*((str) + 3) = (uint8) ((x) >> 32); \
*((str) + 2) = (uint8) ((x) >> 40); \
*((str) + 1) = (uint8) ((x) >> 48); \
*((str) + 0) = (uint8) ((x) >> 56); \
}
#define SHA2_PACK64(str, x) \
{ \
*(x) = ((uint64) *((str) + 7) ) \
| ((uint64) *((str) + 6) << 8) \
| ((uint64) *((str) + 5) << 16) \
| ((uint64) *((str) + 4) << 24) \
| ((uint64) *((str) + 3) << 32) \
| ((uint64) *((str) + 2) << 40) \
| ((uint64) *((str) + 1) << 48) \
| ((uint64) *((str) + 0) << 56); \
}

View File

@@ -1,6 +1,6 @@
#include "ZCompression.h" #include "ZCompression.h"
#include "zlib.h" #include <zlib.h>
namespace ZCompression { namespace ZCompression {
int32_t GetMaxCompressedLength(int32_t nLenSrc) { int32_t GetMaxCompressedLength(int32_t nLenSrc) {

View File

@@ -4,7 +4,7 @@
#include "Game.h" #include "Game.h"
#include "Logger.h" #include "Logger.h"
#include "zlib.h" #include <zlib.h>
AssetManager::AssetManager(const std::filesystem::path& path) { AssetManager::AssetManager(const std::filesystem::path& path) {
if (!std::filesystem::is_directory(path)) { if (!std::filesystem::is_directory(path)) {

View File

@@ -1,6 +1,6 @@
set(DCOMMON_DCLIENT_SOURCES set(DCOMMON_DCLIENT_SOURCES
"AssetManager.cpp"
"PackIndex.cpp" "PackIndex.cpp"
"Pack.cpp" "Pack.cpp"
"AssetManager.cpp"
PARENT_SCOPE PARENT_SCOPE
) )

View File

@@ -1,12 +0,0 @@
#ifndef __CLIENTVERSION_H__
#define __CLIENTVERSION_H__
#include <cstdint>
namespace ClientVersion {
constexpr uint16_t major = 1;
constexpr uint16_t current = 10;
constexpr uint16_t minor = 64;
}
#endif // !__CLIENTVERSION_H__

View File

@@ -9,15 +9,15 @@ namespace StringifiedEnum {
const std::string_view ToString(const T e) { const std::string_view ToString(const T e) {
static_assert(std::is_enum_v<T>, "Not an enum"); // Check type static_assert(std::is_enum_v<T>, "Not an enum"); // Check type
constexpr auto& sv = magic_enum::enum_entries<T>(); constexpr auto sv = &magic_enum::enum_entries<T>();
const auto it = std::lower_bound( const auto it = std::lower_bound(
sv.begin(), sv.end(), e, sv->begin(), sv->end(), e,
[&](const std::pair<T, std::string_view>& lhs, const T rhs) { return lhs.first < rhs; } [&](const std::pair<T, std::string_view>& lhs, const T rhs) { return lhs.first < rhs; }
); );
std::string_view output; std::string_view output;
if (it != sv.end() && it->first == e) { if (it != sv->end() && it->first == e) {
output = it->second; output = it->second;
} else { } else {
output = "UNKNOWN"; output = "UNKNOWN";

View File

@@ -34,89 +34,91 @@ constexpr uint32_t lowFrameDelta = FRAMES_TO_MS(lowFramerate);
#define CINSTREAM RakNet::BitStream inStream(packet->data, packet->length, false); #define CINSTREAM RakNet::BitStream inStream(packet->data, packet->length, false);
#define CINSTREAM_SKIP_HEADER CINSTREAM if (inStream.GetNumberOfUnreadBits() >= BYTES_TO_BITS(HEADER_SIZE)) inStream.IgnoreBytes(HEADER_SIZE); else inStream.IgnoreBits(inStream.GetNumberOfUnreadBits()); #define CINSTREAM_SKIP_HEADER CINSTREAM if (inStream.GetNumberOfUnreadBits() >= BYTES_TO_BITS(HEADER_SIZE)) inStream.IgnoreBytes(HEADER_SIZE); else inStream.IgnoreBits(inStream.GetNumberOfUnreadBits());
#define CMSGHEADER BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::GAME_MSG); #define CMSGHEADER BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::GAME_MSG);
#define SEND_PACKET Game::server->Send(bitStream, sysAddr, false); #define SEND_PACKET Game::server->Send(&bitStream, sysAddr, false);
#define SEND_PACKET_BROADCAST Game::server->Send(bitStream, UNASSIGNED_SYSTEM_ADDRESS, true); #define SEND_PACKET_BROADCAST Game::server->Send(&bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);
//=========== TYPEDEFS ========== //=========== TYPEDEFS ==========
using LOT = int32_t; //!< A LOT typedef int32_t LOT; //!< A LOT
using LWOOBJID = int64_t; //!< An object ID (should be unsigned actually but ok) typedef int64_t LWOOBJID; //!< An object ID (should be unsigned actually but ok)
using TSkillID = int32_t; //!< A skill ID typedef int32_t TSkillID; //!< A skill ID
using LWOCLONEID = uint32_t; //!< Used for Clone IDs typedef uint32_t LWOCLONEID; //!< Used for Clone IDs
using LWOMAPID = uint16_t; //!< Used for Map IDs typedef uint16_t LWOMAPID; //!< Used for Map IDs
using LWOINSTANCEID = uint16_t; //!< Used for Instance IDs typedef uint16_t LWOINSTANCEID; //!< Used for Instance IDs
using PROPERTYCLONELIST = uint32_t; //!< Used for Property Clone IDs typedef uint32_t PROPERTYCLONELIST; //!< Used for Property Clone IDs
using StripId = uint32_t; typedef uint32_t StripId;
constexpr LWOOBJID LWOOBJID_EMPTY = 0; //!< An empty object ID const LWOOBJID LWOOBJID_EMPTY = 0; //!< An empty object ID
constexpr LOT LOT_NULL = -1; //!< A null LOT const LOT LOT_NULL = -1; //!< A null LOT
constexpr int32_t LOOTTYPE_NONE = 0; //!< No loot type available const int32_t LOOTTYPE_NONE = 0; //!< No loot type available
constexpr float SECONDARY_PRIORITY = 1.0f; //!< Secondary Priority const float SECONDARY_PRIORITY = 1.0f; //!< Secondary Priority
constexpr uint32_t INVENTORY_MAX = 9999999; //!< The Maximum Inventory Size const uint32_t INVENTORY_MAX = 9999999; //!< The Maximum Inventory Size
constexpr LWOCLONEID LWOCLONEID_INVALID = -1; //!< Invalid LWOCLONEID const uint32_t LWOCLONEID_INVALID = -1; //!< Invalid LWOCLONEID
constexpr LWOINSTANCEID LWOINSTANCEID_INVALID = -1; //!< Invalid LWOINSTANCEID const uint16_t LWOINSTANCEID_INVALID = -1; //!< Invalid LWOINSTANCEID
constexpr LWOMAPID LWOMAPID_INVALID = -1; //!< Invalid LWOMAPID const uint16_t LWOMAPID_INVALID = -1; //!< Invalid LWOMAPID
constexpr uint64_t LWOZONEID_INVALID = 0; //!< Invalid LWOZONEID const uint64_t LWOZONEID_INVALID = 0; //!< Invalid LWOZONEID
constexpr float PI = 3.14159f; const float PI = 3.14159f;
//============ STRUCTS ============== //============ STRUCTS ==============
struct LWOSCENEID { struct LWOSCENEID {
public: public:
constexpr LWOSCENEID() noexcept { m_sceneID = -1; m_layerID = 0; } LWOSCENEID() { m_sceneID = -1; m_layerID = 0; }
constexpr LWOSCENEID(int32_t sceneID) noexcept { m_sceneID = sceneID; m_layerID = 0; } LWOSCENEID(int sceneID) { m_sceneID = sceneID; m_layerID = 0; }
constexpr LWOSCENEID(int32_t sceneID, uint32_t layerID) noexcept { m_sceneID = sceneID; m_layerID = layerID; } LWOSCENEID(int sceneID, unsigned int layerID) { m_sceneID = sceneID; m_layerID = layerID; }
constexpr LWOSCENEID& operator=(const LWOSCENEID& rhs) noexcept { m_sceneID = rhs.m_sceneID; m_layerID = rhs.m_layerID; return *this; } LWOSCENEID& operator=(const LWOSCENEID& rhs) { m_sceneID = rhs.m_sceneID; m_layerID = rhs.m_layerID; return *this; }
constexpr LWOSCENEID& operator=(const int32_t rhs) noexcept { m_sceneID = rhs; m_layerID = 0; return *this; } LWOSCENEID& operator=(const int rhs) { m_sceneID = rhs; m_layerID = 0; return *this; }
constexpr bool operator<(const LWOSCENEID& rhs) const noexcept { return (m_sceneID < rhs.m_sceneID || (m_sceneID == rhs.m_sceneID && m_layerID < rhs.m_layerID)); } bool operator<(const LWOSCENEID& rhs) const { return (m_sceneID < rhs.m_sceneID || (m_sceneID == rhs.m_sceneID && m_layerID < rhs.m_layerID)); }
constexpr bool operator<(const int32_t rhs) const noexcept { return m_sceneID < rhs; } bool operator<(const int rhs) const { return m_sceneID < rhs; }
constexpr bool operator==(const LWOSCENEID& rhs) const noexcept { return (m_sceneID == rhs.m_sceneID && m_layerID == rhs.m_layerID); } bool operator==(const LWOSCENEID& rhs) const { return (m_sceneID == rhs.m_sceneID && m_layerID == rhs.m_layerID); }
constexpr bool operator==(const int32_t rhs) const noexcept { return m_sceneID == rhs; } bool operator==(const int rhs) const { return m_sceneID == rhs; }
constexpr int32_t GetSceneID() const noexcept { return m_sceneID; } const int GetSceneID() const { return m_sceneID; }
constexpr uint32_t GetLayerID() const noexcept { return m_layerID; } const unsigned int GetLayerID() const { return m_layerID; }
constexpr void SetSceneID(const int32_t sceneID) noexcept { m_sceneID = sceneID; } void SetSceneID(const int sceneID) { m_sceneID = sceneID; }
constexpr void SetLayerID(const uint32_t layerID) noexcept { m_layerID = layerID; } void SetLayerID(const unsigned int layerID) { m_layerID = layerID; }
private: private:
int32_t m_sceneID; int m_sceneID;
uint32_t m_layerID; unsigned int m_layerID;
}; };
struct LWOZONEID { struct LWOZONEID {
public: public:
constexpr const LWOMAPID& GetMapID() const noexcept { return m_MapID; } const LWOMAPID& GetMapID() const { return m_MapID; }
constexpr const LWOINSTANCEID& GetInstanceID() const noexcept { return m_InstanceID; } const LWOINSTANCEID& GetInstanceID() const { return m_InstanceID; }
constexpr const LWOCLONEID& GetCloneID() const noexcept { return m_CloneID; } const LWOCLONEID& GetCloneID() const { return m_CloneID; }
//In order: def constr, constr, assign op //In order: def constr, constr, assign op
constexpr LWOZONEID() noexcept = default; LWOZONEID() { m_MapID = LWOMAPID_INVALID; m_InstanceID = LWOINSTANCEID_INVALID; m_CloneID = LWOCLONEID_INVALID; }
constexpr LWOZONEID(const LWOMAPID& mapID, const LWOINSTANCEID& instanceID, const LWOCLONEID& cloneID) noexcept { m_MapID = mapID; m_InstanceID = instanceID; m_CloneID = cloneID; } LWOZONEID(const LWOMAPID& mapID, const LWOINSTANCEID& instanceID, const LWOCLONEID& cloneID) { m_MapID = mapID; m_InstanceID = instanceID; m_CloneID = cloneID; }
constexpr LWOZONEID(const LWOZONEID& replacement) noexcept { *this = replacement; } LWOZONEID(const LWOZONEID& replacement) { *this = replacement; }
private: private:
LWOMAPID m_MapID = LWOMAPID_INVALID; //1000 for VE, 1100 for AG, etc... LWOMAPID m_MapID; //1000 for VE, 1100 for AG, etc...
LWOINSTANCEID m_InstanceID = LWOINSTANCEID_INVALID; //Instances host the same world, but on a different dWorld process. LWOINSTANCEID m_InstanceID; //Instances host the same world, but on a different dWorld process.
LWOCLONEID m_CloneID = LWOCLONEID_INVALID; //To differentiate between "your property" and "my property". Always 0 for non-prop worlds. LWOCLONEID m_CloneID; //To differentiate between "your property" and "my property". Always 0 for non-prop worlds.
}; };
constexpr LWOSCENEID LWOSCENEID_INVALID = -1; const LWOSCENEID LWOSCENEID_INVALID = -1;
struct LWONameValue { struct LWONameValue {
uint32_t length = 0; //!< The length of the name uint32_t length = 0; //!< The length of the name
std::u16string name; //!< The name std::u16string name; //!< The name
LWONameValue() = default; LWONameValue(void) {}
LWONameValue(const std::u16string& name) { LWONameValue(const std::u16string& name) {
this->name = name; this->name = name;
this->length = static_cast<uint32_t>(name.length()); this->length = static_cast<uint32_t>(name.length());
} }
~LWONameValue(void) {}
}; };
struct FriendData { struct FriendData {
@@ -128,7 +130,7 @@ public:
LWOOBJID friendID; LWOOBJID friendID;
std::string friendName; std::string friendName;
void Serialize(RakNet::BitStream& bitStream) const { void Serialize(RakNet::BitStream& bitStream) {
bitStream.Write<uint8_t>(isOnline); bitStream.Write<uint8_t>(isOnline);
bitStream.Write<uint8_t>(isBestFriend); bitStream.Write<uint8_t>(isBestFriend);
bitStream.Write<uint8_t>(isFTP); bitStream.Write<uint8_t>(isFTP);

View File

@@ -629,7 +629,7 @@ enum class eGameMessageType : uint16_t {
GET_INSTRUCTION_COUNT = 676, GET_INSTRUCTION_COUNT = 676,
GET_IS_NPC = 677, GET_IS_NPC = 677,
ACTIVATE_BUBBLE_BUFF = 678, ACTIVATE_BUBBLE_BUFF = 678,
DECTIVATE_BUBBLE_BUFF = 679, // This is spelled wrong in the client, so we misspell it here. DECTIVATE_BUBBLE_BUFF = 679, // thanks netdevil
EXHIBIT_VOTE = 680, EXHIBIT_VOTE = 680,
ADD_PET_TO_PLAYER = 681, ADD_PET_TO_PLAYER = 681,
REMOVE_PET_FROM_PLAYER = 682, REMOVE_PET_FROM_PLAYER = 682,

View File

@@ -1,13 +0,0 @@
#ifndef __EPETABILITYTYPE__H__
#define __EPETABILITYTYPE__H__
#include <cstdint>
enum class ePetAbilityType : uint32_t {
Invalid,
GoToObject,
JumpOnObject,
DigAtPosition
};
#endif //!__EPETABILITYTYPE__H__

View File

@@ -106,7 +106,7 @@ enum class eReplicaComponentType : uint32_t {
INTERACTION_MANAGER, INTERACTION_MANAGER,
DONATION_VENDOR, DONATION_VENDOR,
COMBAT_MEDIATOR, COMBAT_MEDIATOR,
ACHIEVEMENT_VENDOR, COMMENDATION_VENDOR,
GATE_RUSH_CONTROL, GATE_RUSH_CONTROL,
RAIL_ACTIVATOR, RAIL_ACTIVATOR,
ROLLER, ROLLER,

View File

@@ -1,15 +0,0 @@
#ifndef __EVENDORTRANSACTIONRESULT__
#define __EVENDORTRANSACTIONRESULT__
#include <cstdint>
enum class eVendorTransactionResult : uint32_t {
SELL_SUCCESS = 0,
SELL_FAIL,
PURCHASE_SUCCESS,
PURCHASE_FAIL,
DONATION_FAIL,
DONATION_FULL
};
#endif // !__EVENDORTRANSACTIONRESULT__

View File

@@ -4,13 +4,9 @@
// Static Variables // Static Variables
static CppSQLite3DB* conn = new CppSQLite3DB(); static CppSQLite3DB* conn = new CppSQLite3DB();
// Status Variables
bool CDClientDatabase::isConnected = false;
//! Opens a connection with the CDClient //! Opens a connection with the CDClient
void CDClientDatabase::Connect(const std::string& filename) { void CDClientDatabase::Connect(const std::string& filename) {
conn->open(filename.c_str()); conn->open(filename.c_str());
isConnected = true;
} }
//! Queries the CDClient //! Queries the CDClient

View File

@@ -15,10 +15,6 @@
//! The CDClient Database namespace //! The CDClient Database namespace
namespace CDClientDatabase { namespace CDClientDatabase {
/**
* Boolean defining the connection status of CDClient
*/
extern bool isConnected;
//! Opens a connection with the CDClient //! Opens a connection with the CDClient
/*! /*!

View File

@@ -3,7 +3,6 @@
#include "CDAnimationsTable.h" #include "CDAnimationsTable.h"
#include "CDBehaviorParameterTable.h" #include "CDBehaviorParameterTable.h"
#include "CDBehaviorTemplateTable.h" #include "CDBehaviorTemplateTable.h"
#include "CDClientDatabase.h"
#include "CDComponentsRegistryTable.h" #include "CDComponentsRegistryTable.h"
#include "CDCurrencyTableTable.h" #include "CDCurrencyTableTable.h"
#include "CDDestructibleComponentTable.h" #include "CDDestructibleComponentTable.h"
@@ -39,9 +38,6 @@
#include "CDFeatureGatingTable.h" #include "CDFeatureGatingTable.h"
#include "CDRailActivatorComponent.h" #include "CDRailActivatorComponent.h"
#include "CDRewardCodesTable.h" #include "CDRewardCodesTable.h"
#include "CDPetComponentTable.h"
#include <exception>
#ifndef CDCLIENT_CACHE_ALL #ifndef CDCLIENT_CACHE_ALL
// Uncomment this to cache the full cdclient database into memory. This will make the server load faster, but will use more memory. // Uncomment this to cache the full cdclient database into memory. This will make the server load faster, but will use more memory.
@@ -55,65 +51,7 @@
#define CDCLIENT_DONT_CACHE_TABLE(x) #define CDCLIENT_DONT_CACHE_TABLE(x)
#endif #endif
class CDClientConnectionException : public std::exception { CDClientManager::CDClientManager() {
public:
virtual const char* what() const throw() {
return "CDClientDatabase is not connected!";
}
};
// Using a macro to reduce repetitive code and issues from copy and paste.
// As a note, ## in a macro is used to concatenate two tokens together.
#define SPECIALIZE_TABLE_STORAGE(table) \
template<> typename table::StorageType& CDClientManager::GetEntriesMutable<table>() { return table##Entries; };
#define DEFINE_TABLE_STORAGE(table) namespace { table::StorageType table##Entries; }; SPECIALIZE_TABLE_STORAGE(table)
DEFINE_TABLE_STORAGE(CDActivityRewardsTable);
DEFINE_TABLE_STORAGE(CDActivitiesTable);
DEFINE_TABLE_STORAGE(CDAnimationsTable);
DEFINE_TABLE_STORAGE(CDBehaviorParameterTable);
DEFINE_TABLE_STORAGE(CDBehaviorTemplateTable);
DEFINE_TABLE_STORAGE(CDBrickIDTableTable);
DEFINE_TABLE_STORAGE(CDComponentsRegistryTable);
DEFINE_TABLE_STORAGE(CDCurrencyTableTable);
DEFINE_TABLE_STORAGE(CDDestructibleComponentTable);
DEFINE_TABLE_STORAGE(CDEmoteTableTable);
DEFINE_TABLE_STORAGE(CDFeatureGatingTable);
DEFINE_TABLE_STORAGE(CDInventoryComponentTable);
DEFINE_TABLE_STORAGE(CDItemComponentTable);
DEFINE_TABLE_STORAGE(CDItemSetSkillsTable);
DEFINE_TABLE_STORAGE(CDItemSetsTable);
DEFINE_TABLE_STORAGE(CDLevelProgressionLookupTable);
DEFINE_TABLE_STORAGE(CDLootMatrixTable);
DEFINE_TABLE_STORAGE(CDLootTableTable);
DEFINE_TABLE_STORAGE(CDMissionEmailTable);
DEFINE_TABLE_STORAGE(CDMissionNPCComponentTable);
DEFINE_TABLE_STORAGE(CDMissionTasksTable);
DEFINE_TABLE_STORAGE(CDMissionsTable);
DEFINE_TABLE_STORAGE(CDMovementAIComponentTable);
DEFINE_TABLE_STORAGE(CDObjectSkillsTable);
DEFINE_TABLE_STORAGE(CDObjectsTable);
DEFINE_TABLE_STORAGE(CDPhysicsComponentTable);
DEFINE_TABLE_STORAGE(CDPackageComponentTable);
DEFINE_TABLE_STORAGE(CDPetComponentTable);
DEFINE_TABLE_STORAGE(CDProximityMonitorComponentTable);
DEFINE_TABLE_STORAGE(CDPropertyEntranceComponentTable);
DEFINE_TABLE_STORAGE(CDPropertyTemplateTable);
DEFINE_TABLE_STORAGE(CDRailActivatorComponentTable);
DEFINE_TABLE_STORAGE(CDRarityTableTable);
DEFINE_TABLE_STORAGE(CDRebuildComponentTable);
DEFINE_TABLE_STORAGE(CDRewardCodesTable);
DEFINE_TABLE_STORAGE(CDRewardsTable);
DEFINE_TABLE_STORAGE(CDScriptComponentTable);
DEFINE_TABLE_STORAGE(CDSkillBehaviorTable);
DEFINE_TABLE_STORAGE(CDVendorComponentTable);
DEFINE_TABLE_STORAGE(CDZoneTableTable);
void CDClientManager::LoadValuesFromDatabase() {
if (!CDClientDatabase::isConnected) throw CDClientConnectionException();
CDActivityRewardsTable::Instance().LoadValuesFromDatabase(); CDActivityRewardsTable::Instance().LoadValuesFromDatabase();
CDActivitiesTable::Instance().LoadValuesFromDatabase(); CDActivitiesTable::Instance().LoadValuesFromDatabase();
CDCLIENT_DONT_CACHE_TABLE(CDAnimationsTable::Instance().LoadValuesFromDatabase()); CDCLIENT_DONT_CACHE_TABLE(CDAnimationsTable::Instance().LoadValuesFromDatabase());
@@ -141,7 +79,6 @@ void CDClientManager::LoadValuesFromDatabase() {
CDCLIENT_DONT_CACHE_TABLE(CDObjectsTable::Instance().LoadValuesFromDatabase()); CDCLIENT_DONT_CACHE_TABLE(CDObjectsTable::Instance().LoadValuesFromDatabase());
CDPhysicsComponentTable::Instance().LoadValuesFromDatabase(); CDPhysicsComponentTable::Instance().LoadValuesFromDatabase();
CDPackageComponentTable::Instance().LoadValuesFromDatabase(); CDPackageComponentTable::Instance().LoadValuesFromDatabase();
CDPetComponentTable::Instance().LoadValuesFromDatabase();
CDProximityMonitorComponentTable::Instance().LoadValuesFromDatabase(); CDProximityMonitorComponentTable::Instance().LoadValuesFromDatabase();
CDPropertyEntranceComponentTable::Instance().LoadValuesFromDatabase(); CDPropertyEntranceComponentTable::Instance().LoadValuesFromDatabase();
CDPropertyTemplateTable::Instance().LoadValuesFromDatabase(); CDPropertyTemplateTable::Instance().LoadValuesFromDatabase();
@@ -155,9 +92,3 @@ void CDClientManager::LoadValuesFromDatabase() {
CDVendorComponentTable::Instance().LoadValuesFromDatabase(); CDVendorComponentTable::Instance().LoadValuesFromDatabase();
CDZoneTableTable::Instance().LoadValuesFromDatabase(); CDZoneTableTable::Instance().LoadValuesFromDatabase();
} }
void CDClientManager::LoadValuesFromDefaults() {
LOG("Loading default CDClient tables!");
CDPetComponentTable::Instance().LoadValuesFromDefaults();
}

View File

@@ -1,14 +1,17 @@
#ifndef __CDCLIENTMANAGER__H__ #pragma once
#define __CDCLIENTMANAGER__H__
#include "CDTable.h"
#include "Singleton.h"
#define UNUSED_TABLE(v) #define UNUSED_TABLE(v)
/** /**
* Initialize the CDClient tables so they are all loaded into memory. * Initialize the CDClient tables so they are all loaded into memory.
*/ */
namespace CDClientManager { class CDClientManager : public Singleton<CDClientManager> {
void LoadValuesFromDatabase(); public:
void LoadValuesFromDefaults(); CDClientManager();
/** /**
* Fetch a table from CDClient * Fetch a table from CDClient
@@ -17,28 +20,7 @@ namespace CDClientManager {
* @return A pointer to the requested table. * @return A pointer to the requested table.
*/ */
template<typename T> template<typename T>
T* GetTable(); T* GetTable() {
return &T::Instance();
/** }
* Fetch a table from CDClient
* Note: Calling this function without a template specialization in CDClientManager.cpp will cause a linker error.
*
* @tparam Table type to fetch
* @return A pointer to the requested table.
*/
template<typename T>
typename T::StorageType& GetEntriesMutable();
}; };
// These are included after the CDClientManager namespace declaration as CDTable as of Jan 29 2024 relies on CDClientManager in Templated code.
#include "CDTable.h"
#include "Singleton.h"
template<typename T>
T* CDClientManager::GetTable() {
return &T::Instance();
};
#endif //!__CDCLIENTMANAGER__H__

View File

@@ -1,9 +1,8 @@
#include "CDActivitiesTable.h" #include "CDActivitiesTable.h"
void CDActivitiesTable::LoadValuesFromDatabase() { void CDActivitiesTable::LoadValuesFromDatabase() {
// First, get the size of the table // First, get the size of the table
uint32_t size = 0; unsigned int size = 0;
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM Activities"); auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM Activities");
while (!tableSize.eof()) { while (!tableSize.eof()) {
size = tableSize.getIntField(0, 0); size = tableSize.getIntField(0, 0);
@@ -14,8 +13,7 @@ void CDActivitiesTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
auto& entries = GetEntriesMutable(); this->entries.reserve(size);
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Activities"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Activities");
@@ -41,7 +39,7 @@ void CDActivitiesTable::LoadValuesFromDatabase() {
entry.noTeamLootOnDeath = tableData.getIntField("noTeamLootOnDeath", -1); entry.noTeamLootOnDeath = tableData.getIntField("noTeamLootOnDeath", -1);
entry.optionalPercentage = tableData.getFloatField("optionalPercentage", -1.0f); entry.optionalPercentage = tableData.getFloatField("optionalPercentage", -1.0f);
entries.push_back(entry); this->entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
@@ -50,7 +48,7 @@ void CDActivitiesTable::LoadValuesFromDatabase() {
std::vector<CDActivities> CDActivitiesTable::Query(std::function<bool(CDActivities)> predicate) { std::vector<CDActivities> CDActivitiesTable::Query(std::function<bool(CDActivities)> predicate) {
std::vector<CDActivities> data = cpplinq::from(GetEntries()) std::vector<CDActivities> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();

View File

@@ -4,31 +4,36 @@
#include "CDTable.h" #include "CDTable.h"
struct CDActivities { struct CDActivities {
uint32_t ActivityID; unsigned int ActivityID;
uint32_t locStatus; unsigned int locStatus;
uint32_t instanceMapID; unsigned int instanceMapID;
uint32_t minTeams; unsigned int minTeams;
uint32_t maxTeams; unsigned int maxTeams;
uint32_t minTeamSize; unsigned int minTeamSize;
uint32_t maxTeamSize; unsigned int maxTeamSize;
uint32_t waitTime; unsigned int waitTime;
uint32_t startDelay; unsigned int startDelay;
bool requiresUniqueData; bool requiresUniqueData;
uint32_t leaderboardType; unsigned int leaderboardType;
bool localize; bool localize;
int32_t optionalCostLOT; int optionalCostLOT;
int32_t optionalCostCount; int optionalCostCount;
bool showUIRewards; bool showUIRewards;
uint32_t CommunityActivityFlagID; unsigned int CommunityActivityFlagID;
std::string gate_version; std::string gate_version;
bool noTeamLootOnDeath; bool noTeamLootOnDeath;
float optionalPercentage; float optionalPercentage;
}; };
class CDActivitiesTable : public CDTable<CDActivitiesTable, std::vector<CDActivities>> { class CDActivitiesTable : public CDTable<CDActivitiesTable> {
private:
std::vector<CDActivities> entries;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
// Queries the table with a custom "where" clause // Queries the table with a custom "where" clause
std::vector<CDActivities> Query(std::function<bool(CDActivities)> predicate); std::vector<CDActivities> Query(std::function<bool(CDActivities)> predicate);
const std::vector<CDActivities>& GetEntries() const { return this->entries; }
}; };

View File

@@ -1,10 +1,9 @@
#include "CDActivityRewardsTable.h" #include "CDActivityRewardsTable.h"
void CDActivityRewardsTable::LoadValuesFromDatabase() { void CDActivityRewardsTable::LoadValuesFromDatabase() {
// First, get the size of the table // First, get the size of the table
uint32_t size = 0; unsigned int size = 0;
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM ActivityRewards"); auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM ActivityRewards");
while (!tableSize.eof()) { while (!tableSize.eof()) {
size = tableSize.getIntField(0, 0); size = tableSize.getIntField(0, 0);
@@ -15,8 +14,7 @@ void CDActivityRewardsTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
auto& entries = GetEntriesMutable(); this->entries.reserve(size);
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ActivityRewards"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ActivityRewards");
@@ -30,7 +28,7 @@ void CDActivityRewardsTable::LoadValuesFromDatabase() {
entry.ChallengeRating = tableData.getIntField("ChallengeRating", -1); entry.ChallengeRating = tableData.getIntField("ChallengeRating", -1);
entry.description = tableData.getStringField("description", ""); entry.description = tableData.getStringField("description", "");
entries.push_back(entry); this->entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
@@ -39,7 +37,7 @@ void CDActivityRewardsTable::LoadValuesFromDatabase() {
std::vector<CDActivityRewards> CDActivityRewardsTable::Query(std::function<bool(CDActivityRewards)> predicate) { std::vector<CDActivityRewards> CDActivityRewardsTable::Query(std::function<bool(CDActivityRewards)> predicate) {
std::vector<CDActivityRewards> data = cpplinq::from(GetEntries()) std::vector<CDActivityRewards> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();

View File

@@ -4,18 +4,24 @@
#include "CDTable.h" #include "CDTable.h"
struct CDActivityRewards { struct CDActivityRewards {
uint32_t objectTemplate; //!< The object template (?) unsigned int objectTemplate; //!< The object template (?)
uint32_t ActivityRewardIndex; //!< The activity reward index unsigned int ActivityRewardIndex; //!< The activity reward index
int32_t activityRating; //!< The activity rating int activityRating; //!< The activity rating
uint32_t LootMatrixIndex; //!< The loot matrix index unsigned int LootMatrixIndex; //!< The loot matrix index
uint32_t CurrencyIndex; //!< The currency index unsigned int CurrencyIndex; //!< The currency index
uint32_t ChallengeRating; //!< The challenge rating unsigned int ChallengeRating; //!< The challenge rating
std::string description; //!< The description std::string description; //!< The description
}; };
class CDActivityRewardsTable : public CDTable<CDActivityRewardsTable, std::vector<CDActivityRewards>> { class CDActivityRewardsTable : public CDTable<CDActivityRewardsTable> {
private:
std::vector<CDActivityRewards> entries;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
// Queries the table with a custom "where" clause // Queries the table with a custom "where" clause
std::vector<CDActivityRewards> Query(std::function<bool(CDActivityRewards)> predicate); std::vector<CDActivityRewards> Query(std::function<bool(CDActivityRewards)> predicate);
std::vector<CDActivityRewards> GetEntries() const;
}; };

View File

@@ -5,7 +5,6 @@
void CDAnimationsTable::LoadValuesFromDatabase() { void CDAnimationsTable::LoadValuesFromDatabase() {
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Animations"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Animations");
auto& animations = GetEntriesMutable();
while (!tableData.eof()) { while (!tableData.eof()) {
std::string animation_type = tableData.getStringField("animation_type", ""); std::string animation_type = tableData.getStringField("animation_type", "");
DluAssert(!animation_type.empty()); DluAssert(!animation_type.empty());
@@ -25,7 +24,7 @@ void CDAnimationsTable::LoadValuesFromDatabase() {
UNUSED_COLUMN(entry.priority = tableData.getFloatField("priority", 0.0f);) UNUSED_COLUMN(entry.priority = tableData.getFloatField("priority", 0.0f);)
UNUSED_COLUMN(entry.blendTime = tableData.getFloatField("blendTime", 0.0f);) UNUSED_COLUMN(entry.blendTime = tableData.getFloatField("blendTime", 0.0f);)
animations[CDAnimationKey(animation_type, animationGroupID)].push_back(entry); this->animations[CDAnimationKey(animation_type, animationGroupID)].push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
@@ -36,7 +35,6 @@ bool CDAnimationsTable::CacheData(CppSQLite3Statement& queryToCache) {
auto tableData = queryToCache.execQuery(); auto tableData = queryToCache.execQuery();
// If we received a bad lookup, cache it anyways so we do not run the query again. // If we received a bad lookup, cache it anyways so we do not run the query again.
if (tableData.eof()) return false; if (tableData.eof()) return false;
auto& animations = GetEntriesMutable();
do { do {
std::string animation_type = tableData.getStringField("animation_type", ""); std::string animation_type = tableData.getStringField("animation_type", "");
@@ -57,7 +55,7 @@ bool CDAnimationsTable::CacheData(CppSQLite3Statement& queryToCache) {
UNUSED_COLUMN(entry.priority = tableData.getFloatField("priority", 0.0f);) UNUSED_COLUMN(entry.priority = tableData.getFloatField("priority", 0.0f);)
UNUSED_COLUMN(entry.blendTime = tableData.getFloatField("blendTime", 0.0f);) UNUSED_COLUMN(entry.blendTime = tableData.getFloatField("blendTime", 0.0f);)
animations[CDAnimationKey(animation_type, animationGroupID)].push_back(entry); this->animations[CDAnimationKey(animation_type, animationGroupID)].push_back(entry);
tableData.nextRow(); tableData.nextRow();
} while (!tableData.eof()); } while (!tableData.eof());
@@ -70,17 +68,15 @@ void CDAnimationsTable::CacheAnimations(const CDAnimationKey animationKey) {
auto query = CDClientDatabase::CreatePreppedStmt("SELECT * FROM Animations WHERE animationGroupID = ? and animation_type = ?"); auto query = CDClientDatabase::CreatePreppedStmt("SELECT * FROM Animations WHERE animationGroupID = ? and animation_type = ?");
query.bind(1, static_cast<int32_t>(animationKey.second)); query.bind(1, static_cast<int32_t>(animationKey.second));
query.bind(2, animationKey.first.c_str()); query.bind(2, animationKey.first.c_str());
auto& animations = GetEntriesMutable();
// If we received a bad lookup, cache it anyways so we do not run the query again. // If we received a bad lookup, cache it anyways so we do not run the query again.
if (!CacheData(query)) { if (!CacheData(query)) {
animations[animationKey]; this->animations[animationKey];
} }
} }
void CDAnimationsTable::CacheAnimationGroup(AnimationGroupID animationGroupID) { void CDAnimationsTable::CacheAnimationGroup(AnimationGroupID animationGroupID) {
auto& animations = GetEntriesMutable(); auto animationEntryCached = this->animations.find(CDAnimationKey("", animationGroupID));
auto animationEntryCached = animations.find(CDAnimationKey("", animationGroupID)); if (animationEntryCached != this->animations.end()) {
if (animationEntryCached != animations.end()) {
return; return;
} }
@@ -89,29 +85,28 @@ void CDAnimationsTable::CacheAnimationGroup(AnimationGroupID animationGroupID) {
// Cache the query so we don't run the query again. // Cache the query so we don't run the query again.
CacheData(query); CacheData(query);
animations[CDAnimationKey("", animationGroupID)]; this->animations[CDAnimationKey("", animationGroupID)];
} }
std::optional<CDAnimation> CDAnimationsTable::GetAnimation(const AnimationID& animationType, const std::string& previousAnimationName, const AnimationGroupID animationGroupID) { CDAnimationLookupResult CDAnimationsTable::GetAnimation(const AnimationID& animationType, const std::string& previousAnimationName, const AnimationGroupID animationGroupID) {
auto& animations = GetEntriesMutable();
CDAnimationKey animationKey(animationType, animationGroupID); CDAnimationKey animationKey(animationType, animationGroupID);
auto animationEntryCached = animations.find(animationKey); auto animationEntryCached = this->animations.find(animationKey);
if (animationEntryCached == animations.end()) { if (animationEntryCached == this->animations.end()) {
this->CacheAnimations(animationKey); this->CacheAnimations(animationKey);
} }
auto animationEntry = animations.find(animationKey); auto animationEntry = this->animations.find(animationKey);
// If we have only one animation, return it regardless of the chance to play. // If we have only one animation, return it regardless of the chance to play.
if (animationEntry->second.size() == 1) { if (animationEntry->second.size() == 1) {
return animationEntry->second.front(); return CDAnimationLookupResult(animationEntry->second.front());
} }
auto randomAnimation = GeneralUtils::GenerateRandomNumber<float>(0, 1); auto randomAnimation = GeneralUtils::GenerateRandomNumber<float>(0, 1);
for (auto& animationEntry : animationEntry->second) { for (auto& animationEntry : animationEntry->second) {
randomAnimation -= animationEntry.chance_to_play; randomAnimation -= animationEntry.chance_to_play;
// This is how the client gets the random animation. // This is how the client gets the random animation.
if (animationEntry.animation_name != previousAnimationName && randomAnimation <= 0.0f) return animationEntry; if (animationEntry.animation_name != previousAnimationName && randomAnimation <= 0.0f) return CDAnimationLookupResult(animationEntry);
} }
return std::nullopt; return CDAnimationLookupResult();
} }

View File

@@ -2,20 +2,15 @@
#include "CDTable.h" #include "CDTable.h"
#include <list> #include <list>
#include <optional>
typedef int32_t AnimationGroupID;
typedef std::string AnimationID;
typedef std::pair<std::string, AnimationGroupID> CDAnimationKey;
struct CDAnimation { struct CDAnimation {
// uint32_t animationGroupID; // unsigned int animationGroupID;
// std::string animation_type; // std::string animation_type;
// The above two are a pair to represent a primary key in the map. // The above two are a pair to represent a primary key in the map.
std::string animation_name; //!< The animation name std::string animation_name; //!< The animation name
float chance_to_play; //!< The chance to play the animation float chance_to_play; //!< The chance to play the animation
UNUSED_COLUMN(uint32_t min_loops;) //!< The minimum number of loops UNUSED_COLUMN(unsigned int min_loops;) //!< The minimum number of loops
UNUSED_COLUMN(uint32_t max_loops;) //!< The maximum number of loops UNUSED_COLUMN(unsigned int max_loops;) //!< The maximum number of loops
float animation_length; //!< The animation length float animation_length; //!< The animation length
UNUSED_COLUMN(bool hideEquip;) //!< Whether or not to hide the equip UNUSED_COLUMN(bool hideEquip;) //!< Whether or not to hide the equip
UNUSED_COLUMN(bool ignoreUpperBody;) //!< Whether or not to ignore the upper body UNUSED_COLUMN(bool ignoreUpperBody;) //!< Whether or not to ignore the upper body
@@ -25,7 +20,12 @@ struct CDAnimation {
UNUSED_COLUMN(float blendTime;) //!< The blend time UNUSED_COLUMN(float blendTime;) //!< The blend time
}; };
class CDAnimationsTable : public CDTable<CDAnimationsTable, std::map<CDAnimationKey, std::list<CDAnimation>>> { typedef LookupResult<CDAnimation> CDAnimationLookupResult;
class CDAnimationsTable : public CDTable<CDAnimationsTable> {
typedef int32_t AnimationGroupID;
typedef std::string AnimationID;
typedef std::pair<std::string, AnimationGroupID> CDAnimationKey;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
/** /**
@@ -38,7 +38,7 @@ public:
* @param animationGroupID The animationGroupID to lookup * @param animationGroupID The animationGroupID to lookup
* @return CDAnimationLookupResult * @return CDAnimationLookupResult
*/ */
[[nodiscard]] std::optional<CDAnimation> GetAnimation(const AnimationID& animationType, const std::string& previousAnimationName, const AnimationGroupID animationGroupID); [[nodiscard]] CDAnimationLookupResult GetAnimation(const AnimationID& animationType, const std::string& previousAnimationName, const AnimationGroupID animationGroupID);
/** /**
* Cache a full AnimationGroup by its ID. * Cache a full AnimationGroup by its ID.
@@ -58,4 +58,10 @@ private:
* @return false * @return false
*/ */
bool CacheData(CppSQLite3Statement& queryToCache); bool CacheData(CppSQLite3Statement& queryToCache);
/**
* Each animation is key'd by its animationName and its animationGroupID. Each
* animation has a possible list of animations. This is because there can be animations have a percent chance to play so one is selected at random.
*/
std::map<CDAnimationKey, std::list<CDAnimation>> animations;
}; };

View File

@@ -1,10 +1,6 @@
#include "CDBehaviorParameterTable.h" #include "CDBehaviorParameterTable.h"
#include "GeneralUtils.h" #include "GeneralUtils.h"
namespace {
std::unordered_map<std::string, uint32_t> m_ParametersList;
};
uint64_t GetKey(const uint32_t behaviorID, const uint32_t parameterID) { uint64_t GetKey(const uint32_t behaviorID, const uint32_t parameterID) {
uint64_t key = behaviorID; uint64_t key = behaviorID;
key <<= 31U; key <<= 31U;
@@ -15,7 +11,6 @@ uint64_t GetKey(const uint32_t behaviorID, const uint32_t parameterID) {
void CDBehaviorParameterTable::LoadValuesFromDatabase() { void CDBehaviorParameterTable::LoadValuesFromDatabase() {
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorParameter"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorParameter");
auto& entries = GetEntriesMutable();
while (!tableData.eof()) { while (!tableData.eof()) {
uint32_t behaviorID = tableData.getIntField("behaviorID", -1); uint32_t behaviorID = tableData.getIntField("behaviorID", -1);
auto candidateStringToAdd = std::string(tableData.getStringField("parameterID", "")); auto candidateStringToAdd = std::string(tableData.getStringField("parameterID", ""));
@@ -29,7 +24,7 @@ void CDBehaviorParameterTable::LoadValuesFromDatabase() {
uint64_t hash = GetKey(behaviorID, parameterId); uint64_t hash = GetKey(behaviorID, parameterId);
float value = tableData.getFloatField("value", -1.0f); float value = tableData.getFloatField("value", -1.0f);
entries.insert(std::make_pair(hash, value)); m_Entries.insert(std::make_pair(hash, value));
tableData.nextRow(); tableData.nextRow();
} }
@@ -37,24 +32,22 @@ void CDBehaviorParameterTable::LoadValuesFromDatabase() {
} }
float CDBehaviorParameterTable::GetValue(const uint32_t behaviorID, const std::string& name, const float defaultValue) { float CDBehaviorParameterTable::GetValue(const uint32_t behaviorID, const std::string& name, const float defaultValue) {
auto parameterID = m_ParametersList.find(name); auto parameterID = this->m_ParametersList.find(name);
if (parameterID == m_ParametersList.end()) return defaultValue; if (parameterID == this->m_ParametersList.end()) return defaultValue;
auto hash = GetKey(behaviorID, parameterID->second); auto hash = GetKey(behaviorID, parameterID->second);
// Search for specific parameter // Search for specific parameter
auto& entries = GetEntriesMutable(); auto it = m_Entries.find(hash);
auto it = entries.find(hash); return it != m_Entries.end() ? it->second : defaultValue;
return it != entries.end() ? it->second : defaultValue;
} }
std::map<std::string, float> CDBehaviorParameterTable::GetParametersByBehaviorID(uint32_t behaviorID) { std::map<std::string, float> CDBehaviorParameterTable::GetParametersByBehaviorID(uint32_t behaviorID) {
auto& entries = GetEntriesMutable();
uint64_t hashBase = behaviorID; uint64_t hashBase = behaviorID;
std::map<std::string, float> returnInfo; std::map<std::string, float> returnInfo;
for (auto& [parameterString, parameterId] : m_ParametersList) { for (auto& [parameterString, parameterId] : m_ParametersList) {
uint64_t hash = GetKey(hashBase, parameterId); uint64_t hash = GetKey(hashBase, parameterId);
auto infoCandidate = entries.find(hash); auto infoCandidate = m_Entries.find(hash);
if (infoCandidate != entries.end()) { if (infoCandidate != m_Entries.end()) {
returnInfo.insert(std::make_pair(parameterString, infoCandidate->second)); returnInfo.insert(std::make_pair(parameterString, infoCandidate->second));
} }
} }

View File

@@ -5,10 +5,12 @@
#include <unordered_map> #include <unordered_map>
#include <unordered_set> #include <unordered_set>
typedef uint64_t BehaviorParameterHash; class CDBehaviorParameterTable : public CDTable<CDBehaviorParameterTable> {
typedef float BehaviorParameterValue; private:
typedef uint64_t BehaviorParameterHash;
class CDBehaviorParameterTable : public CDTable<CDBehaviorParameterTable, std::unordered_map<BehaviorParameterHash, BehaviorParameterValue>> { typedef float BehaviorParameterValue;
std::unordered_map<BehaviorParameterHash, BehaviorParameterValue> m_Entries;
std::unordered_map<std::string, uint32_t> m_ParametersList;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();

View File

@@ -1,13 +1,9 @@
#include "CDBehaviorTemplateTable.h" #include "CDBehaviorTemplateTable.h"
namespace {
std::unordered_set<std::string> m_EffectHandles;
};
void CDBehaviorTemplateTable::LoadValuesFromDatabase() { void CDBehaviorTemplateTable::LoadValuesFromDatabase() {
// First, get the size of the table // First, get the size of the table
uint32_t size = 0; unsigned int size = 0;
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM BehaviorTemplate"); auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM BehaviorTemplate");
while (!tableSize.eof()) { while (!tableSize.eof()) {
size = tableSize.getIntField(0, 0); size = tableSize.getIntField(0, 0);
@@ -17,9 +13,11 @@ void CDBehaviorTemplateTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size
this->entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorTemplate"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorTemplate");
auto& entries = GetEntriesMutable();
while (!tableData.eof()) { while (!tableData.eof()) {
CDBehaviorTemplate entry; CDBehaviorTemplate entry;
entry.behaviorID = tableData.getIntField("behaviorID", -1); entry.behaviorID = tableData.getIntField("behaviorID", -1);
@@ -33,17 +31,30 @@ void CDBehaviorTemplateTable::LoadValuesFromDatabase() {
entry.effectHandle = m_EffectHandles.insert(candidateToAdd).first; entry.effectHandle = m_EffectHandles.insert(candidateToAdd).first;
} }
entries.insert(std::make_pair(entry.behaviorID, entry)); this->entries.push_back(entry);
this->entriesMappedByBehaviorID.insert(std::make_pair(entry.behaviorID, entry));
tableData.nextRow(); tableData.nextRow();
} }
tableData.finalize(); tableData.finalize();
} }
std::vector<CDBehaviorTemplate> CDBehaviorTemplateTable::Query(std::function<bool(CDBehaviorTemplate)> predicate) {
std::vector<CDBehaviorTemplate> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate)
>> cpplinq::to_vector();
return data;
}
const std::vector<CDBehaviorTemplate>& CDBehaviorTemplateTable::GetEntries() const {
return this->entries;
}
const CDBehaviorTemplate CDBehaviorTemplateTable::GetByBehaviorID(uint32_t behaviorID) { const CDBehaviorTemplate CDBehaviorTemplateTable::GetByBehaviorID(uint32_t behaviorID) {
auto& entries = GetEntriesMutable(); auto entry = this->entriesMappedByBehaviorID.find(behaviorID);
auto entry = entries.find(behaviorID); if (entry == this->entriesMappedByBehaviorID.end()) {
if (entry == entries.end()) {
CDBehaviorTemplate entryToReturn; CDBehaviorTemplate entryToReturn;
entryToReturn.behaviorID = 0; entryToReturn.behaviorID = 0;
entryToReturn.effectHandle = m_EffectHandles.end(); entryToReturn.effectHandle = m_EffectHandles.end();

View File

@@ -6,15 +6,25 @@
#include <unordered_set> #include <unordered_set>
struct CDBehaviorTemplate { struct CDBehaviorTemplate {
uint32_t behaviorID; //!< The Behavior ID unsigned int behaviorID; //!< The Behavior ID
uint32_t templateID; //!< The Template ID (LOT) unsigned int templateID; //!< The Template ID (LOT)
uint32_t effectID; //!< The Effect ID attached unsigned int effectID; //!< The Effect ID attached
std::unordered_set<std::string>::iterator effectHandle; //!< The effect handle std::unordered_set<std::string>::iterator effectHandle; //!< The effect handle
}; };
class CDBehaviorTemplateTable : public CDTable<CDBehaviorTemplateTable, std::unordered_map<uint32_t, CDBehaviorTemplate>> {
class CDBehaviorTemplateTable : public CDTable<CDBehaviorTemplateTable> {
private:
std::vector<CDBehaviorTemplate> entries;
std::unordered_map<uint32_t, CDBehaviorTemplate> entriesMappedByBehaviorID;
std::unordered_set<std::string> m_EffectHandles;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
// Queries the table with a custom "where" clause
std::vector<CDBehaviorTemplate> Query(std::function<bool(CDBehaviorTemplate)> predicate);
const std::vector<CDBehaviorTemplate>& GetEntries(void) const;
const CDBehaviorTemplate GetByBehaviorID(uint32_t behaviorID); const CDBehaviorTemplate GetByBehaviorID(uint32_t behaviorID);
}; };

View File

@@ -3,7 +3,7 @@
void CDBrickIDTableTable::LoadValuesFromDatabase() { void CDBrickIDTableTable::LoadValuesFromDatabase() {
// First, get the size of the table // First, get the size of the table
uint32_t size = 0; unsigned int size = 0;
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM BrickIDTable"); auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM BrickIDTable");
while (!tableSize.eof()) { while (!tableSize.eof()) {
size = tableSize.getIntField(0, 0); size = tableSize.getIntField(0, 0);
@@ -14,8 +14,7 @@ void CDBrickIDTableTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
auto& entries = GetEntriesMutable(); this->entries.reserve(size);
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BrickIDTable"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BrickIDTable");
@@ -24,7 +23,7 @@ void CDBrickIDTableTable::LoadValuesFromDatabase() {
entry.NDObjectID = tableData.getIntField("NDObjectID", -1); entry.NDObjectID = tableData.getIntField("NDObjectID", -1);
entry.LEGOBrickID = tableData.getIntField("LEGOBrickID", -1); entry.LEGOBrickID = tableData.getIntField("LEGOBrickID", -1);
entries.push_back(entry); this->entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
@@ -32,9 +31,15 @@ void CDBrickIDTableTable::LoadValuesFromDatabase() {
} }
std::vector<CDBrickIDTable> CDBrickIDTableTable::Query(std::function<bool(CDBrickIDTable)> predicate) { std::vector<CDBrickIDTable> CDBrickIDTableTable::Query(std::function<bool(CDBrickIDTable)> predicate) {
std::vector<CDBrickIDTable> data = cpplinq::from(GetEntries())
std::vector<CDBrickIDTable> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();
return data; return data;
} }
const std::vector<CDBrickIDTable>& CDBrickIDTableTable::GetEntries() const {
return this->entries;
}

View File

@@ -10,15 +10,20 @@
//! BrickIDTable Entry Struct //! BrickIDTable Entry Struct
struct CDBrickIDTable { struct CDBrickIDTable {
uint32_t NDObjectID; unsigned int NDObjectID;
uint32_t LEGOBrickID; unsigned int LEGOBrickID;
}; };
//! BrickIDTable table //! BrickIDTable table
class CDBrickIDTableTable : public CDTable<CDBrickIDTableTable, std::vector<CDBrickIDTable>> { class CDBrickIDTableTable : public CDTable<CDBrickIDTableTable> {
private:
std::vector<CDBrickIDTable> entries;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
// Queries the table with a custom "where" clause // Queries the table with a custom "where" clause
std::vector<CDBrickIDTable> Query(std::function<bool(CDBrickIDTable)> predicate); std::vector<CDBrickIDTable> Query(std::function<bool(CDBrickIDTable)> predicate);
const std::vector<CDBrickIDTable>& GetEntries() const;
}; };

View File

@@ -4,15 +4,14 @@
void CDComponentsRegistryTable::LoadValuesFromDatabase() { void CDComponentsRegistryTable::LoadValuesFromDatabase() {
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ComponentsRegistry"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ComponentsRegistry");
auto& entries = GetEntriesMutable();
while (!tableData.eof()) { while (!tableData.eof()) {
CDComponentsRegistry entry; CDComponentsRegistry entry;
entry.id = tableData.getIntField("id", -1); entry.id = tableData.getIntField("id", -1);
entry.component_type = static_cast<eReplicaComponentType>(tableData.getIntField("component_type", 0)); entry.component_type = static_cast<eReplicaComponentType>(tableData.getIntField("component_type", 0));
entry.component_id = tableData.getIntField("component_id", -1); entry.component_id = tableData.getIntField("component_id", -1);
entries.insert_or_assign(static_cast<uint64_t>(entry.component_type) << 32 | static_cast<uint64_t>(entry.id), entry.component_id); this->mappedEntries.insert_or_assign(static_cast<uint64_t>(entry.component_type) << 32 | static_cast<uint64_t>(entry.id), entry.component_id);
entries.insert_or_assign(entry.id, 0); this->mappedEntries.insert_or_assign(entry.id, 0);
tableData.nextRow(); tableData.nextRow();
} }
@@ -21,11 +20,10 @@ void CDComponentsRegistryTable::LoadValuesFromDatabase() {
} }
int32_t CDComponentsRegistryTable::GetByIDAndType(uint32_t id, eReplicaComponentType componentType, int32_t defaultValue) { int32_t CDComponentsRegistryTable::GetByIDAndType(uint32_t id, eReplicaComponentType componentType, int32_t defaultValue) {
auto& entries = GetEntriesMutable(); auto exists = mappedEntries.find(id);
auto exists = entries.find(id); if (exists != mappedEntries.end()) {
if (exists != entries.end()) { auto iter = mappedEntries.find(static_cast<uint64_t>(componentType) << 32 | static_cast<uint64_t>(id));
auto iter = entries.find(static_cast<uint64_t>(componentType) << 32 | static_cast<uint64_t>(id)); return iter == mappedEntries.end() ? defaultValue : iter->second;
return iter == entries.end() ? defaultValue : iter->second;
} }
// Now get the data. Get all components of this entity so we dont do a query for each component // Now get the data. Get all components of this entity so we dont do a query for each component
@@ -40,14 +38,14 @@ int32_t CDComponentsRegistryTable::GetByIDAndType(uint32_t id, eReplicaComponent
entry.component_type = static_cast<eReplicaComponentType>(tableData.getIntField("component_type", 0)); entry.component_type = static_cast<eReplicaComponentType>(tableData.getIntField("component_type", 0));
entry.component_id = tableData.getIntField("component_id", -1); entry.component_id = tableData.getIntField("component_id", -1);
entries.insert_or_assign(static_cast<uint64_t>(entry.component_type) << 32 | static_cast<uint64_t>(entry.id), entry.component_id); this->mappedEntries.insert_or_assign(static_cast<uint64_t>(entry.component_type) << 32 | static_cast<uint64_t>(entry.id), entry.component_id);
tableData.nextRow(); tableData.nextRow();
} }
entries.insert_or_assign(id, 0); mappedEntries.insert_or_assign(id, 0);
auto iter = entries.find(static_cast<uint64_t>(componentType) << 32 | static_cast<uint64_t>(id)); auto iter = this->mappedEntries.find(static_cast<uint64_t>(componentType) << 32 | static_cast<uint64_t>(id));
return iter == entries.end() ? defaultValue : iter->second; return iter == this->mappedEntries.end() ? defaultValue : iter->second;
} }

View File

@@ -7,13 +7,16 @@
enum class eReplicaComponentType : uint32_t; enum class eReplicaComponentType : uint32_t;
struct CDComponentsRegistry { struct CDComponentsRegistry {
uint32_t id; //!< The LOT is used as the ID unsigned int id; //!< The LOT is used as the ID
eReplicaComponentType component_type; //!< See ComponentTypes enum for values eReplicaComponentType component_type; //!< See ComponentTypes enum for values
uint32_t component_id; //!< The ID used within the component's table (0 may either mean it's non-networked, or that the ID is actually 0 unsigned int component_id; //!< The ID used within the component's table (0 may either mean it's non-networked, or that the ID is actually 0
}; };
class CDComponentsRegistryTable : public CDTable<CDComponentsRegistryTable, std::unordered_map<uint64_t, uint32_t>> { class CDComponentsRegistryTable : public CDTable<CDComponentsRegistryTable> {
private:
std::unordered_map<uint64_t, uint32_t> mappedEntries; //id, component_type, component_id
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
int32_t GetByIDAndType(uint32_t id, eReplicaComponentType componentType, int32_t defaultValue = 0); int32_t GetByIDAndType(uint32_t id, eReplicaComponentType componentType, int32_t defaultValue = 0);

View File

@@ -4,7 +4,7 @@
void CDCurrencyTableTable::LoadValuesFromDatabase() { void CDCurrencyTableTable::LoadValuesFromDatabase() {
// First, get the size of the table // First, get the size of the table
uint32_t size = 0; unsigned int size = 0;
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM CurrencyTable"); auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM CurrencyTable");
while (!tableSize.eof()) { while (!tableSize.eof()) {
size = tableSize.getIntField(0, 0); size = tableSize.getIntField(0, 0);
@@ -15,8 +15,7 @@ void CDCurrencyTableTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
auto& entries = GetEntriesMutable(); this->entries.reserve(size);
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM CurrencyTable"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM CurrencyTable");
@@ -28,7 +27,7 @@ void CDCurrencyTableTable::LoadValuesFromDatabase() {
entry.maxvalue = tableData.getIntField("maxvalue", -1); entry.maxvalue = tableData.getIntField("maxvalue", -1);
entry.id = tableData.getIntField("id", -1); entry.id = tableData.getIntField("id", -1);
entries.push_back(entry); this->entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
@@ -36,9 +35,15 @@ void CDCurrencyTableTable::LoadValuesFromDatabase() {
} }
std::vector<CDCurrencyTable> CDCurrencyTableTable::Query(std::function<bool(CDCurrencyTable)> predicate) { std::vector<CDCurrencyTable> CDCurrencyTableTable::Query(std::function<bool(CDCurrencyTable)> predicate) {
std::vector<CDCurrencyTable> data = cpplinq::from(GetEntries())
std::vector<CDCurrencyTable> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();
return data; return data;
} }
const std::vector<CDCurrencyTable>& CDCurrencyTableTable::GetEntries() const {
return this->entries;
}

View File

@@ -10,17 +10,22 @@
//! CurrencyTable Struct //! CurrencyTable Struct
struct CDCurrencyTable { struct CDCurrencyTable {
uint32_t currencyIndex; //!< The Currency Index unsigned int currencyIndex; //!< The Currency Index
uint32_t npcminlevel; //!< The minimum level of the npc unsigned int npcminlevel; //!< The minimum level of the npc
uint32_t minvalue; //!< The minimum currency unsigned int minvalue; //!< The minimum currency
uint32_t maxvalue; //!< The maximum currency unsigned int maxvalue; //!< The maximum currency
uint32_t id; //!< The ID of the currency index unsigned int id; //!< The ID of the currency index
}; };
//! CurrencyTable table //! CurrencyTable table
class CDCurrencyTableTable : public CDTable<CDCurrencyTableTable, std::vector<CDCurrencyTable>> { class CDCurrencyTableTable : public CDTable<CDCurrencyTableTable> {
private:
std::vector<CDCurrencyTable> entries;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
// Queries the table with a custom "where" clause // Queries the table with a custom "where" clause
std::vector<CDCurrencyTable> Query(std::function<bool(CDCurrencyTable)> predicate); std::vector<CDCurrencyTable> Query(std::function<bool(CDCurrencyTable)> predicate);
const std::vector<CDCurrencyTable>& GetEntries() const;
}; };

View File

@@ -2,7 +2,7 @@
void CDDestructibleComponentTable::LoadValuesFromDatabase() { void CDDestructibleComponentTable::LoadValuesFromDatabase() {
// First, get the size of the table // First, get the size of the table
uint32_t size = 0; unsigned int size = 0;
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM DestructibleComponent"); auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM DestructibleComponent");
while (!tableSize.eof()) { while (!tableSize.eof()) {
size = tableSize.getIntField(0, 0); size = tableSize.getIntField(0, 0);
@@ -13,8 +13,7 @@ void CDDestructibleComponentTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
auto& entries = GetEntriesMutable(); this->entries.reserve(size);
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM DestructibleComponent"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM DestructibleComponent");
@@ -35,7 +34,7 @@ void CDDestructibleComponentTable::LoadValuesFromDatabase() {
entry.isSmashable = tableData.getIntField("isSmashable", -1) == 1 ? true : false; entry.isSmashable = tableData.getIntField("isSmashable", -1) == 1 ? true : false;
entry.difficultyLevel = tableData.getIntField("difficultyLevel", -1); entry.difficultyLevel = tableData.getIntField("difficultyLevel", -1);
entries.push_back(entry); this->entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
@@ -43,9 +42,15 @@ void CDDestructibleComponentTable::LoadValuesFromDatabase() {
} }
std::vector<CDDestructibleComponent> CDDestructibleComponentTable::Query(std::function<bool(CDDestructibleComponent)> predicate) { std::vector<CDDestructibleComponent> CDDestructibleComponentTable::Query(std::function<bool(CDDestructibleComponent)> predicate) {
std::vector<CDDestructibleComponent> data = cpplinq::from(GetEntries())
std::vector<CDDestructibleComponent> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();
return data; return data;
} }
const std::vector<CDDestructibleComponent>& CDDestructibleComponentTable::GetEntries() const {
return this->entries;
}

View File

@@ -4,25 +4,30 @@
#include "CDTable.h" #include "CDTable.h"
struct CDDestructibleComponent { struct CDDestructibleComponent {
uint32_t id; //!< The component ID from the ComponentsRegistry Table unsigned int id; //!< The component ID from the ComponentsRegistry Table
int32_t faction; //!< The Faction ID of the object int faction; //!< The Faction ID of the object
std::string factionList; //!< A list of the faction IDs std::string factionList; //!< A list of the faction IDs
int32_t life; //!< The amount of life of the object int life; //!< The amount of life of the object
uint32_t imagination; //!< The amount of imagination of the object unsigned int imagination; //!< The amount of imagination of the object
int32_t LootMatrixIndex; //!< The Loot Matrix Index int LootMatrixIndex; //!< The Loot Matrix Index
int32_t CurrencyIndex; //!< The Currency Index int CurrencyIndex; //!< The Currency Index
uint32_t level; //!< ??? unsigned int level; //!< ???
float armor; //!< The amount of armor of the object float armor; //!< The amount of armor of the object
uint32_t death_behavior; //!< The behavior ID of the death behavior unsigned int death_behavior; //!< The behavior ID of the death behavior
bool isnpc; //!< Whether or not the object is an NPC bool isnpc; //!< Whether or not the object is an NPC
uint32_t attack_priority; //!< ??? unsigned int attack_priority; //!< ???
bool isSmashable; //!< Whether or not the object is smashable bool isSmashable; //!< Whether or not the object is smashable
int32_t difficultyLevel; //!< ??? int difficultyLevel; //!< ???
}; };
class CDDestructibleComponentTable : public CDTable<CDDestructibleComponentTable, std::vector<CDDestructibleComponent>> { class CDDestructibleComponentTable : public CDTable<CDDestructibleComponentTable> {
private:
std::vector<CDDestructibleComponent> entries;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
// Queries the table with a custom "where" clause // Queries the table with a custom "where" clause
std::vector<CDDestructibleComponent> Query(std::function<bool(CDDestructibleComponent)> predicate); std::vector<CDDestructibleComponent> Query(std::function<bool(CDDestructibleComponent)> predicate);
const std::vector<CDDestructibleComponent>& GetEntries(void) const;
}; };

View File

@@ -2,7 +2,6 @@
void CDEmoteTableTable::LoadValuesFromDatabase() { void CDEmoteTableTable::LoadValuesFromDatabase() {
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Emotes"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Emotes");
auto& entries = GetEntriesMutable();
while (!tableData.eof()) { while (!tableData.eof()) {
CDEmoteTable entry; CDEmoteTable entry;
entry.ID = tableData.getIntField("id", -1); entry.ID = tableData.getIntField("id", -1);
@@ -21,8 +20,7 @@ void CDEmoteTableTable::LoadValuesFromDatabase() {
tableData.finalize(); tableData.finalize();
} }
CDEmoteTable* CDEmoteTableTable::GetEmote(int32_t id) { CDEmoteTable* CDEmoteTableTable::GetEmote(int id) {
auto& entries = GetEntriesMutable();
auto itr = entries.find(id); auto itr = entries.find(id);
return itr != entries.end() ? &itr->second : nullptr; return itr != entries.end() ? &itr->second : nullptr;
} }

View File

@@ -16,19 +16,22 @@ struct CDEmoteTable {
gateVersion = ""; gateVersion = "";
} }
int32_t ID; int ID;
std::string animationName; std::string animationName;
std::string iconFilename; std::string iconFilename;
int32_t locState; int locState;
int32_t channel; int channel;
bool locked; bool locked;
bool localize; bool localize;
std::string gateVersion; std::string gateVersion;
}; };
class CDEmoteTableTable : public CDTable<CDEmoteTableTable, std::map<int, CDEmoteTable>> { class CDEmoteTableTable : public CDTable<CDEmoteTableTable> {
private:
std::map<int, CDEmoteTable> entries;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
// Returns an emote by ID // Returns an emote by ID
CDEmoteTable* GetEmote(int32_t id); CDEmoteTable* GetEmote(int id);
}; };

View File

@@ -3,7 +3,7 @@
void CDFeatureGatingTable::LoadValuesFromDatabase() { void CDFeatureGatingTable::LoadValuesFromDatabase() {
// First, get the size of the table // First, get the size of the table
uint32_t size = 0; unsigned int size = 0;
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM FeatureGating"); auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM FeatureGating");
while (!tableSize.eof()) { while (!tableSize.eof()) {
size = tableSize.getIntField(0, 0); size = tableSize.getIntField(0, 0);
@@ -14,8 +14,7 @@ void CDFeatureGatingTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
auto& entries = GetEntriesMutable(); this->entries.reserve(size);
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM FeatureGating"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM FeatureGating");
@@ -27,7 +26,7 @@ void CDFeatureGatingTable::LoadValuesFromDatabase() {
entry.minor = tableData.getIntField("minor", -1); entry.minor = tableData.getIntField("minor", -1);
entry.description = tableData.getStringField("description", ""); entry.description = tableData.getStringField("description", "");
entries.push_back(entry); this->entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
@@ -36,8 +35,7 @@ void CDFeatureGatingTable::LoadValuesFromDatabase() {
std::vector<CDFeatureGating> CDFeatureGatingTable::Query(std::function<bool(CDFeatureGating)> predicate) { std::vector<CDFeatureGating> CDFeatureGatingTable::Query(std::function<bool(CDFeatureGating)> predicate) {
auto& entries = GetEntriesMutable(); std::vector<CDFeatureGating> data = cpplinq::from(this->entries)
std::vector<CDFeatureGating> data = cpplinq::from(entries)
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();
@@ -45,7 +43,6 @@ std::vector<CDFeatureGating> CDFeatureGatingTable::Query(std::function<bool(CDFe
} }
bool CDFeatureGatingTable::FeatureUnlocked(const CDFeatureGating& feature) const { bool CDFeatureGatingTable::FeatureUnlocked(const CDFeatureGating& feature) const {
auto& entries = GetEntriesMutable();
for (const auto& entry : entries) { for (const auto& entry : entries) {
if (entry.featureName == feature.featureName && feature >= entry) { if (entry.featureName == feature.featureName && feature >= entry) {
return true; return true;
@@ -54,3 +51,8 @@ bool CDFeatureGatingTable::FeatureUnlocked(const CDFeatureGating& feature) const
return false; return false;
} }
const std::vector<CDFeatureGating>& CDFeatureGatingTable::GetEntries() const {
return this->entries;
}

View File

@@ -17,7 +17,10 @@ struct CDFeatureGating {
} }
}; };
class CDFeatureGatingTable : public CDTable<CDFeatureGatingTable, std::vector<CDFeatureGating>> { class CDFeatureGatingTable : public CDTable<CDFeatureGatingTable> {
private:
std::vector<CDFeatureGating> entries;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
@@ -25,4 +28,6 @@ public:
std::vector<CDFeatureGating> Query(std::function<bool(CDFeatureGating)> predicate); std::vector<CDFeatureGating> Query(std::function<bool(CDFeatureGating)> predicate);
bool FeatureUnlocked(const CDFeatureGating& feature) const; bool FeatureUnlocked(const CDFeatureGating& feature) const;
const std::vector<CDFeatureGating>& GetEntries(void) const;
}; };

View File

@@ -3,7 +3,7 @@
void CDInventoryComponentTable::LoadValuesFromDatabase() { void CDInventoryComponentTable::LoadValuesFromDatabase() {
// First, get the size of the table // First, get the size of the table
uint32_t size = 0; unsigned int size = 0;
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM InventoryComponent"); auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM InventoryComponent");
while (!tableSize.eof()) { while (!tableSize.eof()) {
size = tableSize.getIntField(0, 0); size = tableSize.getIntField(0, 0);
@@ -14,8 +14,7 @@ void CDInventoryComponentTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
auto& entries = GetEntriesMutable(); this->entries.reserve(size);
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM InventoryComponent"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM InventoryComponent");
@@ -26,7 +25,7 @@ void CDInventoryComponentTable::LoadValuesFromDatabase() {
entry.count = tableData.getIntField("count", -1); entry.count = tableData.getIntField("count", -1);
entry.equip = tableData.getIntField("equip", -1) == 1 ? true : false; entry.equip = tableData.getIntField("equip", -1) == 1 ? true : false;
entries.push_back(entry); this->entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
@@ -34,9 +33,15 @@ void CDInventoryComponentTable::LoadValuesFromDatabase() {
} }
std::vector<CDInventoryComponent> CDInventoryComponentTable::Query(std::function<bool(CDInventoryComponent)> predicate) { std::vector<CDInventoryComponent> CDInventoryComponentTable::Query(std::function<bool(CDInventoryComponent)> predicate) {
std::vector<CDInventoryComponent> data = cpplinq::from(GetEntries())
std::vector<CDInventoryComponent> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();
return data; return data;
} }
const std::vector<CDInventoryComponent>& CDInventoryComponentTable::GetEntries() const {
return this->entries;
}

View File

@@ -4,15 +4,20 @@
#include "CDTable.h" #include "CDTable.h"
struct CDInventoryComponent { struct CDInventoryComponent {
uint32_t id; //!< The component ID for this object unsigned int id; //!< The component ID for this object
uint32_t itemid; //!< The LOT of the object unsigned int itemid; //!< The LOT of the object
uint32_t count; //!< The count of the items the object has unsigned int count; //!< The count of the items the object has
bool equip; //!< Whether or not to equip the item bool equip; //!< Whether or not to equip the item
}; };
class CDInventoryComponentTable : public CDTable<CDInventoryComponentTable, std::vector<CDInventoryComponent>> { class CDInventoryComponentTable : public CDTable<CDInventoryComponentTable> {
private:
std::vector<CDInventoryComponent> entries;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
// Queries the table with a custom "where" clause // Queries the table with a custom "where" clause
std::vector<CDInventoryComponent> Query(std::function<bool(CDInventoryComponent)> predicate); std::vector<CDInventoryComponent> Query(std::function<bool(CDInventoryComponent)> predicate);
const std::vector<CDInventoryComponent>& GetEntries() const;
}; };

View File

@@ -5,7 +5,7 @@ CDItemComponent CDItemComponentTable::Default = {};
void CDItemComponentTable::LoadValuesFromDatabase() { void CDItemComponentTable::LoadValuesFromDatabase() {
// First, get the size of the table // First, get the size of the table
uint32_t size = 0; unsigned int size = 0;
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM ItemComponent"); auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM ItemComponent");
while (!tableSize.eof()) { while (!tableSize.eof()) {
size = tableSize.getIntField(0, 0); size = tableSize.getIntField(0, 0);
@@ -17,7 +17,6 @@ void CDItemComponentTable::LoadValuesFromDatabase() {
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ItemComponent"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ItemComponent");
auto& entries = GetEntriesMutable();
while (!tableData.eof()) { while (!tableData.eof()) {
CDItemComponent entry; CDItemComponent entry;
entry.id = tableData.getIntField("id", -1); entry.id = tableData.getIntField("id", -1);
@@ -63,17 +62,16 @@ void CDItemComponentTable::LoadValuesFromDatabase() {
entry.forgeType = tableData.getIntField("forgeType", -1); entry.forgeType = tableData.getIntField("forgeType", -1);
entry.SellMultiplier = tableData.getFloatField("SellMultiplier", -1.0f); entry.SellMultiplier = tableData.getFloatField("SellMultiplier", -1.0f);
entries.insert(std::make_pair(entry.id, entry)); this->entries.insert(std::make_pair(entry.id, entry));
tableData.nextRow(); tableData.nextRow();
} }
tableData.finalize(); tableData.finalize();
} }
const CDItemComponent& CDItemComponentTable::GetItemComponentByID(uint32_t skillID) { const CDItemComponent& CDItemComponentTable::GetItemComponentByID(unsigned int skillID) {
auto& entries = GetEntriesMutable(); const auto& it = this->entries.find(skillID);
const auto& it = entries.find(skillID); if (it != this->entries.end()) {
if (it != entries.end()) {
return it->second; return it->second;
} }
@@ -131,12 +129,12 @@ const CDItemComponent& CDItemComponentTable::GetItemComponentByID(uint32_t skill
entry.forgeType = tableData.getIntField("forgeType", -1); entry.forgeType = tableData.getIntField("forgeType", -1);
entry.SellMultiplier = tableData.getFloatField("SellMultiplier", -1.0f); entry.SellMultiplier = tableData.getFloatField("SellMultiplier", -1.0f);
entries.insert(std::make_pair(entry.id, entry)); this->entries.insert(std::make_pair(entry.id, entry));
tableData.nextRow(); tableData.nextRow();
} }
const auto& it2 = entries.find(skillID); const auto& it2 = this->entries.find(skillID);
if (it2 != entries.end()) { if (it2 != this->entries.end()) {
return it2->second; return it2->second;
} }

View File

@@ -5,57 +5,60 @@
#include "dCommonVars.h" #include "dCommonVars.h"
struct CDItemComponent { struct CDItemComponent {
uint32_t id; //!< The Component ID unsigned int id; //!< The Component ID
std::string equipLocation; //!< The equip location std::string equipLocation; //!< The equip location
uint32_t baseValue; //!< The monetary base value of the item unsigned int baseValue; //!< The monetary base value of the item
bool isKitPiece; //!< Whether or not the item belongs to a kit bool isKitPiece; //!< Whether or not the item belongs to a kit
uint32_t rarity; //!< The rarity of the item unsigned int rarity; //!< The rarity of the item
uint32_t itemType; //!< The item type unsigned int itemType; //!< The item type
int64_t itemInfo; //!< The item info int64_t itemInfo; //!< The item info
bool inLootTable; //!< Whether or not the item is in a loot table bool inLootTable; //!< Whether or not the item is in a loot table
bool inVendor; //!< Whether or not the item is in a vendor inventory bool inVendor; //!< Whether or not the item is in a vendor inventory
bool isUnique; //!< ??? bool isUnique; //!< ???
bool isBOP; //!< ??? bool isBOP; //!< ???
bool isBOE; //!< ??? bool isBOE; //!< ???
uint32_t reqFlagID; //!< User must have completed this flag to get the item unsigned int reqFlagID; //!< User must have completed this flag to get the item
uint32_t reqSpecialtyID; //!< ??? unsigned int reqSpecialtyID; //!< ???
uint32_t reqSpecRank; //!< ??? unsigned int reqSpecRank; //!< ???
uint32_t reqAchievementID; //!< The required achievement must be completed unsigned int reqAchievementID; //!< The required achievement must be completed
uint32_t stackSize; //!< The stack size of the item unsigned int stackSize; //!< The stack size of the item
uint32_t color1; //!< Something to do with item color... unsigned int color1; //!< Something to do with item color...
uint32_t decal; //!< The decal of the item unsigned int decal; //!< The decal of the item
uint32_t offsetGroupID; //!< Something to do with group IDs unsigned int offsetGroupID; //!< Something to do with group IDs
uint32_t buildTypes; //!< Something to do with building unsigned int buildTypes; //!< Something to do with building
std::string reqPrecondition; //!< The required precondition std::string reqPrecondition; //!< The required precondition
uint32_t animationFlag; //!< The Animation Flag unsigned int animationFlag; //!< The Animation Flag
uint32_t equipEffects; //!< The effect played when the item is equipped unsigned int equipEffects; //!< The effect played when the item is equipped
bool readyForQA; //!< ??? bool readyForQA; //!< ???
uint32_t itemRating; //!< ??? unsigned int itemRating; //!< ???
bool isTwoHanded; //!< Whether or not the item is double handed bool isTwoHanded; //!< Whether or not the item is double handed
uint32_t minNumRequired; //!< Maybe the minimum number required for a mission, or to own this object? unsigned int minNumRequired; //!< Maybe the minimum number required for a mission, or to own this object?
uint32_t delResIndex; //!< ??? unsigned int delResIndex; //!< ???
uint32_t currencyLOT; //!< ??? unsigned int currencyLOT; //!< ???
uint32_t altCurrencyCost; //!< ??? unsigned int altCurrencyCost; //!< ???
std::string subItems; //!< A comma seperate string of sub items (maybe for multi-itemed things like faction test gear set) std::string subItems; //!< A comma seperate string of sub items (maybe for multi-itemed things like faction test gear set)
UNUSED(std::string audioEventUse); //!< ??? UNUSED(std::string audioEventUse); //!< ???
bool noEquipAnimation; //!< Whether or not there is an equip animation bool noEquipAnimation; //!< Whether or not there is an equip animation
uint32_t commendationLOT; //!< The commendation LOT unsigned int commendationLOT; //!< The commendation LOT
uint32_t commendationCost; //!< The commendation cost unsigned int commendationCost; //!< The commendation cost
UNUSED(std::string audioEquipMetaEventSet); //!< ??? UNUSED(std::string audioEquipMetaEventSet); //!< ???
std::string currencyCosts; //!< Used for crafting std::string currencyCosts; //!< Used for crafting
UNUSED(std::string ingredientInfo); //!< Unused UNUSED(std::string ingredientInfo); //!< Unused
uint32_t locStatus; //!< ??? unsigned int locStatus; //!< ???
uint32_t forgeType; //!< Forge Type unsigned int forgeType; //!< Forge Type
float SellMultiplier; //!< Something to do with early vendors perhaps (but replaced) float SellMultiplier; //!< Something to do with early vendors perhaps (but replaced)
}; };
class CDItemComponentTable : public CDTable<CDItemComponentTable, std::map<uint32_t, CDItemComponent>> { class CDItemComponentTable : public CDTable<CDItemComponentTable> {
private:
std::map<unsigned int, CDItemComponent> entries;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
static std::map<LOT, uint32_t> ParseCraftingCurrencies(const CDItemComponent& itemComponent); static std::map<LOT, uint32_t> ParseCraftingCurrencies(const CDItemComponent& itemComponent);
// Gets an entry by ID // Gets an entry by ID
const CDItemComponent& GetItemComponentByID(uint32_t skillID); const CDItemComponent& GetItemComponentByID(unsigned int skillID);
static CDItemComponent Default; static CDItemComponent Default;
}; };

View File

@@ -3,7 +3,7 @@
void CDItemSetSkillsTable::LoadValuesFromDatabase() { void CDItemSetSkillsTable::LoadValuesFromDatabase() {
// First, get the size of the table // First, get the size of the table
uint32_t size = 0; unsigned int size = 0;
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM ItemSetSkills"); auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM ItemSetSkills");
while (!tableSize.eof()) { while (!tableSize.eof()) {
size = tableSize.getIntField(0, 0); size = tableSize.getIntField(0, 0);
@@ -14,8 +14,7 @@ void CDItemSetSkillsTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
auto& entries = GetEntriesMutable(); this->entries.reserve(size);
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ItemSetSkills"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ItemSetSkills");
@@ -25,7 +24,7 @@ void CDItemSetSkillsTable::LoadValuesFromDatabase() {
entry.SkillID = tableData.getIntField("SkillID", -1); entry.SkillID = tableData.getIntField("SkillID", -1);
entry.SkillCastType = tableData.getIntField("SkillCastType", -1); entry.SkillCastType = tableData.getIntField("SkillCastType", -1);
entries.push_back(entry); this->entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
@@ -33,17 +32,22 @@ void CDItemSetSkillsTable::LoadValuesFromDatabase() {
} }
std::vector<CDItemSetSkills> CDItemSetSkillsTable::Query(std::function<bool(CDItemSetSkills)> predicate) { std::vector<CDItemSetSkills> CDItemSetSkillsTable::Query(std::function<bool(CDItemSetSkills)> predicate) {
std::vector<CDItemSetSkills> data = cpplinq::from(GetEntries())
std::vector<CDItemSetSkills> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();
return data; return data;
} }
std::vector<CDItemSetSkills> CDItemSetSkillsTable::GetBySkillID(uint32_t SkillSetID) { const std::vector<CDItemSetSkills>& CDItemSetSkillsTable::GetEntries() const {
return this->entries;
}
std::vector<CDItemSetSkills> CDItemSetSkillsTable::GetBySkillID(unsigned int SkillSetID) {
std::vector<CDItemSetSkills> toReturn; std::vector<CDItemSetSkills> toReturn;
for (const auto& entry : GetEntries()) { for (CDItemSetSkills entry : this->entries) {
if (entry.SkillSetID == SkillSetID) toReturn.push_back(entry); if (entry.SkillSetID == SkillSetID) toReturn.push_back(entry);
if (entry.SkillSetID > SkillSetID) return toReturn; //stop seeking in the db if it's not needed. if (entry.SkillSetID > SkillSetID) return toReturn; //stop seeking in the db if it's not needed.
} }

View File

@@ -4,16 +4,21 @@
#include "CDTable.h" #include "CDTable.h"
struct CDItemSetSkills { struct CDItemSetSkills {
uint32_t SkillSetID; //!< The skill set ID unsigned int SkillSetID; //!< The skill set ID
uint32_t SkillID; //!< The skill ID unsigned int SkillID; //!< The skill ID
uint32_t SkillCastType; //!< The skill cast type unsigned int SkillCastType; //!< The skill cast type
}; };
class CDItemSetSkillsTable : public CDTable<CDItemSetSkillsTable, std::vector<CDItemSetSkills>> { class CDItemSetSkillsTable : public CDTable<CDItemSetSkillsTable> {
private:
std::vector<CDItemSetSkills> entries;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
// Queries the table with a custom "where" clause // Queries the table with a custom "where" clause
std::vector<CDItemSetSkills> Query(std::function<bool(CDItemSetSkills)> predicate); std::vector<CDItemSetSkills> Query(std::function<bool(CDItemSetSkills)> predicate);
std::vector<CDItemSetSkills> GetBySkillID(uint32_t SkillSetID); const std::vector<CDItemSetSkills>& GetEntries() const;
std::vector<CDItemSetSkills> GetBySkillID(unsigned int SkillSetID);
}; };

View File

@@ -3,7 +3,7 @@
void CDItemSetsTable::LoadValuesFromDatabase() { void CDItemSetsTable::LoadValuesFromDatabase() {
// First, get the size of the table // First, get the size of the table
uint32_t size = 0; unsigned int size = 0;
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM ItemSets"); auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM ItemSets");
while (!tableSize.eof()) { while (!tableSize.eof()) {
size = tableSize.getIntField(0, 0); size = tableSize.getIntField(0, 0);
@@ -14,8 +14,7 @@ void CDItemSetsTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
auto& entries = GetEntriesMutable(); this->entries.reserve(size);
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ItemSets"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ItemSets");
@@ -37,7 +36,7 @@ void CDItemSetsTable::LoadValuesFromDatabase() {
entry.kitID = tableData.getIntField("kitID", -1); entry.kitID = tableData.getIntField("kitID", -1);
entry.priority = tableData.getFloatField("priority", -1.0f); entry.priority = tableData.getFloatField("priority", -1.0f);
entries.push_back(entry); this->entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
@@ -46,9 +45,14 @@ void CDItemSetsTable::LoadValuesFromDatabase() {
std::vector<CDItemSets> CDItemSetsTable::Query(std::function<bool(CDItemSets)> predicate) { std::vector<CDItemSets> CDItemSetsTable::Query(std::function<bool(CDItemSets)> predicate) {
std::vector<CDItemSets> data = cpplinq::from(GetEntries()) std::vector<CDItemSets> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();
return data; return data;
} }
const std::vector<CDItemSets>& CDItemSetsTable::GetEntries() const {
return this->entries;
}

View File

@@ -4,27 +4,32 @@
#include "CDTable.h" #include "CDTable.h"
struct CDItemSets { struct CDItemSets {
uint32_t setID; //!< The item set ID unsigned int setID; //!< The item set ID
uint32_t locStatus; //!< The loc status unsigned int locStatus; //!< The loc status
std::string itemIDs; //!< THe item IDs std::string itemIDs; //!< THe item IDs
uint32_t kitType; //!< The item kit type unsigned int kitType; //!< The item kit type
uint32_t kitRank; //!< The item kit rank unsigned int kitRank; //!< The item kit rank
uint32_t kitImage; //!< The item kit image unsigned int kitImage; //!< The item kit image
uint32_t skillSetWith2; //!< The skill set with 2 unsigned int skillSetWith2; //!< The skill set with 2
uint32_t skillSetWith3; //!< The skill set with 3 unsigned int skillSetWith3; //!< The skill set with 3
uint32_t skillSetWith4; //!< The skill set with 4 unsigned int skillSetWith4; //!< The skill set with 4
uint32_t skillSetWith5; //!< The skill set with 5 unsigned int skillSetWith5; //!< The skill set with 5
uint32_t skillSetWith6; //!< The skill set with 6 unsigned int skillSetWith6; //!< The skill set with 6
bool localize; //!< Whether or localize bool localize; //!< Whether or localize
std::string gate_version; //!< The gate version std::string gate_version; //!< The gate version
uint32_t kitID; //!< The kit ID unsigned int kitID; //!< The kit ID
float priority; //!< The priority float priority; //!< The priority
}; };
class CDItemSetsTable : public CDTable<CDItemSetsTable, std::vector<CDItemSets>> { class CDItemSetsTable : public CDTable<CDItemSetsTable> {
private:
std::vector<CDItemSets> entries;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
// Queries the table with a custom "where" clause // Queries the table with a custom "where" clause
std::vector<CDItemSets> Query(std::function<bool(CDItemSets)> predicate); std::vector<CDItemSets> Query(std::function<bool(CDItemSets)> predicate);
const std::vector<CDItemSets>& GetEntries(void) const;
}; };

View File

@@ -3,7 +3,7 @@
void CDLevelProgressionLookupTable::LoadValuesFromDatabase() { void CDLevelProgressionLookupTable::LoadValuesFromDatabase() {
// First, get the size of the table // First, get the size of the table
uint32_t size = 0; unsigned int size = 0;
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM LevelProgressionLookup"); auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM LevelProgressionLookup");
while (!tableSize.eof()) { while (!tableSize.eof()) {
size = tableSize.getIntField(0, 0); size = tableSize.getIntField(0, 0);
@@ -14,8 +14,7 @@ void CDLevelProgressionLookupTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
auto& entries = GetEntriesMutable(); this->entries.reserve(size);
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM LevelProgressionLookup"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM LevelProgressionLookup");
@@ -25,7 +24,7 @@ void CDLevelProgressionLookupTable::LoadValuesFromDatabase() {
entry.requiredUScore = tableData.getIntField("requiredUScore", -1); entry.requiredUScore = tableData.getIntField("requiredUScore", -1);
entry.BehaviorEffect = tableData.getStringField("BehaviorEffect", ""); entry.BehaviorEffect = tableData.getStringField("BehaviorEffect", "");
entries.push_back(entry); this->entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
@@ -34,9 +33,14 @@ void CDLevelProgressionLookupTable::LoadValuesFromDatabase() {
std::vector<CDLevelProgressionLookup> CDLevelProgressionLookupTable::Query(std::function<bool(CDLevelProgressionLookup)> predicate) { std::vector<CDLevelProgressionLookup> CDLevelProgressionLookupTable::Query(std::function<bool(CDLevelProgressionLookup)> predicate) {
std::vector<CDLevelProgressionLookup> data = cpplinq::from(GetEntries()) std::vector<CDLevelProgressionLookup> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();
return data; return data;
} }
const std::vector<CDLevelProgressionLookup>& CDLevelProgressionLookupTable::GetEntries() const {
return this->entries;
}

View File

@@ -4,15 +4,20 @@
#include "CDTable.h" #include "CDTable.h"
struct CDLevelProgressionLookup { struct CDLevelProgressionLookup {
uint32_t id; //!< The Level ID unsigned int id; //!< The Level ID
uint32_t requiredUScore; //!< The required LEGO Score unsigned int requiredUScore; //!< The required LEGO Score
std::string BehaviorEffect; //!< The behavior effect attached to this std::string BehaviorEffect; //!< The behavior effect attached to this
}; };
class CDLevelProgressionLookupTable : public CDTable<CDLevelProgressionLookupTable, std::vector<CDLevelProgressionLookup>> { class CDLevelProgressionLookupTable : public CDTable<CDLevelProgressionLookupTable> {
private:
std::vector<CDLevelProgressionLookup> entries;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
// Queries the table with a custom "where" clause // Queries the table with a custom "where" clause
std::vector<CDLevelProgressionLookup> Query(std::function<bool(CDLevelProgressionLookup)> predicate); std::vector<CDLevelProgressionLookup> Query(std::function<bool(CDLevelProgressionLookup)> predicate);
const std::vector<CDLevelProgressionLookup>& GetEntries() const;
}; };

View File

@@ -16,7 +16,7 @@ CDLootMatrix CDLootMatrixTable::ReadRow(CppSQLite3Query& tableData) const {
void CDLootMatrixTable::LoadValuesFromDatabase() { void CDLootMatrixTable::LoadValuesFromDatabase() {
// First, get the size of the table // First, get the size of the table
uint32_t size = 0; unsigned int size = 0;
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM LootMatrix"); auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM LootMatrix");
while (!tableSize.eof()) { while (!tableSize.eof()) {
size = tableSize.getIntField(0, 0); size = tableSize.getIntField(0, 0);
@@ -25,8 +25,7 @@ void CDLootMatrixTable::LoadValuesFromDatabase() {
} }
// Reserve the size // Reserve the size
auto& entries = GetEntriesMutable(); this->entries.reserve(size);
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM LootMatrix"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM LootMatrix");
@@ -34,15 +33,14 @@ void CDLootMatrixTable::LoadValuesFromDatabase() {
CDLootMatrix entry; CDLootMatrix entry;
uint32_t lootMatrixIndex = tableData.getIntField("LootMatrixIndex", -1); uint32_t lootMatrixIndex = tableData.getIntField("LootMatrixIndex", -1);
entries[lootMatrixIndex].push_back(ReadRow(tableData)); this->entries[lootMatrixIndex].push_back(ReadRow(tableData));
tableData.nextRow(); tableData.nextRow();
} }
} }
const LootMatrixEntries& CDLootMatrixTable::GetMatrix(uint32_t matrixId) { const LootMatrixEntries& CDLootMatrixTable::GetMatrix(uint32_t matrixId) {
auto& entries = GetEntriesMutable(); auto itr = this->entries.find(matrixId);
auto itr = entries.find(matrixId); if (itr != this->entries.end()) {
if (itr != entries.end()) {
return itr->second; return itr->second;
} }
@@ -51,10 +49,10 @@ const LootMatrixEntries& CDLootMatrixTable::GetMatrix(uint32_t matrixId) {
auto tableData = query.execQuery(); auto tableData = query.execQuery();
while (!tableData.eof()) { while (!tableData.eof()) {
entries[matrixId].push_back(ReadRow(tableData)); this->entries[matrixId].push_back(ReadRow(tableData));
tableData.nextRow(); tableData.nextRow();
} }
return entries[matrixId]; return this->entries[matrixId];
} }

View File

@@ -4,19 +4,19 @@
#include "CDTable.h" #include "CDTable.h"
struct CDLootMatrix { struct CDLootMatrix {
uint32_t LootTableIndex; //!< The Loot Table Index unsigned int LootTableIndex; //!< The Loot Table Index
uint32_t RarityTableIndex; //!< The Rarity Table Index unsigned int RarityTableIndex; //!< The Rarity Table Index
float percent; //!< The percent that this matrix is used? float percent; //!< The percent that this matrix is used?
uint32_t minToDrop; //!< The minimum amount of loot from this matrix to drop unsigned int minToDrop; //!< The minimum amount of loot from this matrix to drop
uint32_t maxToDrop; //!< The maximum amount of loot from this matrix to drop unsigned int maxToDrop; //!< The maximum amount of loot from this matrix to drop
uint32_t flagID; //!< ??? unsigned int flagID; //!< ???
UNUSED(std::string gate_version); //!< The Gate Version UNUSED(std::string gate_version); //!< The Gate Version
}; };
typedef uint32_t LootMatrixIndex; typedef uint32_t LootMatrixIndex;
typedef std::vector<CDLootMatrix> LootMatrixEntries; typedef std::vector<CDLootMatrix> LootMatrixEntries;
class CDLootMatrixTable : public CDTable<CDLootMatrixTable, std::unordered_map<LootMatrixIndex, LootMatrixEntries>> { class CDLootMatrixTable : public CDTable<CDLootMatrixTable> {
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
@@ -24,5 +24,6 @@ public:
const LootMatrixEntries& GetMatrix(uint32_t matrixId); const LootMatrixEntries& GetMatrix(uint32_t matrixId);
private: private:
CDLootMatrix ReadRow(CppSQLite3Query& tableData) const; CDLootMatrix ReadRow(CppSQLite3Query& tableData) const;
std::unordered_map<LootMatrixIndex, LootMatrixEntries> entries;
}; };

View File

@@ -6,8 +6,8 @@
// Sort the tables by their rarity so the highest rarity items are first. // Sort the tables by their rarity so the highest rarity items are first.
void SortTable(LootTableEntries& table) { void SortTable(LootTableEntries& table) {
auto* componentsRegistryTable = CDClientManager::GetTable<CDComponentsRegistryTable>(); auto* componentsRegistryTable = CDClientManager::Instance().GetTable<CDComponentsRegistryTable>();
auto* itemComponentTable = CDClientManager::GetTable<CDItemComponentTable>(); auto* itemComponentTable = CDClientManager::Instance().GetTable<CDItemComponentTable>();
// We modify the table in place so the outer loop keeps track of what is sorted // We modify the table in place so the outer loop keeps track of what is sorted
// and the inner loop finds the highest rarity item and swaps it with the current position // and the inner loop finds the highest rarity item and swaps it with the current position
// of the outer loop. // of the outer loop.
@@ -40,7 +40,7 @@ CDLootTable CDLootTableTable::ReadRow(CppSQLite3Query& tableData) const {
void CDLootTableTable::LoadValuesFromDatabase() { void CDLootTableTable::LoadValuesFromDatabase() {
// First, get the size of the table // First, get the size of the table
uint32_t size = 0; unsigned int size = 0;
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM LootTable"); auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM LootTable");
while (!tableSize.eof()) { while (!tableSize.eof()) {
size = tableSize.getIntField(0, 0); size = tableSize.getIntField(0, 0);
@@ -49,8 +49,7 @@ void CDLootTableTable::LoadValuesFromDatabase() {
} }
// Reserve the size // Reserve the size
auto& entries = GetEntriesMutable(); this->entries.reserve(size);
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM LootTable"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM LootTable");
@@ -58,18 +57,17 @@ void CDLootTableTable::LoadValuesFromDatabase() {
CDLootTable entry; CDLootTable entry;
uint32_t lootTableIndex = tableData.getIntField("LootTableIndex", -1); uint32_t lootTableIndex = tableData.getIntField("LootTableIndex", -1);
entries[lootTableIndex].push_back(ReadRow(tableData)); this->entries[lootTableIndex].push_back(ReadRow(tableData));
tableData.nextRow(); tableData.nextRow();
} }
for (auto& [id, table] : entries) { for (auto& [id, table] : this->entries) {
SortTable(table); SortTable(table);
} }
} }
const LootTableEntries& CDLootTableTable::GetTable(uint32_t tableId) { const LootTableEntries& CDLootTableTable::GetTable(uint32_t tableId) {
auto& entries = GetEntriesMutable(); auto itr = this->entries.find(tableId);
auto itr = entries.find(tableId); if (itr != this->entries.end()) {
if (itr != entries.end()) {
return itr->second; return itr->second;
} }
@@ -79,10 +77,10 @@ const LootTableEntries& CDLootTableTable::GetTable(uint32_t tableId) {
while (!tableData.eof()) { while (!tableData.eof()) {
CDLootTable entry; CDLootTable entry;
entries[tableId].push_back(ReadRow(tableData)); this->entries[tableId].push_back(ReadRow(tableData));
tableData.nextRow(); tableData.nextRow();
} }
SortTable(entries[tableId]); SortTable(this->entries[tableId]);
return entries[tableId]; return this->entries[tableId];
} }

View File

@@ -4,18 +4,19 @@
#include "CDTable.h" #include "CDTable.h"
struct CDLootTable { struct CDLootTable {
uint32_t itemid; //!< The LOT of the item unsigned int itemid; //!< The LOT of the item
uint32_t LootTableIndex; //!< The Loot Table Index unsigned int LootTableIndex; //!< The Loot Table Index
bool MissionDrop; //!< Whether or not this loot table is a mission drop bool MissionDrop; //!< Whether or not this loot table is a mission drop
uint32_t sortPriority; //!< The sorting priority unsigned int sortPriority; //!< The sorting priority
}; };
typedef uint32_t LootTableIndex; typedef uint32_t LootTableIndex;
typedef std::vector<CDLootTable> LootTableEntries; typedef std::vector<CDLootTable> LootTableEntries;
class CDLootTableTable : public CDTable<CDLootTableTable, std::unordered_map<LootTableIndex, LootTableEntries>> { class CDLootTableTable : public CDTable<CDLootTableTable> {
private: private:
CDLootTable ReadRow(CppSQLite3Query& tableData) const; CDLootTable ReadRow(CppSQLite3Query& tableData) const;
std::unordered_map<LootTableIndex, LootTableEntries> entries;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();

View File

@@ -1,9 +1,9 @@
#include "CDMissionEmailTable.h" #include "CDMissionEmailTable.h"
void CDMissionEmailTable::LoadValuesFromDatabase() { void CDMissionEmailTable::LoadValuesFromDatabase() {
// First, get the size of the table // First, get the size of the table
uint32_t size = 0; unsigned int size = 0;
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM MissionEmail"); auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM MissionEmail");
while (!tableSize.eof()) { while (!tableSize.eof()) {
size = tableSize.getIntField(0, 0); size = tableSize.getIntField(0, 0);
@@ -14,8 +14,7 @@ void CDMissionEmailTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
auto& entries = GetEntriesMutable(); this->entries.reserve(size);
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM MissionEmail"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM MissionEmail");
@@ -30,7 +29,7 @@ void CDMissionEmailTable::LoadValuesFromDatabase() {
entry.locStatus = tableData.getIntField("locStatus", -1); entry.locStatus = tableData.getIntField("locStatus", -1);
entry.gate_version = tableData.getStringField("gate_version", ""); entry.gate_version = tableData.getStringField("gate_version", "");
entries.push_back(entry); this->entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
@@ -39,9 +38,15 @@ void CDMissionEmailTable::LoadValuesFromDatabase() {
//! Queries the table with a custom "where" clause //! Queries the table with a custom "where" clause
std::vector<CDMissionEmail> CDMissionEmailTable::Query(std::function<bool(CDMissionEmail)> predicate) { std::vector<CDMissionEmail> CDMissionEmailTable::Query(std::function<bool(CDMissionEmail)> predicate) {
std::vector<CDMissionEmail> data = cpplinq::from(GetEntries())
std::vector<CDMissionEmail> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();
return data; return data;
} }
//! Gets all the entries in the table
const std::vector<CDMissionEmail>& CDMissionEmailTable::GetEntries() const {
return this->entries;
}

View File

@@ -4,20 +4,25 @@
#include "CDTable.h" #include "CDTable.h"
struct CDMissionEmail { struct CDMissionEmail {
uint32_t ID; unsigned int ID;
uint32_t messageType; unsigned int messageType;
uint32_t notificationGroup; unsigned int notificationGroup;
uint32_t missionID; unsigned int missionID;
uint32_t attachmentLOT; unsigned int attachmentLOT;
bool localize; bool localize;
uint32_t locStatus; unsigned int locStatus;
std::string gate_version; std::string gate_version;
}; };
class CDMissionEmailTable : public CDTable<CDMissionEmailTable, std::vector<CDMissionEmail>> { class CDMissionEmailTable : public CDTable<CDMissionEmailTable> {
private:
std::vector<CDMissionEmail> entries;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
// Queries the table with a custom "where" clause // Queries the table with a custom "where" clause
std::vector<CDMissionEmail> Query(std::function<bool(CDMissionEmail)> predicate); std::vector<CDMissionEmail> Query(std::function<bool(CDMissionEmail)> predicate);
const std::vector<CDMissionEmail>& GetEntries() const;
}; };

View File

@@ -3,7 +3,7 @@
void CDMissionNPCComponentTable::LoadValuesFromDatabase() { void CDMissionNPCComponentTable::LoadValuesFromDatabase() {
// First, get the size of the table // First, get the size of the table
uint32_t size = 0; unsigned int size = 0;
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM MissionNPCComponent"); auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM MissionNPCComponent");
while (!tableSize.eof()) { while (!tableSize.eof()) {
size = tableSize.getIntField(0, 0); size = tableSize.getIntField(0, 0);
@@ -14,8 +14,7 @@ void CDMissionNPCComponentTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
auto& entries = GetEntriesMutable(); this->entries.reserve(size);
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM MissionNPCComponent"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM MissionNPCComponent");
@@ -27,7 +26,7 @@ void CDMissionNPCComponentTable::LoadValuesFromDatabase() {
entry.acceptsMission = tableData.getIntField("acceptsMission", -1) == 1 ? true : false; entry.acceptsMission = tableData.getIntField("acceptsMission", -1) == 1 ? true : false;
entry.gate_version = tableData.getStringField("gate_version", ""); entry.gate_version = tableData.getStringField("gate_version", "");
entries.push_back(entry); this->entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
@@ -37,9 +36,15 @@ void CDMissionNPCComponentTable::LoadValuesFromDatabase() {
//! Queries the table with a custom "where" clause //! Queries the table with a custom "where" clause
std::vector<CDMissionNPCComponent> CDMissionNPCComponentTable::Query(std::function<bool(CDMissionNPCComponent)> predicate) { std::vector<CDMissionNPCComponent> CDMissionNPCComponentTable::Query(std::function<bool(CDMissionNPCComponent)> predicate) {
std::vector<CDMissionNPCComponent> data = cpplinq::from(GetEntries()) std::vector<CDMissionNPCComponent> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();
return data; return data;
} }
//! Gets all the entries in the table
const std::vector<CDMissionNPCComponent>& CDMissionNPCComponentTable::GetEntries() const {
return this->entries;
}

View File

@@ -4,17 +4,24 @@
#include "CDTable.h" #include "CDTable.h"
struct CDMissionNPCComponent { struct CDMissionNPCComponent {
uint32_t id; //!< The ID unsigned int id; //!< The ID
uint32_t missionID; //!< The Mission ID unsigned int missionID; //!< The Mission ID
bool offersMission; //!< Whether or not this NPC offers a mission bool offersMission; //!< Whether or not this NPC offers a mission
bool acceptsMission; //!< Whether or not this NPC accepts a mission bool acceptsMission; //!< Whether or not this NPC accepts a mission
std::string gate_version; //!< The gate version std::string gate_version; //!< The gate version
}; };
class CDMissionNPCComponentTable : public CDTable<CDMissionNPCComponentTable, std::vector<CDMissionNPCComponent>> { class CDMissionNPCComponentTable : public CDTable<CDMissionNPCComponentTable> {
private:
std::vector<CDMissionNPCComponent> entries;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
// Queries the table with a custom "where" clause // Queries the table with a custom "where" clause
std::vector<CDMissionNPCComponent> Query(std::function<bool(CDMissionNPCComponent)> predicate); std::vector<CDMissionNPCComponent> Query(std::function<bool(CDMissionNPCComponent)> predicate);
// Gets all the entries in the table
const std::vector<CDMissionNPCComponent>& GetEntries() const;
}; };

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