mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2024-11-24 06:27:24 +00:00
Merge remote-tracking branch 'refs/remotes/origin/main'
This commit is contained in:
commit
a91cf3adc7
@ -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
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
# Full path to the LEGO Universe client
|
# Full path to the LEGO Universe client
|
||||||
CLIENT_PATH=/Users/someuser/LEGO Universe
|
CLIENT_PATH=./client
|
||||||
# Can improve build time
|
|
||||||
BUILD_THREADS=1
|
|
||||||
# Updates NET_VERSION in CMakeVariables.txt
|
# Updates NET_VERSION in CMakeVariables.txt
|
||||||
BUILD_VERSION=171022
|
NET_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=
|
||||||
@ -12,6 +10,5 @@ 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=SECRET_VALUE_CHANGE_ME
|
MARIADB_PASSWORD=
|
||||||
MARIADB_ROOT_PASSWORD=SECRET_VALUE_CHANGE_ME
|
|
||||||
MARIADB_DATABASE=darkflame
|
MARIADB_DATABASE=darkflame
|
||||||
|
56
.github/workflows/build-and-push-docker.yml
vendored
Normal file
56
.github/workflows/build-and-push-docker.yml
vendored
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
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 }}
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -122,3 +122,4 @@ docker/__pycache__
|
|||||||
docker-compose.override.yml
|
docker-compose.override.yml
|
||||||
|
|
||||||
!*Test.bin
|
!*Test.bin
|
||||||
|
!cmake/*
|
||||||
|
6
.gitmodules
vendored
6
.gitmodules
vendored
@ -14,6 +14,6 @@
|
|||||||
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"]
|
[submodule "thirdparty/magic_enum"]
|
||||||
path = thirdparty/AccountManager
|
path = thirdparty/magic_enum
|
||||||
url = https://github.com/DarkflameUniverse/AccountManager
|
url = https://github.com/Neargye/magic_enum.git
|
||||||
|
224
CMakeLists.txt
224
CMakeLists.txt
@ -2,7 +2,8 @@ cmake_minimum_required(VERSION 3.18)
|
|||||||
project(Darkflame)
|
project(Darkflame)
|
||||||
include(CTest)
|
include(CTest)
|
||||||
|
|
||||||
set (CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
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)
|
||||||
@ -14,30 +15,26 @@ 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)
|
||||||
|
|
||||||
# Set the variable
|
# Set the variable
|
||||||
set(${variable_name} ${variable_value})
|
set(${variable_name} ${variable_value})
|
||||||
|
|
||||||
# Add compiler definition
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D${variable_name}=${variable_value}")
|
|
||||||
|
|
||||||
message(STATUS "Variable: ${variable_name} = ${variable_value}")
|
message(STATUS "Variable: ${variable_name} = ${variable_value}")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
# Set the version
|
# Set the version
|
||||||
set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
|
set(PROJECT_VERSION "\"${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}\"")
|
||||||
|
|
||||||
# Echo the version
|
# Echo the version
|
||||||
message(STATUS "Version: ${PROJECT_VERSION}")
|
message(STATUS "Version: ${PROJECT_VERSION}")
|
||||||
@ -53,19 +50,22 @@ set(RECASTNAVIGATION_EXAMPLES OFF CACHE BOOL "" FORCE)
|
|||||||
# Disabled misleading indentation as DL_LinkedList from RakNet has a weird indent.
|
# Disabled misleading indentation as DL_LinkedList from RakNet has a weird indent.
|
||||||
# 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.
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DPROJECT_VERSION=${PROJECT_VERSION}")
|
|
||||||
if(UNIX)
|
if(UNIX)
|
||||||
if(APPLE)
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -Wuninitialized -fPIC")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17 -O2 -Wuninitialized -D_GLIBCXX_USE_CXX11_ABI=0 -D_GLIBCXX_USE_CXX17_ABI=0 -fPIC")
|
add_compile_definitions(_GLIBCXX_USE_CXX11_ABI=0 _GLIBCXX_USE_CXX17_ABI=0)
|
||||||
else()
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17 -O2 -Wuninitialized -D_GLIBCXX_USE_CXX11_ABI=0 -D_GLIBCXX_USE_CXX17_ABI=0 -static-libgcc -fPIC -lstdc++fs")
|
if(NOT APPLE)
|
||||||
|
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()
|
||||||
|
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -O2 -fPIC")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -O2 -fPIC")
|
||||||
elseif(MSVC)
|
elseif(MSVC)
|
||||||
# Skip warning for invalid conversion from size_t to uint32_t for all targets below for now
|
# Skip warning for invalid conversion from size_t to uint32_t for all targets below for now
|
||||||
@ -98,47 +98,64 @@ 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})
|
||||||
@ -146,24 +163,23 @@ 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()
|
||||||
|
|
||||||
# Copy navmesh data on first build and extract it
|
# Copy navmesh data on first build and extract it
|
||||||
configure_file(
|
configure_file(${CMAKE_SOURCE_DIR}/resources/navmeshes.zip ${PROJECT_BINARY_DIR}/navmeshes.zip COPYONLY)
|
||||||
${CMAKE_SOURCE_DIR}/resources/navmeshes.zip ${PROJECT_BINARY_DIR}/navmeshes.zip
|
|
||||||
COPYONLY
|
|
||||||
)
|
|
||||||
|
|
||||||
file(ARCHIVE_EXTRACT INPUT ${PROJECT_BINARY_DIR}/navmeshes.zip DESTINATION ${PROJECT_BINARY_DIR}/navmeshes)
|
file(ARCHIVE_EXTRACT INPUT ${PROJECT_BINARY_DIR}/navmeshes.zip DESTINATION ${PROJECT_BINARY_DIR}/navmeshes)
|
||||||
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" "NPC.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()
|
||||||
@ -171,26 +187,18 @@ 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)
|
||||||
if (NOT EXISTS ${PROJECT_BINARY_DIR}/migrations/dlu/${file})
|
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}
|
|
||||||
COPYONLY
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
endforeach()
|
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)
|
||||||
if (NOT EXISTS ${PROJECT_BINARY_DIR}/migrations/cdserver/${file})
|
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}
|
|
||||||
COPYONLY
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
# Create our list of include directories
|
# Create our list of include directories
|
||||||
@ -198,7 +206,9 @@ set(INCLUDED_DIRECTORIES
|
|||||||
"dCommon"
|
"dCommon"
|
||||||
"dCommon/dClient"
|
"dCommon/dClient"
|
||||||
"dCommon/dEnums"
|
"dCommon/dEnums"
|
||||||
|
|
||||||
"dChatFilter"
|
"dChatFilter"
|
||||||
|
|
||||||
"dGame"
|
"dGame"
|
||||||
"dGame/dBehaviors"
|
"dGame/dBehaviors"
|
||||||
"dGame/dComponents"
|
"dGame/dComponents"
|
||||||
@ -210,116 +220,54 @@ set(INCLUDED_DIRECTORIES
|
|||||||
"dGame/dPropertyBehaviors"
|
"dGame/dPropertyBehaviors"
|
||||||
"dGame/dPropertyBehaviors/ControlBehaviorMessages"
|
"dGame/dPropertyBehaviors/ControlBehaviorMessages"
|
||||||
"dGame/dUtilities"
|
"dGame/dUtilities"
|
||||||
|
|
||||||
"dPhysics"
|
"dPhysics"
|
||||||
|
|
||||||
"dNavigation"
|
"dNavigation"
|
||||||
"dNavigation/dTerrain"
|
"dNavigation/dTerrain"
|
||||||
"dZoneManager"
|
|
||||||
"dDatabase"
|
|
||||||
"dDatabase/Tables"
|
|
||||||
"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/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"
|
|
||||||
|
|
||||||
|
"dZoneManager"
|
||||||
|
|
||||||
|
"dDatabase"
|
||||||
|
"dDatabase/CDClientDatabase"
|
||||||
|
"dDatabase/CDClientDatabase/CDClientTables"
|
||||||
|
"dDatabase/GameDatabase"
|
||||||
|
"dDatabase/GameDatabase/ITables"
|
||||||
|
"dDatabase/GameDatabase/MySQL"
|
||||||
|
"dDatabase/GameDatabase/MySQL/Tables"
|
||||||
|
|
||||||
|
"dNet"
|
||||||
|
|
||||||
|
"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"
|
||||||
|
|
||||||
"tests"
|
"tests"
|
||||||
"tests/dCommonTests"
|
"tests/dCommonTests"
|
||||||
"tests/dGameTests"
|
"tests/dGameTests"
|
||||||
"tests/dGameTests/dComponentsTests"
|
"tests/dGameTests/dComponentsTests"
|
||||||
)
|
)
|
||||||
|
|
||||||
# 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)
|
||||||
if (APPLE)
|
if(APPLE)
|
||||||
include_directories("/usr/local/include/")
|
include_directories("/usr/local/include/")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (WIN32)
|
|
||||||
set(INCLUDED_DIRECTORIES ${INCLUDED_DIRECTORIES} "thirdparty/libbcrypt/include")
|
|
||||||
elseif (UNIX)
|
|
||||||
set(INCLUDED_DIRECTORIES ${INCLUDED_DIRECTORIES} "thirdparty/libbcrypt")
|
|
||||||
set(INCLUDED_DIRECTORIES ${INCLUDED_DIRECTORIES} "thirdparty/libbcrypt/include/bcrypt")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Add binary directory as an include directory
|
|
||||||
include_directories(${PROJECT_BINARY_DIR})
|
|
||||||
|
|
||||||
# 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()
|
||||||
|
|
||||||
|
if(NOT WIN32)
|
||||||
|
include_directories("${PROJECT_SOURCE_DIR}/thirdparty/libbcrypt/include/bcrypt")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include_directories("${PROJECT_SOURCE_DIR}/thirdparty/libbcrypt/include")
|
||||||
|
|
||||||
# Add linking directories:
|
# Add linking directories:
|
||||||
link_directories(${PROJECT_BINARY_DIR})
|
link_directories(${PROJECT_BINARY_DIR})
|
||||||
|
|
||||||
@ -330,8 +278,9 @@ add_subdirectory(thirdparty)
|
|||||||
file(
|
file(
|
||||||
GLOB HEADERS_DDATABASE
|
GLOB HEADERS_DDATABASE
|
||||||
LIST_DIRECTORIES false
|
LIST_DIRECTORIES false
|
||||||
${PROJECT_SOURCE_DIR}/dDatabase/*.h
|
${PROJECT_SOURCE_DIR}/dDatabase/CDClientDatabase/*.h
|
||||||
${PROJECT_SOURCE_DIR}/dDatabase/Tables/*.h
|
${PROJECT_SOURCE_DIR}/dDatabase/CDClientDatabase/CDClientTables/*.h
|
||||||
|
${PROJECT_SOURCE_DIR}/dDatabase/GameDatabase/ITables/*.h
|
||||||
${PROJECT_SOURCE_DIR}/thirdparty/SQLite/*.h
|
${PROJECT_SOURCE_DIR}/thirdparty/SQLite/*.h
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -366,15 +315,16 @@ 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" "mariadbConnCpp")
|
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()
|
||||||
@ -385,12 +335,6 @@ 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}
|
||||||
@ -412,6 +356,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__} MATCHES "1")
|
if(${ENABLE_TESTING})
|
||||||
add_subdirectory(tests)
|
add_subdirectory(tests)
|
||||||
endif()
|
endif()
|
||||||
|
@ -1,22 +1,32 @@
|
|||||||
PROJECT_VERSION_MAJOR=1
|
PROJECT_VERSION_MAJOR=1
|
||||||
PROJECT_VERSION_MINOR=1
|
PROJECT_VERSION_MINOR=1
|
||||||
PROJECT_VERSION_PATCH=1
|
PROJECT_VERSION_PATCH=1
|
||||||
# LICENSE
|
|
||||||
LICENSE=AGPL-3.0
|
|
||||||
# Debugging
|
# Debugging
|
||||||
# Set __dynamic to 1 to enable the -rdynamic flag for the linker, yielding some symbols in crashlogs.
|
# Set DYNAMIC to 1 to enable the -rdynamic flag for the linker, yielding some symbols in crashlogs.
|
||||||
__dynamic=1
|
DYNAMIC=1
|
||||||
# Set __ggdb to 1 to enable the -ggdb flag for the linker, including more debug info.
|
|
||||||
# __ggdb=1
|
# Set GGDB to 1 to enable the -ggdb flag for the linker, including more debug info.
|
||||||
# Set __include_backtrace__ to 1 to includes the backtrace library for better crashlogs.
|
# Do note, changing this will re-build the whole server
|
||||||
# __include_backtrace__=1
|
GGDB=0
|
||||||
# Set __compile_backtrace__ to 1 to compile the backtrace library instead of using system libraries.
|
|
||||||
# __compile_backtrace__=1
|
# Set INCLUDE_BACKTRACE to 1 to includes the backtrace library for better crashlogs.
|
||||||
|
# Do note, changing this will re-build the whole server
|
||||||
|
INCLUDE_BACKTRACE=0
|
||||||
|
|
||||||
|
# Set COMPILE_BACKTRACE to 1 to compile the backtrace library instead of using system libraries.
|
||||||
|
# Do note, changing this will re-build the whole server
|
||||||
|
COMPILE_BACKTRACE=0
|
||||||
|
|
||||||
# Set to the number of jobs (make -j equivalent) to compile the mariadbconn files with.
|
# Set to the number of jobs (make -j equivalent) to compile the mariadbconn files with.
|
||||||
__maria_db_connector_compile_jobs__=1
|
MARIADB_CONNECTOR_COMPILE_JOBS=1
|
||||||
|
|
||||||
# When set to 1 and uncommented, compiling and linking testing folders and libraries will be done.
|
# When set to 1 and uncommented, compiling and linking testing folders and libraries will be done.
|
||||||
__enable_testing__=1
|
ENABLE_TESTING=1
|
||||||
|
|
||||||
# The path to OpenSSL. Change this if your OpenSSL install path is different than the default.
|
# The path to OpenSSL. Change this if your OpenSSL install path is different than the default.
|
||||||
OPENSSL_ROOT_DIR=/usr/local/opt/openssl@3/
|
OPENSSL_ROOT_DIR=/usr/local/opt/openssl@3/
|
||||||
# Uncomment the below line to cache the entire CDClient into memory
|
|
||||||
# CDCLIENT_CACHE_ALL=1
|
# Whether or not to cache the entire CDClient Database into memory instead of lazy loading.
|
||||||
|
# 0 means to lazy load, all other values mean load the entire database.
|
||||||
|
CDCLIENT_CACHE_ALL=0
|
||||||
|
46
Docker.md
46
Docker.md
@ -1,46 +0,0 @@
|
|||||||
# 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`
|
|
@ -1,58 +0,0 @@
|
|||||||
# 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)
|
|
51
Dockerfile
Normal file
51
Dockerfile
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
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/src/mariadb_connector_cpp-build/libmariadbcpp.so /usr/local/lib/
|
||||||
|
COPY --from=build /app/build/mariadbcpp/src/mariadb_connector_cpp-build/libmariadb/libmariadb/libmariadb.so.3 /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" ]
|
60
README.md
60
README.md
@ -23,6 +23,9 @@ We do not recommend hosting public servers. Darkflame Universe is intended for s
|
|||||||
### Supply of resource files
|
### Supply of resource files
|
||||||
Darkflame Universe is a server emulator and does not distribute any LEGO® Universe files. A separate game client is required to setup this server emulator and play the game, which we cannot supply. Users are strongly suggested to refer to the safe checksums listed [here](#verifying-your-client-files) to see if a client will work.
|
Darkflame Universe is a server emulator and does not distribute any LEGO® Universe files. A separate game client is required to setup this server emulator and play the game, which we cannot supply. Users are strongly suggested to refer to the safe checksums listed [here](#verifying-your-client-files) to see if a client will work.
|
||||||
|
|
||||||
|
## Step by step walkthrough for a single-player server
|
||||||
|
If you would like a setup for a single player server only on a Windows machine, use the [Native Windows Setup Guide by HailStorm](https://gist.github.com/HailStorm32/169df65a47a104199b5cc57d10fa57de) and skip this README.
|
||||||
|
|
||||||
## Steps to setup server
|
## Steps to setup server
|
||||||
* [Clone this repository](#clone-the-repository)
|
* [Clone this repository](#clone-the-repository)
|
||||||
* [Install dependencies](#install-dependencies)
|
* [Install dependencies](#install-dependencies)
|
||||||
@ -34,6 +37,7 @@ Darkflame Universe is a server emulator and does not distribute any LEGO® Unive
|
|||||||
* [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)
|
||||||
@ -344,6 +348,62 @@ 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
|
||||||
|
|
||||||
|
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)
|
||||||
|
51
cmake/Utils.cmake
Normal file
51
cmake/Utils.cmake
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
# 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()
|
@ -1,6 +1,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
#include <csignal>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
@ -15,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"
|
||||||
@ -24,15 +25,17 @@
|
|||||||
#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;
|
||||||
dConfig* config = nullptr;
|
dConfig* config = nullptr;
|
||||||
bool shouldShutdown = false;
|
Game::signal_t lastSignal = 0;
|
||||||
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) {
|
||||||
@ -42,27 +45,21 @@ int main(int argc, char** argv) {
|
|||||||
Diagnostics::SetProcessFileName(argv[0]);
|
Diagnostics::SetProcessFileName(argv[0]);
|
||||||
Diagnostics::Initialize();
|
Diagnostics::Initialize();
|
||||||
|
|
||||||
|
std::signal(SIGINT, 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:
|
||||||
Game::logger = SetupLogger();
|
Server::SetupLogger("AuthServer");
|
||||||
if (!Game::logger) return EXIT_FAILURE;
|
if (!Game::logger) return EXIT_FAILURE;
|
||||||
|
|
||||||
//Read our config:
|
|
||||||
Game::config = new dConfig((BinaryPathFinder::GetBinaryDir() / "authconfig.ini").string());
|
|
||||||
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: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR);
|
LOG("Version: %s", PROJECT_VERSION);
|
||||||
LOG("Compiled on: %s", __TIMESTAMP__);
|
LOG("Compiled on: %s", __TIMESTAMP__);
|
||||||
|
|
||||||
//Connect to the MySQL Database
|
|
||||||
std::string mysql_host = Game::config->GetValue("mysql_host");
|
|
||||||
std::string mysql_database = Game::config->GetValue("mysql_database");
|
|
||||||
std::string mysql_username = Game::config->GetValue("mysql_username");
|
|
||||||
std::string mysql_password = Game::config->GetValue("mysql_password");
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password);
|
Database::Connect();
|
||||||
} catch (sql::SQLException& ex) {
|
} catch (sql::SQLException& ex) {
|
||||||
LOG("Got an error while connecting to the database: %s", ex.what());
|
LOG("Got an error while connecting to the database: %s", ex.what());
|
||||||
Database::Destroy("AuthServer");
|
Database::Destroy("AuthServer");
|
||||||
@ -74,25 +71,26 @@ int main(int argc, char** argv) {
|
|||||||
//Find out the master's IP:
|
//Find out the master's IP:
|
||||||
std::string masterIP;
|
std::string masterIP;
|
||||||
uint32_t masterPort = 1500;
|
uint32_t masterPort = 1500;
|
||||||
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';");
|
|
||||||
auto res = stmt->executeQuery();
|
|
||||||
while (res->next()) {
|
|
||||||
masterIP = res->getString(1).c_str();
|
|
||||||
masterPort = res->getInt(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
delete res;
|
auto masterInfo = Database::Get()->GetMasterInfo();
|
||||||
delete stmt;
|
if (masterInfo) {
|
||||||
|
masterIP = masterInfo->ip;
|
||||||
|
masterPort = masterInfo->port;
|
||||||
|
}
|
||||||
|
LOG("Master is at %s:%d", masterIP.c_str(), masterPort);
|
||||||
|
|
||||||
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.
|
||||||
uint32_t maxClients = 50;
|
uint32_t maxClients = 999;
|
||||||
uint32_t ourPort = 1001; //LU client is hardcoded to use this for auth port, so I'm making it the default.
|
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"));
|
std::string ourIP = "localhost";
|
||||||
if (Game::config->GetValue("port") != "") ourPort = std::atoi(Game::config->GetValue("port").c_str());
|
GeneralUtils::TryParse(Game::config->GetValue("max_clients"), maxClients);
|
||||||
|
GeneralUtils::TryParse(Game::config->GetValue("auth_server_port"), ourPort);
|
||||||
|
const auto externalIPString = Game::config->GetValue("external_ip");
|
||||||
|
if (!externalIPString.empty()) ourIP = externalIPString;
|
||||||
|
|
||||||
Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Auth, Game::config, &Game::shouldShutdown);
|
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();
|
||||||
@ -103,13 +101,18 @@ int main(int argc, char** argv) {
|
|||||||
uint32_t framesSinceMasterDisconnect = 0;
|
uint32_t framesSinceMasterDisconnect = 0;
|
||||||
uint32_t framesSinceLastSQLPing = 0;
|
uint32_t framesSinceLastSQLPing = 0;
|
||||||
|
|
||||||
while (!Game::shouldShutdown) {
|
AuthPackets::LoadClaimCodes();
|
||||||
|
|
||||||
|
Game::logger->Flush(); // once immediately before main loop
|
||||||
|
while (!Game::ShouldShutdown()) {
|
||||||
//Check if we're still connected to master:
|
//Check if we're still connected to master:
|
||||||
if (!Game::server->GetIsConnectedToMaster()) {
|
if (!Game::server->GetIsConnectedToMaster()) {
|
||||||
framesSinceMasterDisconnect++;
|
framesSinceMasterDisconnect++;
|
||||||
|
|
||||||
if (framesSinceMasterDisconnect >= authFramerate)
|
if (framesSinceMasterDisconnect >= authFramerate) {
|
||||||
|
LOG("No connection to master!");
|
||||||
break; //Exit our loop, shut down.
|
break; //Exit our loop, shut down.
|
||||||
|
}
|
||||||
} else framesSinceMasterDisconnect = 0;
|
} else framesSinceMasterDisconnect = 0;
|
||||||
|
|
||||||
//In world we'd update our other systems here.
|
//In world we'd update our other systems here.
|
||||||
@ -134,16 +137,12 @@ int main(int argc, char** argv) {
|
|||||||
//Find out the master's IP for absolutely no reason:
|
//Find out the master's IP for absolutely no reason:
|
||||||
std::string masterIP;
|
std::string masterIP;
|
||||||
uint32_t masterPort;
|
uint32_t masterPort;
|
||||||
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';");
|
auto masterInfo = Database::Get()->GetMasterInfo();
|
||||||
auto res = stmt->executeQuery();
|
if (masterInfo) {
|
||||||
while (res->next()) {
|
masterIP = masterInfo->ip;
|
||||||
masterIP = res->getString(1).c_str();
|
masterPort = masterInfo->port;
|
||||||
masterPort = res->getInt(2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delete res;
|
|
||||||
delete stmt;
|
|
||||||
|
|
||||||
framesSinceLastSQLPing = 0;
|
framesSinceLastSQLPing = 0;
|
||||||
} else framesSinceLastSQLPing++;
|
} else framesSinceLastSQLPing++;
|
||||||
|
|
||||||
@ -152,6 +151,7 @@ int main(int argc, char** argv) {
|
|||||||
std::this_thread::sleep_until(t);
|
std::this_thread::sleep_until(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOG("Exited Main Loop! (signal %d)", Game::lastSignal);
|
||||||
//Delete our objects here:
|
//Delete our objects here:
|
||||||
Database::Destroy("AuthServer");
|
Database::Destroy("AuthServer");
|
||||||
delete Game::server;
|
delete Game::server;
|
||||||
@ -161,18 +161,6 @@ 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;
|
||||||
|
|
||||||
|
@ -1,2 +1,7 @@
|
|||||||
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}\"")
|
||||||
|
@ -32,15 +32,11 @@ dChatFilter::dChatFilter(const std::string& filepath, bool dontGenerateDCF) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Read player names that are ok as well:
|
//Read player names that are ok as well:
|
||||||
auto stmt = Database::CreatePreppedStmt("select name from charinfo;");
|
auto approvedNames = Database::Get()->GetApprovedCharacterNames();
|
||||||
auto res = stmt->executeQuery();
|
for (auto& name : approvedNames) {
|
||||||
while (res->next()) {
|
std::transform(name.begin(), name.end(), name.begin(), ::tolower); //Transform to lowercase
|
||||||
std::string line = res->getString(1).c_str();
|
m_ApprovedWords.push_back(CalculateHash(name));
|
||||||
std::transform(line.begin(), line.end(), line.begin(), ::tolower); //Transform to lowercase
|
|
||||||
m_ApprovedWords.push_back(CalculateHash(line));
|
|
||||||
}
|
}
|
||||||
delete res;
|
|
||||||
delete stmt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dChatFilter::~dChatFilter() {
|
dChatFilter::~dChatFilter() {
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
set(DCHATSERVER_SOURCES
|
set(DCHATSERVER_SOURCES
|
||||||
|
"ChatIgnoreList.cpp"
|
||||||
"ChatPacketHandler.cpp"
|
"ChatPacketHandler.cpp"
|
||||||
"PlayerContainer.cpp"
|
"PlayerContainer.cpp"
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(ChatServer "ChatServer.cpp")
|
add_executable(ChatServer "ChatServer.cpp")
|
||||||
add_library(dChatServer ${DCHATSERVER_SOURCES})
|
add_library(dChatServer ${DCHATSERVER_SOURCES})
|
||||||
|
target_include_directories(dChatServer PRIVATE ${PROJECT_SOURCE_DIR}/dServer)
|
||||||
|
add_compile_definitions(ChatServer PRIVATE PROJECT_VERSION="\"${PROJECT_VERSION}\"")
|
||||||
|
|
||||||
target_link_libraries(dChatServer ${COMMON_LIBRARIES} dChatFilter)
|
target_link_libraries(dChatServer ${COMMON_LIBRARIES} dChatFilter)
|
||||||
target_link_libraries(ChatServer ${COMMON_LIBRARIES} dChatFilter dChatServer)
|
target_link_libraries(ChatServer ${COMMON_LIBRARIES} dChatFilter dChatServer dServer)
|
||||||
|
|
||||||
|
171
dChatServer/ChatIgnoreList.cpp
Normal file
171
dChatServer/ChatIgnoreList.cpp
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
#include "ChatIgnoreList.h"
|
||||||
|
#include "PlayerContainer.h"
|
||||||
|
#include "eChatInternalMessageType.h"
|
||||||
|
#include "BitStreamUtils.h"
|
||||||
|
#include "Game.h"
|
||||||
|
#include "Logger.h"
|
||||||
|
#include "eObjectBits.h"
|
||||||
|
|
||||||
|
#include "Database.h"
|
||||||
|
|
||||||
|
// A note to future readers, The client handles all the actual ignoring logic:
|
||||||
|
// not allowing teams, rejecting DMs, friends requets etc.
|
||||||
|
// The only thing not auto-handled is instance activities force joining the team on the server.
|
||||||
|
|
||||||
|
void WriteOutgoingReplyHeader(RakNet::BitStream& bitStream, const LWOOBJID& receivingPlayer, const ChatIgnoreList::Response type) {
|
||||||
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||||
|
bitStream.Write(receivingPlayer);
|
||||||
|
|
||||||
|
//portion that will get routed:
|
||||||
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatIgnoreList::GetIgnoreList(Packet* packet) {
|
||||||
|
CINSTREAM_SKIP_HEADER;
|
||||||
|
LWOOBJID playerId;
|
||||||
|
inStream.Read(playerId);
|
||||||
|
|
||||||
|
auto& receiver = Game::playerContainer.GetPlayerDataMutable(playerId);
|
||||||
|
if (!receiver) {
|
||||||
|
LOG("Tried to get ignore list, but player %llu not found in container", playerId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!receiver.ignoredPlayers.empty()) {
|
||||||
|
LOG_DEBUG("Player %llu already has an ignore list, but is requesting it again.", playerId);
|
||||||
|
} else {
|
||||||
|
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) {
|
||||||
|
receiver.ignoredPlayers.emplace_back(ignoredPlayer.name, ignoredPlayer.id);
|
||||||
|
GeneralUtils::SetBit(receiver.ignoredPlayers.back().playerId, eObjectBits::CHARACTER);
|
||||||
|
GeneralUtils::SetBit(receiver.ignoredPlayers.back().playerId, eObjectBits::PERSISTENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CBITSTREAM;
|
||||||
|
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<uint16_t>(0); // literally spacing due to struct alignment
|
||||||
|
|
||||||
|
bitStream.Write<uint16_t>(receiver.ignoredPlayers.size());
|
||||||
|
for (const auto& ignoredPlayer : receiver.ignoredPlayers) {
|
||||||
|
bitStream.Write(ignoredPlayer.playerId);
|
||||||
|
bitStream.Write(LUWString(ignoredPlayer.playerName, 36));
|
||||||
|
}
|
||||||
|
|
||||||
|
Game::server->Send(&bitStream, packet->systemAddress, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatIgnoreList::AddIgnore(Packet* packet) {
|
||||||
|
CINSTREAM_SKIP_HEADER;
|
||||||
|
LWOOBJID playerId;
|
||||||
|
inStream.Read(playerId);
|
||||||
|
|
||||||
|
auto& receiver = Game::playerContainer.GetPlayerDataMutable(playerId);
|
||||||
|
if (!receiver) {
|
||||||
|
LOG("Tried to get ignore list, but player %llu not found in container", playerId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr int32_t MAX_IGNORES = 32;
|
||||||
|
if (receiver.ignoredPlayers.size() > MAX_IGNORES) {
|
||||||
|
LOG_DEBUG("Player %llu has too many ignores", playerId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
inStream.IgnoreBytes(4); // ignore some garbage zeros idk
|
||||||
|
|
||||||
|
LUWString toIgnoreName;
|
||||||
|
inStream.Read(toIgnoreName);
|
||||||
|
std::string toIgnoreStr = toIgnoreName.GetAsString();
|
||||||
|
|
||||||
|
CBITSTREAM;
|
||||||
|
WriteOutgoingReplyHeader(bitStream, receiver.playerID, ChatIgnoreList::Response::ADD_IGNORE);
|
||||||
|
|
||||||
|
// Check if the player exists
|
||||||
|
LWOOBJID ignoredPlayerId = LWOOBJID_EMPTY;
|
||||||
|
if (toIgnoreStr == receiver.playerName || toIgnoreStr.find("[GM]") == 0) {
|
||||||
|
LOG_DEBUG("Player %llu tried to ignore themselves", playerId);
|
||||||
|
|
||||||
|
bitStream.Write(ChatIgnoreList::AddResponse::GENERAL_ERROR);
|
||||||
|
} else if (std::count(receiver.ignoredPlayers.begin(), receiver.ignoredPlayers.end(), toIgnoreStr) > 0) {
|
||||||
|
LOG_DEBUG("Player %llu is already ignoring %s", playerId, toIgnoreStr.c_str());
|
||||||
|
|
||||||
|
bitStream.Write(ChatIgnoreList::AddResponse::ALREADY_IGNORED);
|
||||||
|
} else {
|
||||||
|
// Get the playerId falling back to query if not online
|
||||||
|
const auto& playerData = Game::playerContainer.GetPlayerData(toIgnoreStr);
|
||||||
|
if (!playerData) {
|
||||||
|
// Fall back to query
|
||||||
|
auto player = Database::Get()->GetCharacterInfo(toIgnoreStr);
|
||||||
|
if (!player || player->name != toIgnoreStr) {
|
||||||
|
LOG_DEBUG("Player %s not found", toIgnoreStr.c_str());
|
||||||
|
} else {
|
||||||
|
ignoredPlayerId = player->id;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ignoredPlayerId = playerData.playerID;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ignoredPlayerId != LWOOBJID_EMPTY) {
|
||||||
|
Database::Get()->AddIgnore(static_cast<uint32_t>(playerId), static_cast<uint32_t>(ignoredPlayerId));
|
||||||
|
GeneralUtils::SetBit(ignoredPlayerId, eObjectBits::CHARACTER);
|
||||||
|
GeneralUtils::SetBit(ignoredPlayerId, eObjectBits::PERSISTENT);
|
||||||
|
|
||||||
|
receiver.ignoredPlayers.emplace_back(toIgnoreStr, ignoredPlayerId);
|
||||||
|
LOG_DEBUG("Player %llu is ignoring %s", playerId, toIgnoreStr.c_str());
|
||||||
|
|
||||||
|
bitStream.Write(ChatIgnoreList::AddResponse::SUCCESS);
|
||||||
|
} else {
|
||||||
|
bitStream.Write(ChatIgnoreList::AddResponse::PLAYER_NOT_FOUND);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LUWString playerNameSend(toIgnoreStr, 33);
|
||||||
|
bitStream.Write(playerNameSend);
|
||||||
|
bitStream.Write(ignoredPlayerId);
|
||||||
|
|
||||||
|
Game::server->Send(&bitStream, packet->systemAddress, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatIgnoreList::RemoveIgnore(Packet* packet) {
|
||||||
|
CINSTREAM_SKIP_HEADER;
|
||||||
|
LWOOBJID playerId;
|
||||||
|
inStream.Read(playerId);
|
||||||
|
|
||||||
|
auto& receiver = Game::playerContainer.GetPlayerDataMutable(playerId);
|
||||||
|
if (!receiver) {
|
||||||
|
LOG("Tried to get ignore list, but player %llu not found in container", playerId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
inStream.IgnoreBytes(4); // ignore some garbage zeros idk
|
||||||
|
|
||||||
|
LUWString removedIgnoreName;
|
||||||
|
inStream.Read(removedIgnoreName);
|
||||||
|
std::string removedIgnoreStr = removedIgnoreName.GetAsString();
|
||||||
|
|
||||||
|
auto toRemove = std::remove(receiver.ignoredPlayers.begin(), receiver.ignoredPlayers.end(), removedIgnoreStr);
|
||||||
|
if (toRemove == receiver.ignoredPlayers.end()) {
|
||||||
|
LOG_DEBUG("Player %llu is not ignoring %s", playerId, removedIgnoreStr.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Database::Get()->RemoveIgnore(static_cast<uint32_t>(playerId), static_cast<uint32_t>(toRemove->playerId));
|
||||||
|
receiver.ignoredPlayers.erase(toRemove, receiver.ignoredPlayers.end());
|
||||||
|
|
||||||
|
CBITSTREAM;
|
||||||
|
WriteOutgoingReplyHeader(bitStream, receiver.playerID, ChatIgnoreList::Response::REMOVE_IGNORE);
|
||||||
|
|
||||||
|
bitStream.Write<int8_t>(0);
|
||||||
|
LUWString playerNameSend(removedIgnoreStr, 33);
|
||||||
|
bitStream.Write(playerNameSend);
|
||||||
|
|
||||||
|
Game::server->Send(&bitStream, packet->systemAddress, false);
|
||||||
|
}
|
27
dChatServer/ChatIgnoreList.h
Normal file
27
dChatServer/ChatIgnoreList.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#ifndef __CHATIGNORELIST__H__
|
||||||
|
#define __CHATIGNORELIST__H__
|
||||||
|
|
||||||
|
struct Packet;
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace ChatIgnoreList {
|
||||||
|
void GetIgnoreList(Packet* packet);
|
||||||
|
void AddIgnore(Packet* packet);
|
||||||
|
void RemoveIgnore(Packet* packet);
|
||||||
|
|
||||||
|
enum class Response : uint8_t {
|
||||||
|
ADD_IGNORE = 32,
|
||||||
|
REMOVE_IGNORE = 33,
|
||||||
|
GET_IGNORE = 34,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class AddResponse : uint8_t {
|
||||||
|
SUCCESS,
|
||||||
|
ALREADY_IGNORED,
|
||||||
|
PLAYER_NOT_FOUND,
|
||||||
|
GENERAL_ERROR,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //!__CHATIGNORELIST__H__
|
File diff suppressed because it is too large
Load Diff
@ -4,16 +4,56 @@
|
|||||||
#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);
|
||||||
@ -23,18 +63,18 @@ namespace ChatPacketHandler {
|
|||||||
void HandleTeamLootOption(Packet* packet);
|
void HandleTeamLootOption(Packet* packet);
|
||||||
void HandleTeamStatusRequest(Packet* packet);
|
void HandleTeamStatusRequest(Packet* packet);
|
||||||
|
|
||||||
void SendTeamInvite(PlayerData* receiver, PlayerData* sender);
|
void SendTeamInvite(const PlayerData& receiver, const PlayerData& sender);
|
||||||
void SendTeamInviteConfirm(PlayerData* receiver, bool bLeaderIsFreeTrial, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, uint8_t ucResponseCode, std::u16string wsLeaderName);
|
void SendTeamInviteConfirm(const PlayerData& receiver, bool bLeaderIsFreeTrial, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, uint8_t ucResponseCode, std::u16string wsLeaderName);
|
||||||
void SendTeamStatus(PlayerData* receiver, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, std::u16string wsLeaderName);
|
void SendTeamStatus(const PlayerData& receiver, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, std::u16string wsLeaderName);
|
||||||
void SendTeamSetLeader(PlayerData* receiver, LWOOBJID i64PlayerID);
|
void SendTeamSetLeader(const PlayerData& receiver, LWOOBJID i64PlayerID);
|
||||||
void SendTeamAddPlayer(PlayerData* receiver, bool bIsFreeTrial, bool bLocal, bool bNoLootOnDeath, LWOOBJID i64PlayerID, std::u16string wsPlayerName, LWOZONEID zoneID);
|
void SendTeamAddPlayer(const PlayerData& receiver, bool bIsFreeTrial, bool bLocal, bool bNoLootOnDeath, LWOOBJID i64PlayerID, std::u16string wsPlayerName, LWOZONEID zoneID);
|
||||||
void SendTeamRemovePlayer(PlayerData* receiver, bool bDisband, bool bIsKicked, bool bIsLeaving, bool bLocal, LWOOBJID i64LeaderID, LWOOBJID i64PlayerID, std::u16string wsPlayerName);
|
void SendTeamRemovePlayer(const PlayerData& receiver, bool bDisband, bool bIsKicked, bool bIsLeaving, bool bLocal, LWOOBJID i64LeaderID, LWOOBJID i64PlayerID, std::u16string wsPlayerName);
|
||||||
void SendTeamSetOffWorldFlag(PlayerData* receiver, LWOOBJID i64PlayerID, LWOZONEID zoneID);
|
void SendTeamSetOffWorldFlag(const 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(PlayerData* friendData, PlayerData* playerData, uint8_t notifyType, uint8_t isBestFriend);
|
void SendFriendUpdate(const PlayerData& friendData, const PlayerData& playerData, uint8_t notifyType, uint8_t isBestFriend);
|
||||||
|
|
||||||
void SendFriendRequest(PlayerData* receiver, PlayerData* sender);
|
void SendFriendRequest(const PlayerData& receiver, const PlayerData& sender);
|
||||||
void SendFriendResponse(PlayerData* receiver, PlayerData* sender, eAddFriendResponseType responseCode, uint8_t isBestFriendsAlready = 0U, uint8_t isBestFriendRequest = 0U);
|
void SendFriendResponse(const PlayerData& receiver, const PlayerData& sender, eAddFriendResponseType responseCode, uint8_t isBestFriendsAlready = 0U, uint8_t isBestFriendRequest = 0U);
|
||||||
void SendRemoveFriend(PlayerData* receiver, std::string& personToRemove, bool isSuccessful);
|
void SendRemoveFriend(const PlayerData& receiver, std::string& personToRemove, bool isSuccessful);
|
||||||
};
|
};
|
||||||
|
@ -19,12 +19,15 @@
|
|||||||
#include "eChatMessageType.h"
|
#include "eChatMessageType.h"
|
||||||
#include "eChatInternalMessageType.h"
|
#include "eChatInternalMessageType.h"
|
||||||
#include "eWorldMessageType.h"
|
#include "eWorldMessageType.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;
|
||||||
@ -32,16 +35,13 @@ namespace Game {
|
|||||||
dConfig* config = nullptr;
|
dConfig* config = nullptr;
|
||||||
dChatFilter* chatFilter = nullptr;
|
dChatFilter* chatFilter = nullptr;
|
||||||
AssetManager* assetManager = nullptr;
|
AssetManager* assetManager = nullptr;
|
||||||
bool shouldShutdown = false;
|
Game::signal_t lastSignal = 0;
|
||||||
std::mt19937 randomEngine;
|
std::mt19937 randomEngine;
|
||||||
|
PlayerContainer playerContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Logger* SetupLogger();
|
|
||||||
void HandlePacket(Packet* packet);
|
void HandlePacket(Packet* packet);
|
||||||
|
|
||||||
PlayerContainer playerContainer;
|
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
constexpr uint32_t chatFramerate = mediumFramerate;
|
constexpr uint32_t chatFramerate = mediumFramerate;
|
||||||
constexpr uint32_t chatFrameDelta = mediumFrameDelta;
|
constexpr uint32_t chatFrameDelta = mediumFrameDelta;
|
||||||
@ -49,17 +49,19 @@ int main(int argc, char** argv) {
|
|||||||
Diagnostics::SetProcessFileName(argv[0]);
|
Diagnostics::SetProcessFileName(argv[0]);
|
||||||
Diagnostics::Initialize();
|
Diagnostics::Initialize();
|
||||||
|
|
||||||
|
std::signal(SIGINT, 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:
|
||||||
Game::logger = SetupLogger();
|
Server::SetupLogger("ChatServer");
|
||||||
if (!Game::logger) return EXIT_FAILURE;
|
if (!Game::logger) return EXIT_FAILURE;
|
||||||
|
|
||||||
//Read our config:
|
//Read our config:
|
||||||
Game::config = new dConfig((BinaryPathFinder::GetBinaryDir() / "chatconfig.ini").string());
|
|
||||||
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: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR);
|
LOG("Version: %s", PROJECT_VERSION);
|
||||||
LOG("Compiled on: %s", __TIMESTAMP__);
|
LOG("Compiled on: %s", __TIMESTAMP__);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -78,13 +80,8 @@ int main(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Connect to the MySQL Database
|
//Connect to the MySQL Database
|
||||||
std::string mysql_host = Game::config->GetValue("mysql_host");
|
|
||||||
std::string mysql_database = Game::config->GetValue("mysql_database");
|
|
||||||
std::string mysql_username = Game::config->GetValue("mysql_username");
|
|
||||||
std::string mysql_password = Game::config->GetValue("mysql_password");
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password);
|
Database::Connect();
|
||||||
} catch (sql::SQLException& ex) {
|
} catch (sql::SQLException& ex) {
|
||||||
LOG("Got an error while connecting to the database: %s", ex.what());
|
LOG("Got an error while connecting to the database: %s", ex.what());
|
||||||
Database::Destroy("ChatServer");
|
Database::Destroy("ChatServer");
|
||||||
@ -96,28 +93,30 @@ int main(int argc, char** argv) {
|
|||||||
//Find out the master's IP:
|
//Find out the master's IP:
|
||||||
std::string masterIP;
|
std::string masterIP;
|
||||||
uint32_t masterPort = 1000;
|
uint32_t masterPort = 1000;
|
||||||
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';");
|
auto masterInfo = Database::Get()->GetMasterInfo();
|
||||||
auto res = stmt->executeQuery();
|
if (masterInfo) {
|
||||||
while (res->next()) {
|
masterIP = masterInfo->ip;
|
||||||
masterIP = res->getString(1).c_str();
|
masterPort = masterInfo->port;
|
||||||
masterPort = res->getInt(2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delete res;
|
|
||||||
delete stmt;
|
|
||||||
|
|
||||||
//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.
|
||||||
uint32_t maxClients = 50;
|
uint32_t maxClients = 999;
|
||||||
uint32_t ourPort = 1501;
|
uint32_t ourPort = 1501;
|
||||||
if (Game::config->GetValue("max_clients") != "") maxClients = std::stoi(Game::config->GetValue("max_clients"));
|
std::string ourIP = "localhost";
|
||||||
if (Game::config->GetValue("port") != "") ourPort = std::atoi(Game::config->GetValue("port").c_str());
|
GeneralUtils::TryParse(Game::config->GetValue("max_clients"), maxClients);
|
||||||
|
GeneralUtils::TryParse(Game::config->GetValue("chat_server_port"), ourPort);
|
||||||
|
const auto externalIPString = Game::config->GetValue("external_ip");
|
||||||
|
if (!externalIPString.empty()) ourIP = externalIPString;
|
||||||
|
|
||||||
Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config, &Game::shouldShutdown);
|
Game::server = new dServer(ourIP, ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config, &Game::lastSignal);
|
||||||
|
|
||||||
Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(Game::config->GetValue("dont_generate_dcf"))));
|
bool dontGenerateDCF = false;
|
||||||
|
GeneralUtils::TryParse(Game::config->GetValue("dont_generate_dcf"), dontGenerateDCF);
|
||||||
|
Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", dontGenerateDCF);
|
||||||
|
|
||||||
Game::randomEngine = std::mt19937(time(0));
|
Game::randomEngine = std::mt19937(time(0));
|
||||||
|
|
||||||
|
Game::playerContainer.Initialize();
|
||||||
|
|
||||||
//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();
|
||||||
Packet* packet = nullptr;
|
Packet* packet = nullptr;
|
||||||
@ -127,7 +126,8 @@ int main(int argc, char** argv) {
|
|||||||
uint32_t framesSinceMasterDisconnect = 0;
|
uint32_t framesSinceMasterDisconnect = 0;
|
||||||
uint32_t framesSinceLastSQLPing = 0;
|
uint32_t framesSinceLastSQLPing = 0;
|
||||||
|
|
||||||
while (!Game::shouldShutdown) {
|
Game::logger->Flush(); // once immediately before main loop
|
||||||
|
while (!Game::ShouldShutdown()) {
|
||||||
//Check if we're still connected to master:
|
//Check if we're still connected to master:
|
||||||
if (!Game::server->GetIsConnectedToMaster()) {
|
if (!Game::server->GetIsConnectedToMaster()) {
|
||||||
framesSinceMasterDisconnect++;
|
framesSinceMasterDisconnect++;
|
||||||
@ -158,15 +158,12 @@ int main(int argc, char** argv) {
|
|||||||
//Find out the master's IP for absolutely no reason:
|
//Find out the master's IP for absolutely no reason:
|
||||||
std::string masterIP;
|
std::string masterIP;
|
||||||
uint32_t masterPort;
|
uint32_t masterPort;
|
||||||
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';");
|
|
||||||
auto res = stmt->executeQuery();
|
|
||||||
while (res->next()) {
|
|
||||||
masterIP = res->getString(1).c_str();
|
|
||||||
masterPort = res->getInt(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
delete res;
|
auto masterInfo = Database::Get()->GetMasterInfo();
|
||||||
delete stmt;
|
if (masterInfo) {
|
||||||
|
masterIP = masterInfo->ip;
|
||||||
|
masterPort = masterInfo->port;
|
||||||
|
}
|
||||||
|
|
||||||
framesSinceLastSQLPing = 0;
|
framesSinceLastSQLPing = 0;
|
||||||
} else framesSinceLastSQLPing++;
|
} else framesSinceLastSQLPing++;
|
||||||
@ -185,18 +182,6 @@ 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,19 +196,19 @@ void HandlePacket(Packet* packet) {
|
|||||||
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::CHAT_INTERNAL) {
|
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::CHAT_INTERNAL) {
|
||||||
switch (static_cast<eChatInternalMessageType>(packet->data[3])) {
|
switch (static_cast<eChatInternalMessageType>(packet->data[3])) {
|
||||||
case eChatInternalMessageType::PLAYER_ADDED_NOTIFICATION:
|
case eChatInternalMessageType::PLAYER_ADDED_NOTIFICATION:
|
||||||
playerContainer.InsertPlayer(packet);
|
Game::playerContainer.InsertPlayer(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case eChatInternalMessageType::PLAYER_REMOVED_NOTIFICATION:
|
case eChatInternalMessageType::PLAYER_REMOVED_NOTIFICATION:
|
||||||
playerContainer.RemovePlayer(packet);
|
Game::playerContainer.RemovePlayer(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case eChatInternalMessageType::MUTE_UPDATE:
|
case eChatInternalMessageType::MUTE_UPDATE:
|
||||||
playerContainer.MuteUpdate(packet);
|
Game::playerContainer.MuteUpdate(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case eChatInternalMessageType::CREATE_TEAM:
|
case eChatInternalMessageType::CREATE_TEAM:
|
||||||
playerContainer.CreateTeamServer(packet);
|
Game::playerContainer.CreateTeamServer(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case eChatInternalMessageType::ANNOUNCEMENT: {
|
case eChatInternalMessageType::ANNOUNCEMENT: {
|
||||||
@ -239,13 +224,22 @@ void HandlePacket(Packet* packet) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::CHAT) {
|
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::CHAT) {
|
||||||
switch (static_cast<eChatMessageType>(packet->data[3])) {
|
eChatMessageType chat_message_type = 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;
|
||||||
|
|
||||||
case eChatMessageType::GET_IGNORE_LIST:
|
case eChatMessageType::GET_IGNORE_LIST:
|
||||||
LOG("Asked for ignore list, but is unimplemented right now.");
|
ChatIgnoreList::GetIgnoreList(packet);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case eChatMessageType::ADD_IGNORE:
|
||||||
|
ChatIgnoreList::AddIgnore(packet);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case eChatMessageType::REMOVE_IGNORE:
|
||||||
|
ChatIgnoreList::RemoveIgnore(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case eChatMessageType::TEAM_GET_STATUS:
|
case eChatMessageType::TEAM_GET_STATUS:
|
||||||
@ -301,9 +295,61 @@ 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 id: %i", int(packet->data[3]));
|
LOG("Unknown CHAT Message id: %i", chat_message_type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,14 +10,21 @@
|
|||||||
#include "Database.h"
|
#include "Database.h"
|
||||||
#include "eConnectionType.h"
|
#include "eConnectionType.h"
|
||||||
#include "eChatInternalMessageType.h"
|
#include "eChatInternalMessageType.h"
|
||||||
|
#include "eGameMasterLevel.h"
|
||||||
#include "ChatPackets.h"
|
#include "ChatPackets.h"
|
||||||
#include "dConfig.h"
|
#include "dConfig.h"
|
||||||
|
|
||||||
PlayerContainer::PlayerContainer() {
|
void PlayerContainer::Initialize() {
|
||||||
|
GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("max_number_of_best_friends"), m_MaxNumberOfBestFriends);
|
||||||
|
GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("max_number_of_friends"), m_MaxNumberOfFriends);
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerContainer::~PlayerContainer() {
|
PlayerContainer::~PlayerContainer() {
|
||||||
mPlayers.clear();
|
m_Players.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayerData::PlayerData() {
|
||||||
|
gmLevel == eGameMasterLevel::CIVILIAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
TeamData::TeamData() {
|
TeamData::TeamData() {
|
||||||
@ -26,34 +33,33 @@ TeamData::TeamData() {
|
|||||||
|
|
||||||
void PlayerContainer::InsertPlayer(Packet* packet) {
|
void PlayerContainer::InsertPlayer(Packet* packet) {
|
||||||
CINSTREAM_SKIP_HEADER;
|
CINSTREAM_SKIP_HEADER;
|
||||||
PlayerData* data = new PlayerData();
|
LWOOBJID playerId;
|
||||||
inStream.Read(data->playerID);
|
if (!inStream.Read(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);
|
||||||
data->sysAddr = packet->systemAddress;
|
inStream.Read(data.gmLevel);
|
||||||
|
data.sysAddr = packet->systemAddress;
|
||||||
|
|
||||||
mNames[data->playerID] = GeneralUtils::UTF8ToUTF16(data->playerName);
|
m_Names[data.playerID] = GeneralUtils::UTF8ToUTF16(data.playerName);
|
||||||
|
|
||||||
mPlayers.insert(std::make_pair(data->playerID, data));
|
LOG("Added user: %s (%llu), zone: %i", data.playerName.c_str(), data.playerID, data.zoneID.GetMapID());
|
||||||
LOG("Added user: %s (%llu), zone: %i", data->playerName.c_str(), data->playerID, data->zoneID.GetMapID());
|
|
||||||
|
|
||||||
auto* insertLog = Database::CreatePreppedStmt("INSERT INTO activity_log (character_id, activity, time, map_id) VALUES (?, ?, ?, ?);");
|
Database::Get()->UpdateActivityLog(data.playerID, eActivityType::PlayerLoggedIn, data.zoneID.GetMapID());
|
||||||
|
|
||||||
insertLog->setInt(1, data->playerID);
|
|
||||||
insertLog->setInt(2, 0);
|
|
||||||
insertLog->setUInt64(3, time(nullptr));
|
|
||||||
insertLog->setInt(4, data->zoneID.GetMapID());
|
|
||||||
|
|
||||||
insertLog->executeUpdate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerContainer::RemovePlayer(Packet* packet) {
|
void PlayerContainer::RemovePlayer(Packet* packet) {
|
||||||
@ -62,42 +68,36 @@ 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.
|
||||||
std::unique_ptr<PlayerData> player(this->GetPlayerData(playerID));
|
const auto& player = GetPlayerData(playerID);
|
||||||
|
|
||||||
if (player == nullptr) {
|
if (!player) {
|
||||||
|
LOG("Failed to find user: %llu", playerID);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& fr : player->friends) {
|
for (const auto& fr : player.friends) {
|
||||||
auto fd = this->GetPlayerData(fr.friendID);
|
const auto& fd = this->GetPlayerData(fr.friendID);
|
||||||
if (fd) ChatPacketHandler::SendFriendUpdate(fd, player.get(), 0, fr.isBestFriend);
|
if (fd) ChatPacketHandler::SendFriendUpdate(fd, player, 0, fr.isBestFriend);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* team = GetTeam(playerID);
|
auto* team = GetTeam(playerID);
|
||||||
|
|
||||||
if (team != nullptr) {
|
if (team != nullptr) {
|
||||||
const auto memberName = GeneralUtils::UTF8ToUTF16(std::string(player->playerName.c_str()));
|
const auto memberName = GeneralUtils::UTF8ToUTF16(player.playerName);
|
||||||
|
|
||||||
for (const auto memberId : team->memberIDs) {
|
for (const auto memberId : team->memberIDs) {
|
||||||
auto* otherMember = GetPlayerData(memberId);
|
const auto& otherMember = GetPlayerData(memberId);
|
||||||
|
|
||||||
if (otherMember == nullptr) continue;
|
if (!otherMember) continue;
|
||||||
|
|
||||||
ChatPacketHandler::SendTeamSetOffWorldFlag(otherMember, playerID, { 0, 0, 0 });
|
ChatPacketHandler::SendTeamSetOffWorldFlag(otherMember, playerID, { 0, 0, 0 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG("Removed user: %llu", playerID);
|
LOG("Removed user: %llu", playerID);
|
||||||
mPlayers.erase(playerID);
|
m_Players.erase(playerID);
|
||||||
|
|
||||||
auto* insertLog = Database::CreatePreppedStmt("INSERT INTO activity_log (character_id, activity, time, map_id) VALUES (?, ?, ?, ?);");
|
Database::Get()->UpdateActivityLog(playerID, eActivityType::PlayerLoggedOut, player.zoneID.GetMapID());
|
||||||
|
|
||||||
insertLog->setInt(1, playerID);
|
|
||||||
insertLog->setInt(2, 1);
|
|
||||||
insertLog->setUInt64(3, time(nullptr));
|
|
||||||
insertLog->setInt(4, player->zoneID.GetMapID());
|
|
||||||
|
|
||||||
insertLog->executeUpdate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerContainer::MuteUpdate(Packet* packet) {
|
void PlayerContainer::MuteUpdate(Packet* packet) {
|
||||||
@ -107,15 +107,15 @@ void PlayerContainer::MuteUpdate(Packet* packet) {
|
|||||||
time_t expire = 0;
|
time_t expire = 0;
|
||||||
inStream.Read(expire);
|
inStream.Read(expire);
|
||||||
|
|
||||||
auto* player = this->GetPlayerData(playerID);
|
auto& player = this->GetPlayerDataMutable(playerID);
|
||||||
|
|
||||||
if (player == nullptr) {
|
if (!player) {
|
||||||
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);
|
||||||
}
|
}
|
||||||
@ -191,7 +191,7 @@ TeamData* PlayerContainer::CreateLocalTeam(std::vector<LWOOBJID> members) {
|
|||||||
TeamData* PlayerContainer::CreateTeam(LWOOBJID leader, bool local) {
|
TeamData* PlayerContainer::CreateTeam(LWOOBJID leader, bool local) {
|
||||||
auto* team = new TeamData();
|
auto* team = new TeamData();
|
||||||
|
|
||||||
team->teamID = ++mTeamIDCounter;
|
team->teamID = ++m_TeamIDCounter;
|
||||||
team->leaderID = leader;
|
team->leaderID = leader;
|
||||||
team->local = local;
|
team->local = local;
|
||||||
|
|
||||||
@ -213,11 +213,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");
|
||||||
auto* player = GetPlayerData(playerID);
|
const 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,18 +227,18 @@ void PlayerContainer::AddMember(TeamData* team, LWOOBJID playerID) {
|
|||||||
|
|
||||||
team->memberIDs.push_back(playerID);
|
team->memberIDs.push_back(playerID);
|
||||||
|
|
||||||
auto* leader = GetPlayerData(team->leaderID);
|
const auto& leader = GetPlayerData(team->leaderID);
|
||||||
auto* member = GetPlayerData(playerID);
|
const auto& member = GetPlayerData(playerID);
|
||||||
|
|
||||||
if (leader == nullptr || member == nullptr) return;
|
if (!leader || !member) 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);
|
||||||
}
|
}
|
||||||
@ -246,16 +246,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) {
|
||||||
auto* otherMember = GetPlayerData(memberId);
|
const 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 != nullptr ? otherMember->zoneID : LWOZONEID(0, 0, 0));
|
ChatPacketHandler::SendTeamAddPlayer(member, false, team->local, false, memberId, otherMemberName, otherMember ? otherMember.zoneID : LWOZONEID(0, 0, 0));
|
||||||
|
|
||||||
if (otherMember != nullptr) {
|
if (otherMember) {
|
||||||
ChatPacketHandler::SendTeamAddPlayer(otherMember, false, team->local, false, member->playerID, memberName, member->zoneID);
|
ChatPacketHandler::SendTeamAddPlayer(otherMember, false, team->local, false, member.playerID, memberName, member.zoneID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -265,9 +265,9 @@ void PlayerContainer::RemoveMember(TeamData* team, LWOOBJID playerID, bool disba
|
|||||||
|
|
||||||
if (index == team->memberIDs.end()) return;
|
if (index == team->memberIDs.end()) return;
|
||||||
|
|
||||||
auto* member = GetPlayerData(playerID);
|
const auto& member = GetPlayerData(playerID);
|
||||||
|
|
||||||
if (member != nullptr && !silent) {
|
if (member && !silent) {
|
||||||
ChatPacketHandler::SendTeamSetLeader(member, LWOOBJID_EMPTY);
|
ChatPacketHandler::SendTeamSetLeader(member, LWOOBJID_EMPTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,9 +278,9 @@ void PlayerContainer::RemoveMember(TeamData* team, LWOOBJID playerID, bool disba
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* otherMember = GetPlayerData(memberId);
|
const auto& otherMember = GetPlayerData(memberId);
|
||||||
|
|
||||||
if (otherMember == nullptr) continue;
|
if (!otherMember) continue;
|
||||||
|
|
||||||
ChatPacketHandler::SendTeamRemovePlayer(otherMember, disband, kicked, leaving, false, team->leaderID, playerID, memberName);
|
ChatPacketHandler::SendTeamRemovePlayer(otherMember, disband, kicked, leaving, false, team->leaderID, playerID, memberName);
|
||||||
}
|
}
|
||||||
@ -302,9 +302,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) {
|
||||||
auto* otherMember = GetPlayerData(memberId);
|
const auto& otherMember = GetPlayerData(memberId);
|
||||||
|
|
||||||
if (otherMember == nullptr) continue;
|
if (!otherMember) continue;
|
||||||
|
|
||||||
ChatPacketHandler::SendTeamSetLeader(otherMember, newLeader);
|
ChatPacketHandler::SendTeamSetLeader(otherMember, newLeader);
|
||||||
}
|
}
|
||||||
@ -316,14 +316,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) {
|
||||||
auto* otherMember = GetPlayerData(memberId);
|
const auto& otherMember = GetPlayerData(memberId);
|
||||||
|
|
||||||
if (otherMember == nullptr) continue;
|
if (!otherMember) 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);
|
||||||
@ -338,19 +338,19 @@ void PlayerContainer::TeamStatusUpdate(TeamData* team) {
|
|||||||
|
|
||||||
if (index == mTeams.end()) return;
|
if (index == mTeams.end()) return;
|
||||||
|
|
||||||
auto* leader = GetPlayerData(team->leaderID);
|
const auto& leader = GetPlayerData(team->leaderID);
|
||||||
|
|
||||||
if (leader == nullptr) return;
|
if (!leader) 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) {
|
||||||
auto* otherMember = GetPlayerData(memberId);
|
const auto& otherMember = GetPlayerData(memberId);
|
||||||
|
|
||||||
if (otherMember == nullptr) continue;
|
if (!otherMember) 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -366,7 +366,7 @@ void PlayerContainer::UpdateTeamsOnWorld(TeamData* team, bool deleteTeam) {
|
|||||||
|
|
||||||
if (!deleteTeam) {
|
if (!deleteTeam) {
|
||||||
bitStream.Write(team->lootFlag);
|
bitStream.Write(team->lootFlag);
|
||||||
bitStream.Write(static_cast<char>(team->memberIDs.size()));
|
bitStream.Write<char>(team->memberIDs.size());
|
||||||
for (const auto memberID : team->memberIDs) {
|
for (const auto memberID : team->memberIDs) {
|
||||||
bitStream.Write(memberID);
|
bitStream.Write(memberID);
|
||||||
}
|
}
|
||||||
@ -376,23 +376,42 @@ void PlayerContainer::UpdateTeamsOnWorld(TeamData* team, bool deleteTeam) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::u16string PlayerContainer::GetName(LWOOBJID playerID) {
|
std::u16string PlayerContainer::GetName(LWOOBJID playerID) {
|
||||||
const auto& pair = mNames.find(playerID);
|
const auto iter = m_Names.find(playerID);
|
||||||
|
|
||||||
if (pair == mNames.end()) return u"";
|
if (iter == m_Names.end()) return u"";
|
||||||
|
|
||||||
return pair->second;
|
return iter->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
LWOOBJID PlayerContainer::GetId(const std::u16string& playerName) {
|
LWOOBJID PlayerContainer::GetId(const std::u16string& playerName) {
|
||||||
for (const auto& pair : mNames) {
|
LWOOBJID toReturn = LWOOBJID_EMPTY;
|
||||||
if (pair.second == playerName) {
|
|
||||||
return pair.first;
|
for (const auto& [id, name] : m_Names) {
|
||||||
|
if (name == playerName) {
|
||||||
|
toReturn = id;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return LWOOBJID_EMPTY;
|
return toReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PlayerContainer::GetIsMuted(PlayerData* data) {
|
PlayerData& PlayerContainer::GetPlayerDataMutable(const LWOOBJID& playerID) {
|
||||||
return data->muteExpire == 1 || data->muteExpire > time(NULL);
|
return m_Players[playerID];
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
@ -7,14 +7,46 @@
|
|||||||
#include "dServer.h"
|
#include "dServer.h"
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
struct PlayerData {
|
enum class eGameMasterLevel : uint8_t;
|
||||||
LWOOBJID playerID;
|
|
||||||
|
struct IgnoreData {
|
||||||
|
IgnoreData(const std::string& name, const LWOOBJID& id) : playerName(name), playerId(id) {}
|
||||||
|
inline bool operator==(const std::string& other) const noexcept {
|
||||||
|
return playerName == other;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator==(const LWOOBJID& other) const noexcept {
|
||||||
|
return playerId == other;
|
||||||
|
}
|
||||||
|
|
||||||
|
LWOOBJID playerId = LWOOBJID_EMPTY;
|
||||||
std::string playerName;
|
std::string playerName;
|
||||||
SystemAddress sysAddr;
|
};
|
||||||
LWOZONEID zoneID;
|
|
||||||
std::vector<FriendData> friends;
|
struct PlayerData {
|
||||||
time_t muteExpire;
|
PlayerData();
|
||||||
|
operator bool() const noexcept {
|
||||||
|
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;
|
uint8_t countOfBestFriends = 0;
|
||||||
|
std::string playerName;
|
||||||
|
std::vector<FriendData> friends;
|
||||||
|
std::vector<IgnoreData> ignoredPlayers;
|
||||||
|
eGameMasterLevel gmLevel;
|
||||||
|
bool isFTP = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TeamData {
|
struct TeamData {
|
||||||
@ -29,31 +61,19 @@ struct TeamData {
|
|||||||
|
|
||||||
class PlayerContainer {
|
class PlayerContainer {
|
||||||
public:
|
public:
|
||||||
PlayerContainer();
|
|
||||||
~PlayerContainer();
|
~PlayerContainer();
|
||||||
|
|
||||||
|
void Initialize();
|
||||||
void InsertPlayer(Packet* packet);
|
void InsertPlayer(Packet* packet);
|
||||||
void RemovePlayer(Packet* packet);
|
void RemovePlayer(Packet* packet);
|
||||||
void MuteUpdate(Packet* packet);
|
void MuteUpdate(Packet* packet);
|
||||||
void CreateTeamServer(Packet* packet);
|
void CreateTeamServer(Packet* packet);
|
||||||
void BroadcastMuteUpdate(LWOOBJID player, time_t time);
|
void BroadcastMuteUpdate(LWOOBJID player, time_t time);
|
||||||
|
|
||||||
PlayerData* GetPlayerData(const LWOOBJID& playerID) {
|
const PlayerData& GetPlayerData(const LWOOBJID& playerID);
|
||||||
auto it = mPlayers.find(playerID);
|
const PlayerData& GetPlayerData(const std::string& playerName);
|
||||||
if (it != mPlayers.end()) return it->second;
|
PlayerData& GetPlayerDataMutable(const LWOOBJID& playerID);
|
||||||
return nullptr;
|
PlayerData& GetPlayerDataMutable(const std::string& playerName);
|
||||||
}
|
|
||||||
|
|
||||||
PlayerData* GetPlayerData(const std::string& playerName) {
|
|
||||||
for (auto player : mPlayers) {
|
|
||||||
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);
|
||||||
@ -66,14 +86,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 GetMaxNumberOfFriends() { return m_MaxNumberOfFriends; }
|
||||||
std::map<LWOOBJID, PlayerData*>& GetAllPlayerData() { return mPlayers; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
LWOOBJID mTeamIDCounter = 0;
|
LWOOBJID m_TeamIDCounter = 0;
|
||||||
std::map<LWOOBJID, PlayerData*> mPlayers;
|
std::map<LWOOBJID, PlayerData> m_Players;
|
||||||
std::vector<TeamData*> mTeams;
|
std::vector<TeamData*> mTeams;
|
||||||
std::unordered_map<LWOOBJID, std::u16string> mNames;
|
std::unordered_map<LWOOBJID, std::u16string> m_Names;
|
||||||
|
uint32_t m_MaxNumberOfBestFriends = 5;
|
||||||
|
uint32_t m_MaxNumberOfFriends = 50;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -54,17 +54,17 @@ void RakNet::BitStream::Write<AMFBaseValue&>(AMFBaseValue& value) {
|
|||||||
* 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 = (unsigned char)v;
|
unsigned char b4 = static_cast<unsigned char>(v);
|
||||||
if (v < 0x00200000) {
|
if (v < 0x00200000) {
|
||||||
b4 = b4 & 0x7F;
|
b4 = b4 & 0x7F;
|
||||||
if (v > 0x7F) {
|
if (v > 0x7F) {
|
||||||
unsigned char b3;
|
unsigned char b3;
|
||||||
v = v >> 7;
|
v = v >> 7;
|
||||||
b3 = ((unsigned char)(v)) | 0x80;
|
b3 = static_cast<unsigned char>(v) | 0x80;
|
||||||
if (v > 0x7F) {
|
if (v > 0x7F) {
|
||||||
unsigned char b2;
|
unsigned char b2;
|
||||||
v = v >> 7;
|
v = v >> 7;
|
||||||
b2 = ((unsigned char)(v)) | 0x80;
|
b2 = static_cast<unsigned char>(v) | 0x80;
|
||||||
bs->Write(b2);
|
bs->Write(b2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,11 +76,11 @@ void WriteUInt29(RakNet::BitStream* bs, uint32_t v) {
|
|||||||
unsigned char b3;
|
unsigned char b3;
|
||||||
|
|
||||||
v = v >> 8;
|
v = v >> 8;
|
||||||
b3 = ((unsigned char)(v)) | 0x80;
|
b3 = static_cast<unsigned char>(v) | 0x80;
|
||||||
v = v >> 7;
|
v = v >> 7;
|
||||||
b2 = ((unsigned char)(v)) | 0x80;
|
b2 = static_cast<unsigned char>(v) | 0x80;
|
||||||
v = v >> 7;
|
v = v >> 7;
|
||||||
b1 = ((unsigned char)(v)) | 0x80;
|
b1 = static_cast<unsigned char>(v) | 0x80;
|
||||||
|
|
||||||
bs->Write(b1);
|
bs->Write(b1);
|
||||||
bs->Write(b2);
|
bs->Write(b2);
|
||||||
@ -105,8 +105,8 @@ 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, (uint32_t)str.size());
|
WriteFlagNumber(bs, static_cast<uint32_t>(str.size()));
|
||||||
bs->Write(str.c_str(), (uint32_t)str.size());
|
bs->Write(str.c_str(), static_cast<uint32_t>(str.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#include "Amf3.h"
|
#include "Amf3.h"
|
||||||
|
|
||||||
// RakNet
|
// RakNet
|
||||||
#include <BitStream.h>
|
#include "BitStream.h"
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\file AmfSerialize.h
|
\file AmfSerialize.h
|
||||||
|
@ -1,14 +1,6 @@
|
|||||||
#include "BinaryIO.h"
|
#include "BinaryIO.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
void BinaryIO::WriteString(const std::string& stringToWrite, std::ofstream& outstream) {
|
|
||||||
//BinaryWrite(outstream, uint32_t(stringToWrite.length()));
|
|
||||||
|
|
||||||
for (size_t i = 0; i < size_t(stringToWrite.length()); ++i) {
|
|
||||||
BinaryIO::BinaryWrite(outstream, stringToWrite[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//For reading null-terminated strings
|
//For reading null-terminated strings
|
||||||
std::string BinaryIO::ReadString(std::istream& instream) {
|
std::string BinaryIO::ReadString(std::istream& instream) {
|
||||||
std::string toReturn;
|
std::string toReturn;
|
||||||
@ -23,36 +15,3 @@ std::string BinaryIO::ReadString(std::istream& instream) {
|
|||||||
|
|
||||||
return toReturn;
|
return toReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
//For reading strings of a specific size
|
|
||||||
std::string BinaryIO::ReadString(std::istream& instream, size_t size) {
|
|
||||||
std::string toReturn;
|
|
||||||
char buffer;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < size; ++i) {
|
|
||||||
BinaryIO::BinaryRead(instream, buffer);
|
|
||||||
toReturn += buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
return toReturn;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string BinaryIO::ReadWString(std::istream& instream) {
|
|
||||||
size_t size;
|
|
||||||
BinaryRead(instream, size);
|
|
||||||
//toReturn.resize(size);
|
|
||||||
std::string test;
|
|
||||||
unsigned char buf;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < size; ++i) {
|
|
||||||
//instream.ignore(1);
|
|
||||||
BinaryRead(instream, buf);
|
|
||||||
test += buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
//printf("%s\n", test.c_str());
|
|
||||||
|
|
||||||
//instream.read((char*)&toReturn[0], size * 2);
|
|
||||||
//std::string str(toReturn.begin(), toReturn.end());
|
|
||||||
return test;
|
|
||||||
}
|
|
||||||
|
@ -1,8 +1,17 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef __BINARYIO__H__
|
||||||
|
#define __BINARYIO__H__
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "Game.h"
|
||||||
|
#include "Logger.h"
|
||||||
|
|
||||||
namespace BinaryIO {
|
namespace BinaryIO {
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
std::ostream& BinaryWrite(std::ostream& stream, const T& value) {
|
std::ostream& BinaryWrite(std::ostream& stream, const T& value) {
|
||||||
return stream.write(reinterpret_cast<const char*>(&value), sizeof(T));
|
return stream.write(reinterpret_cast<const char*>(&value), sizeof(T));
|
||||||
@ -15,13 +24,51 @@ namespace BinaryIO {
|
|||||||
return stream.read(reinterpret_cast<char*>(&value), sizeof(T));
|
return stream.read(reinterpret_cast<char*>(&value), sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteString(const std::string& stringToWrite, std::ofstream& outstream);
|
enum class ReadType : int8_t {
|
||||||
|
WideString = 0,
|
||||||
|
String = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename SizeType>
|
||||||
|
inline void ReadString(std::istream& stream, std::u16string& value) {
|
||||||
|
static_assert(std::is_integral<SizeType>::value, "SizeType must be an integral type.");
|
||||||
|
|
||||||
|
SizeType size;
|
||||||
|
BinaryRead(stream, size);
|
||||||
|
|
||||||
|
if (!stream.good()) throw std::runtime_error("Failed to read from istream.");
|
||||||
|
value.resize(size);
|
||||||
|
stream.read(reinterpret_cast<char*>(value.data()), size * sizeof(uint16_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename SizeType>
|
||||||
|
inline void ReadString(std::istream& stream, std::string& value, ReadType readType) {
|
||||||
|
static_assert(std::is_integral<SizeType>::value, "SizeType must be an integral type.");
|
||||||
|
|
||||||
|
SizeType size;
|
||||||
|
BinaryRead(stream, size);
|
||||||
|
|
||||||
|
if (!stream.good()) throw std::runtime_error("Failed to read from istream.");
|
||||||
|
value.resize(size);
|
||||||
|
if (readType == ReadType::WideString) {
|
||||||
|
uint16_t wideChar;
|
||||||
|
|
||||||
|
// Faster to do this than to read a u16string and convert it to a string since we only go through allocator once
|
||||||
|
for (SizeType i = 0; i < size; ++i) {
|
||||||
|
BinaryRead(stream, wideChar);
|
||||||
|
value[i] = static_cast<char>(wideChar);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
stream.read(value.data(), size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::string ReadString(std::istream& instream);
|
std::string ReadString(std::istream& instream);
|
||||||
std::string ReadString(std::istream& instream, size_t size);
|
|
||||||
std::string ReadWString(std::istream& instream);
|
|
||||||
|
|
||||||
inline bool DoesFileExist(const std::string& name) {
|
inline bool DoesFileExist(const std::string& name) {
|
||||||
std::ifstream f(name.c_str());
|
std::ifstream f(name.c_str());
|
||||||
return f.good();
|
return f.good();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif //!__BINARYIO__H__
|
||||||
|
@ -13,9 +13,8 @@
|
|||||||
|
|
||||||
//! Forward declarations
|
//! Forward declarations
|
||||||
|
|
||||||
std::unique_ptr<sql::ResultSet> GetModelsFromDatabase();
|
|
||||||
void WriteSd0Magic(char* input, uint32_t chunkSize);
|
void WriteSd0Magic(char* input, uint32_t chunkSize);
|
||||||
bool CheckSd0Magic(sql::Blob* streamToCheck);
|
bool CheckSd0Magic(std::istream& streamToCheck);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Truncates all models with broken data from the database.
|
* @brief Truncates all models with broken data from the database.
|
||||||
@ -24,28 +23,24 @@ bool CheckSd0Magic(sql::Blob* streamToCheck);
|
|||||||
*/
|
*/
|
||||||
uint32_t BrickByBrickFix::TruncateBrokenBrickByBrickXml() {
|
uint32_t BrickByBrickFix::TruncateBrokenBrickByBrickXml() {
|
||||||
uint32_t modelsTruncated{};
|
uint32_t modelsTruncated{};
|
||||||
auto modelsToTruncate = GetModelsFromDatabase();
|
auto modelsToTruncate = Database::Get()->GetAllUgcModels();
|
||||||
bool previousCommitValue = Database::GetAutoCommit();
|
bool previousCommitValue = Database::Get()->GetAutoCommit();
|
||||||
Database::SetAutoCommit(false);
|
Database::Get()->SetAutoCommit(false);
|
||||||
while (modelsToTruncate->next()) {
|
for (auto& model : modelsToTruncate) {
|
||||||
std::unique_ptr<sql::PreparedStatement> ugcModelToDelete(Database::CreatePreppedStmt("DELETE FROM ugc WHERE ugc.id = ?;"));
|
|
||||||
std::unique_ptr<sql::PreparedStatement> pcModelToDelete(Database::CreatePreppedStmt("DELETE FROM properties_contents WHERE ugc_id = ?;"));
|
|
||||||
std::string completeUncompressedModel{};
|
std::string completeUncompressedModel{};
|
||||||
uint32_t chunkCount{};
|
uint32_t chunkCount{};
|
||||||
uint64_t modelId = modelsToTruncate->getInt(1);
|
|
||||||
std::unique_ptr<sql::Blob> modelAsSd0(modelsToTruncate->getBlob(2));
|
|
||||||
// Check that header is sd0 by checking for the sd0 magic.
|
// Check that header is sd0 by checking for the sd0 magic.
|
||||||
if (CheckSd0Magic(modelAsSd0.get())) {
|
if (CheckSd0Magic(model.lxfmlData)) {
|
||||||
while (true) {
|
while (true) {
|
||||||
uint32_t chunkSize{};
|
uint32_t chunkSize{};
|
||||||
modelAsSd0->read(reinterpret_cast<char*>(&chunkSize), sizeof(uint32_t)); // Extract chunk size from istream
|
model.lxfmlData.read(reinterpret_cast<char*>(&chunkSize), sizeof(uint32_t)); // Extract chunk size from istream
|
||||||
|
|
||||||
// Check if good here since if at the end of an sd0 file, this will have eof flagged.
|
// Check if good here since if at the end of an sd0 file, this will have eof flagged.
|
||||||
if (!modelAsSd0->good()) break;
|
if (!model.lxfmlData.good()) break;
|
||||||
|
|
||||||
std::unique_ptr<uint8_t[]> compressedChunk(new uint8_t[chunkSize]);
|
std::unique_ptr<uint8_t[]> compressedChunk(new uint8_t[chunkSize]);
|
||||||
for (uint32_t i = 0; i < chunkSize; i++) {
|
for (uint32_t i = 0; i < chunkSize; i++) {
|
||||||
compressedChunk[i] = modelAsSd0->get();
|
compressedChunk[i] = model.lxfmlData.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore the valgrind warning about uninitialized values. These are discarded later when we know the actual uncompressed size.
|
// Ignore the valgrind warning about uninitialized values. These are discarded later when we know the actual uncompressed size.
|
||||||
@ -56,10 +51,10 @@ uint32_t BrickByBrickFix::TruncateBrokenBrickByBrickXml() {
|
|||||||
|
|
||||||
if (actualUncompressedSize != -1) {
|
if (actualUncompressedSize != -1) {
|
||||||
uint32_t previousSize = completeUncompressedModel.size();
|
uint32_t previousSize = completeUncompressedModel.size();
|
||||||
completeUncompressedModel.append((char*)uncompressedChunk.get());
|
completeUncompressedModel.append(reinterpret_cast<char*>(uncompressedChunk.get()));
|
||||||
completeUncompressedModel.resize(previousSize + actualUncompressedSize);
|
completeUncompressedModel.resize(previousSize + actualUncompressedSize);
|
||||||
} else {
|
} else {
|
||||||
LOG("Failed to inflate chunk %i for model %llu. Error: %i", chunkCount, modelId, err);
|
LOG("Failed to inflate chunk %i for model %llu. Error: %i", chunkCount, model.id, err);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
chunkCount++;
|
chunkCount++;
|
||||||
@ -75,26 +70,20 @@ uint32_t BrickByBrickFix::TruncateBrokenBrickByBrickXml() {
|
|||||||
"</LXFML>",
|
"</LXFML>",
|
||||||
completeUncompressedModel.length() >= 15 ? completeUncompressedModel.length() - 15 : 0) == std::string::npos
|
completeUncompressedModel.length() >= 15 ? completeUncompressedModel.length() - 15 : 0) == std::string::npos
|
||||||
) {
|
) {
|
||||||
LOG("Brick-by-brick model %llu will be deleted!", modelId);
|
LOG("Brick-by-brick model %llu will be deleted!", model.id);
|
||||||
ugcModelToDelete->setInt64(1, modelsToTruncate->getInt64(1));
|
Database::Get()->DeleteUgcModelData(model.id);
|
||||||
pcModelToDelete->setInt64(1, modelsToTruncate->getInt64(1));
|
|
||||||
ugcModelToDelete->execute();
|
|
||||||
pcModelToDelete->execute();
|
|
||||||
modelsTruncated++;
|
modelsTruncated++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOG("Brick-by-brick model %llu will be deleted!", modelId);
|
LOG("Brick-by-brick model %llu will be deleted!", model.id);
|
||||||
ugcModelToDelete->setInt64(1, modelsToTruncate->getInt64(1));
|
Database::Get()->DeleteUgcModelData(model.id);
|
||||||
pcModelToDelete->setInt64(1, modelsToTruncate->getInt64(1));
|
|
||||||
ugcModelToDelete->execute();
|
|
||||||
pcModelToDelete->execute();
|
|
||||||
modelsTruncated++;
|
modelsTruncated++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Database::Commit();
|
Database::Get()->Commit();
|
||||||
Database::SetAutoCommit(previousCommitValue);
|
Database::Get()->SetAutoCommit(previousCommitValue);
|
||||||
return modelsTruncated;
|
return modelsTruncated;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,21 +95,17 @@ uint32_t BrickByBrickFix::TruncateBrokenBrickByBrickXml() {
|
|||||||
*/
|
*/
|
||||||
uint32_t BrickByBrickFix::UpdateBrickByBrickModelsToSd0() {
|
uint32_t BrickByBrickFix::UpdateBrickByBrickModelsToSd0() {
|
||||||
uint32_t updatedModels = 0;
|
uint32_t updatedModels = 0;
|
||||||
auto modelsToUpdate = GetModelsFromDatabase();
|
auto modelsToUpdate = Database::Get()->GetAllUgcModels();
|
||||||
auto previousAutoCommitState = Database::GetAutoCommit();
|
auto previousAutoCommitState = Database::Get()->GetAutoCommit();
|
||||||
Database::SetAutoCommit(false);
|
Database::Get()->SetAutoCommit(false);
|
||||||
std::unique_ptr<sql::PreparedStatement> insertionStatement(Database::CreatePreppedStmt("UPDATE ugc SET lxfml = ? WHERE id = ?;"));
|
for (auto& model : modelsToUpdate) {
|
||||||
while (modelsToUpdate->next()) {
|
|
||||||
int64_t modelId = modelsToUpdate->getInt64(1);
|
|
||||||
std::unique_ptr<sql::Blob> oldLxfml(modelsToUpdate->getBlob(2));
|
|
||||||
// Check if the stored blob starts with zlib magic (0x78 0xDA - best compression of zlib)
|
// Check if the stored blob starts with zlib magic (0x78 0xDA - best compression of zlib)
|
||||||
// If it does, convert it to sd0.
|
// If it does, convert it to sd0.
|
||||||
if (oldLxfml->get() == 0x78 && oldLxfml->get() == 0xDA) {
|
if (model.lxfmlData.get() == 0x78 && model.lxfmlData.get() == 0xDA) {
|
||||||
|
|
||||||
// Get and save size of zlib compressed chunk.
|
// Get and save size of zlib compressed chunk.
|
||||||
oldLxfml->seekg(0, std::ios::end);
|
model.lxfmlData.seekg(0, std::ios::end);
|
||||||
uint32_t oldLxfmlSize = static_cast<uint32_t>(oldLxfml->tellg());
|
uint32_t oldLxfmlSize = static_cast<uint32_t>(model.lxfmlData.tellg());
|
||||||
oldLxfml->seekg(0);
|
model.lxfmlData.seekg(0);
|
||||||
|
|
||||||
// Allocate 9 extra bytes. 5 for sd0 magic, 4 for the only zlib compressed size.
|
// Allocate 9 extra bytes. 5 for sd0 magic, 4 for the only zlib compressed size.
|
||||||
uint32_t oldLxfmlSizeWithHeader = oldLxfmlSize + 9;
|
uint32_t oldLxfmlSizeWithHeader = oldLxfmlSize + 9;
|
||||||
@ -128,34 +113,27 @@ uint32_t BrickByBrickFix::UpdateBrickByBrickModelsToSd0() {
|
|||||||
|
|
||||||
WriteSd0Magic(sd0ConvertedModel.get(), oldLxfmlSize);
|
WriteSd0Magic(sd0ConvertedModel.get(), oldLxfmlSize);
|
||||||
for (uint32_t i = 9; i < oldLxfmlSizeWithHeader; i++) {
|
for (uint32_t i = 9; i < oldLxfmlSizeWithHeader; i++) {
|
||||||
sd0ConvertedModel.get()[i] = oldLxfml->get();
|
sd0ConvertedModel.get()[i] = model.lxfmlData.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string outputString(sd0ConvertedModel.get(), oldLxfmlSizeWithHeader);
|
std::string outputString(sd0ConvertedModel.get(), oldLxfmlSizeWithHeader);
|
||||||
std::istringstream outputStringStream(outputString);
|
std::istringstream outputStringStream(outputString);
|
||||||
|
|
||||||
insertionStatement->setBlob(1, static_cast<std::istream*>(&outputStringStream));
|
|
||||||
insertionStatement->setInt64(2, modelId);
|
|
||||||
try {
|
try {
|
||||||
insertionStatement->executeUpdate();
|
Database::Get()->UpdateUgcModelData(model.id, outputStringStream);
|
||||||
LOG("Updated model %i to sd0", modelId);
|
LOG("Updated model %i to sd0", model.id);
|
||||||
updatedModels++;
|
updatedModels++;
|
||||||
} catch (sql::SQLException exception) {
|
} catch (sql::SQLException exception) {
|
||||||
LOG("Failed to update model %i. This model should be inspected manually to see why."
|
LOG("Failed to update model %i. This model should be inspected manually to see why."
|
||||||
"The database error is %s", modelId, exception.what());
|
"The database error is %s", model.id, exception.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Database::Commit();
|
Database::Get()->Commit();
|
||||||
Database::SetAutoCommit(previousAutoCommitState);
|
Database::Get()->SetAutoCommit(previousAutoCommitState);
|
||||||
return updatedModels;
|
return updatedModels;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<sql::ResultSet> GetModelsFromDatabase() {
|
|
||||||
std::unique_ptr<sql::PreparedStatement> modelsRawDataQuery(Database::CreatePreppedStmt("SELECT id, lxfml FROM ugc;"));
|
|
||||||
return std::unique_ptr<sql::ResultSet>(modelsRawDataQuery->executeQuery());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Writes sd0 magic at the front of a char*
|
* @brief Writes sd0 magic at the front of a char*
|
||||||
*
|
*
|
||||||
@ -171,6 +149,6 @@ void WriteSd0Magic(char* input, uint32_t chunkSize) {
|
|||||||
*reinterpret_cast<uint32_t*>(input + 5) = chunkSize; // Write the integer to the character array
|
*reinterpret_cast<uint32_t*>(input + 5) = chunkSize; // Write the integer to the character array
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckSd0Magic(sql::Blob* streamToCheck) {
|
bool CheckSd0Magic(std::istream& streamToCheck) {
|
||||||
return streamToCheck->get() == 's' && streamToCheck->get() == 'd' && streamToCheck->get() == '0' && streamToCheck->get() == 0x01 && streamToCheck->get() == 0xFF;
|
return streamToCheck.get() == 's' && streamToCheck.get() == 'd' && streamToCheck.get() == '0' && streamToCheck.get() == 0x01 && streamToCheck.get() == 0xFF;
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ set(DCOMMON_SOURCES
|
|||||||
"dConfig.cpp"
|
"dConfig.cpp"
|
||||||
"Diagnostics.cpp"
|
"Diagnostics.cpp"
|
||||||
"Logger.cpp"
|
"Logger.cpp"
|
||||||
|
"Game.cpp"
|
||||||
"GeneralUtils.cpp"
|
"GeneralUtils.cpp"
|
||||||
"LDFFormat.cpp"
|
"LDFFormat.cpp"
|
||||||
"MD5.cpp"
|
"MD5.cpp"
|
||||||
|
@ -71,7 +71,7 @@ LONG CALLBACK unhandled_handler(EXCEPTION_POINTERS* e) {
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
|
|
||||||
#if defined(__include_backtrace__)
|
#if defined(INCLUDE_BACKTRACE)
|
||||||
#include <backtrace.h>
|
#include <backtrace.h>
|
||||||
|
|
||||||
#include <backtrace-supported.h>
|
#include <backtrace-supported.h>
|
||||||
@ -115,7 +115,14 @@ void GenerateDump() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CatchUnhandled(int sig) {
|
void CatchUnhandled(int sig) {
|
||||||
#ifndef __include_backtrace__
|
std::exception_ptr eptr = std::current_exception();
|
||||||
|
try {
|
||||||
|
if (eptr) std::rethrow_exception(eptr);
|
||||||
|
} catch(const std::exception& e) {
|
||||||
|
LOG("Caught exception: '%s'", e.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef INCLUDE_BACKTRACE
|
||||||
|
|
||||||
std::string fileName = Diagnostics::GetOutDirectory() + "crash_" + Diagnostics::GetProcessName() + "_" + std::to_string(getpid()) + ".log";
|
std::string fileName = Diagnostics::GetOutDirectory() + "crash_" + Diagnostics::GetProcessName() + "_" + std::to_string(getpid()) + ".log";
|
||||||
LOG("Encountered signal %i, creating crash dump %s", sig, fileName.c_str());
|
LOG("Encountered signal %i, creating crash dump %s", sig, fileName.c_str());
|
||||||
@ -167,7 +174,7 @@ void CatchUnhandled(int sig) {
|
|||||||
backtrace_symbols_fd(array, size, STDOUT_FILENO);
|
backtrace_symbols_fd(array, size, STDOUT_FILENO);
|
||||||
# endif // defined(__GNUG__)
|
# endif // defined(__GNUG__)
|
||||||
|
|
||||||
#else // __include_backtrace__
|
#else // INCLUDE_BACKTRACE
|
||||||
|
|
||||||
struct backtrace_state* state = backtrace_create_state(
|
struct backtrace_state* state = backtrace_create_state(
|
||||||
Diagnostics::GetProcessFileName().c_str(),
|
Diagnostics::GetProcessFileName().c_str(),
|
||||||
@ -178,7 +185,7 @@ void CatchUnhandled(int sig) {
|
|||||||
struct bt_ctx ctx = { state, 0 };
|
struct bt_ctx ctx = { state, 0 };
|
||||||
Bt(state);
|
Bt(state);
|
||||||
|
|
||||||
#endif // __include_backtrace__
|
#endif // INCLUDE_BACKTRACE
|
||||||
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
@ -197,10 +204,10 @@ void MakeBacktrace() {
|
|||||||
sigact.sa_sigaction = CritErrHdlr;
|
sigact.sa_sigaction = CritErrHdlr;
|
||||||
sigact.sa_flags = SA_RESTART | SA_SIGINFO;
|
sigact.sa_flags = SA_RESTART | SA_SIGINFO;
|
||||||
|
|
||||||
if (sigaction(SIGSEGV, &sigact, (struct sigaction*)nullptr) != 0 ||
|
if (sigaction(SIGSEGV, &sigact, nullptr) != 0 ||
|
||||||
sigaction(SIGFPE, &sigact, (struct sigaction*)nullptr) != 0 ||
|
sigaction(SIGFPE, &sigact, nullptr) != 0 ||
|
||||||
sigaction(SIGABRT, &sigact, (struct sigaction*)nullptr) != 0 ||
|
sigaction(SIGABRT, &sigact, nullptr) != 0 ||
|
||||||
sigaction(SIGILL, &sigact, (struct sigaction*)nullptr) != 0) {
|
sigaction(SIGILL, &sigact, nullptr) != 0) {
|
||||||
fprintf(stderr, "error setting signal handler for %d (%s)\n",
|
fprintf(stderr, "error setting signal handler for %d (%s)\n",
|
||||||
SIGSEGV,
|
SIGSEGV,
|
||||||
strsignal(SIGSEGV));
|
strsignal(SIGSEGV));
|
||||||
|
@ -28,19 +28,17 @@ FdbToSqlite::Convert::Convert(std::string binaryOutPath) {
|
|||||||
this->m_BinaryOutPath = binaryOutPath;
|
this->m_BinaryOutPath = binaryOutPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FdbToSqlite::Convert::ConvertDatabase(AssetMemoryBuffer& buffer) {
|
bool FdbToSqlite::Convert::ConvertDatabase(AssetStream& buffer) {
|
||||||
if (m_ConversionStarted) return false;
|
if (m_ConversionStarted) return false;
|
||||||
|
|
||||||
std::istream cdClientBuffer(&buffer);
|
|
||||||
|
|
||||||
this->m_ConversionStarted = true;
|
this->m_ConversionStarted = true;
|
||||||
try {
|
try {
|
||||||
CDClientDatabase::Connect(m_BinaryOutPath + "/CDServer.sqlite");
|
CDClientDatabase::Connect(m_BinaryOutPath + "/CDServer.sqlite");
|
||||||
|
|
||||||
CDClientDatabase::ExecuteQuery("BEGIN TRANSACTION;");
|
CDClientDatabase::ExecuteQuery("BEGIN TRANSACTION;");
|
||||||
|
|
||||||
int32_t numberOfTables = ReadInt32(cdClientBuffer);
|
int32_t numberOfTables = ReadInt32(buffer);
|
||||||
ReadTables(numberOfTables, cdClientBuffer);
|
ReadTables(numberOfTables, buffer);
|
||||||
|
|
||||||
CDClientDatabase::ExecuteQuery("COMMIT;");
|
CDClientDatabase::ExecuteQuery("COMMIT;");
|
||||||
} catch (CppSQLite3Exception& e) {
|
} catch (CppSQLite3Exception& e) {
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
class AssetMemoryBuffer;
|
#include "AssetManager.h"
|
||||||
|
|
||||||
enum class eSqliteDataType : int32_t;
|
enum class eSqliteDataType : int32_t;
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ namespace FdbToSqlite {
|
|||||||
*
|
*
|
||||||
* @return true if the database was converted properly, false otherwise.
|
* @return true if the database was converted properly, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool ConvertDatabase(AssetMemoryBuffer& buffer);
|
bool ConvertDatabase(AssetStream& buffer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Reads a 32 bit int from the fdb file.
|
* @brief Reads a 32 bit int from the fdb file.
|
||||||
|
7
dCommon/Game.cpp
Normal file
7
dCommon/Game.cpp
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#include "Game.h"
|
||||||
|
|
||||||
|
namespace Game {
|
||||||
|
void OnSignal(int signal) {
|
||||||
|
lastSignal = signal;
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
#include <random>
|
#include <random>
|
||||||
|
#include <csignal>
|
||||||
|
|
||||||
class dServer;
|
class dServer;
|
||||||
class Logger;
|
class Logger;
|
||||||
@ -12,8 +14,10 @@ class AssetManager;
|
|||||||
struct SystemAddress;
|
struct SystemAddress;
|
||||||
class EntityManager;
|
class EntityManager;
|
||||||
class dZoneManager;
|
class dZoneManager;
|
||||||
|
class PlayerContainer;
|
||||||
|
|
||||||
namespace Game {
|
namespace Game {
|
||||||
|
using signal_t = volatile std::sig_atomic_t;
|
||||||
extern Logger* logger;
|
extern Logger* logger;
|
||||||
extern dServer* server;
|
extern dServer* server;
|
||||||
extern InstanceManager* im;
|
extern InstanceManager* im;
|
||||||
@ -23,7 +27,14 @@ namespace Game {
|
|||||||
extern RakPeerInterface* chatServer;
|
extern RakPeerInterface* chatServer;
|
||||||
extern AssetManager* assetManager;
|
extern AssetManager* assetManager;
|
||||||
extern SystemAddress chatSysAddr;
|
extern SystemAddress chatSysAddr;
|
||||||
extern bool shouldShutdown;
|
extern signal_t lastSignal;
|
||||||
extern EntityManager* entityManager;
|
extern EntityManager* entityManager;
|
||||||
extern dZoneManager* zoneManager;
|
extern dZoneManager* zoneManager;
|
||||||
|
extern PlayerContainer playerContainer;
|
||||||
|
extern std::string projectVersion;
|
||||||
|
|
||||||
|
inline bool ShouldShutdown() {
|
||||||
|
return lastSignal != 0;
|
||||||
|
}
|
||||||
|
void OnSignal(int signal);
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ bool _IsSuffixChar(uint8_t c) {
|
|||||||
bool GeneralUtils::_NextUTF8Char(std::string_view& slice, uint32_t& out) {
|
bool GeneralUtils::_NextUTF8Char(std::string_view& slice, uint32_t& out) {
|
||||||
size_t rem = slice.length();
|
size_t rem = slice.length();
|
||||||
if (slice.empty()) return false;
|
if (slice.empty()) return false;
|
||||||
const uint8_t* bytes = (const uint8_t*)&slice.front();
|
const uint8_t* bytes = reinterpret_cast<const uint8_t*>(&slice.front());
|
||||||
if (rem > 0) {
|
if (rem > 0) {
|
||||||
uint8_t first = bytes[0];
|
uint8_t first = bytes[0];
|
||||||
if (first < 0x80) { // 1 byte character
|
if (first < 0x80) { // 1 byte character
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
#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 "Game.h"
|
#include "Game.h"
|
||||||
@ -151,6 +151,11 @@ namespace GeneralUtils {
|
|||||||
return std::stod(value);
|
return std::stod(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline uint16_t Parse(const char* value) {
|
||||||
|
return std::stoul(value);
|
||||||
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
inline uint32_t Parse(const char* value) {
|
inline uint32_t Parse(const char* value) {
|
||||||
return std::stoul(value);
|
return std::stoul(value);
|
||||||
@ -229,18 +234,30 @@ namespace GeneralUtils {
|
|||||||
return T();
|
return T();
|
||||||
}
|
}
|
||||||
|
|
||||||
// on Windows we need to undef these or else they conflict with our numeric limits calls
|
/**
|
||||||
// DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS
|
* Casts the value of an enum entry to its underlying type
|
||||||
#ifdef _WIN32
|
* @param entry Enum entry to cast
|
||||||
#undef min
|
* @returns The enum entry's value in its underlying type
|
||||||
#undef max
|
*/
|
||||||
#endif
|
template <typename eType>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// on Windows we need to undef these or else they conflict with our numeric limits calls
|
||||||
|
// DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS
|
||||||
|
#ifdef _WIN32
|
||||||
|
#undef min
|
||||||
|
#undef max
|
||||||
|
#endif
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline T GenerateRandomNumber() {
|
inline T GenerateRandomNumber() {
|
||||||
// Make sure it is a numeric type
|
// Make sure it is a numeric type
|
||||||
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
|
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
|
||||||
|
|
||||||
return GenerateRandomNumber<T>(std::numeric_limits<T>::min(), std::numeric_limits<T>::max());
|
return GenerateRandomNumber<T>(std::numeric_limits<T>::min(), std::numeric_limits<T>::max());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,15 +63,15 @@ private:
|
|||||||
|
|
||||||
//! Writes the key to the packet
|
//! Writes the key to the packet
|
||||||
void WriteKey(RakNet::BitStream* packet) {
|
void WriteKey(RakNet::BitStream* packet) {
|
||||||
packet->Write(static_cast<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(static_cast<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(static_cast<uint8_t>(this->GetValueType()));
|
packet->Write<uint8_t>(this->GetValueType());
|
||||||
packet->Write(this->value);
|
packet->Write(this->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,30 +179,30 @@ 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(static_cast<uint8_t>(this->GetValueType()));
|
packet->Write<uint8_t>(this->GetValueType());
|
||||||
|
|
||||||
packet->Write(static_cast<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(static_cast<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(static_cast<uint8_t>(this->GetValueType()));
|
packet->Write<uint8_t>(this->GetValueType());
|
||||||
|
|
||||||
packet->Write(static_cast<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(static_cast<uint8_t>(this->GetValueType()));
|
packet->Write<uint8_t>(this->GetValueType());
|
||||||
|
|
||||||
packet->Write(static_cast<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(static_cast<uint8_t>(this->value[i]));
|
packet->Write<uint8_t>(this->value[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
Writer::~Writer() {
|
Writer::~Writer() {
|
||||||
|
// Flush before we close
|
||||||
|
Flush();
|
||||||
// Dont try to close stdcout...
|
// Dont try to close stdcout...
|
||||||
if (!m_Outfile || m_IsConsoleWriter) return;
|
if (!m_Outfile || m_IsConsoleWriter) return;
|
||||||
|
|
||||||
@ -14,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) return;
|
if (!m_Outfile || !m_Enabled) return;
|
||||||
|
|
||||||
fputs(time, m_Outfile);
|
fputs(time, m_Outfile);
|
||||||
fputs(message, m_Outfile);
|
fputs(message, m_Outfile);
|
||||||
|
@ -107,7 +107,7 @@ void Metrics::EndMeasurement(MetricVariable variable) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
float Metrics::ToMiliseconds(int64_t nanoseconds) {
|
float Metrics::ToMiliseconds(int64_t nanoseconds) {
|
||||||
return (float)nanoseconds / 1e6;
|
return static_cast<float>(nanoseconds) / 1e6;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Metrics::MetricVariableToString(MetricVariable variable) {
|
std::string Metrics::MetricVariableToString(MetricVariable variable) {
|
||||||
@ -193,34 +193,34 @@ size_t Metrics::GetPeakRSS() {
|
|||||||
/* Windows -------------------------------------------------- */
|
/* Windows -------------------------------------------------- */
|
||||||
PROCESS_MEMORY_COUNTERS info;
|
PROCESS_MEMORY_COUNTERS info;
|
||||||
GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info));
|
GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info));
|
||||||
return (size_t)info.PeakWorkingSetSize;
|
return static_cast<size_t>(info.PeakWorkingSetSize);
|
||||||
|
|
||||||
#elif (defined(_AIX) || defined(__TOS__AIX__)) || (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__)))
|
#elif (defined(_AIX) || defined(__TOS__AIX__)) || (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__)))
|
||||||
/* AIX and Solaris ------------------------------------------ */
|
/* AIX and Solaris ------------------------------------------ */
|
||||||
struct psinfo psinfo;
|
struct psinfo psinfo;
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
if ((fd = open("/proc/self/psinfo", O_RDONLY)) == -1)
|
if ((fd = open("/proc/self/psinfo", O_RDONLY)) == -1)
|
||||||
return (size_t)0L; /* Can't open? */
|
return static_cast<size_t>(0L); /* Can't open? */
|
||||||
if (read(fd, &psinfo, sizeof(psinfo)) != sizeof(psinfo)) {
|
if (read(fd, &psinfo, sizeof(psinfo)) != sizeof(psinfo)) {
|
||||||
close(fd);
|
close(fd);
|
||||||
return (size_t)0L; /* Can't read? */
|
return static_cast<size_t>(0L); /* Can't read? */
|
||||||
}
|
}
|
||||||
close(fd);
|
close(fd);
|
||||||
return (size_t)(psinfo.pr_rssize * 1024L);
|
return static_cast<size_t>(psinfo.pr_rssize * 1024L);
|
||||||
|
|
||||||
#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__))
|
#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__))
|
||||||
/* BSD, Linux, and OSX -------------------------------------- */
|
/* BSD, Linux, and OSX -------------------------------------- */
|
||||||
struct rusage rusage;
|
struct rusage rusage;
|
||||||
getrusage(RUSAGE_SELF, &rusage);
|
getrusage(RUSAGE_SELF, &rusage);
|
||||||
#if defined(__APPLE__) && defined(__MACH__)
|
#if defined(__APPLE__) && defined(__MACH__)
|
||||||
return (size_t)rusage.ru_maxrss;
|
return static_cast<size_t>(rusage.ru_maxrss);
|
||||||
#else
|
#else
|
||||||
return (size_t)(rusage.ru_maxrss * 1024L);
|
return static_cast<size_t>(rusage.ru_maxrss * 1024L);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#else
|
#else
|
||||||
/* Unknown OS ----------------------------------------------- */
|
/* Unknown OS ----------------------------------------------- */
|
||||||
return (size_t)0L; /* Unsupported. */
|
return static_cast<size_t>(0L); /* Unsupported. */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -234,33 +234,33 @@ size_t Metrics::GetCurrentRSS() {
|
|||||||
/* Windows -------------------------------------------------- */
|
/* Windows -------------------------------------------------- */
|
||||||
PROCESS_MEMORY_COUNTERS info;
|
PROCESS_MEMORY_COUNTERS info;
|
||||||
GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info));
|
GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info));
|
||||||
return (size_t)info.WorkingSetSize;
|
return static_cast<size_t>(info.WorkingSetSize);
|
||||||
|
|
||||||
#elif defined(__APPLE__) && defined(__MACH__)
|
#elif defined(__APPLE__) && defined(__MACH__)
|
||||||
/* OSX ------------------------------------------------------ */
|
/* OSX ------------------------------------------------------ */
|
||||||
struct mach_task_basic_info info;
|
struct mach_task_basic_info info;
|
||||||
mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT;
|
mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT;
|
||||||
if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO,
|
if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO,
|
||||||
(task_info_t)&info, &infoCount) != KERN_SUCCESS)
|
reinterpret_cast<task_info_t>(&info), &infoCount) != KERN_SUCCESS)
|
||||||
return (size_t)0L; /* Can't access? */
|
return static_cast<size_t>(0L); /* Can't access? */
|
||||||
return (size_t)info.resident_size;
|
return static_cast<size_t>(info.resident_size);
|
||||||
|
|
||||||
#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
|
#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
|
||||||
/* Linux ---------------------------------------------------- */
|
/* Linux ---------------------------------------------------- */
|
||||||
long rss = 0L;
|
long rss = 0L;
|
||||||
FILE* fp = NULL;
|
FILE* fp = NULL;
|
||||||
if ((fp = fopen("/proc/self/statm", "r")) == NULL)
|
if ((fp = fopen("/proc/self/statm", "r")) == NULL)
|
||||||
return (size_t)0L; /* Can't open? */
|
return static_cast<size_t>(0L); /* Can't open? */
|
||||||
if (fscanf(fp, "%*s%ld", &rss) != 1) {
|
if (fscanf(fp, "%*s%ld", &rss) != 1) {
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return (size_t)0L; /* Can't read? */
|
return static_cast<size_t>(0L); /* Can't read? */
|
||||||
}
|
}
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return (size_t)rss * (size_t)sysconf(_SC_PAGESIZE);
|
return static_cast<size_t>(rss) * static_cast<size_t>(sysconf(_SC_PAGESIZE));
|
||||||
|
|
||||||
#else
|
#else
|
||||||
/* AIX, BSD, Solaris, and Unknown OS ------------------------ */
|
/* AIX, BSD, Solaris, and Unknown OS ------------------------ */
|
||||||
return (size_t)0L; /* Unsupported. */
|
return static_cast<size_t>(0L); /* Unsupported. */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -114,13 +114,13 @@ bool NiPoint3::operator!=(const NiPoint3& point) const {
|
|||||||
//! Operator for subscripting
|
//! Operator for subscripting
|
||||||
float& NiPoint3::operator[](int i) {
|
float& NiPoint3::operator[](int i) {
|
||||||
float* base = &x;
|
float* base = &x;
|
||||||
return (float&)base[i];
|
return base[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Operator for subscripting
|
//! Operator for subscripting
|
||||||
const float& NiPoint3::operator[](int i) const {
|
const float& NiPoint3::operator[](int i) const {
|
||||||
const float* base = &x;
|
const float* base = &x;
|
||||||
return (float&)base[i];
|
return base[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Operator for addition of vectors
|
//! Operator for addition of vectors
|
||||||
@ -181,7 +181,7 @@ bool NiPoint3::IsWithinAxisAlignedBox(const NiPoint3& minPoint, const NiPoint3&
|
|||||||
if (this->y < minPoint.y) return false;
|
if (this->y < minPoint.y) return false;
|
||||||
if (this->y > maxPoint.y) return false;
|
if (this->y > maxPoint.y) return false;
|
||||||
|
|
||||||
return (this->z < maxPoint.z&& this->z > minPoint.z);
|
return (this->z < maxPoint.z && this->z > minPoint.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Checks to see if the point (or vector) is within a sphere
|
//! Checks to see if the point (or vector) is within a sphere
|
||||||
@ -232,10 +232,21 @@ NiPoint3 NiPoint3::MoveTowards(const NiPoint3& current, const NiPoint3& target,
|
|||||||
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;
|
||||||
float lengthSquared = (float)((double)dx * (double)dx + (double)dy * (double)dy + (double)dz * (double)dz);
|
|
||||||
if ((double)lengthSquared == 0.0 || (double)maxDistanceDelta >= 0.0 && (double)lengthSquared <= (double)maxDistanceDelta * (double)maxDistanceDelta)
|
float lengthSquared = static_cast<float>(
|
||||||
|
static_cast<double>(dx) * static_cast<double>(dx) +
|
||||||
|
static_cast<double>(dy) * static_cast<double>(dy) +
|
||||||
|
static_cast<double>(dz) * static_cast<double>(dz)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (static_cast<double>(lengthSquared) == 0.0
|
||||||
|
|| static_cast<double>(maxDistanceDelta) >= 0.0
|
||||||
|
&& static_cast<double>(lengthSquared)
|
||||||
|
<= static_cast<double>(maxDistanceDelta) * static_cast<double>(maxDistanceDelta)) {
|
||||||
return target;
|
return target;
|
||||||
float length = (float)std::sqrt((double)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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
50
dCommon/PositionUpdate.h
Normal file
50
dCommon/PositionUpdate.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#ifndef __POSITIONUPDATE__H__
|
||||||
|
#define __POSITIONUPDATE__H__
|
||||||
|
|
||||||
|
#include "NiPoint3.h"
|
||||||
|
#include "NiQuaternion.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct RemoteInputInfo {
|
||||||
|
RemoteInputInfo() {
|
||||||
|
m_RemoteInputX = 0;
|
||||||
|
m_RemoteInputY = 0;
|
||||||
|
m_IsPowersliding = false;
|
||||||
|
m_IsModified = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator=(const RemoteInputInfo& other) {
|
||||||
|
m_RemoteInputX = other.m_RemoteInputX;
|
||||||
|
m_RemoteInputY = other.m_RemoteInputY;
|
||||||
|
m_IsPowersliding = other.m_IsPowersliding;
|
||||||
|
m_IsModified = other.m_IsModified;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
float m_RemoteInputY;
|
||||||
|
bool m_IsPowersliding;
|
||||||
|
bool m_IsModified;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LocalSpaceInfo {
|
||||||
|
LWOOBJID objectId = LWOOBJID_EMPTY;
|
||||||
|
NiPoint3 position = NiPoint3::ZERO;
|
||||||
|
NiPoint3 linearVelocity = NiPoint3::ZERO;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PositionUpdate {
|
||||||
|
NiPoint3 position = NiPoint3::ZERO;
|
||||||
|
NiQuaternion rotation = NiQuaternion::IDENTITY;
|
||||||
|
bool onGround = false;
|
||||||
|
bool onRail = false;
|
||||||
|
NiPoint3 velocity = NiPoint3::ZERO;
|
||||||
|
NiPoint3 angularVelocity = NiPoint3::ZERO;
|
||||||
|
LocalSpaceInfo localSpaceInfo;
|
||||||
|
RemoteInputInfo remoteInputInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //!__POSITIONUPDATE__H__
|
@ -1,3 +1,5 @@
|
|||||||
|
// Source: http://www.zedwood.com/article/cpp-sha512-function
|
||||||
|
|
||||||
#include "SHA512.h"
|
#include "SHA512.h"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
@ -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) {
|
||||||
|
@ -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)) {
|
||||||
@ -81,8 +81,8 @@ bool AssetManager::HasFile(const char* name) {
|
|||||||
std::replace(fixedName.begin(), fixedName.end(), '/', '\\');
|
std::replace(fixedName.begin(), fixedName.end(), '/', '\\');
|
||||||
if (fixedName.rfind("client\\res\\", 0) != 0) fixedName = "client\\res\\" + fixedName;
|
if (fixedName.rfind("client\\res\\", 0) != 0) fixedName = "client\\res\\" + fixedName;
|
||||||
|
|
||||||
uint32_t crc = crc32b(0xFFFFFFFF, (uint8_t*)fixedName.c_str(), fixedName.size());
|
uint32_t crc = crc32b(0xFFFFFFFF, reinterpret_cast<uint8_t*>(const_cast<char*>(fixedName.c_str())), fixedName.size());
|
||||||
crc = crc32b(crc, (Bytef*)"\0\0\0\0", 4);
|
crc = crc32b(crc, reinterpret_cast<Bytef*>(const_cast<char*>("\0\0\0\0")), 4);
|
||||||
|
|
||||||
for (const auto& item : this->m_PackIndex->GetPackFileIndices()) {
|
for (const auto& item : this->m_PackIndex->GetPackFileIndices()) {
|
||||||
if (item.m_Crc == crc) {
|
if (item.m_Crc == crc) {
|
||||||
@ -113,7 +113,7 @@ bool AssetManager::GetFile(const char* name, char** data, uint32_t* len) {
|
|||||||
#endif
|
#endif
|
||||||
fseek(file, 0, SEEK_END);
|
fseek(file, 0, SEEK_END);
|
||||||
*len = ftell(file);
|
*len = ftell(file);
|
||||||
*data = (char*)malloc(*len);
|
*data = static_cast<char*>(malloc(*len));
|
||||||
fseek(file, 0, SEEK_SET);
|
fseek(file, 0, SEEK_SET);
|
||||||
int32_t readInData = fread(*data, sizeof(uint8_t), *len, file);
|
int32_t readInData = fread(*data, sizeof(uint8_t), *len, file);
|
||||||
fclose(file);
|
fclose(file);
|
||||||
@ -129,8 +129,8 @@ bool AssetManager::GetFile(const char* name, char** data, uint32_t* len) {
|
|||||||
fixedName = "client\\res\\" + fixedName;
|
fixedName = "client\\res\\" + fixedName;
|
||||||
}
|
}
|
||||||
int32_t packIndex = -1;
|
int32_t packIndex = -1;
|
||||||
uint32_t crc = crc32b(0xFFFFFFFF, (uint8_t*)fixedName.c_str(), fixedName.size());
|
uint32_t crc = crc32b(0xFFFFFFFF, reinterpret_cast<uint8_t*>(const_cast<char*>(fixedName.c_str())), fixedName.size());
|
||||||
crc = crc32b(crc, (Bytef*)"\0\0\0\0", 4);
|
crc = crc32b(crc, reinterpret_cast<Bytef*>(const_cast<char*>("\0\0\0\0")), 4);
|
||||||
|
|
||||||
for (const auto& item : this->m_PackIndex->GetPackFileIndices()) {
|
for (const auto& item : this->m_PackIndex->GetPackFileIndices()) {
|
||||||
if (item.m_Crc == crc) {
|
if (item.m_Crc == crc) {
|
||||||
@ -152,13 +152,12 @@ bool AssetManager::GetFile(const char* name, char** data, uint32_t* len) {
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
AssetMemoryBuffer AssetManager::GetFileAsBuffer(const char* name) {
|
AssetStream AssetManager::GetFile(const char* name) {
|
||||||
char* buf;
|
char* buf; uint32_t len;
|
||||||
uint32_t len;
|
|
||||||
|
|
||||||
bool success = this->GetFile(name, &buf, &len);
|
bool success = this->GetFile(name, &buf, &len);
|
||||||
|
|
||||||
return AssetMemoryBuffer(buf, len, success);
|
return AssetStream(buf, len, success);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t AssetManager::crc32b(uint32_t base, uint8_t* message, size_t l) {
|
uint32_t AssetManager::crc32b(uint32_t base, uint8_t* message, size_t l) {
|
||||||
@ -168,7 +167,7 @@ uint32_t AssetManager::crc32b(uint32_t base, uint8_t* message, size_t l) {
|
|||||||
crc = base;
|
crc = base;
|
||||||
for (i = 0; i < l; i++) {
|
for (i = 0; i < l; i++) {
|
||||||
// xor next byte to upper bits of crc
|
// xor next byte to upper bits of crc
|
||||||
crc ^= (((unsigned int)message[i]) << 24);
|
crc ^= (static_cast<unsigned int>(message[i]) << 24);
|
||||||
for (j = 0; j < 8; j++) { // Do eight times.
|
for (j = 0; j < 8; j++) { // Do eight times.
|
||||||
msb = crc >> 31;
|
msb = crc >> 31;
|
||||||
crc <<= 1;
|
crc <<= 1;
|
||||||
|
@ -25,6 +25,10 @@ struct AssetMemoryBuffer : std::streambuf {
|
|||||||
this->setg(base, base, base + n);
|
this->setg(base, base, base + n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~AssetMemoryBuffer() {
|
||||||
|
if (m_Success) free(m_Base);
|
||||||
|
}
|
||||||
|
|
||||||
pos_type seekpos(pos_type sp, std::ios_base::openmode which) override {
|
pos_type seekpos(pos_type sp, std::ios_base::openmode which) override {
|
||||||
return seekoff(sp - pos_type(off_type(0)), std::ios_base::beg, which);
|
return seekoff(sp - pos_type(off_type(0)), std::ios_base::beg, which);
|
||||||
}
|
}
|
||||||
@ -40,9 +44,17 @@ struct AssetMemoryBuffer : std::streambuf {
|
|||||||
setg(eback(), eback() + off, egptr());
|
setg(eback(), eback() + off, egptr());
|
||||||
return gptr() - eback();
|
return gptr() - eback();
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
void close() {
|
struct AssetStream : std::istream {
|
||||||
free(m_Base);
|
AssetStream(char* base, std::ptrdiff_t n, bool success) : std::istream(new AssetMemoryBuffer(base, n, success)) {}
|
||||||
|
|
||||||
|
~AssetStream() {
|
||||||
|
delete rdbuf();
|
||||||
|
}
|
||||||
|
|
||||||
|
operator bool() {
|
||||||
|
return reinterpret_cast<AssetMemoryBuffer*>(rdbuf())->m_Success;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -56,7 +68,7 @@ public:
|
|||||||
|
|
||||||
bool HasFile(const char* name);
|
bool HasFile(const char* name);
|
||||||
bool GetFile(const char* name, char** data, uint32_t* len);
|
bool GetFile(const char* name, char** data, uint32_t* len);
|
||||||
AssetMemoryBuffer GetFileAsBuffer(const char* name);
|
AssetStream GetFile(const char* name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void LoadPackIndex();
|
void LoadPackIndex();
|
||||||
|
@ -76,7 +76,7 @@ bool Pack::ReadFileFromPack(uint32_t crc, char** data, uint32_t* len) {
|
|||||||
fseek(file, pos, SEEK_SET);
|
fseek(file, pos, SEEK_SET);
|
||||||
|
|
||||||
if (!isCompressed) {
|
if (!isCompressed) {
|
||||||
char* tempData = (char*)malloc(pkRecord.m_UncompressedSize);
|
char* tempData = static_cast<char*>(malloc(pkRecord.m_UncompressedSize));
|
||||||
int32_t readInData = fread(tempData, sizeof(uint8_t), pkRecord.m_UncompressedSize, file);
|
int32_t readInData = fread(tempData, sizeof(uint8_t), pkRecord.m_UncompressedSize, file);
|
||||||
|
|
||||||
*data = tempData;
|
*data = tempData;
|
||||||
@ -90,7 +90,7 @@ bool Pack::ReadFileFromPack(uint32_t crc, char** data, uint32_t* len) {
|
|||||||
|
|
||||||
fseek(file, pos, SEEK_SET);
|
fseek(file, pos, SEEK_SET);
|
||||||
|
|
||||||
char* decompressedData = (char*)malloc(pkRecord.m_UncompressedSize);
|
char* decompressedData = static_cast<char*>(malloc(pkRecord.m_UncompressedSize));
|
||||||
uint32_t currentReadPos = 0;
|
uint32_t currentReadPos = 0;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -100,12 +100,12 @@ bool Pack::ReadFileFromPack(uint32_t crc, char** data, uint32_t* len) {
|
|||||||
int32_t readInData = fread(&size, sizeof(uint32_t), 1, file);
|
int32_t readInData = fread(&size, sizeof(uint32_t), 1, file);
|
||||||
pos += 4; // Move pointer position 4 to the right
|
pos += 4; // Move pointer position 4 to the right
|
||||||
|
|
||||||
char* chunk = (char*)malloc(size);
|
char* chunk = static_cast<char*>(malloc(size));
|
||||||
int32_t readInData2 = fread(chunk, sizeof(int8_t), size, file);
|
int32_t readInData2 = fread(chunk, sizeof(int8_t), size, file);
|
||||||
pos += size; // Move pointer position the amount of bytes read to the right
|
pos += size; // Move pointer position the amount of bytes read to the right
|
||||||
|
|
||||||
int32_t err;
|
int32_t err;
|
||||||
currentReadPos += ZCompression::Decompress((uint8_t*)chunk, size, reinterpret_cast<uint8_t*>(decompressedData + currentReadPos), ZCompression::MAX_SD0_CHUNK_SIZE, err);
|
currentReadPos += ZCompression::Decompress(reinterpret_cast<uint8_t*>(chunk), size, reinterpret_cast<uint8_t*>(decompressedData + currentReadPos), ZCompression::MAX_SD0_CHUNK_SIZE, err);
|
||||||
|
|
||||||
free(chunk);
|
free(chunk);
|
||||||
}
|
}
|
||||||
|
@ -8,21 +8,10 @@ PackIndex::PackIndex(const std::filesystem::path& filePath) {
|
|||||||
|
|
||||||
BinaryIO::BinaryRead<uint32_t>(m_FileStream, m_Version);
|
BinaryIO::BinaryRead<uint32_t>(m_FileStream, m_Version);
|
||||||
BinaryIO::BinaryRead<uint32_t>(m_FileStream, m_PackPathCount);
|
BinaryIO::BinaryRead<uint32_t>(m_FileStream, m_PackPathCount);
|
||||||
|
|
||||||
for (int i = 0; i < m_PackPathCount; i++) {
|
m_PackPaths.resize(m_PackPathCount);
|
||||||
uint32_t stringLen = 0;
|
for (auto& item : m_PackPaths) {
|
||||||
BinaryIO::BinaryRead<uint32_t>(m_FileStream, stringLen);
|
BinaryIO::ReadString<uint32_t>(m_FileStream, item, BinaryIO::ReadType::String);
|
||||||
|
|
||||||
std::string path;
|
|
||||||
|
|
||||||
for (int j = 0; j < stringLen; j++) {
|
|
||||||
char inChar;
|
|
||||||
BinaryIO::BinaryRead<char>(m_FileStream, inChar);
|
|
||||||
|
|
||||||
path += inChar;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_PackPaths.push_back(path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BinaryIO::BinaryRead<uint32_t>(m_FileStream, m_PackFileIndexCount);
|
BinaryIO::BinaryRead<uint32_t>(m_FileStream, m_PackFileIndexCount);
|
||||||
|
@ -10,8 +10,23 @@ dConfig::dConfig(const std::string& filepath) {
|
|||||||
LoadConfig();
|
LoadConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::filesystem::path GetConfigDir() {
|
||||||
|
std::filesystem::path config_dir = BinaryPathFinder::GetBinaryDir();
|
||||||
|
if (const char* env_p = std::getenv("DLU_CONFIG_DIR")) {
|
||||||
|
config_dir /= env_p;
|
||||||
|
}
|
||||||
|
return config_dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool dConfig::Exists(const std::string& filepath) {
|
||||||
|
std::filesystem::path config_dir = GetConfigDir();
|
||||||
|
return std::filesystem::exists(config_dir / filepath);
|
||||||
|
}
|
||||||
|
|
||||||
void dConfig::LoadConfig() {
|
void dConfig::LoadConfig() {
|
||||||
std::ifstream in(BinaryPathFinder::GetBinaryDir() / m_ConfigFilePath);
|
std::filesystem::path config_dir = GetConfigDir();
|
||||||
|
|
||||||
|
std::ifstream in(config_dir / m_ConfigFilePath);
|
||||||
if (!in.good()) return;
|
if (!in.good()) return;
|
||||||
|
|
||||||
std::string line{};
|
std::string line{};
|
||||||
@ -19,7 +34,7 @@ void dConfig::LoadConfig() {
|
|||||||
if (!line.empty() && line.front() != '#') ProcessLine(line);
|
if (!line.empty() && line.front() != '#') ProcessLine(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ifstream sharedConfig(BinaryPathFinder::GetBinaryDir() / "sharedconfig.ini", std::ios::in);
|
std::ifstream sharedConfig(config_dir / "sharedconfig.ini", std::ios::in);
|
||||||
if (!sharedConfig.good()) return;
|
if (!sharedConfig.good()) return;
|
||||||
|
|
||||||
line.clear();
|
line.clear();
|
||||||
@ -34,23 +49,20 @@ void dConfig::ReloadConfig() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const std::string& dConfig::GetValue(std::string key) {
|
const std::string& dConfig::GetValue(std::string key) {
|
||||||
static std::string emptyString{};
|
std::string upper_key(key);
|
||||||
|
std::transform(upper_key.begin(), upper_key.end(), upper_key.begin(), ::toupper);
|
||||||
const auto& it = this->m_ConfigValues.find(key);
|
if (const char* env_p = std::getenv(upper_key.c_str())) {
|
||||||
|
this->m_ConfigValues[key] = env_p;
|
||||||
if (it == this->m_ConfigValues.end()) return emptyString;
|
}
|
||||||
|
return this->m_ConfigValues[key];
|
||||||
return it->second;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void dConfig::ProcessLine(const std::string& line) {
|
void dConfig::ProcessLine(const std::string& line) {
|
||||||
auto splitLine = GeneralUtils::SplitString(line, '=');
|
auto splitLoc = line.find('=');
|
||||||
|
auto key = line.substr(0, splitLoc);
|
||||||
if (splitLine.size() != 2) return;
|
auto value = line.substr(splitLoc + 1);
|
||||||
|
|
||||||
//Make sure that on Linux, we remove special characters:
|
//Make sure that on Linux, we remove special characters:
|
||||||
auto& key = splitLine.at(0);
|
|
||||||
auto& value = splitLine.at(1);
|
|
||||||
if (!value.empty() && value.at(value.size() - 1) == '\r') value.erase(value.size() - 1);
|
if (!value.empty() && value.at(value.size() - 1) == '\r') value.erase(value.size() - 1);
|
||||||
|
|
||||||
if (this->m_ConfigValues.find(key) != this->m_ConfigValues.end()) return;
|
if (this->m_ConfigValues.find(key) != this->m_ConfigValues.end()) return;
|
||||||
|
@ -7,6 +7,11 @@ class dConfig {
|
|||||||
public:
|
public:
|
||||||
dConfig(const std::string& filepath);
|
dConfig(const std::string& filepath);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the specified filepath exists
|
||||||
|
*/
|
||||||
|
static const bool Exists(const std::string& filepath);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the specified key from the config. Returns an empty string if the value is not found.
|
* Gets the specified key from the config. Returns an empty string if the value is not found.
|
||||||
*
|
*
|
||||||
|
29
dCommon/dEnums/StringifiedEnum.h
Normal file
29
dCommon/dEnums/StringifiedEnum.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#ifndef __STRINGIFIEDENUM_H__
|
||||||
|
#define __STRINGIFIEDENUM_H__
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include "magic_enum.hpp"
|
||||||
|
|
||||||
|
namespace StringifiedEnum {
|
||||||
|
template<typename T>
|
||||||
|
const std::string_view ToString(const T e) {
|
||||||
|
static_assert(std::is_enum_v<T>, "Not an enum"); // Check type
|
||||||
|
|
||||||
|
constexpr auto sv = &magic_enum::enum_entries<T>();
|
||||||
|
|
||||||
|
const auto it = std::lower_bound(
|
||||||
|
sv->begin(), sv->end(), e,
|
||||||
|
[&](const std::pair<T, std::string_view>& lhs, const T rhs) { return lhs.first < rhs; }
|
||||||
|
);
|
||||||
|
|
||||||
|
std::string_view output;
|
||||||
|
if (it != sv->end() && it->first == e) {
|
||||||
|
output = it->second;
|
||||||
|
} else {
|
||||||
|
output = "UNKNOWN";
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // !__STRINGIFIEDENUM_H__
|
@ -130,7 +130,7 @@ public:
|
|||||||
LWOOBJID friendID;
|
LWOOBJID friendID;
|
||||||
std::string friendName;
|
std::string friendName;
|
||||||
|
|
||||||
void Serialize(RakNet::BitStream& bitStream) {
|
void Serialize(RakNet::BitStream& bitStream) const {
|
||||||
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);
|
||||||
@ -148,11 +148,11 @@ public:
|
|||||||
if (size > maxSize) size = maxSize;
|
if (size > maxSize) size = maxSize;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < size; ++i) {
|
for (uint32_t i = 0; i < size; ++i) {
|
||||||
bitStream.Write(static_cast<uint16_t>(friendName[i]));
|
bitStream.Write<uint16_t>(friendName[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint32_t j = 0; j < remSize; ++j) {
|
for (uint32_t j = 0; j < remSize; ++j) {
|
||||||
bitStream.Write(static_cast<uint16_t>(0));
|
bitStream.Write<uint16_t>(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bitStream.Write<uint32_t>(0); //???
|
bitStream.Write<uint32_t>(0); //???
|
||||||
|
File diff suppressed because it is too large
Load Diff
13
dCommon/dEnums/ePetAbilityType.h
Normal file
13
dCommon/dEnums/ePetAbilityType.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#ifndef __EPETABILITYTYPE__H__
|
||||||
|
#define __EPETABILITYTYPE__H__
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
enum class ePetAbilityType : uint32_t {
|
||||||
|
Invalid,
|
||||||
|
GoToObject,
|
||||||
|
JumpOnObject,
|
||||||
|
DigAtPosition
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //!__EPETABILITYTYPE__H__
|
@ -166,7 +166,8 @@ enum ePlayerFlag : int32_t {
|
|||||||
NJ_LIGHTNING_SPINJITZU = 2031,
|
NJ_LIGHTNING_SPINJITZU = 2031,
|
||||||
NJ_ICE_SPINJITZU = 2032,
|
NJ_ICE_SPINJITZU = 2032,
|
||||||
NJ_FIRE_SPINJITZU = 2033,
|
NJ_FIRE_SPINJITZU = 2033,
|
||||||
NJ_WU_SHOW_DAILY_CHEST = 2099
|
NJ_WU_SHOW_DAILY_CHEST = 2099,
|
||||||
|
DLU_SKIP_CINEMATICS = 1'000'000,
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //!__EPLAYERFLAG__H__
|
#endif //!__EPLAYERFLAG__H__
|
||||||
|
15
dCommon/dEnums/eQuickBuildState.h
Normal file
15
dCommon/dEnums/eQuickBuildState.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef __EQUICKBUILDSTATE__H__
|
||||||
|
#define __EQUICKBUILDSTATE__H__
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
enum class eQuickBuildState : uint32_t {
|
||||||
|
OPEN,
|
||||||
|
COMPLETED = 2,
|
||||||
|
RESETTING = 4,
|
||||||
|
BUILDING,
|
||||||
|
INCOMPLETE
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //!__EQUICKBUILDSTATE__H__
|
@ -1,15 +0,0 @@
|
|||||||
#ifndef __EREBUILDSTATE__H__
|
|
||||||
#define __EREBUILDSTATE__H__
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
enum class eRebuildState : uint32_t {
|
|
||||||
OPEN,
|
|
||||||
COMPLETED = 2,
|
|
||||||
RESETTING = 4,
|
|
||||||
BUILDING,
|
|
||||||
INCOMPLETE
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif //!__EREBUILDSTATE__H__
|
|
@ -34,7 +34,7 @@ enum class eReplicaComponentType : uint32_t {
|
|||||||
PLATFORM_BOUNDARY,
|
PLATFORM_BOUNDARY,
|
||||||
MODULE,
|
MODULE,
|
||||||
ARCADE,
|
ARCADE,
|
||||||
VEHICLE_PHYSICS, // Havok demo based
|
HAVOK_VEHICLE_PHYSICS,
|
||||||
MOVEMENT_AI,
|
MOVEMENT_AI,
|
||||||
EXHIBIT,
|
EXHIBIT,
|
||||||
OVERHEAD_ICON,
|
OVERHEAD_ICON,
|
||||||
@ -50,11 +50,11 @@ enum class eReplicaComponentType : uint32_t {
|
|||||||
PROPERTY_ENTRANCE,
|
PROPERTY_ENTRANCE,
|
||||||
FX,
|
FX,
|
||||||
PROPERTY_MANAGEMENT,
|
PROPERTY_MANAGEMENT,
|
||||||
VEHICLE_PHYSICS_NEW, // internal physics based on havok
|
VEHICLE_PHYSICS,
|
||||||
PHYSICS_SYSTEM,
|
PHYSICS_SYSTEM,
|
||||||
QUICK_BUILD,
|
QUICK_BUILD,
|
||||||
SWITCH,
|
SWITCH,
|
||||||
ZONE_CONTROL, // Minigame
|
MINI_GAME_CONTROL,
|
||||||
CHANGLING,
|
CHANGLING,
|
||||||
CHOICE_BUILD,
|
CHOICE_BUILD,
|
||||||
PACKAGE,
|
PACKAGE,
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "magic_enum.hpp"
|
||||||
|
|
||||||
enum class eWorldMessageType : uint32_t {
|
enum class eWorldMessageType : uint32_t {
|
||||||
VALIDATION = 1, // Session info
|
VALIDATION = 1, // Session info
|
||||||
CHARACTER_LIST_REQUEST,
|
CHARACTER_LIST_REQUEST,
|
||||||
@ -36,7 +38,14 @@ enum class eWorldMessageType : uint32_t {
|
|||||||
HANDLE_FUNNESS,
|
HANDLE_FUNNESS,
|
||||||
FAKE_PRG_CSR_MESSAGE,
|
FAKE_PRG_CSR_MESSAGE,
|
||||||
REQUEST_FREE_TRIAL_REFRESH,
|
REQUEST_FREE_TRIAL_REFRESH,
|
||||||
GM_SET_FREE_TRIAL_STATUS
|
GM_SET_FREE_TRIAL_STATUS,
|
||||||
|
UI_HELP_TOP_5 = 91
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct magic_enum::customize::enum_range<eWorldMessageType> {
|
||||||
|
static constexpr int min = 0;
|
||||||
|
static constexpr int max = 91;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //!__EWORLDMESSAGETYPE__H__
|
#endif //!__EWORLDMESSAGETYPE__H__
|
||||||
|
@ -4,9 +4,13 @@
|
|||||||
// 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
|
@ -15,6 +15,10 @@
|
|||||||
|
|
||||||
//! 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
|
||||||
/*!
|
/*!
|
@ -3,6 +3,7 @@
|
|||||||
#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"
|
||||||
@ -37,10 +38,15 @@
|
|||||||
#include "CDPropertyTemplateTable.h"
|
#include "CDPropertyTemplateTable.h"
|
||||||
#include "CDFeatureGatingTable.h"
|
#include "CDFeatureGatingTable.h"
|
||||||
#include "CDRailActivatorComponent.h"
|
#include "CDRailActivatorComponent.h"
|
||||||
|
#include "CDRewardCodesTable.h"
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
|
#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.
|
||||||
// A vanilla CDClient takes about 46MB of memory + the regular world data.
|
// A vanilla CDClient takes about 46MB of memory + the regular world data.
|
||||||
// #define CDCLIENT_CACHE_ALL
|
// # define CDCLIENT_CACHE_ALL
|
||||||
|
#endif // CDCLIENT_CACHE_ALL
|
||||||
|
|
||||||
#ifdef CDCLIENT_CACHE_ALL
|
#ifdef CDCLIENT_CACHE_ALL
|
||||||
#define CDCLIENT_DONT_CACHE_TABLE(x) x
|
#define CDCLIENT_DONT_CACHE_TABLE(x) x
|
||||||
@ -48,7 +54,16 @@
|
|||||||
#define CDCLIENT_DONT_CACHE_TABLE(x)
|
#define CDCLIENT_DONT_CACHE_TABLE(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
CDClientManager::CDClientManager() {
|
class CDClientConnectionException : public std::exception {
|
||||||
|
public:
|
||||||
|
virtual const char* what() const throw() {
|
||||||
|
return "CDClientDatabase is not connected!";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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());
|
||||||
@ -76,15 +91,23 @@ CDClientManager::CDClientManager() {
|
|||||||
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();
|
||||||
CDRailActivatorComponentTable::Instance().LoadValuesFromDatabase();
|
CDRailActivatorComponentTable::Instance().LoadValuesFromDatabase();
|
||||||
CDRarityTableTable::Instance().LoadValuesFromDatabase();
|
CDRarityTableTable::Instance().LoadValuesFromDatabase();
|
||||||
CDRebuildComponentTable::Instance().LoadValuesFromDatabase();
|
CDRebuildComponentTable::Instance().LoadValuesFromDatabase();
|
||||||
|
CDRewardCodesTable::Instance().LoadValuesFromDatabase();
|
||||||
CDRewardsTable::Instance().LoadValuesFromDatabase();
|
CDRewardsTable::Instance().LoadValuesFromDatabase();
|
||||||
CDScriptComponentTable::Instance().LoadValuesFromDatabase();
|
CDScriptComponentTable::Instance().LoadValuesFromDatabase();
|
||||||
CDSkillBehaviorTable::Instance().LoadValuesFromDatabase();
|
CDSkillBehaviorTable::Instance().LoadValuesFromDatabase();
|
||||||
CDVendorComponentTable::Instance().LoadValuesFromDatabase();
|
CDVendorComponentTable::Instance().LoadValuesFromDatabase();
|
||||||
CDZoneTableTable::Instance().LoadValuesFromDatabase();
|
CDZoneTableTable::Instance().LoadValuesFromDatabase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CDClientManager::LoadValuesFromDefaults() {
|
||||||
|
LOG("Loading default CDClient tables!");
|
||||||
|
|
||||||
|
CDPetComponentTable::Instance().LoadValuesFromDefaults();
|
||||||
|
}
|
@ -11,7 +11,10 @@
|
|||||||
*/
|
*/
|
||||||
class CDClientManager : public Singleton<CDClientManager> {
|
class CDClientManager : public Singleton<CDClientManager> {
|
||||||
public:
|
public:
|
||||||
CDClientManager();
|
CDClientManager() = default;
|
||||||
|
|
||||||
|
void LoadValuesFromDatabase();
|
||||||
|
void LoadValuesFromDefaults();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch a table from CDClient
|
* Fetch a table from CDClient
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
void CDActivitiesTable::LoadValuesFromDatabase() {
|
void CDActivitiesTable::LoadValuesFromDatabase() {
|
||||||
// First, get the size of the table
|
// First, get the size of the table
|
||||||
unsigned int size = 0;
|
uint32_t 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);
|
@ -4,22 +4,22 @@
|
|||||||
#include "CDTable.h"
|
#include "CDTable.h"
|
||||||
|
|
||||||
struct CDActivities {
|
struct CDActivities {
|
||||||
unsigned int ActivityID;
|
uint32_t ActivityID;
|
||||||
unsigned int locStatus;
|
uint32_t locStatus;
|
||||||
unsigned int instanceMapID;
|
uint32_t instanceMapID;
|
||||||
unsigned int minTeams;
|
uint32_t minTeams;
|
||||||
unsigned int maxTeams;
|
uint32_t maxTeams;
|
||||||
unsigned int minTeamSize;
|
uint32_t minTeamSize;
|
||||||
unsigned int maxTeamSize;
|
uint32_t maxTeamSize;
|
||||||
unsigned int waitTime;
|
uint32_t waitTime;
|
||||||
unsigned int startDelay;
|
uint32_t startDelay;
|
||||||
bool requiresUniqueData;
|
bool requiresUniqueData;
|
||||||
unsigned int leaderboardType;
|
uint32_t leaderboardType;
|
||||||
bool localize;
|
bool localize;
|
||||||
int optionalCostLOT;
|
int32_t optionalCostLOT;
|
||||||
int optionalCostCount;
|
int32_t optionalCostCount;
|
||||||
bool showUIRewards;
|
bool showUIRewards;
|
||||||
unsigned int CommunityActivityFlagID;
|
uint32_t CommunityActivityFlagID;
|
||||||
std::string gate_version;
|
std::string gate_version;
|
||||||
bool noTeamLootOnDeath;
|
bool noTeamLootOnDeath;
|
||||||
float optionalPercentage;
|
float optionalPercentage;
|
@ -3,7 +3,7 @@
|
|||||||
void CDActivityRewardsTable::LoadValuesFromDatabase() {
|
void CDActivityRewardsTable::LoadValuesFromDatabase() {
|
||||||
|
|
||||||
// First, get the size of the table
|
// First, get the size of the table
|
||||||
unsigned int size = 0;
|
uint32_t 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);
|
@ -4,12 +4,12 @@
|
|||||||
#include "CDTable.h"
|
#include "CDTable.h"
|
||||||
|
|
||||||
struct CDActivityRewards {
|
struct CDActivityRewards {
|
||||||
unsigned int objectTemplate; //!< The object template (?)
|
uint32_t objectTemplate; //!< The object template (?)
|
||||||
unsigned int ActivityRewardIndex; //!< The activity reward index
|
uint32_t ActivityRewardIndex; //!< The activity reward index
|
||||||
int activityRating; //!< The activity rating
|
int32_t activityRating; //!< The activity rating
|
||||||
unsigned int LootMatrixIndex; //!< The loot matrix index
|
uint32_t LootMatrixIndex; //!< The loot matrix index
|
||||||
unsigned int CurrencyIndex; //!< The currency index
|
uint32_t CurrencyIndex; //!< The currency index
|
||||||
unsigned int ChallengeRating; //!< The challenge rating
|
uint32_t ChallengeRating; //!< The challenge rating
|
||||||
std::string description; //!< The description
|
std::string description; //!< The description
|
||||||
};
|
};
|
||||||
|
|
@ -4,13 +4,13 @@
|
|||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
struct CDAnimation {
|
struct CDAnimation {
|
||||||
// unsigned int animationGroupID;
|
// uint32_t 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(unsigned int min_loops;) //!< The minimum number of loops
|
UNUSED_COLUMN(uint32_t min_loops;) //!< The minimum number of loops
|
||||||
UNUSED_COLUMN(unsigned int max_loops;) //!< The maximum number of loops
|
UNUSED_COLUMN(uint32_t 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
|
@ -3,7 +3,7 @@
|
|||||||
void CDBehaviorTemplateTable::LoadValuesFromDatabase() {
|
void CDBehaviorTemplateTable::LoadValuesFromDatabase() {
|
||||||
|
|
||||||
// First, get the size of the table
|
// First, get the size of the table
|
||||||
unsigned int size = 0;
|
uint32_t 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);
|
@ -6,9 +6,9 @@
|
|||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
struct CDBehaviorTemplate {
|
struct CDBehaviorTemplate {
|
||||||
unsigned int behaviorID; //!< The Behavior ID
|
uint32_t behaviorID; //!< The Behavior ID
|
||||||
unsigned int templateID; //!< The Template ID (LOT)
|
uint32_t templateID; //!< The Template ID (LOT)
|
||||||
unsigned int effectID; //!< The Effect ID attached
|
uint32_t 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
|
||||||
};
|
};
|
||||||
|
|
@ -3,7 +3,7 @@
|
|||||||
void CDBrickIDTableTable::LoadValuesFromDatabase() {
|
void CDBrickIDTableTable::LoadValuesFromDatabase() {
|
||||||
|
|
||||||
// First, get the size of the table
|
// First, get the size of the table
|
||||||
unsigned int size = 0;
|
uint32_t 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);
|
@ -10,8 +10,8 @@
|
|||||||
|
|
||||||
//! BrickIDTable Entry Struct
|
//! BrickIDTable Entry Struct
|
||||||
struct CDBrickIDTable {
|
struct CDBrickIDTable {
|
||||||
unsigned int NDObjectID;
|
uint32_t NDObjectID;
|
||||||
unsigned int LEGOBrickID;
|
uint32_t LEGOBrickID;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -10,7 +10,7 @@ void CDComponentsRegistryTable::LoadValuesFromDatabase() {
|
|||||||
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);
|
||||||
|
|
||||||
this->mappedEntries.insert_or_assign(((uint64_t)entry.component_type) << 32 | ((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);
|
||||||
this->mappedEntries.insert_or_assign(entry.id, 0);
|
this->mappedEntries.insert_or_assign(entry.id, 0);
|
||||||
|
|
||||||
tableData.nextRow();
|
tableData.nextRow();
|
||||||
@ -22,7 +22,7 @@ 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 exists = mappedEntries.find(id);
|
auto exists = mappedEntries.find(id);
|
||||||
if (exists != mappedEntries.end()) {
|
if (exists != mappedEntries.end()) {
|
||||||
auto iter = mappedEntries.find(((uint64_t)componentType) << 32 | ((uint64_t)id));
|
auto iter = mappedEntries.find(static_cast<uint64_t>(componentType) << 32 | static_cast<uint64_t>(id));
|
||||||
return iter == mappedEntries.end() ? defaultValue : iter->second;
|
return iter == mappedEntries.end() ? defaultValue : iter->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,15 +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);
|
||||||
|
|
||||||
this->mappedEntries.insert_or_assign(((uint64_t)entry.component_type) << 32 | ((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();
|
||||||
}
|
}
|
||||||
|
|
||||||
mappedEntries.insert_or_assign(id, 0);
|
mappedEntries.insert_or_assign(id, 0);
|
||||||
|
|
||||||
auto iter = this->mappedEntries.find(((uint64_t)componentType) << 32 | ((uint64_t)id));
|
auto iter = this->mappedEntries.find(static_cast<uint64_t>(componentType) << 32 | static_cast<uint64_t>(id));
|
||||||
|
|
||||||
return iter == this->mappedEntries.end() ? defaultValue : iter->second;
|
return iter == this->mappedEntries.end() ? defaultValue : iter->second;
|
||||||
}
|
}
|
||||||
|
|
@ -3,11 +3,13 @@
|
|||||||
// Custom Classes
|
// Custom Classes
|
||||||
#include "CDTable.h"
|
#include "CDTable.h"
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
enum class eReplicaComponentType : uint32_t;
|
enum class eReplicaComponentType : uint32_t;
|
||||||
struct CDComponentsRegistry {
|
struct CDComponentsRegistry {
|
||||||
unsigned int id; //!< The LOT is used as the ID
|
uint32_t id; //!< The LOT is used as the ID
|
||||||
eReplicaComponentType component_type; //!< See ComponentTypes enum for values
|
eReplicaComponentType component_type; //!< See ComponentTypes enum for values
|
||||||
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
|
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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
|||||||
void CDCurrencyTableTable::LoadValuesFromDatabase() {
|
void CDCurrencyTableTable::LoadValuesFromDatabase() {
|
||||||
|
|
||||||
// First, get the size of the table
|
// First, get the size of the table
|
||||||
unsigned int size = 0;
|
uint32_t 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);
|
@ -10,11 +10,11 @@
|
|||||||
|
|
||||||
//! CurrencyTable Struct
|
//! CurrencyTable Struct
|
||||||
struct CDCurrencyTable {
|
struct CDCurrencyTable {
|
||||||
unsigned int currencyIndex; //!< The Currency Index
|
uint32_t currencyIndex; //!< The Currency Index
|
||||||
unsigned int npcminlevel; //!< The minimum level of the npc
|
uint32_t npcminlevel; //!< The minimum level of the npc
|
||||||
unsigned int minvalue; //!< The minimum currency
|
uint32_t minvalue; //!< The minimum currency
|
||||||
unsigned int maxvalue; //!< The maximum currency
|
uint32_t maxvalue; //!< The maximum currency
|
||||||
unsigned int id; //!< The ID of the currency index
|
uint32_t id; //!< The ID of the currency index
|
||||||
};
|
};
|
||||||
|
|
||||||
//! CurrencyTable table
|
//! CurrencyTable table
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
void CDDestructibleComponentTable::LoadValuesFromDatabase() {
|
void CDDestructibleComponentTable::LoadValuesFromDatabase() {
|
||||||
// First, get the size of the table
|
// First, get the size of the table
|
||||||
unsigned int size = 0;
|
uint32_t 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);
|
@ -4,20 +4,20 @@
|
|||||||
#include "CDTable.h"
|
#include "CDTable.h"
|
||||||
|
|
||||||
struct CDDestructibleComponent {
|
struct CDDestructibleComponent {
|
||||||
unsigned int id; //!< The component ID from the ComponentsRegistry Table
|
uint32_t id; //!< The component ID from the ComponentsRegistry Table
|
||||||
int faction; //!< The Faction ID of the object
|
int32_t 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
|
||||||
int life; //!< The amount of life of the object
|
int32_t life; //!< The amount of life of the object
|
||||||
unsigned int imagination; //!< The amount of imagination of the object
|
uint32_t imagination; //!< The amount of imagination of the object
|
||||||
int LootMatrixIndex; //!< The Loot Matrix Index
|
int32_t LootMatrixIndex; //!< The Loot Matrix Index
|
||||||
int CurrencyIndex; //!< The Currency Index
|
int32_t CurrencyIndex; //!< The Currency Index
|
||||||
unsigned int level; //!< ???
|
uint32_t level; //!< ???
|
||||||
float armor; //!< The amount of armor of the object
|
float armor; //!< The amount of armor of the object
|
||||||
unsigned int death_behavior; //!< The behavior ID of the death behavior
|
uint32_t 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
|
||||||
unsigned int attack_priority; //!< ???
|
uint32_t attack_priority; //!< ???
|
||||||
bool isSmashable; //!< Whether or not the object is smashable
|
bool isSmashable; //!< Whether or not the object is smashable
|
||||||
int difficultyLevel; //!< ???
|
int32_t difficultyLevel; //!< ???
|
||||||
};
|
};
|
||||||
|
|
||||||
class CDDestructibleComponentTable : public CDTable<CDDestructibleComponentTable> {
|
class CDDestructibleComponentTable : public CDTable<CDDestructibleComponentTable> {
|
@ -20,7 +20,7 @@ void CDEmoteTableTable::LoadValuesFromDatabase() {
|
|||||||
tableData.finalize();
|
tableData.finalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
CDEmoteTable* CDEmoteTableTable::GetEmote(int id) {
|
CDEmoteTable* CDEmoteTableTable::GetEmote(int32_t id) {
|
||||||
auto itr = entries.find(id);
|
auto itr = entries.find(id);
|
||||||
return itr != entries.end() ? &itr->second : nullptr;
|
return itr != entries.end() ? &itr->second : nullptr;
|
||||||
}
|
}
|
@ -16,11 +16,11 @@ struct CDEmoteTable {
|
|||||||
gateVersion = "";
|
gateVersion = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
int ID;
|
int32_t ID;
|
||||||
std::string animationName;
|
std::string animationName;
|
||||||
std::string iconFilename;
|
std::string iconFilename;
|
||||||
int locState;
|
int32_t locState;
|
||||||
int channel;
|
int32_t channel;
|
||||||
bool locked;
|
bool locked;
|
||||||
bool localize;
|
bool localize;
|
||||||
std::string gateVersion;
|
std::string gateVersion;
|
||||||
@ -33,5 +33,5 @@ private:
|
|||||||
public:
|
public:
|
||||||
void LoadValuesFromDatabase();
|
void LoadValuesFromDatabase();
|
||||||
// Returns an emote by ID
|
// Returns an emote by ID
|
||||||
CDEmoteTable* GetEmote(int id);
|
CDEmoteTable* GetEmote(int32_t id);
|
||||||
};
|
};
|
@ -3,7 +3,7 @@
|
|||||||
void CDFeatureGatingTable::LoadValuesFromDatabase() {
|
void CDFeatureGatingTable::LoadValuesFromDatabase() {
|
||||||
|
|
||||||
// First, get the size of the table
|
// First, get the size of the table
|
||||||
unsigned int size = 0;
|
uint32_t 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);
|
||||||
@ -42,9 +42,9 @@ std::vector<CDFeatureGating> CDFeatureGatingTable::Query(std::function<bool(CDFe
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CDFeatureGatingTable::FeatureUnlocked(const std::string& feature) const {
|
bool CDFeatureGatingTable::FeatureUnlocked(const CDFeatureGating& feature) const {
|
||||||
for (const auto& entry : entries) {
|
for (const auto& entry : entries) {
|
||||||
if (entry.featureName == feature) {
|
if (entry.featureName == feature.featureName && feature >= entry) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -9,6 +9,12 @@ struct CDFeatureGating {
|
|||||||
int32_t current;
|
int32_t current;
|
||||||
int32_t minor;
|
int32_t minor;
|
||||||
std::string description;
|
std::string description;
|
||||||
|
|
||||||
|
bool operator>=(const CDFeatureGating& b) const {
|
||||||
|
return (this->major > b.major) ||
|
||||||
|
(this->major == b.major && this->current > b.current) ||
|
||||||
|
(this->major == b.major && this->current == b.current && this->minor >= b.minor);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CDFeatureGatingTable : public CDTable<CDFeatureGatingTable> {
|
class CDFeatureGatingTable : public CDTable<CDFeatureGatingTable> {
|
||||||
@ -21,7 +27,7 @@ public:
|
|||||||
// Queries the table with a custom "where" clause
|
// Queries the table with a custom "where" clause
|
||||||
std::vector<CDFeatureGating> Query(std::function<bool(CDFeatureGating)> predicate);
|
std::vector<CDFeatureGating> Query(std::function<bool(CDFeatureGating)> predicate);
|
||||||
|
|
||||||
bool FeatureUnlocked(const std::string& feature) const;
|
bool FeatureUnlocked(const CDFeatureGating& feature) const;
|
||||||
|
|
||||||
const std::vector<CDFeatureGating>& GetEntries(void) const;
|
const std::vector<CDFeatureGating>& GetEntries(void) const;
|
||||||
};
|
};
|
@ -3,7 +3,7 @@
|
|||||||
void CDInventoryComponentTable::LoadValuesFromDatabase() {
|
void CDInventoryComponentTable::LoadValuesFromDatabase() {
|
||||||
|
|
||||||
// First, get the size of the table
|
// First, get the size of the table
|
||||||
unsigned int size = 0;
|
uint32_t 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);
|
@ -4,9 +4,9 @@
|
|||||||
#include "CDTable.h"
|
#include "CDTable.h"
|
||||||
|
|
||||||
struct CDInventoryComponent {
|
struct CDInventoryComponent {
|
||||||
unsigned int id; //!< The component ID for this object
|
uint32_t id; //!< The component ID for this object
|
||||||
unsigned int itemid; //!< The LOT of the object
|
uint32_t itemid; //!< The LOT of the object
|
||||||
unsigned int count; //!< The count of the items the object has
|
uint32_t 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
|
||||||
};
|
};
|
||||||
|
|
@ -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
|
||||||
unsigned int size = 0;
|
uint32_t 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);
|
||||||
@ -69,7 +69,7 @@ void CDItemComponentTable::LoadValuesFromDatabase() {
|
|||||||
tableData.finalize();
|
tableData.finalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
const CDItemComponent& CDItemComponentTable::GetItemComponentByID(unsigned int skillID) {
|
const CDItemComponent& CDItemComponentTable::GetItemComponentByID(uint32_t skillID) {
|
||||||
const auto& it = this->entries.find(skillID);
|
const auto& it = this->entries.find(skillID);
|
||||||
if (it != this->entries.end()) {
|
if (it != this->entries.end()) {
|
||||||
return it->second;
|
return it->second;
|
@ -0,0 +1,64 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Custom Classes
|
||||||
|
#include "CDTable.h"
|
||||||
|
#include "dCommonVars.h"
|
||||||
|
|
||||||
|
struct CDItemComponent {
|
||||||
|
uint32_t id; //!< The Component ID
|
||||||
|
std::string equipLocation; //!< The equip location
|
||||||
|
uint32_t baseValue; //!< The monetary base value of the item
|
||||||
|
bool isKitPiece; //!< Whether or not the item belongs to a kit
|
||||||
|
uint32_t rarity; //!< The rarity of the item
|
||||||
|
uint32_t itemType; //!< The item type
|
||||||
|
int64_t itemInfo; //!< The item info
|
||||||
|
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 isUnique; //!< ???
|
||||||
|
bool isBOP; //!< ???
|
||||||
|
bool isBOE; //!< ???
|
||||||
|
uint32_t reqFlagID; //!< User must have completed this flag to get the item
|
||||||
|
uint32_t reqSpecialtyID; //!< ???
|
||||||
|
uint32_t reqSpecRank; //!< ???
|
||||||
|
uint32_t reqAchievementID; //!< The required achievement must be completed
|
||||||
|
uint32_t stackSize; //!< The stack size of the item
|
||||||
|
uint32_t color1; //!< Something to do with item color...
|
||||||
|
uint32_t decal; //!< The decal of the item
|
||||||
|
uint32_t offsetGroupID; //!< Something to do with group IDs
|
||||||
|
uint32_t buildTypes; //!< Something to do with building
|
||||||
|
std::string reqPrecondition; //!< The required precondition
|
||||||
|
uint32_t animationFlag; //!< The Animation Flag
|
||||||
|
uint32_t equipEffects; //!< The effect played when the item is equipped
|
||||||
|
bool readyForQA; //!< ???
|
||||||
|
uint32_t itemRating; //!< ???
|
||||||
|
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?
|
||||||
|
uint32_t delResIndex; //!< ???
|
||||||
|
uint32_t currencyLOT; //!< ???
|
||||||
|
uint32_t altCurrencyCost; //!< ???
|
||||||
|
std::string subItems; //!< A comma seperate string of sub items (maybe for multi-itemed things like faction test gear set)
|
||||||
|
UNUSED(std::string audioEventUse); //!< ???
|
||||||
|
bool noEquipAnimation; //!< Whether or not there is an equip animation
|
||||||
|
uint32_t commendationLOT; //!< The commendation LOT
|
||||||
|
uint32_t commendationCost; //!< The commendation cost
|
||||||
|
UNUSED(std::string audioEquipMetaEventSet); //!< ???
|
||||||
|
std::string currencyCosts; //!< Used for crafting
|
||||||
|
UNUSED(std::string ingredientInfo); //!< Unused
|
||||||
|
uint32_t locStatus; //!< ???
|
||||||
|
uint32_t forgeType; //!< Forge Type
|
||||||
|
float SellMultiplier; //!< Something to do with early vendors perhaps (but replaced)
|
||||||
|
};
|
||||||
|
|
||||||
|
class CDItemComponentTable : public CDTable<CDItemComponentTable> {
|
||||||
|
private:
|
||||||
|
std::map<uint32_t, CDItemComponent> entries;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void LoadValuesFromDatabase();
|
||||||
|
static std::map<LOT, uint32_t> ParseCraftingCurrencies(const CDItemComponent& itemComponent);
|
||||||
|
|
||||||
|
// Gets an entry by ID
|
||||||
|
const CDItemComponent& GetItemComponentByID(uint32_t skillID);
|
||||||
|
|
||||||
|
static CDItemComponent Default;
|
||||||
|
};
|
@ -3,7 +3,7 @@
|
|||||||
void CDItemSetSkillsTable::LoadValuesFromDatabase() {
|
void CDItemSetSkillsTable::LoadValuesFromDatabase() {
|
||||||
|
|
||||||
// First, get the size of the table
|
// First, get the size of the table
|
||||||
unsigned int size = 0;
|
uint32_t 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);
|
||||||
@ -44,7 +44,7 @@ const std::vector<CDItemSetSkills>& CDItemSetSkillsTable::GetEntries() const {
|
|||||||
return this->entries;
|
return this->entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<CDItemSetSkills> CDItemSetSkillsTable::GetBySkillID(unsigned int SkillSetID) {
|
std::vector<CDItemSetSkills> CDItemSetSkillsTable::GetBySkillID(uint32_t SkillSetID) {
|
||||||
std::vector<CDItemSetSkills> toReturn;
|
std::vector<CDItemSetSkills> toReturn;
|
||||||
|
|
||||||
for (CDItemSetSkills entry : this->entries) {
|
for (CDItemSetSkills entry : this->entries) {
|
@ -4,9 +4,9 @@
|
|||||||
#include "CDTable.h"
|
#include "CDTable.h"
|
||||||
|
|
||||||
struct CDItemSetSkills {
|
struct CDItemSetSkills {
|
||||||
unsigned int SkillSetID; //!< The skill set ID
|
uint32_t SkillSetID; //!< The skill set ID
|
||||||
unsigned int SkillID; //!< The skill ID
|
uint32_t SkillID; //!< The skill ID
|
||||||
unsigned int SkillCastType; //!< The skill cast type
|
uint32_t SkillCastType; //!< The skill cast type
|
||||||
};
|
};
|
||||||
|
|
||||||
class CDItemSetSkillsTable : public CDTable<CDItemSetSkillsTable> {
|
class CDItemSetSkillsTable : public CDTable<CDItemSetSkillsTable> {
|
||||||
@ -20,5 +20,5 @@ public:
|
|||||||
|
|
||||||
const std::vector<CDItemSetSkills>& GetEntries() const;
|
const std::vector<CDItemSetSkills>& GetEntries() const;
|
||||||
|
|
||||||
std::vector<CDItemSetSkills> GetBySkillID(unsigned int SkillSetID);
|
std::vector<CDItemSetSkills> GetBySkillID(uint32_t SkillSetID);
|
||||||
};
|
};
|
@ -3,7 +3,7 @@
|
|||||||
void CDItemSetsTable::LoadValuesFromDatabase() {
|
void CDItemSetsTable::LoadValuesFromDatabase() {
|
||||||
|
|
||||||
// First, get the size of the table
|
// First, get the size of the table
|
||||||
unsigned int size = 0;
|
uint32_t 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);
|
35
dDatabase/CDClientDatabase/CDClientTables/CDItemSetsTable.h
Normal file
35
dDatabase/CDClientDatabase/CDClientTables/CDItemSetsTable.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Custom Classes
|
||||||
|
#include "CDTable.h"
|
||||||
|
|
||||||
|
struct CDItemSets {
|
||||||
|
uint32_t setID; //!< The item set ID
|
||||||
|
uint32_t locStatus; //!< The loc status
|
||||||
|
std::string itemIDs; //!< THe item IDs
|
||||||
|
uint32_t kitType; //!< The item kit type
|
||||||
|
uint32_t kitRank; //!< The item kit rank
|
||||||
|
uint32_t kitImage; //!< The item kit image
|
||||||
|
uint32_t skillSetWith2; //!< The skill set with 2
|
||||||
|
uint32_t skillSetWith3; //!< The skill set with 3
|
||||||
|
uint32_t skillSetWith4; //!< The skill set with 4
|
||||||
|
uint32_t skillSetWith5; //!< The skill set with 5
|
||||||
|
uint32_t skillSetWith6; //!< The skill set with 6
|
||||||
|
bool localize; //!< Whether or localize
|
||||||
|
std::string gate_version; //!< The gate version
|
||||||
|
uint32_t kitID; //!< The kit ID
|
||||||
|
float priority; //!< The priority
|
||||||
|
};
|
||||||
|
|
||||||
|
class CDItemSetsTable : public CDTable<CDItemSetsTable> {
|
||||||
|
private:
|
||||||
|
std::vector<CDItemSets> entries;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void LoadValuesFromDatabase();
|
||||||
|
// Queries the table with a custom "where" clause
|
||||||
|
std::vector<CDItemSets> Query(std::function<bool(CDItemSets)> predicate);
|
||||||
|
|
||||||
|
const std::vector<CDItemSets>& GetEntries(void) const;
|
||||||
|
};
|
||||||
|
|
@ -3,7 +3,7 @@
|
|||||||
void CDLevelProgressionLookupTable::LoadValuesFromDatabase() {
|
void CDLevelProgressionLookupTable::LoadValuesFromDatabase() {
|
||||||
|
|
||||||
// First, get the size of the table
|
// First, get the size of the table
|
||||||
unsigned int size = 0;
|
uint32_t 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);
|
@ -4,8 +4,8 @@
|
|||||||
#include "CDTable.h"
|
#include "CDTable.h"
|
||||||
|
|
||||||
struct CDLevelProgressionLookup {
|
struct CDLevelProgressionLookup {
|
||||||
unsigned int id; //!< The Level ID
|
uint32_t id; //!< The Level ID
|
||||||
unsigned int requiredUScore; //!< The required LEGO Score
|
uint32_t requiredUScore; //!< The required LEGO Score
|
||||||
std::string BehaviorEffect; //!< The behavior effect attached to this
|
std::string BehaviorEffect; //!< The behavior effect attached to this
|
||||||
};
|
};
|
||||||
|
|
@ -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
|
||||||
unsigned int size = 0;
|
uint32_t 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);
|
@ -4,12 +4,12 @@
|
|||||||
#include "CDTable.h"
|
#include "CDTable.h"
|
||||||
|
|
||||||
struct CDLootMatrix {
|
struct CDLootMatrix {
|
||||||
unsigned int LootTableIndex; //!< The Loot Table Index
|
uint32_t LootTableIndex; //!< The Loot Table Index
|
||||||
unsigned int RarityTableIndex; //!< The Rarity Table Index
|
uint32_t RarityTableIndex; //!< The Rarity Table Index
|
||||||
float percent; //!< The percent that this matrix is used?
|
float percent; //!< The percent that this matrix is used?
|
||||||
unsigned int minToDrop; //!< The minimum amount of loot from this matrix to drop
|
uint32_t minToDrop; //!< The minimum amount of loot from this matrix to drop
|
||||||
unsigned int maxToDrop; //!< The maximum amount of loot from this matrix to drop
|
uint32_t maxToDrop; //!< The maximum amount of loot from this matrix to drop
|
||||||
unsigned int flagID; //!< ???
|
uint32_t flagID; //!< ???
|
||||||
UNUSED(std::string gate_version); //!< The Gate Version
|
UNUSED(std::string gate_version); //!< The Gate Version
|
||||||
};
|
};
|
||||||
|
|
@ -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
|
||||||
unsigned int size = 0;
|
uint32_t 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);
|
@ -4,10 +4,10 @@
|
|||||||
#include "CDTable.h"
|
#include "CDTable.h"
|
||||||
|
|
||||||
struct CDLootTable {
|
struct CDLootTable {
|
||||||
unsigned int itemid; //!< The LOT of the item
|
uint32_t itemid; //!< The LOT of the item
|
||||||
unsigned int LootTableIndex; //!< The Loot Table Index
|
uint32_t 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
|
||||||
unsigned int sortPriority; //!< The sorting priority
|
uint32_t sortPriority; //!< The sorting priority
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef uint32_t LootTableIndex;
|
typedef uint32_t LootTableIndex;
|
@ -3,7 +3,7 @@
|
|||||||
void CDMissionEmailTable::LoadValuesFromDatabase() {
|
void CDMissionEmailTable::LoadValuesFromDatabase() {
|
||||||
|
|
||||||
// First, get the size of the table
|
// First, get the size of the table
|
||||||
unsigned int size = 0;
|
uint32_t 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);
|
||||||
@ -25,7 +25,7 @@ void CDMissionEmailTable::LoadValuesFromDatabase() {
|
|||||||
entry.notificationGroup = tableData.getIntField("notificationGroup", -1);
|
entry.notificationGroup = tableData.getIntField("notificationGroup", -1);
|
||||||
entry.missionID = tableData.getIntField("missionID", -1);
|
entry.missionID = tableData.getIntField("missionID", -1);
|
||||||
entry.attachmentLOT = tableData.getIntField("attachmentLOT", 0);
|
entry.attachmentLOT = tableData.getIntField("attachmentLOT", 0);
|
||||||
entry.localize = (bool)tableData.getIntField("localize", -1);
|
entry.localize = static_cast<bool>(tableData.getIntField("localize", 1));
|
||||||
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", "");
|
||||||
|
|
||||||
@ -50,4 +50,3 @@ std::vector<CDMissionEmail> CDMissionEmailTable::Query(std::function<bool(CDMiss
|
|||||||
const std::vector<CDMissionEmail>& CDMissionEmailTable::GetEntries() const {
|
const std::vector<CDMissionEmail>& CDMissionEmailTable::GetEntries() const {
|
||||||
return this->entries;
|
return this->entries;
|
||||||
}
|
}
|
||||||
|
|
@ -4,13 +4,13 @@
|
|||||||
#include "CDTable.h"
|
#include "CDTable.h"
|
||||||
|
|
||||||
struct CDMissionEmail {
|
struct CDMissionEmail {
|
||||||
unsigned int ID;
|
uint32_t ID;
|
||||||
unsigned int messageType;
|
uint32_t messageType;
|
||||||
unsigned int notificationGroup;
|
uint32_t notificationGroup;
|
||||||
unsigned int missionID;
|
uint32_t missionID;
|
||||||
unsigned int attachmentLOT;
|
uint32_t attachmentLOT;
|
||||||
bool localize;
|
bool localize;
|
||||||
unsigned int locStatus;
|
uint32_t locStatus;
|
||||||
std::string gate_version;
|
std::string gate_version;
|
||||||
};
|
};
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user