Compare commits

..

12 Commits

Author SHA1 Message Date
7a9bf57af0 Merge branch 'main' into use-npc-paths 2023-01-07 00:52:22 -06:00
2465bb7462 Merge branch 'main' into use-npc-paths 2022-12-12 13:22:36 -06:00
b7d2e591e6 Merge branch 'main' into use-npc-paths 2022-11-23 17:46:59 -06:00
848732e01a WIP 2022-11-14 07:05:44 -06:00
199c73cf75 the go zoom 2022-11-12 15:01:15 -06:00
8533ad3b8d fix compile errors 2022-11-12 08:56:56 -06:00
9a75d2a3e1 Merge branch 'main' into use-npc-paths 2022-11-12 08:48:55 -06:00
ccb4fbc840 they move! 2022-11-12 08:47:47 -06:00
bf75447794 address feedback 2022-11-10 10:17:53 -06:00
54e09e3e30 invert if else block logic patter
Since setting up the comp will be longer han just adding the path
will make the readability flow better
2022-11-08 22:06:35 -06:00
2a13d021ee move stuff around to make it more congruent 2022-11-08 22:05:02 -06:00
b645301867 Stop adding movingpla comps where they aren't needed 2022-11-08 21:22:02 -06:00
1130 changed files with 23864 additions and 30473 deletions

37
.clang-format Normal file
View File

@@ -0,0 +1,37 @@
---
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
BeforeLambdaBody: false
BeforeWhile: false
BreakBeforeBraces: Attach
ColumnLimit: 0
IndentWidth: 4
IndentCaseLabels: true
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '<[[:alnum:].]+\.h>'
Priority: 1
- Regex: '<[[:alnum:].]+>'
Priority: 2
- Regex: '.*/.*'
Priority: 3
- Regex: '.*'
Priority: 4
DerivePointerAlignment: false
PointerAlignment: Left
...

17
.clang-tidy Normal file
View File

@@ -0,0 +1,17 @@
Checks: '-*,readability-*,performance-*,modernize-*,-modernize-use-trailing-return-type,bugprone-*'
WarningsAsErrors: true
HeaderFilterRegex: ''
FormatStyle: none
CheckOptions:
- key: readability-identifier-naming.ClassCase
value: CamelCase
- key: readability-identifier-naming.ClassMethodCase
value: CamelCase
- key: readability-identifier-naming.ClassMemberPrefix
value: m_
- key: readability-identifier-naming.ClassMemberCase
value: CamelCase
- key: readability-identifier-naming.ClassConstantCase
value: UPPER_CASE
- key: readability-identifier-naming.FunctionCase
value: CamelCase

View File

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

View File

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

View File

@@ -6,6 +6,3 @@
# convert to unix line endings
72477e01e2711e0f61cdb192ee266e5e21b8846f
# enum cleanup
faf42d2f8cf432df2993b031f079b0b8c6d7dbe7

View File

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

View File

@@ -13,7 +13,7 @@ jobs:
continue-on-error: true
strategy:
matrix:
os: [ windows-2022, ubuntu-22.04, macos-13 ]
os: [ windows-2022, ubuntu-20.04, macos-11 ]
steps:
- uses: actions/checkout@v3
@@ -25,11 +25,9 @@ jobs:
with:
vs-version: '[17,18)'
msbuild-architecture: x64
- name: Install libssl and switch to XCode 15.2 (Mac Only)
if: ${{ matrix.os == 'macos-13' }}
run: |
brew install openssl@3
sudo xcode-select -s /Applications/Xcode_15.2.app/Contents/Developer
- name: Install libssl (Mac Only)
if: ${{ matrix.os == 'macos-11' }}
run: brew install openssl@3
- name: cmake
uses: lukka/run-cmake@v10
with:
@@ -38,16 +36,22 @@ jobs:
testPreset: "ci-${{matrix.os}}"
- name: artifacts
uses: actions/upload-artifact@v3
if: ${{ github.ref == 'ref/head/main' }}
with:
name: build-${{matrix.os}}
path: |
build/*Server*
build/*.ini
build/*.so
build/*.dll
build/vanity/
build/navmeshes/
build/migrations/
build/*.dcf
!build/*.pdb
!build/d*/
build
!build/tests
!build/Testing
!build/CMakeFiles
!build/DartConfiguration.tcl
!build/CTestTestfile.cmake
!build/CMakeCache.txt
!build/build.ninja
!build/_deps
!build/cmake_install.cmake
!build/*.a
!build/*.lib
!build/*.dir
!build/*.vcxproj
!build/*.vcxproj.filters

1
.gitignore vendored
View File

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

6
.gitmodules vendored
View File

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

View File

@@ -2,9 +2,7 @@ cmake_minimum_required(VERSION 3.18)
project(Darkflame)
include(CTest)
set(CMAKE_CXX_STANDARD 20)
set(CXX_STANDARD_REQUIRED ON)
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
set (CMAKE_CXX_STANDARD 17)
# Read variables from file
FILE(READ "${CMAKE_SOURCE_DIR}/CMakeVariables.txt" variables)
@@ -16,26 +14,30 @@ string(REPLACE "\n" ";" variables ${variables})
foreach(variable ${variables})
# If the string contains a #, skip it
if(NOT "${variable}" MATCHES "#")
# Split the variable into name and value
string(REPLACE "=" ";" variable ${variable})
# Check that the length of the variable is 2 (name and value)
list(LENGTH variable length)
if(${length} EQUAL 2)
list(GET variable 0 variable_name)
list(GET variable 1 variable_value)
# Set the variable
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}")
endif()
endif()
endforeach()
# 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
message(STATUS "Version: ${PROJECT_VERSION}")
@@ -51,22 +53,19 @@ set(RECASTNAVIGATION_EXAMPLES OFF CACHE BOOL "" FORCE)
# Disabled misleading indentation as DL_LinkedList from RakNet has a weird indent.
# Disabled no-register
# Disabled unknown pragmas because Linux doesn't understand Windows pragmas.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DPROJECT_VERSION=${PROJECT_VERSION}")
if(UNIX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -Wuninitialized -fPIC")
add_compile_definitions(_GLIBCXX_USE_CXX11_ABI=0 _GLIBCXX_USE_CXX17_ABI=0)
if(NOT APPLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -lstdc++fs")
if(APPLE)
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")
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")
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")
endif()
if(${GGDB})
if (__ggdb)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb")
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -O2 -fPIC")
elseif(MSVC)
# Skip warning for invalid conversion from size_t to uint32_t for all targets below for now
@@ -98,89 +97,29 @@ make_directory(${CMAKE_BINARY_DIR}/logs)
# Copy resource files on first build
set(RESOURCE_FILES "sharedconfig.ini" "authconfig.ini" "chatconfig.ini" "worldconfig.ini" "masterconfig.ini" "blacklist.dcf")
message(STATUS "Checking resource file integrity")
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)
if(EXISTS ${PROJECT_BINARY_DIR}/${resource_file})
file(SIZE ${PROJECT_BINARY_DIR}/${resource_file} file_size)
endif()
if(${file_size} EQUAL 0)
if (NOT EXISTS ${PROJECT_BINARY_DIR}/${resource_file})
configure_file(
${CMAKE_SOURCE_DIR}/resources/${resource_file} ${PROJECT_BINARY_DIR}/${resource_file}
COPYONLY
)
message(STATUS "Moved " ${resource_file} " to project binary directory")
elseif(resource_file MATCHES ".ini")
message(STATUS "Checking " ${resource_file} " for missing config options")
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})
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()
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})
set(line_to_add "")
foreach(line ${depot_file_contents})
string(FIND ${line} "#" is_comment)
if(NOT ${is_comment} EQUAL 0)
string(REPLACE "=" ";" line_split ${line})
list(GET line_split 0 variable_name)
if(NOT ${parsed_current_file_contents} MATCHES ${variable_name})
message(STATUS "Adding missing config option " ${variable_name} " to " ${resource_file})
set(line_to_add ${line_to_add} ${line})
foreach(line_to_append ${line_to_add})
file(APPEND ${PROJECT_BINARY_DIR}/${resource_file} "\n" ${line_to_append})
endforeach()
file(APPEND ${PROJECT_BINARY_DIR}/${resource_file} "\n")
endif()
set(line_to_add "")
else()
set(line_to_add ${line_to_add} ${line})
endif()
endforeach()
message("Moved ${resource_file} to project binary directory")
endif()
endforeach()
message(STATUS "Resource file integrity check complete")
# if navmeshes directory does not exist, create it
if(NOT EXISTS ${PROJECT_BINARY_DIR}/navmeshes)
file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/navmeshes)
endif()
# Copy navmesh data on first build and extract it
configure_file(${CMAKE_SOURCE_DIR}/resources/navmeshes.zip ${PROJECT_BINARY_DIR}/navmeshes.zip COPYONLY)
if (NOT EXISTS ${PROJECT_BINARY_DIR}/navmeshes/)
configure_file(
${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(REMOVE ${PROJECT_BINARY_DIR}/navmeshes.zip)
file(ARCHIVE_EXTRACT INPUT ${PROJECT_BINARY_DIR}/navmeshes.zip)
file(REMOVE ${PROJECT_BINARY_DIR}/navmeshes.zip)
endif()
# Copy vanity files on first build
set(VANITY_FILES "CREDITS.md" "INFO.md" "TESTAMENT.md" "NPC.xml")
foreach(file ${VANITY_FILES})
configure_file("${CMAKE_SOURCE_DIR}/vanity/${file}" "${CMAKE_BINARY_DIR}/vanity/${file}" COPYONLY)
endforeach()
@@ -188,18 +127,26 @@ endforeach()
# Move our migrations for MasterServer to run
file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/migrations/dlu/)
file(GLOB SQL_FILES ${CMAKE_SOURCE_DIR}/migrations/dlu/*.sql)
foreach(file ${SQL_FILES})
get_filename_component(file ${file} NAME)
configure_file(${CMAKE_SOURCE_DIR}/migrations/dlu/${file} ${PROJECT_BINARY_DIR}/migrations/dlu/${file})
if (NOT EXISTS ${PROJECT_BINARY_DIR}/migrations/dlu/${file})
configure_file(
${CMAKE_SOURCE_DIR}/migrations/dlu/${file} ${PROJECT_BINARY_DIR}/migrations/dlu/${file}
COPYONLY
)
endif()
endforeach()
file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/migrations/cdserver/)
file(GLOB SQL_FILES ${CMAKE_SOURCE_DIR}/migrations/cdserver/*.sql)
foreach(file ${SQL_FILES})
get_filename_component(file ${file} NAME)
configure_file(${CMAKE_SOURCE_DIR}/migrations/cdserver/${file} ${PROJECT_BINARY_DIR}/migrations/cdserver/${file})
if (NOT EXISTS ${PROJECT_BINARY_DIR}/migrations/cdserver/${file})
configure_file(
${CMAKE_SOURCE_DIR}/migrations/cdserver/${file} ${PROJECT_BINARY_DIR}/migrations/cdserver/${file}
COPYONLY
)
endif()
endforeach()
# Create our list of include directories
@@ -207,9 +154,7 @@ set(INCLUDED_DIRECTORIES
"dCommon"
"dCommon/dClient"
"dCommon/dEnums"
"dChatFilter"
"dGame"
"dGame/dBehaviors"
"dGame/dComponents"
@@ -218,71 +163,129 @@ set(INCLUDED_DIRECTORIES
"dGame/dMission"
"dGame/dEntity"
"dGame/dPropertyBehaviors"
"dGame/dPropertyBehaviors/ControlBehaviorMessages"
"dGame/dUtilities"
"dPhysics"
"dNavigation"
"dNavigation/dTerrain"
"dZoneManager"
"dDatabase"
"dDatabase/CDClientDatabase"
"dDatabase/CDClientDatabase/CDClientTables"
"dDatabase/GameDatabase"
"dDatabase/GameDatabase/ITables"
"dDatabase/GameDatabase/MySQL"
"dDatabase/GameDatabase/MySQL/Tables"
"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"
"thirdparty/magic_enum/include/magic_enum"
"thirdparty/raknet/Source"
"thirdparty/tinyxml2"
"thirdparty/recastnavigation"
"thirdparty/SQLite"
"thirdparty/cpplinq"
"thirdparty/cpp-httplib"
"tests"
"tests/dCommonTests"
"tests/dGameTests"
"tests/dGameTests/dComponentsTests"
)
)
# Add system specfic includes for Apple, Windows and Other Unix OS' (including Linux)
if(APPLE)
if (APPLE)
include_directories("/usr/local/include/")
endif()
# Actually include the directories from our list
foreach(dir ${INCLUDED_DIRECTORIES})
include_directories(${PROJECT_SOURCE_DIR}/${dir})
endforeach()
if(NOT WIN32)
include_directories("${PROJECT_SOURCE_DIR}/thirdparty/libbcrypt/include/bcrypt")
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()
include_directories("${PROJECT_SOURCE_DIR}/thirdparty/libbcrypt/include")
# Add binary directory as an include directory
include_directories(${PROJECT_BINARY_DIR})
# Actually include the directories from our list
foreach (dir ${INCLUDED_DIRECTORIES})
include_directories(${PROJECT_SOURCE_DIR}/${dir})
endforeach()
# Add linking directories:
link_directories(${PROJECT_BINARY_DIR})
# Load all of our third party directories
add_subdirectory(thirdparty)
if (UNIX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
endif()
# Glob together all headers that need to be precompiled
file(
GLOB HEADERS_DDATABASE
LIST_DIRECTORIES false
${PROJECT_SOURCE_DIR}/dDatabase/CDClientDatabase/*.h
${PROJECT_SOURCE_DIR}/dDatabase/CDClientDatabase/CDClientTables/*.h
${PROJECT_SOURCE_DIR}/dDatabase/GameDatabase/ITables/*.h
${PROJECT_SOURCE_DIR}/dDatabase/*.h
${PROJECT_SOURCE_DIR}/dDatabase/Tables/*.h
${PROJECT_SOURCE_DIR}/thirdparty/SQLite/*.h
)
@@ -317,16 +320,15 @@ add_subdirectory(dGame)
add_subdirectory(dZoneManager)
add_subdirectory(dNavigation)
add_subdirectory(dPhysics)
add_subdirectory(dServer)
# Create a list of common libraries shared between all binaries
set(COMMON_LIBRARIES "dCommon" "dDatabase" "dNet" "raknet" "mariadbConnCpp" "magic_enum")
set(COMMON_LIBRARIES "dCommon" "dDatabase" "dNet" "raknet" "mariadbConnCpp")
# Add platform specific common libraries
if(UNIX)
if (UNIX)
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")
endif()
endif()
@@ -337,6 +339,12 @@ add_subdirectory(dAuthServer)
add_subdirectory(dChatServer)
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(
dZoneManager PRIVATE
${HEADERS_DZONEMANAGER}
@@ -358,6 +366,6 @@ target_precompile_headers(
"$<$<COMPILE_LANGUAGE:CXX>:${PROJECT_SOURCE_DIR}/thirdparty/tinyxml2/tinyxml2.h>"
)
if(${ENABLE_TESTING})
if (${__enable_testing__} MATCHES "1")
add_subdirectory(tests)
endif()

View File

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

View File

@@ -1,32 +1,24 @@
PROJECT_VERSION_MAJOR=1
PROJECT_VERSION_MINOR=1
PROJECT_VERSION_PATCH=1
PROJECT_VERSION_MINOR=0
PROJECT_VERSION_PATCH=4
# LICENSE
LICENSE=AGPL-3.0
# The network version.
# 171023 - Darkflame Universe client
# 171022 - Unmodded client
NET_VERSION=171022
# Debugging
# Set DYNAMIC to 1 to enable the -rdynamic flag for the linker, yielding some symbols in crashlogs.
DYNAMIC=1
# Set GGDB to 1 to enable the -ggdb flag for the linker, including more debug info.
# Do note, changing this will re-build the whole server
GGDB=0
# 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 __dynamic to 1 to enable the -rdynamic flag for the linker, yielding some symbols in crashlogs.
__dynamic=1
# Set __ggdb to 1 to enable the -ggdb flag for the linker, including more debug info.
# __ggdb=1
# Set __include_backtrace__ to 1 to includes the backtrace library for better crashlogs.
# __include_backtrace__=1
# Set __compile_backtrace__ to 1 to compile the backtrace library instead of using system libraries.
# __compile_backtrace__=1
# Set to the number of jobs (make -j equivalent) to compile the mariadbconn files with.
MARIADB_CONNECTOR_COMPILE_JOBS=1
__maria_db_connector_compile_jobs__=1
# 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.
OPENSSL_ROOT_DIR=/usr/local/opt/openssl@3/
# 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 Normal file
View File

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

58
Docker_Windows.md Normal file
View File

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

View File

@@ -1,51 +0,0 @@
FROM gcc:12 as build
WORKDIR /app
RUN set -ex; \
apt-get update; \
apt-get install -y cmake
COPY . /app/
COPY --chmod=0500 ./build.sh /app/
RUN sed -i 's/MARIADB_CONNECTOR_COMPILE_JOBS__=.*/MARIADB_CONNECTOR_COMPILE_JOBS__=2/' /app/CMakeVariables.txt
RUN ./build.sh
FROM debian:12 as runtime
WORKDIR /app
RUN --mount=type=cache,id=build-apt-cache,target=/var/cache/apt \
apt update && \
apt install -y libssl3 libcurl4 && \
rm -rf /var/lib/apt/lists/*
# Grab libraries and load them
COPY --from=build /app/build/mariadbcpp/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" ]

134
README.md
View File

@@ -23,9 +23,6 @@ We do not recommend hosting public servers. Darkflame Universe is intended for s
### 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.
## 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
* [Clone this repository](#clone-the-repository)
* [Install dependencies](#install-dependencies)
@@ -37,7 +34,6 @@ If you would like a setup for a single player server only on a Windows machine,
* [Verify your setup](#verify-your-setup)
* [Running the server](#running-the-server)
* [User Guide](#user-guide)
* [Docker](#docker)
## Clone the repository
If you are on Windows, you will need to download and install git from [here](https://git-scm.com/download/win)
@@ -176,14 +172,10 @@ You can either run `build.sh` when in the root folder of the repository:
Or manually run the commands used in [build.sh](build.sh).
If you would like to build the server faster, append `-j<number>` where number is the number of simultaneous compile jobs to run at once. It is recommended that you have this number always be 1 less than your core count to prevent slowdowns. The command would look like this if you would build with 4 jobs at once:
```bash
./build.sh -j4
```
### Notes
Depending on your operating system, you may need to adjust some pre-processor defines in [CMakeVariables.txt](./CMakeVariables.txt) before building:
* If you are on MacOS, ensure OPENSSL_ROOT_DIR is pointing to the openssl root directory.
* If you are using a Darkflame Universe client, ensure `client_net_version` in `build/sharedconfig.ini` is changed to 171023.
* If you are using a Darkflame Universe client, ensure NET_VERSION is changed to 171023.
## Configuring your server
This server has a few steps that need to be taken to configure the server for your use case.
@@ -228,44 +220,6 @@ sudo setcap 'cap_net_bind_service=+ep' AuthServer
```
and then go to `build/masterconfig.ini` and change `use_sudo_auth` to 0.
### Linux Service
If you are running this on a linux based system, it will use your terminal to run the program interactively, preventing you using it for other tasks and requiring it to be open to run the server.
_Note: You could use screen or tmux instead for virtual terminals_
To run the server non-interactively, we can use a systemctl service by copying the following file:
```shell
cp ./systemd.example /etc/systemd/system/darkflame.service
```
Make sure to edit the file in `/etc/systemd/system/darkflame.service` and change the:
- `User` and `Group` to the user that runs the darkflame server.
- `ExecPath` to the full file path of the server executable.
To register, enable and start the service use the following commands:
- Reload the systemd manager configuration to make it aware of the new service file:
```shell
systemctl daemon-reload
```
- Start the service:
```shell
systemctl start darkflame.service
```
- Enable OR disable the service to start on boot using:
```shell
systemctl enable darkflame.service
systemctl disable darkflame.service
```
- Verify that the service is running without errors:
```shell
systemctl status darkflame.service
```
- You can also restart, stop, or check the logs of the service using journalctl
```shell
systemctl restart darkflame.service
systemctl stop darkflame.service
journalctl -xeu darkflame.service
```
### First admin user
Run `MasterServer -a` to get prompted to create an admin account. This method is only intended for the system administrator as a means to get started, do NOT use this method to create accounts for other users!
@@ -287,11 +241,30 @@ To connect to a server follow these steps:
* In the client directory, locate `boot.cfg`
* Open it in a text editor and locate where it says `AUTHSERVERIP=0:`
* Replace the contents after to `:` and the following `,` with what you configured as the server's public facing IP. For example `AUTHSERVERIP=0:localhost` for locally hosted servers
* Next locate the line `UGCUSE3DSERVICES=7:`
* Ensure the number after the 7 is a `0`
* Launch `legouniverse.exe`, through `wine` if on a Unix-like operating system
* Note that if you are on WSL2, you will need to configure the public IP in the server and client to be the IP of the WSL2 instance and not localhost, which can be found by running `ifconfig` in the terminal. Windows defaults to WSL1, so this will not apply to most users.
## Brick-By-Brick building
Should you choose to do any brick building, you will want to have some form of a http server that returns a 404 error since we are unable to emulate live User Generated Content at the moment. If you attempt to do any brick building without a 404 server running properly, you will be unable to load into your game. Python is the easiest way to do this, but any thing that returns a 404 should work fine.
* Note: the client hard codes this request on port 80.
<font size="4">**If you do not plan on doing any Brick Building, then you can skip this step.**</font>
The easiest way to do this is to install [python](https://www.python.org/downloads/).
### Allowing a user to build in Brick-by-Brick mode
Brick-By-Brick building requires `PATCHSERVERIP=0:` and `UGCSERVERIP=0:` in the `boot.cfg` to point to a HTTP server which always returns `HTTP 404 - Not Found` for all requests. This can be most easily achieved by pointing both of those variables to `localhost` while having running in the background.
Each client must have their own 404 server running if they are using a locally hosted 404 server.
```bash
# If on linux run this command. Because this is run on a port below 1024, binary network permissions are needed.
sudo python3 -m http.server 80
# If on windows one of the following will work when run through Powershell or Command Prompt assuming python is installed
python3 -m http.server 80
python http.server 80
py -m http.server 80
```
## Updating your server
To update your server to the latest version navigate to your cloned directory
```bash
@@ -327,7 +300,6 @@ Below are known good SHA256 checksums of the client:
* `0d862f71eedcadc4494c4358261669721b40b2131101cbd6ef476c5a6ec6775b` (unpacked client, includes extra locales, rar compressed)
If the returned hash matches one of the lines above then you can continue with setting up the server. If you are using a fully downloaded and complete client from live, then it will work, but the hash above may not match. Otherwise you must obtain a full install of LEGO® Universe 1.10.64.
You must also make absolutely sure your LEGO Universe client is not in a Windows OneDrive. DLU is not and will not support a client being stored in a OneDrive, so ensure you have moved the client outside of that location.
### Darkflame Universe Client
Darkflame Universe clients identify themselves using a higher version number than the regular live clients out there.
@@ -348,66 +320,6 @@ certutil -hashfile <file> SHA1
Known good *SHA1* checksum of the Darkflame Universe client:
- `91498e09b83ce69f46baf9e521d48f23fe502985` (packed client, zip compressed)
# Docker
The Darkflame Server is automatically built and published as a Docker Container / [OCI](https://opencontainers.org/) Image to the GitHub Container Registry at:
[`ghcr.io/darkflameuniverse/darkflameserver`](https://github.com/DarkflameUniverse/DarkflameServer/pkgs/container/darkflameserver).
## Compose
> [!WARNING]
> It seems that Docker Desktop on Windows with the WSL 2 backend has some issues with MariaDB (c.f. [mariadb-docker#331](https://github.com/MariaDB/mariadb-docker/issues/331)) triggered by NexusDashboard
> migrations, so this setup may not work for you. If that is the case, please tell us about your setup in [NexusDashboard#92](https://github.com/DarkflameUniverse/NexusDashboard/issues/92).
You can use the `docker-compose` tool to [setup a MariaDB database](#database-setup), run the Darkflame Server and manage it with [Nexus Dashboard](https://github.com/DarkflameUniverse/NexusDashboard) all
at once. For that:
- [Install Docker Desktop](https://docs.docker.com/get-docker/)
- Open the directory that contains your LU Client
- If the `legouniverse.exe` is in a subfolder called `client`, you're good to go. There may also be a folder `versions`.
- Otherwise, create a new `client` folder and move the exe and everything else (e.g. `res` and `locale`) in there. This is necessary to work around a bug in the client that will prevent that you to log back in after getting disconnected.
- Download the [docker-compose.yml](docker-compose.yml) file and place it next to `client`.
- Download the [.env.example](.env.example) file and place it next to `client` with the file name `.env`
- You may get warnings that this name starts with a dot, acknowledge those, this is intentional. Depending on your operating system, you may need to activate showing hidden files (e.g. Ctrl-H in Gnome on Linux) and/or file extensions ("File name extensions" in the "View" tab on Windows).
- Update the `ACCOUNT_MANAGER_SECRET` and `MARIADB_PASSWORD` with strong random passwords.
- Use a password generator like <https://keygen.io>
- Avoid `:` and `@` characters
- Once the database user is created, changing the password will not update it, so the server will just fail to connect.
- Set `EXTERNAL_IP` to your LAN IP or public IP if you want to host the game for friends & family
- Open a terminal in the folder with the `docker-compose.yml` and `client`
- Run `docker compose up -d`
- This might require `sudo` on Linux, and a recent version of [docker compose](https://docs.docker.com/compose/install/)
- Run `docker exec -it dlu-darkflameserver-1 /app/MasterServer -a` and follow the instructions to create the initial admin account
- Open <http://localhost:8000> to access Nexus Dashboard with the admin account to create normal users
- Set `AUTHSERVERIP=0:localhost` in `client/boot.cfg`
- Replace `localhost` with the value of `EXTERNAL_IP` if you changed that earlier.
- Also make sure `UGCUSE3DSERVICES=7:` is set to `0`
- Launch `legouniverse.exe`
## Standalone
This assumes that you have a database deployed to your host or in another docker container.
A basic deployment of this contianer would look like:
```sh
# example docker contianer deployment
docker run -it \
-v /path/to/configs/:/app/configs \
-v /path/to/logs/:/app/logs \
-v /path/to/dumps/:/app/dumps \
-v /path/to/res:/app/res:ro \
-v /path/to/resServer:/app/resServer \
-e DUMP_FOLDER=/app/dumps \
-p 1001:1001/udp \
-p 2005:2005/udp \
-p 3000-3300:3000-3300/udp \
ghcr.io/darkflameuniverse/darkflameserver:latest
```
You will need to replace the `/path/to/`'s to reflect the paths on your host.
Any config option in the `.ini`'s can be overridden with environmental variables: Ex: `log_to_console=1` from `shared_config.ini` would be overidden like `-e LOG_TO_CONSOLE=0`
# Development Documentation
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)
@@ -441,7 +353,7 @@ This is a Work in Progress, but below are some quick links to documentaion for s
## Former Contributors
* TheMachine
* Matthew
* [Raine](https://github.com/uwainium)
* [Raine](https://github.com/Rainebannister)
* Bricknave
## Special Thanks

View File

@@ -9,5 +9,5 @@ cd build
cmake ..
# To build utilizing multiple cores, append `-j` and the amount of cores to utilize, for example `cmake --build . --config Release -j8'
cmake --build . --config Release $1
cmake --build . --config Release

View File

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

View File

@@ -1,14 +1,13 @@
#include <iostream>
#include <string>
#include <ctime>
#include <csignal>
#include <chrono>
#include <thread>
//DLU Includes:
#include "dCommonVars.h"
#include "dServer.h"
#include "Logger.h"
#include "dLogger.h"
#include "Database.h"
#include "dConfig.h"
#include "Diagnostics.h"
@@ -16,26 +15,20 @@
//RakNet includes:
#include "RakNetDefines.h"
#include "MessageIdentifiers.h"
//Auth includes:
#include "AuthPackets.h"
#include "eConnectionType.h"
#include "eServerMessageType.h"
#include "eAuthMessageType.h"
#include "dMessageIdentifiers.h"
#include "Game.h"
#include "Server.h"
namespace Game {
Logger* logger = nullptr;
dLogger* logger = nullptr;
dServer* server = nullptr;
dConfig* config = nullptr;
Game::signal_t lastSignal = 0;
std::mt19937 randomEngine;
bool shouldShutdown = false;
}
dLogger* SetupLogger();
void HandlePacket(Packet* packet);
int main(int argc, char** argv) {
@@ -45,23 +38,29 @@ int main(int argc, char** argv) {
Diagnostics::SetProcessFileName(argv[0]);
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:
Server::SetupLogger("AuthServer");
Game::logger = SetupLogger();
if (!Game::logger) return EXIT_FAILURE;
LOG("Starting Auth server...");
LOG("Version: %s", PROJECT_VERSION);
LOG("Compiled on: %s", __TIMESTAMP__);
//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");
Game::logger->Log("AuthServer", "Starting Auth server...");
Game::logger->Log("AuthServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR);
Game::logger->Log("AuthServer", "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 {
Database::Connect();
Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password);
} catch (sql::SQLException& ex) {
LOG("Got an error while connecting to the database: %s", ex.what());
Game::logger->Log("AuthServer", "Got an error while connecting to the database: %s", ex.what());
Database::Destroy("AuthServer");
delete Game::server;
delete Game::logger;
@@ -71,26 +70,23 @@ int main(int argc, char** argv) {
//Find out the master's IP:
std::string masterIP;
uint32_t masterPort = 1500;
auto masterInfo = Database::Get()->GetMasterInfo();
if (masterInfo) {
masterIP = masterInfo->ip;
masterPort = masterInfo->port;
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);
}
LOG("Master is at %s:%d", masterIP.c_str(), masterPort);
Game::randomEngine = std::mt19937(time(0));
delete res;
delete stmt;
//It's safe to pass 'localhost' here, as the IP is only used as the external IP.
uint32_t maxClients = 999;
uint32_t maxClients = 50;
uint32_t ourPort = 1001; //LU client is hardcoded to use this for auth port, so I'm making it the default.
std::string ourIP = "localhost";
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;
if (Game::config->GetValue("max_clients") != "") maxClients = std::stoi(Game::config->GetValue("max_clients"));
if (Game::config->GetValue("port") != "") ourPort = std::atoi(Game::config->GetValue("port").c_str());
Game::server = new dServer(ourIP, ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Auth, Game::config, &Game::lastSignal);
Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Auth, Game::config, &Game::shouldShutdown);
//Run it until server gets a kill message from Master:
auto t = std::chrono::high_resolution_clock::now();
@@ -101,18 +97,13 @@ int main(int argc, char** argv) {
uint32_t framesSinceMasterDisconnect = 0;
uint32_t framesSinceLastSQLPing = 0;
AuthPackets::LoadClaimCodes();
Game::logger->Flush(); // once immediately before main loop
while (!Game::ShouldShutdown()) {
while (!Game::shouldShutdown) {
//Check if we're still connected to master:
if (!Game::server->GetIsConnectedToMaster()) {
framesSinceMasterDisconnect++;
if (framesSinceMasterDisconnect >= authFramerate) {
LOG("No connection to master!");
if (framesSinceMasterDisconnect >= authFramerate)
break; //Exit our loop, shut down.
}
} else framesSinceMasterDisconnect = 0;
//In world we'd update our other systems here.
@@ -137,12 +128,16 @@ int main(int argc, char** argv) {
//Find out the master's IP for absolutely no reason:
std::string masterIP;
uint32_t masterPort;
auto masterInfo = Database::Get()->GetMasterInfo();
if (masterInfo) {
masterIP = masterInfo->ip;
masterPort = masterInfo->port;
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;
delete stmt;
framesSinceLastSQLPing = 0;
} else framesSinceLastSQLPing++;
@@ -151,7 +146,6 @@ int main(int argc, char** argv) {
std::this_thread::sleep_until(t);
}
LOG("Exited Main Loop! (signal %d)", Game::lastSignal);
//Delete our objects here:
Database::Destroy("AuthServer");
delete Game::server;
@@ -161,16 +155,26 @@ int main(int argc, char** argv) {
return EXIT_SUCCESS;
}
void HandlePacket(Packet* packet) {
if (packet->length < 4) return;
dLogger* 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 dLogger(logPath, logToConsole, logDebugStatements);
}
void HandlePacket(Packet* packet) {
if (packet->data[0] == ID_USER_PACKET_ENUM) {
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::SERVER) {
if (static_cast<eServerMessageType>(packet->data[3]) == eServerMessageType::VERSION_CONFIRM) {
if (packet->data[1] == SERVER) {
if (packet->data[3] == MSG_SERVER_VERSION_CONFIRM) {
AuthPackets::HandleHandshake(Game::server, packet);
}
} else if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::AUTH) {
if (static_cast<eAuthMessageType>(packet->data[3]) == eAuthMessageType::LOGIN_REQUEST) {
} else if (packet->data[1] == AUTH) {
if (packet->data[3] == MSG_AUTH_LOGIN_REQUEST) {
AuthPackets::HandleLoginRequest(Game::server, packet);
}
}

View File

@@ -1,7 +1,2 @@
add_executable(AuthServer "AuthServer.cpp")
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}\"")
target_link_libraries(AuthServer ${COMMON_LIBRARIES})

View File

@@ -8,11 +8,10 @@
#include <regex>
#include "dCommonVars.h"
#include "Logger.h"
#include "dLogger.h"
#include "dConfig.h"
#include "Database.h"
#include "Game.h"
#include "eGameMasterLevel.h"
using namespace dChatFilterDCF;
@@ -32,11 +31,15 @@ dChatFilter::dChatFilter(const std::string& filepath, bool dontGenerateDCF) {
}
//Read player names that are ok as well:
auto approvedNames = Database::Get()->GetApprovedCharacterNames();
for (auto& name : approvedNames) {
std::transform(name.begin(), name.end(), name.begin(), ::tolower); //Transform to lowercase
m_ApprovedWords.push_back(CalculateHash(name));
auto stmt = Database::CreatePreppedStmt("select name from charinfo;");
auto res = stmt->executeQuery();
while (res->next()) {
std::string line = res->getString(1).c_str();
std::transform(line.begin(), line.end(), line.begin(), ::tolower); //Transform to lowercase
m_ApprovedWords.push_back(CalculateHash(line));
}
delete res;
delete stmt;
}
dChatFilter::~dChatFilter() {
@@ -105,8 +108,8 @@ void dChatFilter::ExportWordlistToDCF(const std::string& filepath, bool whiteLis
}
}
std::vector<std::pair<uint8_t, uint8_t>> dChatFilter::IsSentenceOkay(const std::string& message, eGameMasterLevel gmLevel, bool whiteList) {
if (gmLevel > eGameMasterLevel::FORUM_MODERATOR) return { }; //If anything but a forum mod, return true.
std::vector<std::pair<uint8_t, uint8_t>> dChatFilter::IsSentenceOkay(const std::string& message, int gmLevel, bool whiteList) {
if (gmLevel > GAME_MASTER_LEVEL_FORUM_MODERATOR) return { }; //If anything but a forum mod, return true.
if (message.empty()) return { };
if (!whiteList && m_DeniedWords.empty()) return { { 0, message.length() } };
@@ -140,7 +143,7 @@ std::vector<std::pair<uint8_t, uint8_t>> dChatFilter::IsSentenceOkay(const std::
listOfBadSegments.emplace_back(position, originalSegment.length());
}
position += originalSegment.length() + 1;
position += segment.length() + 1;
}
return listOfBadSegments;

View File

@@ -4,7 +4,6 @@
#include "dCommonVars.h"
enum class eGameMasterLevel : uint8_t;
namespace dChatFilterDCF {
static const uint32_t header = ('D' + ('C' << 8) + ('F' << 16) + ('B' << 24));
static const uint32_t formatVersion = 2;
@@ -24,7 +23,7 @@ public:
void ReadWordlistPlaintext(const std::string& filepath, bool whiteList);
bool ReadWordlistDCF(const std::string& filepath, bool whiteList);
void ExportWordlistToDCF(const std::string& filepath, bool whiteList);
std::vector<std::pair<uint8_t, uint8_t>> IsSentenceOkay(const std::string& message, eGameMasterLevel gmLevel, bool whiteList = true);
std::vector<std::pair<uint8_t, uint8_t>> IsSentenceOkay(const std::string& message, int gmLevel, bool whiteList = true);
private:
bool m_DontGenerateDCF;

View File

@@ -1,14 +1,10 @@
set(DCHATSERVER_SOURCES
"ChatIgnoreList.cpp"
"ChatPacketHandler.cpp"
"PlayerContainer.cpp"
)
add_executable(ChatServer "ChatServer.cpp")
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(ChatServer ${COMMON_LIBRARIES} dChatFilter dChatServer dServer)
target_link_libraries(ChatServer ${COMMON_LIBRARIES} dChatFilter dChatServer)

View File

@@ -1,171 +0,0 @@
#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);
}

View File

@@ -1,27 +0,0 @@
#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

View File

@@ -4,56 +4,16 @@
#include "BitStream.h"
struct PlayerData;
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,
};
enum class AddFriendResponseType : uint8_t;
namespace ChatPacketHandler {
void HandleFriendlistRequest(Packet* packet);
void HandleFriendRequest(Packet* packet);
void HandleFriendResponse(Packet* packet);
void HandleRemoveFriend(Packet* packet);
void HandleGMLevelUpdate(Packet* packet);
void HandleChatMessage(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 HandleTeamInviteResponse(Packet* packet);
@@ -63,18 +23,18 @@ namespace ChatPacketHandler {
void HandleTeamLootOption(Packet* packet);
void HandleTeamStatusRequest(Packet* packet);
void SendTeamInvite(const PlayerData& receiver, const PlayerData& sender);
void SendTeamInviteConfirm(const PlayerData& receiver, bool bLeaderIsFreeTrial, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, uint8_t ucResponseCode, std::u16string wsLeaderName);
void SendTeamStatus(const PlayerData& receiver, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, std::u16string wsLeaderName);
void SendTeamSetLeader(const PlayerData& receiver, LWOOBJID i64PlayerID);
void SendTeamAddPlayer(const PlayerData& receiver, bool bIsFreeTrial, bool bLocal, bool bNoLootOnDeath, LWOOBJID i64PlayerID, std::u16string wsPlayerName, LWOZONEID zoneID);
void SendTeamRemovePlayer(const PlayerData& receiver, bool bDisband, bool bIsKicked, bool bIsLeaving, bool bLocal, LWOOBJID i64LeaderID, LWOOBJID i64PlayerID, std::u16string wsPlayerName);
void SendTeamSetOffWorldFlag(const PlayerData& receiver, LWOOBJID i64PlayerID, LWOZONEID zoneID);
void SendTeamInvite(PlayerData* receiver, 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 SendTeamStatus(PlayerData* receiver, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, std::u16string wsLeaderName);
void SendTeamSetLeader(PlayerData* receiver, LWOOBJID i64PlayerID);
void SendTeamAddPlayer(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 SendTeamSetOffWorldFlag(PlayerData* receiver, LWOOBJID i64PlayerID, LWOZONEID zoneID);
//FriendData is the player we're SENDING this stuff to. Player is the friend that changed state.
void SendFriendUpdate(const PlayerData& friendData, const PlayerData& playerData, uint8_t notifyType, uint8_t isBestFriend);
void SendFriendUpdate(PlayerData* friendData, PlayerData* playerData, uint8_t notifyType, uint8_t isBestFriend);
void SendFriendRequest(const PlayerData& receiver, const PlayerData& sender);
void SendFriendResponse(const PlayerData& receiver, const PlayerData& sender, eAddFriendResponseType responseCode, uint8_t isBestFriendsAlready = 0U, uint8_t isBestFriendRequest = 0U);
void SendRemoveFriend(const PlayerData& receiver, std::string& personToRemove, bool isSuccessful);
void SendFriendRequest(PlayerData* receiver, PlayerData* sender);
void SendFriendResponse(PlayerData* receiver, PlayerData* sender, AddFriendResponseType responseCode, uint8_t isBestFriendsAlready = 0U, uint8_t isBestFriendRequest = 0U);
void SendRemoveFriend(PlayerData* receiver, std::string& personToRemove, bool isSuccessful);
};

View File

@@ -6,42 +6,37 @@
//DLU Includes:
#include "dCommonVars.h"
#include "dServer.h"
#include "Logger.h"
#include "dLogger.h"
#include "Database.h"
#include "dConfig.h"
#include "dMessageIdentifiers.h"
#include "dChatFilter.h"
#include "Diagnostics.h"
#include "AssetManager.h"
#include "BinaryPathFinder.h"
#include "eConnectionType.h"
#include "PlayerContainer.h"
#include "ChatPacketHandler.h"
#include "eChatMessageType.h"
#include "eChatInternalMessageType.h"
#include "eWorldMessageType.h"
#include "ChatIgnoreList.h"
#include "StringifiedEnum.h"
#include "Game.h"
#include "Server.h"
//RakNet includes:
#include "RakNetDefines.h"
#include "MessageIdentifiers.h"
namespace Game {
Logger* logger = nullptr;
dLogger* logger = nullptr;
dServer* server = nullptr;
dConfig* config = nullptr;
dChatFilter* chatFilter = nullptr;
AssetManager* assetManager = nullptr;
Game::signal_t lastSignal = 0;
std::mt19937 randomEngine;
PlayerContainer playerContainer;
bool shouldShutdown = false;
}
dLogger* SetupLogger();
void HandlePacket(Packet* packet);
PlayerContainer playerContainer;
int main(int argc, char** argv) {
constexpr uint32_t chatFramerate = mediumFramerate;
constexpr uint32_t chatFrameDelta = mediumFrameDelta;
@@ -49,20 +44,18 @@ int main(int argc, char** argv) {
Diagnostics::SetProcessFileName(argv[0]);
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:
Server::SetupLogger("ChatServer");
Game::logger = SetupLogger();
if (!Game::logger) return EXIT_FAILURE;
//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("Version: %s", PROJECT_VERSION);
LOG("Compiled on: %s", __TIMESTAMP__);
Game::logger->Log("ChatServer", "Starting Chat server...");
Game::logger->Log("ChatServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR);
Game::logger->Log("ChatServer", "Compiled on: %s", __TIMESTAMP__);
try {
std::string clientPathStr = Game::config->GetValue("client_location");
@@ -74,16 +67,21 @@ int main(int argc, char** argv) {
Game::assetManager = new AssetManager(clientPath);
} catch (std::runtime_error& ex) {
LOG("Got an error while setting up assets: %s", ex.what());
Game::logger->Log("ChatServer", "Got an error while setting up assets: %s", ex.what());
return EXIT_FAILURE;
}
//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 {
Database::Connect();
Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password);
} catch (sql::SQLException& ex) {
LOG("Got an error while connecting to the database: %s", ex.what());
Game::logger->Log("ChatServer", "Got an error while connecting to the database: %s", ex.what());
Database::Destroy("ChatServer");
delete Game::server;
delete Game::logger;
@@ -93,29 +91,25 @@ int main(int argc, char** argv) {
//Find out the master's IP:
std::string masterIP;
uint32_t masterPort = 1000;
auto masterInfo = Database::Get()->GetMasterInfo();
if (masterInfo) {
masterIP = masterInfo->ip;
masterPort = masterInfo->port;
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;
delete stmt;
//It's safe to pass 'localhost' here, as the IP is only used as the external IP.
uint32_t maxClients = 999;
uint32_t maxClients = 50;
uint32_t ourPort = 1501;
std::string ourIP = "localhost";
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;
if (Game::config->GetValue("max_clients") != "") maxClients = std::stoi(Game::config->GetValue("max_clients"));
if (Game::config->GetValue("port") != "") ourPort = std::atoi(Game::config->GetValue("port").c_str());
Game::server = new dServer(ourIP, ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config, &Game::lastSignal);
Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config, &Game::shouldShutdown);
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::playerContainer.Initialize();
Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(Game::config->GetValue("dont_generate_dcf"))));
//Run it until server gets a kill message from Master:
auto t = std::chrono::high_resolution_clock::now();
@@ -126,8 +120,7 @@ int main(int argc, char** argv) {
uint32_t framesSinceMasterDisconnect = 0;
uint32_t framesSinceLastSQLPing = 0;
Game::logger->Flush(); // once immediately before main loop
while (!Game::ShouldShutdown()) {
while (!Game::shouldShutdown) {
//Check if we're still connected to master:
if (!Game::server->GetIsConnectedToMaster()) {
framesSinceMasterDisconnect++;
@@ -158,13 +151,16 @@ int main(int argc, char** argv) {
//Find out the master's IP for absolutely no reason:
std::string masterIP;
uint32_t masterPort;
auto masterInfo = Database::Get()->GetMasterInfo();
if (masterInfo) {
masterIP = masterInfo->ip;
masterPort = masterInfo->port;
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;
delete stmt;
framesSinceLastSQLPing = 0;
} else framesSinceLastSQLPing++;
@@ -182,36 +178,46 @@ int main(int argc, char** argv) {
return EXIT_SUCCESS;
}
dLogger* 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 dLogger(logPath, logToConsole, logDebugStatements);
}
void HandlePacket(Packet* packet) {
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.");
Game::logger->Log("ChatServer", "A server has disconnected, erasing their connected players from the list.");
}
if (packet->data[0] == ID_NEW_INCOMING_CONNECTION) {
LOG("A server is connecting, awaiting user list.");
Game::logger->Log("ChatServer", "A server is connecting, awaiting user list.");
}
if (packet->length < 4) return; // Nothing left to process. Need 4 bytes to continue.
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::CHAT_INTERNAL) {
switch (static_cast<eChatInternalMessageType>(packet->data[3])) {
case eChatInternalMessageType::PLAYER_ADDED_NOTIFICATION:
Game::playerContainer.InsertPlayer(packet);
if (packet->data[1] == CHAT_INTERNAL) {
switch (packet->data[3]) {
case MSG_CHAT_INTERNAL_PLAYER_ADDED_NOTIFICATION:
playerContainer.InsertPlayer(packet);
break;
case eChatInternalMessageType::PLAYER_REMOVED_NOTIFICATION:
Game::playerContainer.RemovePlayer(packet);
case MSG_CHAT_INTERNAL_PLAYER_REMOVED_NOTIFICATION:
playerContainer.RemovePlayer(packet);
break;
case eChatInternalMessageType::MUTE_UPDATE:
Game::playerContainer.MuteUpdate(packet);
case MSG_CHAT_INTERNAL_MUTE_UPDATE:
playerContainer.MuteUpdate(packet);
break;
case eChatInternalMessageType::CREATE_TEAM:
Game::playerContainer.CreateTeamServer(packet);
case MSG_CHAT_INTERNAL_CREATE_TEAM:
playerContainer.CreateTeamServer(packet);
break;
case eChatInternalMessageType::ANNOUNCEMENT: {
case MSG_CHAT_INTERNAL_ANNOUNCEMENT: {
//we just forward this packet to every connected server
CINSTREAM;
Game::server->Send(&inStream, packet->systemAddress, true); //send to everyone except origin
@@ -219,149 +225,88 @@ void HandlePacket(Packet* packet) {
}
default:
LOG("Unknown CHAT_INTERNAL id: %i", int(packet->data[3]));
Game::logger->Log("ChatServer", "Unknown CHAT_INTERNAL id: %i", int(packet->data[3]));
}
}
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::CHAT) {
eChatMessageType chat_message_type = static_cast<eChatMessageType>(packet->data[3]);
switch (chat_message_type) {
case eChatMessageType::GET_FRIENDS_LIST:
if (packet->data[1] == CHAT) {
switch (packet->data[3]) {
case MSG_CHAT_GET_FRIENDS_LIST:
ChatPacketHandler::HandleFriendlistRequest(packet);
break;
case eChatMessageType::GET_IGNORE_LIST:
ChatIgnoreList::GetIgnoreList(packet);
case MSG_CHAT_GET_IGNORE_LIST:
Game::logger->Log("ChatServer", "Asked for ignore list, but is unimplemented right now.");
break;
case eChatMessageType::ADD_IGNORE:
ChatIgnoreList::AddIgnore(packet);
break;
case eChatMessageType::REMOVE_IGNORE:
ChatIgnoreList::RemoveIgnore(packet);
break;
case eChatMessageType::TEAM_GET_STATUS:
case MSG_CHAT_TEAM_GET_STATUS:
ChatPacketHandler::HandleTeamStatusRequest(packet);
break;
case eChatMessageType::ADD_FRIEND_REQUEST:
case MSG_CHAT_ADD_FRIEND_REQUEST:
//this involves someone sending the initial request, the response is below, response as in from the other player.
//We basically just check to see if this player is online or not and route the packet.
ChatPacketHandler::HandleFriendRequest(packet);
break;
case eChatMessageType::ADD_FRIEND_RESPONSE:
case MSG_CHAT_ADD_FRIEND_RESPONSE:
//This isn't the response a server sent, rather it is a player's response to a received request.
//Here, we'll actually have to add them to eachother's friend lists depending on the response code.
ChatPacketHandler::HandleFriendResponse(packet);
break;
case eChatMessageType::REMOVE_FRIEND:
case MSG_CHAT_REMOVE_FRIEND:
ChatPacketHandler::HandleRemoveFriend(packet);
break;
case eChatMessageType::GENERAL_CHAT_MESSAGE:
case MSG_CHAT_GENERAL_CHAT_MESSAGE:
ChatPacketHandler::HandleChatMessage(packet);
break;
case eChatMessageType::PRIVATE_CHAT_MESSAGE:
case MSG_CHAT_PRIVATE_CHAT_MESSAGE:
//This message is supposed to be echo'd to both the sender and the receiver
//BUT: they have to have different responseCodes, so we'll do some of the ol hacky wacky to fix that right up.
ChatPacketHandler::HandlePrivateChatMessage(packet);
break;
case eChatMessageType::TEAM_INVITE:
case MSG_CHAT_TEAM_INVITE:
ChatPacketHandler::HandleTeamInvite(packet);
break;
case eChatMessageType::TEAM_INVITE_RESPONSE:
case MSG_CHAT_TEAM_INVITE_RESPONSE:
ChatPacketHandler::HandleTeamInviteResponse(packet);
break;
case eChatMessageType::TEAM_LEAVE:
case MSG_CHAT_TEAM_LEAVE:
ChatPacketHandler::HandleTeamLeave(packet);
break;
case eChatMessageType::TEAM_SET_LEADER:
case MSG_CHAT_TEAM_SET_LEADER:
ChatPacketHandler::HandleTeamPromote(packet);
break;
case eChatMessageType::TEAM_KICK:
case MSG_CHAT_TEAM_KICK:
ChatPacketHandler::HandleTeamKick(packet);
break;
case eChatMessageType::TEAM_SET_LOOT:
case MSG_CHAT_TEAM_SET_LOOT:
ChatPacketHandler::HandleTeamLootOption(packet);
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:
LOG("Unknown CHAT Message id: %i", chat_message_type);
Game::logger->Log("ChatServer", "Unknown CHAT id: %i", int(packet->data[3]));
}
}
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::WORLD) {
switch (static_cast<eWorldMessageType>(packet->data[3])) {
case eWorldMessageType::ROUTE_PACKET: {
LOG("Routing packet from world");
if (packet->data[1] == WORLD) {
switch (packet->data[3]) {
case MSG_WORLD_CLIENT_ROUTE_PACKET: {
Game::logger->Log("ChatServer", "Routing packet from world");
break;
}
default:
LOG("Unknown World id: %i", int(packet->data[3]));
Game::logger->Log("ChatServer", "Unknown World id: %i", int(packet->data[3]));
}
}
}

View File

@@ -3,126 +3,123 @@
#include <iostream>
#include <algorithm>
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
#include "ChatPacketHandler.h"
#include "GeneralUtils.h"
#include "BitStreamUtils.h"
#include "dMessageIdentifiers.h"
#include "PacketUtils.h"
#include "Database.h"
#include "eConnectionType.h"
#include "eChatInternalMessageType.h"
#include "eGameMasterLevel.h"
#include "ChatPackets.h"
#include "dConfig.h"
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() {
m_Players.clear();
}
PlayerData::PlayerData() {
gmLevel = eGameMasterLevel::CIVILIAN;
}
TeamData::TeamData() {
lootFlag = Game::config->GetValue("default_team_loot") == "0" ? 0 : 1;
mPlayers.clear();
}
void PlayerContainer::InsertPlayer(Packet* packet) {
CINSTREAM_SKIP_HEADER;
LWOOBJID playerId;
if (!inStream.Read(playerId)) {
LOG("Failed to read player ID");
return;
}
auto& data = m_Players[playerId];
data.playerID = playerId;
CINSTREAM;
PlayerData* data = new PlayerData();
inStream.SetReadOffset(inStream.GetReadOffset() + 64);
inStream.Read(data->playerID);
uint32_t len;
inStream.Read<uint32_t>(len);
for (int i = 0; i < len; i++) {
char character; inStream.Read<char>(character);
data.playerName += character;
data->playerName += character;
}
inStream.Read(data.zoneID);
inStream.Read(data.muteExpire);
inStream.Read(data.gmLevel);
data.sysAddr = packet->systemAddress;
inStream.Read(data->zoneID);
inStream.Read(data->muteExpire);
data->sysAddr = packet->systemAddress;
m_Names[data.playerID] = GeneralUtils::UTF8ToUTF16(data.playerName);
mNames[data->playerID] = GeneralUtils::UTF8ToUTF16(data->playerName);
LOG("Added user: %s (%llu), zone: %i", data.playerName.c_str(), data.playerID, data.zoneID.GetMapID());
mPlayers.insert(std::make_pair(data->playerID, data));
Game::logger->Log("PlayerContainer", "Added user: %s (%llu), zone: %i", data->playerName.c_str(), data->playerID, data->zoneID.GetMapID());
Database::Get()->UpdateActivityLog(data.playerID, eActivityType::PlayerLoggedIn, data.zoneID.GetMapID());
auto* insertLog = Database::CreatePreppedStmt("INSERT INTO activity_log (character_id, activity, time, map_id) VALUES (?, ?, ?, ?);");
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) {
CINSTREAM_SKIP_HEADER;
CINSTREAM;
LWOOBJID playerID;
inStream.Read(playerID); //skip header
inStream.Read(playerID);
//Before they get kicked, we need to also send a message to their friends saying that they disconnected.
const auto& player = GetPlayerData(playerID);
std::unique_ptr<PlayerData> player(this->GetPlayerData(playerID));
if (!player) {
LOG("Failed to find user: %llu", playerID);
if (player == nullptr) {
return;
}
for (const auto& fr : player.friends) {
const auto& fd = this->GetPlayerData(fr.friendID);
if (fd) ChatPacketHandler::SendFriendUpdate(fd, player, 0, fr.isBestFriend);
for (auto& fr : player->friends) {
auto fd = this->GetPlayerData(fr.friendID);
if (fd) ChatPacketHandler::SendFriendUpdate(fd, player.get(), 0, fr.isBestFriend);
}
auto* team = GetTeam(playerID);
if (team != nullptr) {
const auto memberName = GeneralUtils::UTF8ToUTF16(player.playerName);
const auto memberName = GeneralUtils::UTF8ToUTF16(std::string(player->playerName.c_str()));
for (const auto memberId : team->memberIDs) {
const auto& otherMember = GetPlayerData(memberId);
auto* otherMember = GetPlayerData(memberId);
if (!otherMember) continue;
if (otherMember == nullptr) continue;
ChatPacketHandler::SendTeamSetOffWorldFlag(otherMember, playerID, { 0, 0, 0 });
}
}
LOG("Removed user: %llu", playerID);
m_Players.erase(playerID);
Game::logger->Log("PlayerContainer", "Removed user: %llu", playerID);
mPlayers.erase(playerID);
Database::Get()->UpdateActivityLog(playerID, eActivityType::PlayerLoggedOut, player.zoneID.GetMapID());
auto* insertLog = Database::CreatePreppedStmt("INSERT INTO activity_log (character_id, activity, time, map_id) VALUES (?, ?, ?, ?);");
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) {
CINSTREAM_SKIP_HEADER;
CINSTREAM;
LWOOBJID playerID;
inStream.Read(playerID); //skip header
inStream.Read(playerID);
time_t expire = 0;
inStream.Read(expire);
auto& player = this->GetPlayerDataMutable(playerID);
auto* player = this->GetPlayerData(playerID);
if (!player) {
LOG("Failed to find user: %llu", playerID);
if (player == nullptr) {
Game::logger->Log("PlayerContainer", "Failed to find user: %llu", playerID);
return;
}
player.muteExpire = expire;
player->muteExpire = expire;
BroadcastMuteUpdate(playerID, expire);
}
void PlayerContainer::CreateTeamServer(Packet* packet) {
CINSTREAM_SKIP_HEADER;
CINSTREAM;
LWOOBJID playerID;
inStream.Read(playerID); //skip header
inStream.Read(playerID);
size_t membersSize = 0;
inStream.Read(membersSize);
@@ -152,7 +149,7 @@ void PlayerContainer::CreateTeamServer(Packet* packet) {
void PlayerContainer::BroadcastMuteUpdate(LWOOBJID player, time_t time) {
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::MUTE_UPDATE);
PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_MUTE_UPDATE);
bitStream.Write(player);
bitStream.Write(time);
@@ -191,7 +188,7 @@ TeamData* PlayerContainer::CreateLocalTeam(std::vector<LWOOBJID> members) {
TeamData* PlayerContainer::CreateTeam(LWOOBJID leader, bool local) {
auto* team = new TeamData();
team->teamID = ++m_TeamIDCounter;
team->teamID = ++mTeamIDCounter;
team->leaderID = leader;
team->local = local;
@@ -213,32 +210,24 @@ TeamData* PlayerContainer::GetTeam(LWOOBJID playerID) {
}
void PlayerContainer::AddMember(TeamData* team, LWOOBJID playerID) {
if (team->memberIDs.size() >= 4) {
LOG("Tried to add player to team that already had 4 players");
const auto& player = GetPlayerData(playerID);
if (!player) return;
ChatPackets::SendSystemMessage(player.sysAddr, u"The teams is full! You have not been added to a team!");
return;
}
const auto index = std::find(team->memberIDs.begin(), team->memberIDs.end(), playerID);
if (index != team->memberIDs.end()) return;
team->memberIDs.push_back(playerID);
const auto& leader = GetPlayerData(team->leaderID);
const auto& member = GetPlayerData(playerID);
auto* leader = GetPlayerData(team->leaderID);
auto* member = GetPlayerData(playerID);
if (!leader || !member) return;
if (leader == nullptr || member == nullptr) return;
const auto leaderName = GeneralUtils::UTF8ToUTF16(leader.playerName);
const auto memberName = GeneralUtils::UTF8ToUTF16(member.playerName);
const auto leaderName = GeneralUtils::UTF8ToUTF16(leader->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) {
ChatPacketHandler::SendTeamSetLeader(member, leader.playerID);
ChatPacketHandler::SendTeamSetLeader(member, leader->playerID);
} else {
ChatPacketHandler::SendTeamSetLeader(member, LWOOBJID_EMPTY);
}
@@ -246,16 +235,16 @@ void PlayerContainer::AddMember(TeamData* team, LWOOBJID playerID) {
UpdateTeamsOnWorld(team, false);
for (const auto memberId : team->memberIDs) {
const auto& otherMember = GetPlayerData(memberId);
auto* otherMember = GetPlayerData(memberId);
if (otherMember == member) continue;
const auto otherMemberName = GetName(memberId);
ChatPacketHandler::SendTeamAddPlayer(member, false, team->local, false, memberId, otherMemberName, otherMember ? otherMember.zoneID : LWOZONEID(0, 0, 0));
ChatPacketHandler::SendTeamAddPlayer(member, false, team->local, false, memberId, otherMemberName, otherMember != nullptr ? otherMember->zoneID : LWOZONEID(0, 0, 0));
if (otherMember) {
ChatPacketHandler::SendTeamAddPlayer(otherMember, false, team->local, false, member.playerID, memberName, member.zoneID);
if (otherMember != nullptr) {
ChatPacketHandler::SendTeamAddPlayer(otherMember, false, team->local, false, member->playerID, memberName, member->zoneID);
}
}
}
@@ -265,9 +254,9 @@ void PlayerContainer::RemoveMember(TeamData* team, LWOOBJID playerID, bool disba
if (index == team->memberIDs.end()) return;
const auto& member = GetPlayerData(playerID);
auto* member = GetPlayerData(playerID);
if (member && !silent) {
if (member != nullptr && !silent) {
ChatPacketHandler::SendTeamSetLeader(member, LWOOBJID_EMPTY);
}
@@ -278,9 +267,9 @@ void PlayerContainer::RemoveMember(TeamData* team, LWOOBJID playerID, bool disba
continue;
}
const auto& otherMember = GetPlayerData(memberId);
auto* otherMember = GetPlayerData(memberId);
if (!otherMember) continue;
if (otherMember == nullptr) continue;
ChatPacketHandler::SendTeamRemovePlayer(otherMember, disband, kicked, leaving, false, team->leaderID, playerID, memberName);
}
@@ -302,9 +291,9 @@ void PlayerContainer::PromoteMember(TeamData* team, LWOOBJID newLeader) {
team->leaderID = newLeader;
for (const auto memberId : team->memberIDs) {
const auto& otherMember = GetPlayerData(memberId);
auto* otherMember = GetPlayerData(memberId);
if (!otherMember) continue;
if (otherMember == nullptr) continue;
ChatPacketHandler::SendTeamSetLeader(otherMember, newLeader);
}
@@ -316,14 +305,14 @@ void PlayerContainer::DisbandTeam(TeamData* team) {
if (index == mTeams.end()) return;
for (const auto memberId : team->memberIDs) {
const auto& otherMember = GetPlayerData(memberId);
auto* otherMember = GetPlayerData(memberId);
if (!otherMember) continue;
if (otherMember == nullptr) continue;
const auto memberName = GeneralUtils::UTF8ToUTF16(otherMember.playerName);
const auto memberName = GeneralUtils::UTF8ToUTF16(otherMember->playerName);
ChatPacketHandler::SendTeamSetLeader(otherMember, LWOOBJID_EMPTY);
ChatPacketHandler::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);
@@ -338,19 +327,19 @@ void PlayerContainer::TeamStatusUpdate(TeamData* team) {
if (index == mTeams.end()) return;
const auto& leader = GetPlayerData(team->leaderID);
auto* leader = GetPlayerData(team->leaderID);
if (!leader) return;
if (leader == nullptr) return;
const auto leaderName = GeneralUtils::UTF8ToUTF16(leader.playerName);
const auto leaderName = GeneralUtils::UTF8ToUTF16(leader->playerName);
for (const auto memberId : team->memberIDs) {
const auto& otherMember = GetPlayerData(memberId);
auto* otherMember = GetPlayerData(memberId);
if (!otherMember) continue;
if (otherMember == nullptr) continue;
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);
}
}
@@ -359,14 +348,14 @@ void PlayerContainer::TeamStatusUpdate(TeamData* team) {
void PlayerContainer::UpdateTeamsOnWorld(TeamData* team, bool deleteTeam) {
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::TEAM_UPDATE);
PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_TEAM_UPDATE);
bitStream.Write(team->teamID);
bitStream.Write(deleteTeam);
if (!deleteTeam) {
bitStream.Write(team->lootFlag);
bitStream.Write<char>(team->memberIDs.size());
bitStream.Write(static_cast<char>(team->memberIDs.size()));
for (const auto memberID : team->memberIDs) {
bitStream.Write(memberID);
}
@@ -376,42 +365,23 @@ void PlayerContainer::UpdateTeamsOnWorld(TeamData* team, bool deleteTeam) {
}
std::u16string PlayerContainer::GetName(LWOOBJID playerID) {
const auto iter = m_Names.find(playerID);
const auto& pair = mNames.find(playerID);
if (iter == m_Names.end()) return u"";
if (pair == mNames.end()) return u"";
return iter->second;
return pair->second;
}
LWOOBJID PlayerContainer::GetId(const std::u16string& playerName) {
LWOOBJID toReturn = LWOOBJID_EMPTY;
for (const auto& [id, name] : m_Names) {
if (name == playerName) {
toReturn = id;
break;
for (const auto& pair : mNames) {
if (pair.second == playerName) {
return pair.first;
}
}
return toReturn;
return LWOOBJID_EMPTY;
}
PlayerData& PlayerContainer::GetPlayerDataMutable(const LWOOBJID& playerID) {
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);
bool PlayerContainer::GetIsMuted(PlayerData* data) {
return data->muteExpire == 1 || data->muteExpire > time(NULL);
}

View File

@@ -7,50 +7,17 @@
#include "dServer.h"
#include <unordered_map>
enum class eGameMasterLevel : uint8_t;
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;
};
struct PlayerData {
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;
LWOOBJID playerID;
std::string playerName;
SystemAddress sysAddr;
LWOZONEID zoneID;
std::vector<FriendData> friends;
std::vector<IgnoreData> ignoredPlayers;
eGameMasterLevel gmLevel;
bool isFTP = false;
time_t muteExpire;
uint8_t countOfBestFriends = 0;
};
struct TeamData {
TeamData();
LWOOBJID teamID = LWOOBJID_EMPTY; // Internal use
LWOOBJID leaderID = LWOOBJID_EMPTY;
std::vector<LWOOBJID> memberIDs{};
@@ -61,19 +28,31 @@ struct TeamData {
class PlayerContainer {
public:
PlayerContainer();
~PlayerContainer();
void Initialize();
void InsertPlayer(Packet* packet);
void RemovePlayer(Packet* packet);
void MuteUpdate(Packet* packet);
void CreateTeamServer(Packet* packet);
void BroadcastMuteUpdate(LWOOBJID player, time_t time);
const PlayerData& GetPlayerData(const LWOOBJID& playerID);
const PlayerData& GetPlayerData(const std::string& playerName);
PlayerData& GetPlayerDataMutable(const LWOOBJID& playerID);
PlayerData& GetPlayerDataMutable(const std::string& playerName);
PlayerData* GetPlayerData(const LWOOBJID& playerID) {
auto it = mPlayers.find(playerID);
if (it != mPlayers.end()) return it->second;
return nullptr;
}
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* CreateTeam(LWOOBJID leader, bool local = false);
@@ -86,15 +65,14 @@ public:
void UpdateTeamsOnWorld(TeamData* team, bool deleteTeam);
std::u16string GetName(LWOOBJID playerID);
LWOOBJID GetId(const std::u16string& playerName);
uint32_t GetMaxNumberOfBestFriends() { return m_MaxNumberOfBestFriends; }
uint32_t GetMaxNumberOfFriends() { return m_MaxNumberOfFriends; }
bool GetIsMuted(PlayerData* data);
std::map<LWOOBJID, PlayerData*>& GetAllPlayerData() { return mPlayers; }
private:
LWOOBJID m_TeamIDCounter = 0;
std::map<LWOOBJID, PlayerData> m_Players;
LWOOBJID mTeamIDCounter = 0;
std::map<LWOOBJID, PlayerData*> mPlayers;
std::vector<TeamData*> mTeams;
std::unordered_map<LWOOBJID, std::u16string> m_Names;
uint32_t m_MaxNumberOfBestFriends = 5;
uint32_t m_MaxNumberOfFriends = 50;
std::unordered_map<LWOOBJID, std::u16string> mNames;
};

View File

@@ -1,79 +1,77 @@
#include "AMFDeserialize.h"
#include <stdexcept>
#include "Amf3.h"
#include "AMFFormat.h"
/**
* AMF3 Reference document https://rtmp.veriskope.com/pdf/amf3-file-format-spec.pdf
* AMF3 Deserializer written by EmosewaMC
*/
AMFBaseValue* AMFDeserialize::Read(RakNet::BitStream* inStream) {
AMFValue* AMFDeserialize::Read(RakNet::BitStream* inStream) {
if (!inStream) return nullptr;
AMFBaseValue* returnValue = nullptr;
AMFValue* returnValue = nullptr;
// Read in the value type from the bitStream
eAmf marker;
int8_t marker;
inStream->Read(marker);
// Based on the typing, create the value associated with that and return the base value class
switch (marker) {
case eAmf::Undefined: {
returnValue = new AMFBaseValue();
case AMFValueType::AMFUndefined: {
returnValue = new AMFUndefinedValue();
break;
}
case eAmf::Null: {
case AMFValueType::AMFNull: {
returnValue = new AMFNullValue();
break;
}
case eAmf::False: {
returnValue = new AMFBoolValue(false);
case AMFValueType::AMFFalse: {
returnValue = new AMFFalseValue();
break;
}
case eAmf::True: {
returnValue = new AMFBoolValue(true);
case AMFValueType::AMFTrue: {
returnValue = new AMFTrueValue();
break;
}
case eAmf::Integer: {
case AMFValueType::AMFInteger: {
returnValue = ReadAmfInteger(inStream);
break;
}
case eAmf::Double: {
case AMFValueType::AMFDouble: {
returnValue = ReadAmfDouble(inStream);
break;
}
case eAmf::String: {
case AMFValueType::AMFString: {
returnValue = ReadAmfString(inStream);
break;
}
case eAmf::Array: {
case AMFValueType::AMFArray: {
returnValue = ReadAmfArray(inStream);
break;
}
// These values are unimplemented in the live client and will remain unimplemented
// unless someone modifies the client to allow serializing of these values.
case eAmf::XMLDoc:
case eAmf::Date:
case eAmf::Object:
case eAmf::XML:
case eAmf::ByteArray:
case eAmf::VectorInt:
case eAmf::VectorUInt:
case eAmf::VectorDouble:
case eAmf::VectorObject:
case eAmf::Dictionary: {
throw marker;
// TODO We do not need these values, but if someone wants to implement them
// then please do so and add the corresponding unit tests.
case AMFValueType::AMFXMLDoc:
case AMFValueType::AMFDate:
case AMFValueType::AMFObject:
case AMFValueType::AMFXML:
case AMFValueType::AMFByteArray:
case AMFValueType::AMFVectorInt:
case AMFValueType::AMFVectorUInt:
case AMFValueType::AMFVectorDouble:
case AMFValueType::AMFVectorObject:
case AMFValueType::AMFDictionary: {
throw static_cast<AMFValueType>(marker);
break;
}
default:
throw std::invalid_argument("Invalid AMF3 marker" + std::to_string(static_cast<int32_t>(marker)));
throw static_cast<AMFValueType>(marker);
break;
}
return returnValue;
@@ -101,7 +99,7 @@ uint32_t AMFDeserialize::ReadU29(RakNet::BitStream* inStream) {
return actualNumber;
}
const std::string AMFDeserialize::ReadString(RakNet::BitStream* inStream) {
std::string AMFDeserialize::ReadString(RakNet::BitStream* inStream) {
auto length = ReadU29(inStream);
// Check if this is a reference
bool isReference = length % 2 == 1;
@@ -115,39 +113,48 @@ const std::string AMFDeserialize::ReadString(RakNet::BitStream* inStream) {
return value;
} else {
// Length is a reference to a previous index - use that as the read in value
return accessedElements.at(length);
return accessedElements[length];
}
}
AMFBaseValue* AMFDeserialize::ReadAmfDouble(RakNet::BitStream* inStream) {
AMFValue* AMFDeserialize::ReadAmfDouble(RakNet::BitStream* inStream) {
auto doubleValue = new AMFDoubleValue();
double value;
inStream->Read<double>(value);
return new AMFDoubleValue(value);
doubleValue->SetDoubleValue(value);
return doubleValue;
}
AMFBaseValue* AMFDeserialize::ReadAmfArray(RakNet::BitStream* inStream) {
AMFValue* AMFDeserialize::ReadAmfArray(RakNet::BitStream* inStream) {
auto arrayValue = new AMFArrayValue();
// Read size of dense array
auto sizeOfDenseArray = (ReadU29(inStream) >> 1);
// Then read associative portion
// Then read Key'd portion
while (true) {
auto key = ReadString(inStream);
// No more associative values when we encounter an empty string key
// No more values when we encounter an empty string
if (key.size() == 0) break;
arrayValue->Insert(key, Read(inStream));
arrayValue->InsertValue(key, Read(inStream));
}
// Finally read dense portion
for (uint32_t i = 0; i < sizeOfDenseArray; i++) {
arrayValue->Insert(i, Read(inStream));
arrayValue->PushBackValue(Read(inStream));
}
return arrayValue;
}
AMFBaseValue* AMFDeserialize::ReadAmfString(RakNet::BitStream* inStream) {
return new AMFStringValue(ReadString(inStream));
AMFValue* AMFDeserialize::ReadAmfString(RakNet::BitStream* inStream) {
auto stringValue = new AMFStringValue();
stringValue->SetStringValue(ReadString(inStream));
return stringValue;
}
AMFBaseValue* AMFDeserialize::ReadAmfInteger(RakNet::BitStream* inStream) {
return new AMFIntValue(ReadU29(inStream));
AMFValue* AMFDeserialize::ReadAmfInteger(RakNet::BitStream* inStream) {
auto integerValue = new AMFIntegerValue();
integerValue->SetIntegerValue(ReadU29(inStream));
return integerValue;
}

View File

@@ -5,8 +5,7 @@
#include <vector>
#include <string>
class AMFBaseValue;
class AMFValue;
class AMFDeserialize {
public:
/**
@@ -15,7 +14,7 @@ public:
* @param inStream inStream to read value from.
* @return Returns an AMFValue with all the information from the bitStream in it.
*/
AMFBaseValue* Read(RakNet::BitStream* inStream);
AMFValue* Read(RakNet::BitStream* inStream);
private:
/**
* @brief Private method to read a U29 integer from a bitstream
@@ -31,7 +30,7 @@ private:
* @param inStream bitStream to read data from
* @return The read string
*/
const std::string ReadString(RakNet::BitStream* inStream);
std::string ReadString(RakNet::BitStream* inStream);
/**
* @brief Read an AMFDouble value from a bitStream
@@ -39,7 +38,7 @@ private:
* @param inStream bitStream to read data from
* @return Double value represented as an AMFValue
*/
AMFBaseValue* ReadAmfDouble(RakNet::BitStream* inStream);
AMFValue* ReadAmfDouble(RakNet::BitStream* inStream);
/**
* @brief Read an AMFArray from a bitStream
@@ -47,7 +46,7 @@ private:
* @param inStream bitStream to read data from
* @return Array value represented as an AMFValue
*/
AMFBaseValue* ReadAmfArray(RakNet::BitStream* inStream);
AMFValue* ReadAmfArray(RakNet::BitStream* inStream);
/**
* @brief Read an AMFString from a bitStream
@@ -55,7 +54,7 @@ private:
* @param inStream bitStream to read data from
* @return String value represented as an AMFValue
*/
AMFBaseValue* ReadAmfString(RakNet::BitStream* inStream);
AMFValue* ReadAmfString(RakNet::BitStream* inStream);
/**
* @brief Read an AMFInteger from a bitStream
@@ -63,7 +62,7 @@ private:
* @param inStream bitStream to read data from
* @return Integer value represented as an AMFValue
*/
AMFBaseValue* ReadAmfInteger(RakNet::BitStream* inStream);
AMFValue* ReadAmfInteger(RakNet::BitStream* inStream);
/**
* List of strings read so far saved to be read by reference.

156
dCommon/AMFFormat.cpp Normal file
View File

@@ -0,0 +1,156 @@
#include "AMFFormat.h"
// AMFInteger
void AMFIntegerValue::SetIntegerValue(uint32_t value) {
this->value = value;
}
uint32_t AMFIntegerValue::GetIntegerValue() {
return this->value;
}
// AMFDouble
void AMFDoubleValue::SetDoubleValue(double value) {
this->value = value;
}
double AMFDoubleValue::GetDoubleValue() {
return this->value;
}
// AMFString
void AMFStringValue::SetStringValue(const std::string& value) {
this->value = value;
}
std::string AMFStringValue::GetStringValue() {
return this->value;
}
// AMFXMLDoc
void AMFXMLDocValue::SetXMLDocValue(const std::string& value) {
this->xmlData = value;
}
std::string AMFXMLDocValue::GetXMLDocValue() {
return this->xmlData;
}
// AMFDate
void AMFDateValue::SetDateValue(uint64_t value) {
this->millisecondTimestamp = value;
}
uint64_t AMFDateValue::GetDateValue() {
return this->millisecondTimestamp;
}
// AMFArray Insert Value
void AMFArrayValue::InsertValue(const std::string& key, AMFValue* value) {
this->associative.insert(std::make_pair(key, value));
}
// AMFArray Remove Value
void AMFArrayValue::RemoveValue(const std::string& key) {
_AMFArrayMap_::iterator it = this->associative.find(key);
if (it != this->associative.end()) {
this->associative.erase(it);
}
}
// AMFArray Get Associative Iterator Begin
_AMFArrayMap_::iterator AMFArrayValue::GetAssociativeIteratorValueBegin() {
return this->associative.begin();
}
// AMFArray Get Associative Iterator End
_AMFArrayMap_::iterator AMFArrayValue::GetAssociativeIteratorValueEnd() {
return this->associative.end();
}
// AMFArray Push Back Value
void AMFArrayValue::PushBackValue(AMFValue* value) {
this->dense.push_back(value);
}
// AMFArray Pop Back Value
void AMFArrayValue::PopBackValue() {
this->dense.pop_back();
}
// AMFArray Get Dense List Size
uint32_t AMFArrayValue::GetDenseValueSize() {
return (uint32_t)this->dense.size();
}
// AMFArray Get Dense Iterator Begin
_AMFArrayList_::iterator AMFArrayValue::GetDenseIteratorBegin() {
return this->dense.begin();
}
// AMFArray Get Dense Iterator End
_AMFArrayList_::iterator AMFArrayValue::GetDenseIteratorEnd() {
return this->dense.end();
}
AMFArrayValue::~AMFArrayValue() {
for (auto valueToDelete : GetDenseArray()) {
if (valueToDelete) delete valueToDelete;
}
for (auto valueToDelete : GetAssociativeMap()) {
if (valueToDelete.second) delete valueToDelete.second;
}
}
// AMFObject Constructor
AMFObjectValue::AMFObjectValue(std::vector<std::pair<std::string, AMFValueType>> traits) {
this->traits.reserve(traits.size());
std::vector<std::pair<std::string, AMFValueType>>::iterator it = traits.begin();
while (it != traits.end()) {
this->traits.insert(std::make_pair(it->first, std::make_pair(it->second, new AMFNullValue())));
it++;
}
}
// AMFObject Set Value
void AMFObjectValue::SetTraitValue(const std::string& trait, AMFValue* value) {
if (value) {
_AMFObjectTraits_::iterator it = this->traits.find(trait);
if (it != this->traits.end()) {
if (it->second.first == value->GetValueType()) {
it->second.second = value;
}
}
}
}
// AMFObject Get Value
AMFValue* AMFObjectValue::GetTraitValue(const std::string& trait) {
_AMFObjectTraits_::iterator it = this->traits.find(trait);
if (it != this->traits.end()) {
return it->second.second;
}
return nullptr;
}
// AMFObject Get Trait Iterator Begin
_AMFObjectTraits_::iterator AMFObjectValue::GetTraitsIteratorBegin() {
return this->traits.begin();
}
// AMFObject Get Trait Iterator End
_AMFObjectTraits_::iterator AMFObjectValue::GetTraitsIteratorEnd() {
return this->traits.end();
}
// AMFObject Get Trait Size
uint32_t AMFObjectValue::GetTraitArrayCount() {
return (uint32_t)this->traits.size();
}
AMFObjectValue::~AMFObjectValue() {
for (auto valueToDelete = GetTraitsIteratorBegin(); valueToDelete != GetTraitsIteratorEnd(); valueToDelete++) {
if (valueToDelete->second.second) delete valueToDelete->second.second;
}
}

413
dCommon/AMFFormat.h Normal file
View File

@@ -0,0 +1,413 @@
#pragma once
// Custom Classes
#include "dCommonVars.h"
// C++
#include <unordered_map>
#include <vector>
/*!
\file AMFFormat.hpp
\brief A class for managing AMF values
*/
class AMFValue; // Forward declaration
// Definitions
#define _AMFArrayMap_ std::unordered_map<std::string, AMFValue*>
#define _AMFArrayList_ std::vector<AMFValue*>
#define _AMFObjectTraits_ std::unordered_map<std::string, std::pair<AMFValueType, AMFValue*>>
#define _AMFObjectDynamicTraits_ std::unordered_map<std::string, AMFValue*>
//! An enum for each AMF value type
enum AMFValueType : unsigned char {
AMFUndefined = 0x00, //!< An undefined AMF Value
AMFNull = 0x01, //!< A null AMF value
AMFFalse = 0x02, //!< A false AMF value
AMFTrue = 0x03, //!< A true AMF value
AMFInteger = 0x04, //!< An integer AMF value
AMFDouble = 0x05, //!< A double AMF value
AMFString = 0x06, //!< A string AMF value
AMFXMLDoc = 0x07, //!< An XML Doc AMF value
AMFDate = 0x08, //!< A date AMF value
AMFArray = 0x09, //!< An array AMF value
AMFObject = 0x0A, //!< An object AMF value
AMFXML = 0x0B, //!< An XML AMF value
AMFByteArray = 0x0C, //!< A byte array AMF value
AMFVectorInt = 0x0D, //!< An integer vector AMF value
AMFVectorUInt = 0x0E, //!< An unsigned integer AMF value
AMFVectorDouble = 0x0F, //!< A double vector AMF value
AMFVectorObject = 0x10, //!< An object vector AMF value
AMFDictionary = 0x11 //!< A dictionary AMF value
};
//! An enum for the object value types
enum AMFObjectValueType : unsigned char {
AMFObjectAnonymous = 0x01,
AMFObjectTyped = 0x02,
AMFObjectDynamic = 0x03,
AMFObjectExternalizable = 0x04
};
//! The base AMF value class
class AMFValue {
public:
//! Returns the AMF value type
/*!
\return The AMF value type
*/
virtual AMFValueType GetValueType() = 0;
virtual ~AMFValue() {};
};
//! A typedef for a pointer to an AMF value
typedef AMFValue* NDGFxValue;
// The various AMF value types
//! The undefined value AMF type
class AMFUndefinedValue : public AMFValue {
private:
//! Returns the AMF value type
/*!
\return The AMF value type
*/
AMFValueType GetValueType() { return ValueType; }
public:
static const AMFValueType ValueType = AMFUndefined;
};
//! The null value AMF type
class AMFNullValue : public AMFValue {
private:
//! Returns the AMF value type
/*!
\return The AMF value type
*/
AMFValueType GetValueType() { return ValueType; }
public:
static const AMFValueType ValueType = AMFNull;
};
//! The false value AMF type
class AMFFalseValue : public AMFValue {
private:
//! Returns the AMF value type
/*!
\return The AMF value type
*/
AMFValueType GetValueType() { return ValueType; }
public:
static const AMFValueType ValueType = AMFFalse;
};
//! The true value AMF type
class AMFTrueValue : public AMFValue {
private:
//! Returns the AMF value type
/*!
\return The AMF value type
*/
AMFValueType GetValueType() { return ValueType; }
public:
static const AMFValueType ValueType = AMFTrue;
};
//! The integer value AMF type
class AMFIntegerValue : public AMFValue {
private:
uint32_t value; //!< The value of the AMF type
//! Returns the AMF value type
/*!
\return The AMF value type
*/
AMFValueType GetValueType() { return ValueType; }
public:
static const AMFValueType ValueType = AMFInteger;
//! Sets the integer value
/*!
\param value The value to set
*/
void SetIntegerValue(uint32_t value);
//! Gets the integer value
/*!
\return The integer value
*/
uint32_t GetIntegerValue();
};
//! The double value AMF type
class AMFDoubleValue : public AMFValue {
private:
double value; //!< The value of the AMF type
//! Returns the AMF value type
/*!
\return The AMF value type
*/
AMFValueType GetValueType() { return ValueType; }
public:
static const AMFValueType ValueType = AMFDouble;
//! Sets the double value
/*!
\param value The value to set to
*/
void SetDoubleValue(double value);
//! Gets the double value
/*!
\return The double value
*/
double GetDoubleValue();
};
//! The string value AMF type
class AMFStringValue : public AMFValue {
private:
std::string value; //!< The value of the AMF type
//! Returns the AMF value type
/*!
\return The AMF value type
*/
AMFValueType GetValueType() { return ValueType; }
public:
static const AMFValueType ValueType = AMFString;
//! Sets the string value
/*!
\param value The string value to set to
*/
void SetStringValue(const std::string& value);
//! Gets the string value
/*!
\return The string value
*/
std::string GetStringValue();
};
//! The XML doc value AMF type
class AMFXMLDocValue : public AMFValue {
private:
std::string xmlData; //!< The value of the AMF type
//! Returns the AMF value type
/*!
\return The AMF value type
*/
AMFValueType GetValueType() { return ValueType; }
public:
static const AMFValueType ValueType = AMFXMLDoc;
//! Sets the XML Doc value
/*!
\param value The value to set to
*/
void SetXMLDocValue(const std::string& value);
//! Gets the XML Doc value
/*!
\return The XML Doc value
*/
std::string GetXMLDocValue();
};
//! The date value AMF type
class AMFDateValue : public AMFValue {
private:
uint64_t millisecondTimestamp; //!< The time in milliseconds since the ephoch
//! Returns the AMF value type
/*!
\return The AMF value type
*/
AMFValueType GetValueType() { return ValueType; }
public:
static const AMFValueType ValueType = AMFDate;
//! Sets the date time
/*!
\param value The value to set to
*/
void SetDateValue(uint64_t value);
//! Gets the date value
/*!
\return The date value in milliseconds since the epoch
*/
uint64_t GetDateValue();
};
//! The array value AMF type
// This object will manage it's own memory map and list. Do not delete its values.
class AMFArrayValue : public AMFValue {
private:
_AMFArrayMap_ associative; //!< The array map (associative part)
_AMFArrayList_ dense; //!< The array list (dense part)
//! Returns the AMF value type
/*!
\return The AMF value type
*/
AMFValueType GetValueType() { return ValueType; }
public:
static const AMFValueType ValueType = AMFArray;
~AMFArrayValue() override;
//! Inserts an item into the array map for a specific key
/*!
\param key The key to set
\param value The value to add
*/
void InsertValue(const std::string& key, AMFValue* value);
//! Removes an item for a specific key
/*!
\param key The key to remove
*/
void RemoveValue(const std::string& key);
//! Finds an AMF value
/*!
\return The AMF value if found, nullptr otherwise
*/
template <typename T>
T* FindValue(const std::string& key) const {
_AMFArrayMap_::const_iterator it = this->associative.find(key);
if (it != this->associative.end() && T::ValueType == it->second->GetValueType()) {
return dynamic_cast<T*>(it->second);
}
return nullptr;
};
//! Returns where the associative iterator begins
/*!
\return Where the array map iterator begins
*/
_AMFArrayMap_::iterator GetAssociativeIteratorValueBegin();
//! Returns where the associative iterator ends
/*!
\return Where the array map iterator ends
*/
_AMFArrayMap_::iterator GetAssociativeIteratorValueEnd();
//! Pushes back a value into the array list
/*!
\param value The value to push back
*/
void PushBackValue(AMFValue* value);
//! Pops back the last value in the array list
void PopBackValue();
//! Gets the count of the dense list
/*!
\return The dense list size
*/
uint32_t GetDenseValueSize();
//! Gets a specific value from the list for the specified index
/*!
\param index The index to get
*/
template <typename T>
T* GetValueAt(uint32_t index) {
if (index >= this->dense.size()) return nullptr;
AMFValue* foundValue = this->dense.at(index);
return T::ValueType == foundValue->GetValueType() ? dynamic_cast<T*>(foundValue) : nullptr;
};
//! Returns where the dense iterator begins
/*!
\return Where the iterator begins
*/
_AMFArrayList_::iterator GetDenseIteratorBegin();
//! Returns where the dense iterator ends
/*!
\return Where the iterator ends
*/
_AMFArrayList_::iterator GetDenseIteratorEnd();
//! Returns the associative map
/*!
\return The associative map
*/
_AMFArrayMap_ GetAssociativeMap() { return this->associative; };
//! Returns the dense array
/*!
\return The dense array
*/
_AMFArrayList_ GetDenseArray() { return this->dense; };
};
//! The anonymous object value AMF type
class AMFObjectValue : public AMFValue {
private:
_AMFObjectTraits_ traits; //!< The object traits
//! Returns the AMF value type
/*!
\return The AMF value type
*/
AMFValueType GetValueType() { return ValueType; }
~AMFObjectValue() override;
public:
static const AMFValueType ValueType = AMFObject;
//! Constructor
/*!
\param traits The traits to set
*/
AMFObjectValue(std::vector<std::pair<std::string, AMFValueType>> traits);
//! Gets the object value type
/*!
\return The object value type
*/
virtual AMFObjectValueType GetObjectValueType() { return AMFObjectAnonymous; }
//! Sets the value of a trait
/*!
\param trait The trait to set the value for
\param value The AMF value to set
*/
void SetTraitValue(const std::string& trait, AMFValue* value);
//! Gets a trait value
/*!
\param trait The trait to get the value for
\return The trait value
*/
AMFValue* GetTraitValue(const std::string& trait);
//! Gets the beginning of the object traits iterator
/*!
\return The AMF trait array iterator begin
*/
_AMFObjectTraits_::iterator GetTraitsIteratorBegin();
//! Gets the end of the object traits iterator
/*!
\return The AMF trait array iterator begin
*/
_AMFObjectTraits_::iterator GetTraitsIteratorEnd();
//! Gets the amount of traits
/*!
\return The amount of traits
*/
uint32_t GetTraitArrayCount();
};

View File

@@ -0,0 +1,250 @@
#include "AMFFormat_BitStream.h"
// Writes an AMFValue pointer to a RakNet::BitStream
template<>
void RakNet::BitStream::Write<AMFValue*>(AMFValue* value) {
if (value != nullptr) {
AMFValueType type = value->GetValueType();
switch (type) {
case AMFUndefined: {
AMFUndefinedValue* v = (AMFUndefinedValue*)value;
this->Write(*v);
break;
}
case AMFNull: {
AMFNullValue* v = (AMFNullValue*)value;
this->Write(*v);
break;
}
case AMFFalse: {
AMFFalseValue* v = (AMFFalseValue*)value;
this->Write(*v);
break;
}
case AMFTrue: {
AMFTrueValue* v = (AMFTrueValue*)value;
this->Write(*v);
break;
}
case AMFInteger: {
AMFIntegerValue* v = (AMFIntegerValue*)value;
this->Write(*v);
break;
}
case AMFDouble: {
AMFDoubleValue* v = (AMFDoubleValue*)value;
this->Write(*v);
break;
}
case AMFString: {
AMFStringValue* v = (AMFStringValue*)value;
this->Write(*v);
break;
}
case AMFXMLDoc: {
AMFXMLDocValue* v = (AMFXMLDocValue*)value;
this->Write(*v);
break;
}
case AMFDate: {
AMFDateValue* v = (AMFDateValue*)value;
this->Write(*v);
break;
}
case AMFArray: {
this->Write((AMFArrayValue*)value);
break;
}
}
}
}
/**
* A private function to write an value to a RakNet::BitStream
* RakNet writes in the correct byte order - do not reverse this.
*/
void WriteUInt29(RakNet::BitStream* bs, uint32_t v) {
unsigned char b4 = (unsigned char)v;
if (v < 0x00200000) {
b4 = b4 & 0x7F;
if (v > 0x7F) {
unsigned char b3;
v = v >> 7;
b3 = ((unsigned char)(v)) | 0x80;
if (v > 0x7F) {
unsigned char b2;
v = v >> 7;
b2 = ((unsigned char)(v)) | 0x80;
bs->Write(b2);
}
bs->Write(b3);
}
} else {
unsigned char b1;
unsigned char b2;
unsigned char b3;
v = v >> 8;
b3 = ((unsigned char)(v)) | 0x80;
v = v >> 7;
b2 = ((unsigned char)(v)) | 0x80;
v = v >> 7;
b1 = ((unsigned char)(v)) | 0x80;
bs->Write(b1);
bs->Write(b2);
bs->Write(b3);
}
bs->Write(b4);
}
/**
* Writes a flag number to a RakNet::BitStream
* RakNet writes in the correct byte order - do not reverse this.
*/
void WriteFlagNumber(RakNet::BitStream* bs, uint32_t v) {
v = (v << 1) | 0x01;
WriteUInt29(bs, v);
}
/**
* Writes an AMFString to a RakNet::BitStream
*
* RakNet writes in the correct byte order - do not reverse this.
*/
void WriteAMFString(RakNet::BitStream* bs, const std::string& str) {
WriteFlagNumber(bs, (uint32_t)str.size());
bs->Write(str.c_str(), (uint32_t)str.size());
}
/**
* Writes an U16 to a bitstream
*
* RakNet writes in the correct byte order - do not reverse this.
*/
void WriteAMFU16(RakNet::BitStream* bs, uint16_t value) {
bs->Write(value);
}
/**
* Writes an U32 to a bitstream
*
* RakNet writes in the correct byte order - do not reverse this.
*/
void WriteAMFU32(RakNet::BitStream* bs, uint32_t value) {
bs->Write(value);
}
/**
* Writes an U64 to a bitstream
*
* RakNet writes in the correct byte order - do not reverse this.
*/
void WriteAMFU64(RakNet::BitStream* bs, uint64_t value) {
bs->Write(value);
}
// Writes an AMFUndefinedValue to BitStream
template<>
void RakNet::BitStream::Write<AMFUndefinedValue>(AMFUndefinedValue value) {
this->Write(AMFUndefined);
}
// Writes an AMFNullValue to BitStream
template<>
void RakNet::BitStream::Write<AMFNullValue>(AMFNullValue value) {
this->Write(AMFNull);
}
// Writes an AMFFalseValue to BitStream
template<>
void RakNet::BitStream::Write<AMFFalseValue>(AMFFalseValue value) {
this->Write(AMFFalse);
}
// Writes an AMFTrueValue to BitStream
template<>
void RakNet::BitStream::Write<AMFTrueValue>(AMFTrueValue value) {
this->Write(AMFTrue);
}
// Writes an AMFIntegerValue to BitStream
template<>
void RakNet::BitStream::Write<AMFIntegerValue>(AMFIntegerValue value) {
this->Write(AMFInteger);
WriteUInt29(this, value.GetIntegerValue());
}
// Writes an AMFDoubleValue to BitStream
template<>
void RakNet::BitStream::Write<AMFDoubleValue>(AMFDoubleValue value) {
this->Write(AMFDouble);
double d = value.GetDoubleValue();
WriteAMFU64(this, *((unsigned long long*) & d));
}
// Writes an AMFStringValue to BitStream
template<>
void RakNet::BitStream::Write<AMFStringValue>(AMFStringValue value) {
this->Write(AMFString);
std::string v = value.GetStringValue();
WriteAMFString(this, v);
}
// Writes an AMFXMLDocValue to BitStream
template<>
void RakNet::BitStream::Write<AMFXMLDocValue>(AMFXMLDocValue value) {
this->Write(AMFXMLDoc);
std::string v = value.GetXMLDocValue();
WriteAMFString(this, v);
}
// Writes an AMFDateValue to BitStream
template<>
void RakNet::BitStream::Write<AMFDateValue>(AMFDateValue value) {
this->Write(AMFDate);
uint64_t date = value.GetDateValue();
WriteAMFU64(this, date);
}
// Writes an AMFArrayValue to BitStream
template<>
void RakNet::BitStream::Write<AMFArrayValue*>(AMFArrayValue* value) {
this->Write(AMFArray);
uint32_t denseSize = value->GetDenseValueSize();
WriteFlagNumber(this, denseSize);
_AMFArrayMap_::iterator it = value->GetAssociativeIteratorValueBegin();
_AMFArrayMap_::iterator end = value->GetAssociativeIteratorValueEnd();
while (it != end) {
WriteAMFString(this, it->first);
this->Write(it->second);
it++;
}
this->Write(AMFNull);
if (denseSize > 0) {
_AMFArrayList_::iterator it2 = value->GetDenseIteratorBegin();
_AMFArrayList_::iterator end2 = value->GetDenseIteratorEnd();
while (it2 != end2) {
this->Write(*it2);
it2++;
}
}
}

View File

@@ -0,0 +1,92 @@
#pragma once
// Custom Classes
#include "AMFFormat.h"
// RakNet
#include <BitStream.h>
/*!
\file AMFFormat_BitStream.h
\brief A class that implements native writing of AMF values to RakNet::BitStream
*/
// We are using the RakNet namespace
namespace RakNet {
//! Writes an AMFValue pointer to a RakNet::BitStream
/*!
\param value The value to write
*/
template <>
void RakNet::BitStream::Write<AMFValue*>(AMFValue* value);
//! Writes an AMFUndefinedValue to a RakNet::BitStream
/*!
\param value The value to write
*/
template <>
void RakNet::BitStream::Write<AMFUndefinedValue>(AMFUndefinedValue value);
//! Writes an AMFNullValue to a RakNet::BitStream
/*!
\param value The value to write
*/
template <>
void RakNet::BitStream::Write<AMFNullValue>(AMFNullValue value);
//! Writes an AMFFalseValue to a RakNet::BitStream
/*!
\param value The value to write
*/
template <>
void RakNet::BitStream::Write<AMFFalseValue>(AMFFalseValue value);
//! Writes an AMFTrueValue to a RakNet::BitStream
/*!
\param value The value to write
*/
template <>
void RakNet::BitStream::Write<AMFTrueValue>(AMFTrueValue value);
//! Writes an AMFIntegerValue to a RakNet::BitStream
/*!
\param value The value to write
*/
template <>
void RakNet::BitStream::Write<AMFIntegerValue>(AMFIntegerValue value);
//! Writes an AMFDoubleValue to a RakNet::BitStream
/*!
\param value The value to write
*/
template <>
void RakNet::BitStream::Write<AMFDoubleValue>(AMFDoubleValue value);
//! Writes an AMFStringValue to a RakNet::BitStream
/*!
\param value The value to write
*/
template <>
void RakNet::BitStream::Write<AMFStringValue>(AMFStringValue value);
//! Writes an AMFXMLDocValue to a RakNet::BitStream
/*!
\param value The value to write
*/
template <>
void RakNet::BitStream::Write<AMFXMLDocValue>(AMFXMLDocValue value);
//! Writes an AMFDateValue to a RakNet::BitStream
/*!
\param value The value to write
*/
template <>
void RakNet::BitStream::Write<AMFDateValue>(AMFDateValue value);
//! Writes an AMFArrayValue to a RakNet::BitStream
/*!
\param value The value to write
*/
template <>
void RakNet::BitStream::Write<AMFArrayValue*>(AMFArrayValue* value);
} // namespace RakNet

View File

@@ -1,367 +0,0 @@
#ifndef __AMF3__H__
#define __AMF3__H__
#include "dCommonVars.h"
#include "Logger.h"
#include "Game.h"
#include <unordered_map>
#include <vector>
enum class eAmf : uint8_t {
Undefined = 0x00, // An undefined AMF Value
Null = 0x01, // A null AMF value
False = 0x02, // A false AMF value
True = 0x03, // A true AMF value
Integer = 0x04, // An integer AMF value
Double = 0x05, // A double AMF value
String = 0x06, // A string AMF value
XMLDoc = 0x07, // Unused in the live client and cannot be serialized without modification. An XML Doc AMF value
Date = 0x08, // Unused in the live client and cannot be serialized without modification. A date AMF value
Array = 0x09, // An array AMF value
Object = 0x0A, // Unused in the live client and cannot be serialized without modification. An object AMF value
XML = 0x0B, // Unused in the live client and cannot be serialized without modification. An XML AMF value
ByteArray = 0x0C, // Unused in the live client and cannot be serialized without modification. A byte array AMF value
VectorInt = 0x0D, // Unused in the live client and cannot be serialized without modification. An integer vector AMF value
VectorUInt = 0x0E, // Unused in the live client and cannot be serialized without modification. An unsigned integer AMF value
VectorDouble = 0x0F, // Unused in the live client and cannot be serialized without modification. A double vector AMF value
VectorObject = 0x10, // Unused in the live client and cannot be serialized without modification. An object vector AMF value
Dictionary = 0x11 // Unused in the live client and cannot be serialized without modification. A dictionary AMF value
};
class AMFBaseValue {
public:
virtual eAmf GetValueType() { return eAmf::Undefined; };
AMFBaseValue() {};
virtual ~AMFBaseValue() {};
};
template<typename ValueType>
class AMFValue : public AMFBaseValue {
public:
AMFValue() {};
AMFValue(ValueType value) { SetValue(value); };
virtual ~AMFValue() override {};
eAmf GetValueType() override { return eAmf::Undefined; };
const ValueType& GetValue() { return data; };
void SetValue(ValueType value) { data = value; };
protected:
ValueType data;
};
// As a string this is much easier to write and read from a BitStream.
template<>
class AMFValue<const char*> : public AMFBaseValue {
public:
AMFValue() {};
AMFValue(const char* value) { SetValue(std::string(value)); };
virtual ~AMFValue() override {};
eAmf GetValueType() override { return eAmf::String; };
const std::string& GetValue() { return data; };
void SetValue(std::string value) { data = value; };
protected:
std::string data;
};
typedef AMFValue<std::nullptr_t> AMFNullValue;
typedef AMFValue<bool> AMFBoolValue;
typedef AMFValue<int32_t> AMFIntValue;
typedef AMFValue<std::string> AMFStringValue;
typedef AMFValue<double> AMFDoubleValue;
template<> inline eAmf AMFValue<std::nullptr_t>::GetValueType() { return eAmf::Null; };
template<> inline eAmf AMFValue<bool>::GetValueType() { return this->data ? eAmf::True : eAmf::False; };
template<> inline eAmf AMFValue<int32_t>::GetValueType() { return eAmf::Integer; };
template<> inline eAmf AMFValue<uint32_t>::GetValueType() { return eAmf::Integer; };
template<> inline eAmf AMFValue<std::string>::GetValueType() { return eAmf::String; };
template<> inline eAmf AMFValue<double>::GetValueType() { return eAmf::Double; };
/**
* The AMFArrayValue object holds 2 types of lists:
* An associative list where a key maps to a value
* A Dense list where elements are stored back to back
*
* Objects that are Registered are owned by this object
* and are not to be deleted by a caller.
*/
class AMFArrayValue : public AMFBaseValue {
typedef std::unordered_map<std::string, AMFBaseValue*> AMFAssociative;
typedef std::vector<AMFBaseValue*> AMFDense;
public:
eAmf GetValueType() override { return eAmf::Array; };
~AMFArrayValue() override {
for (auto valueToDelete : GetDense()) {
if (valueToDelete) {
delete valueToDelete;
valueToDelete = nullptr;
}
}
for (auto valueToDelete : GetAssociative()) {
if (valueToDelete.second) {
delete valueToDelete.second;
valueToDelete.second = nullptr;
}
}
};
/**
* Returns the Associative portion of the object
*/
inline AMFAssociative& GetAssociative() { return this->associative; };
/**
* Returns the dense portion of the object
*/
inline AMFDense& GetDense() { return this->dense; };
/**
* Inserts an AMFValue into the associative portion with the given key.
* If a duplicate is attempted to be inserted, it is ignored and the
* first value with that key is kept in the map.
*
* These objects are not to be deleted by the caller as they are owned by
* the AMFArray object which manages its own memory.
*
* @param key The key to associate with the value
* @param value The value to insert
*
* @return The inserted element if the type matched,
* or nullptr if a key existed and was not the same type
*/
template<typename ValueType>
std::pair<AMFValue<ValueType>*, bool> Insert(const std::string& key, ValueType value) {
auto element = associative.find(key);
AMFValue<ValueType>* val = nullptr;
bool found = true;
if (element == associative.end()) {
val = new AMFValue<ValueType>(value);
associative.insert(std::make_pair(key, val));
} else {
val = dynamic_cast<AMFValue<ValueType>*>(element->second);
found = false;
}
return std::make_pair(val, found);
};
// Associates an array with a string key
std::pair<AMFBaseValue*, bool> Insert(const std::string& key) {
auto element = associative.find(key);
AMFArrayValue* val = nullptr;
bool found = true;
if (element == associative.end()) {
val = new AMFArrayValue();
associative.insert(std::make_pair(key, val));
} else {
val = dynamic_cast<AMFArrayValue*>(element->second);
found = false;
}
return std::make_pair(val, found);
};
// Associates an array with an integer key
std::pair<AMFBaseValue*, bool> Insert(const uint32_t& index) {
AMFArrayValue* val = nullptr;
bool inserted = false;
if (index >= dense.size()) {
dense.resize(index + 1);
val = new AMFArrayValue();
dense.at(index) = val;
inserted = true;
}
return std::make_pair(dynamic_cast<AMFArrayValue*>(dense.at(index)), inserted);
};
/**
* @brief Inserts an AMFValue into the AMFArray key'd by index.
* Attempting to insert the same key to the same value twice overwrites
* the previous value with the new one.
*
* @param index The index to associate with the value
* @param value The value to insert
* @return The inserted element, or nullptr if the type did not match
* what was at the index.
*/
template<typename ValueType>
std::pair<AMFValue<ValueType>*, bool> Insert(const uint32_t& index, ValueType value) {
AMFValue<ValueType>* val = nullptr;
bool inserted = false;
if (index >= this->dense.size()) {
this->dense.resize(index + 1);
val = new AMFValue<ValueType>(value);
this->dense.at(index) = val;
inserted = true;
}
return std::make_pair(dynamic_cast<AMFValue<ValueType>*>(this->dense.at(index)), inserted);
};
/**
* Inserts an AMFValue into the associative portion with the given key.
* If a duplicate is attempted to be inserted, it replaces the original
*
* The inserted element is now owned by this object and is not to be deleted
*
* @param key The key to associate with the value
* @param value The value to insert
*/
void Insert(const std::string& key, AMFBaseValue* value) {
auto element = associative.find(key);
if (element != associative.end() && element->second) {
delete element->second;
element->second = value;
} else {
associative.insert(std::make_pair(key, value));
}
};
/**
* Inserts an AMFValue into the associative portion with the given index.
* If a duplicate is attempted to be inserted, it replaces the original
*
* The inserted element is now owned by this object and is not to be deleted
*
* @param key The key to associate with the value
* @param value The value to insert
*/
void Insert(const uint32_t index, AMFBaseValue* value) {
if (index < dense.size()) {
AMFDense::iterator itr = dense.begin() + index;
if (*itr) delete dense.at(index);
} else {
dense.resize(index + 1);
}
dense.at(index) = value;
};
/**
* Pushes an AMFValue into the back of the dense portion.
*
* These objects are not to be deleted by the caller as they are owned by
* the AMFArray object which manages its own memory.
*
* @param value The value to insert
*
* @return The inserted pointer, or nullptr should the key already be in use.
*/
template<typename ValueType>
inline AMFValue<ValueType>* Push(ValueType value) {
return Insert(this->dense.size(), value).first;
};
/**
* Removes the key from the associative portion
*
* The pointer removed is now no longer managed by this container
*
* @param key The key to remove from the associative portion
*/
void Remove(const std::string& key, bool deleteValue = true) {
AMFAssociative::iterator it = this->associative.find(key);
if (it != this->associative.end()) {
if (deleteValue) delete it->second;
this->associative.erase(it);
}
}
/**
* Pops the last element in the dense portion, deleting it in the process.
*/
void Remove(const uint32_t index) {
if (!this->dense.empty() && index < this->dense.size()) {
auto itr = this->dense.begin() + index;
if (*itr) delete (*itr);
this->dense.erase(itr);
}
}
void Pop() {
if (!this->dense.empty()) Remove(this->dense.size() - 1);
}
AMFArrayValue* GetArray(const std::string& key) {
AMFAssociative::const_iterator it = this->associative.find(key);
if (it != this->associative.end()) {
return dynamic_cast<AMFArrayValue*>(it->second);
}
return nullptr;
};
AMFArrayValue* GetArray(const uint32_t index) {
return index >= this->dense.size() ? nullptr : dynamic_cast<AMFArrayValue*>(this->dense.at(index));
};
inline AMFArrayValue* InsertArray(const std::string& key) {
return static_cast<AMFArrayValue*>(Insert(key).first);
};
inline AMFArrayValue* InsertArray(const uint32_t index) {
return static_cast<AMFArrayValue*>(Insert(index).first);
};
inline AMFArrayValue* PushArray() {
return static_cast<AMFArrayValue*>(Insert(this->dense.size()).first);
};
/**
* Gets an AMFValue by the key from the associative portion and converts it
* to the AmfValue template type. If the key did not exist, it is inserted.
*
* @tparam The target object type
* @param key The key to lookup
*
* @return The AMFValue
*/
template <typename AmfType>
AMFValue<AmfType>* Get(const std::string& key) const {
AMFAssociative::const_iterator it = this->associative.find(key);
return it != this->associative.end() ?
dynamic_cast<AMFValue<AmfType>*>(it->second) :
nullptr;
};
// Get from the array but dont cast it
AMFBaseValue* Get(const std::string& key) const {
AMFAssociative::const_iterator it = this->associative.find(key);
return it != this->associative.end() ? it->second : nullptr;
};
/**
* @brief Get an AMFValue object at a position in the dense portion.
* Gets an AMFValue by the index from the dense portion and converts it
* to the AmfValue template type. If the index did not exist, it is inserted.
*
* @tparam The target object type
* @param index The index to get
* @return The casted object, or nullptr.
*/
template <typename AmfType>
AMFValue<AmfType>* Get(uint32_t index) const {
return index < this->dense.size() ?
dynamic_cast<AMFValue<AmfType>*>(this->dense.at(index)) :
nullptr;
};
// Get from the dense but dont cast it
AMFBaseValue* Get(const uint32_t index) const {
return index < this->dense.size() ? this->dense.at(index) : nullptr;
};
private:
/**
* The associative portion. These values are key'd with strings to an AMFValue.
*/
AMFAssociative associative;
/**
* The dense portion. These AMFValue's are stored one after
* another with the most recent addition being at the back.
*/
AMFDense dense;
};
#endif //!__AMF3__H__

View File

@@ -1,184 +0,0 @@
#include "AmfSerialize.h"
#include "Game.h"
#include "Logger.h"
// Writes an AMFValue pointer to a RakNet::BitStream
template<>
void RakNet::BitStream::Write<AMFBaseValue&>(AMFBaseValue& value) {
eAmf type = value.GetValueType();
this->Write(type);
switch (type) {
case eAmf::Integer: {
this->Write<AMFIntValue&>(*static_cast<AMFIntValue*>(&value));
break;
}
case eAmf::Double: {
this->Write<AMFDoubleValue&>(*static_cast<AMFDoubleValue*>(&value));
break;
}
case eAmf::String: {
this->Write<AMFStringValue&>(*static_cast<AMFStringValue*>(&value));
break;
}
case eAmf::Array: {
this->Write<AMFArrayValue&>(*static_cast<AMFArrayValue*>(&value));
break;
}
default: {
LOG("Encountered unwritable AMFType %i!", type);
}
case eAmf::Undefined:
case eAmf::Null:
case eAmf::False:
case eAmf::True:
case eAmf::Date:
case eAmf::Object:
case eAmf::XML:
case eAmf::XMLDoc:
case eAmf::ByteArray:
case eAmf::VectorInt:
case eAmf::VectorUInt:
case eAmf::VectorDouble:
case eAmf::VectorObject:
case eAmf::Dictionary:
break;
}
}
/**
* A private function to write an value to a RakNet::BitStream
* RakNet writes in the correct byte order - do not reverse this.
*/
void WriteUInt29(RakNet::BitStream* bs, uint32_t v) {
unsigned char b4 = static_cast<unsigned char>(v);
if (v < 0x00200000) {
b4 = b4 & 0x7F;
if (v > 0x7F) {
unsigned char b3;
v = v >> 7;
b3 = static_cast<unsigned char>(v) | 0x80;
if (v > 0x7F) {
unsigned char b2;
v = v >> 7;
b2 = static_cast<unsigned char>(v) | 0x80;
bs->Write(b2);
}
bs->Write(b3);
}
} else {
unsigned char b1;
unsigned char b2;
unsigned char b3;
v = v >> 8;
b3 = static_cast<unsigned char>(v) | 0x80;
v = v >> 7;
b2 = static_cast<unsigned char>(v) | 0x80;
v = v >> 7;
b1 = static_cast<unsigned char>(v) | 0x80;
bs->Write(b1);
bs->Write(b2);
bs->Write(b3);
}
bs->Write(b4);
}
/**
* Writes a flag number to a RakNet::BitStream
* RakNet writes in the correct byte order - do not reverse this.
*/
void WriteFlagNumber(RakNet::BitStream* bs, uint32_t v) {
v = (v << 1) | 0x01;
WriteUInt29(bs, v);
}
/**
* Writes an AMFString to a RakNet::BitStream
*
* RakNet writes in the correct byte order - do not reverse this.
*/
void WriteAMFString(RakNet::BitStream* bs, const std::string& str) {
WriteFlagNumber(bs, static_cast<uint32_t>(str.size()));
bs->Write(str.c_str(), static_cast<uint32_t>(str.size()));
}
/**
* Writes an U16 to a bitstream
*
* RakNet writes in the correct byte order - do not reverse this.
*/
void WriteAMFU16(RakNet::BitStream* bs, uint16_t value) {
bs->Write(value);
}
/**
* Writes an U32 to a bitstream
*
* RakNet writes in the correct byte order - do not reverse this.
*/
void WriteAMFU32(RakNet::BitStream* bs, uint32_t value) {
bs->Write(value);
}
/**
* Writes an U64 to a bitstream
*
* RakNet writes in the correct byte order - do not reverse this.
*/
void WriteAMFU64(RakNet::BitStream* bs, uint64_t value) {
bs->Write(value);
}
// Writes an AMFIntegerValue to BitStream
template<>
void RakNet::BitStream::Write<AMFIntValue&>(AMFIntValue& value) {
WriteUInt29(this, value.GetValue());
}
// Writes an AMFDoubleValue to BitStream
template<>
void RakNet::BitStream::Write<AMFDoubleValue&>(AMFDoubleValue& value) {
double d = value.GetValue();
WriteAMFU64(this, *reinterpret_cast<uint64_t*>(&d));
}
// Writes an AMFStringValue to BitStream
template<>
void RakNet::BitStream::Write<AMFStringValue&>(AMFStringValue& value) {
WriteAMFString(this, value.GetValue());
}
// Writes an AMFArrayValue to BitStream
template<>
void RakNet::BitStream::Write<AMFArrayValue&>(AMFArrayValue& value) {
uint32_t denseSize = value.GetDense().size();
WriteFlagNumber(this, denseSize);
auto it = value.GetAssociative().begin();
auto end = value.GetAssociative().end();
while (it != end) {
WriteAMFString(this, it->first);
this->Write<AMFBaseValue&>(*it->second);
it++;
}
this->Write(eAmf::Null);
if (denseSize > 0) {
auto it2 = value.GetDense().begin();
auto end2 = value.GetDense().end();
while (it2 != end2) {
this->Write<AMFBaseValue&>(**it2);
it2++;
}
}
}

View File

@@ -1,50 +0,0 @@
#pragma once
// Custom Classes
#include "Amf3.h"
// RakNet
#include "BitStream.h"
/*!
\file AmfSerialize.h
\brief A class that implements native writing of AMF values to RakNet::BitStream
*/
// We are using the RakNet namespace
namespace RakNet {
//! Writes an AMFValue pointer to a RakNet::BitStream
/*!
\param value The value to write
*/
template <>
void RakNet::BitStream::Write<AMFBaseValue&>(AMFBaseValue& value);
//! Writes an AMFIntegerValue to a RakNet::BitStream
/*!
\param value The value to write
*/
template <>
void RakNet::BitStream::Write<AMFIntValue&>(AMFIntValue& value);
//! Writes an AMFDoubleValue to a RakNet::BitStream
/*!
\param value The value to write
*/
template <>
void RakNet::BitStream::Write<AMFDoubleValue&>(AMFDoubleValue& value);
//! Writes an AMFStringValue to a RakNet::BitStream
/*!
\param value The value to write
*/
template <>
void RakNet::BitStream::Write<AMFStringValue&>(AMFStringValue& value);
//! Writes an AMFArrayValue to a RakNet::BitStream
/*!
\param value The value to write
*/
template <>
void RakNet::BitStream::Write<AMFArrayValue&>(AMFArrayValue& value);
} // namespace RakNet

View File

@@ -1,6 +1,14 @@
#include "BinaryIO.h"
#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
std::string BinaryIO::ReadString(std::istream& instream) {
std::string toReturn;
@@ -15,3 +23,36 @@ std::string BinaryIO::ReadString(std::istream& instream) {
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;
}

View File

@@ -1,17 +1,8 @@
#pragma once
#ifndef __BINARYIO__H__
#define __BINARYIO__H__
#include <iostream>
#include <fstream>
#include <string>
#include "Game.h"
#include "Logger.h"
namespace BinaryIO {
template<typename T>
std::ostream& BinaryWrite(std::ostream& stream, const T& value) {
return stream.write(reinterpret_cast<const char*>(&value), sizeof(T));
@@ -24,51 +15,13 @@ namespace BinaryIO {
return stream.read(reinterpret_cast<char*>(&value), sizeof(T));
}
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);
}
}
void WriteString(const std::string& stringToWrite, std::ofstream& outstream);
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) {
std::ifstream f(name.c_str());
return f.good();
}
}
#endif //!__BINARYIO__H__

View File

@@ -1,11 +0,0 @@
#ifndef __BRICK__H__
#define __BRICK__H__
#include <cstdint>
struct Brick {
uint32_t designerID;
uint32_t materialID;
};
#endif //!__BRICK__H__

View File

@@ -9,12 +9,13 @@
#include "Database.h"
#include "Game.h"
#include "ZCompression.h"
#include "Logger.h"
#include "dLogger.h"
//! Forward declarations
std::unique_ptr<sql::ResultSet> GetModelsFromDatabase();
void WriteSd0Magic(char* input, uint32_t chunkSize);
bool CheckSd0Magic(std::istream& streamToCheck);
bool CheckSd0Magic(sql::Blob* streamToCheck);
/**
* @brief Truncates all models with broken data from the database.
@@ -23,24 +24,28 @@ bool CheckSd0Magic(std::istream& streamToCheck);
*/
uint32_t BrickByBrickFix::TruncateBrokenBrickByBrickXml() {
uint32_t modelsTruncated{};
auto modelsToTruncate = Database::Get()->GetAllUgcModels();
bool previousCommitValue = Database::Get()->GetAutoCommit();
Database::Get()->SetAutoCommit(false);
for (auto& model : modelsToTruncate) {
auto modelsToTruncate = GetModelsFromDatabase();
bool previousCommitValue = Database::GetAutoCommit();
Database::SetAutoCommit(false);
while (modelsToTruncate->next()) {
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{};
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.
if (CheckSd0Magic(model.lxfmlData)) {
if (CheckSd0Magic(modelAsSd0.get())) {
while (true) {
uint32_t chunkSize{};
model.lxfmlData.read(reinterpret_cast<char*>(&chunkSize), sizeof(uint32_t)); // Extract chunk size from istream
modelAsSd0->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.
if (!model.lxfmlData.good()) break;
if (!modelAsSd0->good()) break;
std::unique_ptr<uint8_t[]> compressedChunk(new uint8_t[chunkSize]);
for (uint32_t i = 0; i < chunkSize; i++) {
compressedChunk[i] = model.lxfmlData.get();
compressedChunk[i] = modelAsSd0->get();
}
// Ignore the valgrind warning about uninitialized values. These are discarded later when we know the actual uncompressed size.
@@ -51,17 +56,17 @@ uint32_t BrickByBrickFix::TruncateBrokenBrickByBrickXml() {
if (actualUncompressedSize != -1) {
uint32_t previousSize = completeUncompressedModel.size();
completeUncompressedModel.append(reinterpret_cast<char*>(uncompressedChunk.get()));
completeUncompressedModel.append((char*)uncompressedChunk.get());
completeUncompressedModel.resize(previousSize + actualUncompressedSize);
} else {
LOG("Failed to inflate chunk %i for model %llu. Error: %i", chunkCount, model.id, err);
Game::logger->Log("BrickByBrickFix", "Failed to inflate chunk %i for model %llu. Error: %i", chunkCount, modelId, err);
break;
}
chunkCount++;
}
std::unique_ptr<tinyxml2::XMLDocument> document = std::make_unique<tinyxml2::XMLDocument>();
if (!document) {
LOG("Failed to initialize tinyxml document. Aborting.");
Game::logger->Log("BrickByBrickFix", "Failed to initialize tinyxml document. Aborting.");
return 0;
}
@@ -70,20 +75,28 @@ uint32_t BrickByBrickFix::TruncateBrokenBrickByBrickXml() {
"</LXFML>",
completeUncompressedModel.length() >= 15 ? completeUncompressedModel.length() - 15 : 0) == std::string::npos
) {
LOG("Brick-by-brick model %llu will be deleted!", model.id);
Database::Get()->DeleteUgcModelData(model.id);
Game::logger->Log("BrickByBrickFix",
"Brick-by-brick model %llu will be deleted!", modelId);
ugcModelToDelete->setInt64(1, modelsToTruncate->getInt64(1));
pcModelToDelete->setInt64(1, modelsToTruncate->getInt64(1));
ugcModelToDelete->execute();
pcModelToDelete->execute();
modelsTruncated++;
}
}
} else {
LOG("Brick-by-brick model %llu will be deleted!", model.id);
Database::Get()->DeleteUgcModelData(model.id);
Game::logger->Log("BrickByBrickFix",
"Brick-by-brick model %llu will be deleted!", modelId);
ugcModelToDelete->setInt64(1, modelsToTruncate->getInt64(1));
pcModelToDelete->setInt64(1, modelsToTruncate->getInt64(1));
ugcModelToDelete->execute();
pcModelToDelete->execute();
modelsTruncated++;
}
}
Database::Get()->Commit();
Database::Get()->SetAutoCommit(previousCommitValue);
Database::Commit();
Database::SetAutoCommit(previousCommitValue);
return modelsTruncated;
}
@@ -95,17 +108,21 @@ uint32_t BrickByBrickFix::TruncateBrokenBrickByBrickXml() {
*/
uint32_t BrickByBrickFix::UpdateBrickByBrickModelsToSd0() {
uint32_t updatedModels = 0;
auto modelsToUpdate = Database::Get()->GetAllUgcModels();
auto previousAutoCommitState = Database::Get()->GetAutoCommit();
Database::Get()->SetAutoCommit(false);
for (auto& model : modelsToUpdate) {
auto modelsToUpdate = GetModelsFromDatabase();
auto previousAutoCommitState = Database::GetAutoCommit();
Database::SetAutoCommit(false);
std::unique_ptr<sql::PreparedStatement> insertionStatement(Database::CreatePreppedStmt("UPDATE ugc SET lxfml = ? WHERE id = ?;"));
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)
// If it does, convert it to sd0.
if (model.lxfmlData.get() == 0x78 && model.lxfmlData.get() == 0xDA) {
if (oldLxfml->get() == 0x78 && oldLxfml->get() == 0xDA) {
// Get and save size of zlib compressed chunk.
model.lxfmlData.seekg(0, std::ios::end);
uint32_t oldLxfmlSize = static_cast<uint32_t>(model.lxfmlData.tellg());
model.lxfmlData.seekg(0);
oldLxfml->seekg(0, std::ios::end);
uint32_t oldLxfmlSize = static_cast<uint32_t>(oldLxfml->tellg());
oldLxfml->seekg(0);
// Allocate 9 extra bytes. 5 for sd0 magic, 4 for the only zlib compressed size.
uint32_t oldLxfmlSizeWithHeader = oldLxfmlSize + 9;
@@ -113,27 +130,36 @@ uint32_t BrickByBrickFix::UpdateBrickByBrickModelsToSd0() {
WriteSd0Magic(sd0ConvertedModel.get(), oldLxfmlSize);
for (uint32_t i = 9; i < oldLxfmlSizeWithHeader; i++) {
sd0ConvertedModel.get()[i] = model.lxfmlData.get();
sd0ConvertedModel.get()[i] = oldLxfml->get();
}
std::string outputString(sd0ConvertedModel.get(), oldLxfmlSizeWithHeader);
std::istringstream outputStringStream(outputString);
insertionStatement->setBlob(1, static_cast<std::istream*>(&outputStringStream));
insertionStatement->setInt64(2, modelId);
try {
Database::Get()->UpdateUgcModelData(model.id, outputStringStream);
LOG("Updated model %i to sd0", model.id);
insertionStatement->executeUpdate();
Game::logger->Log("BrickByBrickFix", "Updated model %i to sd0", modelId);
updatedModels++;
} catch (sql::SQLException exception) {
LOG("Failed to update model %i. This model should be inspected manually to see why."
"The database error is %s", model.id, exception.what());
Game::logger->Log(
"BrickByBrickFix",
"Failed to update model %i. This model should be inspected manually to see why."
"The database error is %s", modelId, exception.what());
}
}
}
Database::Get()->Commit();
Database::Get()->SetAutoCommit(previousAutoCommitState);
Database::Commit();
Database::SetAutoCommit(previousAutoCommitState);
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*
*
@@ -149,6 +175,6 @@ void WriteSd0Magic(char* input, uint32_t chunkSize) {
*reinterpret_cast<uint32_t*>(input + 5) = chunkSize; // Write the integer to the character array
}
bool CheckSd0Magic(std::istream& streamToCheck) {
return streamToCheck.get() == 's' && streamToCheck.get() == 'd' && streamToCheck.get() == '0' && streamToCheck.get() == 0x01 && streamToCheck.get() == 0xFF;
bool CheckSd0Magic(sql::Blob* streamToCheck) {
return streamToCheck->get() == 's' && streamToCheck->get() == 'd' && streamToCheck->get() == '0' && streamToCheck->get() == 0x01 && streamToCheck->get() == 0xFF;
}

View File

@@ -1,11 +1,10 @@
set(DCOMMON_SOURCES
set(DCOMMON_SOURCES "AMFFormat.cpp"
"AMFDeserialize.cpp"
"AmfSerialize.cpp"
"AMFFormat_BitStream.cpp"
"BinaryIO.cpp"
"dConfig.cpp"
"Diagnostics.cpp"
"Logger.cpp"
"Game.cpp"
"dLogger.cpp"
"GeneralUtils.cpp"
"LDFFormat.cpp"
"MD5.cpp"
@@ -13,19 +12,13 @@ set(DCOMMON_SOURCES
"NiPoint3.cpp"
"NiQuaternion.cpp"
"SHA512.cpp"
"Demangler.cpp"
"Type.cpp"
"ZCompression.cpp"
"BrickByBrickFix.cpp"
"BinaryPathFinder.cpp"
"FdbToSqlite.cpp"
)
# Workaround for compiler bug where the optimized code could result in a memcpy of 0 bytes, even though that isnt possible.
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97185
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set_source_files_properties("FdbToSqlite.cpp" PROPERTIES COMPILE_FLAGS "-Wno-stringop-overflow")
endif()
add_subdirectory(dClient)
foreach(file ${DCOMMON_DCLIENT_SOURCES})
@@ -68,8 +61,3 @@ else ()
endif ()
target_link_libraries(dCommon ZLIB::ZLIB)
# Disable deprecation warnings on MD5.cpp and SHA512.cpp for Apple Clang
if (APPLE)
set_source_files_properties("MD5.cpp" "SHA512.cpp" PROPERTIES COMPILE_FLAGS "-Wno-deprecated-declarations")
endif()

View File

@@ -1,29 +0,0 @@
#include "Demangler.h"
#ifdef __GNUG__
#include <cstdlib>
#include <cxxabi.h>
#include <memory>
#include <typeinfo>
std::string Demangler::Demangle(const char* name) {
// some arbitrary value to eliminate the compiler warning
// -4 is not a valid return value for __cxa_demangle so we'll use that.
int status = -4;
// __cxa_demangle requires that we free the returned char*
std::unique_ptr<char, void (*)(void*)> res{
abi::__cxa_demangle(name, NULL, NULL, &status),
std::free
};
return (status == 0) ? res.get() : "";
}
#else // __GNUG__
// does nothing if not g++
std::string Demangler::Demangle(const char* name) {
return name;
}
#endif // __GNUG__

View File

@@ -1,9 +0,0 @@
#pragma once
#include <string>
namespace Demangler {
// Given a char* containing a mangled name, return a std::string containing the demangled name.
// If the function fails for any reason, it returns an empty string.
std::string Demangle(const char* name);
}

View File

@@ -1,6 +1,6 @@
#include "Diagnostics.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
// If we're on Win32, we'll include our minidump writer
#ifdef _WIN32
@@ -9,7 +9,7 @@
#include <Dbghelp.h>
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
void make_minidump(EXCEPTION_POINTERS* e) {
auto hDbgHelp = LoadLibraryA("dbghelp");
@@ -28,7 +28,7 @@ void make_minidump(EXCEPTION_POINTERS* e) {
"_%4d%02d%02d_%02d%02d%02d.dmp",
t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond);
}
LOG("Creating crash dump %s", name);
Game::logger->Log("Diagnostics", "Creating crash dump %s", name);
auto hFile = CreateFileA(name, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if (hFile == INVALID_HANDLE_VALUE)
return;
@@ -71,7 +71,7 @@ LONG CALLBACK unhandled_handler(EXCEPTION_POINTERS* e) {
#include <cstring>
#include <exception>
#if defined(INCLUDE_BACKTRACE)
#if defined(__include_backtrace__)
#include <backtrace.h>
#include <backtrace-supported.h>
@@ -83,7 +83,7 @@ struct bt_ctx {
static inline void Bt(struct backtrace_state* state) {
std::string fileName = Diagnostics::GetOutDirectory() + "crash_" + Diagnostics::GetProcessName() + "_" + std::to_string(getpid()) + ".log";
LOG("backtrace is enabled, crash dump located at %s", fileName.c_str());
Game::logger->Log("Diagnostics", "backtrace is enabled, crash dump located at %s", fileName.c_str());
FILE* file = fopen(fileName.c_str(), "w+");
if (file != nullptr) {
backtrace_print(state, 2, file);
@@ -107,74 +107,66 @@ static void ErrorCallback(void* data, const char* msg, int errnum) {
}
#endif
#include "Demangler.h"
#include "Type.h"
void GenerateDump() {
std::string cmd = "sudo gcore " + std::to_string(getpid());
int ret = system(cmd.c_str()); // Saving a return just to prevent warning
system(cmd.c_str());
}
void CatchUnhandled(int sig) {
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
#ifndef __include_backtrace__
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());
Game::logger->Log("Diagnostics", "Encountered signal %i, creating crash dump %s", sig, fileName.c_str());
if (Diagnostics::GetProduceMemoryDump()) {
GenerateDump();
}
constexpr uint8_t MaxStackTrace = 32;
void* array[MaxStackTrace];
void* array[10];
size_t size;
// get void*'s for all entries on the stack
size = backtrace(array, MaxStackTrace);
size = backtrace(array, 10);
# if defined(__GNUG__)
#if defined(__GNUG__) and defined(__dynamic)
// Loop through the returned addresses, and get the symbols to be demangled
char** strings = backtrace_symbols(array, size);
FILE* file = fopen(fileName.c_str(), "w+");
if (file != NULL) {
fprintf(file, "Error: signal %d:\n", sig);
}
// Print the stack trace
for (size_t i = 0; i < size; i++) {
// Take a string like './WorldServer(_ZN19SlashCommandHandler17HandleChatCommandERKSbIDsSt11char_traitsIDsESaIDsEEP6EntityRK13SystemAddress+0x6187) [0x55869c44ecf7]'
// and extract '_ZN19SlashCommandHandler17HandleChatCommandERKSbIDsSt11char_traitsIDsESaIDsEEP6EntityRK13SystemAddress' from it to be demangled into a proper name
// Take a string like './WorldServer(_ZN19SlashCommandHandler17HandleChatCommandERKSbIDsSt11char_traitsIDsESaIDsEEP6EntityRK13SystemAddress+0x6187) [0x55869c44ecf7]' and extract the function name
std::string functionName = strings[i];
std::string::size_type start = functionName.find('(');
std::string::size_type end = functionName.find('+');
if (start != std::string::npos && end != std::string::npos) {
std::string demangled = functionName.substr(start + 1, end - start - 1);
demangled = Demangler::Demangle(demangled.c_str());
demangled = demangle(functionName.c_str());
// If the demangled string is not empty, then we can replace the mangled string with the demangled one
if (!demangled.empty()) {
demangled.push_back('(');
demangled += functionName.substr(end);
functionName = demangled;
if (demangled.empty()) {
Game::logger->Log("Diagnostics", "[%02zu] %s", i, demangled.c_str());
} else {
Game::logger->Log("Diagnostics", "[%02zu] %s", i, functionName.c_str());
}
}
LOG("[%02zu] %s", i, functionName.c_str());
if (file != NULL) {
fprintf(file, "[%02zu] %s\n", i, functionName.c_str());
} else {
Game::logger->Log("Diagnostics", "[%02zu] %s", i, functionName.c_str());
}
}
# else // defined(__GNUG__)
#else
backtrace_symbols_fd(array, size, STDOUT_FILENO);
# endif // defined(__GNUG__)
#endif
#else // INCLUDE_BACKTRACE
FILE* file = fopen(fileName.c_str(), "w+");
if (file != NULL) {
// print out all the frames to stderr
fprintf(file, "Error: signal %d:\n", sig);
backtrace_symbols_fd(array, size, fileno(file));
fclose(file);
}
#else
struct backtrace_state* state = backtrace_create_state(
Diagnostics::GetProcessFileName().c_str(),
@@ -185,7 +177,7 @@ void CatchUnhandled(int sig) {
struct bt_ctx ctx = { state, 0 };
Bt(state);
#endif // INCLUDE_BACKTRACE
#endif
exit(EXIT_FAILURE);
}
@@ -204,10 +196,10 @@ void MakeBacktrace() {
sigact.sa_sigaction = CritErrHdlr;
sigact.sa_flags = SA_RESTART | SA_SIGINFO;
if (sigaction(SIGSEGV, &sigact, nullptr) != 0 ||
sigaction(SIGFPE, &sigact, nullptr) != 0 ||
sigaction(SIGABRT, &sigact, nullptr) != 0 ||
sigaction(SIGILL, &sigact, nullptr) != 0) {
if (sigaction(SIGSEGV, &sigact, (struct sigaction*)nullptr) != 0 ||
sigaction(SIGFPE, &sigact, (struct sigaction*)nullptr) != 0 ||
sigaction(SIGABRT, &sigact, (struct sigaction*)nullptr) != 0 ||
sigaction(SIGILL, &sigact, (struct sigaction*)nullptr) != 0) {
fprintf(stderr, "error setting signal handler for %d (%s)\n",
SIGSEGV,
strsignal(SIGSEGV));

View File

@@ -1,12 +0,0 @@
#ifndef __DLUASSERT__H__
#define __DLUASSERT__H__
#include <assert.h>
#ifdef _DEBUG
# define DluAssert(expression) assert(expression)
#else
# define DluAssert(expression)
#endif
#endif //!__DLUASSERT__H__

View File

@@ -9,7 +9,7 @@
#include "CDClientDatabase.h"
#include "GeneralUtils.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
#include "AssetManager.h"
#include "eSqliteDataType.h"
@@ -28,21 +28,23 @@ FdbToSqlite::Convert::Convert(std::string binaryOutPath) {
this->m_BinaryOutPath = binaryOutPath;
}
bool FdbToSqlite::Convert::ConvertDatabase(AssetStream& buffer) {
bool FdbToSqlite::Convert::ConvertDatabase(AssetMemoryBuffer& buffer) {
if (m_ConversionStarted) return false;
std::istream cdClientBuffer(&buffer);
this->m_ConversionStarted = true;
try {
CDClientDatabase::Connect(m_BinaryOutPath + "/CDServer.sqlite");
CDClientDatabase::ExecuteQuery("BEGIN TRANSACTION;");
int32_t numberOfTables = ReadInt32(buffer);
ReadTables(numberOfTables, buffer);
int32_t numberOfTables = ReadInt32(cdClientBuffer);
ReadTables(numberOfTables, cdClientBuffer);
CDClientDatabase::ExecuteQuery("COMMIT;");
} catch (CppSQLite3Exception& e) {
LOG("Encountered error %s converting FDB to SQLite", e.errorMessage());
Game::logger->Log("FdbToSqlite", "Encountered error %s converting FDB to SQLite", e.errorMessage());
return false;
}

View File

@@ -7,7 +7,7 @@
#include <iosfwd>
#include <map>
#include "AssetManager.h"
class AssetMemoryBuffer;
enum class eSqliteDataType : int32_t;
@@ -27,7 +27,7 @@ namespace FdbToSqlite {
*
* @return true if the database was converted properly, false otherwise.
*/
bool ConvertDatabase(AssetStream& buffer);
bool ConvertDatabase(AssetMemoryBuffer& buffer);
/**
* @brief Reads a 32 bit int from the fdb file.

View File

@@ -1,7 +0,0 @@
#include "Game.h"
namespace Game {
void OnSignal(int signal) {
lastSignal = signal;
}
}

View File

@@ -1,24 +1,18 @@
#pragma once
#include <string>
#include <random>
#include <csignal>
class dServer;
class Logger;
class dLogger;
class InstanceManager;
class dChatFilter;
class dConfig;
class RakPeerInterface;
class AssetManager;
struct SystemAddress;
class EntityManager;
class dZoneManager;
class PlayerContainer;
namespace Game {
using signal_t = volatile std::sig_atomic_t;
extern Logger* logger;
extern dLogger* logger;
extern dServer* server;
extern InstanceManager* im;
extern dChatFilter* chatFilter;
@@ -27,14 +21,5 @@ namespace Game {
extern RakPeerInterface* chatServer;
extern AssetManager* assetManager;
extern SystemAddress chatSysAddr;
extern signal_t lastSignal;
extern EntityManager* entityManager;
extern dZoneManager* zoneManager;
extern PlayerContainer playerContainer;
extern std::string projectVersion;
inline bool ShouldShutdown() {
return lastSignal != 0;
}
void OnSignal(int signal);
extern bool shouldShutdown;
}

View File

@@ -53,7 +53,7 @@ bool _IsSuffixChar(uint8_t c) {
bool GeneralUtils::_NextUTF8Char(std::string_view& slice, uint32_t& out) {
size_t rem = slice.length();
if (slice.empty()) return false;
const uint8_t* bytes = reinterpret_cast<const uint8_t*>(&slice.front());
const uint8_t* bytes = (const uint8_t*)&slice.front();
if (rem > 0) {
uint8_t first = bytes[0];
if (first < 0x80) { // 1 byte character
@@ -241,7 +241,7 @@ std::vector<std::wstring> GeneralUtils::SplitString(std::wstring& str, wchar_t d
return vector;
}
std::vector<std::u16string> GeneralUtils::SplitString(const std::u16string& str, char16_t delimiter) {
std::vector<std::u16string> GeneralUtils::SplitString(std::u16string& str, char16_t delimiter) {
std::vector<std::u16string> vector = std::vector<std::u16string>();
std::u16string current;
@@ -319,7 +319,3 @@ std::vector<std::string> GeneralUtils::GetSqlFileNamesFromFolder(const std::stri
return sortedFiles;
}
bool GeneralUtils::TryParse(const std::string& x, const std::string& y, const std::string& z, NiPoint3& dst) {
return TryParse<float>(x.c_str(), dst.x) && TryParse<float>(y.c_str(), dst.y) && TryParse<float>(z.c_str(), dst.z);
}

View File

@@ -9,15 +9,12 @@
#include <functional>
#include <type_traits>
#include <stdexcept>
#include "BitStream.h"
#include "NiPoint3.h"
#include <BitStream.h>
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
enum eInventoryType : uint32_t;
enum class eObjectBits : size_t;
enum class eReplicaComponentType : uint32_t;
/*!
\file GeneralUtils.hpp
@@ -67,9 +64,9 @@ namespace GeneralUtils {
//! Sets a bit on a numerical value
template <typename T>
inline void SetBit(T& value, eObjectBits bits) {
void SetBit(T& value, size_t index) {
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
auto index = static_cast<size_t>(bits);
if (index > (sizeof(T) * 8) - 1) {
return;
}
@@ -79,9 +76,9 @@ namespace GeneralUtils {
//! Clears a bit on a numerical value
template <typename T>
inline void ClearBit(T& value, eObjectBits bits) {
void ClearBit(T& value, size_t index) {
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
auto index = static_cast<size_t>(bits);
if (index > (sizeof(T) * 8 - 1)) {
return;
}
@@ -111,106 +108,6 @@ namespace GeneralUtils {
*/
bool CheckBit(int64_t value, uint32_t index);
bool ReplaceInString(std::string& str, const std::string& from, const std::string& to);
std::u16string ReadWString(RakNet::BitStream* inStream);
std::vector<std::wstring> SplitString(std::wstring& str, wchar_t delimiter);
std::vector<std::u16string> SplitString(const std::u16string& str, char16_t delimiter);
std::vector<std::string> SplitString(const std::string& str, char delimiter);
std::vector<std::string> GetSqlFileNamesFromFolder(const std::string& folder);
template <typename T>
T Parse(const char* value);
template <>
inline bool Parse(const char* value) {
return std::stoi(value);
}
template <>
inline int32_t Parse(const char* value) {
return std::stoi(value);
}
template <>
inline int64_t Parse(const char* value) {
return std::stoll(value);
}
template <>
inline float Parse(const char* value) {
return std::stof(value);
}
template <>
inline double Parse(const char* value) {
return std::stod(value);
}
template <>
inline uint16_t Parse(const char* value) {
return std::stoul(value);
}
template <>
inline uint32_t Parse(const char* value) {
return std::stoul(value);
}
template <>
inline uint64_t Parse(const char* value) {
return std::stoull(value);
}
template <>
inline eInventoryType Parse(const char* value) {
return static_cast<eInventoryType>(std::stoul(value));
}
template <>
inline eReplicaComponentType Parse(const char* value) {
return static_cast<eReplicaComponentType>(std::stoul(value));
}
template <typename T>
bool TryParse(const char* value, T& dst) {
try {
dst = Parse<T>(value);
return true;
} catch (...) {
return false;
}
}
template <typename T>
T Parse(const std::string& value) {
return Parse<T>(value.c_str());
}
template <typename T>
bool TryParse(const std::string& value, T& dst) {
return TryParse<T>(value.c_str(), dst);
}
bool TryParse(const std::string& x, const std::string& y, const std::string& z, NiPoint3& dst);
template<typename T>
std::u16string to_u16string(T value) {
return GeneralUtils::ASCIIToUTF16(std::to_string(value));
}
// From boost::hash_combine
template <class T>
void hash_combine(std::size_t& s, const T& v) {
std::hash<T> h;
s ^= h(v) + 0x9e3779b9 + (s << 6) + (s >> 2);
}
// MARK: Random Number Generation
//! Generates a random number
@@ -234,30 +131,86 @@ namespace GeneralUtils {
return T();
}
/**
* Casts the value of an enum entry to its underlying type
* @param entry Enum entry to cast
* @returns The enum entry's value in its underlying type
*/
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");
bool ReplaceInString(std::string& str, const std::string& from, const std::string& to);
return static_cast<typename std::underlying_type_t<eType>>(entry);
}
std::u16string ReadWString(RakNet::BitStream* inStream);
// 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
std::vector<std::wstring> SplitString(std::wstring& str, wchar_t delimiter);
std::vector<std::u16string> SplitString(std::u16string& str, char16_t delimiter);
std::vector<std::string> SplitString(const std::string& str, char delimiter);
std::vector<std::string> GetSqlFileNamesFromFolder(const std::string& folder);
template <typename T>
inline T GenerateRandomNumber() {
// Make sure it is a numeric type
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
T Parse(const char* value);
return GenerateRandomNumber<T>(std::numeric_limits<T>::min(), std::numeric_limits<T>::max());
template <>
inline int32_t Parse(const char* value) {
return std::stoi(value);
}
template <>
inline int64_t Parse(const char* value) {
return std::stoll(value);
}
template <>
inline float Parse(const char* value) {
return std::stof(value);
}
template <>
inline double Parse(const char* value) {
return std::stod(value);
}
template <>
inline uint32_t Parse(const char* value) {
return std::stoul(value);
}
template <>
inline uint64_t Parse(const char* value) {
return std::stoull(value);
}
template <>
inline eInventoryType Parse(const char* value) {
return static_cast<eInventoryType>(std::stoul(value));
}
template <typename T>
bool TryParse(const char* value, T& dst) {
try {
dst = Parse<T>(value);
return true;
} catch (...) {
return false;
}
}
template <typename T>
T Parse(const std::string& value) {
return Parse<T>(value.c_str());
}
template <typename T>
bool TryParse(const std::string& value, T& dst) {
return TryParse<T>(value.c_str(), dst);
}
template<typename T>
std::u16string to_u16string(T value) {
return GeneralUtils::ASCIIToUTF16(std::to_string(value));
}
// From boost::hash_combine
template <class T>
void hash_combine(std::size_t& s, const T& v) {
std::hash<T> h;
s ^= h(v) + 0x9e3779b9 + (s << 6) + (s >> 2);
}
}

View File

@@ -3,166 +3,122 @@
// Custom Classes
#include "GeneralUtils.h"
#include "Game.h"
#include "Logger.h"
// C++
#include <string_view>
#include <sstream>
#include <vector>
using LDFKey = std::string_view;
using LDFTypeAndValue = std::string_view;
using LDFType = std::string_view;
using LDFValue = std::string_view;
//! Returns a pointer to a LDFData value based on string format
LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
// A valid LDF must be at least 3 characters long (=0:) is the shortest valid LDF (empty UTF-16 key with no initial value)
if (format.empty() || format.length() <= 2) return nullptr;
auto equalsPosition = format.find('=');
// You can have an empty key, just make sure the type and value might exist
if (equalsPosition == std::string::npos || equalsPosition == (format.size() - 1)) return nullptr;
LDFBaseData* LDFBaseData::DataFromString(const std::string& format) {
std::pair<LDFKey, LDFTypeAndValue> keyValue;
keyValue.first = format.substr(0, equalsPosition);
keyValue.second = format.substr(equalsPosition + 1, format.size());
// First, check the format
std::istringstream ssFormat(format);
std::string token;
std::u16string key = GeneralUtils::ASCIIToUTF16(keyValue.first);
auto colonPosition = keyValue.second.find(':');
// If : is the first thing after an =, then this is an invalid LDF since
// we dont have a type to use.
if (colonPosition == std::string::npos || colonPosition == 0) return nullptr;
std::pair<LDFType, LDFValue> ldfTypeAndValue;
ldfTypeAndValue.first = keyValue.second.substr(0, colonPosition);
ldfTypeAndValue.second = keyValue.second.substr(colonPosition + 1, keyValue.second.size());
// Only allow empty values for string values.
if (ldfTypeAndValue.second.size() == 0 && !(ldfTypeAndValue.first == "0" || ldfTypeAndValue.first == "13")) return nullptr;
eLDFType type;
char* storage;
try {
type = static_cast<eLDFType>(strtol(ldfTypeAndValue.first.data(), &storage, 10));
} catch (std::exception) {
LOG("Attempted to process invalid ldf type (%s) from string (%s)", ldfTypeAndValue.first.data(), format.data());
return nullptr;
std::vector<std::string> keyValueArray;
while (std::getline(ssFormat, token, '=')) {
keyValueArray.push_back(token);
}
LDFBaseData* returnValue = nullptr;
switch (type) {
case LDF_TYPE_UTF_16: {
std::u16string data = GeneralUtils::UTF8ToUTF16(ldfTypeAndValue.second);
returnValue = new LDFData<std::u16string>(key, data);
break;
}
if (keyValueArray.size() == 2) {
std::u16string key = GeneralUtils::ASCIIToUTF16(keyValueArray[0]);
case LDF_TYPE_S32: {
int32_t data;
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
LOG("Warning: Attempted to process invalid int32 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr;
std::vector<std::string> dataArray;
std::istringstream ssData(keyValueArray[1]);
while (std::getline(ssData, token, ':')) {
dataArray.push_back(token);
}
returnValue = new LDFData<int32_t>(key, data);
break;
}
case LDF_TYPE_FLOAT: {
float data;
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
LOG("Warning: Attempted to process invalid float value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr;
if (dataArray.size() > 2) { // hacky fix for strings with colons in them
std::vector<std::string> newDataArray;
newDataArray.push_back(dataArray[0]);
std::string value = "";
for (size_t i = 1; i < dataArray.size(); ++i) {
value += dataArray[i] + ':';
}
value.pop_back(); // remove last colon
newDataArray.push_back(value);
dataArray = newDataArray;
}
returnValue = new LDFData<float>(key, data);
break;
}
case LDF_TYPE_DOUBLE: {
double data;
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
LOG("Warning: Attempted to process invalid double value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr;
if ((dataArray[0] == "0" || dataArray[0] == "13") && dataArray.size() == 1) {
dataArray.push_back("");
}
returnValue = new LDFData<double>(key, data);
break;
}
case LDF_TYPE_U32:
{
uint32_t data;
if (dataArray.size() == 2) {
eLDFType type = static_cast<eLDFType>(stoi(dataArray[0]));
if (ldfTypeAndValue.second == "true") {
data = 1;
} else if (ldfTypeAndValue.second == "false") {
data = 0;
} else {
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
LOG("Warning: Attempted to process invalid uint32 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
switch (type) {
case LDF_TYPE_UTF_16: {
std::u16string data = GeneralUtils::UTF8ToUTF16(dataArray[1]);
return new LDFData<std::u16string>(key, data);
}
case LDF_TYPE_S32: {
int32_t data = static_cast<int32_t>(stoull(dataArray[1]));
return new LDFData<int32_t>(key, data);
}
case LDF_TYPE_FLOAT: {
float data = static_cast<float>(stof(dataArray[1]));
return new LDFData<float>(key, data);
}
case LDF_TYPE_DOUBLE: {
double data = static_cast<float>(stod(dataArray[1]));
return new LDFData<double>(key, data);
}
case LDF_TYPE_U32:
{
uint32_t data;
if (dataArray[1] == "true") {
data = 1;
} else if (dataArray[1] == "false") {
data = 0;
} else {
data = static_cast<uint32_t>(stoul(dataArray[1]));
}
return new LDFData<uint32_t>(key, data);
}
case LDF_TYPE_BOOLEAN: {
bool data;
if (dataArray[1] == "true") {
data = true;
} else if (dataArray[1] == "false") {
data = false;
} else {
data = static_cast<bool>(stoi(dataArray[1]));
}
return new LDFData<bool>(key, data);
}
case LDF_TYPE_U64: {
uint64_t data = static_cast<uint64_t>(stoull(dataArray[1]));
return new LDFData<uint64_t>(key, data);
}
case LDF_TYPE_OBJID: {
LWOOBJID data = static_cast<LWOOBJID>(stoll(dataArray[1]));
return new LDFData<LWOOBJID>(key, data);
}
case LDF_TYPE_UTF_8: {
std::string data = dataArray[1];
return new LDFData<std::string>(key, data);
}
case LDF_TYPE_UNKNOWN: {
return nullptr;
}
}
returnValue = new LDFData<uint32_t>(key, data);
break;
}
case LDF_TYPE_BOOLEAN: {
bool data;
if (ldfTypeAndValue.second == "true") {
data = true;
} else if (ldfTypeAndValue.second == "false") {
data = false;
} else {
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
LOG("Warning: Attempted to process invalid bool value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr;
}
}
returnValue = new LDFData<bool>(key, data);
break;
}
case LDF_TYPE_U64: {
uint64_t data;
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
LOG("Warning: Attempted to process invalid uint64 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr;
}
returnValue = new LDFData<uint64_t>(key, data);
break;
}
return nullptr;
case LDF_TYPE_OBJID: {
LWOOBJID data;
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
LOG("Warning: Attempted to process invalid LWOOBJID value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr;
}
returnValue = new LDFData<LWOOBJID>(key, data);
break;
}
case LDF_TYPE_UTF_8: {
std::string data = ldfTypeAndValue.second.data();
returnValue = new LDFData<std::string>(key, data);
break;
}
case LDF_TYPE_UNKNOWN: {
LOG("Warning: Attempted to process invalid unknown value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
break;
}
default: {
LOG("Warning: Attempted to process invalid LDF type (%d) from string (%s)", type, format.data());
break;
}
}
return returnValue;
}

View File

@@ -1,5 +1,4 @@
#ifndef __LDFFORMAT__H__
#define __LDFFORMAT__H__
#pragma once
// Custom Classes
#include "dCommonVars.h"
@@ -7,12 +6,18 @@
// C++
#include <string>
#include <string_view>
#include <sstream>
// RakNet
#include "BitStream.h"
#include "../thirdparty/raknet/Source/BitStream.h"
/*!
\file LDFFormat.hpp
\brief A collection of LDF format classes
*/
//! An enum for LDF Data Types
enum eLDFType {
LDF_TYPE_UNKNOWN = -1, //!< Unknown data type
LDF_TYPE_UTF_16 = 0, //!< UTF-16 wstring data type
@@ -26,21 +31,36 @@ enum eLDFType {
LDF_TYPE_UTF_8 = 13, //!< UTF-8 string data type
};
//! A base class for the LDF data
class LDFBaseData {
public:
virtual ~LDFBaseData() {}
//! Destructor
virtual ~LDFBaseData(void) {}
//! Writes the data to a packet
/*!
\param packet The packet
*/
virtual void WriteToPacket(RakNet::BitStream* packet) = 0;
virtual const std::u16string& GetKey() = 0;
//! Gets the key
/*!
\return The key
*/
virtual const std::u16string& GetKey(void) = 0;
virtual eLDFType GetValueType() = 0;
//! Gets the value type
/*!
\return The value type
*/
virtual eLDFType GetValueType(void) = 0;
/** Gets a string from the key/value pair
* @param includeKey Whether or not to include the key in the data
* @param includeTypeId Whether or not to include the type id in the data
* @return The string representation of the data
//! Gets a string from the key/value pair
/*!
\param includeKey Whether or not to include the key in the data
\param includeTypeId Whether or not to include the type id in the data
\return The string representation of the data
*/
virtual std::string GetString(bool includeKey = true, bool includeTypeId = true) = 0;
@@ -48,30 +68,34 @@ public:
virtual LDFBaseData* Copy() = 0;
/**
* Given an input string, return the data as a LDF key.
// MARK: Functions
//! Returns a pointer to a LDFData value based on string format
/*!
\param format The format
*/
static LDFBaseData* DataFromString(const std::string_view& format);
static LDFBaseData* DataFromString(const std::string& format);
};
//! A structure for an LDF key-value pair
template<typename T>
class LDFData: public LDFBaseData {
class LDFData : public LDFBaseData {
private:
std::u16string key;
T value;
//! Writes the key to the packet
void WriteKey(RakNet::BitStream* packet) {
packet->Write<uint8_t>(this->key.length() * sizeof(uint16_t));
packet->Write(static_cast<uint8_t>(this->key.length() * sizeof(uint16_t)));
for (uint32_t i = 0; i < this->key.length(); ++i) {
packet->Write<uint16_t>(this->key[i]);
packet->Write(static_cast<uint16_t>(this->key[i]));
}
}
//! Writes the value to the packet
void WriteValue(RakNet::BitStream* packet) {
packet->Write<uint8_t>(this->GetValueType());
packet->Write(static_cast<uint8_t>(this->GetValueType()));
packet->Write(this->value);
}
@@ -140,11 +164,15 @@ public:
if (includeKey) {
const std::string& sKey = GeneralUtils::UTF16ToWTF8(this->key, this->key.size());
stream << sKey << '=';
stream << sKey << "=";
}
if (includeTypeId) {
stream << this->GetValueType() << ':';
const std::string& sType = std::to_string(this->GetValueType());
stream << sType << ":";
}
const std::string& sData = this->GetValueString();
@@ -179,45 +207,47 @@ template<> inline eLDFType LDFData<std::string>::GetValueType(void) { return LDF
// The specialized version for std::u16string (UTF-16)
template<>
inline void LDFData<std::u16string>::WriteValue(RakNet::BitStream* packet) {
packet->Write<uint8_t>(this->GetValueType());
packet->Write(static_cast<uint8_t>(this->GetValueType()));
packet->Write<uint32_t>(this->value.length());
packet->Write(static_cast<uint32_t>(this->value.length()));
for (uint32_t i = 0; i < this->value.length(); ++i) {
packet->Write<uint16_t>(this->value[i]);
packet->Write(static_cast<uint16_t>(this->value[i]));
}
}
// The specialized version for bool
template<>
inline void LDFData<bool>::WriteValue(RakNet::BitStream* packet) {
packet->Write<uint8_t>(this->GetValueType());
packet->Write(static_cast<uint8_t>(this->GetValueType()));
packet->Write<uint8_t>(this->value);
packet->Write(static_cast<uint8_t>(this->value));
}
// The specialized version for std::string (UTF-8)
template<>
inline void LDFData<std::string>::WriteValue(RakNet::BitStream* packet) {
packet->Write<uint8_t>(this->GetValueType());
packet->Write(static_cast<uint8_t>(this->GetValueType()));
packet->Write<uint32_t>(this->value.length());
packet->Write(static_cast<uint32_t>(this->value.length()));
for (uint32_t i = 0; i < this->value.length(); ++i) {
packet->Write<uint8_t>(this->value[i]);
packet->Write(static_cast<uint8_t>(this->value[i]));
}
}
template<> inline std::string LDFData<std::u16string>::GetValueString() {
// MARK: String Data
template<> inline std::string LDFData<std::u16string>::GetValueString(void) {
//std::string toReturn(this->value.begin(), this->value.end());
//return toReturn;
return GeneralUtils::UTF16ToWTF8(this->value, this->value.size());
}
template<> inline std::string LDFData<int32_t>::GetValueString() { return std::to_string(this->value); }
template<> inline std::string LDFData<float>::GetValueString() { return std::to_string(this->value); }
template<> inline std::string LDFData<double>::GetValueString() { return std::to_string(this->value); }
template<> inline std::string LDFData<uint32_t>::GetValueString() { return std::to_string(this->value); }
template<> inline std::string LDFData<bool>::GetValueString() { return std::to_string(this->value); }
template<> inline std::string LDFData<uint64_t>::GetValueString() { return std::to_string(this->value); }
template<> inline std::string LDFData<LWOOBJID>::GetValueString() { return std::to_string(this->value); }
template<> inline std::string LDFData<int32_t>::GetValueString(void) { return std::to_string(this->value); }
template<> inline std::string LDFData<float>::GetValueString(void) { return std::to_string(this->value); }
template<> inline std::string LDFData<double>::GetValueString(void) { return std::to_string(this->value); }
template<> inline std::string LDFData<uint32_t>::GetValueString(void) { return std::to_string(this->value); }
template<> inline std::string LDFData<bool>::GetValueString(void) { return std::to_string(this->value); }
template<> inline std::string LDFData<uint64_t>::GetValueString(void) { return std::to_string(this->value); }
template<> inline std::string LDFData<LWOOBJID>::GetValueString(void) { return std::to_string(this->value); }
template<> inline std::string LDFData<std::string>::GetValueString() { return this->value; }
#endif //!__LDFFORMAT__H__
template<> inline std::string LDFData<std::string>::GetValueString(void) { return this->value; }

View File

@@ -1,98 +0,0 @@
#include "Logger.h"
#include <algorithm>
#include <ctime>
#include <filesystem>
#include <stdarg.h>
Writer::~Writer() {
// Flush before we close
Flush();
// Dont try to close stdcout...
if (!m_Outfile || m_IsConsoleWriter) return;
fclose(m_Outfile);
m_Outfile = NULL;
}
void Writer::Log(const char* time, const char* message) {
if (!m_Outfile || !m_Enabled) return;
fputs(time, m_Outfile);
fputs(message, m_Outfile);
}
void Writer::Flush() {
if (!m_Outfile) return;
fflush(m_Outfile);
}
FileWriter::FileWriter(const char* outpath) {
m_Outfile = fopen(outpath, "wt");
if (!m_Outfile) printf("Couldn't open %s for writing!\n", outpath);
m_Outpath = outpath;
m_IsConsoleWriter = false;
}
ConsoleWriter::ConsoleWriter(bool enabled) {
m_Enabled = enabled;
m_Outfile = stdout;
m_IsConsoleWriter = true;
}
Logger::Logger(const std::string& outpath, bool logToConsole, bool logDebugStatements) {
m_logDebugStatements = logDebugStatements;
std::filesystem::path outpathPath(outpath);
if (!std::filesystem::exists(outpathPath.parent_path())) std::filesystem::create_directories(outpathPath.parent_path());
m_Writers.push_back(std::make_unique<FileWriter>(outpath));
m_Writers.push_back(std::make_unique<ConsoleWriter>(logToConsole));
}
void Logger::vLog(const char* format, va_list args) {
time_t t = time(NULL);
struct tm* time = localtime(&t);
char timeStr[70];
strftime(timeStr, sizeof(timeStr), "[%d-%m-%y %H:%M:%S ", time);
char message[2048];
vsnprintf(message, 2048, format, args);
for (const auto& writer : m_Writers) {
writer->Log(timeStr, message);
}
}
void Logger::Log(const char* className, const char* format, ...) {
va_list args;
std::string log = std::string(className) + "] " + std::string(format) + "\n";
va_start(args, format);
vLog(log.c_str(), args);
va_end(args);
}
void Logger::LogDebug(const char* className, const char* format, ...) {
if (!m_logDebugStatements) return;
va_list args;
std::string log = std::string(className) + "] " + std::string(format) + "\n";
va_start(args, format);
vLog(log.c_str(), args);
va_end(args);
}
void Logger::Flush() {
for (const auto& writer : m_Writers) {
writer->Flush();
}
}
void Logger::SetLogToConsole(bool logToConsole) {
for (const auto& writer : m_Writers) {
if (writer->IsConsoleWriter()) writer->SetEnabled(logToConsole);
}
}
bool Logger::GetLogToConsole() const {
bool toReturn = false;
for (const auto& writer : m_Writers) {
if (writer->IsConsoleWriter()) toReturn |= writer->GetEnabled();
}
return toReturn;
}

View File

@@ -1,89 +0,0 @@
#pragma once
#include <memory>
#include <string>
#include <vector>
#define STRINGIFY_IMPL(x) #x
#define STRINGIFY(x) STRINGIFY_IMPL(x)
#define GET_FILE_NAME(x, y) GetFileNameFromAbsolutePath(__FILE__ x y)
#define FILENAME_AND_LINE GET_FILE_NAME(":", STRINGIFY(__LINE__))
// Calculate the filename at compile time from the path.
// We just do this by scanning the path for the last '/' or '\' character and returning the string after it.
constexpr const char* GetFileNameFromAbsolutePath(const char* path) {
const char* file = path;
while (*path) {
char nextChar = *path++;
if (nextChar == '/' || nextChar == '\\') {
file = path;
}
}
return file;
}
// These have to have a constexpr variable to store the filename_and_line result in a local variable otherwise
// they will not be valid constexpr and will be evaluated at runtime instead of compile time!
// The full string is still stored in the binary, however the offset of the filename in the absolute paths
// is used in the instruction instead of the start of the absolute path.
#define LOG(message, ...) do { auto str = FILENAME_AND_LINE; Game::logger->Log(str, message, ##__VA_ARGS__); } while(0)
#define LOG_DEBUG(message, ...) do { auto str = FILENAME_AND_LINE; Game::logger->LogDebug(str, message, ##__VA_ARGS__); } while(0)
// Writer class for writing data to files.
class Writer {
public:
Writer(bool enabled = true) : m_Enabled(enabled) {};
virtual ~Writer();
virtual void Log(const char* time, const char* message);
virtual void Flush();
void SetEnabled(bool disabled) { m_Enabled = disabled; }
bool GetEnabled() const { return m_Enabled; }
bool IsConsoleWriter() { return m_IsConsoleWriter; }
public:
bool m_Enabled = true;
bool m_IsConsoleWriter = false;
FILE* m_Outfile;
};
// FileWriter class for writing data to a file on a disk.
class FileWriter : public Writer {
public:
FileWriter(const char* outpath);
FileWriter(const std::string& outpath) : FileWriter(outpath.c_str()) {};
private:
std::string m_Outpath;
};
// ConsoleWriter class for writing data to the console.
class ConsoleWriter : public Writer {
public:
ConsoleWriter(bool enabled);
};
class Logger {
public:
Logger() = delete;
Logger(const std::string& outpath, bool logToConsole, bool logDebugStatements);
void Log(const char* filenameAndLine, const char* format, ...);
void LogDebug(const char* filenameAndLine, const char* format, ...);
void Flush();
bool GetLogToConsole() const;
void SetLogToConsole(bool logToConsole);
void SetLogDebugStatements(bool logDebugStatements) { m_logDebugStatements = logDebugStatements; }
private:
void vLog(const char* format, va_list args);
bool m_logDebugStatements;
std::vector<std::unique_ptr<Writer>> m_Writers;
};

View File

@@ -107,7 +107,7 @@ void Metrics::EndMeasurement(MetricVariable variable) {
}
float Metrics::ToMiliseconds(int64_t nanoseconds) {
return static_cast<float>(nanoseconds) / 1e6;
return (float)nanoseconds / 1e6;
}
std::string Metrics::MetricVariableToString(MetricVariable variable) {
@@ -193,34 +193,34 @@ size_t Metrics::GetPeakRSS() {
/* Windows -------------------------------------------------- */
PROCESS_MEMORY_COUNTERS info;
GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info));
return static_cast<size_t>(info.PeakWorkingSetSize);
return (size_t)info.PeakWorkingSetSize;
#elif (defined(_AIX) || defined(__TOS__AIX__)) || (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__)))
/* AIX and Solaris ------------------------------------------ */
struct psinfo psinfo;
int fd = -1;
if ((fd = open("/proc/self/psinfo", O_RDONLY)) == -1)
return static_cast<size_t>(0L); /* Can't open? */
return (size_t)0L; /* Can't open? */
if (read(fd, &psinfo, sizeof(psinfo)) != sizeof(psinfo)) {
close(fd);
return static_cast<size_t>(0L); /* Can't read? */
return (size_t)0L; /* Can't read? */
}
close(fd);
return static_cast<size_t>(psinfo.pr_rssize * 1024L);
return (size_t)(psinfo.pr_rssize * 1024L);
#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__))
/* BSD, Linux, and OSX -------------------------------------- */
struct rusage rusage;
getrusage(RUSAGE_SELF, &rusage);
#if defined(__APPLE__) && defined(__MACH__)
return static_cast<size_t>(rusage.ru_maxrss);
return (size_t)rusage.ru_maxrss;
#else
return static_cast<size_t>(rusage.ru_maxrss * 1024L);
return (size_t)(rusage.ru_maxrss * 1024L);
#endif
#else
/* Unknown OS ----------------------------------------------- */
return static_cast<size_t>(0L); /* Unsupported. */
return (size_t)0L; /* Unsupported. */
#endif
}
@@ -234,33 +234,33 @@ size_t Metrics::GetCurrentRSS() {
/* Windows -------------------------------------------------- */
PROCESS_MEMORY_COUNTERS info;
GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info));
return static_cast<size_t>(info.WorkingSetSize);
return (size_t)info.WorkingSetSize;
#elif defined(__APPLE__) && defined(__MACH__)
/* OSX ------------------------------------------------------ */
struct mach_task_basic_info info;
mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT;
if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO,
reinterpret_cast<task_info_t>(&info), &infoCount) != KERN_SUCCESS)
return static_cast<size_t>(0L); /* Can't access? */
return static_cast<size_t>(info.resident_size);
(task_info_t)&info, &infoCount) != KERN_SUCCESS)
return (size_t)0L; /* Can't access? */
return (size_t)info.resident_size;
#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
/* Linux ---------------------------------------------------- */
long rss = 0L;
FILE* fp = NULL;
if ((fp = fopen("/proc/self/statm", "r")) == NULL)
return static_cast<size_t>(0L); /* Can't open? */
return (size_t)0L; /* Can't open? */
if (fscanf(fp, "%*s%ld", &rss) != 1) {
fclose(fp);
return static_cast<size_t>(0L); /* Can't read? */
return (size_t)0L; /* Can't read? */
}
fclose(fp);
return static_cast<size_t>(rss) * static_cast<size_t>(sysconf(_SC_PAGESIZE));
return (size_t)rss * (size_t)sysconf(_SC_PAGESIZE);
#else
/* AIX, BSD, Solaris, and Unknown OS ------------------------ */
return static_cast<size_t>(0L); /* Unsupported. */
return (size_t)0L; /* Unsupported. */
#endif
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,50 +0,0 @@
#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 = NiPoint3Constant::ZERO;
NiPoint3 linearVelocity = NiPoint3Constant::ZERO;
};
struct PositionUpdate {
NiPoint3 position = NiPoint3Constant::ZERO;
NiQuaternion rotation = NiQuaternionConstant::IDENTITY;
bool onGround = false;
bool onRail = false;
NiPoint3 velocity = NiPoint3Constant::ZERO;
NiPoint3 angularVelocity = NiPoint3Constant::ZERO;
LocalSpaceInfo localSpaceInfo;
RemoteInputInfo remoteInputInfo;
};
#endif //!__POSITIONUPDATE__H__

View File

@@ -1,5 +1,3 @@
// Source: http://www.zedwood.com/article/cpp-sha512-function
#include "SHA512.h"
#include <cstring>

27
dCommon/Type.cpp Normal file
View File

@@ -0,0 +1,27 @@
#include "Type.h"
#ifdef __GNUG__
#include <cstdlib>
#include <memory>
#include <cxxabi.h>
std::string demangle(const char* name) {
int status = -4; // some arbitrary value to eliminate the compiler warning
// enable c++11 by passing the flag -std=c++11 to g++
std::unique_ptr<char, void(*)(void*)> res{
abi::__cxa_demangle(name, NULL, NULL, &status),
std::free
};
return (status == 0) ? res.get() : name;
}
#else
// does nothing if not g++
std::string demangle(const char* name) {
return name;
}
#endif

12
dCommon/Type.h Normal file
View File

@@ -0,0 +1,12 @@
#pragma once
#include <string>
#include <typeinfo>
std::string demangle(const char* name);
template <class T>
std::string type(const T& t) {
return demangle(typeid(t).name());
}

View File

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

View File

@@ -2,9 +2,9 @@
#include "AssetManager.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
#include "zlib.h"
#include <zlib.h>
AssetManager::AssetManager(const std::filesystem::path& path) {
if (!std::filesystem::is_directory(path)) {
@@ -47,10 +47,6 @@ AssetManager::AssetManager(const std::filesystem::path& path) {
this->LoadPackIndex();
break;
}
case eAssetBundleType::None:
case eAssetBundleType::Unpacked: {
break;
}
}
}
@@ -81,8 +77,8 @@ bool AssetManager::HasFile(const char* name) {
std::replace(fixedName.begin(), fixedName.end(), '/', '\\');
if (fixedName.rfind("client\\res\\", 0) != 0) fixedName = "client\\res\\" + fixedName;
uint32_t crc = crc32b(0xFFFFFFFF, reinterpret_cast<uint8_t*>(const_cast<char*>(fixedName.c_str())), fixedName.size());
crc = crc32b(crc, reinterpret_cast<Bytef*>(const_cast<char*>("\0\0\0\0")), 4);
uint32_t crc = crc32b(0xFFFFFFFF, (uint8_t*)fixedName.c_str(), fixedName.size());
crc = crc32b(crc, (Bytef*)"\0\0\0\0", 4);
for (const auto& item : this->m_PackIndex->GetPackFileIndices()) {
if (item.m_Crc == crc) {
@@ -113,9 +109,9 @@ bool AssetManager::GetFile(const char* name, char** data, uint32_t* len) {
#endif
fseek(file, 0, SEEK_END);
*len = ftell(file);
*data = static_cast<char*>(malloc(*len));
*data = (char*)malloc(*len);
fseek(file, 0, SEEK_SET);
int32_t readInData = fread(*data, sizeof(uint8_t), *len, file);
fread(*data, sizeof(uint8_t), *len, file);
fclose(file);
return true;
@@ -129,8 +125,8 @@ bool AssetManager::GetFile(const char* name, char** data, uint32_t* len) {
fixedName = "client\\res\\" + fixedName;
}
int32_t packIndex = -1;
uint32_t crc = crc32b(0xFFFFFFFF, reinterpret_cast<uint8_t*>(const_cast<char*>(fixedName.c_str())), fixedName.size());
crc = crc32b(crc, reinterpret_cast<Bytef*>(const_cast<char*>("\0\0\0\0")), 4);
uint32_t crc = crc32b(0xFFFFFFFF, (uint8_t*)fixedName.c_str(), fixedName.size());
crc = crc32b(crc, (Bytef*)"\0\0\0\0", 4);
for (const auto& item : this->m_PackIndex->GetPackFileIndices()) {
if (item.m_Crc == crc) {
@@ -152,12 +148,13 @@ bool AssetManager::GetFile(const char* name, char** data, uint32_t* len) {
return success;
}
AssetStream AssetManager::GetFile(const char* name) {
char* buf; uint32_t len;
AssetMemoryBuffer AssetManager::GetFileAsBuffer(const char* name) {
char* buf;
uint32_t len;
bool success = this->GetFile(name, &buf, &len);
return AssetStream(buf, len, success);
return AssetMemoryBuffer(buf, len, success);
}
uint32_t AssetManager::crc32b(uint32_t base, uint8_t* message, size_t l) {
@@ -167,7 +164,7 @@ uint32_t AssetManager::crc32b(uint32_t base, uint8_t* message, size_t l) {
crc = base;
for (i = 0; i < l; i++) {
// xor next byte to upper bits of crc
crc ^= (static_cast<unsigned int>(message[i]) << 24);
crc ^= (((unsigned int)message[i]) << 24);
for (j = 0; j < 8; j++) { // Do eight times.
msb = crc >> 31;
crc <<= 1;

View File

@@ -25,10 +25,6 @@ struct AssetMemoryBuffer : std::streambuf {
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 {
return seekoff(sp - pos_type(off_type(0)), std::ios_base::beg, which);
}
@@ -44,17 +40,9 @@ struct AssetMemoryBuffer : std::streambuf {
setg(eback(), eback() + off, egptr());
return gptr() - eback();
}
};
struct AssetStream : std::istream {
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;
void close() {
delete m_Base;
}
};
@@ -68,7 +56,7 @@ public:
bool HasFile(const char* name);
bool GetFile(const char* name, char** data, uint32_t* len);
AssetStream GetFile(const char* name);
AssetMemoryBuffer GetFileAsBuffer(const char* name);
private:
void LoadPackIndex();

View File

@@ -76,8 +76,8 @@ bool Pack::ReadFileFromPack(uint32_t crc, char** data, uint32_t* len) {
fseek(file, pos, SEEK_SET);
if (!isCompressed) {
char* tempData = static_cast<char*>(malloc(pkRecord.m_UncompressedSize));
int32_t readInData = fread(tempData, sizeof(uint8_t), pkRecord.m_UncompressedSize, file);
char* tempData = (char*)malloc(pkRecord.m_UncompressedSize);
fread(tempData, sizeof(uint8_t), pkRecord.m_UncompressedSize, file);
*data = tempData;
*len = pkRecord.m_UncompressedSize;
@@ -90,22 +90,22 @@ bool Pack::ReadFileFromPack(uint32_t crc, char** data, uint32_t* len) {
fseek(file, pos, SEEK_SET);
char* decompressedData = static_cast<char*>(malloc(pkRecord.m_UncompressedSize));
char* decompressedData = (char*)malloc(pkRecord.m_UncompressedSize);
uint32_t currentReadPos = 0;
while (true) {
if (currentReadPos >= pkRecord.m_UncompressedSize) break;
uint32_t size;
int32_t readInData = fread(&size, sizeof(uint32_t), 1, file);
fread(&size, sizeof(uint32_t), 1, file);
pos += 4; // Move pointer position 4 to the right
char* chunk = static_cast<char*>(malloc(size));
int32_t readInData2 = fread(chunk, sizeof(int8_t), size, file);
char* chunk = (char*)malloc(size);
fread(chunk, sizeof(int8_t), size, file);
pos += size; // Move pointer position the amount of bytes read to the right
int32_t err;
currentReadPos += ZCompression::Decompress(reinterpret_cast<uint8_t*>(chunk), size, reinterpret_cast<uint8_t*>(decompressedData + currentReadPos), ZCompression::MAX_SD0_CHUNK_SIZE, err);
currentReadPos += ZCompression::Decompress((uint8_t*)chunk, size, reinterpret_cast<uint8_t*>(decompressedData + currentReadPos), ZCompression::MAX_SD0_CHUNK_SIZE, err);
free(chunk);
}

View File

@@ -3,7 +3,6 @@
#include <vector>
#include <string>
#include <filesystem>
#include <fstream>
#pragma pack(push, 1)
struct PackRecord {

View File

@@ -1,17 +1,28 @@
#include "PackIndex.h"
#include "BinaryIO.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
PackIndex::PackIndex(const std::filesystem::path& filePath) {
m_FileStream = std::ifstream(filePath / "versions" / "primary.pki", std::ios::in | std::ios::binary);
BinaryIO::BinaryRead<uint32_t>(m_FileStream, m_Version);
BinaryIO::BinaryRead<uint32_t>(m_FileStream, m_PackPathCount);
m_PackPaths.resize(m_PackPathCount);
for (auto& item : m_PackPaths) {
BinaryIO::ReadString<uint32_t>(m_FileStream, item, BinaryIO::ReadType::String);
for (int i = 0; i < m_PackPathCount; i++) {
uint32_t stringLen = 0;
BinaryIO::BinaryRead<uint32_t>(m_FileStream, stringLen);
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);
@@ -23,7 +34,7 @@ PackIndex::PackIndex(const std::filesystem::path& filePath) {
m_PackFileIndices.push_back(packFileIndex);
}
LOG("Loaded pack catalog with %i pack files and %i files", m_PackPaths.size(), m_PackFileIndices.size());
Game::logger->Log("PackIndex", "Loaded pack catalog with %i pack files and %i files", m_PackPaths.size(), m_PackFileIndices.size());
for (auto& item : m_PackPaths) {
std::replace(item.begin(), item.end(), '\\', '/');

View File

@@ -10,23 +10,8 @@ dConfig::dConfig(const std::string& filepath) {
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() {
std::filesystem::path config_dir = GetConfigDir();
std::ifstream in(config_dir / m_ConfigFilePath);
std::ifstream in(BinaryPathFinder::GetBinaryDir() / m_ConfigFilePath);
if (!in.good()) return;
std::string line{};
@@ -34,7 +19,7 @@ void dConfig::LoadConfig() {
if (!line.empty() && line.front() != '#') ProcessLine(line);
}
std::ifstream sharedConfig(config_dir / "sharedconfig.ini", std::ios::in);
std::ifstream sharedConfig(BinaryPathFinder::GetBinaryDir() / "sharedconfig.ini", std::ios::in);
if (!sharedConfig.good()) return;
line.clear();
@@ -49,20 +34,17 @@ void dConfig::ReloadConfig() {
}
const std::string& dConfig::GetValue(std::string key) {
std::string upper_key(key);
std::transform(upper_key.begin(), upper_key.end(), upper_key.begin(), ::toupper);
if (const char* env_p = std::getenv(upper_key.c_str())) {
this->m_ConfigValues[key] = env_p;
}
return this->m_ConfigValues[key];
}
void dConfig::ProcessLine(const std::string& line) {
auto splitLoc = line.find('=');
auto key = line.substr(0, splitLoc);
auto value = line.substr(splitLoc + 1);
auto splitLine = GeneralUtils::SplitString(line, '=');
if (splitLine.size() != 2) return;
//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 (this->m_ConfigValues.find(key) != this->m_ConfigValues.end()) return;

View File

@@ -7,11 +7,6 @@ class dConfig {
public:
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.
*

View File

@@ -1,11 +1,11 @@
#pragma once
#ifndef __EADDFRIENDRESPONSECODE__H__
#define __EADDFRIENDRESPONSECODE__H__
#ifndef __ADDFRIENDRESPONSECODE__H__
#define __ADDFRIENDRESPONSECODE__H__
#include <cstdint>
enum class eAddFriendResponseCode : uint8_t {
enum class AddFriendResponseCode : uint8_t {
ACCEPTED = 0,
REJECTED,
BUSY,

View File

@@ -1,11 +1,11 @@
#pragma once
#ifndef __EADDFRIENDRESPONSETYPE__H__
#define __EADDFRIENDRESPONSETYPE__H__
#ifndef __ADDFRIENDRESPONSETYPE__H__
#define __ADDFRIENDRESPONSETYPE__H__
#include <cstdint>
enum class eAddFriendResponseType : uint8_t {
enum class AddFriendResponseType : uint8_t {
ACCEPTED = 0,
ALREADYFRIEND,
INVALIDCHARACTER,
@@ -21,4 +21,4 @@ enum class eAddFriendResponseType : uint8_t {
FRIENDISFREETRIAL
};
#endif //!__EADDFRIENDRESPONSETYPE__H__
#endif //!__ADDFRIENDRESPONSETYPE__H__

View File

@@ -0,0 +1,105 @@
#pragma once
/**
2 Engineer (Rank 1) Item Set
3 Engineer (Rank 2) Item Set
4 Engineer (Rank 3) Item Set
7 Knight (Rank 1) Item Set
8 Knight (Rank 2) Item Set
9 Knight (Rank 3) Item Set
10 Space Ranger (Rank 1) Item Set
11 Space Ranger (Rank 2) Item Set
12 Space Ranger (Rank 3) Item Set
13 Samurai (Rank 1) Item Set
14 Samurai (Rank 2) Item Set
15 Samurai (Rank 3) Item Set
16 Sorcerer (Rank 1) Item Set
17 Sorcerer (Rank 2) Item Set
18 Sorcerer (Rank 3) Item Set
19 Space Marauder (Rank 1) Item Set
20 Space Marauder (Rank 2) Item Set
21 Space Marauder (Rank 3) Item Set
22 Shinobi (Rank 1) Item Set
23 Shinobi (Rank 2) Item Set
24 Shinobi (Rank 3) Item Set
25 Inventor (Rank 1) Item Set
26 Inventor (Rank 2) Item Set
27 Inventor (Rank 3) Item Set
28 Summoner (Rank 1) Item Set
29 Summoner (Rank 2) Item Set
30 Summoner (Rank 3) Item Set
31 Adventurer (Rank 1) Item Set
32 Adventurer (Rank 2) Item Set
33 Adventurer (Rank 3) Item Set
34 Daredevil (Rank 1) Item Set
35 Daredevil (Rank 2) Item Set
36 Daredevil (Rank 3) Item Set
37 Buccaneer (Rank 1) Item Set
38 Buccaneer (Rank 2) Item Set
39 Buccaneer (Rank 3) Item Set
40 Bone Suit Item Set
41 Imagination Spinjitzu Item Set
42 Bat Lord Item Set
43 Mosaic Jester Item Set
44 Explorien Bot Item Set
45 [Unnamed] Item Set
46 [Unnamed] Item Set
47 [Unnamed] Item Set
48 Earth Spinjitzu Item Set
49 [Unnamed] Item Set
50 Fire Spinjitzu Item Set
51 Ice Spinjitzu Item Set
52 Lightning Spinjitzu Item Set
*/
enum class ItemSetPassiveAbilityID
{
EngineerRank1 = 2,
EngineerRank2 = 3,
EngineerRank3 = 4,
KnightRank1 = 7,
KnightRank2 = 8,
KnightRank3 = 9,
SpaceRangerRank1 = 10,
SpaceRangerRank2 = 11,
SpaceRangerRank3 = 12,
SamuraiRank1 = 13,
SamuraiRank2 = 14,
SamuraiRank3 = 15,
SorcererRank1 = 16,
SorcererRank2 = 17,
SorcererRank3 = 18,
SpaceMarauderRank1 = 19,
SpaceMarauderRank2 = 20,
SpaceMarauderRank3 = 21,
ShinobiRank1 = 22,
ShinobiRank2 = 23,
ShinobiRank3 = 24,
InventorRank1 = 25,
InventorRank2 = 26,
InventorRank3 = 27,
SummonerRank1 = 28,
SummonerRank2 = 29,
SummonerRank3 = 30,
AdventurerRank1 = 31,
AdventurerRank2 = 32,
AdventurerRank3 = 33,
DaredevilRank1 = 34,
DaredevilRank2 = 35,
DaredevilRank3 = 36,
BuccaneerRank1 = 37,
BuccaneerRank2 = 38,
BuccaneerRank3 = 39,
BoneSuit = 40,
ImaginationSpinjitzu = 41,
BatLord = 42,
MosaicJester = 43,
ExplorienBot = 44,
Unnamed1 = 45,
Unnamed2 = 46,
Unnamed3 = 47,
EarthSpinjitzu = 48,
Unnamed4 = 49,
FireSpinjitzu = 50,
IceSpinjitzu = 51,
LightningSpinjitzu = 52
};

View File

@@ -0,0 +1,13 @@
#pragma once
#ifndef MISSIONLOCKSTATE_H
#define MISSIONLOCKSTATE_H
enum class MissionLockState : int
{
MISSION_LOCK_LOCKED,
MISSION_LOCK_NEW,
MISSION_LOCK_UNLOCKED,
};
#endif

View File

@@ -0,0 +1,56 @@
#pragma once
#ifndef __MISSIONSTATE__H__
#define __MISSIONSTATE__H__
/**
* Represents the possible states a mission can be in
*/
enum class MissionState : int32_t {
/**
* The mission state is unknown
*/
MISSION_STATE_UNKNOWN = -1,
/**
* The mission is yielding rewards
*/
MISSION_STATE_REWARDING = 0,
/**
* The mission can be accepted
*/
MISSION_STATE_AVAILABLE = 1,
/**
* The mission has been accepted but not yet completed
*/
MISSION_STATE_ACTIVE = 2,
/**
* All the tasks for the mission have been completed and the entity can turn the mission in to complete it
*/
MISSION_STATE_READY_TO_COMPLETE = 4, //!< The mission is ready to complete
/**
* The mission has been completed
*/
MISSION_STATE_COMPLETE = 8,
/**
* The mission is available again and has been completed before. Used for daily missions.
*/
MISSION_STATE_COMPLETE_AVAILABLE = 9,
/**
* The mission is active and has been completed before. Used for daily missions.
*/
MISSION_STATE_COMPLETE_ACTIVE = 10,
/**
* The mission has been completed before and has now been completed again. Used for daily missions.
*/
MISSION_STATE_COMPLETE_READY_TO_COMPLETE = 12
};
#endif //!__MISSIONSTATE__H__

View File

@@ -0,0 +1,31 @@
#pragma once
#ifndef MISSIONTASKTYPE_H
#define MISSIONTASKTYPE_H
//! An enum for mission task types
enum class MissionTaskType : int {
MISSION_TASK_TYPE_UNKNOWN = -1, //!< The task type is unknown
MISSION_TASK_TYPE_SMASH = 0, //!< A task for smashing something
MISSION_TASK_TYPE_SCRIPT = 1, //!< A task handled by a server LUA script
MISSION_TASK_TYPE_ACTIVITY = 2, //!< A task for completing a quickbuild
MISSION_TASK_TYPE_ENVIRONMENT = 3, //!< A task for something in the environment
MISSION_TASK_TYPE_MISSION_INTERACTION = 4, //!< A task for interacting with a mission
MISSION_TASK_TYPE_EMOTE = 5, //!< A task for playing an emote
MISSION_TASK_TYPE_FOOD = 9, //!< A task for eating food
MISSION_TASK_TYPE_SKILL = 10, //!< A task for performing a skill
MISSION_TASK_TYPE_ITEM_COLLECTION = 11, //!< A task for collecting an item
MISSION_TASK_TYPE_LOCATION = 12, //!< A task for finding a location
MISSION_TASK_TYPE_MINIGAME = 14, //!< A task for doing something in a minigame
MISSION_TASK_TYPE_NON_MISSION_INTERACTION = 15, //!< A task for interacting with a non-mission
MISSION_TASK_TYPE_MISSION_COMPLETE = 16, //!< A task for completing a mission
MISSION_TASK_TYPE_EARN_REPUTATION = 17, //!< A task for earning reputation
MISSION_TASK_TYPE_POWERUP = 21, //!< A task for collecting a powerup
MISSION_TASK_TYPE_PET_TAMING = 22, //!< A task for taming a pet
MISSION_TASK_TYPE_RACING = 23, //!< A task for racing
MISSION_TASK_TYPE_PLAYER_FLAG = 24, //!< A task for setting a player flag
MISSION_TASK_TYPE_PLACE_MODEL = 25, //!< A task for picking up a model
MISSION_TASK_TYPE_VISIT_PROPERTY = 30 //!< A task for visiting a property
};
#endif

View File

@@ -0,0 +1,42 @@
#pragma once
#include <cstdint>
/**
* Bitmap of permissions and restrictions for characters.
*/
enum class PermissionMap : uint64_t
{
/**
* Reserved for future use, bit 0-3.
*/
/**
* The character has restricted trade acccess, bit 4.
*/
RestrictedTradeAccess = 0x1 << 4,
/**
* The character has restricted mail access, bit 5.
*/
RestrictedMailAccess = 0x1 << 5,
/**
* The character has restricted chat access, bit 6.
*/
RestrictedChatAccess = 0x1 << 6,
//
// Combined permissions
//
/**
* The character is marked as 'old', restricted from trade and mail.
*/
Old = RestrictedTradeAccess | RestrictedMailAccess,
/**
* The character is soft banned, restricted from trade, mail, and chat.
*/
SoftBanned = RestrictedTradeAccess | RestrictedMailAccess | RestrictedChatAccess,
};

View File

@@ -0,0 +1,20 @@
#pragma once
#include <cstdint>
enum class RacingTaskParam : int32_t {
RACING_TASK_PARAM_FINISH_WITH_PLACEMENT = 1, //<! A task param for finishing with a specific placement.
RACING_TASK_PARAM_LAP_TIME = 2, //<! A task param for finishing with a specific lap time.
RACING_TASK_PARAM_TOTAL_TRACK_TIME = 3, //<! A task param for finishing with a specific track time.
RACING_TASK_PARAM_COMPLETE_ANY_RACING_TASK = 4, //<! A task param for completing a racing task.
RACING_TASK_PARAM_COMPLETE_TRACK_TASKS = 5, //<! A task param for completing a task for a specific track.
RACING_TASK_PARAM_MODULAR_BUILDING = 6, //<! A task param for modular building with racing builds.
RACING_TASK_PARAM_SAFE_DRIVER = 10, //<! A task param for completing a race without smashing.
RACING_TASK_PARAM_SMASHABLES = 11, //<! A task param for smashing entities during a race.
RACING_TASK_PARAM_COLLECT_IMAGINATION = 12, //<! A task param for collecting imagination during a race.
RACING_TASK_PARAM_COMPETED_IN_RACE = 13, //<! A task param for competing in a race.
RACING_TASK_PARAM_WIN_RACE_IN_WORLD = 14, //<! A task param for winning a race in a specific world.
RACING_TASK_PARAM_FIRST_PLACE_MULTIPLE_TRACKS = 15, //<! A task param for finishing in first place on multiple tracks.
RACING_TASK_PARAM_LAST_PLACE_FINISH = 16, //<! A task param for finishing in last place.
RACING_TASK_PARAM_SMASH_SPECIFIC_SMASHABLE = 17 //<! A task param for smashing dragon eggs during a race.
};

View File

@@ -1,29 +0,0 @@
#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__

View File

@@ -7,12 +7,11 @@
#include <string>
#include <set>
#include "BitStream.h"
#include "eConnectionType.h"
#include "eClientMessageType.h"
#include "BitStreamUtils.h"
#pragma warning (disable:4251) //Disables SQL warnings
typedef int RESTICKET;
// These are the same define, but they mean two different things in different contexts
// so a different define to distinguish what calculation is happening will help clarity.
#define FRAMES_TO_MS(x) 1000 / x
@@ -29,11 +28,9 @@ constexpr uint32_t lowFrameDelta = FRAMES_TO_MS(lowFramerate);
//========== MACROS ===========
#define HEADER_SIZE 8
#define CBITSTREAM RakNet::BitStream bitStream;
#define CINSTREAM RakNet::BitStream inStream(packet->data, packet->length, false);
#define CINSTREAM_SKIP_HEADER CINSTREAM if (inStream.GetNumberOfUnreadBits() >= BYTES_TO_BITS(HEADER_SIZE)) inStream.IgnoreBytes(HEADER_SIZE); else inStream.IgnoreBits(inStream.GetNumberOfUnreadBits());
#define CMSGHEADER BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::GAME_MSG);
#define CMSGHEADER PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_GAME_MSG);
#define SEND_PACKET Game::server->Send(&bitStream, sysAddr, false);
#define SEND_PACKET_BROADCAST Game::server->Send(&bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);
@@ -46,20 +43,33 @@ typedef uint32_t LWOCLONEID; //!< Used for Clone IDs
typedef uint16_t LWOMAPID; //!< Used for Map IDs
typedef uint16_t LWOINSTANCEID; //!< Used for Instance IDs
typedef uint32_t PROPERTYCLONELIST; //!< Used for Property Clone IDs
typedef uint32_t StripId;
typedef uint32_t STRIPID;
typedef uint32_t BEHAVIORSTATE;
typedef int32_t PetTamingPiece; //!< Pet Taming Pieces
const LWOOBJID LWOOBJID_EMPTY = 0; //!< An empty object ID
const LOT LOT_NULL = -1; //!< A null LOT
const int32_t LOOTTYPE_NONE = 0; //!< No loot type available
const float SECONDARY_PRIORITY = 1.0f; //!< Secondary Priority
const uint32_t INVENTORY_INVALID = -1; //!< Invalid Inventory
const uint32_t INVENTORY_DEFAULT = -1; //!< Default Inventory
const uint32_t StatusChangeInfo = 0; //!< Status Change Info (???)
const uint32_t INVENTORY_MAX = 9999999; //!< The Maximum Inventory Size
const uint32_t LWOCLONEID_INVALID = -1; //!< Invalid LWOCLONEID
const uint16_t LWOINSTANCEID_INVALID = -1; //!< Invalid LWOINSTANCEID
const uint16_t LWOMAPID_INVALID = -1; //!< Invalid LWOMAPID
const uint64_t LWOZONEID_INVALID = 0; //!< Invalid LWOZONEID
typedef std::set<LWOOBJID> TSetObjID;
const float PI = 3.14159f;
#if defined(__unix) || defined(__APPLE__)
//For Linux:
typedef __int64_t __int64;
#endif
//============ STRUCTS ==============
struct LWOSCENEID {
@@ -130,7 +140,7 @@ public:
LWOOBJID friendID;
std::string friendName;
void Serialize(RakNet::BitStream& bitStream) const {
void Serialize(RakNet::BitStream& bitStream) {
bitStream.Write<uint8_t>(isOnline);
bitStream.Write<uint8_t>(isBestFriend);
bitStream.Write<uint8_t>(isFTP);
@@ -148,11 +158,11 @@ public:
if (size > maxSize) size = maxSize;
for (uint32_t i = 0; i < size; ++i) {
bitStream.Write<uint16_t>(friendName[i]);
bitStream.Write(static_cast<uint16_t>(friendName[i]));
}
for (uint32_t j = 0; j < remSize; ++j) {
bitStream.Write<uint16_t>(0);
bitStream.Write(static_cast<uint16_t>(0));
}
bitStream.Write<uint32_t>(0); //???
@@ -160,4 +170,480 @@ public:
}
};
struct Brick {
uint32_t designerID;
uint32_t materialID;
};
//This union is used by the behavior system
union suchar {
unsigned char usigned;
char svalue;
};
//=========== DLU ENUMS ============
enum eGameMasterLevel : int32_t {
GAME_MASTER_LEVEL_CIVILIAN = 0, // Normal player.
GAME_MASTER_LEVEL_FORUM_MODERATOR = 1, // No permissions on live servers.
GAME_MASTER_LEVEL_JUNIOR_MODERATOR = 2, // Can kick/mute and pull chat logs.
GAME_MASTER_LEVEL_MODERATOR = 3, // Can return lost items.
GAME_MASTER_LEVEL_SENIOR_MODERATOR = 4, // Can ban.
GAME_MASTER_LEVEL_LEAD_MODERATOR = 5, // Can approve properties.
GAME_MASTER_LEVEL_JUNIOR_DEVELOPER = 6, // Junior developer & future content team. Civilan on live.
GAME_MASTER_LEVEL_INACTIVE_DEVELOPER = 7, // Inactive developer, limited permissions.
GAME_MASTER_LEVEL_DEVELOPER = 8, // Active developer, full permissions on live.
GAME_MASTER_LEVEL_OPERATOR = 9 // Can shutdown server for restarts & updates.
};
//=========== LU ENUMS ============
//! An enum for object ID bits
enum eObjectBits : int32_t {
OBJECT_BIT_PERSISTENT = 32, //!< The 32 bit index
OBJECT_BIT_CLIENT = 46, //!< The 46 bit index
OBJECT_BIT_SPAWNED = 58, //!< The 58 bit index
OBJECT_BIT_CHARACTER = 60 //!< The 60 bit index
};
//! An enum for MatchUpdate types
enum eMatchUpdate : int {
MATCH_UPDATE_PLAYER_JOINED = 0,
MATCH_UPDATE_PLAYER_LEFT = 1,
MATCH_UPDATE_TIME = 3,
MATCH_UPDATE_TIME_START_DELAY = 4,
MATCH_UPDATE_PLAYER_READY = 5,
MATCH_UPDATE_PLAYER_UNREADY = 6
};
//! An enum for camera cycling modes
enum eCyclingMode : uint32_t {
ALLOW_CYCLE_TEAMMATES,
DISALLOW_CYCLING
};
enum eCinematicEvent : uint32_t {
STARTED,
WAYPOINT,
ENDED,
};
//! An enum for character creation responses
enum eCreationResponse : uint8_t {
CREATION_RESPONSE_SUCCESS = 0, //!< The creation was successful
CREATION_RESPONSE_OBJECT_ID_UNAVAILABLE, //!< The Object ID can't be used
CREATION_RESPONSE_NAME_NOT_ALLOWED, //!< The name is not allowed
CREATION_RESPONSE_PREDEFINED_NAME_IN_USE, //!< The predefined name is already in use
CREATION_RESPONSE_CUSTOM_NAME_IN_USE //!< The custom name is already in use
};
//! An enum for login responses
enum eLoginResponse : uint8_t {
LOGIN_RESPONSE_GENERAL_FAILED = 0,
LOGIN_RESPONSE_SUCCESS = 1,
LOGIN_RESPONSE_BANNED = 2,
LOGIN_RESPONSE_PERMISSIONS_NOT_HIGH_ENOUGH = 5,
LOGIN_RESPONSE_WRONG_PASS_OR_USER = 6,
LOGIN_RESPONSE_ACCOUNT_LOCKED = 7
};
//! An enum for character rename responses
enum eRenameResponse : uint8_t {
RENAME_RESPONSE_SUCCESS = 0, //!< The renaming was successful
RENAME_RESPONSE_UNKNOWN_ERROR, //!< There was an unknown error
RENAME_RESPONSE_NAME_UNAVAILABLE, //!< The name is unavailable
RENAME_RESPONSE_NAME_IN_USE //!< The name is already in use
};
//! A replica packet type
enum eReplicaPacketType {
PACKET_TYPE_CONSTRUCTION, //!< A construction packet
PACKET_TYPE_SERIALIZATION, //!< A serialization packet
PACKET_TYPE_DESTRUCTION //!< A destruction packet
};
enum ServerDisconnectIdentifiers {
SERVER_DISCON_UNKNOWN_SERVER_ERROR = 0, //!< Unknown server error
SERVER_DISCON_DUPLICATE_LOGIN = 4, //!< Used when another user with the same username is logged in (duplicate login)
SERVER_DISCON_SERVER_SHUTDOWN = 5, //!< Used when the server is shutdown
SERVER_DISCON_SERVER_MAP_LOAD_FAILURE = 6, //!< Used when the server cannot load a map
SERVER_DISCON_INVALID_SESSION_KEY = 7, //!< Used if the session is invalid
SERVER_DISCON_ACCOUNT_NOT_IN_PENDING_LIST = 8, //!< ???
SERVER_DISCON_CHARACTER_NOT_FOUND = 9, //!< Used if a character that the server has is not found (i.e, corruption with user-player data)
SERVER_DISCON_CHARACTER_CORRUPTED = 10, //!< Similar to abovce
SERVER_DISCON_KICK = 11, //!< Used if the user is kicked from the server
SERVER_DISCON_FREE_TRIAL_EXPIRED = 12, //!< Used if the user's free trial expired
SERVER_DISCON_PLAY_SCHEDULE_TIME_DONE = 13 //!< Used if the user's play time is used up
};
//! The Behavior Types for use with the AI system
enum eCombatBehaviorTypes : uint32_t {
PASSIVE = 0, //!< The object is passive
AGGRESSIVE = 1, //!< The object is aggressive
PASSIVE_TURRET = 2, //!< The object is a passive turret
AGGRESSIVE_TURRET = 3 //!< The object is an aggressive turret
};
//! The Combat Role Type for use with the AI system
enum eCombatRoleType : uint32_t {
MELEE = 0, //!< Used for melee attacks
RANGED = 1, //!< Used for range attacks
SUPPORT = 2 //!< Used for support
};
//! The kill types for the Die packet
enum eKillType : uint32_t {
VIOLENT,
SILENT
};
//! The various world states used throughout the server
enum eObjectWorldState {
WORLDSTATE_INWORLD, //!< Probably used when the object is in the world
WORLDSTATE_ATTACHED, //!< Probably used when the object is attached to another object
WORLDSTATE_INVENTORY //!< Probably used when the object is in an inventory
};
//! The trigger stats (???)
enum eTriggerStat {
INVALID_STAT, //!< ???
HEALTH, //!< Probably used for health
ARMOR, //!< Probably used for armor
IMAGINATION //!< Probably used for imagination
};
//! The trigger operations (???)
enum eTriggerOperator {
INVALID_OPER, //!< ???
EQUAL, //!< ???
NOT_EQUAL, //!< ???
GREATER, //!< ???
GREATER_EQUAL, //!< ???
LESS, //!< ???
LESS_EQUAL //!< ???
};
//! The various build types
enum eBuildType {
BUILD_NOWHERE, //!< Used if something can't be built anywhere
BUILD_IN_WORLD, //!< Used if something can be built in the world
BUILD_ON_PROPERTY //!< Used if something can be build on a property
};
//! Quickbuild fail reasons
enum eFailReason : uint32_t {
REASON_NOT_GIVEN,
REASON_OUT_OF_IMAGINATION,
REASON_CANCELED_EARLY,
REASON_BUILD_ENDED
};
//! Terminate interaction type
enum eTerminateType : uint32_t {
RANGE,
USER,
FROM_INTERACTION
};
//! The combat state
enum eCombatState {
IDLE, //!< The AI is in an idle state
AGGRO, //!< The AI is in an aggressive state
TETHER, //!< The AI is being redrawn back to tether point
SPAWN, //!< The AI is spawning
DEAD //!< The AI is dead
};
enum eControlSceme {
SCHEME_A,
SCHEME_D,
SCHEME_GAMEPAD,
SCHEME_E,
SCHEME_FPS,
SCHEME_DRIVING,
SCHEME_TAMING,
SCHEME_MODULAR_BUILD,
SCHEME_WEAR_A_ROBOT //== freecam?
};
enum class eStateChangeType : uint32_t {
PUSH,
POP
};
enum eNotifyType {
NOTIFY_TYPE_SUCCESS,
NOTIFY_TYPE_QUIT,
NOTIFY_TYPE_FAILED,
NOTIFY_TYPE_BEGIN,
NOTIFY_TYPE_READY,
NOTIFY_TYPE_NAMINGPET
};
enum eReplicaComponentType : int32_t {
COMPONENT_TYPE_CONTROLLABLE_PHYSICS = 1, //!< The ControllablePhysics Component
COMPONENT_TYPE_RENDER = 2, //!< The Render Component
COMPONENT_TYPE_SIMPLE_PHYSICS = 3, //!< The SimplePhysics Component
COMPONENT_TYPE_CHARACTER = 4, //!< The Character Component
COMPONENT_TYPE_SCRIPT = 5, //!< The Script Component
COMPONENT_TYPE_BOUNCER = 6, //!< The Bouncer Component
COMPONENT_TYPE_BUFF = 7, //!< The Buff Component
COMPONENT_TYPE_SKILL = 9, //!< The Skill Component
COMPONENT_TYPE_ITEM = 11, //!< The Item Component
COMPONENT_TYPE_VENDOR = 16, //!< The Vendor Component
COMPONENT_TYPE_INVENTORY = 17, //!< The Inventory Component
COMPONENT_TYPE_SHOOTING_GALLERY = 19, //!< The Shooting Gallery Component
COMPONENT_TYPE_RIGID_BODY_PHANTOM_PHYSICS = 20, //!< The RigidBodyPhantomPhysics Component
COMPONENT_TYPE_COLLECTIBLE = 23, //!< The Collectible Component
COMPONENT_TYPE_MOVING_PLATFORM = 25, //!< The MovingPlatform Component
COMPONENT_TYPE_PET = 26, //!< The Pet Component
COMPONENT_TYPE_VEHICLE_PHYSICS = 30, //!< The VehiclePhysics Component
COMPONENT_TYPE_MOVEMENT_AI = 31, //!< The MovementAI Component
COMPONENT_TYPE_PROPERTY = 36, //!< The Property Component
COMPONENT_TYPE_SCRIPTED_ACTIVITY = 39, //!< The ScriptedActivity Component
COMPONENT_TYPE_PHANTOM_PHYSICS = 40, //!< The PhantomPhysics Component
COMPONENT_TYPE_MODEL = 42, //!< The Model Component
COMPONENT_TYPE_PROPERTY_ENTRANCE = 43, //!< The PhantomPhysics Component
COMPONENT_TYPE_PROPERTY_MANAGEMENT = 45, //!< The PropertyManagement Component
COMPONENT_TYPE_REBUILD = 48, //!< The Rebuild Component
COMPONENT_TYPE_SWITCH = 49, //!< The Switch Component
COMPONENT_TYPE_ZONE_CONTROL = 50, //!< The ZoneControl Component
COMPONENT_TYPE_PACKAGE = 53, //!< The Package Component
COMPONENT_TYPE_PLAYER_FLAG = 58, //!< The PlayerFlag Component
COMPONENT_TYPE_BASE_COMBAT_AI = 60, //!< The BaseCombatAI Component
COMPONENT_TYPE_MODULE_ASSEMBLY = 61, //!< The ModuleAssembly Component
COMPONENT_TYPE_PROPERTY_VENDOR = 65, //!< The PropertyVendor Component
COMPONENT_TYPE_ROCKET_LAUNCH = 67, //!< The RocketLaunch Component
COMPONENT_TYPE_RACING_CONTROL = 71, //!< The RacingControl Component
COMPONENT_TYPE_MISSION_OFFER = 73, //!< The MissionOffer Component
COMPONENT_TYPE_EXHIBIT = 75, //!< The Exhibit Component
COMPONENT_TYPE_RACING_STATS = 74, //!< The Racing Stats Component
COMPONENT_TYPE_SOUND_TRIGGER = 77, //!< The Sound Trigger Component
COMPONENT_TYPE_PROXIMITY_MONITOR = 78, //!< The Proximity Monitor Component
COMPONENT_TYPE_MISSION = 84, //!< The Mission Component
COMPONENT_TYPE_ROCKET_LAUNCH_LUP = 97, //!< The LUP Launchpad Componen
COMPONENT_TYPE_RAIL_ACTIVATOR = 104, //!< The Rail Activator Component
COMPONENT_TYPE_PLAYER_FORCED_MOVEMENT = 106, //!< The Player Forced Movement Component
COMPONENT_TYPE_POSSESSABLE = 108, //!< The Possessable Component
COMPONENT_TYPE_LEVEL_PROGRESSION = 109, //!< The Level Progression Component
COMPONENT_TYPE_POSSESSOR = 110, //!< The Possessor Component
COMPONENT_TYPE_BUILD_BORDER = 114, //!< The Build Border Component
COMPONENT_TYPE_DESTROYABLE = 1000, //!< The Destroyable Component
};
enum class UseItemResponse : uint32_t {
NoImaginationForPet = 1,
FailedPrecondition,
MountsNotAllowed
};
enum eRebuildState : uint32_t {
REBUILD_OPEN,
REBUILD_COMPLETED = 2,
REBUILD_RESETTING = 4,
REBUILD_BUILDING,
REBUILD_INCOMPLETE
};
/**
* The loot source's type.
*/
enum eLootSourceType : int32_t {
LOOT_SOURCE_NONE = 0,
LOOT_SOURCE_CHEST,
LOOT_SOURCE_MISSION,
LOOT_SOURCE_MAIL,
LOOT_SOURCE_CURRENCY,
LOOT_SOURCE_ACHIEVEMENT,
LOOT_SOURCE_TRADE,
LOOT_SOURCE_QUICKBUILD,
LOOT_SOURCE_DELETION,
LOOT_SOURCE_VENDOR,
LOOT_SOURCE_ACTIVITY,
LOOT_SOURCE_PICKUP,
LOOT_SOURCE_BRICK,
LOOT_SOURCE_PROPERTY,
LOOT_SOURCE_MODERATION,
LOOT_SOURCE_EXHIBIT,
LOOT_SOURCE_INVENTORY,
LOOT_SOURCE_CLAIMCODE,
LOOT_SOURCE_CONSUMPTION,
LOOT_SOURCE_CRAFTING,
LOOT_SOURCE_LEVEL_REWARD,
LOOT_SOURCE_RELOCATE
};
enum eGameActivities : uint32_t {
ACTIVITY_NONE,
ACTIVITY_QUICKBUILDING,
ACTIVITY_SHOOTING_GALLERY,
ACTIVITY_RACING,
ACTIVITY_PINBALL,
ACTIVITY_PET_TAMING
};
enum ePlayerFlags {
BTARR_TESTING = 0,
PLAYER_HAS_ENTERED_PET_RANCH = 1,
MINIMAP_UNLOCKED = 2,
ACTIVITY_REBUILDING_FAIL_TIME = 3,
ACTIVITY_REBUILDING_FAIL_RANGE = 4,
ACTIVITY_SHOOTING_GALLERY_HELP = 5,
HELP_WALKING_CONTROLS = 6,
FIRST_SMASHABLE = 7,
FIRST_IMAGINATION_PICKUP = 8,
FIRST_DAMAGE = 9,
FIRST_ITEM = 10,
FIRST_BRICK = 11,
FIRST_CONSUMABLE = 12,
FIRST_EQUIPPABLE = 13,
CHAT_HELP = 14,
FIRST_PET_TAMING_MINIGAME = 15,
FIRST_PET_ON_SWITCH = 16,
FIRST_PET_JUMPED_ON_SWITCH = 17,
FIRST_PET_FOUND_TREASURE = 18,
FIRST_PET_DUG_TREASURE = 19,
FIRST_PET_OWNER_ON_PET_BOUNCER = 20,
FIRST_PET_DESPAWN_NO_IMAGINATION = 21,
FIRST_PET_SELECTED_ENOUGH_BRICKS = 22,
FIRST_EMOTE_UNLOCKED = 23,
GF_PIRATE_REP = 24,
AG_BOB_CINEMATIC_EVENT = 25,
HELP_JUMPING_CONTROLS = 26,
HELP_DOUBLE_JUMP_CONTROLS = 27,
HELP_CAMERA_CONTROLS = 28,
HELP_ROTATE_CONTROLS = 29,
HELP_SMASH = 30,
MONUMENT_INTRO_MUSIC_PLAYED = 31,
BEGINNING_ZONE_SUMMARY_DISPLAYED = 32,
AG_FINISH_LINE_BUILT = 33,
AG_BOSS_AREA_FOUND = 34,
AG_LANDED_IN_BATTLEFIELD = 35,
GF_PLAYER_HAS_BEEN_TO_THE_RAVINE = 36,
MODULAR_BUILD_STARTED = 37,
MODULAR_BUILD_FINISHED_CLICK_BUTTON = 38,
THINKING_HAT_RECEIVED_GO_TO_MODULAR_BUILD_AREA = 39,
BUILD_AREA_ENTERED_MOD_NOT_ACTIVATED_PUT_ON_HAT = 40,
HAT_ON_INSIDE_OF_MOD_BUILD_EQUIP_A_MODULE_FROM_LEG = 41,
MODULE_EQUIPPED_PLACE_ON_GLOWING_BLUE_SPOT = 42,
FIRST_MODULE_PLACED_CORRECTLY_NOW_DO_THE_REST = 43,
ROCKET_COMPLETE_NOW_LAUNCH_FROM_PAD = 44,
JOINED_A_FACTION = 45,
VENTURE_FACTION = 46,
ASSEMBLY_FACTION = 47,
PARADOX_FACTION = 48,
SENTINEL_FACTION = 49,
LUP_WORLD_ACCESS = 50,
AG_FIRST_FLAG_COLLECTED = 51,
TOOLTIP_TALK_TO_SKYLAND_TO_GET_HAT = 52,
MODULAR_BUILD_PLAYER_PLACES_FIRST_MODEL_IN_SCRATCH = 53,
MODULAR_BUILD_FIRST_ARROW_DISPLAY_FOR_MODULE = 54,
AG_BEACON_QB_SO_THE_PLAYER_CAN_ALWAYS_BUILD_THEM = 55,
GF_PET_DIG_FLAG_1 = 56,
GF_PET_DIG_FLAG_2 = 57,
GF_PET_DIG_FLAG_3 = 58,
SUPPRESS_SPACESHIP_CINEMATIC_FLYTHROUGH = 59,
GF_PLAYER_FALL_DEATH = 60,
GF_PLAYER_CAN_GET_FLAG_1 = 61,
GF_PLAYER_CAN_GET_FLAG_2 = 62,
GF_PLAYER_CAN_GET_FLAG_3 = 63,
ENTER_BBB_FROM_PROPERTY_EDIT_CONFIRMATION_DIALOG = 64,
AG_FIRST_COMBAT_COMPLETE = 65,
AG_COMPLETE_BOB_MISSION = 66,
IS_NEWS_SCREEN_VISIBLE = 114,
NJ_GARMADON_CINEMATIC_SEEN = 125,
ELEPHANT_PET_3050 = 801,
CAT_PET_3054 = 802,
TRICERATOPS_PET_3195 = 803,
TERRIER_PET_3254 = 804,
SKUNK_PET_3261 = 805,
LION_PET_3520 = 806,
BUNNY_PET_3672 = 807,
CROCODILE_PET_3994 = 808,
DOBERMAN_PET_5635 = 809,
BUFFALO_PET_5636 = 810,
ROBOT_DOG_PET_5637 = 811,
EUROPEAN_DRAGON_PET_5639 = 812,
TORTOISE_PET_5640 = 813,
ASIAN_DRAGON_PET_5641 = 814,
MANTIS_PET_5642 = 815,
PANDA_PET_5643 = 816,
WARTHOG_PET_6720 = 817,
GOAT_PET_7638 = 818,
CRAB_PET_7694 = 819,
AG_SPACE_SHIP_BINOC_AT_LAUNCH = 1001,
AG_SPACE_SHIP_BINOC_AT_LAUNCH_PLATFORM = 1002,
AG_SPACE_SHIP_BINOC_ON_PLATFORM_TO_LEFT_OF_START = 1003,
AG_SPACE_SHIP_BINOC_ON_PLATFORM_TO_RIGHT_OF_START = 1004,
AG_SPACE_SHIP_BINOC_AT_BOB = 1005,
AG_BATTLE_BINOC_FOR_TRICERETOPS = 1101,
AG_BATTLE_BINOC_AT_PARADOX = 1102,
AG_BATTLE_BINOC_AT_MISSION_GIVER = 1103,
AG_BATTLE_BINOC_AT_BECK = 1104,
AG_MONUMENT_BINOC_INTRO = 1105,
AG_MONUMENT_BINOC_OUTRO = 1106,
AG_LAUNCH_BINOC_INTRO = 1107,
AG_LAUNCH_BINOC_BISON = 1108,
AG_LAUNCH_BINOC_SHARK = 1109,
NS_BINOC_CONCERT_TRANSITION = 1201,
NS_BINOC_RACE_PLACE_TRANSITION = 1202,
NS_BINOC_BRICK_ANNEX_TRANSITION = 1203,
NS_BINOC_GF_LAUNCH = 1204,
NS_BINOC_FV_LAUNCH = 1205,
NS_BINOC_BRICK_ANNEX_WATER = 1206,
NS_BINOC_AG_LAUNCH_AT_RACE_PLACE = 1207,
NS_BINOC_AG_LAUNCH_AT_BRICK_ANNEX = 1208,
NS_BINOC_AG_LAUNCH_AT_PLAZA = 1209,
NS_BINOC_TBA = 1210,
NS_FLAG_COLLECTABLE_1_BY_JONNY_THUNDER = 1211,
NS_FLAG_COLLECTABLE_2_UNDER_CONCERT_BRIDGE = 1212,
NS_FLAG_COLLECTABLE_3_BY_FV_LAUNCH = 1213,
NS_FLAG_COLLECTABLE_4_IN_PLAZA_BEHIND_BUILDING = 1214,
NS_FLAG_COLLECTABLE_5_BY_GF_LAUNCH = 1215,
NS_FLAG_COLLECTABLE_6_BY_DUCK_SG = 1216,
NS_FLAG_COLLECTABLE_7_BY_LUP_LAUNCH = 1217,
NS_FLAG_COLLECTABLE_8_BY_NT_LUANCH = 1218,
NS_FLAG_COLLECTABLE_9_BY_RACE_BUILD = 1219,
NS_FLAG_COLLECTABLE_10_ON_AG_LAUNCH_PATH = 1220,
PR_BINOC_AT_LAUNCH_PAD = 1251,
PR_BINOC_AT_BEGINNING_OF_ISLAND_B = 1252,
PR_BINOC_AT_FIRST_PET_BOUNCER = 1253,
PR_BINOC_ON_BY_CROWS_NEST = 1254,
PR_PET_DIG_AT_BEGINNING_OF_ISLAND_B = 1261,
PR_PET_DIG_AT_THE_LOCATION_OF_OLD_BOUNCE_BACK = 1262,
PR_PET_DIG_UNDER_QB_BRIDGE = 1263,
PR_PET_DIG_BACK_SIDE_BY_PARTNER_BOUNCE = 1264,
PR_PET_DIG_BY_LAUNCH_PAD = 1265,
PR_PET_DIG_BY_FIRST_PET_BOUNCER = 1266,
GF_BINOC_ON_LANDING_PAD = 1301,
GF_BINOC_AT_RAVINE_START = 1302,
GF_BINOC_ON_TOP_OF_RAVINE_HEAD = 1303,
GF_BINOC_AT_TURTLE_AREA = 1304,
GF_BINOC_IN_TUNNEL_TO_ELEPHANTS = 1305,
GF_BINOC_IN_ELEPHANTS_AREA = 1306,
GF_BINOC_IN_RACING_AREA = 1307,
GF_BINOC_IN_CROC_AREA = 1308,
GF_BINOC_IN_JAIL_AREA = 1309,
GF_BINOC_TELESCOPE_NEXT_TO_CAPTAIN_JACK = 1310,
NT_PLINTH_REBUILD = 1919,
NT_FACTION_SPY_DUKE = 1974,
NT_FACTION_SPY_OVERBUILD = 1976,
NT_FACTION_SPY_HAEL = 1977,
NJ_EARTH_SPINJITZU = 2030,
NJ_LIGHTNING_SPINJITZU = 2031,
NJ_ICE_SPINJITZU = 2032,
NJ_FIRE_SPINJITZU = 2033,
NJ_WU_SHOW_DAILY_CHEST = 2099
};
//======== FUNC ===========
template<typename T>
inline T const& clamp(const T& val, const T& low, const T& high) {
if (val < low) return low;
else if (val > high) return high;
return val;
}
#endif //!__DCOMMONVARS__H__

View File

@@ -0,0 +1,559 @@
#pragma once
#include "MessageIdentifiers.h"
enum CONNECTION_TYPE {
SERVER = 0, //!< Means it is used throughout all servers
AUTH, //!< Means it is sent from the client authentication
CHAT, //!< Means it is sent from and to the chat server
CHAT_INTERNAL, //!< Unused - We can potentially use this in the future for various things
WORLD, //!< Means it is sent from the client world
CLIENT, //!< Means it is sent to the client from the world server
MASTER //!< Means it is sent to and from the master server
};
//! The Internal Server Packet Identifiers
enum SERVER {
MSG_SERVER_VERSION_CONFIRM = 0, /*!< Sent during a handshake to confirm the server/client version */
MSG_SERVER_DISCONNECT_NOTIFY, /*!< Sent when a user disconnected */
MSG_SERVER_GENERAL_NOTIFY /*!< A general notification */
};
//! The Internal Authentication Packet Identifiers
enum AUTH {
MSG_AUTH_LOGIN_REQUEST = 0, /*!< Sent from the client when a user logs in */
MSG_AUTH_LOGOUT_REQUEST, /*!< Sent from the client when a user logs out */
MSG_AUTH_CREATE_NEW_ACCOUNT_REQUEST, /*!< Sent from the client when a user creates a new account */
MSG_AUTH_LEGOINTERFACE_AUTH_RESPONSE, /*!< Unknown */
MSG_AUTH_SESSIONKEY_RECEIVED_CONFIRM, /*!< Sent when the server recieved the session key (?) */
MSG_AUTH_RUNTIME_CONFIG /*!< Unknown */
};
//! The Internal Chat Packet Identifiers
enum CHAT {
MSG_CHAT_LOGIN_SESSION_NOTIFY = 0, /*!< When a user logs in */
MSG_CHAT_GENERAL_CHAT_MESSAGE, /*!< Used for global chat messages */
MSG_CHAT_PRIVATE_CHAT_MESSAGE, /*!< Used for private chat messages */
MSG_CHAT_USER_CHANNEL_CHAT_MESSAGE, /*!< Unknown */
MSG_CHAT_WORLD_DISCONNECT_REQUEST, /*!< Unknown */
MSG_CHAT_WORLD_PROXIMITY_RESPONSE, /*!< Unknown */
MSG_CHAT_WORLD_PARCEL_RESPONSE, /*!< Unknown */
MSG_CHAT_ADD_FRIEND_REQUEST, /*!< When the client requests to add a friend */
MSG_CHAT_ADD_FRIEND_RESPONSE, /*!< Sent from the server when the client adds a friend */
MSG_CHAT_REMOVE_FRIEND, /*!< When the client removes a friend */
MSG_CHAT_GET_FRIENDS_LIST, /*!< Sent when the client requests a user's friends list */
MSG_CHAT_ADD_IGNORE, /*!< Sent when the client adds a friend to the "ignore" list */
MSG_CHAT_REMOVE_IGNORE, /*!< Sent when the client removes a friend from the "ignore" list */
MSG_CHAT_GET_IGNORE_LIST, /*!< Sent when the client requests a user's ignored list */
MSG_CHAT_TEAM_MISSED_INVITE_CHECK, /*!< Unknown (Something with an unresponded-to friend request probably) */
MSG_CHAT_TEAM_INVITE, /*!< When the client invites a user to a team */
MSG_CHAT_TEAM_INVITE_RESPONSE, /*!< Sent from the server when the client invites someone to the team */
MSG_CHAT_TEAM_KICK, /*!< Sent when the client kicks a member from a team */
MSG_CHAT_TEAM_LEAVE, /*!< Sent when the client leaves a team */
MSG_CHAT_TEAM_SET_LOOT, /*!< Unknown (Something to do with team loot) */
MSG_CHAT_TEAM_SET_LEADER, /*!< Unknown (Probably sets the team leader or something) */
MSG_CHAT_TEAM_GET_STATUS, /*!< Check to see if we are in a team or not, sent on world join */
MSG_CHAT_GUILD_CREATE, /*!< Guild Creation */
MSG_CHAT_GUILD_INVITE, /*!< Guild Invitation */
MSG_CHAT_GUILD_INVITE_RESPONSE, /*!< Guild Invite Response */
MSG_CHAT_GUILD_LEAVE, /*!< Guild Leave */
MSG_CHAT_GUILD_KICK, /*!< Guild Kick */
MSG_CHAT_GUILD_GET_STATUS, /*!< Guild Get Status */
MSG_CHAT_GUILD_GET_ALL, /*!< Guild Get All */
MSG_CHAT_SHOW_ALL,
MSG_CHAT_BLUEPRINT_MODERATED,
MSG_CHAT_BLUEPRINT_MODEL_READY,
MSG_CHAT_PROPERTY_READY_FOR_APPROVAL,
MSG_CHAT_PROPERTY_MODERATION_CHANGED,
MSG_CHAT_PROPERTY_BUILDMODE_CHANGED,
MSG_CHAT_PROPERTY_BUILDMODE_CHANGED_REPORT,
MSG_CHAT_MAIL,
MSG_CHAT_WORLD_INSTANCE_LOCATION_REQUEST,
MSG_CHAT_REPUTATION_UPDATE,
MSG_CHAT_SEND_CANNED_TEXT,
MSG_CHAT_GMLEVEL_UPDATE,
MSG_CHAT_CHARACTER_NAME_CHANGE_REQUEST,
MSG_CHAT_CSR_REQUEST,
MSG_CHAT_CSR_REPLY,
MSG_CHAT_GM_KICK,
MSG_CHAT_GM_ANNOUNCE,
MSG_CHAT_GM_MUTE,
MSG_CHAT_ACTIVITY_UPDATE,
MSG_CHAT_WORLD_ROUTE_PACKET,
MSG_CHAT_GET_ZONE_POPULATIONS,
MSG_CHAT_REQUEST_MINIMUM_CHAT_MODE,
MSG_CHAT_REQUEST_MINIMUM_CHAT_MODE_PRIVATE,
MSG_CHAT_MATCH_REQUEST,
MSG_CHAT_UGCMANIFEST_REPORT_MISSING_FILE,
MSG_CHAT_UGCMANIFEST_REPORT_DONE_FILE,
MSG_CHAT_UGCMANIFEST_REPORT_DONE_BLUEPRINT,
MSG_CHAT_UGCC_REQUEST,
MSG_CHAT_WHO,
MSG_CHAT_WORLD_PLAYERS_PET_MODERATED_ACKNOWLEDGE,
MSG_CHAT_ACHIEVEMENT_NOTIFY,
MSG_CHAT_GM_CLOSE_PRIVATE_CHAT_WINDOW,
MSG_CHAT_UNEXPECTED_DISCONNECT,
MSG_CHAT_PLAYER_READY,
MSG_CHAT_GET_DONATION_TOTAL,
MSG_CHAT_UPDATE_DONATION,
MSG_CHAT_PRG_CSR_COMMAND,
MSG_CHAT_HEARTBEAT_REQUEST_FROM_WORLD,
MSG_CHAT_UPDATE_FREE_TRIAL_STATUS
};
//! Used for packets related to chatting
enum CHAT_INTERNAL {
MSG_CHAT_INTERNAL_PLAYER_ADDED_NOTIFICATION = 0,
MSG_CHAT_INTERNAL_PLAYER_REMOVED_NOTIFICATION,
MSG_CHAT_INTERNAL_ADD_FRIEND,
MSG_CHAT_INTERNAL_ADD_BEST_FRIEND,
MSG_CHAT_INTERNAL_ADD_TO_TEAM,
MSG_CHAT_INTERNAL_ADD_BLOCK,
MSG_CHAT_INTERNAL_REMOVE_FRIEND,
MSG_CHAT_INTERNAL_REMOVE_BLOCK,
MSG_CHAT_INTERNAL_REMOVE_FROM_TEAM,
MSG_CHAT_INTERNAL_DELETE_TEAM,
MSG_CHAT_INTERNAL_REPORT,
MSG_CHAT_INTERNAL_PRIVATE_CHAT,
MSG_CHAT_INTERNAL_PRIVATE_CHAT_RESPONSE,
MSG_CHAT_INTERNAL_ANNOUNCEMENT,
MSG_CHAT_INTERNAL_MAIL_COUNT_UPDATE,
MSG_CHAT_INTERNAL_MAIL_SEND_NOTIFY,
MSG_CHAT_INTERNAL_REQUEST_USER_LIST,
MSG_CHAT_INTERNAL_FRIEND_LIST,
MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER,
MSG_CHAT_INTERNAL_TEAM_UPDATE,
MSG_CHAT_INTERNAL_MUTE_UPDATE,
MSG_CHAT_INTERNAL_CREATE_TEAM,
};
//! Used for packets send to the world
enum WORLD {
MSG_WORLD_CLIENT_VALIDATION = 1, // Session info
MSG_WORLD_CLIENT_CHARACTER_LIST_REQUEST,
MSG_WORLD_CLIENT_CHARACTER_CREATE_REQUEST,
MSG_WORLD_CLIENT_LOGIN_REQUEST, // Character selected
MSG_WORLD_CLIENT_GAME_MSG,
MSG_WORLD_CLIENT_CHARACTER_DELETE_REQUEST,
MSG_WORLD_CLIENT_CHARACTER_RENAME_REQUEST,
MSG_WORLD_CLIENT_HAPPY_FLOWER_MODE_NOTIFY,
MSG_WORLD_CLIENT_SLASH_RELOAD_MAP, // Reload map cmp
MSG_WORLD_CLIENT_SLASH_PUSH_MAP_REQUEST, // Push map req cmd
MSG_WORLD_CLIENT_SLASH_PUSH_MAP, // Push map cmd
MSG_WORLD_CLIENT_SLASH_PULL_MAP, // Pull map cmd
MSG_WORLD_CLIENT_LOCK_MAP_REQUEST,
MSG_WORLD_CLIENT_GENERAL_CHAT_MESSAGE, // General chat message
MSG_WORLD_CLIENT_HTTP_MONITOR_INFO_REQUEST,
MSG_WORLD_CLIENT_SLASH_DEBUG_SCRIPTS, // Debug scripts cmd
MSG_WORLD_CLIENT_MODELS_CLEAR,
MSG_WORLD_CLIENT_EXHIBIT_INSERT_MODEL,
MSG_WORLD_CLIENT_LEVEL_LOAD_COMPLETE, // Character data request
MSG_WORLD_CLIENT_TMP_GUILD_CREATE,
MSG_WORLD_CLIENT_ROUTE_PACKET, // Social?
MSG_WORLD_CLIENT_POSITION_UPDATE,
MSG_WORLD_CLIENT_MAIL,
MSG_WORLD_CLIENT_WORD_CHECK, // Whitelist word check
MSG_WORLD_CLIENT_STRING_CHECK, // Whitelist string check
MSG_WORLD_CLIENT_GET_PLAYERS_IN_ZONE,
MSG_WORLD_CLIENT_REQUEST_UGC_MANIFEST_INFO,
MSG_WORLD_CLIENT_BLUEPRINT_GET_ALL_DATA_REQUEST,
MSG_WORLD_CLIENT_CANCEL_MAP_QUEUE,
MSG_WORLD_CLIENT_HANDLE_FUNNESS,
MSG_WORLD_CLIENT_FAKE_PRG_CSR_MESSAGE,
MSG_WORLD_CLIENT_REQUEST_FREE_TRIAL_REFRESH,
MSG_WORLD_CLIENT_GM_SET_FREE_TRIAL_STATUS
};
//! An enum for packets sent to the client
enum CLIENT {
MSG_CLIENT_LOGIN_RESPONSE = 0,
MSG_CLIENT_LOGOUT_RESPONSE,
MSG_CLIENT_LOAD_STATIC_ZONE,
MSG_CLIENT_CREATE_OBJECT,
MSG_CLIENT_CREATE_CHARACTER,
MSG_CLIENT_CREATE_CHARACTER_EXTENDED,
MSG_CLIENT_CHARACTER_LIST_RESPONSE,
MSG_CLIENT_CHARACTER_CREATE_RESPONSE,
MSG_CLIENT_CHARACTER_RENAME_RESPONSE,
MSG_CLIENT_CHAT_CONNECT_RESPONSE,
MSG_CLIENT_AUTH_ACCOUNT_CREATE_RESPONSE,
MSG_CLIENT_DELETE_CHARACTER_RESPONSE,
MSG_CLIENT_GAME_MSG,
MSG_CLIENT_CONNECT_CHAT,
MSG_CLIENT_TRANSFER_TO_WORLD,
MSG_CLIENT_IMPENDING_RELOAD_NOTIFY,
MSG_CLIENT_MAKE_GM_RESPONSE,
MSG_CLIENT_HTTP_MONITOR_INFO_RESPONSE,
MSG_CLIENT_SLASH_PUSH_MAP_RESPONSE,
MSG_CLIENT_SLASH_PULL_MAP_RESPONSE,
MSG_CLIENT_SLASH_LOCK_MAP_RESPONSE,
MSG_CLIENT_BLUEPRINT_SAVE_RESPONSE,
MSG_CLIENT_BLUEPRINT_LUP_SAVE_RESPONSE,
MSG_CLIENT_BLUEPRINT_LOAD_RESPONSE_ITEMID,
MSG_CLIENT_BLUEPRINT_GET_ALL_DATA_RESPONSE,
MSG_CLIENT_MODEL_INSTANTIATE_RESPONSE,
MSG_CLIENT_DEBUG_OUTPUT,
MSG_CLIENT_ADD_FRIEND_REQUEST,
MSG_CLIENT_ADD_FRIEND_RESPONSE,
MSG_CLIENT_REMOVE_FRIEND_RESPONSE,
MSG_CLIENT_GET_FRIENDS_LIST_RESPONSE,
MSG_CLIENT_UPDATE_FRIEND_NOTIFY,
MSG_CLIENT_ADD_IGNORE_RESPONSE,
MSG_CLIENT_REMOVE_IGNORE_RESPONSE,
MSG_CLIENT_GET_IGNORE_LIST_RESPONSE,
MSG_CLIENT_TEAM_INVITE,
MSG_CLIENT_TEAM_INVITE_INITIAL_RESPONSE,
MSG_CLIENT_GUILD_CREATE_RESPONSE,
MSG_CLIENT_GUILD_GET_STATUS_RESPONSE,
MSG_CLIENT_GUILD_INVITE,
MSG_CLIENT_GUILD_INVITE_INITIAL_RESPONSE,
MSG_CLIENT_GUILD_INVITE_FINAL_RESPONSE,
MSG_CLIENT_GUILD_INVITE_CONFIRM,
MSG_CLIENT_GUILD_ADD_PLAYER,
MSG_CLIENT_GUILD_REMOVE_PLAYER,
MSG_CLIENT_GUILD_LOGIN_LOGOUT,
MSG_CLIENT_GUILD_RANK_CHANGE,
MSG_CLIENT_GUILD_DATA,
MSG_CLIENT_GUILD_STATUS,
MSG_CLIENT_MAIL,
MSG_CLIENT_DB_PROXY_RESULT,
MSG_CLIENT_SHOW_ALL_RESPONSE,
MSG_CLIENT_WHO_RESPONSE,
MSG_CLIENT_SEND_CANNED_TEXT,
MSG_CLIENT_UPDATE_CHARACTER_NAME,
MSG_CLIENT_SET_NETWORK_SIMULATOR,
MSG_CLIENT_INVALID_CHAT_MESSAGE,
MSG_CLIENT_MINIMUM_CHAT_MODE_RESPONSE,
MSG_CLIENT_MINIMUM_CHAT_MODE_RESPONSE_PRIVATE,
MSG_CLIENT_CHAT_MODERATION_STRING,
MSG_CLIENT_UGC_MANIFEST_RESPONSE,
MSG_CLIENT_IN_LOGIN_QUEUE,
MSG_CLIENT_SERVER_STATES,
MSG_CLIENT_GM_CLOSE_TARGET_CHAT_WINDOW,
MSG_CLIENT_GENERAL_TEXT_FOR_LOCALIZATION,
MSG_CLIENT_UPDATE_FREE_TRIAL_STATUS,
MSG_CLIENT_UGC_DOWNLOAD_FAILED = 120
};
//! Used for packets sent to the master server
enum MASTER {
MSG_MASTER_REQUEST_PERSISTENT_ID = 1,
MSG_MASTER_REQUEST_PERSISTENT_ID_RESPONSE,
MSG_MASTER_REQUEST_ZONE_TRANSFER,
MSG_MASTER_REQUEST_ZONE_TRANSFER_RESPONSE,
MSG_MASTER_SERVER_INFO,
MSG_MASTER_REQUEST_SESSION_KEY,
MSG_MASTER_SET_SESSION_KEY,
MSG_MASTER_SESSION_KEY_RESPONSE,
MSG_MASTER_PLAYER_ADDED,
MSG_MASTER_PLAYER_REMOVED,
MSG_MASTER_CREATE_PRIVATE_ZONE,
MSG_MASTER_REQUEST_PRIVATE_ZONE,
MSG_MASTER_WORLD_READY,
MSG_MASTER_PREP_ZONE,
MSG_MASTER_SHUTDOWN,
MSG_MASTER_SHUTDOWN_RESPONSE,
MSG_MASTER_SHUTDOWN_IMMEDIATE,
MSG_MASTER_SHUTDOWN_UNIVERSE,
MSG_MASTER_AFFIRM_TRANSFER_REQUEST,
MSG_MASTER_AFFIRM_TRANSFER_RESPONSE,
MSG_MASTER_NEW_SESSION_ALERT
};
//! The Game messages
enum GAME_MSG : unsigned short {
GAME_MSG_TELEPORT = 19,
GAME_MSG_SET_PLAYER_CONTROL_SCHEME = 26,
GAME_MSG_DROP_CLIENT_LOOT = 30,
GAME_MSG_DIE = 37,
GAME_MSG_REQUEST_DIE = 38,
GAME_MSG_PLAY_EMOTE = 41,
GAME_MSG_PLAY_ANIMATION = 43,
GAME_MSG_CONTROL_BEHAVIOR = 48,
GAME_MSG_SET_NAME = 72,
GAME_MSG_ECHO_START_SKILL = 118,
GAME_MSG_START_SKILL = 119,
GAME_MSG_VERIFY_ACK = 121,
GAME_MSG_ADD_SKILL = 127,
GAME_MSG_REMOVE_SKILL = 128,
GAME_MSG_SET_CURRENCY = 133,
GAME_MSG_PICKUP_CURRENCY = 137,
GAME_MSG_PICKUP_ITEM = 139,
GAME_MSG_TEAM_PICKUP_ITEM = 140,
GAME_MSG_PLAY_FX_EFFECT = 154,
GAME_MSG_STOP_FX_EFFECT = 155,
GAME_MSG_REQUEST_RESURRECT = 159,
GAME_MSG_RESURRECT = 160,
GAME_MSG_PUSH_EQUIPPED_ITEMS_STATE = 191,
GAME_MSG_POP_EQUIPPED_ITEMS_STATE = 192,
GAME_MSG_SET_GM_LEVEL = 193,
GAME_MSG_SET_STUNNED = 198,
GAME_MSG_SET_STUN_IMMUNITY = 200,
GAME_MSG_KNOCKBACK = 202,
GAME_MSG_REBUILD_CANCEL = 209,
GAME_MSG_ENABLE_REBUILD = 213,
GAME_MSG_MOVE_ITEM_IN_INVENTORY = 224,
GAME_MSG_ADD_ITEM_TO_INVENTORY_CLIENT_SYNC = 227,
GAME_MSG_REMOVE_ITEM_FROM_INVENTORY = 230,
GAME_MSG_EQUIP_ITEM = 231,
GAME_MSG_UN_EQUIP_ITEM = 233,
GAME_MSG_OFFER_MISSION = 248,
GAME_MSG_RESPOND_TO_MISSION = 249,
GAME_MSG_NOTIFY_MISSION = 254,
GAME_MSG_NOTIFY_MISSION_TASK = 255,
GAME_MSG_REBUILD_NOTIFY_STATE = 336,
GAME_MSG_TERMINATE_INTERACTION = 357,
GAME_MSG_SERVER_TERMINATE_INTERACTION = 358,
GAME_MSG_REQUEST_USE = 364,
GAME_MSG_VENDOR_OPEN_WINDOW = 369,
GAME_MSG_BUY_FROM_VENDOR = 373,
GAME_MSG_SELL_TO_VENDOR = 374,
GAME_MSG_TEAM_SET_OFF_WORLD_FLAG = 383,
GAME_MSG_SET_INVENTORY_SIZE = 389,
GAME_MSG_ACKNOWLEDGE_POSSESSION = 391,
GAME_MSG_SET_SHOOTING_GALLERY_PARAMS = 400,
GAME_MSG_REQUEST_ACTIVITY_START_STOP = 402,
GAME_MSG_REQUEST_ACTIVITY_ENTER = 403,
GAME_MSG_REQUEST_ACTIVITY_EXIT = 404,
GAME_MSG_ACTIVITY_ENTER = 405,
GAME_MSG_ACTIVITY_EXIT = 406,
GAME_MSG_ACTIVITY_START = 407,
GAME_MSG_ACTIVITY_STOP = 408,
GAME_MSG_SHOOTING_GALLERY_CLIENT_AIM_UPDATE = 409,
GAME_MSG_SHOOTING_GALLERY_FIRE = 411,
GAME_MSG_REQUEST_VENDOR_STATUS_UPDATE = 416,
GAME_MSG_VENDOR_STATUS_UPDATE = 417,
GAME_MSG_NOTIFY_CLIENT_SHOOTING_GALLERY_SCORE = 425,
GAME_MSG_CONSUME_CLIENT_ITEM = 427,
GAME_MSG_CLIENT_ITEM_CONSUMED = 428,
GAME_MSG_UPDATE_SHOOTING_GALLERY_ROTATION = 448,
GAME_MSG_SET_FLAG = 471,
GAME_MSG_NOTIFY_CLIENT_FLAG_CHANGE = 472,
GAME_MSG_VENDOR_TRANSACTION_RESULT = 476,
GAME_MSG_HAS_BEEN_COLLECTED = 486,
GAME_MSG_DISPLAY_CHAT_BUBBLE = 495,
GAME_MSG_SPAWN_PET = 498,
GAME_MSG_DESPAWN_PET = 499,
GAME_MSG_PLAYER_LOADED = 505,
GAME_MSG_PLAYER_READY = 509,
GAME_MSG_REQUEST_LINKED_MISSION = 515,
GAME_MSG_INVALID_ZONE_TRANSFER_LIST = 519,
GAME_MSG_MISSION_DIALOGUE_OK = 520,
GAME_MSG_DISPLAY_MESSAGE_BOX = 529,
GAME_MSG_MESSAGE_BOX_RESPOND = 530,
GAME_MSG_CHOICE_BOX_RESPOND = 531,
GAME_MSG_SMASH = 537,
GAME_MSG_UNSMASH = 538,
GAME_MSG_SET_SHOOTING_GALLERY_RETICULE_EFFECT = 548,
GAME_MSG_PLACE_MODEL_RESPONSE = 0x223,
GAME_MSG_SET_JET_PACK_MODE = 561,
GAME_MSG_REGISTER_PET_ID = 565,
GAME_MSG_REGISTER_PET_DBID = 566,
GAME_MSG_SHOW_ACTIVITY_COUNTDOWN = 568,
GAME_MSG_START_ACTIVITY_TIME = 576,
GAME_MSG_ACTIVITY_PAUSE = 602,
GAME_MSG_USE_NON_EQUIPMENT_ITEM = 603,
GAME_MSG_USE_ITEM_RESULT = 607,
GAME_MSG_COMMAND_PET = 640,
GAME_MSG_PET_RESPONSE = 641,
GAME_MSG_REQUEST_ACTIVITY_SUMMARY_LEADERBOARD_DATA = 648,
GAME_MSG_SEND_ACTIVITY_SUMMARY_LEADERBOARD_DATA = 649,
GAME_MSG_NOTIFY_OBJECT = 656,
GAME_MSG_CLIENT_NOTIFY_PET = 659,
GAME_MSG_NOTIFY_PET = 660,
GAME_MSG_NOTIFY_PET_TAMING_MINIGAME = 661,
GAME_MSG_START_SERVER_PET_MINIGAME_TIMER = 662,
GAME_MSG_CLIENT_EXIT_TAMING_MINIGAME = 663,
GAME_MSG_PET_NAME_CHANGED = 686,
GAME_MSG_PET_TAMING_MINIGAME_RESULT = 667,
GAME_MSG_PET_TAMING_TRY_BUILD_RESULT = 668,
GAME_MSG_NOTIFY_TAMING_BUILD_SUCCESS = 673,
GAME_MSG_NOTIFY_TAMING_MODEL_LOADED_ON_SERVER = 674,
GAME_MSG_ACTIVATE_BUBBLE_BUFF = 678,
GAME_MSG_DEACTIVATE_BUBBLE_BUFF = 679,
GAME_MSG_ADD_PET_TO_PLAYER = 681,
GAME_MSG_REQUEST_SET_PET_NAME = 683,
GAME_MSG_SET_PET_NAME = 684,
GAME_MSG_NOTIFY_PET_TAMING_PUZZLE_SELECTED = 675,
GAME_MSG_SHOW_PET_ACTION_BUTTON = 692,
GAME_MSG_SET_EMOTE_LOCK_STATE = 693,
GAME_MSG_USE_ITEM_REQUIREMENTS_RESPONSE = 703,
GAME_MSG_PLAY_EMBEDDED_EFFECT_ON_ALL_CLIENTS_NEAR_OBJECT = 713,
GAME_MSG_DOWNLOAD_PROPERTY_DATA = 716,
GAME_MSG_QUERY_PROPERTY_DATA = 717,
GAME_MSG_PROPERTY_EDITOR_BEGIN = 724,
GAME_MSG_PROPERTY_EDITOR_END = 725,
GAME_MSG_IS_MINIFIG_IN_A_BUBBLE = 729,
GAME_MSG_START_PATHING = 733,
GAME_MSG_ACTIVATE_BUBBLE_BUFF_FROM_SERVER = 734,
GAME_MSG_DEACTIVATE_BUBBLE_BUFF_FROM_SERVER = 735,
GAME_MSG_NOTIFY_CLIENT_ZONE_OBJECT = 737,
GAME_MSG_UPDATE_REPUTATION = 746,
GAME_MSG_PROPERTY_RENTAL_RESPONSE = 750,
GAME_MSG_REQUEST_PLATFORM_RESYNC = 760,
GAME_MSG_PLATFORM_RESYNC = 761,
GAME_MSG_PLAY_CINEMATIC = 762,
GAME_MSG_END_CINEMATIC = 763,
GAME_MSG_CINEMATIC_UPDATE = 764,
GAME_MSG_TOGGLE_GHOST_REFERENCE_OVERRIDE = 767,
GAME_MSG_SET_GHOST_REFERENCE_POSITION = 768,
GAME_MSG_FIRE_EVENT_SERVER_SIDE = 770,
GAME_MSG_SET_NETWORK_SCRIPT_VAR = 781,
GAME_MSG_UPDATE_MODEL_FROM_CLIENT = 793,
GAME_MSG_DELETE_MODEL_FROM_CLIENT = 794,
GAME_MSG_PLAY_ND_AUDIO_EMITTER = 821,
GAME_MSG_PLAY2_DAMBIENT_SOUND = 831,
GAME_MSG_ENTER_PROPERTY1 = 840,
GAME_MSG_ENTER_PROPERTY2 = 841,
GAME_MSG_PROPERTY_ENTRANCE_SYNC = 842,
GAME_MSG_PROPERTY_SELECT_QUERY = 845,
GAME_MSG_PARSE_CHAT_MESSAGE = 850,
GAME_MSG_BROADCAST_TEXT_TO_CHATBOX = 858,
GAME_MSG_OPEN_PROPERTY_MANAGEMENT = 860,
GAME_MSG_OPEN_PROPERTY_VENDOR = 861,
GAME_MSG_UPDATE_PROPERTY_OR_MODEL_FOR_FILTER_CHECK = 863,
GAME_MSG_CLIENT_TRADE_REQUEST = 868,
GAME_MSG_SERVER_TRADE_REQUEST = 869,
GAME_MSG_SERVER_TRADE_INVITE = 870,
GAME_MSG_CLIENT_TRADE_REPLY = 871,
GAME_MSG_SERVER_TRADE_REPLY = 872,
GAME_MSG_SERVER_TRADE_INITIAL_REPLY = 873,
GAME_MSG_SERVER_TRADE_FINAL_REPLY = 874,
GAME_MSG_CLIENT_TRADE_UPDATE = 875,
GAME_MSG_SERVER_SIDE_TRADE_UPDATE = 876,
GAME_MSG_SERVER_TRADE_UPDATE = 877,
GAME_MSG_CLIENT_TRADE_CANCEL = 878,
GAME_MSG_CLIENT_SIDE_TRADE_CANCEL = 879,
GAME_MSG_CLIENT_TRADE_ACCEPT = 880,
GAME_MSG_SERVER_SIDE_TRADE_ACCEPT = 881,
GAME_MSG_SERVER_SIDE_TRADE_CANCEL = 882,
GAME_MSG_SERVER_TRADE_CANCEL = 883,
GAME_MSG_SERVER_TRADE_ACCEPT = 884,
GAME_MSG_READY_FOR_UPDATES = 888,
GAME_MSG_ORIENT_TO_OBJECT = 905,
GAME_MSG_ORIENT_TO_POSITION = 906,
GAME_MSG_ORIENT_TO_ANGLE = 907,
GAME_MSG_BOUNCER_ACTIVE_STATUS = 942,
GAME_MSG_UN_USE_BBB_MODEL = 999,
GAME_MSG_BBB_LOAD_ITEM_REQUEST = 1000,
GAME_MSG_BBB_SAVE_REQUEST = 1001,
GAME_MSG_BBB_SAVE_RESPONSE = 1006,
GAME_MSG_NOTIFY_CLIENT_OBJECT = 1042,
GAME_MSG_DISPLAY_ZONE_SUMMARY = 1043,
GAME_MSG_ACTIVITY_STATE_CHANGE_REQUEST = 1053,
GAME_MSG_MODIFY_PLAYER_ZONE_STATISTIC = 1046,
GAME_MSG_START_BUILDING_WITH_ITEM = 1057,
GAME_MSG_START_ARRANGING_WITH_ITEM = 1061,
GAME_MSG_FINISH_ARRANGING_WITH_ITEM = 1062,
GAME_MSG_DONE_ARRANGING_WITH_ITEM = 1063,
GAME_MSG_SET_BUILD_MODE = 1068,
GAME_MSG_BUILD_MODE_SET = 1069,
GAME_MSG_SET_BUILD_MODE_CONFIRMED = 1073,
GAME_MSG_NOTIFY_CLIENT_FAILED_PRECONDITION = 1081,
GAME_MSG_MOVE_ITEM_BETWEEN_INVENTORY_TYPES = 1093,
GAME_MSG_MODULAR_BUILD_BEGIN = 1094,
GAME_MSG_MODULAR_BUILD_END = 1095,
GAME_MSG_MODULAR_BUILD_MOVE_AND_EQUIP = 1096,
GAME_MSG_MODULAR_BUILD_FINISH = 1097,
GAME_MSG_REPORT_BUG = 1198,
GAME_MSG_MISSION_DIALOGUE_CANCELLED = 1129,
GAME_MSG_ECHO_SYNC_SKILL = 1144,
GAME_MSG_SYNC_SKILL = 1145,
GAME_MSG_REQUEST_SERVER_PROJECTILE_IMPACT = 1148,
GAME_MSG_DO_CLIENT_PROJECTILE_IMPACT = 1151,
GAME_MSG_MODULAR_BUILD_CONVERT_MODEL = 1155,
GAME_MSG_SET_PLAYER_ALLOWED_RESPAWN = 1165,
GAME_MSG_UI_MESSAGE_SERVER_TO_SINGLE_CLIENT = 1184,
GAME_MSG_UI_MESSAGE_SERVER_TO_ALL_CLIENTS = 1185,
GAME_MSG_PET_TAMING_TRY_BUILD = 1197,
GAME_MSG_REQUEST_SMASH_PLAYER = 1202,
GAME_MSG_FIRE_EVENT_CLIENT_SIDE = 1213,
GAME_MSG_TOGGLE_GM_INVIS = 1218,
GAME_MSG_CHANGE_OBJECT_WORLD_STATE = 1223,
GAME_MSG_VEHICLE_LOCK_INPUT = 1230,
GAME_MSG_VEHICLE_UNLOCK_INPUT = 1231,
GAME_MSG_RACING_RESET_PLAYER_TO_LAST_RESET = 1252,
GAME_MSG_RACING_SERVER_SET_PLAYER_LAP_AND_PLANE = 1253,
GAME_MSG_RACING_SET_PLAYER_RESET_INFO = 1254,
GAME_MSG_RACING_PLAYER_INFO_RESET_FINISHED = 1255,
GAME_MSG_LOCK_NODE_ROTATION = 1260,
GAME_MSG_VEHICLE_SET_WHEEL_LOCK_STATE = 1273,
GAME_MSG_NOTIFY_VEHICLE_OF_RACING_OBJECT = 1276,
GAME_MSG_PLAYER_REACHED_RESPAWN_CHECKPOINT = 1296,
GAME_MSG_HANDLE_UGC_EQUIP_POST_DELETE_BASED_ON_EDIT_MODE = 1300,
GAME_MSG_HANDLE_UGC_EQUIP_PRE_CREATE_BASED_ON_EDIT_MODE = 1301,
GAME_MSG_PROPERTY_CONTENTS_FROM_CLIENT = 1305,
GAME_MSG_GET_MODELS_ON_PROPERTY = 1306,
GAME_MSG_MATCH_REQUEST = 1308,
GAME_MSG_MATCH_RESPONSE = 1309,
GAME_MSG_MATCH_UPDATE = 1310,
GAME_MSG_MODULE_ASSEMBLY_DB_DATA_FOR_CLIENT = 1131,
GAME_MSG_MODULE_ASSEMBLY_QUERY_DATA = 1132,
GAME_MSG_CHANGE_IDLE_FLAGS = 1338,
GAME_MSG_VEHICLE_ADD_PASSIVE_BOOST_ACTION = 1340,
GAME_MSG_VEHICLE_REMOVE_PASSIVE_BOOST_ACTION = 1341,
GAME_MSG_VEHICLE_NOTIFY_SERVER_ADD_PASSIVE_BOOST_ACTION = 1342,
GAME_MSG_VEHICLE_NOTIFY_SERVER_REMOVE_PASSIVE_BOOST_ACTION = 1343,
GAME_MSG_VEHICLE_ADD_SLOWDOWN_ACTION = 1344,
GAME_MSG_VEHICLE_REMOVE_SLOWDOWN_ACTION = 1345,
GAME_MSG_VEHICLE_NOTIFY_SERVER_ADD_SLOWDOWN_ACTION = 1346,
GAME_MSG_VEHICLE_NOTIFY_SERVER_REMOVE_SLOWDOWN_ACTION = 1347,
GAME_MSG_BUYBACK_FROM_VENDOR = 1350,
GAME_MSG_SET_PROPERTY_ACCESS = 1366,
GAME_MSG_ZONE_PROPERTY_MODEL_PLACED = 1369,
GAME_MSG_ZONE_PROPERTY_MODEL_ROTATED = 1370,
GAME_MSG_ZONE_PROPERTY_MODEL_REMOVED_WHILE_EQUIPPED = 1371,
GAME_MSG_ZONE_PROPERTY_MODEL_EQUIPPED = 1372,
GAME_MSG_ZONE_PROPERTY_MODEL_PICKED_UP = 1373,
GAME_MSG_ZONE_PROPERTY_MODEL_REMOVED = 1374,
GAME_MSG_NOTIFY_RACING_CLIENT = 1390,
GAME_MSG_RACING_PLAYER_HACK_CAR = 1391,
GAME_MSG_RACING_PLAYER_LOADED = 1392,
GAME_MSG_RACING_CLIENT_READY = 1393,
GAME_MSG_UPDATE_CHAT_MODE = 1395,
GAME_MSG_VEHICLE_NOTIFY_FINISHED_RACE = 1396,
GAME_MSG_SET_CONSUMABLE_ITEM = 1409,
GAME_MSG_SET_STATUS_IMMUNITY = 1435,
GAME_MSG_SET_PET_NAME_MODERATED = 1448,
GAME_MSG_MODIFY_LEGO_SCORE = 1459,
GAME_MSG_RESTORE_TO_POST_LOAD_STATS = 1468,
GAME_MSG_SET_RAIL_MOVEMENT = 1471,
GAME_MSG_START_RAIL_MOVEMENT = 1472,
GAME_MSG_CANCEL_RAIL_MOVEMENT = 1474,
GAME_MSG_CLIENT_RAIL_MOVEMENT_READY = 1476,
GAME_MSG_PLAYER_RAIL_ARRIVED_NOTIFICATION = 1477,
GAME_MSG_UPDATE_PLAYER_STATISTIC = 1481,
GAME_MSG_MODULAR_ASSEMBLY_NIF_COMPLETED = 1498,
GAME_MSG_NOTIFY_NOT_ENOUGH_INV_SPACE = 1516,
GAME_MSG_TEAM_SET_LEADER = 0x0615,
GAME_MSG_TEAM_INVITE_CONFIRM = 0x0616,
GAME_MSG_TEAM_GET_STATUS_RESPONSE = 0x0617,
GAME_MSG_TEAM_ADD_PLAYER = 0x061a,
GAME_MSG_TEAM_REMOVE_PLAYER = 0x061b,
GAME_MSG_START_CELEBRATION_EFFECT = 1618,
GAME_MSG_ADD_BUFF = 1647,
GAME_MSG_SERVER_DONE_LOADING_ALL_OBJECTS = 1642,
GAME_MSG_PLACE_PROPERTY_MODEL = 1170,
GAME_MSG_VEHICLE_NOTIFY_HIT_IMAGINATION_SERVER = 1606,
GAME_MSG_ADD_RUN_SPEED_MODIFIER = 1505,
GAME_MSG_HANDLE_HOT_PROPERTY_DATA = 1511,
GAME_MSG_SEND_HOT_PROPERTY_DATA = 1510,
GAME_MSG_REMOVE_RUN_SPEED_MODIFIER = 1506,
GAME_MSG_UPDATE_PROPERTY_PERFORMANCE_COST = 1547,
GAME_MSG_PROPERTY_ENTRANCE_BEGIN = 1553,
GAME_MSG_REMOVE_BUFF = 1648,
GAME_MSG_REQUEST_MOVE_ITEM_BETWEEN_INVENTORY_TYPES = 1666,
GAME_MSG_RESPONSE_MOVE_ITEM_BETWEEN_INVENTORY_TYPES = 1667,
GAME_MSG_PLAYER_SET_CAMERA_CYCLING_MODE = 1676,
GAME_MSG_SET_MOUNT_INVENTORY_ID = 1726,
GAME_MSG_NOTIFY_SERVER_LEVEL_PROCESSING_COMPLETE = 1734,
GAME_MSG_NOTIFY_LEVEL_REWARDS = 1735,
GAME_MSG_DISMOUNT_COMPLETE = 1756,
GAME_MSG_MARK_INVENTORY_ITEM_AS_ACTIVE = 1767,
END
};

View File

@@ -1,15 +0,0 @@
#ifndef __EAUTHMESSAGETYPE__H__
#define __EAUTHMESSAGETYPE__H__
#include <cstdint>
enum class eAuthMessageType : uint32_t {
LOGIN_REQUEST = 0,
LOGOUT_REQUEST,
CREATE_NEW_ACCOUNT_REQUEST,
LEGOINTERFACE_AUTH_RESPONSE,
SESSIONKEY_RECEIVED_CONFIRM,
RUNTIME_CONFIG
};
#endif //!__EAUTHMESSAGETYPE__H__

View File

@@ -7,8 +7,8 @@
enum class eBubbleType : uint32_t {
DEFAULT = 0,
ENERGY,
SKUNK
ENERGY = 1,
SKUNK = 2,
};
#endif //!__EBUBBLETYPE__H__

View File

@@ -1,12 +0,0 @@
#ifndef __EBUILDTYPE__H__
#define __EBUILDTYPE__H__
#include <cstdint>
enum class eBuildType :uint32_t {
NOWHERE,
IN_WORLD,
ON_PROPERTY
};
#endif //!__EBUILDTYPE__H__

View File

@@ -1,14 +0,0 @@
#ifndef __ECHARACTERCREATIONRESPONSE__H__
#define __ECHARACTERCREATIONRESPONSE__H__
#include <cstdint>
enum class eCharacterCreationResponse : uint8_t {
SUCCESS = 0,
OBJECT_ID_UNAVAILABLE,
NAME_NOT_ALLOWED,
PREDEFINED_NAME_IN_USE,
CUSTOM_NAME_IN_USE
};
#endif //!__ECHARACTERCREATIONRESPONSE__H__

View File

@@ -1,31 +0,0 @@
#ifndef __ECHATINTERNALMESSAGETYPE__H__
#define __ECHATINTERNALMESSAGETYPE__H__
#include <cstdint>
enum eChatInternalMessageType : uint32_t {
PLAYER_ADDED_NOTIFICATION = 0,
PLAYER_REMOVED_NOTIFICATION,
ADD_FRIEND,
ADD_BEST_FRIEND,
ADD_TO_TEAM,
ADD_BLOCK,
REMOVE_FRIEND,
REMOVE_BLOCK,
REMOVE_FROM_TEAM,
DELETE_TEAM,
REPORT,
PRIVATE_CHAT,
PRIVATE_CHAT_RESPONSE,
ANNOUNCEMENT,
MAIL_COUNT_UPDATE,
MAIL_SEND_NOTIFY,
REQUEST_USER_LIST,
FRIEND_LIST,
ROUTE_TO_PLAYER,
TEAM_UPDATE,
MUTE_UPDATE,
CREATE_TEAM,
};
#endif //!__ECHATINTERNALMESSAGETYPE__H__

View File

@@ -1,78 +0,0 @@
#ifndef __ECHATMESSAGETYPE__H__
#define __ECHATMESSAGETYPE__H__
#include <cstdint>
//! The Internal Chat Packet Identifiers
enum class eChatMessageType :uint32_t {
LOGIN_SESSION_NOTIFY = 0,
GENERAL_CHAT_MESSAGE,
PRIVATE_CHAT_MESSAGE,
USER_CHANNEL_CHAT_MESSAGE,
WORLD_DISCONNECT_REQUEST,
WORLD_PROXIMITY_RESPONSE,
WORLD_PARCEL_RESPONSE,
ADD_FRIEND_REQUEST,
ADD_FRIEND_RESPONSE,
REMOVE_FRIEND,
GET_FRIENDS_LIST,
ADD_IGNORE,
REMOVE_IGNORE,
GET_IGNORE_LIST,
TEAM_MISSED_INVITE_CHECK,
TEAM_INVITE,
TEAM_INVITE_RESPONSE,
TEAM_KICK,
TEAM_LEAVE,
TEAM_SET_LOOT,
TEAM_SET_LEADER,
TEAM_GET_STATUS,
GUILD_CREATE,
GUILD_INVITE,
GUILD_INVITE_RESPONSE,
GUILD_LEAVE,
GUILD_KICK,
GUILD_GET_STATUS,
GUILD_GET_ALL,
SHOW_ALL,
BLUEPRINT_MODERATED,
BLUEPRINT_MODEL_READY,
PROPERTY_READY_FOR_APPROVAL,
PROPERTY_MODERATION_CHANGED,
PROPERTY_BUILDMODE_CHANGED,
PROPERTY_BUILDMODE_CHANGED_REPORT,
MAIL,
WORLD_INSTANCE_LOCATION_REQUEST,
REPUTATION_UPDATE,
SEND_CANNED_TEXT,
GMLEVEL_UPDATE,
CHARACTER_NAME_CHANGE_REQUEST,
CSR_REQUEST,
CSR_REPLY,
GM_KICK,
GM_ANNOUNCE,
GM_MUTE,
ACTIVITY_UPDATE,
WORLD_ROUTE_PACKET,
GET_ZONE_POPULATIONS,
REQUEST_MINIMUM_CHAT_MODE,
REQUEST_MINIMUM_CHAT_MODE_PRIVATE,
MATCH_REQUEST,
UGCMANIFEST_REPORT_MISSING_FILE,
UGCMANIFEST_REPORT_DONE_FILE,
UGCMANIFEST_REPORT_DONE_BLUEPRINT,
UGCC_REQUEST,
WHO,
WORLD_PLAYERS_PET_MODERATED_ACKNOWLEDGE,
ACHIEVEMENT_NOTIFY,
GM_CLOSE_PRIVATE_CHAT_WINDOW,
UNEXPECTED_DISCONNECT,
PLAYER_READY,
GET_DONATION_TOTAL,
UPDATE_DONATION,
PRG_CSR_COMMAND,
HEARTBEAT_REQUEST_FROM_WORLD,
UPDATE_FREE_TRIAL_STATUS
};
#endif //!__ECHATMESSAGETYPE__H__

View File

@@ -1,12 +0,0 @@
#ifndef __ECINEMATICEVENT__H__
#define __ECINEMATICEVENT__H__
#include <cstdint>
enum class eCinematicEvent : uint32_t {
STARTED,
WAYPOINT,
ENDED,
};
#endif //!__ECINEMATICEVENT__H__

View File

@@ -1,76 +0,0 @@
#ifndef __ECLIENTMESSAGETYPE__H__
#define __ECLIENTMESSAGETYPE__H__
#include <cstdint>
enum class eClientMessageType : uint32_t {
LOGIN_RESPONSE = 0,
LOGOUT_RESPONSE,
LOAD_STATIC_ZONE,
CREATE_OBJECT,
CREATE_CHARACTER,
CREATE_CHARACTER_EXTENDED,
CHARACTER_LIST_RESPONSE,
CHARACTER_CREATE_RESPONSE,
CHARACTER_RENAME_RESPONSE,
CHAT_CONNECT_RESPONSE,
AUTH_ACCOUNT_CREATE_RESPONSE,
DELETE_CHARACTER_RESPONSE,
GAME_MSG,
CONNECT_CHAT,
TRANSFER_TO_WORLD,
IMPENDING_RELOAD_NOTIFY,
MAKE_GM_RESPONSE,
HTTP_MONITOR_INFO_RESPONSE,
SLASH_PUSH_MAP_RESPONSE,
SLASH_PULL_MAP_RESPONSE,
SLASH_LOCK_MAP_RESPONSE,
BLUEPRINT_SAVE_RESPONSE,
BLUEPRINT_LUP_SAVE_RESPONSE,
BLUEPRINT_LOAD_RESPONSE_ITEMID,
BLUEPRINT_GET_ALL_DATA_RESPONSE,
MODEL_INSTANTIATE_RESPONSE,
DEBUG_OUTPUT,
ADD_FRIEND_REQUEST,
ADD_FRIEND_RESPONSE,
REMOVE_FRIEND_RESPONSE,
GET_FRIENDS_LIST_RESPONSE,
UPDATE_FRIEND_NOTIFY,
ADD_IGNORE_RESPONSE,
REMOVE_IGNORE_RESPONSE,
GET_IGNORE_LIST_RESPONSE,
TEAM_INVITE,
TEAM_INVITE_INITIAL_RESPONSE,
GUILD_CREATE_RESPONSE,
GUILD_GET_STATUS_RESPONSE,
GUILD_INVITE,
GUILD_INVITE_INITIAL_RESPONSE,
GUILD_INVITE_FINAL_RESPONSE,
GUILD_INVITE_CONFIRM,
GUILD_ADD_PLAYER,
GUILD_REMOVE_PLAYER,
GUILD_LOGIN_LOGOUT,
GUILD_RANK_CHANGE,
GUILD_DATA,
GUILD_STATUS,
MAIL,
DB_PROXY_RESULT,
SHOW_ALL_RESPONSE,
WHO_RESPONSE,
SEND_CANNED_TEXT,
UPDATE_CHARACTER_NAME,
SET_NETWORK_SIMULATOR,
INVALID_CHAT_MESSAGE,
MINIMUM_CHAT_MODE_RESPONSE,
MINIMUM_CHAT_MODE_RESPONSE_PRIVATE,
CHAT_MODERATION_STRING,
UGC_MANIFEST_RESPONSE,
IN_LOGIN_QUEUE,
SERVER_STATES,
GM_CLOSE_TARGET_CHAT_WINDOW,
GENERAL_TEXT_FOR_LOCALIZATION,
UPDATE_FREE_TRIAL_STATUS,
UGC_DOWNLOAD_FAILED = 120
};
#endif //!__ECLIENTMESSAGETYPE__H__

View File

@@ -1,14 +0,0 @@
#ifndef __ECONNECTIONTYPE__H__
#define __ECONNECTIONTYPE__H__
enum class eConnectionType : uint16_t {
SERVER = 0,
AUTH,
CHAT,
CHAT_INTERNAL,
WORLD,
CLIENT,
MASTER
};
#endif //!__ECONNECTIONTYPE__H__

View File

@@ -1,18 +0,0 @@
#ifndef __ECONTROLSCHEME__H__
#define __ECONTROLSCHEME__H__
#include <cstdint>
enum class eControlScheme : uint32_t {
SCHEME_A,
SCHEME_D,
SCHEME_GAMEPAD,
SCHEME_E,
SCHEME_FPS,
SCHEME_DRIVING,
SCHEME_TAMING,
SCHEME_MODULAR_BUILD,
SCHEME_WEAR_A_ROBOT //== freecam?
};
#endif //!__ECONTROLSCHEME__H__

View File

@@ -1,11 +0,0 @@
#ifndef __ECYCLINGMODE__H__
#define __ECYCLINGMODE__H__
#include <cstdint>
enum class eCyclingMode : uint32_t {
ALLOW_CYCLE_TEAMMATES,
DISALLOW_CYCLING
};
#endif //!__ECYCLINGMODE__H__

View File

@@ -1,11 +0,0 @@
#ifndef __EENDBEHAVIOR__H__
#define __EENDBEHAVIOR__H__
#include <cstdint>
enum class eEndBehavior : uint32_t {
RETURN,
WAIT
};
#endif //!__EENDBEHAVIOR__H__

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